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

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

Kernel interface provides only those services used for building pipelines

File size: 7.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    errs() << "KernelInterface::addKernelDeclarations\n";
17    Module * saveModule = iBuilder->getModule();
18    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
19    iBuilder->setModule(client);
20    if (mKernelStateType == nullptr) {
21        throw std::runtime_error("Kernel interface " + mKernelName + " not yet finalized.");
22    }
23    Type * selfType = PointerType::getUnqual(mKernelStateType);
24    // Create the accumulator get function prototypes
25    for (auto binding : mScalarOutputs) {
26        FunctionType * accumFnType = FunctionType::get(binding.scalarType, {selfType}, false);
27        std::string fnName = mKernelName + accumulator_infix + binding.scalarName;
28        Function * accumFn = Function::Create(accumFnType, GlobalValue::ExternalLinkage, fnName, client);
29        accumFn->setCallingConv(CallingConv::C);
30        accumFn->setDoesNotThrow();
31        Value * self = &*(accumFn->arg_begin());
32        self->setName("self");       
33    }
34    // Create the initialization function prototype
35
36    std::vector<Type *> initParameters = {selfType};
37    for (auto binding : mScalarInputs) {
38        initParameters.push_back(binding.scalarType);
39    }
40    FunctionType * initFunctionType = FunctionType::get(iBuilder->getVoidTy(), initParameters, false);
41    std::string initFnName = mKernelName + init_suffix;
42    Function * initFn = Function::Create(initFunctionType, GlobalValue::ExternalLinkage, initFnName, client);
43    initFn->setCallingConv(CallingConv::C);
44    initFn->setDoesNotThrow();
45    Function::arg_iterator initArgs = initFn->arg_begin();
46    Value * initArg = &*(initArgs++);
47    initArg->setName("self");
48    for (auto binding : mScalarInputs) {
49        initArg = &*(initArgs++);
50        initArg->setName(binding.scalarName);
51    }
52
53    // Create the doBlock and finalBlock function prototypes
54   
55    std::vector<Type *> doBlockParameters = {selfType};
56    std::vector<Type *> finalBlockParameters = {selfType, iBuilder->getInt64Ty()};
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    FunctionType * doBlockFunctionType = FunctionType::get(iBuilder->getVoidTy(), doBlockParameters, false);
68    std::string doBlockName = mKernelName + doBlock_suffix;
69    Function * doBlockFn = Function::Create(doBlockFunctionType, GlobalValue::ExternalLinkage, doBlockName, client);
70    doBlockFn->setCallingConv(CallingConv::C);
71    doBlockFn->setDoesNotThrow();
72    for (int i = 1; i <= doBlockParameters.size(); i++) {
73        doBlockFn->setDoesNotCapture(i);
74    }
75   
76    FunctionType * finalBlockType = FunctionType::get(iBuilder->getVoidTy(), finalBlockParameters, false);
77    std::string finalBlockName = mKernelName + finalBlock_suffix;
78    Function * finalBlockFn = Function::Create(finalBlockType, GlobalValue::ExternalLinkage, finalBlockName, client);
79    finalBlockFn->setCallingConv(CallingConv::C);
80    finalBlockFn->setDoesNotThrow();
81    finalBlockFn->setDoesNotCapture(1);
82    // Parameter #2 is not a pointer; nocapture is irrelevant
83    for (int i = 3; i <= finalBlockParameters.size(); i++) {
84        finalBlockFn->setDoesNotCapture(i);
85    }
86   
87    Function::arg_iterator doBlockArgs = doBlockFn->arg_begin();
88    Function::arg_iterator finalBlockArgs = finalBlockFn->arg_begin();
89    Value * doBlockArg = &*(doBlockArgs++);
90    doBlockArg->setName("self");
91    Value * finalBlockArg = &*(finalBlockArgs++);
92    finalBlockArg->setName("self");
93    finalBlockArg = &*(finalBlockArgs++);
94    finalBlockArg->setName("remainingBytes");
95
96    for (auto inputSet : mStreamSetInputs) {
97        doBlockArg = &*(doBlockArgs++);
98        finalBlockArg = &*(finalBlockArgs++);
99        doBlockArg->setName(inputSet.ssName);
100        finalBlockArg->setName(inputSet.ssName);
101    }
102    for (auto outputSet : mStreamSetOutputs) {
103        doBlockArg = &*(doBlockArgs++);
104        finalBlockArg = &*(finalBlockArgs++);
105        doBlockArg->setName(outputSet.ssName);
106        finalBlockArg->setName(outputSet.ssName);
107    }
108    iBuilder->setModule(saveModule);
109    iBuilder->restoreIP(savePoint);
110}
111
112
113Value * KernelInterface::createInstance(std::vector<Value *> args) {
114    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
115    Module * m = iBuilder->getModule();
116    std::vector<Value *> init_args = {kernelInstance};
117    for (auto a : args) {
118        init_args.push_back(a);
119    }
120    std::string initFnName = mKernelName + init_suffix;
121    Function * initMethod = m->getFunction(initFnName);
122    if (!initMethod) {
123        throw std::runtime_error("Cannot find " + initFnName);
124        //Or just zero-initialize???
125        //iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), kernelInstance);
126        //return kernelInstance;
127    }
128    iBuilder->CreateCall(initMethod, init_args);
129    return kernelInstance;
130}
131
132Value * KernelInterface::createDoBlockCall(Value * self, std::vector<Value *> streamSets) {
133    Module * m = iBuilder->getModule();
134    std::string doBlockName = mKernelName + doBlock_suffix;
135    Function * doBlockMethod = m->getFunction(doBlockName);
136    if (!doBlockMethod) {
137        throw std::runtime_error("Cannot find " + doBlockName);
138    }
139    std::vector<Value *> args = {self};
140    for (auto ss : streamSets) {
141        args.push_back(ss);
142    }
143    return iBuilder->CreateCall(doBlockMethod, args);
144}
145
146Value * KernelInterface::createFinalBlockCall(Value * self, Value * remainingBytes, std::vector<Value *> streamSets) {
147    Module * m = iBuilder->getModule();
148    std::string finalBlockName = mKernelName + finalBlock_suffix;
149    Function * finalBlockMethod = m->getFunction(finalBlockName);
150    if (!finalBlockMethod) {
151        throw std::runtime_error("Cannot find " + finalBlockName);
152    }
153    std::vector<Value *> args = {self, remainingBytes};
154    for (auto ss : streamSets) {
155        args.push_back(ss);
156    }
157    return iBuilder->CreateCall(finalBlockMethod, args);
158}
159
160Value * KernelInterface::createGetAccumulatorCall(Value * self, std::string accumName) {
161    Module * m = iBuilder->getModule();
162    std::string fnName = mKernelName + accumulator_infix + accumName;
163    Function * accumMethod = m->getFunction(fnName);
164    if (!accumMethod) {
165        throw std::runtime_error("Cannot find " + fnName);
166    }
167    return iBuilder->CreateCall(accumMethod, {self});
168}
169
170
Note: See TracBrowser for help on using the repository browser.