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

Last change on this file since 5516 was 5486, checked in by nmedfort, 23 months 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.