Ignore:
Timestamp:
Jan 28, 2017, 3:12:03 PM (2 years ago)
Author:
nmedfort
Message:

Start of work to simplify kernel writing. Removed generateDoBlockLogic method.

File:
1 edited

Legend:

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

    r5283 r5285  
    2121namespace llvm { class Type; }
    2222
     23const std::string blockNoScalar = "blockNo";
     24
    2325using namespace llvm;
    2426using namespace kernel;
     
    149151}
    150152
     153ConstantInt * KernelBuilder::getScalarIndex(const std::string & name) const {
     154    const auto f = mKernelMap.find(name);
     155    if (LLVM_UNLIKELY(f == mKernelMap.end())) {
     156        llvm::report_fatal_error("Kernel does not contain scalar: " + name);
     157    }
     158    return iBuilder->getInt32(f->second);
     159}
     160
     161unsigned KernelBuilder::getScalarCount() const {
     162    return mKernelFields.size();
     163}
     164
     165Value * KernelBuilder::getScalarFieldPtr(Value * self, const std::string & fieldName) const {
     166    return getScalarFieldPtr(self, getScalarIndex(fieldName));
     167}
     168
     169Value * KernelBuilder::getScalarFieldPtr(Value * self, Value * index) const {
     170    return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), index});
     171}
     172
     173Value * KernelBuilder::getScalarField(Value * self, const std::string & fieldName) const {
     174    return iBuilder->CreateLoad(getScalarFieldPtr(self, fieldName));
     175}
     176
     177Value * KernelBuilder::getScalarField(Value * self, Value * index) const {
     178    return iBuilder->CreateLoad(getScalarFieldPtr(self, index));
     179}
     180
     181void KernelBuilder::setScalarField(Value * self, const std::string & fieldName, Value * value) const {
     182    iBuilder->CreateStore(value, getScalarFieldPtr(self, fieldName));
     183}
     184
     185void KernelBuilder::setScalarField(Value * self, Value * index, Value * value) const {
     186    iBuilder->CreateStore(value, getScalarFieldPtr(self, index));
     187}
     188
     189LoadInst * KernelBuilder::acquireLogicalSegmentNo(Value * self) const {
     190    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(logicalSegmentNoScalar)});
     191    return iBuilder->CreateAtomicLoadAcquire(ptr);
     192}
     193
     194Value * KernelBuilder::getProcessedItemCount(Value * self, const std::string & ssName) const {
     195    return getScalarField(self, ssName + processedItemCountSuffix);
     196}
     197
     198Value * KernelBuilder::getProducedItemCount(Value * self, const std::string & ssName) const {
     199    return getScalarField(self, ssName + producedItemCountSuffix);
     200}
     201
     202Value * KernelBuilder::getTerminationSignal(Value * self) const {
     203    return getScalarField(self, terminationSignal);
     204}
     205
     206void KernelBuilder::releaseLogicalSegmentNo(Value * self, Value * newCount) const {
     207    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(logicalSegmentNoScalar)});
     208    iBuilder->CreateAtomicStoreRelease(newCount, ptr);
     209}
     210
     211void KernelBuilder::setProcessedItemCount(Value * self, const std::string & name, Value * value) const {
     212    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(name + processedItemCountSuffix)});
     213    iBuilder->CreateStore(value, ptr);
     214}
     215
     216void KernelBuilder::setProducedItemCount(Value * self, const std::string & name, Value * value) const {
     217    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(name + producedItemCountSuffix)});
     218    iBuilder->CreateStore(value, ptr);
     219}
     220
     221void KernelBuilder::setTerminationSignal(Value * self) const {
     222    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(terminationSignal)});
     223    iBuilder->CreateStore(ConstantInt::get(iBuilder->getInt1Ty(), 1), ptr);
     224}
     225
     226Value * KernelBuilder::getBlockNo(Value * self) const {
     227    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
     228    return iBuilder->CreateLoad(ptr);
     229}
     230
     231void KernelBuilder::setBlockNo(Value * self, Value * value) const {
     232    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
     233    iBuilder->CreateStore(value, ptr);
     234}
     235
     236
     237Argument * KernelBuilder::getParameter(Function * const f, const std::string & name) const {
     238    for (auto & arg : f->getArgumentList()) {
     239        if (arg.getName().equals(name)) {
     240            return &arg;
     241        }
     242    }
     243    llvm::report_fatal_error(f->getName() + " does not have parameter " + name);
     244}
     245
     246unsigned KernelBuilder::getStreamSetIndex(const std::string & name) const {
     247    const auto f = mStreamSetNameMap.find(name);
     248    if (LLVM_UNLIKELY(f == mStreamSetNameMap.end())) {
     249        llvm::report_fatal_error("Kernel " + getName() + " does not contain stream set: " + name);
     250    }
     251    return f->second;
     252}
     253
     254Value * KernelBuilder::getStreamSetBufferPtr(Value * self, const std::string & name) const {
     255    return getScalarField(self, name + bufferPtrSuffix);
     256}
     257
     258inline const StreamSetBuffer * KernelBuilder::getStreamSetBuffer(const std::string & name) const {
     259    const unsigned structIdx = getStreamSetIndex(name);
     260    if (structIdx < mStreamSetInputs.size()) {
     261        return mStreamSetInputBuffers[structIdx];
     262    } else {
     263        return mStreamSetOutputBuffers[structIdx - mStreamSetInputs.size()];
     264    }
     265}
     266
     267Value * KernelBuilder::getStreamSetPtr(Value * self, const std::string & name, Value * blockNo) const {
     268    return getStreamSetBuffer(name)->getStreamSetPtr(getStreamSetBufferPtr(self, name), blockNo);
     269}
     270
     271Value * KernelBuilder::getStream(Value * self, const std::string & name, Value * blockNo, Value * index) const {
     272    return getStreamSetBuffer(name)->getStream(getStreamSetBufferPtr(self, name), blockNo, index);
     273}
     274
     275Value * KernelBuilder::getStream(Value * self, const std::string & name, Value * blockNo, Value * index1, Value * index2) const {
     276    assert (index1->getType() == index2->getType());
     277    return getStreamSetBuffer(name)->getStream(getStreamSetBufferPtr(self, name), blockNo, index1, index2);
     278}
     279
     280Value * KernelBuilder::getStreamView(Value * self, const std::string & name, Value * blockNo, Value * index) const {
     281    return getStreamSetBuffer(name)->getStreamView(getStreamSetBufferPtr(self, name), blockNo, index);
     282}
     283
     284Value * KernelBuilder::getStreamView(llvm::Type * type, Value * self, const std::string & name, Value * blockNo, Value * index) const {
     285    return getStreamSetBuffer(name)->getStreamView(type, getStreamSetBufferPtr(self, name), blockNo, index);
     286}
     287
     288void KernelBuilder::createInstance() {
     289    if (LLVM_UNLIKELY(mKernelStateType == nullptr)) {
     290        llvm::report_fatal_error("Cannot create kernel instance before calling prepareKernel()");
     291    }
     292    mKernelInstance = iBuilder->CreateCacheAlignedAlloca(mKernelStateType);
     293    Module * m = iBuilder->getModule();
     294    std::vector<Value *> init_args = {mKernelInstance};
     295    for (auto a : mInitialArguments) {
     296        init_args.push_back(a);
     297    }
     298    for (auto b : mStreamSetInputBuffers) {
     299        init_args.push_back(b->getStreamSetBasePtr());
     300    }
     301    for (auto b : mStreamSetOutputBuffers) {
     302        init_args.push_back(b->getStreamSetBasePtr());
     303    }
     304    std::string initFnName = mKernelName + init_suffix;
     305    Function * initMethod = m->getFunction(initFnName);
     306    if (initMethod == nullptr) {
     307        llvm::report_fatal_error("Cannot find " + initFnName);
     308    }
     309    iBuilder->CreateCall(initMethod, init_args);
     310}
     311
    151312//  The default finalBlock method simply dispatches to the doBlock routine.
    152 void BlockOrientedKernel::generateFinalBlockMethod() const {
    153     auto savePoint = iBuilder->saveIP();
    154     Module * m = iBuilder->getModule();
    155     Function * doBlockFunction = m->getFunction(mKernelName + doBlock_suffix);
    156     Function * finalBlockFunction = m->getFunction(mKernelName + finalBlock_suffix);
    157     iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "fb_entry", finalBlockFunction, 0));
    158     // Final Block arguments: self, remaining, then the standard DoBlock args.
    159     Function::arg_iterator args = finalBlockFunction->arg_begin();
    160     Value * self = &*(args++);
    161     /* Skip "remaining" arg */ args++;
    162     std::vector<Value *> doBlockArgs = {self};
    163     iBuilder->CreateCall(doBlockFunction, doBlockArgs);
    164     iBuilder->CreateRetVoid();
    165     iBuilder->restoreIP(savePoint);
    166 }
    167 
    168 // Note: this may be overridden to incorporate doBlock logic directly into
    169 // the doSegment function.
    170 void BlockOrientedKernel::generateDoBlockLogic(Value * self, Value * /* blockNo */) const {
    171     Function * doBlockFunction = iBuilder->getModule()->getFunction(mKernelName + doBlock_suffix);
    172     iBuilder->CreateCall(doBlockFunction, self);
     313void BlockOrientedKernel::generateFinalBlockMethod(Function * function, Value * self, Value * /* remainingBytes */, Value * /* blockNo */) const {
     314//    std::vector<Value *> args = {self};
     315//    for (Argument & arg : function->getArgumentList()){
     316//        args.push_back(&arg);
     317//    }
     318    iBuilder->CreateCall(getDoBlockFunction(), { self });
    173319}
    174320
     
    176322//  each block of the given number of blocksToDo, and then updates counts.
    177323void BlockOrientedKernel::generateDoSegmentMethod() const {
    178     generateDoBlockMethod();    // must be implemented by the KernelBuilder subtype
    179     generateFinalBlockMethod(); // possibly overridden by the KernelBuilder subtype
    180324    auto savePoint = iBuilder->saveIP();
     325
     326    callGenerateDoBlockMethod();
     327
     328    callGenerateDoFinalBlockMethod();
     329
    181330    Module * m = iBuilder->getModule();
    182331    Function * doSegmentFunction = m->getFunction(mKernelName + doSegment_suffix);
     
    189338    BasicBlock * segmentDone = BasicBlock::Create(iBuilder->getContext(), mKernelName + "_segmentDone", doSegmentFunction, 0);
    190339    Type * const size_ty = iBuilder->getSizeTy();
    191     Constant * stride = ConstantInt::get(size_ty, iBuilder->getStride());
    192     Value * strideBlocks = ConstantInt::get(size_ty, iBuilder->getStride() / iBuilder->getBitBlockWidth());
     340
     341    ConstantInt * stride = iBuilder->getSize(iBuilder->getStride());
     342    ConstantInt * strideBlocks = iBuilder->getSize(iBuilder->getStride() / iBuilder->getBitBlockWidth());
    193343
    194344    Function::arg_iterator args = doSegmentFunction->arg_begin();
     
    216366
    217367    iBuilder->SetInsertPoint(strideLoopBody);
    218     Value * blockNo = getScalarField(self, blockNoScalar);
    219 
    220     generateDoBlockLogic(self, blockNo);
     368    Value * blockNo = getBlockNo(self);
     369
     370    iBuilder->CreateCall(getDoBlockFunction(), self);
     371
    221372    setBlockNo(self, iBuilder->CreateAdd(blockNo, strideBlocks));
    222373    stridesRemaining->addIncoming(iBuilder->CreateSub(stridesRemaining, ConstantInt::get(size_ty, 1)), strideLoopBody);
     
    233384        for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
    234385            Value * preProduced = getProducedItemCount(self, mStreamSetOutputs[i].name);
    235 
    236386            setProducedItemCount(self, mStreamSetOutputs[i].name, iBuilder->CreateAdd(preProduced, segmentItemsProcessed));
    237             //iBuilder->CallPrintInt(mKernelName + " produced ", iBuilder->CreateAdd(preProduced, segmentItemsProcessed));
    238387        }
    239388    }
     
    244393
    245394    Value * remainingItems = iBuilder->CreateSub(producerPos[0], getProcessedItemCount(self, mStreamSetInputs[0].name));
    246     //iBuilder->CallPrintInt(mKernelName + " remainingItems", remainingItems);
    247 
    248     createFinalBlockCall(self, remainingItems);
     395
     396    iBuilder->CreateCall(getDoFinalBlockFunction(), {self, remainingItems});
     397
     398    // createFinalBlockCall(self, remainingItems);
    249399    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
    250400        Value * preProcessed = getProcessedItemCount(self, mStreamSetInputs[i].name);
     
    266416}
    267417
    268 
    269 ConstantInt * KernelBuilder::getScalarIndex(const std::string & name) const {
    270     const auto f = mKernelMap.find(name);
    271     if (LLVM_UNLIKELY(f == mKernelMap.end())) {
    272         llvm::report_fatal_error("Kernel does not contain scalar: " + name);
    273     }
    274     return iBuilder->getInt32(f->second);
    275 }
    276 
    277 unsigned KernelBuilder::getScalarCount() const {
    278     return mKernelFields.size();
    279 }
    280 
    281 Value * KernelBuilder::getScalarFieldPtr(Value * self, const std::string & fieldName) const {
    282     return getScalarFieldPtr(self, getScalarIndex(fieldName));
    283 }
    284 
    285 Value * KernelBuilder::getScalarFieldPtr(Value * self, Value * index) const {
    286     return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), index});
    287 }
    288 
    289 Value * KernelBuilder::getScalarField(Value * self, const std::string & fieldName) const {
    290     return iBuilder->CreateLoad(getScalarFieldPtr(self, fieldName));
    291 }
    292 
    293 Value * KernelBuilder::getScalarField(Value * self, Value * index) const {
    294     return iBuilder->CreateLoad(getScalarFieldPtr(self, index));
    295 }
    296 
    297 void KernelBuilder::setScalarField(Value * self, const std::string & fieldName, Value * value) const {
    298     iBuilder->CreateStore(value, getScalarFieldPtr(self, fieldName));
    299 }
    300 
    301 void KernelBuilder::setScalarField(Value * self, Value * index, Value * value) const {
    302     iBuilder->CreateStore(value, getScalarFieldPtr(self, index));
    303 }
    304 
    305 LoadInst * KernelBuilder::acquireLogicalSegmentNo(Value * self) const {
    306     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(logicalSegmentNoScalar)});
    307     return iBuilder->CreateAtomicLoadAcquire(ptr);
    308 }
    309 
    310 Value * KernelBuilder::getProcessedItemCount(Value * self, const std::string & ssName) const {
    311     return getScalarField(self, ssName + processedItemCountSuffix);
    312 }
    313 
    314 Value * KernelBuilder::getProducedItemCount(Value * self, const std::string & ssName) const {
    315     return getScalarField(self, ssName + producedItemCountSuffix);
    316 }
    317 
    318 Value * KernelBuilder::getTerminationSignal(Value * self) const {
    319     return getScalarField(self, terminationSignal);
    320 }
    321 
    322 void KernelBuilder::releaseLogicalSegmentNo(Value * self, Value * newCount) const {
    323     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(logicalSegmentNoScalar)});
    324     iBuilder->CreateAtomicStoreRelease(newCount, ptr);
    325 }
    326 
    327 void KernelBuilder::setProcessedItemCount(Value * self, const std::string & name, Value * value) const {
    328     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(name + processedItemCountSuffix)});
    329     iBuilder->CreateStore(value, ptr);
    330 }
    331 
    332 void KernelBuilder::setProducedItemCount(Value * self, const std::string & name, Value * value) const {
    333     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(name + producedItemCountSuffix)});
    334     iBuilder->CreateStore(value, ptr);
    335 }
    336 
    337 void KernelBuilder::setTerminationSignal(Value * self) const {
    338     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(terminationSignal)});
    339     iBuilder->CreateStore(ConstantInt::get(iBuilder->getInt1Ty(), 1), ptr);
    340 }
    341 
    342 Value * KernelBuilder::getBlockNo(Value * self) const {
    343     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
    344     return iBuilder->CreateLoad(ptr);
    345 }
    346 
    347 void KernelBuilder::setBlockNo(Value * self, Value * value) const {
    348     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
    349     iBuilder->CreateStore(value, ptr);
    350 }
    351 
    352 
    353 Argument * KernelBuilder::getParameter(Function * const f, const std::string & name) const {
    354     for (auto & arg : f->getArgumentList()) {
    355         if (arg.getName().equals(name)) {
    356             return &arg;
    357         }
    358     }
    359     llvm::report_fatal_error("Method does not have parameter: " + name);
    360 }
    361 
    362 unsigned KernelBuilder::getStreamSetIndex(const std::string & name) const {
    363     const auto f = mStreamSetNameMap.find(name);
    364     if (LLVM_UNLIKELY(f == mStreamSetNameMap.end())) {
    365         llvm::report_fatal_error("Kernel " + getName() + " does not contain stream set: " + name);
    366     }
    367     return f->second;
    368 }
    369 
    370 Value * KernelBuilder::getStreamSetBufferPtr(Value * self, const std::string & name) const {
    371     return getScalarField(self, name + bufferPtrSuffix);
    372 }
    373 
    374 inline const StreamSetBuffer * KernelBuilder::getStreamSetBuffer(const std::string & name) const {
    375     const unsigned structIdx = getStreamSetIndex(name);
    376     if (structIdx < mStreamSetInputs.size()) {
    377         return mStreamSetInputBuffers[structIdx];
    378     } else {
    379         return mStreamSetOutputBuffers[structIdx - mStreamSetInputs.size()];
    380     }
    381 }
    382 
    383 Value * KernelBuilder::getStreamSetPtr(Value * self, const std::string & name, Value * blockNo) const {
    384     return getStreamSetBuffer(name)->getStreamSetPtr(getStreamSetBufferPtr(self, name), blockNo);
    385 }
    386 
    387 Value * KernelBuilder::getStream(Value * self, const std::string & name, Value * blockNo, Value * index) const {
    388     return getStreamSetBuffer(name)->getStream(getStreamSetBufferPtr(self, name), blockNo, index);
    389 }
    390 
    391 Value * KernelBuilder::getStream(Value * self, const std::string & name, Value * blockNo, Value * index1, Value * index2) const {
    392     assert (index1->getType() == index2->getType());
    393     return getStreamSetBuffer(name)->getStream(getStreamSetBufferPtr(self, name), blockNo, index1, index2);
    394 }
    395 
    396 Value * KernelBuilder::getStreamView(Value * self, const std::string & name, Value * blockNo, Value * index) const {
    397     return getStreamSetBuffer(name)->getStreamView(getStreamSetBufferPtr(self, name), blockNo, index);
    398 }
    399 
    400 Value * KernelBuilder::getStreamView(llvm::Type * type, Value * self, const std::string & name, Value * blockNo, Value * index) const {
    401     return getStreamSetBuffer(name)->getStreamView(type, getStreamSetBufferPtr(self, name), blockNo, index);
    402 }
    403 
    404 void KernelBuilder::createInstance() {
    405     if (LLVM_UNLIKELY(mKernelStateType == nullptr)) {
    406         llvm::report_fatal_error("Cannot create kernel instance before calling prepareKernel()");
    407     }
    408     mKernelInstance = iBuilder->CreateCacheAlignedAlloca(mKernelStateType);
    409     Module * m = iBuilder->getModule();
    410     std::vector<Value *> init_args = {mKernelInstance};
    411     for (auto a : mInitialArguments) {
    412         init_args.push_back(a);
    413     }
    414     for (auto b : mStreamSetInputBuffers) {
    415         init_args.push_back(b->getStreamSetBasePtr());
    416     }
    417     for (auto b : mStreamSetOutputBuffers) {
    418         init_args.push_back(b->getStreamSetBasePtr());
    419     }
    420     std::string initFnName = mKernelName + init_suffix;
    421     Function * initMethod = m->getFunction(initFnName);
    422     if (!initMethod) {
    423         llvm::report_fatal_error("Cannot find " + initFnName);
    424     }
    425     iBuilder->CreateCall(initMethod, init_args);
    426 }
    427 
     418void BlockOrientedKernel::callGenerateDoBlockMethod() const {
     419    Function * f = getDoBlockFunction();
     420    Value * const self = getParameter(f, "self"); assert (self);
     421    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", f));
     422    generateDoBlockMethod(f, self, getBlockNo(self)); // must be implemented by the KernelBuilder subtype
     423    iBuilder->CreateRetVoid();
     424//    #ifndef NDEBUG
     425//    llvm::verifyFunction(*f, &errs());
     426//    #endif
     427}
     428
     429void BlockOrientedKernel::callGenerateDoFinalBlockMethod() const {
     430    Function * f = getDoFinalBlockFunction();
     431    Value * const self = getParameter(f, "self"); assert (self);
     432    Value * remainingBytes = getParameter(f, "remainingBytes"); assert (remainingBytes);
     433    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", f));
     434    generateFinalBlockMethod(f, self, remainingBytes, getBlockNo(self)); // possibly overridden by the KernelBuilder subtype
     435    iBuilder->CreateRetVoid();
     436//    #ifndef NDEBUG
     437//    llvm::verifyFunction(*f, &errs());
     438//    #endif
     439}
     440
     441Function * BlockOrientedKernel::getDoBlockFunction() const {
     442    return iBuilder->getModule()->getFunction(mKernelName + doBlock_suffix);
     443}
     444
     445Function * BlockOrientedKernel::getDoFinalBlockFunction() const {
     446    return iBuilder->getModule()->getFunction(mKernelName + finalBlock_suffix);
     447}
     448
     449// CONSTRUCTOR
    428450KernelBuilder::KernelBuilder(IDISA::IDISA_Builder * builder,
    429451                             std::string && kernelName,
     
    439461}
    440462
    441 KernelBuilder::~KernelBuilder() {
    442 
    443 }
    444 
     463KernelBuilder::~KernelBuilder() { }
     464
     465// CONSTRUCTOR
    445466BlockOrientedKernel::BlockOrientedKernel(IDISA::IDISA_Builder * builder,
    446467                                         std::string && kernelName,
     
    454475}
    455476
     477// CONSTRUCTOR
    456478SegmentOrientedKernel::SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
    457479                                             std::string && kernelName,
Note: See TracChangeset for help on using the changeset viewer.