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

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

s2p kernel with new infrastructure, includes s2p_FinalBlock

File size: 12.6 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 "streamset.h"
9#include "interface.h"
10
11#include "pipeline.h"
12#include "utf_encoding.h"
13
14#include <kernels/scanmatchgen.h>
15#include <kernels/s2p_kernel.h>
16#include <kernels/instance.h>
17
18#include <pablo/function.h>
19#include <pablo/pablo_compiler.h>
20#include <pablo/pablo_toolchain.h>
21
22#include <llvm/IR/Intrinsics.h>
23#include "llvm/Support/SourceMgr.h"
24#include "llvm/IRReader/IRReader.h"
25#include "llvm/Linker/Linker.h"
26
27using namespace pablo;
28using namespace kernel;
29
30PipelineBuilder::PipelineBuilder(Module * m, IDISA::IDISA_Builder * b)
31: mMod(m)
32, iBuilder(b)
33, mBitBlockType(b->getBitBlockType())
34, mBlockSize(b->getBitBlockWidth()) {
35
36}
37
38PipelineBuilder::~PipelineBuilder() {
39}
40
41void PipelineBuilder::CreateKernels(PabloFunction * function, bool UTF_16, bool isNameExpression){
42    //mS2PKernel = new KernelBuilder(iBuilder, "s2p", codegen::SegmentSize);
43    mICgrepKernel = new KernelBuilder(iBuilder, "icgrep", codegen::SegmentSize);
44    mScanMatchKernel = new KernelBuilder(iBuilder, "scanMatch", codegen::SegmentSize);
45//#define LOAD_S2P_LL
46#ifdef LOAD_S2P_LL
47    SMDiagnostic Err;
48    std::unique_ptr<Module> s2p_Module = parseIRFile("s2p.ll", Err, mMod->getContext());
49    if (!s2p_Module) {
50         Err.print("icgrep", errs());
51         exit(1);
52    }
53    Linker L(*mMod);
54    //s2p_Module->dump();
55    generateScanMatch(mMod, iBuilder, 64, mScanMatchKernel, isNameExpression);
56    L.linkInModule(std::move(s2p_Module));
57    errs() << "s2p.ll loaded\n";
58#else
59    errs() << "A\n";
60    //mS2PKernel = new KernelBuilder(iBuilder, "s2p", codegen::SegmentSize);
61    s2pKernel  s2pk(iBuilder);
62    //s2pk.addKernelDeclarations(mMod);
63    //mMod->dump();
64    std::unique_ptr<Module> s2pM = s2pk.createKernelModule();
65    Linker L(*mMod);
66    L.linkInModule(std::move(s2pM));
67    errs() << "b\n";
68   
69   
70    generateScanMatch(mMod, iBuilder, 64, mScanMatchKernel, isNameExpression);
71#endif
72   
73    pablo_function_passes(function);
74    PabloCompiler pablo_compiler(mMod, iBuilder);
75    try {
76        pablo_compiler.setKernel(mICgrepKernel);
77        pablo_compiler.compile(function);
78        delete function;
79        releaseSlabAllocatorMemory();
80    } catch (std::runtime_error e) {
81        delete function;
82        releaseSlabAllocatorMemory();
83        std::cerr << "Runtime error: " << e.what() << std::endl;
84        exit(1);
85    }
86}
87
88inline Value * generatePopcount(IDISA::IDISA_Builder * iBuilder, Value * bits) {
89    Value * ctpopFunc = Intrinsic::getDeclaration(iBuilder->getModule(), Intrinsic::ctpop, bits->getType());
90    return iBuilder->CreateCall(ctpopFunc, {bits});
91}
92
93inline Value * Cal_Count(Value * match_ptr, IDISA::IDISA_Builder * iBuilder) {
94    Value * matches = iBuilder->CreateLoad(match_ptr, false, "match");
95    return generatePopcount(iBuilder, matches);
96}
97
98Function * PipelineBuilder::ExecuteKernels(bool CountOnly, bool UTF_16) {
99
100    Type * const int64ty = iBuilder->getInt64Ty();
101    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
102    Type * const inputType = PointerType::get(ArrayType::get(ArrayType::get(mBitBlockType, (UTF_16 ? 16 : 8)), 1), 0);
103    Type * const resultTy = CountOnly ? int64ty : iBuilder->getVoidTy();
104    Function * const main = cast<Function>(mMod->getOrInsertFunction("Main", resultTy, inputType, int64ty, int64ty, nullptr));
105    main->setCallingConv(CallingConv::C);
106    Function::arg_iterator args = main->arg_begin();
107
108    Value * const inputStream = &*(args++);
109    inputStream->setName("input");
110    Value * const bufferSize = &*(args++);
111    bufferSize->setName("bufferSize");
112    Value * const fileIdx = &*(args++);
113    fileIdx->setName("fileIdx");
114    errs() << "B\n";
115
116    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", main,0));
117    iBuilder->CallPrintInt("bufferSize", bufferSize); 
118    BasicBlock * entryBlock = iBuilder->GetInsertBlock();
119    BasicBlock * segmentCondBlock = nullptr;
120    BasicBlock * segmentBodyBlock = nullptr;
121    const unsigned segmentSize = codegen::SegmentSize;
122    if (segmentSize > 1) {
123        segmentCondBlock = BasicBlock::Create(mMod->getContext(), "segmentCond", main, 0);
124        segmentBodyBlock = BasicBlock::Create(mMod->getContext(), "segmentBody", main, 0);
125    }
126    BasicBlock * fullCondBlock = BasicBlock::Create(mMod->getContext(), "fullCond", main, 0);
127    BasicBlock * fullBodyBlock = BasicBlock::Create(mMod->getContext(), "fullBody", main, 0);
128    BasicBlock * finalBlock = BasicBlock::Create(mMod->getContext(), "final", main, 0);
129
130    Value * count = nullptr;
131    if (CountOnly) {
132        count = iBuilder->CreateAlloca(mBitBlockType, nullptr, "count");
133        iBuilder->CreateStore(ConstantInt::getNullValue(mBitBlockType), count);
134    }
135    errs() << "C\n";
136
137    Value * s2pI = make_New(iBuilder,  "s2p", {});
138    errs() << "D\n";
139
140    StreamSetBuffer ByteStream(iBuilder, StreamSetType(1, (UTF_16 ? 16 : 8)), 0);
141    ByteStream.setStreamSetBuffer(inputStream);
142   
143    StreamSetBuffer BasisBits(iBuilder, StreamSetType((UTF_16 ? 16 : 8), 1), codegen::SegmentSize);
144    Value * basis_bits_ptr = BasisBits.allocateBuffer();
145   
146    Value * grepI = make_New(iBuilder,  "icgrep", {});
147   
148    StreamSetBuffer MatchResults(iBuilder, StreamSetType(2, 1), codegen::SegmentSize);
149    Value * match_results_ptr = MatchResults.allocateBuffer();
150
151    Instance * scanMatchInstance = nullptr;
152   
153    if (!CountOnly) {
154        scanMatchInstance = mScanMatchKernel->instantiate(match_results_ptr);
155        scanMatchInstance->setInternalState("FileBuf", iBuilder->CreateBitCast(inputStream, int8PtrTy));
156        scanMatchInstance->setInternalState("FileSize", bufferSize);
157        scanMatchInstance->setInternalState("FileIdx", fileIdx);
158    }
159    Value * initialBufferSize = nullptr;
160    Value * initialBlockNo = nullptr;
161    BasicBlock * initialBlock = nullptr;
162
163    if (segmentSize > 1) {
164        iBuilder->CreateBr(segmentCondBlock);
165        iBuilder->SetInsertPoint(segmentCondBlock);
166        PHINode * remainingBytes = iBuilder->CreatePHI(int64ty, 2, "remainingBytes");
167        remainingBytes->addIncoming(bufferSize, entryBlock);
168        PHINode * blockNo = iBuilder->CreatePHI(int64ty, 2, "blockNo");
169        blockNo->addIncoming(iBuilder->getInt64(0), entryBlock);
170        Constant * const step = ConstantInt::get(int64ty, mBlockSize * segmentSize * (UTF_16 ? 2 : 1));
171        Value * segmentCondTest = iBuilder->CreateICmpULT(remainingBytes, step);
172        iBuilder->CreateCondBr(segmentCondTest, fullCondBlock, segmentBodyBlock);
173        iBuilder->SetInsertPoint(segmentBodyBlock);
174        for (unsigned i = 0; i < segmentSize; ++i) {
175            Value * blkNo = iBuilder->CreateAdd(blockNo, iBuilder->getInt64(i));
176            make_DoBlock_Call(iBuilder, "s2p", {s2pI, ByteStream.getBlockPointer(blkNo), BasisBits.getBlockPointer(blkNo)});
177        }
178        for (unsigned i = 0; i < segmentSize; ++i) {
179            Value * blkNo = iBuilder->CreateAdd(blockNo, iBuilder->getInt64(i));
180            match_results_ptr = MatchResults.getBlockPointer(blkNo);
181            make_DoBlock_Call(iBuilder, "icgrep", {grepI, BasisBits.getBlockPointer(blkNo), match_results_ptr});
182            if (CountOnly) {
183                Value * matchptr = iBuilder->CreateGEP(mBitBlockType, match_results_ptr, {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(0)});
184                Value * temp = iBuilder->CreateLoad(matchptr);
185                Value * matches = iBuilder->CreateBitCast(temp, iBuilder->getIntNTy(mBlockSize));
186                Value * popcount_for = generatePopcount(iBuilder, matches);
187                Value * temp_count = iBuilder->CreateLoad(count);
188                Value * prev_count = iBuilder->CreateBitCast(temp_count, iBuilder->getIntNTy(mBlockSize));
189                Value * add_for = iBuilder->CreateAdd(prev_count, popcount_for);
190                Value * add = iBuilder->CreateBitCast(add_for, mBitBlockType);
191                iBuilder->CreateStore(add, count);
192            }
193        }
194        if (!CountOnly) {
195            for (unsigned i = 0; i < segmentSize; ++i) {
196                Value * blkNo = iBuilder->CreateAdd(blockNo, iBuilder->getInt64(i));
197                match_results_ptr = MatchResults.getBlockPointer(blkNo);
198                make_DoBlock_Call(iBuilder, "scanMatch", {scanMatchInstance->getKernelState(), match_results_ptr});
199            }
200        }
201        remainingBytes->addIncoming(iBuilder->CreateSub(remainingBytes, step), segmentBodyBlock);
202        blockNo->addIncoming(iBuilder->CreateAdd(blockNo, iBuilder->getInt64(segmentSize)), segmentBodyBlock);
203        iBuilder->CreateBr(segmentCondBlock);
204        initialBufferSize = remainingBytes;
205        initialBlock = segmentCondBlock;
206        initialBlockNo = blockNo;
207    } else {
208        initialBufferSize = bufferSize;
209        initialBlock = entryBlock;
210        initialBlockNo = iBuilder->getInt64(0);
211        iBuilder->CreateBr(fullCondBlock);
212    }
213
214    iBuilder->SetInsertPoint(fullCondBlock);
215    PHINode * remainingBytes = iBuilder->CreatePHI(int64ty, 2, "remainingBytes");
216    remainingBytes->addIncoming(initialBufferSize, initialBlock);
217    PHINode * blockNo = iBuilder->CreatePHI(int64ty, 2, "blockNo");
218    blockNo->addIncoming(initialBlockNo, initialBlock);
219   
220    Constant * const step = ConstantInt::get(int64ty, mBlockSize * (UTF_16 ? 2 : 1));
221    Value * fullCondTest = iBuilder->CreateICmpULT(remainingBytes, step);
222    iBuilder->CreateCondBr(fullCondTest, finalBlock, fullBodyBlock);
223
224    iBuilder->SetInsertPoint(fullBodyBlock);
225    errs() << "E\n";
226
227    make_DoBlock_Call(iBuilder, "s2p", {s2pI, ByteStream.getBlockPointer(blockNo), BasisBits.getBlockPointer(blockNo)});
228    errs() << "F\n";
229    make_DoBlock_Call(iBuilder, "icgrep", {grepI, BasisBits.getBlockPointer(blockNo), MatchResults.getBlockPointer(blockNo)});
230    if (CountOnly) {
231        Value * matchptr = iBuilder->CreateGEP(mBitBlockType, match_results_ptr, {iBuilder->getInt64(0), iBuilder->getInt32(0)});
232        Value * popcount = Cal_Count(matchptr, iBuilder);
233        Value * temp_count = iBuilder->CreateLoad(count);
234        Value * add = iBuilder->CreateAdd(temp_count, popcount);
235        iBuilder->CreateStore(add, count);
236    } else {
237        make_DoBlock_Call(iBuilder, "scanMatch", {scanMatchInstance->getKernelState(), MatchResults.getBlockPointer(blockNo)});
238    }
239
240    remainingBytes->addIncoming(iBuilder->CreateSub(remainingBytes, step), fullBodyBlock);
241    blockNo->addIncoming(iBuilder->CreateAdd(blockNo, iBuilder->getInt64(1)), fullBodyBlock);
242    iBuilder->CreateBr(fullCondBlock);
243
244    iBuilder->SetInsertPoint(finalBlock);
245    basis_bits_ptr = BasisBits.getBlockPointer(blockNo);
246
247    make_FinalBlock_Call(iBuilder, "s2p", {s2pI, remainingBytes, ByteStream.getBlockPointer(blockNo), basis_bits_ptr});
248   
249    errs() << "G\n";
250
251    Value * remainingByte = iBuilder->CreateZExt(remainingBytes, iBuilder->getIntNTy(mBlockSize));
252    Value * remainingUnit = iBuilder->CreateLShr(remainingByte, ConstantInt::get(iBuilder->getIntNTy(mBlockSize), 1));
253    Value * EOFmark = iBuilder->CreateShl(ConstantInt::get(iBuilder->getIntNTy(mBlockSize), 1), UTF_16 ? remainingUnit : remainingByte);
254    //icGrepInstance->setInternalState("EOFmark", iBuilder->CreateBitCast(EOFmark, mBitBlockType));
255    match_results_ptr = MatchResults.getBlockPointer(blockNo);
256    make_DoBlock_Call(iBuilder, "icgrep", {grepI, basis_bits_ptr, match_results_ptr});
257    errs() << "H\n";
258    if (CountOnly) {
259        Value * matchptr = iBuilder->CreateGEP(mBitBlockType, match_results_ptr, {iBuilder->getInt64(0), iBuilder->getInt32(0)});
260        Value * popcount1 = Cal_Count(matchptr, iBuilder);
261        Value * temp_count1 = iBuilder->CreateLoad(count);
262        Value * result = iBuilder->CreateAdd(temp_count1, popcount1);
263        for (unsigned width = (mBlockSize / 64); width > 1; width /= 2) {
264            std::vector<Constant *> mask(width / 2);
265            for (unsigned i = 0; i < (width / 2); ++i) {
266                mask[i] = iBuilder->getInt32(i);
267            }
268            Value * const undef = UndefValue::get(VectorType::get(int64ty, width));
269            Value * const lh = iBuilder->CreateShuffleVector(result, undef, ConstantVector::get(mask));
270            for (unsigned i = 0; i < (width / 2); ++i) {
271                mask[i] = iBuilder->getInt32(i + (width / 2));
272            }
273            Value * const rh = iBuilder->CreateShuffleVector(result, undef, ConstantVector::get(mask));
274            result = iBuilder->CreateAdd(lh, rh);
275        }
276        iBuilder->CreateRet(iBuilder->CreateExtractElement(result, iBuilder->getInt32(0)));
277    } else {
278        make_DoBlock_Call(iBuilder, "scanMatch", {scanMatchInstance->getKernelState(), match_results_ptr});
279        iBuilder->CreateRetVoid();
280    }
281    return main;
282}
Note: See TracBrowser for help on using the repository browser.