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

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

Optimized Symbol Generation (and fixed potential bug that could allow duplicate names being constructed); made PabloKernel? extend PabloAST (temporarily removed PabloAST::getName() to avoid diamond problem); added an internal scalar to PabloKernel? struct for each Count to avoid InOut? output scalar variable problem; allowed CodeMotionPass? to move code within the same scope but across a branch statement. Began work on separating Kernels into either Block-Oriented or Segment-Oriented kernels.

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