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

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

First version of expandable buffers + minor change to array-test to use them.

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