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

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

Refactor: move grep-specific code out of toolchain

File size: 10.3 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#include <fstream>
29#include <sstream>
30#include <iostream>
31#include <string>
32#include <stdint.h>
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <errno.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <stdexcept>
41#include <cctype>
42
43
44#include <llvm/Support/raw_os_ostream.h>
45
46// mmap system
47#include <boost/filesystem.hpp>
48#include <boost/iostreams/device/mapped_file.hpp>
49using namespace boost::iostreams;
50using namespace boost::filesystem;
51
52#include <fcntl.h>
53
54#include <kernels/kernel.h>
55
56static cl::OptionCategory bGrepOutputOptions("Output Options",
57                                             "These options control the output.");
58
59static cl::opt<bool> NormalizeLineBreaks("normalize-line-breaks", cl::desc("Normalize line breaks to std::endl."), cl::init(false),  cl::cat(bGrepOutputOptions));
60
61static cl::opt<bool> ShowFileNames("H", cl::desc("Show the file name with each matching line."), cl::cat(bGrepOutputOptions));
62static cl::alias ShowFileNamesLong("with-filename", cl::desc("Alias for -H"), cl::aliasopt(ShowFileNames));
63
64static cl::opt<bool> ShowLineNumbers("n", cl::desc("Show the line number with each matching line."), cl::cat(bGrepOutputOptions));
65static cl::alias ShowLineNumbersLong("line-number", cl::desc("Alias for -n"), cl::aliasopt(ShowLineNumbers));
66
67
68
69
70bool GrepEngine::finalLineIsUnterminated(const char * const fileBuffer, const size_t fileSize) {
71    if (fileSize == 0) return false;
72    unsigned char end_byte = static_cast<unsigned char>(fileBuffer[fileSize-1]);
73    // LF through CR are line break characters
74    if ((end_byte >= 0xA) && (end_byte <= 0xD)) return false;
75    // Other line breaks require at least two bytes.
76    if (fileSize == 1) return true;
77    // NEL
78    unsigned char penult_byte = static_cast<unsigned char>(fileBuffer[fileSize-2]);
79    if ((end_byte == 0x85) && (penult_byte == 0xC2)) return false;
80    if (fileSize == 2) return true;
81    // LS and PS
82    if ((end_byte < 0xA8) || (end_byte > 0xA9)) return true;
83    return (static_cast<unsigned char>(fileBuffer[fileSize-3]) != 0xE2) || (penult_byte != 0x80);
84}
85
86void GrepEngine::doGrep(const std::string & fileName, const int fileIdx, bool CountOnly, std::vector<int> & total_CountOnly) {
87    const 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 size_t fileSize = file_size(file);
98    if (fileSize > 0) {
99        mapped_file_source file;
100        try {
101            file.open(fileName);
102        } catch (std::exception &e) {
103            throw std::runtime_error("Boost mmap error: " + fileName + ": " + e.what());
104        }
105        char * fileBuffer = const_cast<char *>(file.data());
106        if(CountOnly){
107            total_CountOnly[fileIdx] = mGrepFunction_CountOnly(fileBuffer, fileSize, fileIdx, finalLineIsUnterminated(fileBuffer, fileSize));
108        }
109        else{
110            mGrepFunction(fileBuffer, fileSize, fileIdx, finalLineIsUnterminated(fileBuffer, fileSize));
111        }
112        file.close();
113    }
114    else {
115        if(CountOnly) {
116            mGrepFunction_CountOnly(nullptr, 0, fileIdx, false);
117        }
118        else{
119            mGrepFunction(nullptr, 0, fileIdx, false);
120        }
121    }
122}
123
124
125void GrepEngine::grepCodeGen(std::string moduleName, re::RE * re_ast, bool CountOnly, bool isNameExpression) {
126    Module * M = new Module(moduleName, getGlobalContext());
127   
128    IDISA::IDISA_Builder * idb = IDISA::GetIDISA_Builder(M);
129
130    kernel::PipelineBuilder pipelineBuilder(M, idb);
131
132    Encoding encoding(Encoding::Type::UTF_8, 8);
133    mIsNameExpression = isNameExpression;
134    re_ast = re::regular_expression_passes(encoding, re_ast);   
135    pablo::PabloFunction * function = re::re2pablo_compiler(encoding, re_ast);
136   
137
138    pipelineBuilder.CreateKernels(function, isNameExpression);
139
140    llvm::Function * grepIR = pipelineBuilder.ExecuteKernels(CountOnly);
141
142    mEngine = JIT_to_ExecutionEngine(M);
143    ApplyObjectCache(mEngine);
144    icgrep_Linking(M, mEngine);
145   
146    #ifndef NDEBUG
147    verifyModule(*M, &dbgs());
148    #endif
149    mEngine->finalizeObject();
150    delete idb;
151
152    if(CountOnly){
153        mGrepFunction_CountOnly = reinterpret_cast<GrepFunctionType_CountOnly>(mEngine->getPointerToFunction(grepIR));
154    }
155    else{
156        mGrepFunction = reinterpret_cast<GrepFunctionType>(mEngine->getPointerToFunction(grepIR));
157    }
158
159}
160
161
162
163re::CC *  GrepEngine::grepCodepoints() {
164
165    setParsedCodePointSet();
166    char * mFileBuffer = getUnicodeNameDataPtr();
167    size_t mFileSize = getUnicodeNameDataSize();
168    std::string mFileName = "Uname.txt";
169
170    uint64_t finalLineUnterminated = 0;
171    if(finalLineIsUnterminated(mFileBuffer, mFileSize))
172        finalLineUnterminated = 1;   
173    mGrepFunction(mFileBuffer, mFileSize, 0, finalLineUnterminated);
174
175    return getParsedCodePointSet();
176}
177
178GrepEngine::~GrepEngine() {
179    delete mEngine;
180}
181
182
183static int * total_count;
184static std::stringstream * resultStrs = nullptr;
185static std::vector<std::string> inputFiles;
186
187void initResult(std::vector<std::string> filenames){
188    const int n = filenames.size();
189    if (n > 1) {
190        ShowFileNames = true;
191    }
192    inputFiles = filenames;
193    resultStrs = new std::stringstream[n];
194    total_count = new int[n];
195    for (int i=0; i<inputFiles.size(); i++){
196        total_count[i] = 0;
197    }
198   
199}
200
201extern "C" {
202    void wrapped_report_match(uint64_t lineNum, uint64_t line_start, uint64_t line_end, const char * buffer, uint64_t filesize, int fileIdx) {
203       
204        int idx = fileIdx;
205       
206        if (ShowFileNames) {
207            resultStrs[idx] << inputFiles[idx] << ':';
208        }
209        if (ShowLineNumbers) {
210            resultStrs[idx] << lineNum << ":";
211        }
212       
213        if ((buffer[line_start] == 0xA) && (line_start != line_end)) {
214            // The line "starts" on the LF of a CRLF.  Really the end of the last line.
215            line_start++;
216        }
217        if (line_end == filesize) {
218            // The match position is at end-of-file.   We have a final unterminated line.
219            resultStrs[idx].write(&buffer[line_start], line_end - line_start);
220            if (NormalizeLineBreaks) {
221                resultStrs[idx] << '\n';  // terminate it
222            }
223            return;
224        }
225        unsigned char end_byte = (unsigned char)buffer[line_end]; 
226        if (NormalizeLineBreaks) {
227            if (end_byte == 0x85) {
228                // Line terminated with NEL, on the second byte.  Back up 1.
229                line_end--;
230            } else if (end_byte > 0xD) {
231                // Line terminated with PS or LS, on the third byte.  Back up 2.
232                line_end -= 2;
233            }
234            resultStrs[idx].write(&buffer[line_start], line_end - line_start);
235            resultStrs[idx] << '\n';
236        }
237        else{   
238            if (end_byte == 0x0D) {
239                // Check for line_end on first byte of CRLF;  note that we don't
240                // want to access past the end of buffer.
241                if ((line_end + 1 < filesize) && (buffer[line_end + 1] == 0x0A)) {
242                    // Found CRLF; preserve both bytes.
243                    line_end++;
244                }
245            }
246            resultStrs[idx].write(&buffer[line_start], line_end - line_start + 1);
247        }
248    }
249}
250
251void PrintResult(bool CountOnly, std::vector<int> & total_CountOnly){
252    if(CountOnly){
253        if (!ShowFileNames) {
254            for (int i=0; i<inputFiles.size(); i++){
255                std::cout << total_CountOnly[i] << std::endl;
256            }
257        }
258        else {
259            for (int i=0; i<inputFiles.size(); i++){
260                std::cout << inputFiles[i] << ':' << total_CountOnly[i] << std::endl;
261            };
262        }
263        return;
264    }
265   
266    std::string out;
267    for (int i=0; i<inputFiles.size(); i++){
268        std::cout << resultStrs[i].str();
269    }
270}
271
272re::CC * parsedCodePointSet;
273
274extern "C" {
275    void insert_codepoints(uint64_t lineNum, uint64_t line_start, uint64_t line_end, const char * buffer) {
276        re::codepoint_t c = 0;
277        ssize_t line_pos = line_start;
278        while (isxdigit(buffer[line_pos])) {
279            if (isdigit(buffer[line_pos])) {
280                c = (c << 4) | (buffer[line_pos] - '0');
281            }
282            else {
283                c = (c << 4) | (tolower(buffer[line_pos]) - 'a' + 10);
284            }
285            line_pos++;
286        }
287        assert(((line_pos - line_start) >= 4) && ((line_pos - line_start) <= 6)); // UCD format 4 to 6 hex digits.       
288        parsedCodePointSet->insert(c);
289    }
290}
291
292void setParsedCodePointSet(){
293    parsedCodePointSet = re::makeCC();
294}
295
296re::CC * getParsedCodePointSet(){
297    return parsedCodePointSet;
298}
299
300
301
302
303void icgrep_Linking(Module * m, ExecutionEngine * e) {
304    Module::FunctionListType & fns = m->getFunctionList();
305    for (Module::FunctionListType::iterator it = fns.begin(), it_end = fns.end(); it != it_end; ++it) {
306        std::string fnName = it->getName().str();
307        if (fnName == "s2p_block") continue;
308        if (fnName == "process_block") continue;
309        if (fnName == "process_block_initialize_carries") continue;
310       
311        if (fnName == "wrapped_report_match") {
312            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&wrapped_report_match);
313        }
314        if (fnName == "insert_codepoints") {
315            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&insert_codepoints);
316        }
317#ifndef DISABLE_PREGENERATED_UCD_FUNCTIONS
318        else {
319            const UCD::ExternalProperty & ep = UCD::resolveExternalProperty(fnName);
320            e->addGlobalMapping(cast<GlobalValue>(it), std::get<0>(ep));
321        }
322#endif
323    }
324}
325
Note: See TracBrowser for help on using the repository browser.