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

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

Simplify kernel DoBlock? interface

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    /*
57    for (auto inputSet : mStreamSetInputs) {
58        Type * inputSetParmType = PointerType::getUnqual(inputSet.ssType.getStreamSetBlockType(iBuilder));
59        doBlockParameters.push_back(inputSetParmType);
60        finalBlockParameters.push_back(inputSetParmType);
61    }
62    for (auto outputSet : mStreamSetOutputs) {
63        Type * outputSetParmType = PointerType::getUnqual(outputSet.ssType.getStreamSetBlockType(iBuilder));
64        doBlockParameters.push_back(outputSetParmType);
65        finalBlockParameters.push_back(outputSetParmType);
66    }
67     */
68    FunctionType * doBlockFunctionType = FunctionType::get(mDoBlockReturnType, doBlockParameters, false);
69    std::string doBlockName = mKernelName + doBlock_suffix;
70    Function * doBlockFn = Function::Create(doBlockFunctionType, GlobalValue::ExternalLinkage, doBlockName, client);
71    doBlockFn->setCallingConv(CallingConv::C);
72    doBlockFn->setDoesNotThrow();
73    for (int i = 1; i <= doBlockParameters.size(); i++) {
74        doBlockFn->setDoesNotCapture(i);
75    }
76   
77    FunctionType * finalBlockType = FunctionType::get(mDoBlockReturnType, finalBlockParameters, false);
78    std::string finalBlockName = mKernelName + finalBlock_suffix;
79    Function * finalBlockFn = Function::Create(finalBlockType, GlobalValue::ExternalLinkage, finalBlockName, client);
80    finalBlockFn->setCallingConv(CallingConv::C);
81    finalBlockFn->setDoesNotThrow();
82    finalBlockFn->setDoesNotCapture(1);
83    // Parameter #2 is not a pointer; nocapture is irrelevant
84    for (int i = 3; i <= finalBlockParameters.size(); i++) {
85        finalBlockFn->setDoesNotCapture(i);
86    }
87   
88    Function::arg_iterator doBlockArgs = doBlockFn->arg_begin();
89    Function::arg_iterator finalBlockArgs = finalBlockFn->arg_begin();
90    Value * doBlockArg = &*(doBlockArgs++);
91    doBlockArg->setName("self");
92    Value * finalBlockArg = &*(finalBlockArgs++);
93    finalBlockArg->setName("self");
94    finalBlockArg = &*(finalBlockArgs++);
95    finalBlockArg->setName("remainingBytes");
96
97/*    for (auto inputSet : mStreamSetInputs) {
98        doBlockArg = &*(doBlockArgs++);
99        finalBlockArg = &*(finalBlockArgs++);
100        doBlockArg->setName(inputSet.ssName);
101        finalBlockArg->setName(inputSet.ssName);
102    }
103    for (auto outputSet : mStreamSetOutputs) {
104        doBlockArg = &*(doBlockArgs++);
105        finalBlockArg = &*(finalBlockArgs++);
106        doBlockArg->setName(outputSet.ssName);
107        finalBlockArg->setName(outputSet.ssName);
108    }
109    */
110    // Create the doSegment function prototype.
111    std::vector<Type *> doSegmentParameters = {selfType, iBuilder->getInt64Ty()};
112    FunctionType * doSegmentFunctionType = FunctionType::get(mDoBlockReturnType, doSegmentParameters, false);
113    std::string doSegmentName = mKernelName + doSegment_suffix;
114    Function * doSegmentFn = Function::Create(doSegmentFunctionType, GlobalValue::ExternalLinkage, doSegmentName, client);
115    doSegmentFn->setCallingConv(CallingConv::C);
116    doSegmentFn->setDoesNotThrow();
117    Function::arg_iterator args = doSegmentFn->arg_begin();
118    Value * arg = &*(args++);
119    arg->setName("self");
120    arg = &*(args++);
121    arg->setName("blockCnt");
122    doSegmentFn->setDoesNotCapture(1); // for self parameter only.
123    iBuilder->setModule(saveModule);
124    iBuilder->restoreIP(savePoint);
125}
126
127
128Value * KernelInterface::createInstance(std::vector<Value *> args) {
129    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
130    Module * m = iBuilder->getModule();
131    std::vector<Value *> init_args = {kernelInstance};
132    for (auto a : args) {
133        init_args.push_back(a);
134    }
135    std::string initFnName = mKernelName + init_suffix;
136    Function * initMethod = m->getFunction(initFnName);
137    if (!initMethod) {
138        throw std::runtime_error("Cannot find " + initFnName);
139        //Or just zero-initialize???
140        //iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), kernelInstance);
141        //return kernelInstance;
142    }
143    iBuilder->CreateCall(initMethod, init_args);
144    return kernelInstance;
145}
146
147Value * KernelInterface::createInstance(std::vector<Value *> args, 
148                                        std::vector<StreamSetBuffer *> inputBuffers,
149                                        std::vector<StreamSetBuffer *> outputBuffers) {
150    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
151    Module * m = iBuilder->getModule();
152    std::vector<Value *> init_args = {kernelInstance};
153    for (auto a : args) {
154        init_args.push_back(a);
155    }
156    for (auto b : inputBuffers) { 
157        init_args.push_back(b->getStreamSetBufferPtr());
158        init_args.push_back(iBuilder->getInt64(b->getSegmentSize() - 1));
159    }
160    for (auto b : outputBuffers) { 
161        init_args.push_back(b->getStreamSetBufferPtr());
162        init_args.push_back(iBuilder->getInt64(b->getSegmentSize() - 1));
163    }
164    std::string initFnName = mKernelName + init_suffix;
165    Function * initMethod = m->getFunction(initFnName);
166    if (!initMethod) {
167        throw std::runtime_error("Cannot find " + initFnName);
168    }
169    iBuilder->CreateCall(initMethod, init_args);
170    return kernelInstance;
171}
172
173Value * KernelInterface::createDoBlockCall(Value * self) {
174    Module * m = iBuilder->getModule();
175    std::string doBlockName = mKernelName + doBlock_suffix;
176    Function * doBlockMethod = m->getFunction(doBlockName);
177    if (!doBlockMethod) {
178        throw std::runtime_error("Cannot find " + doBlockName);
179    }
180    std::vector<Value *> args = {self};
181    return iBuilder->CreateCall(doBlockMethod, args);
182}
183
184Value * KernelInterface::createFinalBlockCall(Value * self, Value * remainingBytes) {
185    Module * m = iBuilder->getModule();
186    std::string finalBlockName = mKernelName + finalBlock_suffix;
187    Function * finalBlockMethod = m->getFunction(finalBlockName);
188    if (!finalBlockMethod) {
189        throw std::runtime_error("Cannot find " + finalBlockName);
190    }
191    std::vector<Value *> args = {self, remainingBytes};
192    return iBuilder->CreateCall(finalBlockMethod, args);
193}
194
195
196Value * KernelInterface::createDoSegmentCall(Value * self, Value * blksToDo) {
197    Module * m = iBuilder->getModule();
198    std::string fnName = mKernelName + doSegment_suffix;
199    Function * method = m->getFunction(fnName);
200    if (!method) {
201        throw std::runtime_error("Cannot find " + fnName);
202    }
203    std::vector<Value *> args = {self, blksToDo};
204    return iBuilder->CreateCall(method, args);
205}
206
207Value * KernelInterface::createGetAccumulatorCall(Value * self, std::string accumName) {
208    Module * m = iBuilder->getModule();
209    std::string fnName = mKernelName + accumulator_infix + accumName;
210    Function * accumMethod = m->getFunction(fnName);
211    if (!accumMethod) {
212        throw std::runtime_error("Cannot find " + fnName);
213    }
214    return iBuilder->CreateCall(accumMethod, {self});
215}
216
217
Note: See TracBrowser for help on using the repository browser.