source: icGREP/icgrep-devel/icgrep/pablo/pablo_compiler.cpp @ 5353

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

Progress on parenthesis matching example

File size: 27.3 KB
Line 
1/*
2 *  Copyright (c) 2014-16 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 "pablo_compiler.h"
8#include <pablo/pablo_kernel.h>
9#include <pablo/pablo_toolchain.h>
10#include <pablo/codegenstate.h>
11#include <pablo/boolean.h>
12#include <pablo/arithmetic.h>
13#include <pablo/branch.h>
14#include <pablo/pe_advance.h>
15#include <pablo/pe_lookahead.h>
16#include <pablo/pe_matchstar.h>
17#include <pablo/pe_scanthru.h>
18#include <pablo/pe_infile.h>
19#include <pablo/pe_count.h>
20#include <pablo/pe_integer.h>
21#include <pablo/pe_string.h>
22#include <pablo/pe_zeroes.h>
23#include <pablo/pe_ones.h>
24#include <pablo/pe_var.h>
25#include <pablo/ps_assign.h>
26#include <pablo/carry_manager.h>
27#include <IR_Gen/idisa_builder.h>
28#include <kernels/streamset.h>
29#include <llvm/IR/Module.h>
30#include <llvm/Support/raw_os_ostream.h>
31
32using namespace llvm;
33
34namespace pablo {
35
36using TypeId = PabloAST::ClassTypeId;
37
38inline static unsigned getAlignment(const Value * const ptr) {
39    return ptr->getType()->getPrimitiveSizeInBits() / 8;
40}
41
42inline static unsigned getPointerElementAlignment(const Value * const ptr) {
43    return ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
44}
45
46void PabloCompiler::compile() {
47
48    mCarryManager->initializeCodeGen();
49     
50    PabloBlock * const entryBlock = mKernel->getEntryBlock(); assert (entryBlock);
51    mMarker.emplace(entryBlock->createZeroes(), iBuilder->allZeroes());
52    mMarker.emplace(entryBlock->createOnes(), iBuilder->allOnes());
53
54    compileBlock(entryBlock);
55
56    mCarryManager->finalizeCodeGen();
57
58}
59
60void PabloCompiler::initializeKernelData() {
61    examineBlock(mKernel->getEntryBlock());
62    mCarryManager->initializeCarryData(mKernel);
63}
64
65void PabloCompiler::examineBlock(const PabloBlock * const block) {
66    for (const Statement * stmt : *block) {
67        if (LLVM_UNLIKELY(isa<Lookahead>(stmt))) {
68            const Lookahead * const la = cast<Lookahead>(stmt);
69            assert (isa<Var>(la->getExpr()));
70            if (LLVM_LIKELY(la->getAmount() > mKernel->getLookAhead())) {
71                mKernel->setLookAhead(la->getAmount());
72            }
73        } else if (LLVM_UNLIKELY(isa<Branch>(stmt))) {
74            examineBlock(cast<Branch>(stmt)->getBody());
75        } else if (LLVM_UNLIKELY(isa<Count>(stmt))) {
76            mAccumulator.insert(std::make_pair(stmt, iBuilder->getInt32(mKernel->addUnnamedScalar(stmt->getType()))));
77        }
78    }   
79}
80
81inline void PabloCompiler::compileBlock(const PabloBlock * const block) {
82    for (const Statement * statement : *block) {
83        compileStatement(statement);
84    }
85}
86
87void PabloCompiler::compileIf(const If * const ifStatement) {
88    //
89    //  The If-ElseZero stmt:
90    //  if <predicate:expr> then <body:stmt>* elsezero <defined:var>* endif
91    //  If the value of the predicate is nonzero, then determine the values of variables
92    //  <var>* by executing the given statements.  Otherwise, the value of the
93    //  variables are all zero.  Requirements: (a) no variable that is defined within
94    //  the body of the if may be accessed outside unless it is explicitly
95    //  listed in the variable list, (b) every variable in the defined list receives
96    //  a value within the body, and (c) the logical consequence of executing
97    //  the statements in the event that the predicate is zero is that the
98    //  values of all defined variables indeed work out to be 0.
99    //
100    //  Simple Implementation with Phi nodes:  a phi node in the if exit block
101    //  is inserted for each variable in the defined variable list.  It receives
102    //  a zero value from the ifentry block and the defined value from the if
103    //  body.
104    //
105
106    BasicBlock * const ifEntryBlock = iBuilder->GetInsertBlock();
107    BasicBlock * const ifBodyBlock = mKernel->CreateBasicBlock("if.body");
108    BasicBlock * const ifEndBlock = mKernel->CreateBasicBlock("if.end");
109   
110    std::vector<std::pair<const Var *, Value *>> incoming;
111
112    for (const Var * var : ifStatement->getEscaped()) {
113        if (LLVM_UNLIKELY(var->isKernelParameter())) {
114            Value * marker = nullptr;
115            if (var->isScalar()) {
116                marker = mKernel->getScalarFieldPtr(var->getName());
117            } else if (var->isReadOnly()) {
118                marker = mKernel->getInputStreamBlockPtr(var->getName(), iBuilder->getInt32(0));
119            } else if (var->isReadNone()) {
120                marker = mKernel->getOutputStreamBlockPtr(var->getName(), iBuilder->getInt32(0));
121            }
122            mMarker[var] = marker;
123        } else {
124            auto f = mMarker.find(var);
125            if (LLVM_UNLIKELY(f == mMarker.end())) {
126                std::string tmp;
127                raw_string_ostream out(tmp);
128                var->print(out);
129                out << " is uninitialized prior to entering ";
130                ifStatement->print(out);
131                report_fatal_error(out.str());
132            }
133            incoming.emplace_back(var, f->second);
134        }
135    }
136
137    const PabloBlock * ifBody = ifStatement->getBody();
138   
139    mCarryManager->enterIfScope(ifBody);
140
141    Value * condition = compileExpression(ifStatement->getCondition());
142    if (condition->getType() == iBuilder->getBitBlockType()) {
143        condition = iBuilder->bitblock_any(mCarryManager->generateSummaryTest(condition));
144    }
145   
146    iBuilder->CreateCondBr(condition, ifBodyBlock, ifEndBlock);
147   
148    // Entry processing is complete, now handle the body of the if.
149    iBuilder->SetInsertPoint(ifBodyBlock);
150
151    mCarryManager->enterIfBody(ifEntryBlock);
152
153    compileBlock(ifBody);
154
155    BasicBlock * ifExitBlock = iBuilder->GetInsertBlock();   
156
157    mCarryManager->leaveIfBody(ifExitBlock);
158
159    iBuilder->CreateBr(ifEndBlock);
160
161    ifEndBlock->moveAfter(ifExitBlock);
162
163    //End Block
164    iBuilder->SetInsertPoint(ifEndBlock);
165
166    mCarryManager->leaveIfScope(ifEntryBlock, ifExitBlock);
167
168    for (const auto i : incoming) {
169        const Var * var; Value * incoming;
170        std::tie(var, incoming) = i;
171
172        auto f = mMarker.find(var);
173        if (LLVM_UNLIKELY(f == mMarker.end())) {
174            std::string tmp;
175            raw_string_ostream out(tmp);
176            out << "PHINode creation error: ";
177            var->print(out);
178            out << " was not assigned an outgoing value.";
179            report_fatal_error(out.str());
180        }
181
182        Value * const outgoing = f->second;
183        if (LLVM_UNLIKELY(incoming == outgoing)) {
184            continue;
185        }
186
187        if (LLVM_UNLIKELY(incoming->getType() != outgoing->getType())) {
188            std::string tmp;
189            raw_string_ostream out(tmp);
190            out << "PHINode creation error: incoming type of ";
191            var->print(out);
192            out << " (";
193            incoming->getType()->print(out);
194            out << ") differs from the outgoing type (";
195            outgoing->getType()->print(out);
196            out << ") within ";
197            ifStatement->print(out);
198            report_fatal_error(out.str());
199        }
200
201        PHINode * phi = iBuilder->CreatePHI(incoming->getType(), 2, var->getName());
202        phi->addIncoming(incoming, ifEntryBlock);
203        phi->addIncoming(outgoing, ifExitBlock);
204        f->second = phi;
205    }   
206}
207
208void PabloCompiler::compileWhile(const While * const whileStatement) {
209
210    const PabloBlock * const whileBody = whileStatement->getBody();
211
212    BasicBlock * whileEntryBlock = iBuilder->GetInsertBlock();
213
214    const auto escaped = whileStatement->getEscaped();
215
216#ifdef ENABLE_BOUNDED_WHILE
217    PHINode * bound_phi = nullptr;  // Needed for bounded while loops.
218#endif
219    // On entry to the while structure, proceed to execute the first iteration
220    // of the loop body unconditionally. The while condition is tested at the end of
221    // the loop.
222
223    for (const Var * var : escaped) {
224        if (LLVM_UNLIKELY(var->isKernelParameter())) {
225            Value * marker = nullptr;
226            if (var->isScalar()) {
227                marker = mKernel->getScalarFieldPtr(var->getName());
228            } else if (var->isReadOnly()) {
229                marker = mKernel->getInputStreamBlockPtr(var->getName(), iBuilder->getInt32(0));
230            } else if (var->isReadNone()) {
231                marker = mKernel->getOutputStreamBlockPtr(var->getName(), iBuilder->getInt32(0));
232            }
233            mMarker[var] = marker;
234        }
235    }
236
237    mCarryManager->enterLoopScope(whileBody);
238
239    BasicBlock * whileBodyBlock = mKernel->CreateBasicBlock("while.body");
240
241    iBuilder->CreateBr(whileBodyBlock);
242
243    iBuilder->SetInsertPoint(whileBodyBlock);
244
245    //
246    // There are 3 sets of Phi nodes for the while loop.
247    // (1) Carry-ins: (a) incoming carry data first iterations, (b) zero thereafter
248    // (2) Carry-out accumulators: (a) zero first iteration, (b) |= carry-out of each iteration
249    // (3) Next nodes: (a) values set up before loop, (b) modified values calculated in loop.
250#ifdef ENABLE_BOUNDED_WHILE
251    // (4) The loop bound, if any.
252#endif
253
254    std::vector<std::pair<const Var *, PHINode *>> variants;
255
256    // for any Next nodes in the loop body, initialize to (a) pre-loop value.
257    for (const auto var : escaped) {
258        auto f = mMarker.find(var);
259        if (LLVM_UNLIKELY(f == mMarker.end())) {
260            std::string tmp;
261            raw_string_ostream out(tmp);
262            out << "PHINode creation error: ";
263            var->print(out);
264            out << " is uninitialized prior to entering ";
265            whileStatement->print(out);
266            report_fatal_error(out.str());
267        }
268        Value * entryValue = f->second;
269        PHINode * phi = iBuilder->CreatePHI(entryValue->getType(), 2, var->getName());
270        phi->addIncoming(entryValue, whileEntryBlock);
271        f->second = phi;
272        assert(mMarker[var] == phi);
273        variants.emplace_back(var, phi);
274    }
275#ifdef ENABLE_BOUNDED_WHILE
276    if (whileStatement->getBound()) {
277        bound_phi = iBuilder->CreatePHI(iBuilder->getSizeTy(), 2, "while_bound");
278        bound_phi->addIncoming(iBuilder->getSize(whileStatement->getBound()), whileEntryBlock);
279    }
280#endif
281
282    mCarryManager->enterLoopBody(whileEntryBlock);
283
284    //
285    // Now compile the loop body proper.  Carry-out accumulated values
286    // and iterated values of Next nodes will be computed.
287    compileBlock(whileBody);
288
289    // After the whileBody has been compiled, we may be in a different basic block.
290    BasicBlock * const whileExitBlock = iBuilder->GetInsertBlock();
291
292    // Terminate the while loop body with a conditional branch back.
293    Value * condition = compileExpression(whileStatement->getCondition());
294    if (condition->getType() == iBuilder->getBitBlockType()) {
295        condition = iBuilder->bitblock_any(mCarryManager->generateSummaryTest(condition));
296    }
297
298    mCarryManager->leaveLoopBody(whileExitBlock);
299
300
301#ifdef ENABLE_BOUNDED_WHILE
302    if (whileStatement->getBound()) {
303        Value * new_bound = iBuilder->CreateSub(bound_phi, iBuilder->getSize(1));
304        bound_phi->addIncoming(new_bound, whileExitBlock);
305        condition = iBuilder->CreateAnd(condition, iBuilder->CreateICmpUGT(new_bound, ConstantInt::getNullValue(iBuilder->getSizeTy())));
306    }
307#endif
308
309    // and for any variant nodes in the loop body
310    for (const auto variant : variants) {
311        const Var * var; PHINode * incomingPhi;
312        std::tie(var, incomingPhi) = variant;
313        const auto f = mMarker.find(var);
314        if (LLVM_UNLIKELY(f == mMarker.end())) {
315            std::string tmp;
316            raw_string_ostream out(tmp);
317            out << "PHINode creation error: ";
318            var->print(out);
319            out << " is no longer assigned a value.";
320            report_fatal_error(out.str());
321        }
322
323        Value * const outgoingValue = f->second;
324
325        if (LLVM_UNLIKELY(incomingPhi->getType() != outgoingValue->getType())) {
326            std::string tmp;
327            raw_string_ostream out(tmp);
328            out << "PHINode creation error: incoming type of ";
329            var->print(out);
330            out << " (";
331            incomingPhi->getType()->print(out);
332            out << ") differs from the outgoing type (";
333            outgoingValue->getType()->print(out);
334            out << ") within ";
335            whileStatement->print(out);
336            report_fatal_error(out.str());
337        }
338
339        incomingPhi->addIncoming(outgoingValue, whileExitBlock);
340    }
341
342    BasicBlock * whileEndBlock = mKernel->CreateBasicBlock("while.end");
343
344    iBuilder->CreateCondBr(condition, whileBodyBlock, whileEndBlock);
345
346    iBuilder->SetInsertPoint(whileEndBlock);
347
348    mCarryManager->leaveLoopScope(whileEntryBlock, whileExitBlock);
349
350}
351
352void PabloCompiler::compileStatement(const Statement * const stmt) {
353
354    if (LLVM_UNLIKELY(isa<If>(stmt))) {
355        compileIf(cast<If>(stmt));
356    } else if (LLVM_UNLIKELY(isa<While>(stmt))) {
357        compileWhile(cast<While>(stmt));
358    } else {
359        const PabloAST * expr = stmt;
360        Value * value = nullptr;
361        if (LLVM_UNLIKELY(isa<Assign>(stmt))) {
362            value = compileExpression(cast<Assign>(stmt)->getValue());
363            expr = cast<Assign>(stmt)->getVariable();
364            Value * ptr = nullptr;
365            if (LLVM_LIKELY(isa<Var>(expr))) {
366                const Var * var = cast<Var>(expr);
367                if (LLVM_UNLIKELY(var->isReadOnly())) {
368                    std::string tmp;
369                    raw_string_ostream out(tmp);
370                    out << mKernel->getName();
371                    out << " cannot assign value to ";
372                    var->print(out);
373                    out << ": ";
374                    var->print(out);
375                    out << " is read only";
376                    report_fatal_error(out.str());
377                }
378                if (var->isKernelParameter()) {
379                    if (var->isScalar()) {
380                        ptr = mKernel->getScalarFieldPtr(var->getName());
381                    } else {
382                        ptr = mKernel->getOutputStreamBlockPtr(var->getName(), iBuilder->getInt32(0));
383                    }
384                }
385            } else if (isa<Extract>(expr)) {
386                const auto f = mMarker.find(expr);
387                if (LLVM_UNLIKELY(f == mMarker.end())) {
388                    std::string tmp;
389                    raw_string_ostream out(tmp);
390                    out << mKernel->getName();
391                    out << " cannot assign value to ";
392                    expr->print(out);
393                    out << ": ";
394                    expr->print(out);
395                    out << " does not dominate ";
396                    stmt->print(out);
397                    report_fatal_error(out.str());
398                }
399                ptr = f->second;
400                assert (ptr);
401            }
402            if (ptr) {
403                iBuilder->CreateAlignedStore(value, ptr, getAlignment(value));
404                value = ptr;
405            }
406        } else if (const Extract * extract = dyn_cast<Extract>(stmt)) {
407            Value * index = compileExpression(extract->getIndex());
408            Var * const array = dyn_cast<Var>(extract->getArray());
409            if (LLVM_LIKELY(array && array->isKernelParameter())) {
410                if (array->isReadOnly()) {
411                    value = mKernel->getInputStreamBlockPtr(array->getName(), index);
412                } else if (array->isReadNone()) {
413                    value = mKernel->getOutputStreamBlockPtr(array->getName(), index);
414                } else {
415                    std::string tmp;
416                    raw_string_ostream out(tmp);
417                    out << mKernel->getName();
418                    out << " stream ";
419                    expr->print(out);
420                    out << " cannot be read or written to";
421                    report_fatal_error(out.str());
422                }
423            } else {
424                Value * ptr = compileExpression(extract->getArray(), false);
425                value = iBuilder->CreateGEP(ptr, {ConstantInt::getNullValue(index->getType()), index}, "extract");
426            }
427        } else if (isa<And>(stmt)) {
428            value = compileExpression(stmt->getOperand(0));
429            for (unsigned i = 1; i < stmt->getNumOperands(); ++i) {
430                value = iBuilder->simd_and(value, compileExpression(stmt->getOperand(1)));
431            }
432        } else if (isa<Or>(stmt)) {
433            value = compileExpression(stmt->getOperand(0));
434            for (unsigned i = 1; i < stmt->getNumOperands(); ++i) {
435                value = iBuilder->simd_or(value, compileExpression(stmt->getOperand(1)));
436            }
437        } else if (isa<Xor>(stmt)) {
438            value = compileExpression(stmt->getOperand(0));
439            for (unsigned i = 1; i < stmt->getNumOperands(); ++i) {
440                value = iBuilder->simd_xor(value, compileExpression(stmt->getOperand(1)));
441            }
442        } else if (const Sel * sel = dyn_cast<Sel>(stmt)) {
443            Value* ifMask = compileExpression(sel->getCondition());
444            Value* ifTrue = iBuilder->simd_and(ifMask, compileExpression(sel->getTrueExpr()));
445            Value* ifFalse = iBuilder->simd_and(iBuilder->simd_not(ifMask), compileExpression(sel->getFalseExpr()));
446            value = iBuilder->simd_or(ifTrue, ifFalse);
447        } else if (isa<Not>(stmt)) {
448            value = iBuilder->simd_not(compileExpression(stmt->getOperand(0)));
449        } else if (isa<Advance>(stmt)) {
450            const Advance * const adv = cast<Advance>(stmt);
451            // If our expr is an Extract op on a mutable Var then we need to pass the index value to the carry
452            // manager so that it properly selects the correct carry bit.
453            value = mCarryManager->advanceCarryInCarryOut(adv, compileExpression(adv->getExpression()));
454        } else if (const MatchStar * mstar = dyn_cast<MatchStar>(stmt)) {
455            Value * const marker = compileExpression(mstar->getMarker());
456            Value * const cc = compileExpression(mstar->getCharClass());
457            Value * const marker_and_cc = iBuilder->simd_and(marker, cc);
458            Value * const sum = mCarryManager->addCarryInCarryOut(mstar, marker_and_cc, cc);
459            value = iBuilder->simd_or(iBuilder->simd_xor(sum, cc), marker);
460        } else if (const ScanThru * sthru = dyn_cast<ScanThru>(stmt)) {
461            Value * const from = compileExpression(sthru->getScanFrom());
462            Value * const thru = compileExpression(sthru->getScanThru());
463            Value * const sum = mCarryManager->addCarryInCarryOut(sthru, from, thru);
464            value = iBuilder->simd_and(sum, iBuilder->simd_not(thru));
465        } else if (const ScanTo * sthru = dyn_cast<ScanTo>(stmt)) {
466            Value * const marker_expr = compileExpression(sthru->getScanFrom());
467            Value * const to = iBuilder->simd_xor(compileExpression(sthru->getScanTo()), mKernel->getScalarField("EOFmask"));
468            Value * const sum = mCarryManager->addCarryInCarryOut(sthru, marker_expr, iBuilder->simd_not(to));
469            value = iBuilder->simd_and(sum, to);
470        } else if (const AdvanceThenScanThru * sthru = dyn_cast<AdvanceThenScanThru>(stmt)) {
471            Value * const from = compileExpression(sthru->getScanFrom());
472            Value * const thru = compileExpression(sthru->getScanThru());
473            Value * const sum = mCarryManager->addCarryInCarryOut(sthru, from, iBuilder->simd_or(from, thru));
474            value = iBuilder->simd_and(sum, iBuilder->simd_not(thru));
475        } else if (const AdvanceThenScanTo * sthru = dyn_cast<AdvanceThenScanTo>(stmt)) {
476            Value * const from = compileExpression(sthru->getScanFrom());
477            Value * const to = iBuilder->simd_xor(compileExpression(sthru->getScanTo()), mKernel->getScalarField("EOFmask"));
478            Value * const sum = mCarryManager->addCarryInCarryOut(sthru, from, iBuilder->simd_or(from, iBuilder->simd_not(to)));
479            value = iBuilder->simd_and(sum, to);
480        } else if (const InFile * e = dyn_cast<InFile>(stmt)) {
481            Value * EOFmask = mKernel->getScalarField("EOFmask");
482            value = iBuilder->simd_and(compileExpression(e->getExpr()), iBuilder->simd_not(EOFmask));
483        } else if (const AtEOF * e = dyn_cast<AtEOF>(stmt)) {
484            Value * EOFbit = mKernel->getScalarField("EOFbit");
485            value = iBuilder->simd_and(compileExpression(e->getExpr()), EOFbit);
486        } else if (const Count * c = dyn_cast<Count>(stmt)) {
487            Value * const to_count = compileExpression(c->getExpr());
488            const unsigned counterSize = iBuilder->getSizeTy()->getBitWidth();
489            const auto f = mAccumulator.find(c);
490            if (LLVM_UNLIKELY(f == mAccumulator.end())) {
491                report_fatal_error("Unknown accumulator: " + c->getName().str());
492            }
493            Value * ptr = mKernel->getScalarFieldPtr(f->second);
494            const auto alignment = getPointerElementAlignment(ptr);
495            Value * count = iBuilder->CreateAlignedLoad(ptr, alignment, c->getName() + "_accumulator");
496            Value * const partial = iBuilder->simd_popcount(counterSize, to_count);
497            if (LLVM_UNLIKELY(counterSize <= 1)) {
498                value = partial;
499            } else {
500                value = iBuilder->mvmd_extract(counterSize, partial, 0);
501                const auto fields = (iBuilder->getBitBlockWidth() / counterSize);
502                for (unsigned i = 1; i < fields; ++i) {
503                    Value * temp = iBuilder->mvmd_extract(counterSize, partial, i);
504                    value = iBuilder->CreateAdd(value, temp);
505                }
506            }
507            value = iBuilder->CreateAdd(value, count);
508            iBuilder->CreateAlignedStore(value, ptr, alignment);
509        } else if (const Lookahead * l = dyn_cast<Lookahead>(stmt)) {
510            Var * var = nullptr;
511            PabloAST * stream = l->getExpr();
512            Value * index = iBuilder->getInt32(0);
513
514            if (LLVM_UNLIKELY(isa<Extract>(stream))) {
515                stream = cast<Extract>(stream)->getArray();
516                index = compileExpression(cast<Extract>(stream)->getIndex());
517            }
518            if (LLVM_LIKELY(isa<Var>(stream))) {
519                var = cast<Var>(stream);
520                if (!var->isKernelParameter() || var->isReadNone()) {
521                    std::string tmp;
522                    raw_string_ostream out(tmp);
523                    out << "Lookahead operation cannot be applied to ";
524                    stmt->print(out);
525                    out << ": ";
526                    var->print(out);
527                    out << " is not an input stream";
528                    report_fatal_error(out.str());
529                }
530            }
531
532            const auto bit_shift = (l->getAmount() % iBuilder->getBitBlockWidth());
533            const auto block_shift = (l->getAmount() / iBuilder->getBitBlockWidth());
534
535            Value * ptr = mKernel->getAdjustedInputStreamBlockPtr(iBuilder->getSize(block_shift), var->getName(), index);
536            Value * lookAhead = iBuilder->CreateBlockAlignedLoad(ptr);
537            if (bit_shift == 0) {  // Simple case with no intra-block shifting.
538                value = lookAhead;
539            } else { // Need to form shift result from two adjacent blocks.
540                Value * ptr = mKernel->getAdjustedInputStreamBlockPtr(iBuilder->getSize(block_shift + 1), var->getName(), index);
541                Value * lookAhead1 = iBuilder->CreateBlockAlignedLoad(ptr);
542                if (LLVM_UNLIKELY((bit_shift % 8) == 0)) { // Use a single whole-byte shift, if possible.
543                    value = iBuilder->mvmd_dslli(8, lookAhead1, lookAhead, (bit_shift / 8));
544                } else {
545                    Type  * const streamType = iBuilder->getIntNTy(iBuilder->getBitBlockWidth());
546                    Value * b1 = iBuilder->CreateBitCast(lookAhead1, streamType);
547                    Value * b0 = iBuilder->CreateBitCast(lookAhead, streamType);
548                    Value * result = iBuilder->CreateOr(iBuilder->CreateShl(b1, iBuilder->getBitBlockWidth() - bit_shift), iBuilder->CreateLShr(b0, bit_shift));
549                    value = iBuilder->CreateBitCast(result, iBuilder->getBitBlockType());
550                }
551            }
552
553        } else {
554            std::string tmp;
555            raw_string_ostream out(tmp);
556            out << "PabloCompiler: statement ";
557            stmt->print(out);
558            out << " was not recognized by the compiler";
559            report_fatal_error(out.str());
560        }
561
562        mMarker[expr] = value;
563        if (DebugOptionIsSet(DumpTrace)) {
564            const String & name = isa<Var>(expr) ? cast<Var>(expr)->getName() : cast<Statement>(expr)->getName();
565            if (value->getType()->isPointerTy()) {
566                value = iBuilder->CreateLoad(value);
567            }
568            if (value->getType()->isVectorTy()) {
569                iBuilder->CallPrintRegister(name.str(), value);
570            } else if (value->getType()->isIntegerTy()) {
571                iBuilder->CallPrintInt(name.str(), value);
572            }
573        }
574    }
575}
576
577Value * PabloCompiler::compileExpression(const PabloAST * expr, const bool ensureLoaded) const {
578    if (LLVM_UNLIKELY(isa<Ones>(expr))) {
579        return iBuilder->allOnes();
580    } else if (LLVM_UNLIKELY(isa<Zeroes>(expr))) {
581        return iBuilder->allZeroes();
582    } else if (LLVM_UNLIKELY(isa<Integer>(expr))) {
583        return ConstantInt::get(cast<Integer>(expr)->getType(), cast<Integer>(expr)->value());
584    } else if (LLVM_UNLIKELY(isa<Operator>(expr))) {
585        const Operator * op = cast<Operator>(expr);
586        Value * lh = compileExpression(op->getLH());
587        Value * rh = compileExpression(op->getRH());
588        if (LLVM_UNLIKELY(lh->getType() != rh->getType())) {
589            std::string tmp;
590            raw_string_ostream out(tmp);
591            out << "Operator creation error: left hand type of ";
592            expr->print(out);
593            out << " (";
594            lh->getType()->print(out);
595            out << ") differs from right hand type (";
596            rh->getType()->print(out);
597            out << ")";
598            report_fatal_error(out.str());
599        }
600        switch (op->getClassTypeId()) {
601            case TypeId::Add:
602                return iBuilder->CreateAdd(lh, rh);
603            case TypeId::Subtract:
604                return iBuilder->CreateSub(lh, rh);
605            case TypeId::LessThan:
606                return iBuilder->CreateICmpSLT(lh, rh);
607            case TypeId::LessThanEquals:
608                return iBuilder->CreateICmpSLE(lh, rh);
609            case TypeId::Equals:
610                return iBuilder->CreateICmpEQ(lh, rh);
611            case TypeId::GreaterThanEquals:
612                return iBuilder->CreateICmpSGE(lh, rh);
613            case TypeId::GreaterThan:
614                return iBuilder->CreateICmpSGT(lh, rh);
615            case TypeId::NotEquals:
616                return iBuilder->CreateICmpNE(lh, rh);
617            default: break;
618        }
619        std::string tmp;
620        raw_string_ostream out(tmp);
621        expr->print(out);
622        out << " is not a valid Operator";
623        report_fatal_error(out.str());
624    }
625    const auto f = mMarker.find(expr);
626    if (LLVM_UNLIKELY(f == mMarker.end())) {
627        std::string tmp;
628        raw_string_ostream out(tmp);
629        out << "Compilation error: ";
630        expr->print(out);
631        out << " was used before definition!";
632        report_fatal_error(out.str());
633    }
634    Value * value = f->second;
635    if (LLVM_UNLIKELY(isa<GetElementPtrInst>(value) && ensureLoaded)) {
636        value = iBuilder->CreateAlignedLoad(value, getPointerElementAlignment(value));
637    }
638    return value;
639}
640
641PabloCompiler::PabloCompiler(PabloKernel * kernel)
642: iBuilder(kernel->getBuilder())
643, mKernel(kernel)
644, mCarryManager(new CarryManager(iBuilder)) {
645
646}
647
648PabloCompiler::~PabloCompiler() {
649    delete mCarryManager;
650}
651
652}
Note: See TracBrowser for help on using the repository browser.