Ignore:
Timestamp:
Mar 7, 2016, 3:37:30 PM (4 years ago)
Author:
nmedfort
Message:

Initial modifications to Pablo Compiler and Kernel Builder to support circular buffers for Lookahead.

File:
1 edited

Legend:

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

    r4945 r4959  
    55
    66#include "kernel.h"
    7 #include <iostream>
     7#include <pablo/function.h>
     8#include <IDISA/idisa_builder.h>
     9
     10using namespace llvm;
     11using namespace pablo;
     12
     13inline bool isPowerOfTwo(const unsigned x) {
     14    return (x != 0) && (x & (x - 1)) == 0;
     15}
    816
    917// sets name & sets internal state to the kernel superclass state
     
    1220, iBuilder(b)
    1321, mKernelName(name)
    14 , mPredifinedStates(2)
    1522, mBitBlockType(b->getBitBlockType())
    16 , mBlockSize(b->getBitBlockWidth()){
    17     mStates = std::vector<Type *>(4, b->getIntNTy(64));
    18     mSegmentBlocks = 1;
    19     mBufferSize = mSegmentBlocks * mBlockSize;
    20 }
    21 
    22 KernelBuilder::~KernelBuilder(){
    23 }
    24 
    25 int KernelBuilder::extendKernelInternalStateType(Type * t){
    26     int idx = mStates.size();
    27     mStates.push_back(t);
     23, mBlockSize(b->getBitBlockWidth())
     24, mBlocksPerSegment(1)
     25, mCircularBufferModulo(1)
     26, mSegmentIndex(0)
     27, mStartIndex(0) {
     28    addInternalStateType(b->getInt64Ty());
     29    addInternalStateType(b->getInt64Ty());
     30    addInternalStateType(b->getInt64Ty());
     31    addInternalStateType(b->getInt64Ty());
     32}
     33
     34unsigned KernelBuilder::addInternalStateType(Type * type){
     35    unsigned idx = mStates.size();
     36    mStates.push_back(type);
    2837    return idx;
    2938}
    30 void KernelBuilder::addKernelOutputStream(int fw){
    31     if (fw == 1){
     39void KernelBuilder::addOutputStream(const unsigned fields){
     40    if (fields == 1){
    3241        mOutputStreams.push_back(mBitBlockType);
    3342    }
    3443    else {
    35         mOutputStreams.push_back(ArrayType::get(mBitBlockType, fw));
    36     }
    37 
    38 }
    39 void KernelBuilder::addKernelOutputAccum(Type * t){
     44        mOutputStreams.push_back(ArrayType::get(mBitBlockType, fields));
     45    }
     46
     47}
     48void KernelBuilder::addOutputAccum(Type * t){
    4049    mOutputAccums.push_back(t);
    4150
    4251}
    43 void KernelBuilder::addKernelInputStream(int fw, std::string name = ""){
    44     if (name=="")
     52void KernelBuilder::addInputStream(const unsigned fields, std::string name){
     53    if (name.empty())
    4554        mInputStreamNames.push_back(mKernelName + "_inputstream_" + std::to_string(mInputStreams.size()));
    4655    else
    4756        mInputStreamNames.push_back(name);
    4857
    49     if (fw == 1){
     58    if (fields == 1){
    5059        mInputStreams.push_back(mBitBlockType);
    51     }
    52     else {
    53         mInputStreams.push_back(ArrayType::get(mBitBlockType, fw));
    54     }
    55 }
    56 void KernelBuilder::addKernelInputScalar(Type * t, std::string name = ""){
    57     if (name=="")
     60    } else {
     61        mInputStreams.push_back(ArrayType::get(mBitBlockType, fields));
     62    }
     63}
     64void KernelBuilder::addInputScalar(Type * t, std::string name){
     65    if (name.empty())
    5866        mInputScalarNames.push_back(mKernelName + "_inputscalar_" + std::to_string(mInputScalars.size()));
    5967    else
     
    6371}
    6472
    65 void KernelBuilder::PrepareDoBlockFunction(){
    66     mInputStreamType = PointerType::get(ArrayType::get(StructType::get(mMod->getContext(), mInputStreams), mSegmentBlocks), 0);
     73/** ------------------------------------------------------------------------------------------------------------- *
     74 * @brief prepareFunction
     75 ** ------------------------------------------------------------------------------------------------------------- */
     76Function * KernelBuilder::prepareFunction() {   
     77    if (mCircularBufferModulo > 1) {
     78        mStartIndex = addInternalStateType(iBuilder->getInt32Ty());
     79    }
     80    const unsigned capacity = mBlocksPerSegment + mCircularBufferModulo - 1;
     81    mInputStreamType = PointerType::get(ArrayType::get(StructType::get(mMod->getContext(), mInputStreams), capacity), 0);
    6782    mInputScalarType = PointerType::get(StructType::get(mMod->getContext(), mInputScalars), 0);
    68     Type * outputStreamType = ArrayType::get(StructType::get(mMod->getContext(), mOutputStreams), mSegmentBlocks);
     83    Type * outputStreamType = ArrayType::get(StructType::get(mMod->getContext(), mOutputStreams), capacity);
    6984    Type * outputAccumType = StructType::get(mMod->getContext(), mOutputAccums);
    7085    Type * stateType = StructType::create(mMod->getContext(), mStates, mKernelName);
    71     mKernelStructType = StructType::create(mMod->getContext(),std::vector<Type *>({stateType, outputStreamType, outputAccumType}), "KernelStruct_"+mKernelName);
    72 }
    73 
    74 struct Inputs KernelBuilder::openDoBlock(){
    75     // FunctionType * functionType = FunctionType::get(Type::getVoidTy(mMod->getContext()),
    76     //     std::vector<Type *>({PointerType::get(mKernelStructType, 0), mInputStreamType, mInputScalarType}), false);
    77        
    78     FunctionType * functionType = FunctionType::get(Type::getVoidTy(mMod->getContext()),
    79         std::vector<Type *>({PointerType::get(mKernelStructType, 0), mInputStreamType}), false);
    80 
    81     mDoBlockFunction = Function::Create(functionType, GlobalValue::ExternalLinkage, mKernelName + "_DoBlock", mMod);
    82     mDoBlockFunction->setCallingConv(CallingConv::C);
    83    
    84     Function::arg_iterator args = mDoBlockFunction->arg_begin();
    85     mKernelStructParam = args++;
    86     mKernelStructParam->setName("this");
    87     Value* input_stream_param = args++;
    88     input_stream_param->setName("input_stream");
    89     // Value* input_scalar_param = args++;
    90     // input_scalar_param->setName("input_scalar");
    91 
    92     iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mDoBlockFunction,0));
    93 
    94     struct Inputs inputs;
    95     for(int j = 0; j<mSegmentBlocks; j++){
    96         for(int i = 0; i<mInputStreams.size(); i++){
    97             Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(j), iBuilder->getInt32(i)};
    98             Value * gep = iBuilder->CreateGEP(input_stream_param, indices);
    99             Type * t = gep->getType()->getPointerElementType();
    100             if (t != mBitBlockType) {
    101                 int arraySize = t->getArrayNumElements();
    102                 inputs.streams.resize(mSegmentBlocks, std::vector<valptr>(arraySize));
    103                 for (int k=0; k<arraySize; k++){
    104                     Value * gep_array_elem = iBuilder->CreateGEP(gep, {iBuilder->getInt32(0), iBuilder->getInt32(k)});
    105                     inputs.streams[j][k] = iBuilder->CreateAlignedLoad(gep_array_elem, mBlockSize/8, false, mInputStreamNames.at(i));
    106                 }
    107             }
    108             else{
    109                 inputs.streams.resize(mSegmentBlocks, std::vector<valptr>(mInputStreams.size()));
    110                 inputs.streams[j][i] = iBuilder->CreateAlignedLoad(gep, mBlockSize/8, false, mInputStreamNames.at(i));
    111             }
    112            
     86    mKernelStructType = StructType::create(mMod->getContext(),std::vector<Type *>({stateType, outputStreamType, outputAccumType}), "KernelStruct_"+ mKernelName);
     87
     88    FunctionType * functionType = FunctionType::get(Type::getVoidTy(mMod->getContext()),
     89        std::vector<Type *>({PointerType::get(mKernelStructType, 0), mInputStreamType}), false);
     90
     91    mFunction = Function::Create(functionType, GlobalValue::ExternalLinkage, mKernelName + "_DoBlock", mMod);
     92    mFunction->setCallingConv(CallingConv::C);
     93
     94    Function::arg_iterator args = mFunction->arg_begin();
     95    mKernelParam = args++;
     96    mKernelParam->setName("this");
     97
     98    mInputParam = args++;
     99    mInputParam->setName("input_stream");
     100
     101    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mFunction, 0));
     102
     103    mSegmentIndex = 0;
     104
     105    return mFunction;
     106}
     107
     108/** ------------------------------------------------------------------------------------------------------------- *
     109 * @brief finalize
     110 ** ------------------------------------------------------------------------------------------------------------- */
     111void KernelBuilder::finalize() {
     112    Type * const int64Ty = iBuilder->getInt64Ty();
     113
     114    // Finish the actual function
     115    if (mCircularBufferModulo > 1) {
     116        Value * startIdx = getInternalState(mStartIndex);
     117        Value * value = iBuilder->CreateAdd(iBuilder->CreateBlockAlignedLoad(startIdx), iBuilder->getInt32(1));
     118        iBuilder->CreateBlockAlignedStore(value, startIdx);
     119    }
     120    iBuilder->CreateRetVoid();
     121
     122
     123    // Generate the zero initializer
     124    Function * initializer = cast<Function>(mMod->getOrInsertFunction(mKernelName + "_Init", Type::getVoidTy(mMod->getContext()), PointerType::get(mKernelStructType, 0), nullptr));
     125    initializer->setCallingConv(CallingConv::C);
     126    Function::arg_iterator args = initializer->arg_begin();
     127
     128    mKernelParam = args++;
     129    mKernelParam->setName("this");
     130
     131    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", initializer, 0));
     132
     133    for (unsigned i = 0; i < mStates.size(); ++i) {
     134        Value * const gep = getInternalState(i);
     135        Type * const type = gep->getType();
     136        if (type->isIntegerTy() || type->isArrayTy() || type->isVectorTy()) {
     137            setInternalState(i, Constant::getNullValue(type));
     138        } else {
     139            Value * gep_next = iBuilder->CreateGEP(gep, iBuilder->getInt32(1));
     140            Value * get_int = iBuilder->CreatePtrToInt(gep, int64Ty);
     141            Value * get_next_int = iBuilder->CreatePtrToInt(gep_next, int64Ty);
     142            Value * state_size = iBuilder->CreateSub(get_next_int, get_int);
     143            iBuilder->CreateMemSet(gep, iBuilder->getInt8(0), state_size, 4);
    113144        }
    114145    }
    115146
    116     // inputs.scalars.resize(mInputScalars.size());
    117     // for(int i = 0; i<mInputScalars.size(); i++){
    118     //     Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(i)};
    119     //     Value * gep = iBuilder->CreateGEP(input_scalar_param, indices);
    120     //     inputs.scalars[i] = iBuilder->CreateAlignedLoad(gep, mBlockSize/8, false, mInputScalarNames.at(i));
    121     // }
    122 
    123     return inputs;
    124 }
    125 
    126 void KernelBuilder::closeDoBlock(struct Outputs result){
    127    
    128 
    129     for(int j=0; j<mSegmentBlocks; j++){
    130         for(int i = 0; i<mOutputStreams.size(); i++){   
    131             Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(1), iBuilder->getInt32(j), iBuilder->getInt32(i)};
    132             Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
    133             iBuilder->CreateAlignedStore(result.streams[j][i], gep, mBlockSize/8, false);
    134         }
    135     }
    136 
    137     for(int i = 0; i<mOutputAccums.size(); i++){   
    138         Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(2), iBuilder->getInt32(i)};
    139         Value* gep = iBuilder->CreateGEP(mKernelStructParam, indices);
    140         iBuilder->CreateAlignedStore(result.accums[i], gep, mBlockSize/8, false);
    141     }
    142 
    143147    iBuilder->CreateRetVoid();
    144 }
    145 
    146 void KernelBuilder::changeKernelInternalState(Value * kernelStruct, int idx, Value * stateValue){
    147     Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(idx)};
    148     Value* gep = iBuilder->CreateGEP(kernelStruct, indices);
    149     iBuilder->CreateAlignedStore(stateValue, gep, mBlockSize/8, false);
    150 }
    151 
    152 Value * KernelBuilder::getKernelInternalState(Value * kernelStruct, int idx){
    153     Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(idx)};
    154     Value* gep = iBuilder->CreateGEP(kernelStruct, indices);
    155     return iBuilder->CreateAlignedLoad(gep, mBlockSize/8, false, "state"+std::to_string(idx));
    156 }
    157 
    158 Value * KernelBuilder::getKernelInternalStatePtr(Value * kernelStruct, int idx){
    159     Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(idx)};
    160     Value* gep = iBuilder->CreateGEP(kernelStruct, indices);
    161     return gep;
    162 }
    163 
    164 void KernelBuilder::finalizeMethods(){
    165     Type * T = iBuilder->getIntNTy(64);
    166 
    167     Constant* c = mMod->getOrInsertFunction(mKernelName+"_Init", Type::getVoidTy(mMod->getContext()), PointerType::get(mKernelStructType, 0), NULL);
    168     Function* mInitFunction = cast<Function>(c);
    169     mInitFunction->setCallingConv(CallingConv::C);
    170     Function::arg_iterator args = mInitFunction->arg_begin();
    171 
    172     Value* this_param = args++;
    173     this_param->setName("this");
    174 
    175     int i = mPredifinedStates;
    176     iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mInitFunction, 0));
    177     Value * gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(i++) }));
    178     iBuilder->CreateStore(iBuilder->getInt64(0), gep);  //FileBasePos
    179     gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(i++) }));
    180     iBuilder->CreateStore(iBuilder->getInt64(0), gep);  //AvailableBlocks
    181 
    182     while(i < mStates.size()){
    183         gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(i++) }));
    184         Value * gep_next = iBuilder->CreateGEP(gep, std::vector<Value *>({iBuilder->getInt32(1)}));
    185         Value * get_int = iBuilder->CreatePtrToInt(gep, T);
    186         Value * get_next_int = iBuilder->CreatePtrToInt(gep_next, T);
    187         Value * state_size = iBuilder->CreateSub(get_next_int, get_int);
    188         iBuilder->CreateMemSet(gep, iBuilder->getInt8(0), state_size, 4);
    189     }
    190 
    191     iBuilder->CreateRetVoid();
    192 
    193     c = mMod->getOrInsertFunction(mKernelName+"_Create_Default", Type::getVoidTy(mMod->getContext()), PointerType::get(mKernelStructType, 0), T, T, NULL);
    194     mConstructor = cast<Function>(c);
     148
     149    // and then the constructor
     150    mConstructor = cast<Function>(mMod->getOrInsertFunction(mKernelName+"_Create_Default", Type::getVoidTy(mMod->getContext()), PointerType::get(mKernelStructType, 0), int64Ty, int64Ty, nullptr));
    195151    mConstructor->setCallingConv(CallingConv::C);
    196152    args = mConstructor->arg_begin();
    197153
    198     this_param = args++;
    199     this_param->setName("this");
     154    mKernelParam = args++;
     155    mKernelParam->setName("this");
     156
    200157    Value* block_size_param = args++;
    201158    block_size_param->setName("block_size");
    202159    Value* seg_size_param = args++;
    203160    seg_size_param->setName("seg_size");
    204  
    205161    iBuilder->SetInsertPoint(BasicBlock::Create(mMod->getContext(), "entry", mConstructor, 0));
    206     gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(0) }));
    207     iBuilder->CreateStore(block_size_param, gep);   
    208     gep = iBuilder->CreateGEP(this_param, std::vector<Value *>({ iBuilder->getInt32(0), iBuilder->getInt32(0), iBuilder->getInt32(1) }));
    209     iBuilder->CreateStore(seg_size_param, gep);
    210 
    211     iBuilder->CreateCall(mInitFunction, this_param);
     162    iBuilder->CreateStore(block_size_param, getInternalState(0));
     163    iBuilder->CreateStore(seg_size_param, getInternalState(1));
     164    iBuilder->CreateCall(initializer, mKernelParam);
    212165    iBuilder->CreateRetVoid();
    213 
    214 }
    215 
    216 Value * KernelBuilder::generateKernelInstance(){
    217 
    218     mKernelStruct = iBuilder->CreateAlloca(mKernelStructType);
    219     iBuilder->CreateCall3(mConstructor, mKernelStruct,
    220         ConstantInt::get(iBuilder->getIntNTy(64), mBlockSize),
    221         ConstantInt::get(iBuilder->getIntNTy(64), mBufferSize));
     166}
     167
     168/** ------------------------------------------------------------------------------------------------------------- *
     169 * @brief generateKernelInstance
     170 ** ------------------------------------------------------------------------------------------------------------- */
     171Value * KernelBuilder::generateKernelInstance() {
     172    mKernelStruct = iBuilder->CreateAlloca(mKernelStructType);
     173    iBuilder->CreateCall3(mConstructor, mKernelStruct,
     174        ConstantInt::get(iBuilder->getIntNTy(64), mBlockSize),
     175        ConstantInt::get(iBuilder->getIntNTy(64), (mBlocksPerSegment + mCircularBufferModulo) * mBlockSize));
    222176    return mKernelStruct;
    223177
    224178}
     179
     180Value * KernelBuilder::getInputStream(const unsigned index, const unsigned streamOffset) {
     181    Value * const indices[] = {iBuilder->getInt32(0), getOffset(streamOffset), iBuilder->getInt32(index)};
     182    return iBuilder->CreateGEP(mInputParam, indices);
     183}
     184
     185Value * KernelBuilder::getKernelState(const unsigned index, const unsigned streamOffset) {
     186    Value * const indices[] = {iBuilder->getInt32(0), iBuilder->getInt32(0), getOffset(streamOffset), iBuilder->getInt32(index)};
     187    return iBuilder->CreateGEP(mKernelParam, indices);
     188}
     189
     190Value * KernelBuilder::getOutputStream(const unsigned index, const unsigned streamOffset) {
     191    Value * const indices[] = {iBuilder->getInt32(0), iBuilder->getInt32(1), getOffset(streamOffset), iBuilder->getInt32(index)};
     192    return iBuilder->CreateGEP(mKernelParam, indices);
     193}
     194
     195Value * KernelBuilder::getOutputScalar(const unsigned index, const unsigned streamOffset) {
     196    Value * const indices[] = {iBuilder->getInt32(0), iBuilder->getInt32(2), getOffset(streamOffset), iBuilder->getInt32(index)};
     197    return iBuilder->CreateGEP(mKernelParam, indices);
     198}
     199
     200Value * KernelBuilder::getInternalState(const unsigned index){
     201    Value* indices[] = {iBuilder->getInt64(0), iBuilder->getInt32(0), iBuilder->getInt32(index)};
     202    return iBuilder->CreateGEP(mKernelParam, indices);
     203}
     204
     205void KernelBuilder::setInternalState(const unsigned index, Value * const value) {
     206    iBuilder->CreateBlockAlignedStore(value, getInternalState(index));
     207}
     208
    225209void KernelBuilder::generateInitCall(){
    226210    iBuilder->CreateCall(mInitFunction, mKernelStruct);
    227211}
    228212
    229 // void KernelBuilder::generateDoBlockCall(Value * inputStreams, Value * inputScalars){
    230 //     iBuilder->CreateCall3(mDoBlockFunction, mKernelStruct, inputStreams, inputScalars);
    231 // }
    232213void KernelBuilder::generateDoBlockCall(Value * inputStreams){
    233     iBuilder->CreateCall2(mDoBlockFunction, mKernelStruct, inputStreams);
    234 }
    235 
    236 int KernelBuilder::getSegmentBlocks(){
    237     return mSegmentBlocks;
    238 }
    239 
    240 Function * KernelBuilder::getDoBlockFunction(){
    241     return mDoBlockFunction;
    242 }
    243 
    244 Type * KernelBuilder::getKernelStructType(){
    245     return mKernelStructType;
    246 }
    247 
    248 Value * KernelBuilder::getKernelStructParam(){
    249     return mKernelStructParam;
    250 }
    251 
     214    iBuilder->CreateCall2(mFunction, mKernelStruct, inputStreams);
     215}
     216
     217/** ------------------------------------------------------------------------------------------------------------- *
     218 * @brief offset
     219 *
     220 * Compute the index of the given offset value.
     221 ** ------------------------------------------------------------------------------------------------------------- */
     222Value * KernelBuilder::getOffset(const unsigned offset) {
     223    Value * index = iBuilder->getInt32(mSegmentIndex + offset);
     224    if (mStartIndex) {
     225        index = iBuilder->CreateAdd(iBuilder->CreateBlockAlignedLoad(getInternalState(mStartIndex)), index);
     226        const unsigned capacity = (mBlocksPerSegment + mCircularBufferModulo);
     227        if (isPowerOfTwo(capacity)) {
     228            index = iBuilder->CreateAnd(index, ConstantInt::get(index->getType(), capacity - 1));
     229        } else {
     230            index = iBuilder->CreateURem(index, ConstantInt::get(index->getType(), capacity));
     231        }
     232        // TODO: generate branch / phi node when it's sufficiently unlikely that we'll wrap around.
     233    }
     234    return index;
     235}
     236
Note: See TracChangeset for help on using the changeset viewer.