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

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

memcpy/memset support for 32-bit systems; more error messages/handling; bug fix for ParabixCharacterClassKernelBuilder?. continued work on parenthesis matching + expandable buffers.

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