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

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

Large refactoring step. Removed IR generation code from Kernel (formally KernelBuilder?) and moved it into the new KernelBuilder? class.

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