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

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

Initial doSegment support; pipeline generation

File size: 9.0 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    for (int i = 1; i <= doBlockParameters.size(); i++) {
116        doSegmentFn->setDoesNotCapture(i);
117    }
118    iBuilder->setModule(saveModule);
119    iBuilder->restoreIP(savePoint);
120}
121
122
123Value * KernelInterface::createInstance(std::vector<Value *> args) {
124    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
125    Module * m = iBuilder->getModule();
126    std::vector<Value *> init_args = {kernelInstance};
127    for (auto a : args) {
128        init_args.push_back(a);
129    }
130    std::string initFnName = mKernelName + init_suffix;
131    Function * initMethod = m->getFunction(initFnName);
132    if (!initMethod) {
133        throw std::runtime_error("Cannot find " + initFnName);
134        //Or just zero-initialize???
135        //iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), kernelInstance);
136        //return kernelInstance;
137    }
138    iBuilder->CreateCall(initMethod, init_args);
139    return kernelInstance;
140}
141
142Value * KernelInterface::createInstance(std::vector<Value *> args, 
143                                        std::vector<StreamSetBuffer *> inputBuffers,
144                                        std::vector<StreamSetBuffer *> outputBuffers) {
145    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
146    Module * m = iBuilder->getModule();
147    std::vector<Value *> init_args = {kernelInstance};
148    for (auto a : args) {
149        init_args.push_back(a);
150    }
151    for (auto b : inputBuffers) { 
152        init_args.push_back(b->getStreamSetBufferPtr());
153        init_args.push_back(iBuilder->getInt64(b->getSegmentSize() - 1));
154    }
155    for (auto b : outputBuffers) { 
156        init_args.push_back(b->getStreamSetBufferPtr());
157        init_args.push_back(iBuilder->getInt64(b->getSegmentSize() - 1));
158    }
159    std::string initFnName = mKernelName + init_suffix;
160    Function * initMethod = m->getFunction(initFnName);
161    if (!initMethod) {
162        throw std::runtime_error("Cannot find " + initFnName);
163    }
164    iBuilder->CreateCall(initMethod, init_args);
165    return kernelInstance;
166}
167
168
169
170
171Value * KernelInterface::createDoBlockCall(Value * self, std::vector<Value *> streamSets) {
172    Module * m = iBuilder->getModule();
173    std::string doBlockName = mKernelName + doBlock_suffix;
174    Function * doBlockMethod = m->getFunction(doBlockName);
175    if (!doBlockMethod) {
176        throw std::runtime_error("Cannot find " + doBlockName);
177    }
178    std::vector<Value *> args = {self};
179    for (auto ss : streamSets) {
180        args.push_back(ss);
181    }
182    return iBuilder->CreateCall(doBlockMethod, args);
183}
184
185Value * KernelInterface::createFinalBlockCall(Value * self, Value * remainingBytes, std::vector<Value *> streamSets) {
186    Module * m = iBuilder->getModule();
187    std::string finalBlockName = mKernelName + finalBlock_suffix;
188    Function * finalBlockMethod = m->getFunction(finalBlockName);
189    if (!finalBlockMethod) {
190        throw std::runtime_error("Cannot find " + finalBlockName);
191    }
192    std::vector<Value *> args = {self, remainingBytes};
193    for (auto ss : streamSets) {
194        args.push_back(ss);
195    }
196    return iBuilder->CreateCall(finalBlockMethod, args);
197}
198
199Value * KernelInterface::createDoSegmentCall(Value * self, Value * blksToDo) {
200    Module * m = iBuilder->getModule();
201    std::string fnName = mKernelName + doSegment_suffix;
202    Function * method = m->getFunction(fnName);
203    if (!method) {
204        throw std::runtime_error("Cannot find " + fnName);
205    }
206    std::vector<Value *> args = {self, blksToDo};
207    return iBuilder->CreateCall(method, args);
208}
209
210Value * KernelInterface::createGetAccumulatorCall(Value * self, std::string accumName) {
211    Module * m = iBuilder->getModule();
212    std::string fnName = mKernelName + accumulator_infix + accumName;
213    Function * accumMethod = m->getFunction(fnName);
214    if (!accumMethod) {
215        throw std::runtime_error("Cannot find " + fnName);
216    }
217    return iBuilder->CreateCall(accumMethod, {self});
218}
219
220
Note: See TracBrowser for help on using the repository browser.