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

Last change on this file since 5087 was 5087, checked in by cameron, 3 years ago

icgrep using doSegment; pipeline generation

File size: 13.5 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include <grep_engine.h>
8#include <IDISA/idisa_builder.h>
9#include <IDISA/idisa_target.h>
10#include <llvm/Support/CommandLine.h>
11#include <re/re_toolchain.h>
12#include <re/re_cc.h>
13
14#include <pablo/pablo_toolchain.h>
15#include <toolchain.h>
16#include <utf_encoding.h>
17#include <pablo/pablo_compiler.h>
18#include <kernels/pipeline.h>
19#include <llvm/IR/Function.h>
20#include <llvm/IR/Type.h>
21#include <llvm/IR/Module.h>
22#include <llvm/ExecutionEngine/MCJIT.h>
23#include <llvm/IRReader/IRReader.h>
24#include <llvm/Support/Debug.h>
25#include <llvm/IR/Verifier.h>
26#include <UCD/UnicodeNameData.h>
27
28
29#include <kernels/streamset.h>
30#include <kernels/scanmatchgen.h>
31#include <kernels/s2p_kernel.h>
32#include <kernels/pipeline.h>
33
34#include <pablo/function.h>
35#include <pablo/pablo_kernel.h>
36#include <pablo/pablo_toolchain.h>
37
38#include <llvm/IR/Intrinsics.h>
39#include "llvm/Support/SourceMgr.h"
40#include "llvm/IRReader/IRReader.h"
41#include "llvm/Linker/Linker.h"
42
43
44#include <fstream>
45#include <sstream>
46#include <iostream>
47#include <string>
48#include <stdint.h>
49
50#include <stdio.h>
51#include <stdlib.h>
52#include <unistd.h>
53#include <errno.h>
54#include <sys/types.h>
55#include <sys/stat.h>
56#include <stdexcept>
57#include <cctype>
58
59
60#include <llvm/Support/raw_os_ostream.h>
61
62// mmap system
63#include <boost/filesystem.hpp>
64#include <boost/iostreams/device/mapped_file.hpp>
65using namespace boost::iostreams;
66using namespace boost::filesystem;
67
68#include <fcntl.h>
69
70#include <kernels/kernel.h>
71
72static cl::OptionCategory bGrepOutputOptions("Output Options",
73                                             "These options control the output.");
74
75static cl::opt<bool> NormalizeLineBreaks("normalize-line-breaks", cl::desc("Normalize line breaks to std::endl."), cl::init(false),  cl::cat(bGrepOutputOptions));
76
77static cl::opt<bool> ShowFileNames("H", cl::desc("Show the file name with each matching line."), cl::cat(bGrepOutputOptions));
78static cl::alias ShowFileNamesLong("with-filename", cl::desc("Alias for -H"), cl::aliasopt(ShowFileNames));
79
80static cl::opt<bool> ShowLineNumbers("n", cl::desc("Show the line number with each matching line."), cl::cat(bGrepOutputOptions));
81static cl::alias ShowLineNumbersLong("line-number", cl::desc("Alias for -n"), cl::aliasopt(ShowLineNumbers));
82
83
84bool isUTF_16 = false;
85
86void GrepEngine::doGrep(const std::string & fileName, const int fileIdx, bool CountOnly, std::vector<uint64_t> & total_CountOnly, bool UTF_16) {
87    path file(fileName);
88    if (exists(file)) {
89        if (is_directory(file)) {
90            return;
91        }
92    } else {
93        std::cerr << "Error: cannot open " << fileName << " for processing. Skipped.\n";
94        return;
95    }
96
97    const auto fileSize = file_size(file);
98    if (fileSize > 0) {
99        try {
100            mapped_file_source source(fileName, fileSize, 0);
101            char * fileBuffer = const_cast<char *>(source.data());
102            if (CountOnly) {
103                total_CountOnly[fileIdx] = mGrepFunction_CountOnly(fileBuffer, fileSize, fileIdx);
104            } else {
105                mGrepFunction(fileBuffer, fileSize, fileIdx);
106            }
107            source.close();
108        } catch (std::exception & e) {
109            throw std::runtime_error("Boost mmap error: " + fileName + ": " + e.what());
110        }
111    } else {
112        if (CountOnly) {
113            mGrepFunction_CountOnly(nullptr, 0, fileIdx);
114        } else {
115            mGrepFunction(nullptr, 0, fileIdx);
116        }
117    }
118}
119
120
121void GrepEngine::grepCodeGen(std::string moduleName, re::RE * re_ast, bool CountOnly, bool UTF_16, bool isNameExpression) {
122    isUTF_16 = UTF_16; 
123    Module * M = new Module(moduleName, getGlobalContext());
124   
125    IDISA::IDISA_Builder * iBuilder = IDISA::GetIDISA_Builder(M);
126
127
128    Encoding::Type type;
129    type = UTF_16 ? Encoding::Type::UTF_16 : Encoding::Type::UTF_8;
130    unsigned bits;
131    bits = UTF_16 ? 16 : 8;
132
133    Encoding encoding(type, bits);
134
135    mIsNameExpression = isNameExpression;
136    re_ast = re::regular_expression_passes(encoding, re_ast);   
137    pablo::PabloFunction * function = re::re2pablo_compiler(encoding, re_ast);
138   
139    kernel::s2pKernel  s2pk(iBuilder);
140    kernel::scanMatchKernel scanMatchK(iBuilder, 64, false);
141   
142    s2pk.generateKernel();
143    scanMatchK.generateKernel();
144   
145    //std::unique_ptr<Module> s2pM = s2pk.createKernelModule();
146    //std::unique_ptr<Module> scanMatchM = scanMatchK.createKernelModule();
147   
148    //s2pk.addKernelDeclarations(mMod);
149    //scanMatchK.addKernelDeclarations(mMod);
150   
151    pablo_function_passes(function);
152    pablo::PabloKernel  icgrepK(iBuilder, "icgrep", function, {"matchedLineCount"});
153    icgrepK.generateKernel();
154   
155    //std::unique_ptr<Module> icgrepM = icgrepK.createKernelModule();
156    //icgrepK.addKernelDeclarations(mMod);
157   
158    Type * const int64ty = iBuilder->getInt64Ty();
159    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
160    Type * const inputType = PointerType::get(ArrayType::get(ArrayType::get(iBuilder->getBitBlockType(), (UTF_16 ? 16 : 8)), 1), 0);
161    Type * const resultTy = CountOnly ? int64ty : iBuilder->getVoidTy();
162    Function * const mainFn = cast<Function>(M->getOrInsertFunction("Main", resultTy, inputType, int64ty, int64ty, nullptr));
163    mainFn->setCallingConv(CallingConv::C);
164    iBuilder->SetInsertPoint(BasicBlock::Create(M->getContext(), "entry", mainFn, 0));
165    Function::arg_iterator args = mainFn->arg_begin();
166   
167    Value * const inputStream = &*(args++);
168    inputStream->setName("input");
169    Value * const fileSize = &*(args++);
170    fileSize->setName("fileSize");
171    Value * const fileIdx = &*(args++);
172    fileIdx->setName("fileIdx");
173
174    const unsigned segmentSize = codegen::SegmentSize;
175
176    kernel::StreamSetBuffer ByteStream(iBuilder, kernel::StreamSetType(1, (UTF_16 ? 16 : 8)), 0);
177    kernel::StreamSetBuffer BasisBits(iBuilder, kernel::StreamSetType((UTF_16 ? 16 : 8), 1), segmentSize);
178    ByteStream.setStreamSetBuffer(inputStream);
179    BasisBits.allocateBuffer();
180
181    if (CountOnly) {
182        Value * s2pInstance = s2pk.createInstance({}, {&ByteStream}, {&BasisBits});
183        Value * icgrepInstance = icgrepK.createInstance({}, {&BasisBits}, {});
184       
185        generatePipelineLoop(iBuilder, {&s2pk, &icgrepK}, {s2pInstance, icgrepInstance}, fileSize);
186        Value * matchCount = icgrepK.createGetAccumulatorCall(icgrepInstance, "matchedLineCount");
187        iBuilder->CreateRet(matchCount);
188    }
189    else {
190        kernel::StreamSetBuffer MatchResults(iBuilder, kernel::StreamSetType(2, 1), segmentSize);
191        ByteStream.setStreamSetBuffer(inputStream);
192        BasisBits.allocateBuffer();
193        MatchResults.allocateBuffer();
194       
195       
196        Value * s2pInstance = s2pk.createInstance({}, {&ByteStream}, {&BasisBits});
197        Value * icgrepInstance = icgrepK.createInstance({}, {&BasisBits}, {&MatchResults});
198        Value * scanMatchInstance = scanMatchK.createInstance({iBuilder->CreateBitCast(inputStream, int8PtrTy), fileSize, fileIdx}, {&MatchResults}, {});
199       
200        generatePipelineLoop(iBuilder, {&s2pk, &icgrepK, &scanMatchK}, {s2pInstance, icgrepInstance, scanMatchInstance}, fileSize);
201        iBuilder->CreateRetVoid();
202    }
203   
204    mEngine = JIT_to_ExecutionEngine(M);
205    ApplyObjectCache(mEngine);
206    icgrep_Linking(M, mEngine);
207
208#ifndef NDEBUG
209    verifyModule(*M, &dbgs());
210#endif
211
212    mEngine->finalizeObject();
213    delete iBuilder;
214   
215    if (CountOnly) {
216        mGrepFunction_CountOnly = reinterpret_cast<GrepFunctionType_CountOnly>(mEngine->getPointerToFunction(mainFn));
217    } else {
218        mGrepFunction = reinterpret_cast<GrepFunctionType>(mEngine->getPointerToFunction(mainFn));
219    }
220
221}
222
223
224
225re::CC *  GrepEngine::grepCodepoints() {
226
227    setParsedCodePointSet();
228    char * mFileBuffer = getUnicodeNameDataPtr();
229    size_t mFileSize = getUnicodeNameDataSize();
230
231    mGrepFunction(mFileBuffer, mFileSize, 0);
232
233    return getParsedCodePointSet();
234}
235
236GrepEngine::~GrepEngine() {
237    delete mEngine;
238}
239
240
241static int * total_count;
242static std::stringstream * resultStrs = nullptr;
243static std::vector<std::string> inputFiles;
244
245void initResult(std::vector<std::string> filenames){
246    const int n = filenames.size();
247    if (n > 1) {
248        ShowFileNames = true;
249    }
250    inputFiles = filenames;
251    resultStrs = new std::stringstream[n];
252    total_count = new int[n];
253    for (unsigned i = 0; i < inputFiles.size(); ++i){
254        total_count[i] = 0;
255    }
256   
257}
258
259extern "C" {
260    void wrapped_report_match(uint64_t lineNum, uint64_t line_start, uint64_t line_end, const char * buffer, uint64_t filesize, int fileIdx) {
261        int index = isUTF_16 ? 2 : 1;
262        int idx = fileIdx;
263         
264        if (ShowFileNames) {
265            resultStrs[idx] << inputFiles[idx] << ':';
266        }
267        if (ShowLineNumbers) {
268            resultStrs[idx] << lineNum << ":";
269        }
270       
271        if ((!isUTF_16 && buffer[line_start] == 0xA) && (line_start != line_end)) {
272            // The line "starts" on the LF of a CRLF.  Really the end of the last line.
273            line_start++;
274        }
275        if (((isUTF_16 && buffer[line_start] == 0x0) && buffer[line_start + 1] == 0xA) && (line_start != line_end)) {
276            // The line "starts" on the LF of a CRLF.  Really the end of the last line.
277            line_start += 2;
278        }
279        if (line_end == filesize) {
280            // The match position is at end-of-file.   We have a final unterminated line.
281            resultStrs[idx].write(&buffer[line_start * index], (line_end - line_start) * index);
282            if (NormalizeLineBreaks) {
283                resultStrs[idx] << '\n';  // terminate it
284            }
285            return;
286        }
287        unsigned char end_byte = (unsigned char)buffer[line_end]; 
288        unsigned char penult_byte = (unsigned char)(buffer[line_end - 1]);
289        if (NormalizeLineBreaks) {
290            if (end_byte == 0x85) {
291                // Line terminated with NEL, on the second byte.  Back up 1.
292                line_end--;
293            } else if (end_byte > 0xD) {
294                // Line terminated with PS or LS, on the third byte.  Back up 2.
295                isUTF_16 ? line_end-- : line_end -= 2;
296            }
297            resultStrs[idx].write(&buffer[line_start * index], (line_end - line_start) * index);
298            resultStrs[idx] << '\n';
299        }
300        else {   
301            if ((!isUTF_16 && end_byte == 0x0D) || (isUTF_16 && (end_byte == 0x0D && penult_byte == 0x0))) {
302                // Check for line_end on first byte of CRLF;  note that we don't
303                // want to access past the end of buffer.
304                if (line_end + 1 < filesize) {
305                    if (!isUTF_16 && buffer[line_end + 1] == 0x0A) {
306                        // Found CRLF; preserve both bytes.
307                        line_end++;
308                    }
309                    if (isUTF_16 && buffer[line_end + 1] == 0x0 && buffer[line_end + 2] == 0x0A) {
310                        // Found CRLF; preserve both bytes.
311                        line_end += 2;
312                    }
313                }
314            }
315            resultStrs[idx].write(&buffer[line_start * index], (line_end - line_start + 1) * index);
316        }
317    }
318}
319
320void PrintResult(bool CountOnly, std::vector<uint64_t> & total_CountOnly){
321    if(CountOnly){
322        if (!ShowFileNames) {
323            for (unsigned i = 0; i < inputFiles.size(); ++i){
324                std::cout << total_CountOnly[i] << std::endl;
325            }
326        }
327        else {
328            for (unsigned i = 0; i < inputFiles.size(); ++i){
329                std::cout << inputFiles[i] << ':' << total_CountOnly[i] << std::endl;
330            };
331        }
332        return;
333    }
334   
335    for (unsigned i = 0; i < inputFiles.size(); ++i){
336        std::cout << resultStrs[i].str();
337    }
338}
339
340re::CC * parsedCodePointSet;
341
342extern "C" {
343    void insert_codepoints(uint64_t lineNum, uint64_t line_start, uint64_t line_end, const char * buffer) {
344        re::codepoint_t c = 0;
345        ssize_t line_pos = line_start;
346        while (isxdigit(buffer[line_pos])) {
347            if (isdigit(buffer[line_pos])) {
348                c = (c << 4) | (buffer[line_pos] - '0');
349            }
350            else {
351                c = (c << 4) | (tolower(buffer[line_pos]) - 'a' + 10);
352            }
353            line_pos++;
354        }
355        assert(((line_pos - line_start) >= 4) && ((line_pos - line_start) <= 6)); // UCD format 4 to 6 hex digits.       
356        parsedCodePointSet->insert(c);
357    }
358}
359
360void setParsedCodePointSet(){
361    parsedCodePointSet = re::makeCC();
362}
363
364re::CC * getParsedCodePointSet(){
365    return parsedCodePointSet;
366}
367
368
369
370
371void icgrep_Linking(Module * m, ExecutionEngine * e) {
372    Module::FunctionListType & fns = m->getFunctionList();
373    for (Module::FunctionListType::iterator it = fns.begin(), it_end = fns.end(); it != it_end; ++it) {
374        std::string fnName = it->getName().str();
375        if (fnName == "s2p_block") continue;
376        if (fnName == "process_block") continue;
377        if (fnName == "process_block_initialize_carries") continue;
378       
379        if (fnName == "wrapped_report_match") {
380            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&wrapped_report_match);
381        }
382        if (fnName == "insert_codepoints") {
383            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&insert_codepoints);
384        }
385#ifndef DISABLE_PREGENERATED_UCD_FUNCTIONS
386        else {
387            const UCD::ExternalProperty & ep = UCD::resolveExternalProperty(fnName);
388            e->addGlobalMapping(cast<GlobalValue>(it), std::get<0>(ep));
389        }
390#endif
391    }
392}
393
Note: See TracBrowser for help on using the repository browser.