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

Last change on this file since 5475 was 5475, checked in by cameron, 2 years ago

Fixes for icgrep -NVPTX

File size: 30.6 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include "grep_engine.h"
8#include <llvm/IR/Module.h>
9#include <llvm/Support/CommandLine.h>
10#include <boost/filesystem.hpp>
11#include <UCD/UnicodeNameData.h>
12#include <UCD/resolve_properties.h>
13#include <kernels/cc_kernel.h>
14#include <kernels/grep_kernel.h>
15#include <kernels/linebreak_kernel.h>
16#include <kernels/streams_merge.h>
17#include <kernels/match_count.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 <toolchain/cpudriver.h>
29#include <toolchain/NVPTXDriver.h>
30#include <iostream>
31#include <sstream>
32#include <cc/multiplex_CCs.h>
33#include <llvm/Support/raw_ostream.h>
34#include <util/aligned_allocator.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37
38#ifdef CUDA_ENABLED
39#include <preprocess.cpp>
40#include <IR_Gen/CudaDriver.h>
41#endif
42
43using namespace parabix;
44using namespace llvm;
45
46namespace grep {
47
48static cl::OptionCategory RE_Options("A. Regular Expression Interpretation", "These options control regular expression parsing and interpretation");
49
50re::RE_Syntax RegexpSyntax;
51static cl::opt<re::RE_Syntax, true> RegexpSyntaxOption(cl::desc("Regular expression syntax: (default PCRE)"),
52    cl::values(
53        clEnumValN(re::RE_Syntax::ERE, "E", "Posix extended regular expression (ERE) syntax"),
54        clEnumValN(re::RE_Syntax::FixedStrings, "F", "Fixed strings, separated by newlines"),
55        clEnumValN(re::RE_Syntax::BRE, "G", "Posix basic regular expression (BRE) syntax"),
56        clEnumValN(re::RE_Syntax::PCRE, "P", "Perl-compatible regular expression (PCRE) syntax"),
57        clEnumValN(re::RE_Syntax::ERE, "extended-regexp", "Alias for -E"),
58        clEnumValN(re::RE_Syntax::FixedStrings, "fixed-strings", "Alias for -F"),
59        clEnumValN(re::RE_Syntax::BRE, "basic-regexp", "Alias for -G"),
60        clEnumValN(re::RE_Syntax::PCRE, "perl-regexp", "Alias for -P"),
61        clEnumValN(re::RE_Syntax::PROSITE, "PROSITE", "PROSITE protein patterns syntax"),
62        clEnumValEnd), cl::cat(RE_Options), cl::Grouping, cl::location(RegexpSyntax), cl::init(re::RE_Syntax::PCRE));
63
64bool IgnoreCaseFlag;
65static cl::opt<bool, true> IgnoreCase("i", cl::desc("Ignore case distinctions in the pattern and the file (alias: -ignore-case)."), 
66                                      cl::cat(RE_Options), cl::location(IgnoreCaseFlag), cl::Grouping);
67static cl::alias IgnoreCaseAlias("ignore-case", cl::desc("Alias for -i"), cl::aliasopt(IgnoreCase), cl::NotHidden);
68
69bool InvertMatchFlag;
70static cl::opt<bool, true> InvertMatch("v", cl::desc("Invert match results: select non-matching lines (alias: -invert-match)."), 
71                                       cl::cat(RE_Options), cl::location(InvertMatchFlag), cl::Grouping);
72static cl::alias InvertMatchAlias("invert-match", cl::desc("Alias for -v"), cl::aliasopt(InvertMatch), cl::NotHidden);
73
74bool LineRegexpFlag;
75static cl::opt<bool, true> LineRegexp("x", cl::desc("Require that entire lines be matched (alias: -line-regexp)."), cl::cat(RE_Options), 
76                                      cl::location(LineRegexpFlag), cl::Grouping);
77static cl::alias LineRegexpAlias("line-regexp", cl::desc("Alias for -x"), cl::aliasopt(LineRegexp), cl::NotHidden);
78
79bool WordRegexpFlag;
80static cl::opt<bool, true> WordRegexp("w", cl::desc("Require that that whole words be matched (alias: -word-regexp)."), cl::cat(RE_Options),
81                                      cl::location(WordRegexpFlag), cl::Grouping);
82static cl::alias WordRegexpAlias("word-regexp", cl::desc("Alias for -w"), cl::aliasopt(WordRegexp), cl::NotHidden);
83
84const cl::OptionCategory * grep_regexp_flags() {
85    return &RE_Options;
86}
87
88static cl::OptionCategory GrepInputOptions("B. Input Options",
89                                             "These options control the input.");
90
91static cl::opt<bool> NullData("z", cl::desc("Use the NUL character (codepoint 00) as the line-break character for input."), cl::cat(GrepInputOptions), cl::Grouping);
92static cl::alias NullDataAlias("null-data", cl::desc("Alias for -z"), cl::aliasopt(NullData));
93
94bool RecursiveFlag;
95static cl::opt<bool, true> Recursive("r", cl::desc("Recursively process files within directories, (but follow only top-level symlinks unless -R)."), 
96                               cl::location(RecursiveFlag), cl::cat(GrepInputOptions), cl::Grouping);
97static cl::alias RecursiveAlias("recursive", cl::desc("Alias for -r"), cl::aliasopt(Recursive));
98
99bool DereferenceRecursiveFlag;
100static cl::opt<bool, true> DereferenceRecursive("R", cl::desc("Recursively process files within directories, following symlinks at all levels."),
101                                          cl::location(DereferenceRecursiveFlag), cl::cat(GrepInputOptions), cl::Grouping);
102static cl::alias DereferenceRecursiveAlias("dereference-recursive", cl::desc("Alias for -R"), cl::aliasopt(DereferenceRecursive));
103
104
105
106
107static cl::OptionCategory bGrepOutputOptions("C. Output Options",
108                                             "These options control the output.");
109
110GrepModeType Mode;
111static cl::opt<GrepModeType, true> GrepModeOption(cl::desc("Abbreviated output mode options:"),
112    cl::values(
113        clEnumValN(CountOnly, "c", "Display only the count of matching lines per file."),
114        clEnumValN(FilesWithMatch, "l", "Display only the names of files that have at least one match to the pattern."),
115        clEnumValN(FilesWithoutMatch, "L", "Display only the names of files that do not match the pattern."),
116        clEnumValN(QuietMode, "q", "Do not generate any output and ignore errors; set the return to zero status if a match is found."),
117        clEnumValN(CountOnly, "count", "Alias for -c"),
118        clEnumValN(FilesWithMatch, "files-with-match", "Alias for -l"),
119        clEnumValN(FilesWithoutMatch, "files-without-match", "Alias for -L"),
120        clEnumValN(QuietMode, "quiet", "Alias for -q"),
121        clEnumValN(QuietMode, "silent", "Alias for -q"),
122        clEnumValEnd), cl::cat(bGrepOutputOptions), cl::Grouping, cl::location(Mode), cl::init(NormalMode));
123
124
125static cl::opt<bool> SilenceFileErrors("s", cl::desc("Suppress messages for file errors."), cl::init(false),  cl::cat(bGrepOutputOptions));
126
127static cl::opt<bool> NormalizeLineBreaks("normalize-line-breaks", cl::desc("Normalize line breaks to std::endl."), cl::init(false),  cl::cat(bGrepOutputOptions));
128
129static cl::opt<bool> ShowFileNames("H", cl::desc("Show the file name with each matching line."), cl::cat(bGrepOutputOptions));
130static cl::alias ShowFileNamesLong("with-filename", cl::desc("Alias for -H"), cl::aliasopt(ShowFileNames));
131
132static cl::opt<bool> ShowLineNumbers("n", cl::desc("Show the line number with each matching line."), cl::cat(bGrepOutputOptions));
133static cl::alias ShowLineNumbersLong("line-number", cl::desc("Alias for -n"), cl::aliasopt(ShowLineNumbers));
134
135static cl::opt<int> MaxCount("m", cl::desc("Limit the number of matches per file."), cl::cat(bGrepOutputOptions), cl::init((size_t) 0), cl::Prefix);
136static cl::alias MaxCountLong("max-count", cl::desc("Alias for -m"), cl::aliasopt(MaxCount));
137
138static cl::opt<int> AfterContext("A", cl::desc("Print <num> lines of context after each matching line."), cl::cat(bGrepOutputOptions), cl::Prefix);
139static cl::alias AfterContextAlias("after-context", cl::desc("Alias for -A"), cl::aliasopt(AfterContext));
140
141static cl::opt<int> BeforeContext("B", cl::desc("Print <num>lines of context before each matching line."), cl::cat(bGrepOutputOptions), cl::Prefix);
142static cl::alias BeforeContextAlias("before-context", cl::desc("Alias for -B"), cl::aliasopt(BeforeContext));
143
144static cl::opt<int> Context("C", cl::desc("Print <num> lines of context before and after each matching line."), cl::cat(bGrepOutputOptions), cl::Prefix);
145static cl::alias ContextAlias("context", cl::desc("Alias for -C"), cl::aliasopt(Context));
146
147static cl::opt<bool> OnlyMatching("o", cl::desc("Display only the exact strings that match the pattern, with possibly multiple matches per line."), cl::cat(bGrepOutputOptions), cl::Grouping);
148static cl::alias OnlyMatchingAlias("only-matching", cl::desc("Alias for -o"), cl::aliasopt(OnlyMatching));
149
150static cl::opt<bool> Null("Z", cl::desc("Write NUL characters after filenames generated to output."), cl::cat(bGrepOutputOptions), cl::Grouping);
151static cl::alias NullAlias("null", cl::desc("Alias for -Z"), cl::aliasopt(Null));
152
153static cl::opt<bool> ByteOffset("b", cl::desc("Show the byte offset within the file for each matching line."), cl::cat(bGrepOutputOptions), cl::Grouping);
154static cl::alias ByteOffsetAlias("byte-offset", cl::desc("Alias for -b"), cl::aliasopt(ByteOffset));
155
156static cl::opt<bool> UnixByteOffsets("u", cl::desc("If byte offsets are displayed, report offsets as if all lines are terminated with a single LF."), cl::cat(bGrepOutputOptions), cl::Grouping);
157static cl::alias UnixByteOffsetsAlias("unix-byte-offsets", cl::desc("Alias for -u"), cl::aliasopt(UnixByteOffsets));
158
159static cl::opt<bool> InitialTab("T", cl::desc("Line up matched line content using an inital tab character."), cl::cat(bGrepOutputOptions), cl::Grouping);
160static cl::alias InitialTabAlias("initial-tab", cl::desc("Alias for -T"), cl::aliasopt(InitialTab));
161
162
163const cl::OptionCategory * grep_output_flags() {
164    return &bGrepOutputOptions;
165}
166
167const cl::OptionCategory * grep_input_flags() {
168    return &GrepInputOptions;
169}
170
171
172static re::CC * parsedCodePointSet = nullptr;
173
174static std::vector<std::string> parsedPropertyValues;
175
176size_t * startPoints = nullptr;
177size_t * accumBytes = nullptr;
178
179
180void GrepEngine::doGrep(const std::string & fileName) const{
181#ifdef CUDA_ENABLED
182    const bool CountOnly = true;
183    boost::filesystem::path file(fileName);
184    if (exists(file)) {
185        if (is_directory(file)) {
186            return;
187        }
188    } else {
189        if (!SilenceFileErrors) {
190            std::cerr << "Error: cannot open " << fileName << " for processing. Skipped.\n";
191            return;
192        }
193    }
194
195    const auto fileSize = file_size(file);
196   
197    if (fileSize > 0) {
198        try {
199            boost::iostreams::mapped_file_source source(fileName, fileSize, 0);
200            char * fileBuffer = const_cast<char *>(source.data());
201           
202            codegen::BlockSize = 128;
203            std::vector<size_t> LFPositions = preprocess(fileBuffer, fileSize);
204           
205            const unsigned numOfGroups = codegen::GroupNum;
206            if (posix_memalign((void**)&startPoints, 8, (numOfGroups+1)*sizeof(size_t)) ||
207                posix_memalign((void**)&accumBytes, 8, (numOfGroups+1)*sizeof(size_t))) {
208                std::cerr << "Cannot allocate memory for startPoints or accumBytes.\n";
209                exit(-1);
210            }
211            const auto PTXFilename = mGrepDriver->getBuilder()->getModule()->getModuleIdentifier() + ".ptx";
212            ulong * rslt = RunPTX(PTXFilename, fileBuffer, fileSize, CountOnly, LFPositions, startPoints, accumBytes);
213            source.close();
214        } catch (std::exception & e) {
215            if (!SilenceFileErrors) {
216                std::cerr << "Boost mmap error: " + fileName + ": " + e.what() + " Skipped.\n";
217                return;
218            }
219        }
220    } else {
221        std::cout << 0 << std::endl;
222    }
223#endif
224}
225
226uint64_t GrepEngine::doGrep(const std::string & fileName, const uint32_t fileIdx) const {
227    const int32_t fd = open(fileName.c_str(), O_RDONLY);
228    if (LLVM_UNLIKELY(fd == -1)) {
229        return 0;
230    }
231    const auto result = doGrep(fd, fileIdx);
232    close(fd);
233    return result;
234}
235
236uint64_t GrepEngine::doGrep(const int32_t fileDescriptor, const uint32_t fileIdx) const {
237    assert (mGrepDriver);
238    typedef uint64_t (*GrepFunctionType)(int32_t fileDescriptor, const uint32_t fileIdx);
239    auto f = reinterpret_cast<GrepFunctionType>(mGrepDriver->getMain());
240    return f(fileDescriptor, fileIdx);
241}
242
243void GrepEngine::doGrep(const char * buffer, const uint64_t length, const uint32_t fileIdx) const {
244    assert (mGrepDriver);
245    typedef uint64_t (*GrepFunctionType)(const char * buffer, const uint64_t length, const uint32_t fileIdx);
246    auto f = reinterpret_cast<GrepFunctionType>(mGrepDriver->getMain());
247    f(buffer, length, fileIdx);
248}
249
250static int * total_count;
251static std::stringstream * resultStrs = nullptr;
252static std::vector<std::string> inputFiles;
253
254void initFileResult(std::vector<std::string> filenames){
255    const int n = filenames.size();
256    if (n > 1) {
257        ShowFileNames = true;
258    }
259    inputFiles = filenames;
260    resultStrs = new std::stringstream[n];
261    total_count = new int[n];
262    for (unsigned i = 0; i < inputFiles.size(); ++i){
263        total_count[i] = 0;
264    }
265
266}
267
268template<typename CodeUnit>
269void 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) {
270
271//    errs().write_hex((size_t)buffer) << " : " << lineNum << " (" << line_start << ", " << line_end << ", " << filesize << ")\n";
272
273    assert (buffer);
274    assert (line_start <= line_end);
275    assert (line_end <= filesize);
276
277    if (ShowFileNames) {
278        resultStrs[fileIdx] << inputFiles[fileIdx] << ':';
279    }
280    if (ShowLineNumbers) {
281        // Internally line numbers are counted from 0.  For display, adjust
282        // the line number so that lines are numbered from 1.
283        resultStrs[fileIdx] << lineNum+1 << ":";
284    }
285
286    // If the line "starts" on the LF of a CRLF, it is actually the end of the last line.
287    if ((buffer[line_start] == 0xA) && (line_start != line_end)) {
288        ++line_start;
289    }
290
291    if (LLVM_UNLIKELY(line_end == filesize)) {
292        // The match position is at end-of-file.   We have a final unterminated line.
293        resultStrs[fileIdx].write((char *)&buffer[line_start], (line_end - line_start) * sizeof(CodeUnit));
294        if (NormalizeLineBreaks) {
295            resultStrs[fileIdx] << '\n';  // terminate it
296        }
297    } else {
298        const auto end_byte = buffer[line_end];
299        if (NormalizeLineBreaks) {
300            if (LLVM_UNLIKELY(end_byte == 0x85)) {
301                // Line terminated with NEL, on the second byte.  Back up 1.
302                line_end -= 1;
303            } else if (LLVM_UNLIKELY(end_byte > 0xD)) {
304                // Line terminated with PS or LS, on the third byte.  Back up 2.
305                line_end -= 2;
306            }
307            resultStrs[fileIdx].write((char *)&buffer[line_start], (line_end - line_start) * sizeof(CodeUnit));
308            resultStrs[fileIdx] << '\n';
309        } else {
310            if (end_byte == 0x0D) {
311                // Check for line_end on first byte of CRLF; we don't want to access past the end of buffer.
312                if ((line_end + 1) < filesize) {
313                    if (buffer[line_end + 1] == 0x0A) {
314                        // Found CRLF; preserve both bytes.
315                        ++line_end;
316                    }
317                }
318            }
319            resultStrs[fileIdx].write((char *)&buffer[line_start], (line_end - line_start + 1) * sizeof(CodeUnit));
320        }
321    }
322}
323
324const int MatchFoundReturnCode = 0;
325const int MatchNotFoundReturnCode = 1;
326void PrintResult(GrepModeType grepMode, std::vector<size_t> & total_CountOnly){
327    if (grepMode == NormalMode) {
328        int returnCode = MatchNotFoundReturnCode;
329        for (unsigned i = 0; i < inputFiles.size(); ++i){
330            std::cout << resultStrs[i].str();
331            if (!resultStrs[i].str().empty()) returnCode = MatchFoundReturnCode;
332        }
333        exit(returnCode);
334    }
335    if (grepMode == CountOnly) {
336        size_t total = 0;
337        if (!ShowFileNames) {
338            for (unsigned i = 0; i < inputFiles.size(); ++i) {
339                std::cout << total_CountOnly[i] << std::endl;
340                total += total_CountOnly[i];
341            }
342        } else {
343            for (unsigned i = 0; i < inputFiles.size(); ++i){
344                std::cout << inputFiles[i] << ':' << total_CountOnly[i] << std::endl;
345                total += total_CountOnly[i];
346            };
347        }
348        exit(total == 0 ? MatchNotFoundReturnCode : MatchFoundReturnCode);
349    }
350    else if (grepMode == FilesWithMatch || grepMode == FilesWithoutMatch ) {
351        size_t total = 0;
352        size_t requiredCount = grepMode == FilesWithMatch ? 1 : 0;
353        for (unsigned i = 0; i < inputFiles.size(); ++i) {
354            if (total_CountOnly[i] == requiredCount) {
355                std::cout << inputFiles[i] << std::endl;
356            }
357            total += total_CountOnly[i];
358        }
359        exit(total == 0 ? MatchNotFoundReturnCode : MatchFoundReturnCode);
360    } else /* QuietMode */ {
361        for (unsigned i = 0; i < inputFiles.size(); ++i){
362            if (total_CountOnly[i] > 0) exit(MatchFoundReturnCode);
363        }
364        exit(MatchNotFoundReturnCode);
365    }
366}
367
368void insert_codepoints(const size_t lineNum, const size_t line_start, const size_t line_end, const char * const buffer) {
369    assert (buffer);
370    assert (line_start <= line_end);
371    re::codepoint_t c = 0;
372    size_t line_pos = line_start;
373    while (isxdigit(buffer[line_pos])) {
374        assert (line_pos < line_end);
375        if (isdigit(buffer[line_pos])) {
376            c = (c << 4) | (buffer[line_pos] - '0');
377        }
378        else {
379            c = (c << 4) | (tolower(buffer[line_pos]) - 'a' + 10);
380        }
381        line_pos++;
382    }
383    assert(((line_pos - line_start) >= 4) && ((line_pos - line_start) <= 6)); // UCD format 4 to 6 hex digits.
384    parsedCodePointSet->insert(c);
385}
386
387void insert_property_values(size_t lineNum, size_t line_start, size_t line_end, const char * buffer) {
388    assert (line_start <= line_end);
389    parsedPropertyValues.emplace_back(buffer + line_start, buffer + line_end);
390}
391
392void GrepEngine::grepCodeGen_nvptx(std::vector<re::RE *> REs, const GrepModeType grepMode, const bool UTF_16) {
393
394    assert (mGrepDriver == nullptr);
395
396    mGrepDriver = new NVPTXDriver("engine");
397    auto & idb = mGrepDriver->getBuilder();
398    Module * M = idb->getModule();
399
400    const unsigned segmentSize = codegen::SegmentSize;
401    const unsigned bufferSegments = codegen::BufferSegments * codegen::ThreadNum;
402    const unsigned encodingBits = UTF_16 ? 16 : 8;
403
404    Type * const int64Ty = idb->getInt64Ty();
405    Type * const int32Ty = idb->getInt32Ty();
406    Type * const size_ty = idb->getSizeTy();
407    Type * const sizeTyPtr = PointerType::get(size_ty, 1);
408    Type * const int64tyPtr = PointerType::get(int64Ty, 1);
409    Type * const voidTy = idb->getVoidTy();
410
411    Function * mainFunc = cast<Function>(M->getOrInsertFunction("Main", voidTy, int64tyPtr, sizeTyPtr, sizeTyPtr, int64tyPtr, nullptr));
412    mainFunc->setCallingConv(CallingConv::C);
413    idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
414    auto args = mainFunc->arg_begin();
415
416    Value * const inputPtr = &*(args++);
417    inputPtr->setName("inputPtr");
418    Value * const startPointsPtr = &*(args++);
419    startPointsPtr->setName("startPointsPtr");
420    Value * const bufferSizesPtr = &*(args++);
421    bufferSizesPtr->setName("bufferSizesPtr");
422    Value * const outputPtr = &*(args++);
423    outputPtr->setName("outputPtr");
424
425    Function * tidFunc = M->getFunction("llvm.nvvm.read.ptx.sreg.tid.x");
426    Value * tid = idb->CreateCall(tidFunc);
427    Function * bidFunc = cast<Function>(M->getOrInsertFunction("llvm.nvvm.read.ptx.sreg.ctaid.x", int32Ty, nullptr));
428    Value * bid = idb->CreateCall(bidFunc);
429
430    Value * startPoint = idb->CreateLoad(idb->CreateGEP(startPointsPtr, bid));
431    Value * startBlock = idb->CreateUDiv(startPoint, ConstantInt::get(int64Ty, idb->getBitBlockWidth()));
432    Type * const inputStreamType = PointerType::get(ArrayType::get(ArrayType::get(idb->getBitBlockType(), 8), 1), 1);   
433    Value * inputStreamPtr = idb->CreateGEP(idb->CreateBitCast(inputPtr, inputStreamType), startBlock);
434    Value * inputStream = idb->CreateGEP(inputStreamPtr, tid);
435    Value * bufferSize = idb->CreateLoad(idb->CreateGEP(bufferSizesPtr, bid));
436
437    StreamSetBuffer * ByteStream = mGrepDriver->addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8), 1));
438    kernel::Kernel * sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, inputStreamType, segmentSize));
439    sourceK->setInitialArguments({inputStream, bufferSize});
440    mGrepDriver->makeKernelCall(sourceK, {}, {ByteStream});
441
442    StreamSetBuffer * BasisBits = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(8, 1), segmentSize * bufferSegments));
443    kernel::Kernel * s2pk = mGrepDriver->addKernelInstance(make_unique<kernel::S2PKernel>(idb));
444    mGrepDriver->makeKernelCall(s2pk, {ByteStream}, {BasisBits});
445 
446    StreamSetBuffer * LineBreakStream = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
447    kernel::Kernel * linebreakK = mGrepDriver->addKernelInstance(make_unique<kernel::LineBreakKernelBuilder>(idb, encodingBits));
448    mGrepDriver->makeKernelCall(linebreakK, {BasisBits}, {LineBreakStream});
449   
450    const auto n = REs.size();
451
452    std::vector<StreamSetBuffer *> MatchResultsBufs(n);
453
454    for(unsigned i = 0; i < n; ++i){
455        StreamSetBuffer * MatchResults = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
456        kernel::Kernel * icgrepK = mGrepDriver->addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, REs[i]));
457        mGrepDriver->makeKernelCall(icgrepK, {BasisBits, LineBreakStream}, {MatchResults});
458        MatchResultsBufs[i] = MatchResults;
459    }
460    StreamSetBuffer * MergedResults = MatchResultsBufs[0];
461    if (REs.size() > 1) {
462        MergedResults = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
463        kernel::Kernel * streamsMergeK = mGrepDriver->addKernelInstance(make_unique<kernel::StreamsMerge>(idb, 1, REs.size()));
464        mGrepDriver->makeKernelCall(streamsMergeK, MatchResultsBufs, {MergedResults});
465    }
466
467    kernel::MatchCount matchCountK(idb);
468    mGrepDriver->addKernelCall(matchCountK, {MergedResults}, {});
469    mGrepDriver->generatePipelineIR();
470
471    idb->setKernel(&matchCountK);
472    Value * matchedLineCount = idb->getScalarField("matchedLineCount");
473    matchedLineCount = idb->CreateZExt(matchedLineCount, int64Ty);
474   
475    Value * strideBlocks = ConstantInt::get(int32Ty, idb->getStride() / idb->getBitBlockWidth());
476    Value * outputThreadPtr = idb->CreateGEP(outputPtr, idb->CreateAdd(idb->CreateMul(bid, strideBlocks), tid));
477    idb->CreateStore(matchedLineCount, outputThreadPtr);
478    idb->CreateRetVoid();
479
480    mGrepDriver->finalizeObject();
481}
482
483void GrepEngine::grepCodeGen(std::vector<re::RE *> REs, const GrepModeType grepMode, const bool UTF_16, GrepSource grepSource, const GrepType grepType) {
484
485    assert (mGrepDriver == nullptr);
486    mGrepDriver = new ParabixDriver("engine");
487    auto & idb = mGrepDriver->getBuilder();
488    Module * M = idb->getModule();
489
490    const unsigned segmentSize = codegen::SegmentSize;
491    const unsigned bufferSegments = codegen::BufferSegments * codegen::ThreadNum;
492    const unsigned encodingBits = UTF_16 ? 16 : 8;
493
494    Type * const int64Ty = idb->getInt64Ty();
495    Type * const int32Ty = idb->getInt32Ty();
496
497    Function * mainFunc = nullptr;
498    Value * fileIdx = nullptr;
499    StreamSetBuffer * ByteStream = nullptr;
500    kernel::Kernel * sourceK = nullptr;
501   
502    size_t MatchLimit = ((grepMode == QuietMode) | (grepMode == FilesWithMatch) | (grepMode == FilesWithoutMatch)) ? 1 : MaxCount;
503
504    if (grepSource == GrepSource::Internal) {
505
506        mainFunc = cast<Function>(M->getOrInsertFunction("Main", int64Ty, idb->getInt8PtrTy(), int64Ty, int32Ty, nullptr));
507        mainFunc->setCallingConv(CallingConv::C);
508        idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
509        auto args = mainFunc->arg_begin();
510
511        Value * const buffer = &*(args++);
512        buffer->setName("buffer");
513
514        Value * length = &*(args++);
515        length->setName("length");
516        length = idb->CreateZExtOrTrunc(length, idb->getSizeTy());
517
518        fileIdx = &*(args++);
519        fileIdx->setName("fileIdx");
520
521        ByteStream = mGrepDriver->addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8)));
522
523        sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::MemorySourceKernel>(idb, idb->getInt8PtrTy(), segmentSize));
524        sourceK->setInitialArguments({buffer, length});
525
526    } else {
527
528        mainFunc = cast<Function>(M->getOrInsertFunction("Main", int64Ty, idb->getInt32Ty(), int32Ty, nullptr));
529        mainFunc->setCallingConv(CallingConv::C);
530        idb->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFunc, 0));
531        auto args = mainFunc->arg_begin();
532
533        Value * const fileDescriptor = &*(args++);
534        fileDescriptor->setName("fileDescriptor");
535        fileIdx = &*(args++);
536        fileIdx->setName("fileIdx");
537
538        ByteStream = mGrepDriver->addBuffer(make_unique<SourceBuffer>(idb, idb->getStreamSetTy(1, 8)));
539
540        if (grepSource == GrepSource::File) {
541            sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::MMapSourceKernel>(idb, segmentSize));
542            sourceK->setInitialArguments({fileDescriptor});
543        } else { // if (grepSource == GrepSource::StdIn) {
544            sourceK = mGrepDriver->addKernelInstance(make_unique<kernel::ReadSourceKernel>(idb, segmentSize));
545            sourceK->setInitialArguments({idb->getInt32(STDIN_FILENO)});
546        }
547    }
548
549    mGrepDriver->makeKernelCall(sourceK, {}, {ByteStream});
550    StreamSetBuffer * BasisBits = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(8, 1), segmentSize * bufferSegments));
551   
552    kernel::Kernel * s2pk = mGrepDriver->addKernelInstance(make_unique<kernel::S2PKernel>(idb));
553    mGrepDriver->makeKernelCall(s2pk, {ByteStream}, {BasisBits});
554   
555    kernel::Kernel * linebreakK = mGrepDriver->addKernelInstance(make_unique<kernel::LineBreakKernelBuilder>(idb, encodingBits));
556    StreamSetBuffer * LineBreakStream = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
557    mGrepDriver->makeKernelCall(linebreakK, {BasisBits}, {LineBreakStream});
558   
559    const auto n = REs.size();
560
561    std::vector<StreamSetBuffer *> MatchResultsBufs(n);
562
563    for(unsigned i = 0; i < n; ++i){
564        StreamSetBuffer * MatchResults = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
565        kernel::Kernel * icgrepK = mGrepDriver->addKernelInstance(make_unique<kernel::ICGrepKernel>(idb, REs[i]));
566        mGrepDriver->makeKernelCall(icgrepK, {BasisBits, LineBreakStream}, {MatchResults});
567        MatchResultsBufs[i] = MatchResults;
568    }
569    StreamSetBuffer * MergedResults = MatchResultsBufs[0];
570    if (REs.size() > 1) {
571        MergedResults = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
572        kernel::Kernel * streamsMergeK = mGrepDriver->addKernelInstance(make_unique<kernel::StreamsMerge>(idb, 1, REs.size()));
573        mGrepDriver->makeKernelCall(streamsMergeK, MatchResultsBufs, {MergedResults});
574    }
575   
576    if (InvertMatch) {
577        kernel::Kernel * invertK = mGrepDriver->addKernelInstance(make_unique<kernel::InvertMatchesKernel>(idb));
578        StreamSetBuffer * OriginalMatches = MergedResults;
579        MergedResults = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
580        mGrepDriver->makeKernelCall(invertK, {OriginalMatches, LineBreakStream}, {MergedResults});
581    }
582    if (MatchLimit > 0) {
583        kernel::Kernel * untilK = mGrepDriver->addKernelInstance(make_unique<kernel::UntilNkernel>(idb));
584        untilK->setInitialArguments({idb->getSize(MatchLimit)});
585        StreamSetBuffer * AllMatches = MergedResults;
586        MergedResults = mGrepDriver->addBuffer(make_unique<CircularBuffer>(idb, idb->getStreamSetTy(1, 1), segmentSize * bufferSegments));
587        mGrepDriver->makeKernelCall(untilK, {AllMatches}, {MergedResults});
588    }
589    if (grepMode != NormalMode) {
590        kernel::Kernel * matchCountK = mGrepDriver->addKernelInstance(make_unique<kernel::MatchCount>(idb));
591        mGrepDriver->makeKernelCall(matchCountK, {MergedResults}, {});
592        mGrepDriver->generatePipelineIR();
593        idb->setKernel(matchCountK);
594        Value * matchedLineCount = idb->getScalarField("matchedLineCount");
595        matchedLineCount = idb->CreateZExt(matchedLineCount, int64Ty);
596        idb->CreateRet(matchedLineCount);
597    } else {
598        kernel::Kernel * scanMatchK = mGrepDriver->addKernelInstance(make_unique<kernel::ScanMatchKernel>(idb, grepType, encodingBits));
599        scanMatchK->setInitialArguments({fileIdx});
600        mGrepDriver->makeKernelCall(scanMatchK, {MergedResults, LineBreakStream, ByteStream}, {});
601        switch (grepType) {
602            case GrepType::Normal:
603                if (UTF_16) {
604                    mGrepDriver->LinkFunction(*scanMatchK, "matcher", &wrapped_report_match<uint16_t>);
605                } else {
606                    mGrepDriver->LinkFunction(*scanMatchK, "matcher", &wrapped_report_match<uint8_t>);
607                }
608                break;
609            case GrepType::NameExpression:
610                mGrepDriver->LinkFunction(*scanMatchK, "matcher", &insert_codepoints);
611                break;
612            case GrepType::PropertyValue:
613                mGrepDriver->LinkFunction(*scanMatchK, "matcher", &insert_property_values);
614                break;
615        }
616        mGrepDriver->generatePipelineIR();
617        idb->CreateRet(idb->getInt64(0));
618    }
619    mGrepDriver->finalizeObject();
620}
621
622re::CC * GrepEngine::grepCodepoints() {
623    parsedCodePointSet = re::makeCC();
624    char * mFileBuffer = getUnicodeNameDataPtr();
625    size_t mFileSize = getUnicodeNameDataSize();
626    doGrep(mFileBuffer, mFileSize, 0);
627    return parsedCodePointSet;
628}
629
630const std::vector<std::string> & GrepEngine::grepPropertyValues(const std::string& propertyName) {
631    enum { MaxSupportedVectorWidthInBytes = 32 };
632    AlignedAllocator<char, MaxSupportedVectorWidthInBytes> alloc;
633    parsedPropertyValues.clear();
634    const std::string & str = UCD::getPropertyValueGrepString(propertyName);
635    const auto n = str.length();
636    // NOTE: MaxSupportedVectorWidthInBytes of trailing 0s are needed to prevent the grep function from
637    // erroneously matching garbage data when loading the final partial block.
638    char * aligned = alloc.allocate(n + MaxSupportedVectorWidthInBytes, 0);
639    std::memcpy(aligned, str.data(), n);
640    std::memset(aligned + n, 0, MaxSupportedVectorWidthInBytes);
641    doGrep(aligned, n, 0);
642    alloc.deallocate(aligned, 0);
643    return parsedPropertyValues;
644}
645
646GrepEngine::GrepEngine()
647: mGrepDriver(nullptr) {
648
649}
650
651GrepEngine::~GrepEngine() {
652    delete mGrepDriver;
653}
654
655}
Note: See TracBrowser for help on using the repository browser.