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

Last change on this file since 5585 was 5585, checked in by xuedongx, 21 months ago

use multiplexed character classes as the input to grep kernel, restructure the icGrep pipeline: Matches = RE_compiler<regexp>(CharacterClasses?, LineBreaks?)

File size: 29.3 KB
Line 
1/*
2 *  Copyright (c) 2017 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 "grep_interface.h"
9#include <llvm/IR/Module.h>
10#include <boost/filesystem.hpp>
11#include <UCD/UnicodeNameData.h>
12#include <UCD/resolve_properties.h>
13#include <kernels/charclasses.h>
14#include <kernels/cc_kernel.h>
15#include <kernels/grep_kernel.h>
16#include <kernels/linebreak_kernel.h>
17#include <kernels/streams_merge.h>
18#include <kernels/source_kernel.h>
19#include <kernels/s2p_kernel.h>
20#include <kernels/scanmatchgen.h>
21#include <kernels/streamset.h>
22#include <kernels/until_n.h>
23#include <kernels/kernel_builder.h>
24#include <pablo/pablo_kernel.h>
25#include <re/re_cc.h>
26#include <re/re_toolchain.h>
27#include <toolchain/toolchain.h>
28#include <re/re_name_resolve.h>   
29#include <re/re_collect_unicodesets.h>
30#include <re/re_multiplex.h>
31#include <toolchain/cpudriver.h>
32#include <toolchain/NVPTXDriver.h>
33#include <iostream>
34#include <sstream>
35#include <cc/multiplex_CCs.h>
36#include <llvm/Support/raw_ostream.h>
37#include <util/aligned_allocator.h>
38#include <sys/stat.h>
39#include <fcntl.h>
40#include <errno.h>
41#include <mutex>
42#ifdef CUDA_ENABLED
43#include <preprocess.cpp>
44#include <IR_Gen/CudaDriver.h>
45#endif
46
47using namespace parabix;
48using namespace llvm;
49
50namespace grep {
51
52static std::stringstream * resultStrs = nullptr;
53static std::vector<std::string> inputFiles;
54static std::vector<std::string> linePrefix;
55static bool grepMatchFound;
56
57size_t * startPoints = nullptr;
58size_t * accumBytes = nullptr;
59
60
61std::mutex count_mutex;
62size_t fileCount;
63
64// DoGrep thread function.
65void *DoGrepThreadFunction(void *args)
66{
67    size_t fileIdx;
68    grep::GrepEngine * grepEngine = (grep::GrepEngine *)args;
69
70    count_mutex.lock();
71    fileIdx = fileCount;
72    fileCount++;
73    count_mutex.unlock();
74
75    while (fileIdx < inputFiles.size()) {
76        size_t grepResult = grepEngine->doGrep(inputFiles[fileIdx], fileIdx);
77       
78        count_mutex.lock();
79        if (grepResult > 0) grepMatchFound = true;
80        fileIdx = fileCount;
81        fileCount++;
82        count_mutex.unlock();
83        if (QuietMode && grepMatchFound) pthread_exit(nullptr);
84    }
85
86    pthread_exit(nullptr);
87}
88
89bool matchesNeedToBeMovedToEOL() {
90    if ((Mode == QuietMode) | (Mode == FilesWithMatch) | (Mode == FilesWithoutMatch)) {
91        return false;
92    }
93    else if (LineRegexpFlag) {
94        return false;
95    }
96    // TODO: return false for other cases based on regexp analysis, e.g., regexp ends with $.
97    return true;
98}
99   
100void GrepEngine::doGrep(const std::string & fileName, std::string & PTXFilename) const{
101#ifdef CUDA_ENABLED
102    const bool CountOnly = true;
103    boost::filesystem::path file(fileName);
104    if (exists(file)) {
105        if (is_directory(file)) {
106            return;
107        }
108    } else {
109        if (!NoMessagesFlag) {
110            std::cerr << "Error: cannot open " << fileName << " for processing. Skipped.\n";
111            return;
112        }
113    }
114
115    const auto fileSize = file_size(file);
116   
117    if (fileSize > 0) {
118        try {
119            boost::iostreams::mapped_file_source source(fileName, fileSize, 0);
120            char * fileBuffer = const_cast<char *>(source.data());
121           
122            codegen::BlockSize = 128;
123            std::vector<size_t> LFPositions = preprocess(fileBuffer, fileSize);
124           
125            const unsigned numOfGroups = codegen::GroupNum;
126            if (posix_memalign((void**)&startPoints, 8, (numOfGroups+1)*sizeof(size_t)) ||
127                posix_memalign((void**)&accumBytes, 8, (numOfGroups+1)*sizeof(size_t))) {
128                std::cerr << "Cannot allocate memory for startPoints or accumBytes.\n";
129                exit(-1);
130            }
131            if(PTXFilename=="")
132                PTXFilename = mGrepDriver->getBuilder()->getModule()->getModuleIdentifier() + ".ptx";
133            RunPTX(PTXFilename, fileBuffer, fileSize, CountOnly, LFPositions, startPoints, accumBytes);
134            source.close();
135        } catch (std::exception & e) {
136            if (!NoMessagesFlag) {
137                std::cerr << "Boost mmap error: " + fileName + ": " + e.what() + " Skipped.\n";
138                return;
139            }
140        }
141    } else {
142        std::cout << 0 << std::endl;
143    }
144#endif
145}
146
147uint64_t GrepEngine::doGrep(const std::string & fileName, const uint32_t fileIdx) const {
148    struct stat sb;
149    const int32_t fd = open(fileName.c_str(), O_RDONLY);
150    if (LLVM_UNLIKELY(fd == -1)) {
151        if (!NoMessagesFlag  && !(Mode == QuietMode)) {
152            if (errno == EACCES) {
153                resultStrs[fileIdx] << "icgrep: " << fileName << ": Permission denied.\n";
154            }
155            else if (errno == ENOENT) {
156                resultStrs[fileIdx] << "icgrep: " << fileName << ": No such file.\n";
157            }
158            else {
159                resultStrs[fileIdx] << "icgrep: " << fileName << ": Failed.\n";
160            }
161        }
162        return 0;
163    }
164    if (stat(fileName.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
165        if (!NoMessagesFlag  && !(Mode == QuietMode)) {
166            resultStrs[fileIdx] << "icgrep: " << fileName << ": Is a directory.\n";
167        }
168        close(fd);
169        return 0;
170    }
171    const auto result = doGrep(fd, fileIdx);
172    close(fd);
173    return result;
174}
175
176uint64_t GrepEngine::doGrep(const int32_t fileDescriptor, const uint32_t fileIdx) const {
177    assert (mGrepDriver);
178    typedef uint64_t (*GrepFunctionType)(int32_t fileDescriptor, const uint32_t fileIdx);
179    auto f = reinterpret_cast<GrepFunctionType>(mGrepDriver->getMain());
180   
181    uint64_t grepResult = f(fileDescriptor, fileIdx);
182    if (grepResult > 0) grepMatchFound = true;
183    else if ((Mode == NormalMode) && !resultStrs[fileIdx].str().empty()) grepMatchFound = true;
184   
185    if (Mode == CountOnly) {
186        resultStrs[fileIdx] << linePrefix[fileIdx] << grepResult << "\n";
187    }
188    else if (Mode == FilesWithMatch || Mode == FilesWithoutMatch ) {
189        size_t requiredCount = Mode == FilesWithMatch ? 1 : 0;
190        if (grepResult == requiredCount) {
191            resultStrs[fileIdx] << linePrefix[fileIdx];
192        }
193    }
194    else if (Mode == QuietMode) {
195        if (grepMatchFound) exit(MatchFoundExitCode);
196    }
197    return grepResult;
198}
199
200void initFileResult(std::vector<std::string> filenames){
201    grepMatchFound = false;
202    const int n = filenames.size();
203    linePrefix.resize(n);
204    if ((n > 1) && !NoFilenameFlag) {
205        WithFilenameFlag = true;
206    }
207    std::string fileSuffix = "";
208    bool setLinePrefix = WithFilenameFlag || (Mode == FilesWithMatch) || (Mode == FilesWithoutMatch);
209    if (setLinePrefix) {
210        if (NullFlag) {
211            fileSuffix = std::string("\0", 1);
212        }
213        else if ((Mode == NormalMode) && InitialTabFlag && !(LineNumberFlag || ByteOffsetFlag)) {
214            fileSuffix = "\t:";
215        }
216        else if ((Mode == NormalMode) || (Mode == CountOnly)) {
217            fileSuffix = ":";
218        }
219        else if ((Mode == FilesWithMatch) || (Mode == FilesWithoutMatch)) {
220            fileSuffix = "\n";
221        }
222    }
223    inputFiles = filenames;
224    resultStrs = new std::stringstream[n];
225    for (unsigned i = 0; i < inputFiles.size(); ++i) {
226        if (setLinePrefix) {
227            if (inputFiles[i] == "-") {
228                linePrefix[i] = LabelFlag + fileSuffix;
229            }
230            else {
231                linePrefix[i] = inputFiles[i] + fileSuffix;
232            }
233        }
234    }
235}
236
237template<typename CodeUnit>
238void 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) {
239
240//    errs().write_hex((size_t)buffer) << " : " << lineNum << " (" << line_start << ", " << line_end << ", " << filesize << ")\n";
241
242    assert (buffer);
243    assert (line_start <= line_end);
244    assert (line_end <= filesize);
245
246    if (WithFilenameFlag) {
247        resultStrs[fileIdx] << linePrefix[fileIdx];
248    }
249    if (LineNumberFlag) {
250        // Internally line numbers are counted from 0.  For display, adjust
251        // the line number so that lines are numbered from 1.
252        if (InitialTabFlag) {
253            resultStrs[fileIdx] << lineNum+1 << "\t:";
254        }
255        else {
256            resultStrs[fileIdx] << lineNum+1 << ":";
257        }
258    }
259
260    // If the line "starts" on the LF of a CRLF, it is actually the end of the last line.
261    if ((buffer[line_start] == 0xA) && (line_start != line_end)) {
262        ++line_start;
263    }
264
265    if (LLVM_UNLIKELY(line_end == filesize)) {
266        // The match position is at end-of-file.   We have a final unterminated line.
267        resultStrs[fileIdx].write((char *)&buffer[line_start], (line_end - line_start) * sizeof(CodeUnit));
268        if (NormalizeLineBreaksFlag) {
269            resultStrs[fileIdx] << '\n';  // terminate it
270        }
271    } else {
272        const auto end_byte = buffer[line_end];
273        if (grep::NormalizeLineBreaksFlag) {
274            if (LLVM_UNLIKELY(end_byte == 0x85)) {
275                // Line terminated with NEL, on the second byte.  Back up 1.
276                line_end -= 1;
277            } else if (LLVM_UNLIKELY(end_byte > 0xD)) {
278                // Line terminated with PS or LS, on the third byte.  Back up 2.
279                line_end -= 2;
280            }
281            resultStrs[fileIdx].write((char *)&buffer[line_start], (line_end - line_start) * sizeof(CodeUnit));
282            resultStrs[fileIdx] << '\n';
283        } else {
284            if (end_byte == 0x0D) {
285                // Check for line_end on first byte of CRLF; we don't want to access past the end of buffer.
286                if ((line_end + 1) < filesize) {
287                    if (buffer[line_end + 1] == 0x0A) {
288                        // Found CRLF; preserve both bytes.
289                        ++line_end;
290                    }
291                }
292            }
293            resultStrs[fileIdx].write((char *)&buffer[line_start], (line_end - line_start + 1) * sizeof(CodeUnit));
294        }
295    }
296}
297
298void PrintResults(){
299   
300    for (unsigned i = 0; i < inputFiles.size(); ++i){
301        std::cout << resultStrs[i].str();
302    }
303    exit(grepMatchFound ? MatchFoundExitCode : MatchNotFoundExitCode);
304}
305
306   
307std::pair<StreamSetBuffer *, StreamSetBuffer *> grepPipeline(Driver * grepDriver, std::vector<re::RE *> REs, const GrepModeType grepMode, unsigned encodingBits, StreamSetBuffer * ByteStream) {
308    auto & idb = grepDriver->getBuilder();
309    const unsigned segmentSize = codegen::SegmentSize;
310    const unsigned bufferSegments = codegen::BufferSegments * codegen::ThreadNum;
311    size_t MatchLimit = ((grepMode == QuietMode) | (grepMode == FilesWithMatch) | (grepMode == FilesWithoutMatch)) ? 1 : MaxCountFlag;
312   
313
314    StreamSetBuffer * BasisBits = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(encodingBits, 1), segmentSize * bufferSegments));
315    kernel::Kernel * s2pk = grepDriver->addKernelInstance(make_unique<kernel::S2PKernel>(idb));
316    grepDriver->makeKernelCall(s2pk, {ByteStream}, {BasisBits});
317   
318    StreamSetBuffer * LineBreakStream = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
319    kernel::Kernel * linebreakK = grepDriver->addKernelInstance(make_unique<kernel::LineBreakKernelBuilder>(idb, encodingBits));
320    grepDriver->makeKernelCall(linebreakK, {BasisBits}, {LineBreakStream});
321   
322    kernel::Kernel * requiredStreamsK = grepDriver->addKernelInstance(make_unique<kernel::RequiredStreams_UTF8>(idb));
323    StreamSetBuffer * RequiredStreams = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(4, 1), segmentSize * bufferSegments));
324    grepDriver->makeKernelCall(requiredStreamsK, {BasisBits}, {RequiredStreams});
325   
326    const auto n = REs.size();
327   
328    std::vector<std::vector<UCD::UnicodeSet>> charclasses;
329
330    for (unsigned i = 0; i < n; i++) {
331        std::vector<UCD::UnicodeSet> UnicodeSets;
332        REs[i] = resolveNames(REs[i]);
333        re::collect_UnicodeSets(REs[i], UnicodeSets);
334        std::vector<std::vector<unsigned>> exclusiveSetIDs;
335        std::vector<UCD::UnicodeSet> multiplexedCCs;
336
337        doMultiplexCCs(UnicodeSets, exclusiveSetIDs, multiplexedCCs);
338
339        REs[i] = multiplex(REs[i], UnicodeSets, exclusiveSetIDs, multiplexedCCs);
340        charclasses.push_back(multiplexedCCs);
341    } 
342
343    std::vector<StreamSetBuffer *> MatchResultsBufs(n);
344
345    for(unsigned i = 0; i < n; ++i){
346        StreamSetBuffer * CharClasses = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(charclasses[i].size()), segmentSize * bufferSegments));
347        kernel::Kernel * ccK = grepDriver->addKernelInstance(make_unique<kernel::CharClassesKernel>(idb, charclasses[i]));
348        grepDriver->makeKernelCall(ccK, {BasisBits}, {CharClasses});
349        StreamSetBuffer * MatchResults = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
350        kernel::Kernel * icgrepK = grepDriver->addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, REs[i], true, charclasses[i].size()));
351        grepDriver->makeKernelCall(icgrepK, {CharClasses, LineBreakStream, RequiredStreams}, {MatchResults});
352        MatchResultsBufs[i] = MatchResults;
353    }
354    StreamSetBuffer * MergedResults = MatchResultsBufs[0];
355    if (REs.size() > 1) {
356        MergedResults = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
357        kernel::Kernel * streamsMergeK = grepDriver->addKernelInstance(make_unique<kernel::StreamsMerge>(idb, 1, REs.size()));
358        grepDriver->makeKernelCall(streamsMergeK, MatchResultsBufs, {MergedResults});
359    }
360    StreamSetBuffer * Matches = MergedResults;
361   
362    if (matchesNeedToBeMovedToEOL()) {
363        StreamSetBuffer * OriginalMatches = Matches;
364        kernel::Kernel * matchedLinesK = grepDriver->addKernelInstance(make_unique<kernel::MatchedLinesKernel>(idb));
365        Matches = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
366        grepDriver->makeKernelCall(matchedLinesK, {OriginalMatches, LineBreakStream}, {Matches});
367    }
368   
369    if (InvertMatchFlag) {
370        kernel::Kernel * invertK = grepDriver->addKernelInstance(make_unique<kernel::InvertMatchesKernel>(idb));
371        StreamSetBuffer * OriginalMatches = Matches;
372        Matches = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
373        grepDriver->makeKernelCall(invertK, {OriginalMatches, LineBreakStream}, {Matches});
374    }
375    if (MatchLimit > 0) {
376        kernel::Kernel * untilK = grepDriver->addKernelInstance(make_unique<kernel::UntilNkernel>(idb));
377        untilK->setInitialArguments({idb->getSize(MatchLimit)});
378        StreamSetBuffer * AllMatches = Matches;
379        Matches = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
380        grepDriver->makeKernelCall(untilK, {AllMatches}, {Matches});
381    }
382    return std::pair<StreamSetBuffer *, StreamSetBuffer *>(LineBreakStream, Matches);
383}
384
385
386   
387void GrepEngine::grepCodeGen_nvptx(std::vector<re::RE *> REs, const GrepModeType grepMode, const bool UTF_16) {
388
389    assert (mGrepDriver == nullptr);
390
391    mGrepDriver = new NVPTXDriver("engine");
392    auto & idb = mGrepDriver->getBuilder();
393    Module * M = idb->getModule();
394
395    const unsigned segmentSize = codegen::SegmentSize;
396    const unsigned encodingBits = UTF_16 ? 16 : 8;
397
398    Type * const int64Ty = idb->getInt64Ty();
399    Type * const int32Ty = idb->getInt32Ty();
400    Type * const size_ty = idb->getSizeTy();
401    Type * const sizeTyPtr = PointerType::get(size_ty, 1);
402    Type * const int64tyPtr = PointerType::get(int64Ty, 1);
403    Type * const voidTy = idb->getVoidTy();
404   
405    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", voidTy, int64tyPtr, sizeTyPtr, sizeTyPtr, int64tyPtr, nullptr));
406    mainFunc->setCallingConv(CallingConv::C);
407    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
408    auto args = mainFunc->arg_begin();
409
410    Value * const inputPtr = &*(args++);
411    inputPtr->setName("inputPtr");
412    Value * const startPointsPtr = &*(args++);
413    startPointsPtr->setName("startPointsPtr");
414    Value * const bufferSizesPtr = &*(args++);
415    bufferSizesPtr->setName("bufferSizesPtr");
416    Value * const outputPtr = &*(args++);
417    outputPtr->setName("outputPtr");
418
419    Function * tidFunc = M->getFunction("llvm.nvvm.read.ptx.sreg.tid.x");
420    Value * tid = idb->CreateCall(tidFunc);
421    Function * bidFunc = cast<Function>(M->getOrInsertFunction("llvm.nvvm.read.ptx.sreg.ctaid.x", int32Ty, nullptr));
422    Value * bid = idb->CreateCall(bidFunc);
423
424    Value * startPoint = idb->CreateLoad(idb->CreateGEP(startPointsPtr, bid));
425    Value * startBlock = idb->CreateUDiv(startPoint, ConstantInt::get(int64Ty, idb->getBitBlockWidth()));
426    Type * const inputStreamType = PointerType::get(ArrayType::get(ArrayType::get(idb->getBitBlockType(), 8), 1), 1);   
427    Value * inputStreamPtr = idb->CreateGEP(idb->CreateBitCast(inputPtr, inputStreamType), startBlock);
428    Value * inputStream = idb->CreateGEP(inputStreamPtr, tid);
429    Value * bufferSize = idb->CreateLoad(idb->CreateGEP(bufferSizesPtr, bid));
430
431    StreamSetBuffer * ByteStream = mGrepDriver->addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8), 1));
432    kernel::Kernel * sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, inputStreamType, segmentSize));
433    sourceK->setInitialArguments({inputStream, bufferSize});
434    mGrepDriver->makeKernelCall(sourceK, {}, {ByteStream});
435
436    StreamSetBuffer * Matches = std::get<1>(grepPipeline(mGrepDriver, REs, grepMode, encodingBits, ByteStream));
437   
438    kernel::Kernel * matchCountK = mGrepDriver->addKernelInstance(make_unique<kernel::PopcountKernel>(idb));
439    mGrepDriver->makeKernelCall(matchCountK, {Matches}, {});
440    mGrepDriver->generatePipelineIR();
441    idb->setKernel(matchCountK);
442    Value * matchedLineCount = idb->getAccumulator("countResult");
443    matchedLineCount = idb->CreateZExt(matchedLineCount, int64Ty);
444   
445    Value * strideBlocks = ConstantInt::get(int32Ty, idb->getStride() / idb->getBitBlockWidth());
446    Value * outputThreadPtr = idb->CreateGEP(outputPtr, idb->CreateAdd(idb->CreateMul(bid, strideBlocks), tid));
447    idb->CreateStore(matchedLineCount, outputThreadPtr);
448    idb->CreateRetVoid();
449
450    mGrepDriver->finalizeObject();
451}
452
453void GrepEngine::grepCodeGen(std::vector<re::RE *> REs, const GrepModeType grepMode, const bool UTF_16, GrepSource grepSource) {
454
455    assert (mGrepDriver == nullptr);
456    mGrepDriver = new ParabixDriver("engine");
457    auto & idb = mGrepDriver->getBuilder();
458    Module * M = idb->getModule();
459
460    const unsigned segmentSize = codegen::SegmentSize;
461    const unsigned encodingBits = UTF_16 ? 16 : 8;
462
463    Type * const int64Ty = idb->getInt64Ty();
464    Type * const int32Ty = idb->getInt32Ty();
465
466    kernel::Kernel * sourceK = nullptr;
467   
468    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", int64Ty, idb->getInt32Ty(), int32Ty, nullptr));
469    mainFunc->setCallingConv(CallingConv::C);
470    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
471    auto args = mainFunc->arg_begin();
472
473    Value * const fileDescriptor = &*(args++);
474    fileDescriptor->setName("fileDescriptor");
475    Value * fileIdx = &*(args++);
476    fileIdx->setName("fileIdx");
477
478    StreamSetBuffer * ByteStream = mGrepDriver->addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8)));
479
480    if (grepSource == GrepSource::File) {
481        sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::MMapSourceKernel>(idb, segmentSize));
482    } else {
483        sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::ReadSourceKernel>(idb, segmentSize));
484    }
485    sourceK->setInitialArguments({fileDescriptor});
486
487    mGrepDriver->makeKernelCall(sourceK, {}, {ByteStream});
488   
489    StreamSetBuffer * LineBreakStream;
490    StreamSetBuffer * Matches;
491    std::tie(LineBreakStream, Matches) = grepPipeline(mGrepDriver, REs, grepMode, encodingBits, ByteStream);
492   
493    if (grepMode == NormalMode) {
494        kernel::Kernel * scanMatchK = mGrepDriver->addKernelInstance(make_unique<kernel::ScanMatchKernel>(idb, GrepType::Normal, encodingBits));
495        scanMatchK->setInitialArguments({fileIdx});
496        mGrepDriver->makeKernelCall(scanMatchK, {Matches, LineBreakStream, ByteStream}, {});
497        if (UTF_16) {
498            mGrepDriver->LinkFunction(*scanMatchK, "matcher", &wrapped_report_match<uint16_t>);
499        } else {
500            mGrepDriver->LinkFunction(*scanMatchK, "matcher", &wrapped_report_match<uint8_t>);
501        }
502        mGrepDriver->generatePipelineIR();
503        mGrepDriver->deallocateBuffers();
504
505        idb->CreateRet(idb->getInt64(0));
506    } else {
507        kernel::Kernel * matchCountK = mGrepDriver->addKernelInstance(make_unique<kernel::PopcountKernel>(idb));
508        mGrepDriver->makeKernelCall(matchCountK, {Matches}, {});
509        mGrepDriver->generatePipelineIR();
510        idb->setKernel(matchCountK);
511        Value * matchedLineCount = idb->getAccumulator("countResult");
512        matchedLineCount = idb->CreateZExt(matchedLineCount, int64Ty);
513        mGrepDriver->deallocateBuffers();
514        idb->CreateRet(matchedLineCount);
515    }
516    mGrepDriver->finalizeObject();
517}
518
519GrepEngine::GrepEngine()
520: mGrepDriver(nullptr) {
521
522}
523
524GrepEngine::~GrepEngine() {
525    delete mGrepDriver;
526}
527
528
529   
530static re::CC * parsedCodePointSet = nullptr;
531
532void insert_codepoints(const size_t lineNum, const size_t line_start, const size_t line_end, const char * const buffer) {
533    assert (buffer);
534    assert (line_start <= line_end);
535    re::codepoint_t c = 0;
536    size_t line_pos = line_start;
537    while (isxdigit(buffer[line_pos])) {
538        assert (line_pos < line_end);
539        if (isdigit(buffer[line_pos])) {
540            c = (c << 4) | (buffer[line_pos] - '0');
541        }
542        else {
543            c = (c << 4) | (tolower(buffer[line_pos]) - 'a' + 10);
544        }
545        line_pos++;
546    }
547    assert(((line_pos - line_start) >= 4) && ((line_pos - line_start) <= 6)); // UCD format 4 to 6 hex digits.
548    parsedCodePointSet->insert(c);
549}
550
551re::CC * grepCodepoints(re::RE * pattern, char * UnicodeDataBuffer, size_t bufferLength) {
552    parsedCodePointSet = re::makeCC();       
553    const unsigned segmentSize = 8;
554
555    ParabixDriver pxDriver("codepointEngine");
556    auto & idb = pxDriver.getBuilder();
557    Module * M = idb->getModule();
558   
559    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", idb->getVoidTy(), idb->getInt8PtrTy(), idb->getSizeTy(), nullptr));
560    mainFunc->setCallingConv(CallingConv::C);
561    auto args = mainFunc->arg_begin();
562    Value * const buffer = &*(args++);
563    buffer->setName("buffer");
564    Value * length = &*(args++);
565    length->setName("length");
566   
567    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
568   
569    StreamSetBuffer * ByteStream = pxDriver.addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8)));
570    kernel::Kernel * sourceK = pxDriver.addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, idb->getInt8PtrTy(), segmentSize));
571    sourceK->setInitialArguments({buffer, length});
572    pxDriver.makeKernelCall(sourceK, {}, {ByteStream});
573   
574    StreamSetBuffer * BasisBits = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(8, 1), segmentSize));
575   
576    kernel::Kernel * s2pk = pxDriver.addKernelInstance(make_unique<kernel::S2PKernel>(idb));
577    pxDriver.makeKernelCall(s2pk, {ByteStream}, {BasisBits});
578   
579    kernel::Kernel * linebreakK = pxDriver.addKernelInstance(make_unique<kernel::LineBreakKernelBuilder>(idb, 8));
580    StreamSetBuffer * LineBreakStream = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
581    pxDriver.makeKernelCall(linebreakK, {BasisBits}, {LineBreakStream});
582   
583    kernel::Kernel * requiredStreamsK = pxDriver.addKernelInstance(make_unique<kernel::RequiredStreams_UTF8>(idb));
584    StreamSetBuffer * RequiredStreams = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(4, 1), segmentSize));
585    pxDriver.makeKernelCall(requiredStreamsK, {BasisBits}, {RequiredStreams});
586   
587    StreamSetBuffer * MatchResults = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
588    kernel::Kernel * icgrepK = pxDriver.addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, pattern));
589    pxDriver.makeKernelCall(icgrepK, {BasisBits, LineBreakStream, RequiredStreams}, {MatchResults});
590   
591    StreamSetBuffer * MatchedLines = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
592    kernel::Kernel * matchedLinesK = pxDriver.addKernelInstance(make_unique<kernel::MatchedLinesKernel>(idb));
593    pxDriver.makeKernelCall(matchedLinesK, {MatchResults, LineBreakStream}, {MatchedLines});
594   
595    kernel::Kernel * scanMatchK = pxDriver.addKernelInstance(make_unique<kernel::ScanMatchKernel>(idb, GrepType::NameExpression, 8));
596    scanMatchK->setInitialArguments({idb->getInt32(0)});
597    pxDriver.makeKernelCall(scanMatchK, {MatchedLines, LineBreakStream, ByteStream}, {});
598    pxDriver.LinkFunction(*scanMatchK, "matcher", &insert_codepoints);
599    pxDriver.generatePipelineIR();
600    idb->CreateRetVoid();
601    pxDriver.finalizeObject();
602   
603    typedef void (*GrepFunctionType)(const char * buffer, const size_t length);
604    auto f = reinterpret_cast<GrepFunctionType>(pxDriver.getMain());
605    f(UnicodeDataBuffer, bufferLength);
606   
607    return parsedCodePointSet;   
608}
609
610   
611static std::vector<std::string> parsedPropertyValues;
612
613void insert_property_values(size_t lineNum, size_t line_start, size_t line_end, const char * buffer) {
614    assert (line_start <= line_end);
615    parsedPropertyValues.emplace_back(buffer + line_start, buffer + line_end);
616}
617
618
619const std::vector<std::string> & grepPropertyValues(const std::string& propertyName, re::RE * propertyValuePattern) {
620    ParabixDriver pxDriver("propertyValueEngine");
621    AlignedAllocator<char, 32> alloc;
622
623    parsedPropertyValues.clear();
624
625    const std::string & str = UCD::getPropertyValueGrepString(propertyName);
626
627    auto & idb = pxDriver.getBuilder();
628
629    const unsigned segmentSize = 8;
630    const auto n = str.length();
631    const auto w = idb->getBitBlockWidth() * segmentSize;
632    const auto m = w - (n % w);
633
634    char * aligned = alloc.allocate(n + m, 0);
635    std::memcpy(aligned, str.data(), n);
636    std::memset(aligned + n, 0, m);
637
638    Module * M = idb->getModule();
639   
640    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", idb->getVoidTy(), idb->getInt8PtrTy(), idb->getSizeTy(), nullptr));
641    mainFunc->setCallingConv(CallingConv::C);
642    auto args = mainFunc->arg_begin();
643    Value * const buffer = &*(args++);
644    buffer->setName("buffer");
645    Value * length = &*(args++);
646    length->setName("length");
647   
648    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
649   
650    StreamSetBuffer * ByteStream = pxDriver.addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8)));
651    kernel::Kernel * sourceK = pxDriver.addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, idb->getInt8PtrTy(), segmentSize));
652    sourceK->setInitialArguments({buffer, length});
653    pxDriver.makeKernelCall(sourceK, {}, {ByteStream});
654   
655    StreamSetBuffer * BasisBits = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(8, 1), segmentSize));
656   
657    kernel::Kernel * s2pk = pxDriver.addKernelInstance(make_unique<kernel::S2PKernel>(idb));
658    pxDriver.makeKernelCall(s2pk, {ByteStream}, {BasisBits});
659   
660    kernel::Kernel * linebreakK = pxDriver.addKernelInstance(make_unique<kernel::LineBreakKernelBuilder>(idb, 8));
661    StreamSetBuffer * LineBreakStream = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
662    pxDriver.makeKernelCall(linebreakK, {BasisBits}, {LineBreakStream});
663   
664    kernel::Kernel * requiredStreamsK = pxDriver.addKernelInstance(make_unique<kernel::RequiredStreams_UTF8>(idb));
665    StreamSetBuffer * RequiredStreams = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(4, 1), segmentSize));
666    pxDriver.makeKernelCall(requiredStreamsK, {BasisBits}, {RequiredStreams});
667   
668    StreamSetBuffer * MatchResults = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
669    kernel::Kernel * icgrepK = pxDriver.addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, propertyValuePattern));
670    pxDriver.makeKernelCall(icgrepK, {BasisBits, LineBreakStream, RequiredStreams}, {MatchResults});
671
672    StreamSetBuffer * MatchedLines = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
673    kernel::Kernel * matchedLinesK = pxDriver.addKernelInstance(make_unique<kernel::MatchedLinesKernel>(idb));
674    pxDriver.makeKernelCall(matchedLinesK, {MatchResults, LineBreakStream}, {MatchedLines});
675
676    kernel::Kernel * scanMatchK = pxDriver.addKernelInstance(make_unique<kernel::ScanMatchKernel>(idb, GrepType::PropertyValue, 8));
677    scanMatchK->setInitialArguments({idb->getInt32(0)});
678    pxDriver.makeKernelCall(scanMatchK, {MatchedLines, LineBreakStream, ByteStream}, {});
679    pxDriver.LinkFunction(*scanMatchK, "matcher", &insert_property_values);
680    pxDriver.generatePipelineIR();
681    idb->CreateRetVoid();
682    pxDriver.finalizeObject();
683
684    typedef void (*GrepFunctionType)(const char * buffer, const size_t length);
685    auto f = reinterpret_cast<GrepFunctionType>(pxDriver.getMain());
686    f(aligned, n);
687   
688    alloc.deallocate(aligned, 0);
689    return parsedPropertyValues;
690}
691
692   
693}
Note: See TracBrowser for help on using the repository browser.