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

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

Updates for kernels with variable output length; stdout kernel

File size: 6.9 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    iBuilder->setModule(saveModule);
108    iBuilder->restoreIP(savePoint);
109}
110
111
112Value * KernelInterface::createInstance(std::vector<Value *> args) {
113    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
114    Module * m = iBuilder->getModule();
115    std::vector<Value *> init_args = {kernelInstance};
116    for (auto a : args) {
117        init_args.push_back(a);
118    }
119    std::string initFnName = mKernelName + init_suffix;
120    Function * initMethod = m->getFunction(initFnName);
121    if (!initMethod) {
122        throw std::runtime_error("Cannot find " + initFnName);
123        //Or just zero-initialize???
124        //iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), kernelInstance);
125        //return kernelInstance;
126    }
127    iBuilder->CreateCall(initMethod, init_args);
128    return kernelInstance;
129}
130
131Value * KernelInterface::createDoBlockCall(Value * self, std::vector<Value *> streamSets) {
132    Module * m = iBuilder->getModule();
133    std::string doBlockName = mKernelName + doBlock_suffix;
134    Function * doBlockMethod = m->getFunction(doBlockName);
135    if (!doBlockMethod) {
136        throw std::runtime_error("Cannot find " + doBlockName);
137    }
138    std::vector<Value *> args = {self};
139    for (auto ss : streamSets) {
140        args.push_back(ss);
141    }
142    return iBuilder->CreateCall(doBlockMethod, args);
143}
144
145Value * KernelInterface::createFinalBlockCall(Value * self, Value * remainingBytes, std::vector<Value *> streamSets) {
146    Module * m = iBuilder->getModule();
147    std::string finalBlockName = mKernelName + finalBlock_suffix;
148    Function * finalBlockMethod = m->getFunction(finalBlockName);
149    if (!finalBlockMethod) {
150        throw std::runtime_error("Cannot find " + finalBlockName);
151    }
152    std::vector<Value *> args = {self, remainingBytes};
153    for (auto ss : streamSets) {
154        args.push_back(ss);
155    }
156    return iBuilder->CreateCall(finalBlockMethod, args);
157}
158
159Value * KernelInterface::createGetAccumulatorCall(Value * self, std::string accumName) {
160    Module * m = iBuilder->getModule();
161    std::string fnName = mKernelName + accumulator_infix + accumName;
162    Function * accumMethod = m->getFunction(fnName);
163    if (!accumMethod) {
164        throw std::runtime_error("Cannot find " + fnName);
165    }
166    return iBuilder->CreateCall(accumMethod, {self});
167}
168
169
Note: See TracBrowser for help on using the repository browser.