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

Last change on this file since 5620 was 5620, checked in by nmedfort, 19 months ago

Bug fixes for multigrep mode. Optional PabloKernel? branch hit counter added. Minor optimizations.

File size: 29.5 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        doMultiplexCCs(UnicodeSets, exclusiveSetIDs, multiplexedCCs);
337        REs[i] = multiplex(REs[i], UnicodeSets, exclusiveSetIDs);
338        charclasses.push_back(multiplexedCCs);
339    } 
340
341    std::vector<StreamSetBuffer *> MatchResultsBufs(n);
342
343    for(unsigned i = 0; i < n; ++i){
344        const auto numOfCharacterClasses = charclasses[i].size();
345        StreamSetBuffer * CharClasses = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(numOfCharacterClasses), segmentSize * bufferSegments));
346        kernel::Kernel * ccK = grepDriver->addKernelInstance(make_unique<kernel::CharClassesKernel>(idb, std::move(charclasses[i])));
347        grepDriver->makeKernelCall(ccK, {BasisBits}, {CharClasses});
348        StreamSetBuffer * MatchResults = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
349        kernel::Kernel * icgrepK = grepDriver->addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, REs[i], true, numOfCharacterClasses));
350        grepDriver->makeKernelCall(icgrepK, {CharClasses, LineBreakStream, RequiredStreams}, {MatchResults});
351        MatchResultsBufs[i] = MatchResults;
352    }
353    StreamSetBuffer * MergedResults = MatchResultsBufs[0];
354    if (REs.size() > 1) {
355        MergedResults = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
356        kernel::Kernel * streamsMergeK = grepDriver->addKernelInstance(make_unique<kernel::StreamsMerge>(idb, 1, REs.size()));
357        grepDriver->makeKernelCall(streamsMergeK, MatchResultsBufs, {MergedResults});
358    }
359    StreamSetBuffer * Matches = MergedResults;
360   
361    if (matchesNeedToBeMovedToEOL()) {
362        StreamSetBuffer * OriginalMatches = Matches;
363        kernel::Kernel * matchedLinesK = grepDriver->addKernelInstance(make_unique<kernel::MatchedLinesKernel>(idb));
364        Matches = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
365        grepDriver->makeKernelCall(matchedLinesK, {OriginalMatches, LineBreakStream}, {Matches});
366    }
367   
368    if (InvertMatchFlag) {
369        kernel::Kernel * invertK = grepDriver->addKernelInstance(make_unique<kernel::InvertMatchesKernel>(idb));
370        StreamSetBuffer * OriginalMatches = Matches;
371        Matches = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
372        grepDriver->makeKernelCall(invertK, {OriginalMatches, LineBreakStream}, {Matches});
373    }
374    if (MatchLimit > 0) {
375        kernel::Kernel * untilK = grepDriver->addKernelInstance(make_unique<kernel::UntilNkernel>(idb));
376        untilK->setInitialArguments({idb->getSize(MatchLimit)});
377        StreamSetBuffer * AllMatches = Matches;
378        Matches = grepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
379        grepDriver->makeKernelCall(untilK, {AllMatches}, {Matches});
380    }
381    return std::pair<StreamSetBuffer *, StreamSetBuffer *>(LineBreakStream, Matches);
382}
383
384
385   
386void GrepEngine::grepCodeGen_nvptx(std::vector<re::RE *> REs, const GrepModeType grepMode, const bool UTF_16) {
387
388    assert (mGrepDriver == nullptr);
389
390    mGrepDriver = new NVPTXDriver("engine");
391    auto & idb = mGrepDriver->getBuilder();
392    Module * M = idb->getModule();
393
394    const unsigned segmentSize = codegen::SegmentSize;
395    const unsigned encodingBits = UTF_16 ? 16 : 8;
396
397    Type * const int64Ty = idb->getInt64Ty();
398    Type * const int32Ty = idb->getInt32Ty();
399    Type * const size_ty = idb->getSizeTy();
400    Type * const sizeTyPtr = PointerType::get(size_ty, 1);
401    Type * const int64tyPtr = PointerType::get(int64Ty, 1);
402    Type * const voidTy = idb->getVoidTy();
403   
404    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", voidTy, int64tyPtr, sizeTyPtr, sizeTyPtr, int64tyPtr, nullptr));
405    mainFunc->setCallingConv(CallingConv::C);
406    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
407    auto args = mainFunc->arg_begin();
408
409    Value * const inputPtr = &*(args++);
410    inputPtr->setName("inputPtr");
411    Value * const startPointsPtr = &*(args++);
412    startPointsPtr->setName("startPointsPtr");
413    Value * const bufferSizesPtr = &*(args++);
414    bufferSizesPtr->setName("bufferSizesPtr");
415    Value * const outputPtr = &*(args++);
416    outputPtr->setName("outputPtr");
417
418    Function * tidFunc = M->getFunction("llvm.nvvm.read.ptx.sreg.tid.x");
419    Value * tid = idb->CreateCall(tidFunc);
420    Function * bidFunc = cast<Function>(M->getOrInsertFunction("llvm.nvvm.read.ptx.sreg.ctaid.x", int32Ty, nullptr));
421    Value * bid = idb->CreateCall(bidFunc);
422
423    Value * startPoint = idb->CreateLoad(idb->CreateGEP(startPointsPtr, bid));
424    Value * startBlock = idb->CreateUDiv(startPoint, ConstantInt::get(int64Ty, idb->getBitBlockWidth()));
425    Type * const inputStreamType = PointerType::get(ArrayType::get(ArrayType::get(idb->getBitBlockType(), 8), 1), 1);   
426    Value * inputStreamPtr = idb->CreateGEP(idb->CreateBitCast(inputPtr, inputStreamType), startBlock);
427    Value * inputStream = idb->CreateGEP(inputStreamPtr, tid);
428    Value * bufferSize = idb->CreateLoad(idb->CreateGEP(bufferSizesPtr, bid));
429
430    StreamSetBuffer * ByteStream = mGrepDriver->addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8), 1));
431    kernel::Kernel * sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, inputStreamType, segmentSize));
432    sourceK->setInitialArguments({inputStream, bufferSize});
433    mGrepDriver->makeKernelCall(sourceK, {}, {ByteStream});
434
435    StreamSetBuffer * Matches = std::get<1>(grepPipeline(mGrepDriver, REs, grepMode, encodingBits, ByteStream));
436   
437    kernel::Kernel * matchCountK = mGrepDriver->addKernelInstance(make_unique<kernel::PopcountKernel>(idb));
438    mGrepDriver->makeKernelCall(matchCountK, {Matches}, {});
439    mGrepDriver->generatePipelineIR();
440    idb->setKernel(matchCountK);
441    Value * matchedLineCount = idb->getAccumulator("countResult");
442    matchedLineCount = idb->CreateZExt(matchedLineCount, int64Ty);
443   
444    Value * strideBlocks = ConstantInt::get(int32Ty, idb->getStride() / idb->getBitBlockWidth());
445    Value * outputThreadPtr = idb->CreateGEP(outputPtr, idb->CreateAdd(idb->CreateMul(bid, strideBlocks), tid));
446    idb->CreateStore(matchedLineCount, outputThreadPtr);
447    mGrepDriver->deallocateBuffers();
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    pxDriver.deallocateBuffers();
601    idb->CreateRetVoid();
602    pxDriver.finalizeObject();
603   
604    typedef void (*GrepFunctionType)(const char * buffer, const size_t length);
605    auto f = reinterpret_cast<GrepFunctionType>(pxDriver.getMain());
606    f(UnicodeDataBuffer, bufferLength);
607   
608    return parsedCodePointSet;   
609}
610
611   
612static std::vector<std::string> parsedPropertyValues;
613
614void insert_property_values(size_t lineNum, size_t line_start, size_t line_end, const char * buffer) {
615    assert (line_start <= line_end);
616    parsedPropertyValues.emplace_back(buffer + line_start, buffer + line_end);
617}
618
619
620const std::vector<std::string> & grepPropertyValues(const std::string& propertyName, re::RE * propertyValuePattern) {
621    ParabixDriver pxDriver("propertyValueEngine");
622    AlignedAllocator<char, 32> alloc;
623
624    parsedPropertyValues.clear();
625
626    const std::string & str = UCD::getPropertyValueGrepString(propertyName);
627
628    auto & idb = pxDriver.getBuilder();
629
630    const unsigned segmentSize = 8;
631    const auto n = str.length();
632    const auto w = idb->getBitBlockWidth() * segmentSize;
633    const auto m = w - (n % w);
634
635    char * aligned = alloc.allocate(n + m, 0);
636    std::memcpy(aligned, str.data(), n);
637    std::memset(aligned + n, 0, m);
638
639    Module * M = idb->getModule();
640   
641    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", idb->getVoidTy(), idb->getInt8PtrTy(), idb->getSizeTy(), nullptr));
642    mainFunc->setCallingConv(CallingConv::C);
643    auto args = mainFunc->arg_begin();
644    Value * const buffer = &*(args++);
645    buffer->setName("buffer");
646    Value * length = &*(args++);
647    length->setName("length");
648   
649    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
650   
651    StreamSetBuffer * ByteStream = pxDriver.addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8)));
652    kernel::Kernel * sourceK = pxDriver.addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, idb->getInt8PtrTy(), segmentSize));
653    sourceK->setInitialArguments({buffer, length});
654    pxDriver.makeKernelCall(sourceK, {}, {ByteStream});
655   
656    StreamSetBuffer * BasisBits = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(8, 1), segmentSize));
657   
658    kernel::Kernel * s2pk = pxDriver.addKernelInstance(make_unique<kernel::S2PKernel>(idb));
659    pxDriver.makeKernelCall(s2pk, {ByteStream}, {BasisBits});
660   
661    kernel::Kernel * linebreakK = pxDriver.addKernelInstance(make_unique<kernel::LineBreakKernelBuilder>(idb, 8));
662    StreamSetBuffer * LineBreakStream = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
663    pxDriver.makeKernelCall(linebreakK, {BasisBits}, {LineBreakStream});
664   
665    kernel::Kernel * requiredStreamsK = pxDriver.addKernelInstance(make_unique<kernel::RequiredStreams_UTF8>(idb));
666    StreamSetBuffer * RequiredStreams = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(4, 1), segmentSize));
667    pxDriver.makeKernelCall(requiredStreamsK, {BasisBits}, {RequiredStreams});
668   
669    StreamSetBuffer * MatchResults = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
670    kernel::Kernel * icgrepK = pxDriver.addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, propertyValuePattern));
671    pxDriver.makeKernelCall(icgrepK, {BasisBits, LineBreakStream, RequiredStreams}, {MatchResults});
672
673    StreamSetBuffer * MatchedLines = pxDriver.addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize));
674    kernel::Kernel * matchedLinesK = pxDriver.addKernelInstance(make_unique<kernel::MatchedLinesKernel>(idb));
675    pxDriver.makeKernelCall(matchedLinesK, {MatchResults, LineBreakStream}, {MatchedLines});
676
677    kernel::Kernel * scanMatchK = pxDriver.addKernelInstance(make_unique<kernel::ScanMatchKernel>(idb, GrepType::PropertyValue, 8));
678    scanMatchK->setInitialArguments({idb->getInt32(0)});
679    pxDriver.makeKernelCall(scanMatchK, {MatchedLines, LineBreakStream, ByteStream}, {});
680    pxDriver.LinkFunction(*scanMatchK, "matcher", &insert_property_values);
681    pxDriver.generatePipelineIR();
682    pxDriver.deallocateBuffers();
683    idb->CreateRetVoid();
684    pxDriver.finalizeObject();
685
686    typedef void (*GrepFunctionType)(const char * buffer, const size_t length);
687    auto f = reinterpret_cast<GrepFunctionType>(pxDriver.getMain());
688    f(aligned, n);
689   
690    alloc.deallocate(aligned, 0);
691    return parsedPropertyValues;
692}
693
694   
695}
Note: See TracBrowser for help on using the repository browser.