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

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

Set names and attributes for doSegment functions

File size: 9.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/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
15void KernelInterface::addKernelDeclarations(Module * client) {
16    Module * saveModule = iBuilder->getModule();
17    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
18    iBuilder->setModule(client);
19    if (mKernelStateType == nullptr) {
20        throw std::runtime_error("Kernel interface " + mKernelName + " not yet finalized.");
21    }
22    Type * selfType = PointerType::getUnqual(mKernelStateType);
23    // Create the accumulator get function prototypes
24    for (auto binding : mScalarOutputs) {
25        FunctionType * accumFnType = FunctionType::get(binding.scalarType, {selfType}, false);
26        std::string fnName = mKernelName + accumulator_infix + binding.scalarName;
27        Function * accumFn = Function::Create(accumFnType, GlobalValue::ExternalLinkage, fnName, client);
28        accumFn->setCallingConv(CallingConv::C);
29        accumFn->setDoesNotThrow();
30        Value * self = &*(accumFn->arg_begin());
31        self->setName("self");       
32    }
33    // Create the initialization function prototype
34
35    std::vector<Type *> initParameters = {selfType};
36    for (auto binding : mScalarInputs) {
37        initParameters.push_back(binding.scalarType);
38    }
39    FunctionType * initFunctionType = FunctionType::get(iBuilder->getVoidTy(), initParameters, false);
40    std::string initFnName = mKernelName + init_suffix;
41    Function * initFn = Function::Create(initFunctionType, GlobalValue::ExternalLinkage, initFnName, client);
42    initFn->setCallingConv(CallingConv::C);
43    initFn->setDoesNotThrow();
44    Function::arg_iterator initArgs = initFn->arg_begin();
45    Value * initArg = &*(initArgs++);
46    initArg->setName("self");
47    for (auto binding : mScalarInputs) {
48        initArg = &*(initArgs++);
49        initArg->setName(binding.scalarName);
50    }
51
52    // Create the doBlock and finalBlock function prototypes
53   
54    std::vector<Type *> doBlockParameters = {selfType};
55    std::vector<Type *> finalBlockParameters = {selfType, iBuilder->getInt64Ty()};
56    for (auto inputSet : mStreamSetInputs) {
57        Type * inputSetParmType = PointerType::getUnqual(inputSet.ssType.getStreamSetBlockType(iBuilder));
58        doBlockParameters.push_back(inputSetParmType);
59        finalBlockParameters.push_back(inputSetParmType);
60    }
61    for (auto outputSet : mStreamSetOutputs) {
62        Type * outputSetParmType = PointerType::getUnqual(outputSet.ssType.getStreamSetBlockType(iBuilder));
63        doBlockParameters.push_back(outputSetParmType);
64        finalBlockParameters.push_back(outputSetParmType);
65    }
66    FunctionType * doBlockFunctionType = FunctionType::get(mDoBlockReturnType, doBlockParameters, false);
67    std::string doBlockName = mKernelName + doBlock_suffix;
68    Function * doBlockFn = Function::Create(doBlockFunctionType, GlobalValue::ExternalLinkage, doBlockName, client);
69    doBlockFn->setCallingConv(CallingConv::C);
70    doBlockFn->setDoesNotThrow();
71    for (int i = 1; i <= doBlockParameters.size(); i++) {
72        doBlockFn->setDoesNotCapture(i);
73    }
74   
75    FunctionType * finalBlockType = FunctionType::get(mDoBlockReturnType, finalBlockParameters, false);
76    std::string finalBlockName = mKernelName + finalBlock_suffix;
77    Function * finalBlockFn = Function::Create(finalBlockType, GlobalValue::ExternalLinkage, finalBlockName, client);
78    finalBlockFn->setCallingConv(CallingConv::C);
79    finalBlockFn->setDoesNotThrow();
80    finalBlockFn->setDoesNotCapture(1);
81    // Parameter #2 is not a pointer; nocapture is irrelevant
82    for (int i = 3; i <= finalBlockParameters.size(); i++) {
83        finalBlockFn->setDoesNotCapture(i);
84    }
85   
86    Function::arg_iterator doBlockArgs = doBlockFn->arg_begin();
87    Function::arg_iterator finalBlockArgs = finalBlockFn->arg_begin();
88    Value * doBlockArg = &*(doBlockArgs++);
89    doBlockArg->setName("self");
90    Value * finalBlockArg = &*(finalBlockArgs++);
91    finalBlockArg->setName("self");
92    finalBlockArg = &*(finalBlockArgs++);
93    finalBlockArg->setName("remainingBytes");
94
95    for (auto inputSet : mStreamSetInputs) {
96        doBlockArg = &*(doBlockArgs++);
97        finalBlockArg = &*(finalBlockArgs++);
98        doBlockArg->setName(inputSet.ssName);
99        finalBlockArg->setName(inputSet.ssName);
100    }
101    for (auto outputSet : mStreamSetOutputs) {
102        doBlockArg = &*(doBlockArgs++);
103        finalBlockArg = &*(finalBlockArgs++);
104        doBlockArg->setName(outputSet.ssName);
105        finalBlockArg->setName(outputSet.ssName);
106    }
107   
108    // Create the doSegment function prototype.
109    std::vector<Type *> doSegmentParameters = {selfType, iBuilder->getInt64Ty()};
110    FunctionType * doSegmentFunctionType = FunctionType::get(mDoBlockReturnType, doSegmentParameters, false);
111    std::string doSegmentName = mKernelName + doSegment_suffix;
112    Function * doSegmentFn = Function::Create(doSegmentFunctionType, GlobalValue::ExternalLinkage, doSegmentName, client);
113    doSegmentFn->setCallingConv(CallingConv::C);
114    doSegmentFn->setDoesNotThrow();
115    Function::arg_iterator args = doSegmentFn->arg_begin();
116    Value * arg = &*(args++);
117    arg->setName("self");
118    arg = &*(args++);
119    arg->setName("blockCnt");
120    doSegmentFn->setDoesNotCapture(1); // for self parameter only.
121    iBuilder->setModule(saveModule);
122    iBuilder->restoreIP(savePoint);
123}
124
125
126Value * KernelInterface::createInstance(std::vector<Value *> args) {
127    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
128    Module * m = iBuilder->getModule();
129    std::vector<Value *> init_args = {kernelInstance};
130    for (auto a : args) {
131        init_args.push_back(a);
132    }
133    std::string initFnName = mKernelName + init_suffix;
134    Function * initMethod = m->getFunction(initFnName);
135    if (!initMethod) {
136        throw std::runtime_error("Cannot find " + initFnName);
137        //Or just zero-initialize???
138        //iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), kernelInstance);
139        //return kernelInstance;
140    }
141    iBuilder->CreateCall(initMethod, init_args);
142    return kernelInstance;
143}
144
145Value * KernelInterface::createInstance(std::vector<Value *> args, 
146                                        std::vector<StreamSetBuffer *> inputBuffers,
147                                        std::vector<StreamSetBuffer *> outputBuffers) {
148    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
149    Module * m = iBuilder->getModule();
150    std::vector<Value *> init_args = {kernelInstance};
151    for (auto a : args) {
152        init_args.push_back(a);
153    }
154    for (auto b : inputBuffers) { 
155        init_args.push_back(b->getStreamSetBufferPtr());
156        init_args.push_back(iBuilder->getInt64(b->getSegmentSize() - 1));
157    }
158    for (auto b : outputBuffers) { 
159        init_args.push_back(b->getStreamSetBufferPtr());
160        init_args.push_back(iBuilder->getInt64(b->getSegmentSize() - 1));
161    }
162    std::string initFnName = mKernelName + init_suffix;
163    Function * initMethod = m->getFunction(initFnName);
164    if (!initMethod) {
165        throw std::runtime_error("Cannot find " + initFnName);
166    }
167    iBuilder->CreateCall(initMethod, init_args);
168    return kernelInstance;
169}
170
171
172
173
174Value * KernelInterface::createDoBlockCall(Value * self, std::vector<Value *> streamSets) {
175    Module * m = iBuilder->getModule();
176    std::string doBlockName = mKernelName + doBlock_suffix;
177    Function * doBlockMethod = m->getFunction(doBlockName);
178    if (!doBlockMethod) {
179        throw std::runtime_error("Cannot find " + doBlockName);
180    }
181    std::vector<Value *> args = {self};
182    for (auto ss : streamSets) {
183        args.push_back(ss);
184    }
185    return iBuilder->CreateCall(doBlockMethod, args);
186}
187
188Value * KernelInterface::createFinalBlockCall(Value * self, Value * remainingBytes, std::vector<Value *> streamSets) {
189    Module * m = iBuilder->getModule();
190    std::string finalBlockName = mKernelName + finalBlock_suffix;
191    Function * finalBlockMethod = m->getFunction(finalBlockName);
192    if (!finalBlockMethod) {
193        throw std::runtime_error("Cannot find " + finalBlockName);
194    }
195    std::vector<Value *> args = {self, remainingBytes};
196    for (auto ss : streamSets) {
197        args.push_back(ss);
198    }
199    return iBuilder->CreateCall(finalBlockMethod, args);
200}
201
202Value * KernelInterface::createDoSegmentCall(Value * self, Value * blksToDo) {
203    Module * m = iBuilder->getModule();
204    std::string fnName = mKernelName + doSegment_suffix;
205    Function * method = m->getFunction(fnName);
206    if (!method) {
207        throw std::runtime_error("Cannot find " + fnName);
208    }
209    std::vector<Value *> args = {self, blksToDo};
210    return iBuilder->CreateCall(method, args);
211}
212
213Value * KernelInterface::createGetAccumulatorCall(Value * self, std::string accumName) {
214    Module * m = iBuilder->getModule();
215    std::string fnName = mKernelName + accumulator_infix + accumName;
216    Function * accumMethod = m->getFunction(fnName);
217    if (!accumMethod) {
218        throw std::runtime_error("Cannot find " + fnName);
219    }
220    return iBuilder->CreateCall(accumMethod, {self});
221}
222
223
Note: See TracBrowser for help on using the repository browser.