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

Last change on this file since 5049 was 5049, checked in by cameron, 3 years ago

Set parameter names and attributes for kernel methods

File size: 7.7 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/Module.h>
8#include <llvm/IR/Type.h>
9#include <llvm/IR/Value.h>
10#include <llvm/Support/raw_ostream.h>
11
12using namespace llvm;
13using namespace kernel;
14
15KernelInterface::KernelInterface(IDISA::IDISA_Builder * builder,
16                                 std::string kernelName,
17                                 std::vector<StreamSetBinding> stream_inputs,
18                                 std::vector<StreamSetBinding> stream_outputs,
19                                 std::vector<ScalarBinding> scalar_parameters,
20                                 std::vector<ScalarBinding> scalar_outputs,
21                                 std::vector<ScalarBinding> internal_scalars) {
22    iBuilder = builder;
23    mKernelName = kernelName;
24    mStreamSetInputs = stream_inputs;
25    mStreamSetOutputs = stream_outputs;
26    mScalarInputs = scalar_parameters;
27    mScalarOutputs = scalar_outputs;
28    mInternalScalars = internal_scalars;
29    std::vector<Type *> kernelFields;
30    for (auto binding : scalar_parameters) {
31        unsigned index = kernelFields.size();
32        kernelFields.push_back(binding.scalarType);
33        mInternalStateNameMap.emplace(binding.scalarName, iBuilder->getInt32(index));
34    }
35    for (auto binding : scalar_outputs) {
36        unsigned index = kernelFields.size();
37        kernelFields.push_back(binding.scalarType);
38        mInternalStateNameMap.emplace(binding.scalarName, iBuilder->getInt32(index));
39    }
40    for (auto binding : internal_scalars) {
41        unsigned index = kernelFields.size();
42        kernelFields.push_back(binding.scalarType);
43        mInternalStateNameMap.emplace(binding.scalarName, iBuilder->getInt32(index));
44    }
45    mKernelStateType = StructType::create(getGlobalContext(), kernelFields, kernelName);
46}
47
48void KernelInterface::addKernelDeclarations(Module * client) {
49   
50    Type * selfType = PointerType::getUnqual(mKernelStateType);
51    // Create the accumulator get function prototypes
52    for (auto binding : mScalarOutputs) {
53        FunctionType * accumFnType = FunctionType::get(binding.scalarType, {selfType}, false);
54        Function * accumFn = Function::Create(accumFnType, GlobalValue::ExternalLinkage, mKernelName + "_get_" + binding.scalarName, client);
55        accumFn->setCallingConv(CallingConv::C);
56        accumFn->setDoesNotThrow();
57        Value * self = &*(accumFn->arg_begin());
58        self->setName("self");       
59    }
60    // Create the initialization function prototype
61
62    std::vector<Type *> initParameters = {selfType};
63    for (auto binding : mScalarInputs) {
64        initParameters.push_back(binding.scalarType);
65    }
66    FunctionType * initFunctionType = FunctionType::get(iBuilder->getVoidTy(), initParameters, false);
67    Function * initFn = Function::Create(initFunctionType, GlobalValue::ExternalLinkage, mKernelName + "_Init", client);
68    initFn->setCallingConv(CallingConv::C);
69    initFn->setDoesNotThrow();
70    Function::arg_iterator initArgs = initFn->arg_begin();
71    Value * initArg = &*(initArgs++);
72    initArg->setName("self");
73    for (auto binding : mScalarInputs) {
74        initArg = &*(initArgs++);
75        initArg->setName(binding.scalarName);
76    }
77
78    // Create the doBlock and finalBlock function prototypes
79   
80    std::vector<Type *> doBlockParameters = {selfType};
81    std::vector<Type *> finalBlockParameters = {selfType, iBuilder->getInt64Ty()};
82    for (auto inputSet : mStreamSetInputs) {
83        Type * inputSetParmType = PointerType::getUnqual(inputSet.ssType.getStreamSetBlockType(iBuilder));
84        doBlockParameters.push_back(inputSetParmType);
85        finalBlockParameters.push_back(inputSetParmType);
86    }
87    for (auto outputSet : mStreamSetOutputs) {
88        Type * outputSetParmType = PointerType::getUnqual(outputSet.ssType.getStreamSetBlockType(iBuilder));
89        doBlockParameters.push_back(outputSetParmType);
90        finalBlockParameters.push_back(outputSetParmType);
91    }
92    FunctionType * doBlockFunctionType = FunctionType::get(iBuilder->getVoidTy(), doBlockParameters, false);
93    Function * doBlockFn = Function::Create(doBlockFunctionType, GlobalValue::ExternalLinkage, mKernelName + "_DoBlock", client);
94    doBlockFn->setCallingConv(CallingConv::C);
95    doBlockFn->setDoesNotThrow();
96    for (int i = 1; i <= doBlockParameters.size(); i++) {
97        doBlockFn->setDoesNotCapture(i);
98    }
99   
100    FunctionType * finalBlockFunctionType = FunctionType::get(iBuilder->getVoidTy(), finalBlockParameters, false);
101    Function * finalBlockFn = Function::Create(finalBlockFunctionType, GlobalValue::ExternalLinkage, mKernelName + "_FinalBlock", client);
102    finalBlockFn->setCallingConv(CallingConv::C);
103    finalBlockFn->setDoesNotThrow();
104    finalBlockFn->setDoesNotCapture(1);
105    // Parameter #2 is not a pointer; nocapture is irrelevant
106    for (int i = 3; i <= finalBlockParameters.size(); i++) {
107        finalBlockFn->setDoesNotCapture(i);
108    }
109   
110    Function::arg_iterator doBlockArgs = doBlockFn->arg_begin();
111    Function::arg_iterator finalBlockArgs = finalBlockFn->arg_begin();
112    Value * doBlockArg = &*(doBlockArgs++);
113    doBlockArg->setName("self");
114    Value * finalBlockArg = &*(finalBlockArgs++);
115    finalBlockArg->setName("self");
116    finalBlockArg = &*(finalBlockArgs++);
117    finalBlockArg->setName("remainingBytes");
118
119    for (auto inputSet : mStreamSetInputs) {
120        doBlockArg = &*(doBlockArgs++);
121        finalBlockArg = &*(finalBlockArgs++);
122        doBlockArg->setName(inputSet.ssName);
123        finalBlockArg->setName(inputSet.ssName);
124    }
125    for (auto outputSet : mStreamSetOutputs) {
126        doBlockArg = &*(doBlockArgs++);
127        finalBlockArg = &*(finalBlockArgs++);
128        doBlockArg->setName(outputSet.ssName);
129        finalBlockArg->setName(outputSet.ssName);
130    }
131}
132
133
134std::unique_ptr<Module> KernelInterface::createKernelModule() {
135    std::unique_ptr<Module> theModule = llvm::make_unique<Module>(mKernelName, getGlobalContext());
136    addKernelDeclarations(theModule.get());
137   
138    // Implement the accumulator get functions
139    for (auto binding : mScalarOutputs) {
140        auto fnName = mKernelName + "_get_" + binding.scalarName;
141        Function * accumFn = theModule->getFunction(fnName);
142        iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "get_" + binding.scalarName, accumFn, 0));
143        Value * self = &*(accumFn->arg_begin());
144        const auto f = mInternalStateNameMap.find(binding.scalarName);
145        if (LLVM_UNLIKELY(f == mInternalStateNameMap.end())) {
146            throw std::runtime_error("Kernel does not contain internal state " + binding.scalarName);
147        }
148        Value * idx = f->second;
149        Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), idx});
150        Value * retVal = iBuilder->CreateLoad(ptr);
151        iBuilder->CreateRet(retVal);
152    }
153   
154    // Implement the initializer function
155    Function * initFunction = theModule->getFunction(mKernelName + "_Init");
156    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "Init_entry", initFunction, 0));
157   
158    Function::arg_iterator args = initFunction->arg_begin();
159    Value * self = &*(args++);
160    iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), self);
161    for (auto binding : mScalarInputs) {
162        Value * parm = &*(args++);
163        const auto f = mInternalStateNameMap.find(binding.scalarName);
164        if (LLVM_UNLIKELY(f == mInternalStateNameMap.end())) {
165            throw std::runtime_error("Kernel does not contain internal state " + binding.scalarName);
166        }
167        Value * idx = f->second;
168        Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), idx});
169        iBuilder->CreateStore(ptr, parm);
170    }
171    iBuilder->CreateRetVoid();
172    return theModule;
173}
Note: See TracBrowser for help on using the repository browser.