source: icGREP/icgrep-devel/icgrep/grep_engine.cpp @ 5353

Last change on this file since 5353 was 5353, checked in by nmedfort, 2 years ago

Progress on parenthesis matching example

File size: 31.5 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 *  icgrep is a trademark of International Characters.
5 */
6
7#include "grep_engine.h"
8#include <llvm/IR/Module.h>
9#include <llvm/ExecutionEngine/MCJIT.h>
10#include <llvm/IR/Verifier.h>
11#include <llvm/Support/CommandLine.h>
12#include <boost/filesystem.hpp>
13#include <boost/iostreams/device/mapped_file.hpp>
14#include <IR_Gen/idisa_builder.h>
15#include <IR_Gen/idisa_target.h>
16#include <UCD/UnicodeNameData.h>
17#include <UCD/resolve_properties.h>
18#include <kernels/cc_kernel.h>
19#include <kernels/unicode_linebreak_kernel.h>
20#include <kernels/streams_merge.h>
21#include <kernels/match_count.h>
22#include <kernels/pipeline.h>
23#include <kernels/mmap_kernel.h>
24#include <kernels/s2p_kernel.h>
25#include <kernels/scanmatchgen.h>
26#include <kernels/streamset.h>
27#include <kernels/interface.h>
28#include <pablo/pablo_compiler.h>
29#include <pablo/pablo_kernel.h>
30#include <pablo/pablo_toolchain.h>
31#include <re/re_cc.h>
32#include <re/re_toolchain.h>
33#include <toolchain.h>
34#include <iostream>
35#include <sstream>
36#ifdef CUDA_ENABLED
37#include <IR_Gen/CudaDriver.h>
38#include "preprocess.cpp"
39#endif
40#include <util/aligned_allocator.h>
41
42#define UNICODE_LINE_BREAK (!re::AlgorithmOptionIsSet(re::DisableUnicodeLineBreak))
43
44using namespace parabix;
45using namespace llvm;
46
47static cl::OptionCategory bGrepOutputOptions("Output Options",
48                                             "These options control the output.");
49static cl::opt<bool> SilenceFileErrors("s", cl::desc("Suppress messages for file errors."), cl::init(false),  cl::cat(bGrepOutputOptions));
50
51static cl::opt<bool> SuppressOutput("q", cl::desc("Suppress normal output; set return code only."), cl::init(false),  cl::cat(bGrepOutputOptions));
52
53static cl::opt<bool> NormalizeLineBreaks("normalize-line-breaks", cl::desc("Normalize line breaks to std::endl."), cl::init(false),  cl::cat(bGrepOutputOptions));
54
55static cl::opt<bool> ShowFileNames("H", cl::desc("Show the file name with each matching line."), cl::cat(bGrepOutputOptions));
56static cl::alias ShowFileNamesLong("with-filename", cl::desc("Alias for -H"), cl::aliasopt(ShowFileNames));
57
58static cl::opt<bool> ShowLineNumbers("n", cl::desc("Show the line number with each matching line."), cl::cat(bGrepOutputOptions));
59static cl::alias ShowLineNumbersLong("line-number", cl::desc("Alias for -n"), cl::aliasopt(ShowLineNumbers));
60
61static cl::opt<bool> pipelineParallel("enable-pipeline-parallel", cl::desc("Enable multithreading with pipeline parallelism."), cl::cat(bGrepOutputOptions));
62
63static cl::opt<bool> segmentPipelineParallel("enable-segment-pipeline-parallel", cl::desc("Enable multithreading with segment pipeline parallelism."), cl::cat(bGrepOutputOptions));
64
65bool isUTF_16 = false;
66std::string IRFilename = "icgrep.ll";
67std::string PTXFilename = "icgrep.ptx";
68
69static re::CC * parsedCodePointSet = nullptr;
70static std::vector<std::string> parsedPropertyValues;
71
72#ifdef CUDA_ENABLED
73int blockNo = 0;
74size_t * startPoints = nullptr;
75size_t * accumBytes = nullptr;
76#endif
77
78void GrepEngine::doGrep(const std::string & fileName, const int fileIdx, bool CountOnly, std::vector<size_t> & total_CountOnly, bool UTF_16) {
79    boost::filesystem::path file(fileName);
80    if (exists(file)) {
81        if (is_directory(file)) {
82            return;
83        }
84    } else {
85        if (!SilenceFileErrors) {
86            std::cerr << "Error: cannot open " << fileName << " for processing. Skipped.\n";
87            return;
88        }
89    }
90
91    const auto fileSize = file_size(file);
92    if (fileSize > 0) {
93        try {
94            boost::iostreams::mapped_file_source source(fileName, fileSize, 0);
95            char * fileBuffer = const_cast<char *>(source.data());
96           
97#ifdef CUDA_ENABLED 
98            if(codegen::NVPTX){
99                codegen::BlockSize = 128;
100                char * LineBreak;
101                if (posix_memalign((void**)&LineBreak, 32, fileSize)) {
102                    std::cerr << "Cannot allocate memory for linebreak.\n";
103                    exit(-1);
104                }
105                std::vector<size_t> LFPositions = preprocess(fileBuffer, fileSize, LineBreak);
106
107                const unsigned numOfGroups = codegen::GroupNum;
108                if (posix_memalign((void**)&startPoints, 8, (numOfGroups+1)*sizeof(size_t)) ||
109                    posix_memalign((void**)&accumBytes, 8, (numOfGroups+1)*sizeof(size_t))) {
110                    std::cerr << "Cannot allocate memory for startPoints or accumBytes.\n";
111                    exit(-1);
112                }
113
114                ulong * rslt = RunPTX(PTXFilename, fileBuffer, fileSize, CountOnly, LFPositions, startPoints, accumBytes);
115                if (CountOnly){
116                    exit(0);
117                }
118                else{
119                    size_t intputSize = startPoints[numOfGroups]-accumBytes[numOfGroups]+accumBytes[numOfGroups-1];
120                    mGrepFunction_CPU((char *)rslt, LineBreak, fileBuffer, intputSize, fileIdx);
121                    return;
122                }
123               
124            } 
125#endif
126            if (CountOnly) {
127                total_CountOnly[fileIdx] = mGrepFunction_CountOnly(fileBuffer, fileSize, fileIdx);
128            } else {
129                mGrepFunction(fileBuffer, fileSize, fileIdx);
130            }
131            source.close();
132        } catch (std::exception & e) {
133            if (!SilenceFileErrors) {
134                std::cerr << "Boost mmap error: " + fileName + ": " + e.what() + " Skipped.\n";
135                return;
136            }
137        }
138    } else {
139#ifdef CUDA_ENABLED
140        if (codegen::NVPTX){
141            std::cout << 0 << std::endl;
142            exit(0);
143        }
144#endif
145        if (CountOnly) {
146            total_CountOnly[fileIdx] = mGrepFunction_CountOnly(nullptr, 0, fileIdx);
147        } else {
148            mGrepFunction(nullptr, 0, fileIdx);
149        }
150    }
151}
152
153
154Function * generateGPUKernel(Module * m, IDISA::IDISA_Builder * iBuilder, bool CountOnly){
155    Type * const int64ty = iBuilder->getInt64Ty();
156    Type * const size_ty = iBuilder->getSizeTy();
157    Type * const int32ty = iBuilder->getInt32Ty();
158    Type * const sizeTyPtr = PointerType::get(size_ty, 1);
159    Type * const int64tyPtr = PointerType::get(int64ty, 1);
160    Type * const inputType = PointerType::get(iBuilder->getInt8Ty(), 1);
161    Type * const resultTy = iBuilder->getVoidTy();
162    Function * kernelFunc = cast<Function>(m->getOrInsertFunction("GPU_Main", resultTy, inputType, sizeTyPtr, sizeTyPtr, int64tyPtr, nullptr));
163    kernelFunc->setCallingConv(CallingConv::C);
164    Function::arg_iterator args = kernelFunc->arg_begin();
165
166    Value * const inputPtr = &*(args++);
167    inputPtr->setName("inputPtr");
168    Value * const startPointsPtr = &*(args++);
169    startPointsPtr->setName("startPointsPtr");
170    Value * const bufferSizesPtr = &*(args++);
171    bufferSizesPtr->setName("bufferSizesPtr");
172    Value * const outputPtr = &*(args++);
173    outputPtr->setName("resultPtr");
174
175    BasicBlock * entryBlock = BasicBlock::Create(m->getContext(), "entry", kernelFunc, 0);
176    iBuilder->SetInsertPoint(entryBlock);
177
178    Function * tidFunc = m->getFunction("llvm.nvvm.read.ptx.sreg.tid.x");
179    Value * tid = iBuilder->CreateCall(tidFunc);
180    Function * bidFunc = cast<Function>(m->getOrInsertFunction("llvm.nvvm.read.ptx.sreg.ctaid.x", int32ty, nullptr));
181    Value * bid = iBuilder->CreateCall(bidFunc);
182
183    Value * startPoint = iBuilder->CreateLoad(iBuilder->CreateGEP(startPointsPtr, bid));
184
185    Function * mainFunc = m->getFunction("Main");
186    Value * startBlock = iBuilder->CreateUDiv(startPoint, ConstantInt::get(int64ty, iBuilder->getBitBlockWidth()));
187    Type * const inputStreamType = PointerType::get(ArrayType::get(ArrayType::get(iBuilder->getBitBlockType(), 8), 1), 1);   
188    Value * inputStreamPtr = iBuilder->CreateGEP(iBuilder->CreateBitCast(inputPtr, inputStreamType), startBlock);
189    Value * inputStream = iBuilder->CreateGEP(inputStreamPtr, tid);
190    Value * bufferSize = iBuilder->CreateLoad(iBuilder->CreateGEP(bufferSizesPtr, bid));
191
192    if (CountOnly){
193        Value * strideBlocks = ConstantInt::get(int32ty, iBuilder->getStride() / iBuilder->getBitBlockWidth());
194        Value * outputThreadPtr = iBuilder->CreateGEP(outputPtr, iBuilder->CreateAdd(iBuilder->CreateMul(bid, strideBlocks), tid));
195        Value * result = iBuilder->CreateCall(mainFunc, {inputStream, bufferSize});
196        iBuilder->CreateStore(result, outputThreadPtr);
197    }
198    else {
199        Type * const outputStremType = PointerType::get(ArrayType::get(iBuilder->getBitBlockType(), 1), 1);
200        Value * outputStreamPtr = iBuilder->CreateGEP(iBuilder->CreateBitCast(outputPtr, outputStremType), startBlock);
201        Value * outputStream = iBuilder->CreateGEP(outputStreamPtr, tid);
202        iBuilder->CreateCall(mainFunc, {inputStream, bufferSize, outputStream});
203    }   
204
205    iBuilder->CreateRetVoid();
206    return kernelFunc;
207}
208
209Function * generateCPUKernel(Module * m, IDISA::IDISA_Builder * iBuilder, GrepType grepType){
210    Type * const size_ty = iBuilder->getSizeTy();
211    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
212    Type * const rsltType = PointerType::get(ArrayType::get(iBuilder->getBitBlockType(), 1), 0);
213    Function * const mainCPUFn = cast<Function>(m->getOrInsertFunction("CPU_Main", iBuilder->getVoidTy(), rsltType, rsltType, int8PtrTy, size_ty, size_ty, nullptr));
214    mainCPUFn->setCallingConv(CallingConv::C);
215    iBuilder->SetInsertPoint(BasicBlock::Create(m->getContext(), "entry", mainCPUFn, 0));
216    Function::arg_iterator args = mainCPUFn->arg_begin();
217   
218    Value * const rsltStream = &*(args++);
219    rsltStream->setName("rslt");
220    Value * const lbStream = &*(args++);
221    lbStream->setName("lb");
222    Value * const inputStream = &*(args++);
223    inputStream->setName("input");
224    Value * const fileSize = &*(args++);
225    fileSize->setName("fileSize");
226    Value * const fileIdx = &*(args++);
227    fileIdx->setName("fileIdx");
228
229    const unsigned segmentSize = codegen::SegmentSize;
230   
231    ExternalFileBuffer MatchResults(iBuilder, iBuilder->getStreamSetTy(1, 1));
232    MatchResults.setStreamSetBuffer(rsltStream, fileSize);
233
234    kernel::MMapSourceKernel mmapK1(iBuilder, segmentSize); 
235    mmapK1.setName("mmap1");
236    mmapK1.generateKernel({}, {&MatchResults});
237    mmapK1.setInitialArguments({fileSize});
238
239    ExternalFileBuffer LineBreak(iBuilder, iBuilder->getStreamSetTy(1, 1));
240    LineBreak.setStreamSetBuffer(lbStream, fileSize);
241   
242    kernel::MMapSourceKernel mmapK2(iBuilder, segmentSize); 
243    mmapK2.setName("mmap2");
244    mmapK2.generateKernel({}, {&LineBreak});
245    mmapK2.setInitialArguments({fileSize});
246
247    kernel::ScanMatchKernel scanMatchK(iBuilder, grepType);
248    scanMatchK.generateKernel({&MatchResults, &LineBreak}, {});
249    scanMatchK.setInitialArguments({iBuilder->CreateBitCast(inputStream, int8PtrTy), fileSize, fileIdx});
250   
251    generatePipelineLoop(iBuilder, {&mmapK1, &mmapK2, &scanMatchK});
252    iBuilder->CreateRetVoid();
253
254    return mainCPUFn;
255}
256
257void GrepEngine::multiGrepCodeGen(std::string moduleName, std::vector<re::RE *> REs, bool CountOnly, bool UTF_16, GrepType grepType) {
258
259    isUTF_16 = UTF_16;
260    Module * M = new Module(moduleName + ":icgrep", getGlobalContext());; 
261    IDISA::IDISA_Builder * iBuilder = IDISA::GetIDISA_Builder(M);; 
262
263    const unsigned segmentSize = codegen::SegmentSize;
264    const unsigned bufferSegments = segmentPipelineParallel ? (codegen::BufferSegments * codegen::ThreadNum) : codegen::BufferSegments;
265    const unsigned encodingBits = UTF_16 ? 16 : 8;
266
267    mGrepType = grepType;
268
269    Type * const size_ty = iBuilder->getSizeTy();
270    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
271    Type * const inputType = PointerType::get(ArrayType::get(ArrayType::get(iBuilder->getBitBlockType(), encodingBits), 1), 0);
272    Type * const resultTy = CountOnly ? size_ty : iBuilder->getVoidTy();
273
274    Function * mainFn = cast<Function>(M->getOrInsertFunction("Main", resultTy, inputType, size_ty, size_ty, nullptr));
275    mainFn->setCallingConv(CallingConv::C);
276    iBuilder->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFn, 0));
277    Function::arg_iterator args = mainFn->arg_begin();
278   
279    Value * inputStream = &*(args++);
280    inputStream->setName("input");
281    Value * fileSize = &*(args++);
282    fileSize->setName("fileSize");
283    Value * fileIdx = &*(args++);
284    fileIdx->setName("fileIdx");
285
286    ExternalFileBuffer ByteStream(iBuilder, iBuilder->getStreamSetTy(1, 8));   
287    CircularBuffer BasisBits(iBuilder, iBuilder->getStreamSetTy(8), segmentSize * bufferSegments);
288    ByteStream.setStreamSetBuffer(inputStream, fileSize);
289    BasisBits.allocateBuffer();
290   
291    kernel::MMapSourceKernel mmapK(iBuilder, segmentSize); 
292    mmapK.generateKernel({}, {&ByteStream});
293    mmapK.setInitialArguments({fileSize});
294
295    kernel::S2PKernel  s2pk(iBuilder);
296    s2pk.generateKernel({&ByteStream}, {&BasisBits});
297
298    std::vector<re::CC *> LF;
299    LF.push_back(re::makeCC(0x0A));
300   
301    kernel::UnicodeLineBreakKernelBuilder unicodelbK(iBuilder, "unicodelinebreak", encodingBits);
302    kernel::ParabixCharacterClassKernelBuilder linefeedK(iBuilder, "linefeed", LF, encodingBits);
303
304    std::vector<pablo::PabloKernel *> icgrepKs;
305    std::vector<StreamSetBuffer *> MatchResultsBufs;
306
307    for(unsigned i=0; i<REs.size(); i++){   
308        pablo::PabloKernel * icgrepK = new pablo::PabloKernel(iBuilder, "icgrep"+std::to_string(i), {Binding{iBuilder->getStreamSetTy(8), "basis"}});
309        re::re2pablo_compiler(icgrepK, re::regular_expression_passes(REs[i]), false);
310        pablo_function_passes(icgrepK);
311        icgrepKs.push_back(icgrepK);
312        CircularBuffer * MatchResults = new CircularBuffer(iBuilder, iBuilder->getStreamSetTy(2, 1), segmentSize * bufferSegments);       
313        MatchResults->allocateBuffer();
314        MatchResultsBufs.push_back(MatchResults);
315    }   
316
317    std::vector<kernel::KernelBuilder *> KernelList;
318    KernelList.push_back(&mmapK);
319    KernelList.push_back(&s2pk);
320
321    CircularBuffer mergedResults(iBuilder, iBuilder->getStreamSetTy(1, 1), segmentSize * bufferSegments);
322    mergedResults.allocateBuffer();
323
324    kernel::StreamsMerge streamsMergeK(iBuilder, 1, REs.size());
325    streamsMergeK.generateKernel(MatchResultsBufs, {&mergedResults});
326
327    for(unsigned i=0; i<REs.size(); i++){
328        icgrepKs[i]->generateKernel({&BasisBits}, {MatchResultsBufs[i]});
329        KernelList.push_back(icgrepKs[i]);
330    }
331    KernelList.push_back(&streamsMergeK);
332
333    if (CountOnly) {
334        kernel::MatchCount matchCountK(iBuilder);
335        matchCountK.generateKernel({&mergedResults}, {}); 
336
337        KernelList.push_back(&matchCountK); 
338
339        if (pipelineParallel){
340            generatePipelineParallel(iBuilder, KernelList);
341        } else if (segmentPipelineParallel){
342            generateSegmentParallelPipeline(iBuilder, KernelList);
343        }  else{
344            generatePipelineLoop(iBuilder, KernelList);
345        }
346        iBuilder->CreateRet(matchCountK.getScalarField(matchCountK.getInstance(), "matchedLineCount"));
347
348    }
349    else{
350        pablo::PabloKernel *linebreakK = UNICODE_LINE_BREAK ? &cast<pablo::PabloKernel>(unicodelbK) :  &cast<pablo::PabloKernel>(linefeedK);
351        CircularBuffer LineBreakStream(iBuilder, iBuilder->getStreamSetTy(1, 1), segmentSize * bufferSegments);
352        LineBreakStream.allocateBuffer();
353        linebreakK->generateKernel({&BasisBits}, {&LineBreakStream});
354
355        kernel::ScanMatchKernel scanMatchK(iBuilder, mGrepType);
356        scanMatchK.generateKernel({&mergedResults, &LineBreakStream}, {});               
357        scanMatchK.setInitialArguments({iBuilder->CreateBitCast(inputStream, int8PtrTy), fileSize, fileIdx});
358
359        KernelList.push_back(linebreakK);
360        KernelList.push_back(&scanMatchK);
361
362        if (pipelineParallel){
363            generatePipelineParallel(iBuilder, KernelList);
364        } else if (segmentPipelineParallel){
365            generateSegmentParallelPipeline(iBuilder, KernelList);
366        }  else{
367            generatePipelineLoop(iBuilder, KernelList);
368        }
369       
370        iBuilder->CreateRetVoid();
371    }
372   
373    mEngine = JIT_to_ExecutionEngine(M);
374    ApplyObjectCache(mEngine);
375    icgrep_Linking(M, mEngine);
376
377#ifndef NDEBUG
378    verifyModule(*M, &dbgs());
379#endif
380
381    mEngine->finalizeObject();
382    delete iBuilder;
383   
384    if (CountOnly) {
385        mGrepFunction_CountOnly = reinterpret_cast<GrepFunctionType_CountOnly>(mEngine->getPointerToFunction(mainFn));
386    } else {
387        mGrepFunction = reinterpret_cast<GrepFunctionType>(mEngine->getPointerToFunction(mainFn));
388    }
389
390}
391
392void GrepEngine::grepCodeGen(std::string moduleName, re::RE * re_ast, bool CountOnly, bool UTF_16, GrepType grepType) {
393    isUTF_16 = UTF_16;
394    int addrSpace = 0;
395    bool CPU_Only = true;
396    Module * M = nullptr; 
397    IDISA::IDISA_Builder * iBuilder = nullptr; 
398
399#ifdef CUDA_ENABLED
400    setNVPTXOption(); 
401    if (codegen::NVPTX) {
402        Module * gpuM = new Module(moduleName+":gpu", getGlobalContext());
403        IDISA::IDISA_Builder * GPUBuilder = IDISA::GetIDISA_GPU_Builder(gpuM);
404        M = gpuM;
405        iBuilder = GPUBuilder;
406        M->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64");
407        M->setTargetTriple("nvptx64-nvidia-cuda");
408        addrSpace = 1;
409        CPU_Only = false;
410        codegen::BlockSize = 64;
411    }
412#endif
413
414    Module * cpuM = new Module(moduleName + ":cpu", getGlobalContext());
415    IDISA::IDISA_Builder * CPUBuilder = IDISA::GetIDISA_Builder(cpuM);
416
417    if (CPU_Only) {
418        M = cpuM;
419        iBuilder = CPUBuilder;
420    }
421
422    // segment size made availabe for each call to the mmap source kernel
423    const unsigned segmentSize = codegen::SegmentSize;
424    const unsigned bufferSegments = segmentPipelineParallel ? (codegen::BufferSegments * codegen::ThreadNum) : codegen::BufferSegments;
425    const unsigned encodingBits = UTF_16 ? 16 : 8;
426
427    mGrepType = grepType;
428
429    Type * const size_ty = iBuilder->getSizeTy();
430    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
431    Type * const inputType = PointerType::get(ArrayType::get(ArrayType::get(iBuilder->getBitBlockType(), encodingBits), 1), addrSpace);
432    Type * const resultTy = CountOnly ? size_ty : iBuilder->getVoidTy();
433
434    Function * mainFn = nullptr;
435    Value * inputStream = nullptr;
436    Value * fileSize = nullptr;
437    Value * fileIdx = nullptr;
438
439#ifdef CUDA_ENABLED   
440    Value * outputStream = nullptr;
441    Type * const outputType = PointerType::get(ArrayType::get(iBuilder->getBitBlockType(), 1), addrSpace);
442    if (codegen::NVPTX){
443        if (CountOnly){
444            mainFn = cast<Function>(M->getOrInsertFunction("Main", resultTy, inputType, size_ty, nullptr));
445            mainFn->setCallingConv(CallingConv::C);
446            iBuilder->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFn, 0));
447            Function::arg_iterator args = mainFn->arg_begin();
448           
449            inputStream = &*(args++);
450            inputStream->setName("input");
451            fileSize = &*(args++);
452            fileSize->setName("fileSize");
453        } else {
454            mainFn = cast<Function>(M->getOrInsertFunction("Main", resultTy, inputType, size_ty, outputType, nullptr));
455            mainFn->setCallingConv(CallingConv::C);
456            iBuilder->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFn, 0));
457            Function::arg_iterator args = mainFn->arg_begin();
458           
459            inputStream = &*(args++);
460            inputStream->setName("input");
461            fileSize = &*(args++);
462            fileSize->setName("fileSize");
463            outputStream = &*(args++);
464            outputStream->setName("output");
465        }
466    } 
467#endif
468    if (CPU_Only) {
469        mainFn = cast<Function>(M->getOrInsertFunction("Main", resultTy, inputType, size_ty, size_ty, nullptr));
470        mainFn->setCallingConv(CallingConv::C);
471        iBuilder->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFn, 0));
472        Function::arg_iterator args = mainFn->arg_begin();
473       
474        inputStream = &*(args++);
475        inputStream->setName("input");
476        fileSize = &*(args++);
477        fileSize->setName("fileSize");
478        fileIdx = &*(args++);
479        fileIdx->setName("fileIdx");
480    }
481       
482    ExternalFileBuffer ByteStream(iBuilder, iBuilder->getStreamSetTy(1, 8));
483   
484    kernel::MMapSourceKernel mmapK(iBuilder, segmentSize); 
485    mmapK.generateKernel({}, {&ByteStream});
486    mmapK.setInitialArguments({fileSize});
487   
488    CircularBuffer BasisBits(iBuilder, iBuilder->getStreamSetTy(8), segmentSize * bufferSegments);
489
490    kernel::S2PKernel  s2pk(iBuilder);
491    s2pk.generateKernel({&ByteStream}, {&BasisBits});
492   
493    std::vector<re::CC *> LF;
494    LF.push_back(re::makeCC(0x0A));
495   
496    kernel::UnicodeLineBreakKernelBuilder unicodelbK(iBuilder, "unicodelinebreak", encodingBits);
497    kernel::ParabixCharacterClassKernelBuilder linefeedK(iBuilder, "linefeed", LF, encodingBits);
498
499    pablo::PabloKernel *linebreakK = UNICODE_LINE_BREAK ? &cast<pablo::PabloKernel>(unicodelbK) :  &cast<pablo::PabloKernel>(linefeedK);
500    CircularBuffer LineBreakStream(iBuilder, iBuilder->getStreamSetTy(1, 1), segmentSize * bufferSegments);
501    LineBreakStream.allocateBuffer();
502    linebreakK->generateKernel({&BasisBits}, {&LineBreakStream});
503
504    pablo::PabloKernel icgrepK(iBuilder, "icgrep", {Binding{iBuilder->getStreamSetTy(8), "basis"}});
505    re::re2pablo_compiler(&icgrepK, re::regular_expression_passes(re_ast), CountOnly);
506    pablo_function_passes(&icgrepK);
507
508    ByteStream.setStreamSetBuffer(inputStream, fileSize);
509    BasisBits.allocateBuffer();
510
511    if (CountOnly) {
512        icgrepK.generateKernel({&BasisBits}, {});
513        if (pipelineParallel) {
514            generatePipelineParallel(iBuilder, {&mmapK, &s2pk, &icgrepK});
515        } else if (segmentPipelineParallel) {
516            generateSegmentParallelPipeline(iBuilder, {&mmapK, &s2pk, &icgrepK});
517        } else {
518            generatePipelineLoop(iBuilder, {&mmapK, &s2pk, &icgrepK});
519        }
520        iBuilder->CreateRet(icgrepK.createGetAccumulatorCall(icgrepK.getInstance(), "matchedLineCount"));
521    } else {
522#ifdef CUDA_ENABLED
523        if (codegen::NVPTX){
524            ExternalFileBuffer MatchResults(iBuilder, iBuilder->getStreamSetTy(1, 1), addrSpace);
525            MatchResults.setStreamSetBuffer(outputStream, fileSize);
526
527            icgrepK.generateKernel({&BasisBits},  {&MatchResults});
528            generatePipelineLoop(iBuilder, {&mmapK, &s2pk, &icgrepK});
529
530        }
531#endif
532        if (CPU_Only) {
533            CircularBuffer MatchResults(iBuilder, iBuilder->getStreamSetTy(1, 1), segmentSize * bufferSegments);
534            MatchResults.allocateBuffer();
535
536            icgrepK.generateKernel({&BasisBits}, {&MatchResults});
537
538            kernel::ScanMatchKernel scanMatchK(iBuilder, mGrepType);
539            scanMatchK.generateKernel({&MatchResults, &LineBreakStream}, {});               
540            scanMatchK.setInitialArguments({iBuilder->CreateBitCast(inputStream, int8PtrTy), fileSize, fileIdx});
541           
542            if (pipelineParallel) {
543                generatePipelineParallel(iBuilder, {&mmapK, &s2pk, &icgrepK, linebreakK, &scanMatchK});
544            } else if (segmentPipelineParallel) {
545                generateSegmentParallelPipeline(iBuilder, {&mmapK, &s2pk, &icgrepK, linebreakK, &scanMatchK});
546            } else {
547                generatePipelineLoop(iBuilder, {&mmapK, &s2pk, &icgrepK, linebreakK, &scanMatchK});
548            }
549        }
550        iBuilder->CreateRetVoid();
551    }
552
553#ifdef CUDA_ENABLED
554    Function * mainCPUFn = nullptr;
555    if(codegen::NVPTX){
556        Function * kernelFunction = generateGPUKernel(M, iBuilder, CountOnly);
557        MDNode * Node = MDNode::get(M->getContext(),
558                                    {llvm::ValueAsMetadata::get(kernelFunction),
559                                     MDString::get(M->getContext(), "kernel"), 
560                                     ConstantAsMetadata::get(ConstantInt::get(iBuilder->getInt32Ty(), 1))});
561        NamedMDNode *NMD = M->getOrInsertNamedMetadata("nvvm.annotations");
562        NMD->addOperand(Node);
563   
564        Compile2PTX(M, IRFilename, PTXFilename);
565        mainCPUFn = generateCPUKernel(cpuM, CPUBuilder, mGrepType);
566        if (CountOnly) return;
567    }
568#endif
569
570
571    mEngine = JIT_to_ExecutionEngine(cpuM);
572    ApplyObjectCache(mEngine);
573    icgrep_Linking(cpuM, mEngine);
574
575#ifndef NDEBUG
576    verifyModule(*M, &dbgs());
577#endif
578
579    mEngine->finalizeObject();
580    delete iBuilder;
581   
582    if (CountOnly) {
583        mGrepFunction_CountOnly = reinterpret_cast<GrepFunctionType_CountOnly>(mEngine->getPointerToFunction(mainFn));
584    } else {
585#ifdef CUDA_ENABLED
586        if(codegen::NVPTX){
587            mGrepFunction_CPU = reinterpret_cast<GrepFunctionType_CPU>(mEngine->getPointerToFunction(mainCPUFn));
588        }
589#endif
590        if (CPU_Only) {
591            mGrepFunction = reinterpret_cast<GrepFunctionType>(mEngine->getPointerToFunction(mainFn));
592        }
593    }
594
595}
596
597re::CC * GrepEngine::grepCodepoints() {
598    parsedCodePointSet = re::makeCC();
599    char * mFileBuffer = getUnicodeNameDataPtr();
600    size_t mFileSize = getUnicodeNameDataSize();
601    mGrepFunction(mFileBuffer, mFileSize, 0);
602    return parsedCodePointSet;
603}
604
605const std::vector<std::string> & GrepEngine::grepPropertyValues(const std::string& propertyName) {
606    enum { MaxSupportedVectorWidthInBytes = 32 };
607    AlignedAllocator<char, MaxSupportedVectorWidthInBytes> alloc;
608    parsedPropertyValues.clear();
609    const std::string & str = UCD::getPropertyValueGrepString(propertyName);
610    const auto n = str.length();
611    // NOTE: MaxSupportedVectorWidthInBytes of trailing 0s are needed to prevent the grep function from
612    // erroneously matching garbage data when loading the final partial block.
613    char * aligned = alloc.allocate(n + MaxSupportedVectorWidthInBytes, 0);
614    std::memcpy(aligned, str.data(), n);
615    std::memset(aligned + n, 0, MaxSupportedVectorWidthInBytes);
616    mGrepFunction(aligned, n, 0);
617    alloc.deallocate(aligned, 0);
618    return parsedPropertyValues;
619}
620
621static int * total_count;
622static std::stringstream * resultStrs = nullptr;
623static std::vector<std::string> inputFiles;
624
625void initResult(std::vector<std::string> filenames){
626    const int n = filenames.size();
627    if (n > 1) {
628        ShowFileNames = true;
629    }
630    inputFiles = filenames;
631    resultStrs = new std::stringstream[n];
632    total_count = new int[n];
633    for (unsigned i = 0; i < inputFiles.size(); ++i){
634        total_count[i] = 0;
635    }
636   
637}
638
639extern "C" {
640    void wrapped_report_match(size_t lineNum, size_t line_start, size_t line_end, const char * buffer, size_t filesize, int fileIdx) {
641        assert (buffer);
642#ifdef CUDA_ENABLED
643    if (codegen::NVPTX){
644        while(line_start>startPoints[blockNo]) blockNo++;
645        line_start -= accumBytes[blockNo-1];
646        line_end -= accumBytes[blockNo-1];
647    }
648#endif
649        int index = isUTF_16 ? 2 : 1;
650        int idx = fileIdx;
651         
652        if (ShowFileNames) {
653            resultStrs[idx] << inputFiles[idx] << ':';
654        }
655        if (ShowLineNumbers) {
656            resultStrs[idx] << lineNum << ":";
657        }
658       
659        if ((!isUTF_16 && buffer[line_start] == 0xA) && (line_start != line_end)) {
660            // The line "starts" on the LF of a CRLF.  Really the end of the last line.
661            line_start++;
662        }
663        if (((isUTF_16 && buffer[line_start] == 0x0) && buffer[line_start + 1] == 0xA) && (line_start != line_end)) {
664            // The line "starts" on the LF of a CRLF.  Really the end of the last line.
665            line_start += 2;
666        }
667        if (line_end == filesize) {
668            // The match position is at end-of-file.   We have a final unterminated line.
669            resultStrs[idx].write(&buffer[line_start * index], (line_end - line_start) * index);
670            if (NormalizeLineBreaks) {
671                resultStrs[idx] << '\n';  // terminate it
672            }
673            return;
674        }
675        unsigned char end_byte = (unsigned char)buffer[line_end]; 
676        unsigned char penult_byte = (unsigned char)(buffer[line_end - 1]);
677        if (NormalizeLineBreaks) {
678            if (end_byte == 0x85) {
679                // Line terminated with NEL, on the second byte.  Back up 1.
680                line_end--;
681            } else if (end_byte > 0xD) {
682                // Line terminated with PS or LS, on the third byte.  Back up 2.
683                isUTF_16 ? line_end-- : line_end -= 2;
684            }
685            resultStrs[idx].write(&buffer[line_start * index], (line_end - line_start) * index);
686            resultStrs[idx] << '\n';
687        } else {
688            if ((!isUTF_16 && end_byte == 0x0D) || (isUTF_16 && (end_byte == 0x0D && penult_byte == 0x0))) {
689                // Check for line_end on first byte of CRLF;  note that we don't
690                // want to access past the end of buffer.
691                if (line_end + 1 < filesize) {
692                    if (!isUTF_16 && buffer[line_end + 1] == 0x0A) {
693                        // Found CRLF; preserve both bytes.
694                        line_end++;
695                    }
696                    if (isUTF_16 && buffer[line_end + 1] == 0x0 && buffer[line_end + 2] == 0x0A) {
697                        // Found CRLF; preserve both bytes.
698                        line_end += 2;
699                    }
700                }
701            }
702            resultStrs[idx].write(&buffer[line_start * index], (line_end - line_start + 1) * index);
703        }
704    }
705}
706
707void PrintResult(bool CountOnly, std::vector<size_t> & total_CountOnly){
708   
709    if(CountOnly){
710        if (!ShowFileNames) {
711            for (unsigned i = 0; i < inputFiles.size(); ++i){
712                std::cout << total_CountOnly[i] << std::endl;
713            }
714        }
715        else {
716            for (unsigned i = 0; i < inputFiles.size(); ++i){
717                std::cout << inputFiles[i] << ':' << total_CountOnly[i] << std::endl;
718            };
719        }
720        return;
721    }
722   
723    for (unsigned i = 0; i < inputFiles.size(); ++i){
724        std::cout << resultStrs[i].str();
725    }
726}
727
728extern "C" {
729    void insert_codepoints(size_t lineNum, size_t line_start, size_t line_end, const char * buffer) {
730        assert (buffer);
731        re::codepoint_t c = 0;
732        ssize_t line_pos = line_start;
733        while (isxdigit(buffer[line_pos])) {
734            if (isdigit(buffer[line_pos])) {
735                c = (c << 4) | (buffer[line_pos] - '0');
736            }
737            else {
738                c = (c << 4) | (tolower(buffer[line_pos]) - 'a' + 10);
739            }
740            line_pos++;
741        }
742        assert(((line_pos - line_start) >= 4) && ((line_pos - line_start) <= 6)); // UCD format 4 to 6 hex digits.       
743        parsedCodePointSet->insert(c);
744    }
745}
746
747extern "C" {
748    void insert_property_values(size_t lineNum, size_t line_start, size_t line_end, const char * buffer) {
749        parsedPropertyValues.emplace_back(buffer + line_start, buffer + line_end);
750    }
751}
752
753void icgrep_Linking(Module * m, ExecutionEngine * e) {
754    Module::FunctionListType & fns = m->getFunctionList();
755    for (auto it = fns.begin(), it_end = fns.end(); it != it_end; ++it) {
756        std::string fnName = it->getName().str();
757        if (fnName == "s2p_block") continue;
758        if (fnName == "process_block") continue;
759        if (fnName == "process_block_initialize_carries") continue;
760       
761        if (fnName == "wrapped_report_match") {
762            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&wrapped_report_match);
763        }
764        if (fnName == "insert_codepoints") {
765            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&insert_codepoints);
766        }
767        if (fnName == "insert_property_values") {
768            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&insert_property_values);
769        }
770    }
771}
772
773GrepEngine::GrepEngine()
774: mGrepFunction(nullptr)
775, mGrepFunction_CountOnly(nullptr)
776, mGrepFunction_CPU(nullptr)
777, mGrepType(GrepType::Normal)
778, mEngine(nullptr) {
779
780}
781
782GrepEngine::~GrepEngine() {
783    delete mEngine;
784}
Note: See TracBrowser for help on using the repository browser.