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

Last change on this file since 5045 was 5045, checked in by xuedongx, 3 years ago

Support over UTF-16 representation of Unicode

File size: 10.1 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 UTF_16, 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        if (UTF_16) {
43                generateS2P_16Kernel(mMod, iBuilder, mS2PKernel);
44        }
45        else {
46                generateS2PKernel(mMod, iBuilder, mS2PKernel);
47        }
48    generateScanMatch(mMod, iBuilder, 64, mScanMatchKernel, isNameExpression);
49    pablo_function_passes(function);
50    PabloCompiler pablo_compiler(mMod, iBuilder);
51    try {
52        pablo_compiler.setKernel(mICgrepKernel);
53        pablo_compiler.compile(function);
54        delete function;
55        releaseSlabAllocatorMemory();
56    } catch (std::runtime_error e) {
57        delete function;
58        releaseSlabAllocatorMemory();
59        std::cerr << "Runtime error: " << e.what() << std::endl;
60        exit(1);
61    }
62}
63
64inline Value * generatePopcount(IDISA::IDISA_Builder * iBuilder, Value * bits) {
65    Value * ctpopFunc = Intrinsic::getDeclaration(iBuilder->getModule(), Intrinsic::ctpop, bits->getType());
66    return iBuilder->CreateCall(ctpopFunc, {bits});
67}
68
69inline Value * Cal_Count(Instance * icGrepInstance, IDISA::IDISA_Builder * iBuilder) {
70    Value * match = icGrepInstance->getOutputStream(0, 0);
71    Value * matches = iBuilder->CreateLoad(match, false, "match");
72    return generatePopcount(iBuilder, matches);
73}
74
75Function * PipelineBuilder::ExecuteKernels(bool CountOnly, bool UTF_16) {
76    Type * const int64ty = iBuilder->getInt64Ty();
77    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
78    Type * const inputType = PointerType::get(ArrayType::get(StructType::get(mMod->getContext(), std::vector<Type *>({ArrayType::get(mBitBlockType, (UTF_16 ? 16 : 8))})), 1), 0);
79    Type * const resultTy = CountOnly ? int64ty : iBuilder->getVoidTy();
80    Function * const main = cast<Function>(mMod->getOrInsertFunction("Main", resultTy, inputType, int64ty, int64ty, iBuilder->getInt1Ty(), nullptr));
81    main->setCallingConv(CallingConv::C);
82    Function::arg_iterator args = main->arg_begin();
83
84    Value * const inputStream = &*(args++);
85    inputStream->setName("input");
86    Value * const bufferSize = &*(args++);
87    bufferSize->setName("bufferSize");
88    Value * const fileIdx = &*(args++);
89    fileIdx->setName("fileIdx");
90    Value * const finalLineUnterminated = &*(args++);
91    finalLineUnterminated->setName("finalLineUnterminated");
92
93    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", main,0));
94
95
96    BasicBlock * entryBlock = iBuilder->GetInsertBlock();
97    BasicBlock * segmentCondBlock = nullptr;
98    BasicBlock * segmentBodyBlock = nullptr;
99    const unsigned segmentSize = codegen::SegmentSize;
100    if (segmentSize > 1) {
101        segmentCondBlock = BasicBlock::Create(mMod->getContext(), "segmentCond", main, 0);
102        segmentBodyBlock = BasicBlock::Create(mMod->getContext(), "segmentBody", main, 0);
103    }
104    BasicBlock * fullCondBlock = BasicBlock::Create(mMod->getContext(), "fullCond", main, 0);
105    BasicBlock * fullBodyBlock = BasicBlock::Create(mMod->getContext(), "fullBody", main, 0);
106    BasicBlock * finalBlock = BasicBlock::Create(mMod->getContext(), "final", main, 0);
107    BasicBlock * finalPartialBlock = BasicBlock::Create(mMod->getContext(), "partial", main, 0);
108    BasicBlock * finalEmptyBlock = BasicBlock::Create(mMod->getContext(), "empty", main, 0);
109    BasicBlock * exitBlock = BasicBlock::Create(mMod->getContext(), "exit", main, 0);
110
111    Value * count = nullptr;
112    if (CountOnly) {
113        count = iBuilder->CreateAlloca(mBitBlockType, nullptr, "count");
114        iBuilder->CreateStore(ConstantInt::getNullValue(mBitBlockType), count);
115    }
116
117    Instance * s2pInstance = mS2PKernel->instantiate(inputStream);
118    Instance * icGrepInstance = mICgrepKernel->instantiate(s2pInstance->getOutputStreamBuffer());
119    Instance * scanMatchInstance = nullptr;
120   
121    if (!CountOnly) {
122        scanMatchInstance = mScanMatchKernel->instantiate(icGrepInstance->getOutputStreamBuffer());
123        scanMatchInstance->setInternalState("FileBuf", iBuilder->CreateBitCast(inputStream, int8PtrTy));
124        scanMatchInstance->setInternalState("FileSize", bufferSize);
125        scanMatchInstance->setInternalState("FileIdx", fileIdx);
126    }
127    Value * initialBufferSize = nullptr;
128    BasicBlock * initialBlock = nullptr;
129
130    if (segmentSize > 1) {
131        iBuilder->CreateBr(segmentCondBlock);
132        iBuilder->SetInsertPoint(segmentCondBlock);
133        PHINode * remainingBytes = iBuilder->CreatePHI(int64ty, 2, "remainingBytes");
134        remainingBytes->addIncoming(bufferSize, entryBlock);
135        Constant * const step = ConstantInt::get(int64ty, mBlockSize * segmentSize * (UTF_16 ? 2 : 1));
136        Value * segmentCondTest = iBuilder->CreateICmpULT(remainingBytes, step);
137        iBuilder->CreateCondBr(segmentCondTest, fullCondBlock, segmentBodyBlock);
138        iBuilder->SetInsertPoint(segmentBodyBlock);
139        for (unsigned i = 0; i < segmentSize; ++i) {
140            s2pInstance->CreateDoBlockCall();
141        }
142        for (unsigned i = 0; i < segmentSize; ++i) {
143            Value * match = (icGrepInstance->getOutputStream(0, 0)); 
144            icGrepInstance->CreateDoBlockCall();
145            Value * temp = iBuilder->CreateLoad(match);
146            Value * matches = iBuilder->CreateBitCast(temp, iBuilder->getIntNTy(mBlockSize));
147            Value * popcount_for = generatePopcount(iBuilder, matches);
148            if(CountOnly){
149                Value * temp_count = iBuilder->CreateLoad(count);
150                Value * prev_count = iBuilder->CreateBitCast(temp_count, iBuilder->getIntNTy(mBlockSize));
151                Value * add_for = iBuilder->CreateAdd(prev_count, popcount_for);
152                Value * add = iBuilder->CreateBitCast(add_for, mBitBlockType);
153                iBuilder->CreateStore(add, count);
154            }
155        }
156        if (!CountOnly) {
157            for (unsigned i = 0; i < segmentSize; ++i) {
158                scanMatchInstance->CreateDoBlockCall();
159            }
160        }
161        remainingBytes->addIncoming(iBuilder->CreateSub(remainingBytes, step), segmentBodyBlock);
162        iBuilder->CreateBr(segmentCondBlock);
163        initialBufferSize = remainingBytes;
164        initialBlock = segmentCondBlock;
165    } else {
166        initialBufferSize = bufferSize;
167        initialBlock = entryBlock;
168        iBuilder->CreateBr(fullCondBlock);
169    }
170
171    iBuilder->SetInsertPoint(fullCondBlock);
172    PHINode * remainingBytes = iBuilder->CreatePHI(int64ty, 2, "remainingBytes");
173    remainingBytes->addIncoming(initialBufferSize, initialBlock);
174
175    Constant * const step = ConstantInt::get(int64ty, mBlockSize * (UTF_16 ? 2 : 1));
176    Value * fullCondTest = iBuilder->CreateICmpULT(remainingBytes, step);
177    iBuilder->CreateCondBr(fullCondTest, finalBlock, fullBodyBlock);
178
179    iBuilder->SetInsertPoint(fullBodyBlock);
180    s2pInstance->CreateDoBlockCall();
181    icGrepInstance->CreateDoBlockCall();
182    if (CountOnly) {
183        Value * popcount = Cal_Count(icGrepInstance, iBuilder);
184        Value * temp_count = iBuilder->CreateLoad(count);
185        Value * add = iBuilder->CreateAdd(temp_count, popcount);
186        iBuilder->CreateStore(add, count);
187    } else {
188        scanMatchInstance->CreateDoBlockCall();
189    }
190
191    remainingBytes->addIncoming(iBuilder->CreateSub(remainingBytes, step), fullBodyBlock);
192    iBuilder->CreateBr(fullCondBlock);
193
194    iBuilder->SetInsertPoint(finalBlock);
195    Value * emptyBlockCond = iBuilder->CreateICmpEQ(remainingBytes, ConstantInt::get(int64ty, 0));
196    iBuilder->CreateCondBr(emptyBlockCond, finalEmptyBlock, finalPartialBlock);
197
198
199    iBuilder->SetInsertPoint(finalPartialBlock);
200    s2pInstance->CreateDoBlockCall();
201    iBuilder->CreateBr(exitBlock);
202
203    iBuilder->SetInsertPoint(finalEmptyBlock);
204    s2pInstance->clearOutputStreamSet();
205    iBuilder->CreateBr(exitBlock);
206
207    iBuilder->SetInsertPoint(exitBlock);
208
209    Value * remainingByte = iBuilder->CreateZExt(remainingBytes, iBuilder->getIntNTy(mBlockSize));
210        Value * remainingUnit = iBuilder->CreateLShr(remainingByte, ConstantInt::get(iBuilder->getIntNTy(mBlockSize), 1));
211    Value * EOFmark = iBuilder->CreateShl(ConstantInt::get(iBuilder->getIntNTy(mBlockSize), 1), UTF_16 ? remainingUnit : remainingByte);
212        icGrepInstance->setInternalState("EOFmark", iBuilder->CreateBitCast(EOFmark, mBitBlockType));
213
214    icGrepInstance->CreateDoBlockCall();
215    if (CountOnly) {
216        Value * popcount1 = Cal_Count(icGrepInstance, iBuilder);
217        Value * temp_count1 = iBuilder->CreateLoad(count);
218        Value * result = iBuilder->CreateAdd(temp_count1, popcount1);
219        for (unsigned width = (mBlockSize / 64); width > 1; width /= 2) {
220            std::vector<Constant *> mask(width / 2);
221            for (unsigned i = 0; i < (width / 2); ++i) {
222                mask[i] = iBuilder->getInt32(i);
223            }
224            Value * const undef = UndefValue::get(VectorType::get(int64ty, width));
225            Value * const lh = iBuilder->CreateShuffleVector(result, undef, ConstantVector::get(mask));
226            for (unsigned i = 0; i < (width / 2); ++i) {
227                mask[i] = iBuilder->getInt32(i + (width / 2));
228            }
229            Value * const rh = iBuilder->CreateShuffleVector(result, undef, ConstantVector::get(mask));
230            result = iBuilder->CreateAdd(lh, rh);
231        }
232        iBuilder->CreateRet(iBuilder->CreateExtractElement(result, iBuilder->getInt32(0)));
233    } else {
234        scanMatchInstance->CreateDoBlockCall();
235        iBuilder->CreateRetVoid();
236    }
237    return main;
238}
Note: See TracBrowser for help on using the repository browser.