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

Last change on this file since 4290 was 4290, checked in by linmengl, 5 years ago

add static_assert for 256 block size

File size: 39.4 KB
Line 
1/*
2 *  Copyright (c) 2014 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/*
8 *  Copyright (c) 2014 International Characters.
9 *  This software is licensed to the public under the Open Software License 3.0.
10 *  icgrep is a trademark of International Characters.
11 */
12
13#include <pablo/pablo_compiler.h>
14#include <pablo/codegenstate.h>
15#include <pablo/printer_pablos.h>
16#include <cc/cc_namemap.hpp>
17#include <re/re_name.h>
18#include <stdexcept>
19#include <include/simd-lib/bitblock.hpp>
20
21#ifdef USE_LLVM_3_4
22#include <llvm/Analysis/Verifier.h>
23#include <llvm/Assembly/PrintModulePass.h>
24#include <llvm/Linker.h>
25#endif
26#ifdef USE_LLVM_3_5
27#include <llvm/IR/Verifier.h>
28#endif
29
30#include <llvm/Pass.h>
31#include <llvm/PassManager.h>
32#include <llvm/ADT/SmallVector.h>
33#include <llvm/Analysis/Passes.h>
34#include <llvm/IR/BasicBlock.h>
35#include <llvm/IR/CallingConv.h>
36#include <llvm/IR/Constants.h>
37#include <llvm/IR/DataLayout.h>
38#include <llvm/IR/DerivedTypes.h>
39#include <llvm/IR/Function.h>
40#include <llvm/IR/GlobalVariable.h>
41#include <llvm/IR/InlineAsm.h>
42#include <llvm/IR/Instructions.h>
43#include <llvm/IR/LLVMContext.h>
44#include <llvm/IR/Module.h>
45#include <llvm/Support/FormattedStream.h>
46#include <llvm/Support/MathExtras.h>
47#include <llvm/Support/Casting.h>
48#include <llvm/Support/Compiler.h>
49#include <llvm/Support/Debug.h>
50#include <llvm/Support/TargetSelect.h>
51#include <llvm/Support/Host.h>
52#include <llvm/Transforms/Scalar.h>
53#include <llvm/ExecutionEngine/ExecutionEngine.h>
54#include <llvm/ExecutionEngine/MCJIT.h>
55#include <llvm/IRReader/IRReader.h>
56#include <llvm/Bitcode/ReaderWriter.h>
57#include <llvm/Support/MemoryBuffer.h>
58#include <llvm/IR/IRBuilder.h>
59
60//#define DUMP_GENERATED_IR
61
62extern "C" {
63  void wrapped_print_register(BitBlock bit_block) {
64      print_register<BitBlock>("", bit_block);
65  }
66}
67
68#define CREATE_GENERAL_CODE_CATEGORY(SUFFIX) \
69SUFFIX * f##SUFFIX = nullptr; \
70extern "C" { \
71    BitBlock __get_category_##SUFFIX(Basis_bits &basis_bits) { \
72        if (f##SUFFIX == nullptr) f##SUFFIX = new SUFFIX(); \
73        Struct_##SUFFIX output; \
74        f##SUFFIX->do_block(basis_bits, output); \
75        return output.cc; \
76    } \
77}
78
79CREATE_GENERAL_CODE_CATEGORY(Cc)
80CREATE_GENERAL_CODE_CATEGORY(Cf)
81CREATE_GENERAL_CODE_CATEGORY(Cn)
82CREATE_GENERAL_CODE_CATEGORY(Co)
83CREATE_GENERAL_CODE_CATEGORY(Cs)
84CREATE_GENERAL_CODE_CATEGORY(Ll)
85CREATE_GENERAL_CODE_CATEGORY(Lm)
86CREATE_GENERAL_CODE_CATEGORY(Lo)
87CREATE_GENERAL_CODE_CATEGORY(Lt)
88CREATE_GENERAL_CODE_CATEGORY(Lu)
89CREATE_GENERAL_CODE_CATEGORY(Mc)
90CREATE_GENERAL_CODE_CATEGORY(Me)
91CREATE_GENERAL_CODE_CATEGORY(Mn)
92CREATE_GENERAL_CODE_CATEGORY(Nd)
93CREATE_GENERAL_CODE_CATEGORY(Nl)
94CREATE_GENERAL_CODE_CATEGORY(No)
95CREATE_GENERAL_CODE_CATEGORY(Pc)
96CREATE_GENERAL_CODE_CATEGORY(Pd)
97CREATE_GENERAL_CODE_CATEGORY(Pe)
98CREATE_GENERAL_CODE_CATEGORY(Pf)
99CREATE_GENERAL_CODE_CATEGORY(Pi)
100CREATE_GENERAL_CODE_CATEGORY(Po)
101CREATE_GENERAL_CODE_CATEGORY(Ps)
102CREATE_GENERAL_CODE_CATEGORY(Sc)
103CREATE_GENERAL_CODE_CATEGORY(Sk)
104CREATE_GENERAL_CODE_CATEGORY(Sm)
105CREATE_GENERAL_CODE_CATEGORY(So)
106CREATE_GENERAL_CODE_CATEGORY(Zl)
107CREATE_GENERAL_CODE_CATEGORY(Zp)
108CREATE_GENERAL_CODE_CATEGORY(Zs)
109
110#undef CREATE_GENERAL_CODE_CATEGORY
111
112namespace pablo {
113
114PabloCompiler::PabloCompiler(const std::vector<Var*> & basisBits)
115: mBasisBits(basisBits)
116, mMod(new Module("icgrep", getGlobalContext()))
117, mBasicBlock(nullptr)
118, mExecutionEngine(nullptr)
119, mBitBlockType(VectorType::get(IntegerType::get(mMod->getContext(), 64), BLOCK_SIZE / 64))
120, mBasisBitsInputPtr(nullptr)
121, mCarryQueueIdx(0)
122, mCarryQueuePtr(nullptr)
123, mNestingDepth(0)
124, mCarryQueueSize(0)
125, mAdvanceQueueIdx(0)
126, mAdvanceQueuePtr(nullptr)
127, mAdvanceQueueSize(0)
128, mZeroInitializer(ConstantAggregateZero::get(mBitBlockType))
129, mOneInitializer(ConstantVector::getAllOnesValue(mBitBlockType))
130, mFunctionType(nullptr)
131, mFunction(nullptr)
132, mBasisBitsAddr(nullptr)
133, mOutputAddrPtr(nullptr)
134, mMaxNestingDepth(0)
135{
136    //Create the jit execution engine.up
137    InitializeNativeTarget();
138    InitializeNativeTargetAsmPrinter();
139    InitializeNativeTargetAsmParser();
140    DefineTypes();
141    DeclareFunctions();
142}
143
144PabloCompiler::~PabloCompiler()
145{
146    delete mMod;
147    delete fPs;
148    delete fNl;
149    delete fNo;
150    delete fLo;
151    delete fLl;
152    delete fLm;
153    delete fNd;
154    delete fPc;
155    delete fLt;
156    delete fLu;
157    delete fPf;
158    delete fPd;
159    delete fPe;
160    delete fPi;
161    delete fPo;
162    delete fMe;
163    delete fMc;
164    delete fMn;
165    delete fSk;
166    delete fSo;
167    delete fSm;
168    delete fSc;
169    delete fZl;
170    delete fCo;
171    delete fCn;
172    delete fCc;
173    delete fCf;
174    delete fCs;
175    delete fZp;
176    delete fZs;
177}
178
179LLVM_Gen_RetVal PabloCompiler::compile(PabloBlock & pb)
180{
181    mNestingDepth = 0;
182    mMaxNestingDepth = 0;
183    mCarryQueueSize = 0;
184    mAdvanceQueueSize = 0;
185    Examine(pb.statements());
186    mCarryQueueVector.resize(mCarryQueueSize);
187    mAdvanceQueueVector.resize(mAdvanceQueueSize);
188    std::string errMessage;
189    EngineBuilder builder(mMod);
190    builder.setErrorStr(&errMessage);
191    builder.setMCPU(sys::getHostCPUName());
192    builder.setUseMCJIT(true);
193    builder.setOptLevel(mMaxNestingDepth ? CodeGenOpt::Level::Less : CodeGenOpt::Level::None);
194    mExecutionEngine = builder.create();
195    if (mExecutionEngine == nullptr) {
196        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
197    }
198
199    if (!mCalleeMap.empty()) {
200        DeclareCallFunctions();
201    }
202
203    Function::arg_iterator args = mFunction->arg_begin();
204    mBasisBitsAddr = args++;
205    mBasisBitsAddr->setName("basis_bits");
206    mCarryQueuePtr = args++;
207    mCarryQueuePtr->setName("carry_q");
208    mAdvanceQueuePtr = args++;
209    mAdvanceQueuePtr->setName("advance_q");
210    mOutputAddrPtr = args++;
211    mOutputAddrPtr->setName("output");
212
213    //Create the carry and advance queues.
214    mCarryQueueIdx = 0;
215    mAdvanceQueueIdx = 0;
216    mNestingDepth = 0;
217    mMaxNestingDepth = 0;
218    mBasicBlock = BasicBlock::Create(mMod->getContext(), "parabix_entry", mFunction,0);
219
220    //The basis bits structure
221    for (unsigned i = 0; i != mBasisBits.size(); ++i) {
222        IRBuilder<> b(mBasicBlock);
223        Value* indices[] = {b.getInt64(0), b.getInt32(i)};
224        const String * const name = mBasisBits[i]->getName();
225        Value * gep = b.CreateGEP(mBasisBitsAddr, indices);
226        LoadInst * basisBit = b.CreateAlignedLoad(gep, BLOCK_SIZE/8, false, name->str());
227        mMarkerMap.insert(std::make_pair(name, basisBit));
228    }
229
230    //Generate the IR instructions for the function.
231    compileStatements(pb.statements());
232
233    assert (mCarryQueueIdx == mCarryQueueSize);
234    assert (mAdvanceQueueIdx == mAdvanceQueueSize);
235    assert (mNestingDepth == 0);
236    //Terminate the block
237    ReturnInst::Create(mMod->getContext(), mBasicBlock);
238
239    //Un-comment this line in order to display the IR that has been generated by this module.
240    #if defined(DUMP_GENERATED_IR)
241    mMod->dump();
242    #endif
243
244
245
246    //Create a verifier.  The verifier will print an error message if our module is malformed in any way.
247    #ifdef USE_LLVM_3_5
248    verifyModule(*mMod, &dbgs());
249    #endif
250    #ifdef USE_LLVM_3_4
251    verifyModule(*mMod, PrintMessageAction);
252    #endif
253
254    //Use the pass manager to run optimizations on the function.
255    FunctionPassManager fpm(mMod);
256 #ifdef USE_LLVM_3_5
257    mMod->setDataLayout(mExecutionEngine->getDataLayout());
258    // Set up the optimizer pipeline.  Start with registering info about how the target lays out data structures.
259    fpm.add(new DataLayoutPass(mMod));
260#endif
261#ifdef USE_LLVM_3_4
262    fpm.add(new DataLayout(*mExecutionEngine->getDataLayout()));
263#endif
264    fpm.doInitialization();
265    fpm.run(*mFunction);
266
267    mExecutionEngine->finalizeObject();
268
269    LLVM_Gen_RetVal retVal;
270    //Return the required size of the carry queue and a pointer to the process_block function.
271    retVal.carry_q_size = mCarryQueueSize;
272    retVal.advance_q_size = mAdvanceQueueSize;
273    retVal.process_block_fptr = mExecutionEngine->getPointerToFunction(mFunction);
274
275    return retVal;
276}
277
278void PabloCompiler::DefineTypes()
279{
280    StructType * structBasisBits = mMod->getTypeByName("struct.Basis_bits");
281    if (structBasisBits == nullptr) {
282        structBasisBits = StructType::create(mMod->getContext(), "struct.Basis_bits");
283    }
284    std::vector<Type*>StructTy_struct_Basis_bits_fields;
285    for (int i = 0; i != mBasisBits.size(); i++)
286    {
287        StructTy_struct_Basis_bits_fields.push_back(mBitBlockType);
288    }
289    if (structBasisBits->isOpaque()) {
290        structBasisBits->setBody(StructTy_struct_Basis_bits_fields, /*isPacked=*/false);
291    }
292    mBasisBitsInputPtr = PointerType::get(structBasisBits, 0);
293
294    std::vector<Type*>functionTypeArgs;
295    functionTypeArgs.push_back(mBasisBitsInputPtr);
296
297    //The carry q array.
298    //A pointer to the BitBlock vector.
299    functionTypeArgs.push_back(PointerType::get(mBitBlockType, 0));
300    // Advance q array
301    functionTypeArgs.push_back(PointerType::get(mBitBlockType, 0));
302
303    //The output structure.
304    StructType * outputStruct = mMod->getTypeByName("struct.Output");
305    if (!outputStruct) {
306        outputStruct = StructType::create(mMod->getContext(), "struct.Output");
307    }
308    if (outputStruct->isOpaque()) {
309        std::vector<Type*>fields;
310        fields.push_back(mBitBlockType);
311        fields.push_back(mBitBlockType);
312        outputStruct->setBody(fields, /*isPacked=*/false);
313    }
314    PointerType* outputStructPtr = PointerType::get(outputStruct, 0);
315
316    //The &output parameter.
317    functionTypeArgs.push_back(outputStructPtr);
318
319    mFunctionType = FunctionType::get(
320     /*Result=*/Type::getVoidTy(mMod->getContext()),
321     /*Params=*/functionTypeArgs,
322     /*isVarArg=*/false);
323}
324
325void PabloCompiler::DeclareFunctions()
326{
327    //This function can be used for testing to print the contents of a register from JIT'd code to the terminal window.
328    //mFunc_print_register = mMod->getOrInsertFunction("wrapped_print_register", Type::getVoidTy(getGlobalContext()), mXi64Vect, NULL);
329    //mExecutionEngine->addGlobalMapping(cast<GlobalValue>(mFunc_print_register), (void *)&wrapped_print_register);
330    // to call->  b.CreateCall(mFunc_print_register, unicode_category);
331
332#ifdef USE_UADD_OVERFLOW
333    // Type Definitions for llvm.uadd.with.overflow.carryin.i128 or .i256
334    std::vector<Type*>StructTy_0_fields;
335    StructTy_0_fields.push_back(IntegerType::get(mMod->getContext(), BLOCK_SIZE));
336    StructTy_0_fields.push_back(IntegerType::get(mMod->getContext(), 1));
337    StructType *StructTy_0 = StructType::get(mMod->getContext(), StructTy_0_fields, /*isPacked=*/false);
338
339    std::vector<Type*>FuncTy_1_args;
340    FuncTy_1_args.push_back(IntegerType::get(mMod->getContext(), BLOCK_SIZE));
341    FuncTy_1_args.push_back(IntegerType::get(mMod->getContext(), BLOCK_SIZE));
342    FuncTy_1_args.push_back(IntegerType::get(mMod->getContext(), 1));
343    FunctionType* FuncTy_1 = FunctionType::get(
344                                              /*Result=*/StructTy_0,
345                                              /*Params=*/FuncTy_1_args,
346                                              /*isVarArg=*/false);
347
348    mFunctionUaddOverflow = mMod->getFunction("llvm.uadd.with.overflow.carryin.i" +
349                                              std::to_string(BLOCK_SIZE));
350    if (!mFunctionUaddOverflow) {
351        mFunctionUaddOverflow = Function::Create(
352          /*Type=*/ FuncTy_1,
353          /*Linkage=*/ GlobalValue::ExternalLinkage,
354          /*Name=*/ "llvm.uadd.with.overflow.carryin.i" + std::to_string(BLOCK_SIZE), mMod); // (external, no body)
355        mFunctionUaddOverflow->setCallingConv(CallingConv::C);
356    }
357    AttributeSet mFunctionUaddOverflowPAL;
358    {
359        SmallVector<AttributeSet, 4> Attrs;
360        AttributeSet PAS;
361        {
362          AttrBuilder B;
363          B.addAttribute(Attribute::NoUnwind);
364          B.addAttribute(Attribute::ReadNone);
365          PAS = AttributeSet::get(mMod->getContext(), ~0U, B);
366        }
367
368        Attrs.push_back(PAS);
369        mFunctionUaddOverflowPAL = AttributeSet::get(mMod->getContext(), Attrs);
370    }
371    mFunctionUaddOverflow->setAttributes(mFunctionUaddOverflowPAL);
372#endif
373
374    //Starts on process_block
375    SmallVector<AttributeSet, 5> Attrs;
376    AttributeSet PAS;
377    {
378        AttrBuilder B;
379        B.addAttribute(Attribute::ReadOnly);
380        B.addAttribute(Attribute::NoCapture);
381        PAS = AttributeSet::get(mMod->getContext(), 1U, B);
382    }
383    Attrs.push_back(PAS);
384    {
385        AttrBuilder B;
386        B.addAttribute(Attribute::NoCapture);
387        PAS = AttributeSet::get(mMod->getContext(), 2U, B);
388    }
389    Attrs.push_back(PAS);
390    {
391        AttrBuilder B;
392        B.addAttribute(Attribute::NoCapture);
393        PAS = AttributeSet::get(mMod->getContext(), 3U, B);
394    }
395    Attrs.push_back(PAS);
396    {
397        AttrBuilder B;
398        B.addAttribute(Attribute::NoCapture);
399        PAS = AttributeSet::get(mMod->getContext(), 4U, B);
400    }
401    Attrs.push_back(PAS);
402    {
403        AttrBuilder B;
404        B.addAttribute(Attribute::NoUnwind);
405        B.addAttribute(Attribute::UWTable);
406        PAS = AttributeSet::get(mMod->getContext(), ~0U, B);
407    }
408    AttributeSet AttrSet = AttributeSet::get(mMod->getContext(), Attrs);
409
410    //Create the function that will be generated.
411    mFunction = mMod->getFunction("process_block");
412    if (!mFunction) {
413        mFunction = Function::Create(
414            /*Type=*/mFunctionType,
415            /*Linkage=*/GlobalValue::ExternalLinkage,
416            /*Name=*/"process_block", mMod);
417        mFunction->setCallingConv(CallingConv::C);
418    }
419    mFunction->setAttributes(AttrSet);
420}
421
422void PabloCompiler::Examine(StatementList & stmts) {
423    for (Statement * stmt : stmts) {
424        if (Assign * assign = dyn_cast<Assign>(stmt)) {
425            Examine(assign->getExpr());
426        }
427        if (Next * next = dyn_cast<Next>(stmt)) {
428            Examine(next->getExpr());
429        }
430        else if (If * ifStatement = dyn_cast<If>(stmt)) {
431            const auto preIfCarryCount = mCarryQueueSize;
432            const auto preIfAdvanceCount = mAdvanceQueueSize;
433            Examine(ifStatement->getCondition());
434            mMaxNestingDepth = std::max(mMaxNestingDepth, ++mNestingDepth);
435            Examine(ifStatement->getBody());
436            --mNestingDepth;
437            ifStatement->setInclusiveCarryCount(mCarryQueueSize - preIfCarryCount);
438            ifStatement->setInclusiveAdvanceCount(mAdvanceQueueSize - preIfAdvanceCount);
439        }
440        else if (While * whileStatement = dyn_cast<While>(stmt)) {
441            const auto preWhileCarryCount = mCarryQueueSize;
442            const auto preWhileAdvanceCount = mAdvanceQueueSize;
443            Examine(whileStatement->getCondition());
444            mMaxNestingDepth = std::max(mMaxNestingDepth, ++mNestingDepth);
445            Examine(whileStatement->getBody());
446            --mNestingDepth;
447            whileStatement->setInclusiveCarryCount(mCarryQueueSize - preWhileCarryCount);
448            whileStatement->setInclusiveAdvanceCount(mAdvanceQueueSize - preWhileAdvanceCount);
449        }
450    }
451}
452
453void PabloCompiler::Examine(PabloAST *expr)
454{
455    if (Call * call = dyn_cast<Call>(expr)) {
456        mCalleeMap.insert(std::make_pair(call->getCallee(), nullptr));
457    }
458    else if (And * pablo_and = dyn_cast<And>(expr)) {
459        Examine(pablo_and->getExpr1());
460        Examine(pablo_and->getExpr2());
461    }
462    else if (Or * pablo_or = dyn_cast<Or>(expr)) {
463        Examine(pablo_or->getExpr1());
464        Examine(pablo_or->getExpr2());
465    }
466    else if (Sel * pablo_sel = dyn_cast<Sel>(expr)) {
467        Examine(pablo_sel->getCondition());
468        Examine(pablo_sel->getTrueExpr());
469        Examine(pablo_sel->getFalseExpr());
470    }
471    else if (Not * pablo_not = dyn_cast<Not>(expr)) {
472        Examine(pablo_not->getExpr());
473    }
474    else if (Advance * adv = dyn_cast<Advance>(expr)) {
475        ++mAdvanceQueueSize;
476        Examine(adv->getExpr());
477    }
478    else if (MatchStar * mstar = dyn_cast<MatchStar>(expr)) {
479        ++mCarryQueueSize;
480        Examine(mstar->getMarker());
481        Examine(mstar->getCharClass());
482    }
483    else if (ScanThru * sthru = dyn_cast<ScanThru>(expr)) {
484        ++mCarryQueueSize;
485        Examine(sthru->getScanFrom());
486        Examine(sthru->getScanThru());
487    }
488}
489
490void PabloCompiler::DeclareCallFunctions() {
491    for (auto mapping : mCalleeMap) {
492        const String * callee = mapping.first;
493        void * callee_ptr = nullptr;
494        #define CHECK_GENERAL_CODE_CATEGORY(SUFFIX) \
495            if (callee->str() == #SUFFIX) { \
496                callee_ptr = (void*)&__get_category_##SUFFIX; \
497            } else
498        CHECK_GENERAL_CODE_CATEGORY(Cc)
499        CHECK_GENERAL_CODE_CATEGORY(Cf)
500        CHECK_GENERAL_CODE_CATEGORY(Cn)
501        CHECK_GENERAL_CODE_CATEGORY(Co)
502        CHECK_GENERAL_CODE_CATEGORY(Cs)
503        CHECK_GENERAL_CODE_CATEGORY(Ll)
504        CHECK_GENERAL_CODE_CATEGORY(Lm)
505        CHECK_GENERAL_CODE_CATEGORY(Lo)
506        CHECK_GENERAL_CODE_CATEGORY(Lt)
507        CHECK_GENERAL_CODE_CATEGORY(Lu)
508        CHECK_GENERAL_CODE_CATEGORY(Mc)
509        CHECK_GENERAL_CODE_CATEGORY(Me)
510        CHECK_GENERAL_CODE_CATEGORY(Mn)
511        CHECK_GENERAL_CODE_CATEGORY(Nd)
512        CHECK_GENERAL_CODE_CATEGORY(Nl)
513        CHECK_GENERAL_CODE_CATEGORY(No)
514        CHECK_GENERAL_CODE_CATEGORY(Pc)
515        CHECK_GENERAL_CODE_CATEGORY(Pd)
516        CHECK_GENERAL_CODE_CATEGORY(Pe)
517        CHECK_GENERAL_CODE_CATEGORY(Pf)
518        CHECK_GENERAL_CODE_CATEGORY(Pi)
519        CHECK_GENERAL_CODE_CATEGORY(Po)
520        CHECK_GENERAL_CODE_CATEGORY(Ps)
521        CHECK_GENERAL_CODE_CATEGORY(Sc)
522        CHECK_GENERAL_CODE_CATEGORY(Sk)
523        CHECK_GENERAL_CODE_CATEGORY(Sm)
524        CHECK_GENERAL_CODE_CATEGORY(So)
525        CHECK_GENERAL_CODE_CATEGORY(Zl)
526        CHECK_GENERAL_CODE_CATEGORY(Zp)
527        CHECK_GENERAL_CODE_CATEGORY(Zs)
528        // OTHERWISE ...
529        throw std::runtime_error("Unknown unicode category \"" + callee->str() + "\"");
530        #undef CHECK_GENERAL_CODE_CATEGORY
531        Value * unicodeCategory = mMod->getOrInsertFunction("__get_category_" + callee->str(), mBitBlockType, mBasisBitsInputPtr, NULL);
532        if (LLVM_UNLIKELY(unicodeCategory == nullptr)) {
533            throw std::runtime_error("Could not create static method call for unicode category \"" + callee->str() + "\"");
534        }
535        mExecutionEngine->addGlobalMapping(cast<GlobalValue>(unicodeCategory), callee_ptr);
536        mCalleeMap[callee] = unicodeCategory;
537    }
538}
539
540Value * PabloCompiler::compileStatements(const StatementList & stmts) {
541    Value * retVal = nullptr;
542    for (const PabloAST * statement : stmts) {
543        retVal = compileStatement(statement);
544    }
545    return retVal;
546}
547
548Value * PabloCompiler::compileStatement(const PabloAST * stmt)
549{
550    Value * retVal = nullptr;
551    if (const Assign * assign = dyn_cast<const Assign>(stmt))
552    {
553        Value* expr = compileExpression(assign->getExpr());
554        mMarkerMap[assign->getName()] = expr;
555        if (LLVM_UNLIKELY(assign->isOutputAssignment())) {
556            SetOutputValue(expr, assign->getOutputIndex());
557        }
558        retVal = expr;
559    }
560    if (const Next * next = dyn_cast<const Next>(stmt))
561    {
562        Value* expr = compileExpression(next->getExpr());
563        mMarkerMap[next->getName()] = expr;
564        retVal = expr;
565    }
566    else if (const If * ifstmt = dyn_cast<const If>(stmt))
567    {
568        BasicBlock * ifEntryBlock = mBasicBlock;
569        BasicBlock * ifBodyBlock = BasicBlock::Create(mMod->getContext(), "if.body", mFunction, 0);
570        BasicBlock * ifEndBlock = BasicBlock::Create(mMod->getContext(), "if.end", mFunction, 0);
571
572        int if_start_idx = mCarryQueueIdx;
573        int if_start_idx_advance = mAdvanceQueueIdx;
574
575        Value* if_test_value = compileExpression(ifstmt->getCondition());
576
577        /* Generate the statements into the if body block, and also determine the
578           final carry index.  */
579
580        IRBuilder<> bIfBody(ifBodyBlock);
581        mBasicBlock = ifBodyBlock;
582
583        ++mNestingDepth;
584
585        Value *  returnMarker = compileStatements(ifstmt->getBody());
586
587        int if_end_idx = mCarryQueueIdx;
588        int if_end_idx_advance = mAdvanceQueueIdx;
589        if (if_start_idx < if_end_idx + 1) {
590            // Have at least two internal carries.   Accumulate and store.
591            int if_accum_idx = mCarryQueueIdx++;
592
593            Value* if_carry_accum_value = genCarryInLoad(if_start_idx);
594
595            for (int c = if_start_idx+1; c < if_end_idx; c++)
596            {
597                Value* carryq_value = genCarryInLoad(c);
598                if_carry_accum_value = bIfBody.CreateOr(carryq_value, if_carry_accum_value);
599            }
600            genCarryOutStore(if_carry_accum_value, if_accum_idx);
601
602        }
603        if (if_start_idx_advance < if_end_idx_advance + 1) {
604            // Have at least two internal advances.   Accumulate and store.
605            int if_accum_idx = mAdvanceQueueIdx++;
606
607            Value* if_advance_accum_value = genAdvanceInLoad(if_start_idx_advance);
608
609            for (int c = if_start_idx_advance+1; c < if_end_idx_advance; c++)
610            {
611                Value* advance_q_value = genAdvanceInLoad(c);
612                if_advance_accum_value = bIfBody.CreateOr(advance_q_value, if_advance_accum_value);
613            }
614            genAdvanceOutStore(if_advance_accum_value, if_accum_idx);
615
616        }
617        bIfBody.CreateBr(ifEndBlock);
618
619        IRBuilder<> b_entry(ifEntryBlock);
620        mBasicBlock = ifEntryBlock;
621        if (if_start_idx < if_end_idx) {
622            // Have at least one internal carry.
623            int if_accum_idx = mCarryQueueIdx - 1;
624            Value* last_if_pending_carries = genCarryInLoad(if_accum_idx);
625            if_test_value = b_entry.CreateOr(if_test_value, last_if_pending_carries);
626        }
627        if (if_start_idx_advance < if_end_idx_advance) {
628            // Have at least one internal carry.
629            int if_accum_idx = mAdvanceQueueIdx - 1;
630            Value* last_if_pending_advances = genAdvanceInLoad(if_accum_idx);
631            if_test_value = b_entry.CreateOr(if_test_value, last_if_pending_advances);
632        }
633        b_entry.CreateCondBr(genBitBlockAny(if_test_value), ifEndBlock, ifBodyBlock);
634
635        mBasicBlock = ifEndBlock;
636        --mNestingDepth;
637
638        retVal = returnMarker;
639    }
640    else if (const While * whileStatement = dyn_cast<const While>(stmt))
641    {
642        const auto baseCarryQueueIdx = mCarryQueueIdx;
643        const auto baseAdvanceQueueIdx = mAdvanceQueueIdx;
644        if (mNestingDepth == 0) {
645            for (auto i = 0; i != whileStatement->getInclusiveCarryCount(); ++i) {
646                genCarryInLoad(baseCarryQueueIdx + i);
647            }
648            for (auto i = 0; i != whileStatement->getInclusiveAdvanceCount(); ++i) {
649                genAdvanceInLoad(baseAdvanceQueueIdx + i);
650            }
651        }
652
653        SmallVector<const Next*, 4> nextNodes;
654        for (const PabloAST * node : whileStatement->getBody()) {
655            if (isa<Next>(node)) {
656                nextNodes.push_back(cast<Next>(node));
657            }
658        }
659
660        // Compile the initial iteration statements; the calls to genCarryOutStore will update the
661        // mCarryQueueVector with the appropriate values. Although we're not actually entering a new basic
662        // block yet, increment the nesting depth so that any calls to genCarryInLoad or genCarryOutStore
663        // will refer to the previous value.
664
665        ++mNestingDepth;
666
667        compileStatements(whileStatement->getBody());
668
669        // Reset the carry queue index. Note: this ought to be changed in the future. Currently this assumes
670        // that compiling the while body twice will generate the equivalent IR. This is not necessarily true
671        // but works for now.
672        mCarryQueueIdx = baseCarryQueueIdx;
673        mAdvanceQueueIdx = baseAdvanceQueueIdx;
674
675        BasicBlock* whileCondBlock = BasicBlock::Create(mMod->getContext(), "while.cond", mFunction, 0);
676        BasicBlock* whileBodyBlock = BasicBlock::Create(mMod->getContext(), "while.body", mFunction, 0);
677        BasicBlock* whileEndBlock = BasicBlock::Create(mMod->getContext(), "while.end", mFunction, 0);
678
679        // Note: compileStatements may update the mBasicBlock pointer if the body contains nested loops. It
680        // may not be same one that we entered the function with.
681        IRBuilder<> bEntry(mBasicBlock);
682        bEntry.CreateBr(whileCondBlock);
683
684        // CONDITION BLOCK
685        IRBuilder<> bCond(whileCondBlock);
686        // generate phi nodes for any carry propogating instruction
687        int whileCarryCount = whileStatement->getInclusiveCarryCount();
688        int whileAdvanceCount = whileStatement->getInclusiveAdvanceCount();
689        std::vector<PHINode*> phiNodes(whileCarryCount + whileAdvanceCount + nextNodes.size());
690        unsigned index = 0;
691        for (index = 0; index != whileCarryCount; ++index) {
692            PHINode * phi = bCond.CreatePHI(mBitBlockType, 2);
693            phi->addIncoming(mCarryQueueVector[baseCarryQueueIdx + index], mBasicBlock);
694            mCarryQueueVector[baseCarryQueueIdx + index] = mZeroInitializer; // (use phi for multi-carry mode.)
695            phiNodes[index] = phi;
696        }
697        for (int i = 0; i != whileAdvanceCount; ++i) {
698            PHINode * phi = bCond.CreatePHI(mBitBlockType, 2);
699            phi->addIncoming(mAdvanceQueueVector[baseAdvanceQueueIdx + i], mBasicBlock);
700            mAdvanceQueueVector[baseAdvanceQueueIdx + i] = mZeroInitializer; // (use phi for multi-carry mode.)
701            phiNodes[index++] = phi;
702        }
703        // and for any Next nodes in the loop body
704        for (const Next * n : nextNodes) {
705            PHINode * phi = bCond.CreatePHI(mBitBlockType, 2, n->getName()->str());
706            auto f = mMarkerMap.find(n->getName());
707            assert (f != mMarkerMap.end());
708            phi->addIncoming(f->second, mBasicBlock);
709            mMarkerMap[n->getName()] = phi;
710            phiNodes[index++] = phi;
711        }
712
713        mBasicBlock = whileCondBlock;
714        bCond.CreateCondBr(genBitBlockAny(compileExpression(whileStatement->getCondition())), whileEndBlock, whileBodyBlock);
715
716        // BODY BLOCK
717        mBasicBlock = whileBodyBlock;
718        retVal = compileStatements(whileStatement->getBody());
719        // update phi nodes for any carry propogating instruction
720        IRBuilder<> bWhileBody(mBasicBlock);
721        for (index = 0; index != whileStatement->getInclusiveCarryCount(); ++index) {
722            Value * carryOut = bWhileBody.CreateOr(phiNodes[index], mCarryQueueVector[baseCarryQueueIdx + index]);
723            PHINode * phi = phiNodes[index];
724            phi->addIncoming(carryOut, mBasicBlock);
725            mCarryQueueVector[baseCarryQueueIdx + index] = phi;
726        }
727        for (int i = 0; i != whileAdvanceCount; ++i) {
728            Value * advOut = bWhileBody.CreateOr(phiNodes[index], mAdvanceQueueVector[baseAdvanceQueueIdx + i]);
729            PHINode * phi = phiNodes[index++];
730            phi->addIncoming(advOut, mBasicBlock);
731            mAdvanceQueueVector[baseAdvanceQueueIdx + i] = phi;
732        }
733        // and for any Next nodes in the loop body
734        for (const Next * n : nextNodes) {
735            auto f = mMarkerMap.find(n->getName());
736            assert (f != mMarkerMap.end());
737            PHINode * phi = phiNodes[index++];
738            phi->addIncoming(f->second, mBasicBlock);
739            mMarkerMap[n->getName()] = phi;
740        }
741
742        bWhileBody.CreateBr(whileCondBlock);
743
744        // EXIT BLOCK
745        mBasicBlock = whileEndBlock;
746        if (--mNestingDepth == 0) {
747            for (index = 0; index != whileCarryCount; ++index) {
748                genCarryOutStore(phiNodes[index], baseCarryQueueIdx + index);
749            }
750            for (index = 0; index != whileAdvanceCount; ++index) {
751                genAdvanceOutStore(phiNodes[whileCarryCount + index], baseAdvanceQueueIdx + index);
752            }
753        }
754    }
755    return retVal;
756}
757
758Value * PabloCompiler::compileExpression(const PabloAST * expr)
759{
760    Value * retVal = nullptr;
761    IRBuilder<> b(mBasicBlock);
762    if (isa<Ones>(expr)) {
763        retVal = mOneInitializer;
764    }
765    else if (isa<Zeroes>(expr)) {
766        retVal = mZeroInitializer;
767    }
768    else if (const Call* call = dyn_cast<Call>(expr)) {
769        //Call the callee once and store the result in the marker map.
770        auto mi = mMarkerMap.find(call->getCallee());
771        if (mi == mMarkerMap.end()) {
772            auto ci = mCalleeMap.find(call->getCallee());
773            if (LLVM_UNLIKELY(ci == mCalleeMap.end())) {
774                throw std::runtime_error("Unexpected error locating static function for \"" + call->getCallee()->str() + "\"");
775            }
776            mi = mMarkerMap.insert(std::make_pair(call->getCallee(), b.CreateCall(ci->second, mBasisBitsAddr))).first;
777        }
778        retVal = mi->second;
779    }
780    else if (const Var * var = dyn_cast<Var>(expr))
781    {
782        auto f = mMarkerMap.find(var->getName());
783        if (LLVM_UNLIKELY(f == mMarkerMap.end())) {
784            throw std::runtime_error(PabloPrinter::print(var) + " used before creation.");
785        }
786        retVal = f->second;
787    }
788    else if (const And * pablo_and = dyn_cast<And>(expr))
789    {
790        retVal = b.CreateAnd(compileExpression(pablo_and->getExpr1()), compileExpression(pablo_and->getExpr2()), "and");
791    }
792    else if (const Or * pablo_or = dyn_cast<Or>(expr))
793    {
794        retVal = b.CreateOr(compileExpression(pablo_or->getExpr1()), compileExpression(pablo_or->getExpr2()), "or");
795    }
796    else if (const Sel * sel = dyn_cast<Sel>(expr))
797    {
798        Value* ifMask = compileExpression(sel->getCondition());
799        Value* ifTrue = b.CreateAnd(ifMask, compileExpression(sel->getTrueExpr()));
800        Value* ifFalse = b.CreateAnd(genNot(ifMask), compileExpression(sel->getFalseExpr()));
801        retVal = b.CreateOr(ifTrue, ifFalse);
802    }
803    else if (const Not * pablo_not = dyn_cast<Not>(expr))
804    {
805        retVal = genNot(compileExpression(pablo_not->getExpr()));
806    }
807    else if (const Advance * adv = dyn_cast<Advance>(expr))
808    {
809        Value* strm_value = compileExpression(adv->getExpr());
810        int shift = adv->getAdvanceAmount();
811        retVal = genAdvanceWithCarry(strm_value, shift);
812    }
813    else if (const MatchStar * mstar = dyn_cast<MatchStar>(expr))
814    {
815        Value* marker = compileExpression(mstar->getMarker());
816        Value* cc = compileExpression(mstar->getCharClass());
817        Value* marker_and_cc = b.CreateAnd(marker, cc);
818        retVal = b.CreateOr(b.CreateXor(genAddWithCarry(marker_and_cc, cc), cc), marker, "matchstar");
819    }
820    else if (const ScanThru * sthru = dyn_cast<ScanThru>(expr))
821    {
822        Value* marker_expr = compileExpression(sthru->getScanFrom());
823        Value* cc_expr = compileExpression(sthru->getScanThru());
824        retVal = b.CreateAnd(genAddWithCarry(marker_expr, cc_expr), genNot(cc_expr), "scanthru");
825    }
826    return retVal;
827}
828
829#ifdef USE_UADD_OVERFLOW
830PabloCompiler::SumWithOverflowPack PabloCompiler::callUaddOverflow(Value* int128_e1, Value* int128_e2, Value* int1_cin) {
831    std::vector<Value*> struct_res_params;
832    struct_res_params.push_back(int128_e1);
833    struct_res_params.push_back(int128_e2);
834    struct_res_params.push_back(int1_cin);
835    CallInst* struct_res = CallInst::Create(mFunctionUaddOverflow, struct_res_params, "uadd_overflow_res", mBasicBlock);
836    struct_res->setCallingConv(CallingConv::C);
837    struct_res->setTailCall(false);
838    AttributeSet struct_res_PAL;
839    struct_res->setAttributes(struct_res_PAL);
840
841    SumWithOverflowPack ret;
842
843    std::vector<unsigned> int128_sum_indices;
844    int128_sum_indices.push_back(0);
845    ret.sum = ExtractValueInst::Create(struct_res, int128_sum_indices, "sum", mBasicBlock);
846
847    std::vector<unsigned> int1_obit_indices;
848    int1_obit_indices.push_back(1);
849    ret.obit = ExtractValueInst::Create(struct_res, int1_obit_indices, "obit", mBasicBlock);
850
851    return ret;
852}
853#endif
854
855Value* PabloCompiler::genAddWithCarry(Value* e1, Value* e2) {
856    IRBuilder<> b(mBasicBlock);
857
858    //CarryQ - carry in.
859    const int carryIdx = mCarryQueueIdx++;
860    Value* carryq_value = genCarryInLoad(carryIdx);
861
862#ifdef USE_UADD_OVERFLOW
863    //use llvm.uadd.with.overflow.i128 or i256
864    ConstantInt* const_int32_6 = ConstantInt::get(mMod->getContext(), APInt(32, StringRef("0"), 10));
865    CastInst* int128_e1 = new BitCastInst(e1, IntegerType::get(mMod->getContext(), BLOCK_SIZE), "e1_128", mBasicBlock);
866    CastInst* int128_e2 = new BitCastInst(e2, IntegerType::get(mMod->getContext(), BLOCK_SIZE), "e2_128", mBasicBlock);
867    ExtractElementInst * int64_carryq_value = ExtractElementInst::Create(carryq_value, const_int32_6, "carryq_64", mBasicBlock);
868    CastInst* int1_carryq_value = new TruncInst(int64_carryq_value, IntegerType::get(mMod->getContext(), 1), "carryq_1", mBasicBlock);
869    SumWithOverflowPack sumpack0;
870    sumpack0 = callUaddOverflow(int128_e1, int128_e2, int1_carryq_value);
871    Value* obit = sumpack0.obit;
872    Value* sum = b.CreateBitCast(sumpack0.sum, mBitBlockType, "sum");
873    /*obit is the i1 carryout, zero extend and insert it into a v2i64 or v4i64 vector.*/
874    ConstantAggregateZero* const_packed_5 = ConstantAggregateZero::get(mBitBlockType);
875    CastInst* int64_o0 = new ZExtInst(obit, IntegerType::get(mMod->getContext(), 64), "o0", mBasicBlock);
876    InsertElementInst* carry_out = InsertElementInst::Create(const_packed_5, int64_o0, const_int32_6, "carry_out", mBasicBlock);
877#else
878
879#if (BLOCK_SIZE == 128)
880    //calculate carry through logical ops
881    Value* carrygen = b.CreateAnd(e1, e2, "carrygen");
882    Value* carryprop = b.CreateOr(e1, e2, "carryprop");
883    Value* digitsum = b.CreateAdd(e1, e2, "digitsum");
884    Value* partial = b.CreateAdd(digitsum, carryq_value, "partial");
885    Value* digitcarry = b.CreateOr(carrygen, b.CreateAnd(carryprop, genNot(partial)));
886    Value* mid_carry_in = genShiftLeft64(b.CreateLShr(digitcarry, 63), "mid_carry_in");
887
888    Value* sum = b.CreateAdd(partial, mid_carry_in, "sum");
889    Value* carry_out = genShiftHighbitToLow(b.CreateOr(carrygen, b.CreateAnd(carryprop, genNot(sum))), "carry_out");
890#else
891    //BLOCK_SIZE == 256, there is no other implementation
892    static_assert(false, "Add with carry for 256-bit bitblock requires USE_UADD_OVERFLOW");
893#endif
894
895#endif
896    genCarryOutStore(carry_out, carryIdx);
897    return sum;
898}
899
900Value* PabloCompiler::genCarryInLoad(const unsigned index) {
901    assert (index < mCarryQueueVector.size());
902    if (mNestingDepth == 0) {
903        IRBuilder<> b(mBasicBlock);
904        mCarryQueueVector[index] = b.CreateAlignedLoad(b.CreateGEP(mCarryQueuePtr, b.getInt64(index)), BLOCK_SIZE/8, false);
905    }
906    return mCarryQueueVector[index];
907}
908
909void PabloCompiler::genCarryOutStore(Value* carryOut, const unsigned index ) {
910    assert (carryOut);
911    assert (index < mCarryQueueVector.size());
912    if (mNestingDepth == 0) {
913        IRBuilder<> b(mBasicBlock);
914        b.CreateAlignedStore(carryOut, b.CreateGEP(mCarryQueuePtr, b.getInt64(index)), BLOCK_SIZE/8, false);
915    }
916    mCarryQueueVector[index] = carryOut;
917}
918
919Value* PabloCompiler::genAdvanceInLoad(const unsigned index) {
920    assert (index < mAdvanceQueueVector.size());
921    if (mNestingDepth == 0) {
922        IRBuilder<> b(mBasicBlock);
923        mAdvanceQueueVector[index] = b.CreateAlignedLoad(b.CreateGEP(mAdvanceQueuePtr, b.getInt64(index)), BLOCK_SIZE/8, false);
924    }
925    return mAdvanceQueueVector[index];
926}
927
928void PabloCompiler::genAdvanceOutStore(Value* advanceOut, const unsigned index ) {
929    assert (advanceOut);
930    assert (index < mAdvanceQueueVector.size());
931    if (mNestingDepth == 0) {
932        IRBuilder<> b(mBasicBlock);
933        b.CreateAlignedStore(advanceOut, b.CreateGEP(mAdvanceQueuePtr, b.getInt64(index)), BLOCK_SIZE/8, false);
934    }
935    mAdvanceQueueVector[index] = advanceOut;
936}
937
938inline Value* PabloCompiler::genBitBlockAny(Value* test) {
939    IRBuilder<> b(mBasicBlock);
940    Value* cast_marker_value_1 = b.CreateBitCast(test, IntegerType::get(mMod->getContext(), BLOCK_SIZE));
941    return b.CreateICmpEQ(cast_marker_value_1, ConstantInt::get(IntegerType::get(mMod->getContext(), BLOCK_SIZE), 0));
942}
943
944Value* PabloCompiler::genShiftHighbitToLow(Value* e, const Twine &namehint) {
945    IRBuilder<> b(mBasicBlock);
946    Value* i128_val = b.CreateBitCast(e, IntegerType::get(mMod->getContext(), BLOCK_SIZE));
947    return b.CreateBitCast(b.CreateLShr(i128_val, BLOCK_SIZE - 1, namehint), mBitBlockType);
948}
949
950Value* PabloCompiler::genShiftLeft64(Value* e, const Twine &namehint) {
951    IRBuilder<> b(mBasicBlock);
952    Value* i128_val = b.CreateBitCast(e, IntegerType::get(mMod->getContext(), BLOCK_SIZE));
953    return b.CreateBitCast(b.CreateShl(i128_val, 64, namehint), mBitBlockType);
954}
955
956inline Value* PabloCompiler::genNot(Value* expr) {
957    IRBuilder<> b(mBasicBlock);
958    return b.CreateXor(expr, mOneInitializer, "not");
959}
960
961Value* PabloCompiler::genAdvanceWithCarry(Value* strm_value, int shift_amount) {
962
963    IRBuilder<> b(mBasicBlock);
964
965    const auto advanceIdx = mAdvanceQueueIdx++;
966#ifdef USE_LONG_INTEGER_SHIFT
967    Value* advanceq_longint = b.CreateBitCast(genAdvanceInLoad(advanceIdx), IntegerType::get(mMod->getContext(), BLOCK_SIZE));
968    Value* strm_longint = b.CreateBitCast(strm_value, IntegerType::get(mMod->getContext(), BLOCK_SIZE));
969    Value* adv_longint = b.CreateOr(b.CreateShl(strm_longint, shift_amount), advanceq_longint, "advance");
970    Value* result_value = b.CreateBitCast(adv_longint, mBitBlockType);
971    Value* advance_out = b.CreateBitCast(b.CreateLShr(strm_longint, BLOCK_SIZE - shift_amount, "advance_out"), mBitBlockType);
972    genAdvanceOutStore(advance_out, advanceIdx);
973
974    return result_value;
975#elif (BLOCK_SIZE == 128)
976    if (shift_amount == 1) {
977        Value* advanceq_value = genAdvanceInLoad(advanceIdx);
978        Value* srli_1_value = b.CreateLShr(strm_value, 63);
979        Value* packed_shuffle;
980        Constant* const_packed_1_elems [] = {b.getInt32(0), b.getInt32(2)};
981        Constant* const_packed_1 = ConstantVector::get(const_packed_1_elems);
982        packed_shuffle = b.CreateShuffleVector(advanceq_value, srli_1_value, const_packed_1);
983
984        Constant* const_packed_2_elems[] = {b.getInt64(1), b.getInt64(1)};
985        Constant* const_packed_2 = ConstantVector::get(const_packed_2_elems);
986
987        Value* shl_value = b.CreateShl(strm_value, const_packed_2);
988        Value* result_value = b.CreateOr(shl_value, packed_shuffle, "advance");
989
990        Value* advance_out = genShiftHighbitToLow(strm_value, "advance_out");
991        //CarryQ - carry out:
992        genAdvanceOutStore(advance_out, advanceIdx);
993
994        return result_value;
995    }
996    else if (shift_amount < 64) {
997        // This is the preferred logic, but is too slow for the general case.
998        // We need to speed up our custom LLVM for this code.
999        Value* advanceq_longint = b.CreateBitCast(genAdvanceInLoad(advanceIdx), IntegerType::get(mMod->getContext(), BLOCK_SIZE));
1000        Value* strm_longint = b.CreateBitCast(strm_value, IntegerType::get(mMod->getContext(), BLOCK_SIZE));
1001        Value* adv_longint = b.CreateOr(b.CreateShl(strm_longint, shift_amount), advanceq_longint, "advance");
1002        Value* result_value = b.CreateBitCast(adv_longint, mBitBlockType);
1003        Value* advance_out = b.CreateBitCast(b.CreateLShr(strm_longint, BLOCK_SIZE - shift_amount, "advance_out"), mBitBlockType);
1004        genAdvanceOutStore(advance_out, advanceIdx);
1005
1006        return result_value;
1007    }
1008    else {//if (shift_amount >= 64) {
1009        throw std::runtime_error("Shift amount >= 64 in Advance is currently unsupported.");
1010    }
1011#else
1012    //BLOCK_SIZE == 256
1013    static_assert(false, "Advance with carry on 256-bit bitblock requires long integer shifts (USE_LONG_INTEGER_SHIFT).");
1014#endif //USE_LONG_INTEGER_SHIFT
1015}
1016
1017void PabloCompiler::SetOutputValue(Value * marker, const unsigned index) {
1018    IRBuilder<> b(mBasicBlock);
1019    if (marker->getType()->isPointerTy()) {
1020        marker = b.CreateAlignedLoad(marker, BLOCK_SIZE/8, false);
1021    }
1022    Value* indices[] = {b.getInt64(0), b.getInt32(index)};
1023    Value* gep = b.CreateGEP(mOutputAddrPtr, indices);
1024    b.CreateAlignedStore(marker, gep, BLOCK_SIZE/8, false);
1025}
1026
1027}
Note: See TracBrowser for help on using the repository browser.