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

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

partial refactoring check in with change for Linda.

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