source: icGREP/icgrep-devel/icgrep/kernels/pipeline.cpp @ 5033

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

Refactor: move grep-specific code out of toolchain

File size: 9.8 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
7#include <toolchain.h>
8#include "pipeline.h"
9#include "utf_encoding.h"
10
11#include <kernels/scanmatchgen.h>
12#include <kernels/s2p_kernel.h>
13#include <kernels/instance.h>
14
15#include <pablo/function.h>
16#include <pablo/pablo_compiler.h>
17#include <pablo/pablo_toolchain.h>
18
19#include <llvm/IR/Intrinsics.h>
20
21using namespace pablo;
22using namespace kernel;
23
24PipelineBuilder::PipelineBuilder(Module * m, IDISA::IDISA_Builder * b)
25: mMod(m)
26, iBuilder(b)
27, mBitBlockType(b->getBitBlockType())
28, mBlockSize(b->getBitBlockWidth()) {
29
30}
31
32PipelineBuilder::~PipelineBuilder() {
33    delete mS2PKernel;
34    delete mICgrepKernel;
35    delete mScanMatchKernel;
36}
37
38void PipelineBuilder::CreateKernels(PabloFunction * function, bool isNameExpression){
39    mS2PKernel = new KernelBuilder(iBuilder, "s2p", codegen::SegmentSize);
40    mICgrepKernel = new KernelBuilder(iBuilder, "icgrep", codegen::SegmentSize);
41    mScanMatchKernel = new KernelBuilder(iBuilder, "scanMatch", codegen::SegmentSize);
42    generateS2PKernel(mMod, iBuilder, mS2PKernel);
43    generateScanMatch(mMod, iBuilder, 64, mScanMatchKernel, isNameExpression);
44    pablo_function_passes(function);
45    PabloCompiler pablo_compiler(mMod, iBuilder);
46    try {
47        pablo_compiler.setKernel(mICgrepKernel);
48        pablo_compiler.compile(function);
49        delete function;
50        releaseSlabAllocatorMemory();
51    } catch (std::runtime_error e) {
52        delete function;
53        releaseSlabAllocatorMemory();
54        std::cerr << "Runtime error: " << e.what() << std::endl;
55        exit(1);
56    }
57}
58
59Value * generatePopcount(IDISA::IDISA_Builder * iBuilder, Value * bits) {
60    Value * ctpopFunc = Intrinsic::getDeclaration(iBuilder->getModule(), Intrinsic::ctpop, bits->getType());
61    return iBuilder->CreateCall(ctpopFunc, std::vector<Value *>({bits}));
62}
63
64Value * Cal_Count(Instance * icGrepInstance, IDISA::IDISA_Builder * iBuilder, int mBlockSize) {
65    const unsigned index = 0;
66    const unsigned streamOffset = 0;
67    Value * match = (icGrepInstance->getOutputStream(index, streamOffset));
68    Value * temp = iBuilder->CreateLoad(match);
69    Value * matches = iBuilder->CreateBitCast(temp, iBuilder->getIntNTy(mBlockSize));
70    Value * popcount = generatePopcount(iBuilder, matches);
71    return popcount;
72}
73
74Function * PipelineBuilder::ExecuteKernels(bool CountOnly) {
75    Type * const int64ty = iBuilder->getInt64Ty();
76    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
77    Type * const inputType = PointerType::get(ArrayType::get(StructType::get(mMod->getContext(), std::vector<Type *>({ArrayType::get(mBitBlockType, 8)})), 1), 0);
78
79    Function * const main = cast<Function>(mMod->getOrInsertFunction("Main", Type::getVoidTy(mMod->getContext()), inputType, int64ty, int64ty, iBuilder->getInt1Ty(), nullptr));
80    main->setCallingConv(CallingConv::C);
81    Function::arg_iterator args = main->arg_begin();
82
83    Value * const inputStream = &*(args++);
84    inputStream->setName("input");
85    Value * const bufferSize = &*(args++);
86    bufferSize->setName("bufferSize");
87    Value * const fileIdx = &*(args++);
88    fileIdx->setName("fileIdx");
89    Value * const finalLineUnterminated = &*(args++);
90    finalLineUnterminated->setName("finalLineUnterminated");
91
92    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", main,0));
93
94
95    BasicBlock * entryBlock = iBuilder->GetInsertBlock();
96    BasicBlock * segmentCondBlock = nullptr;
97    BasicBlock * segmentBodyBlock = nullptr;
98    const unsigned segmentSize = codegen::SegmentSize;
99    if (segmentSize > 1) {
100        segmentCondBlock = BasicBlock::Create(mMod->getContext(), "segmentCond", main, 0);
101        segmentBodyBlock = BasicBlock::Create(mMod->getContext(), "segmentBody", main, 0);
102    }
103    BasicBlock * fullCondBlock = BasicBlock::Create(mMod->getContext(), "fullCond", main, 0);
104    BasicBlock * fullBodyBlock = BasicBlock::Create(mMod->getContext(), "fullBody", main, 0);
105    BasicBlock * finalBlock = BasicBlock::Create(mMod->getContext(), "final", main, 0);
106    BasicBlock * finalPartialBlock = BasicBlock::Create(mMod->getContext(), "partial", main, 0);
107    BasicBlock * finalEmptyBlock = BasicBlock::Create(mMod->getContext(), "empty", main, 0);
108    BasicBlock * endBlock = BasicBlock::Create(mMod->getContext(), "end", main, 0);
109    BasicBlock * unterminatedBlock = BasicBlock::Create(mMod->getContext(), "unterminated", main, 0);
110    BasicBlock * exitBlock = BasicBlock::Create(mMod->getContext(), "exit", main, 0);
111
112    Value * count = iBuilder->CreateAlloca (Type::getIntNTy(mMod->getContext(), mBlockSize), nullptr, "count");
113    Value * num = ConstantInt::get(iBuilder->getIntNTy(mBlockSize), 0);
114    iBuilder->CreateStore(num, count, false);
115
116    Instance * s2pInstance = mS2PKernel->instantiate(inputStream);
117    Instance * icGrepInstance = mICgrepKernel->instantiate(s2pInstance->getOutputStreamBuffer());
118    Instance * scanMatchInstance = mScanMatchKernel->instantiate(icGrepInstance->getOutputStreamBuffer());
119   
120    if(!CountOnly) {
121        scanMatchInstance->setInternalState("FileBuf", iBuilder->CreateBitCast(inputStream, int8PtrTy));
122        scanMatchInstance->setInternalState("FileSize", bufferSize);
123        scanMatchInstance->setInternalState("FileIdx", fileIdx);
124    }
125    Value * initialBufferSize = nullptr;
126    BasicBlock * initialBlock = nullptr;
127
128    if (segmentSize > 1) {
129        iBuilder->CreateBr(segmentCondBlock);
130        iBuilder->SetInsertPoint(segmentCondBlock);
131        PHINode * remainingBytes = iBuilder->CreatePHI(int64ty, 2, "remainingBytes");
132        remainingBytes->addIncoming(bufferSize, entryBlock);
133        Constant * const step = ConstantInt::get(int64ty, mBlockSize * segmentSize);
134        Value * segmentCondTest = iBuilder->CreateICmpULT(remainingBytes, step);
135        iBuilder->CreateCondBr(segmentCondTest, fullCondBlock, segmentBodyBlock);
136        iBuilder->SetInsertPoint(segmentBodyBlock);
137        for (unsigned i = 0; i < segmentSize; ++i) {
138            s2pInstance->CreateDoBlockCall();
139        }
140        for (unsigned i = 0; i < segmentSize; ++i) {
141            icGrepInstance->CreateDoBlockCall();
142            if(CountOnly){
143                Value * popcount_for = Cal_Count(icGrepInstance, iBuilder, mBlockSize);
144                Value * temp_countfor = iBuilder->CreateLoad(count);
145                Value * add_for = iBuilder->CreateAdd(temp_countfor, popcount_for);
146                iBuilder->CreateStore(add_for, count);
147            }
148        }
149        if(!CountOnly) {
150            for (unsigned i = 0; i < segmentSize; ++i) {
151                scanMatchInstance->CreateDoBlockCall();
152            }
153        }
154        remainingBytes->addIncoming(iBuilder->CreateSub(remainingBytes, step), segmentBodyBlock);
155        iBuilder->CreateBr(segmentCondBlock);
156        initialBufferSize = remainingBytes;
157        initialBlock = segmentCondBlock;
158    } else {
159        initialBufferSize = bufferSize;
160        initialBlock = entryBlock;
161        iBuilder->CreateBr(fullCondBlock);
162    }
163
164    iBuilder->SetInsertPoint(fullCondBlock);
165    PHINode * remainingBytes = iBuilder->CreatePHI(int64ty, 2, "remainingBytes");
166    remainingBytes->addIncoming(initialBufferSize, initialBlock);
167
168    Constant * const step = ConstantInt::get(int64ty, mBlockSize);
169    Value * fullCondTest = iBuilder->CreateICmpULT(remainingBytes, step);
170    iBuilder->CreateCondBr(fullCondTest, finalBlock, fullBodyBlock);
171
172    iBuilder->SetInsertPoint(fullBodyBlock);
173    s2pInstance->CreateDoBlockCall();
174    icGrepInstance->CreateDoBlockCall();
175    if(CountOnly){
176        Value * popcount = Cal_Count(icGrepInstance, iBuilder, mBlockSize);   
177        Value * temp_count = iBuilder->CreateLoad(count);
178        Value * add = iBuilder->CreateAdd(temp_count, popcount);
179        iBuilder->CreateStore(add, count);
180    }
181
182    if(!CountOnly) {
183        scanMatchInstance->CreateDoBlockCall();
184    }
185
186    remainingBytes->addIncoming(iBuilder->CreateSub(remainingBytes, step), fullBodyBlock);
187    iBuilder->CreateBr(fullCondBlock);
188
189    iBuilder->SetInsertPoint(finalBlock);
190    Value * const b4 = s2pInstance->getOutputStream(4);
191    Value * const b6 = s2pInstance->getOutputStream(6);
192    Value * emptyBlockCond = iBuilder->CreateICmpEQ(remainingBytes, ConstantInt::get(int64ty, 0));
193    iBuilder->CreateCondBr(emptyBlockCond, finalEmptyBlock, finalPartialBlock);
194
195
196    iBuilder->SetInsertPoint(finalPartialBlock);
197    s2pInstance->CreateDoBlockCall();
198    iBuilder->CreateBr(endBlock);
199
200    iBuilder->SetInsertPoint(finalEmptyBlock);
201    s2pInstance->clearOutputStreamSet();
202    iBuilder->CreateBr(endBlock);
203
204    iBuilder->SetInsertPoint(endBlock);
205    Value * isFinalLineUnterminated = iBuilder->CreateICmpEQ(finalLineUnterminated, ConstantInt::getNullValue(finalLineUnterminated->getType()));
206    iBuilder->CreateCondBr(isFinalLineUnterminated, exitBlock, unterminatedBlock);
207   
208    iBuilder->SetInsertPoint(unterminatedBlock);
209
210    Value * remaining = iBuilder->CreateZExt(remainingBytes, iBuilder->getIntNTy(mBlockSize));
211    Value * EOF_pos = iBuilder->CreateShl(ConstantInt::get(iBuilder->getIntNTy(mBlockSize), 1), remaining);
212    EOF_pos = iBuilder->CreateBitCast(EOF_pos, mBitBlockType);
213
214
215    Value * b4val = iBuilder->CreateBlockAlignedLoad(b4);
216    b4val = iBuilder->CreateOr(b4val, EOF_pos);
217    iBuilder->CreateBlockAlignedStore(b4val, b4);
218
219    Value * b6val = iBuilder->CreateBlockAlignedLoad(b6);
220    b6val = iBuilder->CreateOr(b6val, EOF_pos);
221    iBuilder->CreateBlockAlignedStore(b6val, b6);
222
223    iBuilder->CreateBr(exitBlock);
224
225    iBuilder->SetInsertPoint(exitBlock);
226
227    icGrepInstance->CreateDoBlockCall();
228    if(CountOnly){
229        Value * popcount1 = Cal_Count(icGrepInstance, iBuilder, mBlockSize);   
230        Value * temp_count1 = iBuilder->CreateLoad(count);
231        Value * add1 = iBuilder->CreateAdd(temp_count1, popcount1);
232        iBuilder->CreateStore(add1, count);
233    }
234    if(!CountOnly) {
235        scanMatchInstance->CreateDoBlockCall();
236    }
237    if(CountOnly){
238        Value * Ret = iBuilder->CreateLoad(count);
239        iBuilder->CreateRet(Ret);
240    }
241    else{
242        iBuilder->CreateRetVoid();
243    }
244
245
246    return main;
247}
Note: See TracBrowser for help on using the repository browser.