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

Last change on this file since 5510 was 5510, checked in by nmedfort, 22 months ago

Back up check-in. Should have no effect on current programs.

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