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

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

Updated all projects to use ParabixDriver?. Deprecated original pipeline generation methods. Enabled LLVM optimizations, IR and ASM printing for Kernel modules. Enabled object cache by default. Begun work on moving consumed position information back to producing kernels.

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