source: icGREP/icgrep-devel/icgrep/kernels/interface.cpp @ 5402

Last change on this file since 5402 was 5402, checked in by nmedfort, 2 years ago

Moved toolchain and object_cache to kernels directory. Continued work on providing input consumed information.

File size: 7.1 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5
6#include "interface.h"
7#include <llvm/IR/Value.h>         // for Value
8#include <llvm/IR/CallingConv.h>   // for ::C
9#include <llvm/IR/DerivedTypes.h>  // for FunctionType (ptr only), PointerType
10#include <llvm/IR/Function.h>      // for Function, Function::arg_iterator
11#include <llvm/IR/Module.h>
12#include <IR_Gen/idisa_builder.h>
13namespace llvm { class Module; }
14namespace llvm { class Type; }
15
16static const auto INIT_SUFFIX = "_Init";
17
18static const auto DO_SEGMENT_SUFFIX = "_DoSegment";
19
20static const auto ACCUMULATOR_INFIX = "_get_";
21
22using namespace llvm;
23
24ProcessingRate FixedRatio(unsigned strmItemsPer, unsigned perPrincipalInputItems, std::string && referenceStreamSet) {
25    return ProcessingRate(ProcessingRate::ProcessingRateKind::Fixed, strmItemsPer, perPrincipalInputItems, std::move(referenceStreamSet));
26}
27
28ProcessingRate MaxRatio(unsigned strmItemsPer, unsigned perPrincipalInputItems, std::string && referenceStreamSet) {
29    return ProcessingRate(ProcessingRate::ProcessingRateKind::Max, strmItemsPer, perPrincipalInputItems, std::move(referenceStreamSet));
30}
31
32ProcessingRate RoundUpToMultiple(unsigned itemMultiple, std::string && referenceStreamSet) {
33    return ProcessingRate(ProcessingRate::ProcessingRateKind::RoundUp, itemMultiple, itemMultiple, std::move(referenceStreamSet));
34}
35
36ProcessingRate Add1(std::string && referenceStreamSet) {
37    return ProcessingRate(ProcessingRate::ProcessingRateKind::Add1, 0, 0, std::move(referenceStreamSet));
38}
39
40ProcessingRate UnknownRate() {
41    return ProcessingRate(ProcessingRate::ProcessingRateKind::Unknown, 0, 0, "");
42}
43
44Value * ProcessingRate::CreateRatioCalculation(IDISA::IDISA_Builder * b, Value * principalInputItems, Value * doFinal) const {
45    if (mKind == ProcessingRate::ProcessingRateKind::Fixed || mKind == ProcessingRate::ProcessingRateKind::Max) {
46        if (mRatioNumerator == 1) {
47            return principalInputItems;
48        }
49        Type * const T = principalInputItems->getType();
50        Constant * const numerator = ConstantInt::get(T, mRatioNumerator);
51        Constant * const denominator = ConstantInt::get(T, mRatioDenominator);
52        Constant * const denominatorLess1 = ConstantInt::get(T, mRatioDenominator - 1);
53        Value * strmItems = b->CreateMul(principalInputItems, numerator);
54        return b->CreateUDiv(b->CreateAdd(denominatorLess1, strmItems), denominator);
55    }
56    if (mKind == ProcessingRate::ProcessingRateKind::RoundUp) {
57        Type * const T = principalInputItems->getType();
58        Constant * const denominator = ConstantInt::get(T, mRatioDenominator);
59        Constant * const denominatorLess1 = ConstantInt::get(T, mRatioDenominator - 1);
60        return b->CreateMul(b->CreateUDiv(b->CreateAdd(principalInputItems, denominatorLess1), denominator), denominator);
61    }
62    if (mKind == ProcessingRate::ProcessingRateKind::Add1) {
63        if (doFinal) {
64            Type * const T = principalInputItems->getType();
65            principalInputItems = b->CreateAdd(principalInputItems, b->CreateZExt(doFinal, T));
66        }
67        return principalInputItems;
68    }
69    return nullptr;
70}
71
72void KernelInterface::addKernelDeclarations(Module * client) {
73    Module * saveModule = iBuilder->getModule();
74    auto savePoint = iBuilder->saveIP();
75    iBuilder->setModule(client);
76    if (mKernelStateType == nullptr) {
77        throw std::runtime_error("Kernel interface " + getName() + " not yet finalized.");
78    }
79    PointerType * selfType = PointerType::getUnqual(mKernelStateType);
80
81    // Create the initialization function prototype
82    std::vector<Type *> initParameters = {selfType};
83    for (auto binding : mScalarInputs) {
84        initParameters.push_back(binding.type);
85    }
86    FunctionType * initType = FunctionType::get(iBuilder->getVoidTy(), initParameters, false);
87    Function * init = Function::Create(initType, GlobalValue::ExternalLinkage, getName() + INIT_SUFFIX, client);
88    init->setCallingConv(CallingConv::C);
89    init->setDoesNotThrow();
90    auto args = init->arg_begin();
91    args->setName("self");
92    for (auto binding : mScalarInputs) {
93        (++args)->setName(binding.name);
94    }
95
96    /// INVESTIGATE: should we explicitly mark whether to track a kernel output's consumed amount? It would have
97    /// to be done at the binding level using the current architecture. It would reduce the number of arguments
98    /// passed between kernels.
99
100    // Create the doSegment function prototype.   
101    IntegerType * const sizeTy = iBuilder->getSizeTy();
102
103    std::vector<Type *> params = {selfType, iBuilder->getInt1Ty()};
104    params.insert(params.end(), mStreamSetInputs.size() + mStreamSetOutputs.size(), sizeTy);
105
106    FunctionType * const doSegmentType = FunctionType::get(iBuilder->getVoidTy(), params, false);
107    Function * doSegment = Function::Create(doSegmentType, GlobalValue::ExternalLinkage, getName() + DO_SEGMENT_SUFFIX, client);
108    doSegment->setCallingConv(CallingConv::C);
109    doSegment->setDoesNotThrow();
110    doSegment->setDoesNotCapture(1); // for self parameter only.
111    args = doSegment->arg_begin();
112    args->setName("self");
113    (++args)->setName("doFinal");
114    for (const Binding & input : mStreamSetInputs) {
115        (++args)->setName(input.name + "_availableItems");
116    }
117    for (const Binding & output : mStreamSetOutputs) {
118        (++args)->setName(output.name + "_consumedItems");
119    }
120
121    /// INVESTIGATE: replace the accumulator methods with a single Exit method that handles any clean up and returns
122    /// a struct containing all scalar outputs?
123
124    // Create the accumulator get function prototypes
125    for (const auto & binding : mScalarOutputs) {
126        FunctionType * accumFnType = FunctionType::get(binding.type, {selfType}, false);
127        Function * accumFn = Function::Create(accumFnType, GlobalValue::ExternalLinkage, getName() + ACCUMULATOR_INFIX + binding.name, client);
128        accumFn->setCallingConv(CallingConv::C);
129        accumFn->setDoesNotThrow();
130        accumFn->setDoesNotCapture(1);
131        auto args = accumFn->arg_begin();
132        args->setName("self");
133    }
134
135    iBuilder->setModule(saveModule);
136    iBuilder->restoreIP(savePoint);
137}
138
139void KernelInterface::setInitialArguments(std::vector<Value *> args) {
140    mInitialArguments = args;
141}
142
143llvm::Function * KernelInterface::getAccumulatorFunction(const std::string & accumName) const {
144    const auto name = getName() + ACCUMULATOR_INFIX + accumName;
145    Function * f = iBuilder->getModule()->getFunction(name);
146    if (LLVM_UNLIKELY(f == nullptr)) {
147        llvm::report_fatal_error("Cannot find " + name);
148    }
149    return f;
150}
151
152Function * KernelInterface::getInitFunction() const {
153    const auto name = getName() + INIT_SUFFIX;
154    Function * f = iBuilder->getModule()->getFunction(name);
155    if (LLVM_UNLIKELY(f == nullptr)) {
156        llvm::report_fatal_error("Cannot find " + name);
157    }
158    return f;
159}
160
161Function * KernelInterface::getDoSegmentFunction() const {
162    const auto name = getName() + DO_SEGMENT_SUFFIX;
163    Function * f = iBuilder->getModule()->getFunction(name);
164    if (LLVM_UNLIKELY(f == nullptr)) {
165        llvm::report_fatal_error("Cannot find " + name);
166    }
167    return f;
168}
Note: See TracBrowser for help on using the repository browser.