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

Last change on this file since 5037 was 5037, checked in by nmedfort, 3 years ago

UnicodeSet? bug fix and compile warning clean-up.

File size: 10.4 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<uint64_t> & total_CountOnly) {
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, finalLineIsUnterminated(fileBuffer, fileSize));
104            } else {
105                mGrepFunction(fileBuffer, fileSize, fileIdx, finalLineIsUnterminated(fileBuffer, fileSize));
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, false);
114        } else {
115            mGrepFunction(nullptr, 0, fileIdx, false);
116        }
117    }
118}
119
120
121void GrepEngine::grepCodeGen(std::string moduleName, re::RE * re_ast, bool CountOnly, bool isNameExpression) {
122    Module * M = new Module(moduleName, getGlobalContext());
123   
124    IDISA::IDISA_Builder * idb = IDISA::GetIDISA_Builder(M);
125
126    kernel::PipelineBuilder pipelineBuilder(M, idb);
127
128    Encoding encoding(Encoding::Type::UTF_8, 8);
129    mIsNameExpression = isNameExpression;
130    re_ast = re::regular_expression_passes(encoding, re_ast);   
131    pablo::PabloFunction * function = re::re2pablo_compiler(encoding, re_ast);
132   
133
134    pipelineBuilder.CreateKernels(function, isNameExpression);
135
136    llvm::Function * grepIR = pipelineBuilder.ExecuteKernels(CountOnly);
137
138    mEngine = JIT_to_ExecutionEngine(M);
139    ApplyObjectCache(mEngine);
140    icgrep_Linking(M, mEngine);
141   
142    #ifndef NDEBUG
143    verifyModule(*M, &dbgs());
144    #endif
145
146    mEngine->finalizeObject();
147    delete idb;
148
149    if (CountOnly) {
150        mGrepFunction_CountOnly = reinterpret_cast<GrepFunctionType_CountOnly>(mEngine->getPointerToFunction(grepIR));
151    } else {
152        mGrepFunction = reinterpret_cast<GrepFunctionType>(mEngine->getPointerToFunction(grepIR));
153    }
154
155}
156
157
158
159re::CC *  GrepEngine::grepCodepoints() {
160
161    setParsedCodePointSet();
162    char * mFileBuffer = getUnicodeNameDataPtr();
163    size_t mFileSize = getUnicodeNameDataSize();
164    std::string mFileName = "Uname.txt";
165
166    uint64_t finalLineUnterminated = 0;
167    if(finalLineIsUnterminated(mFileBuffer, mFileSize))
168        finalLineUnterminated = 1;   
169    mGrepFunction(mFileBuffer, mFileSize, 0, finalLineUnterminated);
170
171    return getParsedCodePointSet();
172}
173
174GrepEngine::~GrepEngine() {
175    delete mEngine;
176}
177
178
179static int * total_count;
180static std::stringstream * resultStrs = nullptr;
181static std::vector<std::string> inputFiles;
182
183void initResult(std::vector<std::string> filenames){
184    const int n = filenames.size();
185    if (n > 1) {
186        ShowFileNames = true;
187    }
188    inputFiles = filenames;
189    resultStrs = new std::stringstream[n];
190    total_count = new int[n];
191    for (unsigned i = 0; i < inputFiles.size(); ++i){
192        total_count[i] = 0;
193    }
194   
195}
196
197extern "C" {
198    void wrapped_report_match(uint64_t lineNum, uint64_t line_start, uint64_t line_end, const char * buffer, uint64_t filesize, int fileIdx) {
199       
200        int idx = fileIdx;
201       
202        if (ShowFileNames) {
203            resultStrs[idx] << inputFiles[idx] << ':';
204        }
205        if (ShowLineNumbers) {
206            resultStrs[idx] << lineNum << ":";
207        }
208       
209        if ((buffer[line_start] == 0xA) && (line_start != line_end)) {
210            // The line "starts" on the LF of a CRLF.  Really the end of the last line.
211            line_start++;
212        }
213        if (line_end == filesize) {
214            // The match position is at end-of-file.   We have a final unterminated line.
215            resultStrs[idx].write(&buffer[line_start], line_end - line_start);
216            if (NormalizeLineBreaks) {
217                resultStrs[idx] << '\n';  // terminate it
218            }
219            return;
220        }
221        unsigned char end_byte = (unsigned char)buffer[line_end]; 
222        if (NormalizeLineBreaks) {
223            if (end_byte == 0x85) {
224                // Line terminated with NEL, on the second byte.  Back up 1.
225                line_end--;
226            } else if (end_byte > 0xD) {
227                // Line terminated with PS or LS, on the third byte.  Back up 2.
228                line_end -= 2;
229            }
230            resultStrs[idx].write(&buffer[line_start], line_end - line_start);
231            resultStrs[idx] << '\n';
232        }
233        else{   
234            if (end_byte == 0x0D) {
235                // Check for line_end on first byte of CRLF;  note that we don't
236                // want to access past the end of buffer.
237                if ((line_end + 1 < filesize) && (buffer[line_end + 1] == 0x0A)) {
238                    // Found CRLF; preserve both bytes.
239                    line_end++;
240                }
241            }
242            resultStrs[idx].write(&buffer[line_start], line_end - line_start + 1);
243        }
244    }
245}
246
247void PrintResult(bool CountOnly, std::vector<uint64_t> & total_CountOnly){
248    if(CountOnly){
249        if (!ShowFileNames) {
250            for (unsigned i = 0; i < inputFiles.size(); ++i){
251                std::cout << total_CountOnly[i] << std::endl;
252            }
253        }
254        else {
255            for (unsigned i = 0; i < inputFiles.size(); ++i){
256                std::cout << inputFiles[i] << ':' << total_CountOnly[i] << std::endl;
257            };
258        }
259        return;
260    }
261   
262    for (unsigned i = 0; i < inputFiles.size(); ++i){
263        std::cout << resultStrs[i].str();
264    }
265}
266
267re::CC * parsedCodePointSet;
268
269extern "C" {
270    void insert_codepoints(uint64_t lineNum, uint64_t line_start, uint64_t line_end, const char * buffer) {
271        re::codepoint_t c = 0;
272        ssize_t line_pos = line_start;
273        while (isxdigit(buffer[line_pos])) {
274            if (isdigit(buffer[line_pos])) {
275                c = (c << 4) | (buffer[line_pos] - '0');
276            }
277            else {
278                c = (c << 4) | (tolower(buffer[line_pos]) - 'a' + 10);
279            }
280            line_pos++;
281        }
282        assert(((line_pos - line_start) >= 4) && ((line_pos - line_start) <= 6)); // UCD format 4 to 6 hex digits.       
283        parsedCodePointSet->insert(c);
284    }
285}
286
287void setParsedCodePointSet(){
288    parsedCodePointSet = re::makeCC();
289}
290
291re::CC * getParsedCodePointSet(){
292    return parsedCodePointSet;
293}
294
295
296
297
298void icgrep_Linking(Module * m, ExecutionEngine * e) {
299    Module::FunctionListType & fns = m->getFunctionList();
300    for (Module::FunctionListType::iterator it = fns.begin(), it_end = fns.end(); it != it_end; ++it) {
301        std::string fnName = it->getName().str();
302        if (fnName == "s2p_block") continue;
303        if (fnName == "process_block") continue;
304        if (fnName == "process_block_initialize_carries") continue;
305       
306        if (fnName == "wrapped_report_match") {
307            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&wrapped_report_match);
308        }
309        if (fnName == "insert_codepoints") {
310            e->addGlobalMapping(cast<GlobalValue>(it), (void *)&insert_codepoints);
311        }
312#ifndef DISABLE_PREGENERATED_UCD_FUNCTIONS
313        else {
314            const UCD::ExternalProperty & ep = UCD::resolveExternalProperty(fnName);
315            e->addGlobalMapping(cast<GlobalValue>(it), std::get<0>(ep));
316        }
317#endif
318    }
319}
320
Note: See TracBrowser for help on using the repository browser.