source: icGREP/icgrep-devel/icgrep/kernels/kernel.cpp @ 4926

Last change on this file since 4926 was 4926, checked in by lindanl, 4 years ago

Update kernel builder.

File size: 9.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 "kernel.h"
7#include <iostream>
8
9// sets name & sets internal state to the kernel superclass state
10KernelBuilder::KernelBuilder(std::string name, Module * m, IDISA::IDISA_Builder * b)
11: mMod(m)
12, iBuilder(b)
13, mKernelName(name)
14, mPredifinedStates(2)
15, mBitBlockType(b->getBitBlockType())
16, mBlockSize(b->getBitBlockWidth()){
17    mStates = std::vector<Type *>(4, b->getIntNTy(64)); 
18    mSegmentBlocks = 1;
19    mBufferSize = mSegmentBlocks * mBlockSize;
20}
21
22KernelBuilder::~KernelBuilder(){
23}
24
25int KernelBuilder::extendKernelInternalStateType(Type * t){
26    int idx = mStates.size();
27    mStates.push_back(t);
28    return idx;
29}
30void KernelBuilder::addKernelOutputStream(int fw){
31    if (fw == 1){
32        mOutputStreams.push_back(mBitBlockType);
33    }
34    else {
35        mOutputStreams.push_back(ArrayType::get(mBitBlockType, fw));
36    }
37
38}
39void KernelBuilder::addKernelOutputAccum(Type * t){
40    mOutputAccums.push_back(t);
41
42}
43void KernelBuilder::addKernelInputStream(int fw, std::string name = ""){
44    if (name=="")
45        mInputStreamNames.push_back(mKernelName + "_inputstream_" + std::to_string(mInputStreams.size()));
46    else
47        mInputStreamNames.push_back(name);
48
49    if (fw == 1){
50        mInputStreams.push_back(mBitBlockType);
51    }
52    else {
53        mInputStreams.push_back(ArrayType::get(mBitBlockType, fw));
54    }
55}
56void KernelBuilder::addKernelInputScalar(Type * t, std::string name = ""){
57    if (name=="")
58        mInputScalarNames.push_back(mKernelName + "_inputscalar_" + std::to_string(mInputScalars.size()));
59    else
60        mInputScalarNames.push_back(name);
61
62    mInputScalars.push_back(t);
63}
64
65Function* KernelBuilder::CreateDoBlockFunction(){ 
66    Type * inputStreamType = PointerType::get(ArrayType::get(StructType::get(mMod->getContext(), mInputStreams), mSegmentBlocks), 0);
67    Type * inputScalarType = PointerType::get(StructType::get(mMod->getContext(), mInputScalars), 0);
68    Type * outputStreamType = ArrayType::get(StructType::get(mMod->getContext(), mOutputStreams), mSegmentBlocks);
69    Type * outputAccumType = StructType::get(mMod->getContext(), mOutputAccums);
70    Type * stateType = StructType::create(mMod->getContext(), mStates, mKernelName);
71    mKernelStructType = StructType::create(mMod->getContext(),std::vector<Type *>({stateType, outputStreamType, outputAccumType}), "KernelStruct_"+mKernelName);
72 
73   
74    FunctionType * functionType = FunctionType::get(Type::getVoidTy(mMod->getContext()), 
75        std::vector<Type *>({PointerType::get(mKernelStructType, 0), inputStreamType, inputScalarType}), false); 
76       
77    mDoBlockFunction = Function::Create(functionType, GlobalValue::ExternalLinkage, mKernelName + "_DoBlock", mMod);
78    mDoBlockFunction->setCallingConv(CallingConv::C);
79
80    return mDoBlockFunction;
81}
82
83//create doBlock method with empty body and load inputs
84struct Inputs KernelBuilder::openDoBlock(){
85   
86
87    Function::arg_iterator args = mDoBlockFunction->arg_begin();
88    mKernelStructParam = args++;
89    mKernelStructParam->setName("this");
90    Value* input_stream_param = args++;
91    input_stream_param->setName("input_stream");
92    Value* input_scalar_param = args++;
93    input_scalar_param->setName("input_scalar");
94
95    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mDoBlockFunction,0));
96
97    // std::vector<std::vector<valptr>> inputs;
98    struct Inputs inputs;
99    for(int j = 0; j<mSegmentBlocks; j++){
100        for(int i = 0; i<mInputStreams.size(); i++){
101            Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(j), iBuilder->getInt32(i)};
102            Value * gep = iBuilder->CreateGEP(input_stream_param, indices);
103            Type * t = gep->getType()->getPointerElementType();
104            if (t != mBitBlockType) {
105                int arraySize = t->getArrayNumElements();
106                inputs.streams.resize(mSegmentBlocks, std::vector<valptr>(arraySize));
107                for (int k=0; k<arraySize; k++){
108                    Value * gep_array_elem = iBuilder->CreateGEP(gep, {iBuilder->getInt32(0), iBuilder->getInt32(k)});
109                    inputs.streams[j][k] = iBuilder->CreateAlignedLoad(gep_array_elem, mBlockSize/8, false, mInputStreamNames.at(i));
110                }
111            }
112            else{
113                inputs.streams.resize(mSegmentBlocks, std::vector<valptr>(mInputStreams.size()));
114                inputs.streams[j][i] = iBuilder->CreateAlignedLoad(gep, mBlockSize/8, false, mInputStreamNames.at(i));
115            }
116           
117        }
118    }
119
120    inputs.scalars.resize(mInputScalars.size());
121    for(int i = 0; i<mInputScalars.size(); i++){
122        Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(i)};
123        Value * gep = iBuilder->CreateGEP(input_scalar_param, indices);
124        inputs.scalars[i] = iBuilder->CreateAlignedLoad(gep, mBlockSize/8, false, mInputScalarNames.at(i));
125    }
126
127    return inputs;
128}
129
130void KernelBuilder::closeDoBlock(struct Outputs result){
131   
132
133    for(int j=0; j<mSegmentBlocks; j++){
134        for(int i = 0; i<mOutputStreams.size(); i++){   
135            Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(1), iBuilder->getInt32(j), iBuilder->getInt32(i)};
136            Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
137            iBuilder->CreateAlignedStore(result.streams[j][i], gep, mBlockSize/8, false);
138        }
139    }
140
141    for(int i = 0; i<mOutputAccums.size(); i++){   
142        Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(2), iBuilder->getInt32(i)};
143        Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
144        iBuilder->CreateAlignedStore(result.accums[i], gep, mBlockSize/8, false);
145    }
146
147    iBuilder->CreateRetVoid();
148}
149
150void KernelBuilder::changeKernelInternalState(int idx, Value * stateValue){
151    Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(idx)};
152    Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
153    iBuilder->CreateAlignedStore(stateValue, gep, mBlockSize/8, false);
154}
155
156Value * KernelBuilder::getKernelInternalState(int idx){
157    Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(idx)};
158    Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
159    return iBuilder->CreateAlignedLoad(gep, mBlockSize/8, false, "state"+std::to_string(idx));
160}
161
162Value * KernelBuilder::getKernelInternalStatePtr(int idx){
163    Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(idx)};
164    Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
165    return gep;
166}
167
168void KernelBuilder::finalizeMethods(){
169    Type * T = iBuilder->getIntNTy(64);
170
171    Constant* c = mMod->getOrInsertFunction(mKernelName+"_Init", Type::getVoidTy(mMod->getContext()), PointerType::get(mKernelStructType, 0), NULL);
172    Function* mInitFunction = cast<Function>(c);
173    mInitFunction->setCallingConv(CallingConv::C);
174    Function::arg_iterator args = mInitFunction->arg_begin();
175
176    Value* this_param = args++;
177    this_param->setName("this");
178
179    int i = mPredifinedStates;
180    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mInitFunction, 0));
181    Value * gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(i++) }));
182    iBuilder->CreateStore(iBuilder->getInt64(0), gep);  //FileBasePos
183    gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(i++) }));
184    iBuilder->CreateStore(iBuilder->getInt64(0), gep);  //AvailableBlocks
185
186    while(i < mStates.size()){
187        gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(i++) }));
188        // iBuilder->CreateStore(iBuilder->getInt64(0), gep);
189        // std::cerr << "size = " << mMod->getDataLayout()->getTypeAllocSize(mStates[i]) << std::endl;
190        // iBuilder->CreateMemSet(gep, iBuilder->getInt8(0), mMod->getDataLayout()->getTypeAllocSize(mStates[i]), 4);
191    }
192
193    iBuilder->CreateRetVoid();
194
195    c = mMod->getOrInsertFunction(mKernelName+"_Create_Default", Type::getVoidTy(mMod->getContext()), PointerType::get(mKernelStructType, 0), T, T, NULL);
196    Function* mConstructor = cast<Function>(c);
197    mConstructor->setCallingConv(CallingConv::C);
198    args = mConstructor->arg_begin();
199
200    this_param = args++;
201    this_param->setName("this");
202    Value* block_size_param = args++;
203    block_size_param->setName("block_size");
204    Value* seg_size_param = args++;
205    seg_size_param->setName("seg_size");
206
207    //initialize blockz_size and seg_size in Constructor not in init function
208    //allocate buffer
209    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mConstructor, 0));
210    gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(0) }));
211    iBuilder->CreateStore(block_size_param, gep);   
212    gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(1) }));
213    iBuilder->CreateStore(seg_size_param, gep); 
214
215    iBuilder->CreateCall(mInitFunction, this_param);
216    iBuilder->CreateRetVoid();
217
218}
219//alloc space & set buffer size
220void KernelBuilder::generateKernelInstance(int segmentBlocks = 1){
221
222    mKernelStruct = iBuilder->CreateAlloca(mKernelStructType); 
223    iBuilder->CreateCall3(mConstructor, mKernelStruct, 
224        ConstantInt::get(iBuilder->getIntNTy(64), mBlockSize), 
225        ConstantInt::get(iBuilder->getIntNTy(64), mBufferSize));
226
227}
228void KernelBuilder::generateInitCall(){
229    iBuilder->CreateCall(mInitFunction, mKernelStruct);
230}
231
232// Value * KernelBuilder::generateDoBlockCall(Value * inputBuffer){
233//     iBuilder->CreateCall3(mDoBlockFunction, mKernelStruct, inputBuffer, outputBuffer);
234//     return outputBuffer;
235// }
236
237int KernelBuilder::getSegmentBlocks(){
238    return mSegmentBlocks;
239}
240
Note: See TracBrowser for help on using the repository browser.