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

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

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

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