Ignore:
Timestamp:
Feb 25, 2017, 12:50:29 PM (2 years ago)
Author:
nmedfort
Message:

Added enable asserts (-ea) command line flag + restructured BlockOrientedKernels? to allow for inlined code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • icGREP/icgrep-devel/icgrep/kernels/kernel.cpp

    r5340 r5347  
    1414#include <llvm/IR/LegacyPassManager.h>
    1515#include <llvm/Transforms/Scalar.h>
    16 #ifndef NDEBUG
    1716#include <llvm/IR/Verifier.h>
    18 #endif
    1917
    2018static const auto DO_BLOCK_SUFFIX = "_DoBlock";
     
    166164    addKernelDeclarations(iBuilder->getModule());
    167165    callGenerateInitMethod();
    168     generateInternalMethods();
    169166    callGenerateDoSegmentMethod();
    170167    // Implement the accumulator get functions
     
    181178
    182179void KernelBuilder::callGenerateDoSegmentMethod() {
    183     mCurrentFunction = getDoSegmentFunction();
     180    mCurrentMethod = getDoSegmentFunction();
    184181    iBuilder->SetInsertPoint(CreateBasicBlock(getName() + "_entry"));
    185     auto args = mCurrentFunction->arg_begin();
     182    auto args = mCurrentMethod->arg_begin();
    186183    mSelf = &*(args++);
    187184    Value * doFinal = &*(args++);
     
    195192
    196193void KernelBuilder::callGenerateInitMethod() {
    197     mCurrentFunction = getInitFunction();
     194    mCurrentMethod = getInitFunction();
    198195    iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
    199     Function::arg_iterator args = mCurrentFunction->arg_begin();
     196    Function::arg_iterator args = mCurrentMethod->arg_begin();
    200197    mSelf = &*(args++);
    201198    iBuilder->CreateStore(ConstantAggregateZero::get(mKernelStateType), mSelf);
     
    265262
    266263void KernelBuilder::setProcessedItemCount(Value * instance, const std::string & name, Value * value) const {
    267     //iBuilder->CallPrintInt(getName() + " " + name + " processed", value);
    268264    setScalarField(instance, name + PROCESSED_ITEM_COUNT_SUFFIX, value);
    269265}
    270266
    271267void KernelBuilder::setProducedItemCount(Value * instance, const std::string & name, Value * value) const {
    272     //iBuilder->CallPrintInt(getName() + " " + name +  " produced", value);
    273268    setScalarField(instance, name + PRODUCED_ITEM_COUNT_SUFFIX, value);
    274269}
     
    397392
    398393BasicBlock * KernelBuilder::CreateBasicBlock(std::string && name) const {
    399     return BasicBlock::Create(iBuilder->getContext(), name, mCurrentFunction);
     394    return BasicBlock::Create(iBuilder->getContext(), name, mCurrentMethod);
    400395}
    401396
     
    440435}
    441436
    442 //  The default finalBlock method simply dispatches to the doBlock routine.
    443 void BlockOrientedKernel::generateFinalBlockMethod(Value * remainingBytes) {
    444 //    std::vector<Value *> args = {self};
    445 //    for (Argument & arg : function->getArgumentList()){
    446 //        args.push_back(&arg);
    447 //    }
    448     CreateDoBlockMethodCall();
    449 }
    450 
    451437//  The default doSegment method dispatches to the doBlock routine for
    452438//  each block of the given number of blocksToDo, and then updates counts.
     439
    453440void BlockOrientedKernel::generateDoSegmentMethod(Value * doFinal, const std::vector<Value *> & producerPos) {
     441
     442    // Use the pass manager to optimize the function.
     443    FunctionPassManager fpm(iBuilder->getModule());
     444    #ifndef NDEBUG
     445    fpm.add(createVerifierPass());
     446    #endif
     447    fpm.add(createReassociatePass());             //Reassociate expressions.
     448    fpm.add(createGVNPass());                     //Eliminate common subexpressions.
     449    fpm.add(createInstructionCombiningPass());    //Simple peephole optimizations and bit-twiddling.
     450    fpm.doInitialization();
    454451
    455452    BasicBlock * const entryBlock = iBuilder->GetInsertBlock();
     
    457454    BasicBlock * const strideLoopBody = CreateBasicBlock(getName() + "_strideLoopBody");
    458455    BasicBlock * const stridesDone = CreateBasicBlock(getName() + "_stridesDone");
    459     BasicBlock * const doFinalBlock = CreateBasicBlock(getName() + "_doFinalBlock");
    460     BasicBlock * const segmentDone = CreateBasicBlock(getName() + "_segmentDone");
    461456
    462457    ConstantInt * stride = iBuilder->getSize(iBuilder->getStride());
     
    481476    iBuilder->SetInsertPoint(strideLoopBody);
    482477
    483     CreateDoBlockMethodCall();
     478    /// GENERATE DO BLOCK METHOD
     479
     480    generateDoBlockMethod(fpm);
     481
     482    /// UPDATE PROCESSED COUNTS
    484483
    485484    processed = getProcessedItemCount(mStreamSetInputs[0].name);
    486485    Value * itemsDone = iBuilder->CreateAdd(processed, stride);
    487486    setProcessedItemCount(mStreamSetInputs[0].name, itemsDone);
    488    
    489     stridesRemaining->addIncoming(iBuilder->CreateSub(stridesRemaining, iBuilder->getSize(1)), strideLoopBody);
     487
     488    stridesRemaining->addIncoming(iBuilder->CreateSub(stridesRemaining, iBuilder->getSize(1)), iBuilder->GetInsertBlock());
    490489    iBuilder->CreateBr(strideLoopCond);
    491490
     
    493492
    494493    // Now conditionally perform the final block processing depending on the doFinal parameter.
     494    BasicBlock * const doFinalBlock = CreateBasicBlock(getName() + "_doFinalBlock");
     495    BasicBlock * const segmentDone = CreateBasicBlock(getName() + "_segmentDone");
    495496    iBuilder->CreateCondBr(doFinal, doFinalBlock, segmentDone);
    496497    iBuilder->SetInsertPoint(doFinalBlock);
    497498
    498499    Value * remainingItems = iBuilder->CreateSub(producerPos[0], getProcessedItemCount(mStreamSetInputs[0].name));
    499 
    500     CreateDoFinalBlockMethodCall(remainingItems);
    501    
     500    generateFinalBlockMethod(remainingItems, fpm);
     501
    502502    itemsDone = producerPos[0];
    503     setProcessedItemCount(mStreamSetInputs[0].name, itemsDone);   
    504    
     503    setProcessedItemCount(mStreamSetInputs[0].name, itemsDone);
    505504    setTerminationSignal();
    506505    iBuilder->CreateBr(segmentDone);
    507506
    508507    iBuilder->SetInsertPoint(segmentDone);
    509 
    510 }
    511 
    512 void BlockOrientedKernel::generateInternalMethods() {
    513 
    514     callGenerateDoBlockMethod();
    515 
    516     callGenerateDoFinalBlockMethod();
    517 }
    518 
    519 void BlockOrientedKernel::callGenerateDoBlockMethod() {
    520     mCurrentFunction = getDoBlockFunction();
    521     auto args = mCurrentFunction->arg_begin();
    522     mSelf = &(*args);
    523     iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
     508}
     509
     510void BlockOrientedKernel::generateDoBlockMethod(FunctionPassManager & fpm) {
     511
     512    Value * const self = mSelf;
     513    Function * const cp = mCurrentMethod;
     514    auto ip = iBuilder->saveIP();
     515
     516    /// Check if the do block method is called and create the function if necessary   
     517    if (isCalled()) {
     518        FunctionType * const type = FunctionType::get(iBuilder->getVoidTy(), {mSelf->getType()}, false);
     519        mCurrentMethod = Function::Create(type, GlobalValue::ExternalLinkage, getName() + DO_BLOCK_SUFFIX, iBuilder->getModule());
     520        mCurrentMethod->setCallingConv(CallingConv::C);
     521        mCurrentMethod->setDoesNotThrow();
     522        mCurrentMethod->setDoesNotCapture(1);
     523        auto args = mCurrentMethod->arg_begin();
     524        mCurrentMethod = mCurrentMethod;
     525        mSelf = &*args;
     526        mSelf->setName("self");
     527        iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
     528    }
     529
     530    writeDoBlockMethod();
     531
     532    /// Call the do block method if necessary then restore the current function state to the do segement method
     533
     534    if (isCalled()) {
     535        iBuilder->CreateRetVoid();
     536        mDoBlockMethod = mCurrentMethod;
     537        fpm.run(*mCurrentMethod);
     538        iBuilder->restoreIP(ip);
     539        iBuilder->CreateCall(mCurrentMethod, self);
     540
     541        mSelf = self;
     542        mCurrentMethod = cp;
     543    }
     544
     545}
     546
     547void BlockOrientedKernel::writeDoBlockMethod() {
     548
    524549    std::vector<Value *> priorProduced;
    525550    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
     
    528553        }
    529554    }
    530     generateDoBlockMethod(); // must be implemented by the KernelBuilder subtype
     555
     556    generateDoBlockMethod(); // must be implemented by the BlockOrientedKernelBuilder subtype
     557
    531558    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
    532559        unsigned priorIdx = 0;
     
    545572            priorIdx++;
    546573        }
    547     }   
    548     iBuilder->CreateRetVoid();
    549     #ifndef NDEBUG
    550     std::string tmp;
    551     raw_string_ostream out(tmp);
    552     if (verifyFunction(*mCurrentFunction, &out)) {
    553         mCurrentFunction->dump();
    554         report_fatal_error(getName() + ": " + out.str());
    555     }
    556     #endif
    557     // Use the pass manager to optimize the function.
    558     FunctionPassManager fpm(iBuilder->getModule());
    559     fpm.add(createReassociatePass());             //Reassociate expressions.
    560     fpm.add(createGVNPass());                     //Eliminate common subexpressions.
    561     fpm.add(createInstructionCombiningPass());    //Simple peephole optimizations and bit-twiddling.
    562     fpm.doInitialization();
    563     fpm.run(*mCurrentFunction);
    564 }
    565 
    566 
    567 void BlockOrientedKernel::callGenerateDoFinalBlockMethod() {
    568     mCurrentFunction = getDoFinalBlockFunction();
    569     auto args = mCurrentFunction->arg_begin();
    570     mSelf = &(*args++);
    571     Value * const remainingBytes = &(*args);
    572     iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
    573     generateFinalBlockMethod(remainingBytes); // possibly overridden by the KernelBuilder subtype
    574     iBuilder->CreateRetVoid();
    575 }
    576 
    577 Function * BlockOrientedKernel::getDoBlockFunction() const {
    578     const auto name = getName() + DO_BLOCK_SUFFIX;
    579     Function * const f = iBuilder->getModule()->getFunction(name);
    580     if (LLVM_UNLIKELY(f == nullptr)) {
    581         report_fatal_error("Cannot find " + name);
    582     }
    583     return f;
    584 }
    585 
    586 CallInst * BlockOrientedKernel::CreateDoBlockMethodCall() const {
    587     return iBuilder->CreateCall(getDoBlockFunction(), mSelf);
    588 }
    589 
    590 Function * BlockOrientedKernel::getDoFinalBlockFunction() const {
    591     const auto name = getName() + FINAL_BLOCK_SUFFIX;
    592     Function * const f = iBuilder->getModule()->getFunction(name);
    593     if (LLVM_UNLIKELY(f == nullptr)) {
    594         report_fatal_error("Cannot find " + name);
    595     }
    596     return f;
    597 }
    598 
    599 CallInst * BlockOrientedKernel::CreateDoFinalBlockMethodCall(Value * remainingItems) const {
    600     return iBuilder->CreateCall(getDoFinalBlockFunction(), {mSelf, remainingItems});
    601 }
    602 
    603 void BlockOrientedKernel::addAdditionalKernelDeclarations(Module * m, PointerType * selfType) {
    604     // Create the doBlock and finalBlock function prototypes
    605     FunctionType * const doBlockType = FunctionType::get(iBuilder->getVoidTy(), {selfType}, false);
    606     Function * const doBlock = Function::Create(doBlockType, GlobalValue::ExternalLinkage, getName() + DO_BLOCK_SUFFIX, m);
    607     doBlock->setCallingConv(CallingConv::C);
    608     doBlock->setDoesNotThrow();
    609     doBlock->setDoesNotCapture(1);
    610     auto args = doBlock->arg_begin();
    611     args->setName("self");
    612 
    613     FunctionType * const finalBlockType = FunctionType::get(iBuilder->getVoidTy(), {selfType, iBuilder->getSizeTy()}, false);
    614     Function * const finalBlock = Function::Create(finalBlockType, GlobalValue::ExternalLinkage, getName() + FINAL_BLOCK_SUFFIX, m);
    615     finalBlock->setCallingConv(CallingConv::C);
    616     finalBlock->setDoesNotThrow();
    617     finalBlock->setDoesNotCapture(1);
    618     args = finalBlock->arg_begin();
    619     args->setName("self");
    620     (++args)->setName("remainingBytes");
    621 }
     574    }
     575
     576}
     577
     578void BlockOrientedKernel::generateFinalBlockMethod(Value * remainingItems, FunctionPassManager & fpm) {
     579
     580    Value * const self = mSelf;
     581    Function * const cp = mCurrentMethod;
     582    Value * const remainingItemCount = remainingItems;
     583    auto ip = iBuilder->saveIP();
     584
     585    if (isCalled()) {
     586        FunctionType * const type = FunctionType::get(iBuilder->getVoidTy(), {mSelf->getType(), iBuilder->getSizeTy()}, false);
     587        mCurrentMethod = Function::Create(type, GlobalValue::ExternalLinkage, getName() + FINAL_BLOCK_SUFFIX, iBuilder->getModule());
     588        mCurrentMethod->setCallingConv(CallingConv::C);
     589        mCurrentMethod->setDoesNotThrow();
     590        mCurrentMethod->setDoesNotCapture(1);
     591        auto args = mCurrentMethod->arg_begin();
     592        mSelf = &*args;
     593        mSelf->setName("self");
     594        remainingItems = &*(++args);
     595        remainingItems->setName("remainingItems");
     596        iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
     597    }
     598
     599    generateFinalBlockMethod(remainingItems); // may be implemented by the BlockOrientedKernelBuilder subtype
     600
     601    if (isCalled()) {
     602        iBuilder->CreateRetVoid();       
     603        fpm.run(*mCurrentMethod);
     604        iBuilder->restoreIP(ip);
     605        iBuilder->CreateCall(mCurrentMethod, {self, remainingItemCount});
     606        mCurrentMethod = cp;
     607        mSelf = self;
     608    }
     609
     610}
     611
     612//  The default finalBlock method simply dispatches to the doBlock routine.
     613void BlockOrientedKernel::generateFinalBlockMethod(Value * remainingItems) {
     614    CreateDoBlockMethodCall();
     615}
     616
     617void BlockOrientedKernel::CreateDoBlockMethodCall() {
     618    if (isCalled()) {
     619        iBuilder->CreateCall(mDoBlockMethod, mSelf);
     620    } else {
     621        // TODO: can we clone the DoBlock method instead of regenerating it?
     622        writeDoBlockMethod();
     623    }
     624}
     625
     626// CONSTRUCTOR
     627
     628BlockOrientedKernel::BlockOrientedKernel(IDISA::IDISA_Builder * builder,
     629                                                           std::string && kernelName,
     630                                                           std::vector<Binding> && stream_inputs,
     631                                                           std::vector<Binding> && stream_outputs,
     632                                                           std::vector<Binding> && scalar_parameters,
     633                                                           std::vector<Binding> && scalar_outputs,
     634                                                           std::vector<Binding> && internal_scalars)
     635: KernelBuilder(builder, std::move(kernelName), std::move(stream_inputs), std::move(stream_outputs), std::move(scalar_parameters), std::move(scalar_outputs), std::move(internal_scalars))
     636, mDoBlockMethod(nullptr)
     637, mInlined(false) {
     638
     639}
     640
    622641
    623642// CONSTRUCTOR
     
    638657
    639658// CONSTRUCTOR
    640 BlockOrientedKernel::BlockOrientedKernel(IDISA::IDISA_Builder * builder,
    641                                          std::string && kernelName,
    642                                          std::vector<Binding> && stream_inputs,
    643                                          std::vector<Binding> && stream_outputs,
    644                                          std::vector<Binding> && scalar_parameters,
    645                                          std::vector<Binding> && scalar_outputs,
    646                                          std::vector<Binding> && internal_scalars)
    647 : KernelBuilder(builder, std::move(kernelName), std::move(stream_inputs), std::move(stream_outputs), std::move(scalar_parameters), std::move(scalar_outputs), std::move(internal_scalars)) {
    648 
    649 }
    650 
    651 
    652 
    653 
    654 // CONSTRUCTOR
    655659SegmentOrientedKernel::SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
    656660                                             std::string && kernelName,
Note: See TracChangeset for help on using the changeset viewer.