source: icGREP/icgrep-devel/icgrep/array-test.cpp @ 5495

Last change on this file since 5495 was 5486, checked in by nmedfort, 2 years ago

Initial attempt to improve debugging capabilities with compilation stack traces on error.

File size: 9.9 KB
Line 
1/*
2 *  Copyright (c) 2015 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 <IR_Gen/idisa_target.h>                   // for GetIDISA_Builder
8#include <kernels/source_kernel.h>
9#include <kernels/s2p_kernel.h>                    // for S2PKernel
10#include <kernels/alignedprint.h>
11#include <kernels/kernel_builder.h>
12#include <kernels/streamset.h>                     // for CircularBuffer
13#include <llvm/ExecutionEngine/ExecutionEngine.h>  // for ExecutionEngine
14#include <llvm/IR/Function.h>                      // for Function, Function...
15#include <llvm/IR/Module.h>                        // for Module
16#include <llvm/IR/Verifier.h>                      // for verifyModule
17#include <llvm/Support/CommandLine.h>              // for ParseCommandLineOp...
18#include <llvm/Support/raw_ostream.h>              // for errs
19#include <pablo/pablo_kernel.h>                    // for PabloKernel
20#include <pablo/pe_zeroes.h>
21#include <pablo/pe_ones.h>
22#include <toolchain/toolchain.h>
23#include <pablo/builder.hpp>                       // for PabloBuilder
24#include <boost/filesystem.hpp>
25#include <boost/iostreams/device/mapped_file.hpp>
26#include <llvm/ADT/StringRef.h>
27#include <llvm/IR/CallingConv.h>
28#include <llvm/IR/DerivedTypes.h>
29#include <llvm/IR/LLVMContext.h>
30#include <llvm/IR/Value.h>
31#include <llvm/Support/Debug.h>
32#include <pablo/pablo_toolchain.h>
33#include <iostream>
34#include <toolchain/cpudriver.h>
35#include <pablo/passes/ssapass.h>
36
37namespace llvm { class Type; }
38namespace pablo { class Integer; }
39namespace pablo { class Var; }
40
41using namespace pablo;
42using namespace kernel;
43using namespace parabix;
44using namespace llvm;
45
46static cl::list<std::string> inputFiles(cl::Positional, cl::desc("<input file ...>"), cl::OneOrMore);
47
48class ParenthesisMatchingKernel final: public pablo::PabloKernel {
49public:
50    ParenthesisMatchingKernel(const std::unique_ptr<kernel::KernelBuilder> & b, const unsigned count);
51    bool isCachable() const override { return true; }
52    bool hasSignature() const override { return false; }
53protected:
54    void generatePabloMethod() override;
55};
56
57ParenthesisMatchingKernel::ParenthesisMatchingKernel(const std::unique_ptr<kernel::KernelBuilder> & b, const unsigned count)
58: PabloKernel(b, "MatchParens",
59    {Binding{b->getStreamSetTy(8), "input"}},
60    {Binding{b->getStreamSetTy(count), "matches"}, Binding{b->getStreamTy(), "errors"}}) {
61
62}
63
64void ParenthesisMatchingKernel::generatePabloMethod() {
65
66    PabloBuilder pb(getEntryBlock());
67
68    Var * input = getInputStreamVar("input");
69
70    PabloAST * basis[8];
71    for (int i = 0; i < 8; ++i) {
72        basis[i] = pb.createExtract(input, i);
73    }
74
75    PabloAST * temp1 = pb.createOr(basis[0], basis[1], "temp1");
76    PabloAST * temp2 = pb.createAnd(basis[2], pb.createNot(basis[3]), "temp2");
77    PabloAST * temp3 = pb.createAnd(temp2, pb.createNot(temp1), "temp3");
78    PabloAST * temp4 = pb.createAnd(basis[4], pb.createNot(basis[5]), "temp4");
79    PabloAST * temp5 = pb.createOr(basis[6], basis[7], "temp5");
80    PabloAST * temp6 = pb.createAnd(temp4, pb.createNot(temp5), "temp6");
81    PabloAST * lparen = pb.createAnd(temp3, temp6, "lparens");
82    PabloAST * temp7 = pb.createAnd(basis[7], pb.createNot(basis[6]), "temp7");
83    PabloAST * temp8 = pb.createAnd(temp4, temp7, "temp8");
84    PabloAST * rparen = pb.createAnd(temp3, temp8, "rparens");
85    PabloAST * parens = pb.createOr(lparen, rparen, "parens");
86
87
88    Var * const pending_lparen = pb.createVar("pending_lparen", lparen);
89    Var * const all_closed = pb.createVar("all_closed", pb.createZeroes());
90    Var * const accumulated_errors = pb.createVar("accumulated_errors", pb.createZeroes());
91    Var * const in_play = pb.createVar("in_play", parens);
92    Var * const index = pb.createVar("i", pb.getInteger(0));
93
94    Var * matches = getOutputStreamVar("matches");
95
96//    PabloBuilder outer = PabloBuilder::Create(pb);
97
98//    pb.createWhile(pending_lparen, outer);
99
100    PabloBuilder body = PabloBuilder::Create(pb); // outer
101
102    pb.createWhile(pending_lparen, body); // outer
103
104        PabloAST * adv_pending_lparen = body.createAdvance(pending_lparen, 1);
105
106        Var * pscan = body.createVar("pscan", pb.createZeroes());
107
108        PabloBuilder ifPScan = PabloBuilder::Create(body);
109
110        body.createIf(adv_pending_lparen, ifPScan); // <-- inefficient but tests whether we're probably calculating the summary later
111
112            ifPScan.createAssign(pscan, ifPScan.createScanTo(adv_pending_lparen, in_play));
113
114//        body.createAssign(pscan, body.createScanTo(adv_pending_lparen, in_play));
115
116        body.createAssign(pending_lparen, body.createAnd(pscan, lparen));
117
118        PabloAST * closed_rparen = body.createAnd(pscan, rparen, "closed_rparen");
119
120        body.createAssign(all_closed, body.createOr(all_closed, closed_rparen));
121
122        // Mark any opening paren without a matching closer as an error.
123        PabloAST * unmatched_lparen = body.createAtEOF(pscan, "unmatched_lparen");
124
125        body.createAssign(accumulated_errors, body.createOr(accumulated_errors, unmatched_lparen));
126
127        PabloAST * pending_rparen = body.createAnd(rparen, body.createNot(all_closed, "open_rparen"), "pending_rparen");
128
129        body.createAssign(in_play, body.createOr(pending_lparen, pending_rparen));
130
131        body.createAssign(body.createExtract(matches, index), closed_rparen);
132
133        body.createAssign(index, body.createAdd(index, body.getInteger(1)));
134
135    // Mark any closing paren that was not actually used to close an opener as an error.
136    PabloAST * const unmatched_rparen = pb.createAnd(rparen, pb.createNot(all_closed), "unmatched_rparen");
137    pb.createAssign(getOutputStreamVar("errors"), pb.createOr(accumulated_errors, unmatched_rparen));
138
139}
140
141void pipeline(ParabixDriver & pxDriver, const unsigned count) {
142
143    auto & iBuilder = pxDriver.getBuilder();
144    Module * const mod = iBuilder->getModule();
145
146    Type * const byteStreamTy = iBuilder->getStreamSetTy(1, 8);
147
148    Function * const main = cast<Function>(mod->getOrInsertFunction("Main", iBuilder->getVoidTy(), iBuilder->getSizeTy(), nullptr));
149    main->setCallingConv(CallingConv::C);
150    auto args = main->arg_begin();
151   
152    Value * const fileDecriptor = &*(args++);
153    fileDecriptor->setName("input");
154
155    const unsigned segmentSize = codegen::SegmentSize;
156    const unsigned bufferSegments = codegen::BufferSegments;
157   
158    auto ByteStream = pxDriver.addBuffer(make_unique<SourceBuffer>(iBuilder, byteStreamTy));
159
160    auto mmapK = pxDriver.addKernelInstance(make_unique<MMapSourceKernel>(iBuilder, segmentSize));
161    mmapK->setInitialArguments({fileDecriptor});
162
163    pxDriver.makeKernelCall(mmapK, {}, {ByteStream});
164
165    auto BasisBits = pxDriver.addBuffer(make_unique<CircularBuffer>(iBuilder, byteStreamTy, segmentSize * bufferSegments));
166
167    auto s2pk = pxDriver.addKernelInstance(make_unique<S2PKernel>(iBuilder));
168    pxDriver.makeKernelCall(s2pk, {ByteStream}, {BasisBits});
169
170    auto bm = pxDriver.addKernelInstance(make_unique<ParenthesisMatchingKernel>(iBuilder, count));
171
172    auto matches = pxDriver.addBuffer(make_unique<ExpandableBuffer>(iBuilder, iBuilder->getStreamSetTy(count), segmentSize * bufferSegments));
173
174    auto errors = pxDriver.addBuffer(make_unique<CircularBuffer>(iBuilder, iBuilder->getStreamTy(), segmentSize * bufferSegments));
175
176    pxDriver.makeKernelCall(bm, {BasisBits}, {matches, errors});
177
178    auto printer = pxDriver.addKernelInstance(make_unique<PrintStreamSet>(iBuilder, std::vector<std::string>{"matches", "errors"}));
179    pxDriver.makeKernelCall(printer, {&matches, &errors}, {});
180
181    iBuilder->SetInsertPoint(BasicBlock::Create(mod->getContext(), "entry", main, 0));
182    pxDriver.generatePipelineIR();
183    iBuilder->CreateRetVoid();
184
185    pxDriver.finalizeObject();
186}
187
188typedef void (*MatchParens)(char * byteStream, size_t fileSize);
189
190template <typename T>
191std::ostream & operator<< (std::ostream& out, const std::vector<T>& v) {
192  if ( !v.empty() ) {
193    out << '[';
194    std::copy (v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
195    out << "\b\b]";
196  }
197  return out;
198}
199
200void check(const char * byteStream, const size_t fileSize) {
201
202    std::vector<size_t> unmatched_left;
203    std::vector<size_t> unmatched_right;
204    size_t maxDepth = 0;
205    for (size_t i = 0; i < fileSize; ++i) {
206        switch (byteStream[i]) {
207            case '(':
208                unmatched_left.push_back(i);
209                maxDepth = std::max<size_t>(maxDepth, unmatched_left.size());
210                break;
211            case ')':
212                if (unmatched_left.empty()) {
213                    unmatched_right.push_back(i);
214                } else {
215                    unmatched_left.pop_back();
216                }
217            default:
218                break;
219        }
220    }
221
222    std::cerr << "maximum depth:        " << maxDepth << "\n"
223                 "invalid left parens:  " << unmatched_left << "\n"
224                 "invalid right parens: " << unmatched_right <<
225                 std::endl;
226}
227
228void run(MatchParens match, const std::string & fileName) {
229    const boost::filesystem::path file(fileName);
230    if (exists(file)) {
231        if (is_directory(file)) {
232            return;
233        }
234        size_t fileSize = file_size(file);
235        boost::iostreams::mapped_file_source mappedFile;
236        if (fileSize > 0) {
237            mappedFile.open(fileName);
238            char * fileBuffer = const_cast<char *>(mappedFile.data());
239            check(fileBuffer, fileSize);
240            match(fileBuffer, fileSize);
241            mappedFile.close();
242        }
243    } else {
244        std::cerr << "Error: cannot open " << fileName << " for processing. Skipped.\n";
245    }
246}
247
248int main(int argc, char *argv[]) {
249    codegen::ParseCommandLineOptions(argc, argv);
250    ParabixDriver pxDriver("mp");
251    pipeline(pxDriver, 3);
252    auto main = reinterpret_cast<MatchParens>(pxDriver.getMain());
253    for (const auto & inputFile : inputFiles) {
254        run(main, inputFile);
255    }
256    return 0;
257}
Note: See TracBrowser for help on using the repository browser.