Changeset 5283


Ignore:
Timestamp:
Jan 27, 2017, 2:22:06 PM (8 months ago)
Author:
nmedfort
Message:

Optimized Symbol Generation (and fixed potential bug that could allow duplicate names being constructed); made PabloKernel? extend PabloAST (temporarily removed PabloAST::getName() to avoid diamond problem); added an internal scalar to PabloKernel? struct for each Count to avoid InOut? output scalar variable problem; allowed CodeMotionPass? to move code within the same scope but across a branch statement. Began work on separating Kernels into either Block-Oriented or Segment-Oriented kernels.

Location:
icGREP/icgrep-devel/icgrep
Files:
2 deleted
56 edited

Legend:

Unmodified
Added
Removed
  • icGREP/icgrep-devel/icgrep/IR_Gen/CBuilder.cpp

    r5281 r5283  
    164164}
    165165
    166 void CBuilder::CreateAlignedFree(Value * const ptr, const bool ptrMayBeNull) {
    167     // WARNING: this will cause a segfault if the value of the ptr at runtime is null but ptrMayBeNull was not set
     166void CBuilder::CreateAlignedFree(Value * const ptr, const bool testForNullAddress) {
     167    // WARNING: this will segfault if the value of the ptr at runtime is null but testForNullAddress was not set
    168168    PointerType * type = cast<PointerType>(ptr->getType());
    169169    BasicBlock * exit = nullptr;
    170     if (ptrMayBeNull) {
     170    if (testForNullAddress) {
    171171        LLVMContext & C = getContext();
    172172        BasicBlock * bb = GetInsertBlock();
     
    186186    prefix = CreateIntToPtr(CreateAlignedLoad(prefix, byteWidth), type);
    187187    CreateFree(prefix);
    188     if (ptrMayBeNull) {
     188    if (testForNullAddress) {
    189189        CreateBr(exit);
    190190        SetInsertPoint(exit);
     
    242242
    243243LoadInst * CBuilder::CreateAtomicLoadAcquire(Value * ptr) {
    244     unsigned alignment = dyn_cast<PointerType>(ptr->getType())->getElementType()->getPrimitiveSizeInBits()/8;
     244    unsigned alignment = cast<PointerType>(ptr->getType())->getElementType()->getPrimitiveSizeInBits() / 8;
    245245    LoadInst * inst = CreateAlignedLoad(ptr, alignment);
    246246    inst->setOrdering(AtomicOrdering::Acquire);
     
    249249}
    250250StoreInst * CBuilder::CreateAtomicStoreRelease(Value * val, Value * ptr) {
    251     unsigned alignment = dyn_cast<PointerType>(ptr->getType())->getElementType()->getPrimitiveSizeInBits()/8;
     251    unsigned alignment = cast<PointerType>(ptr->getType())->getElementType()->getPrimitiveSizeInBits() / 8;
    252252    StoreInst * inst = CreateAlignedStore(val, ptr, alignment);
    253253    inst->setOrdering(AtomicOrdering::Release);
  • icGREP/icgrep-devel/icgrep/IR_Gen/CBuilder.h

    r5281 r5283  
    3838    void CreateFree(llvm::Value * const ptr);
    3939   
    40     void CreateAlignedFree(llvm::Value * const ptr, const bool ptrMayBeNull = false);
     40    void CreateAlignedFree(llvm::Value * const ptr, const bool testForNullAddress = false);
    4141   
    4242    llvm::Value * CreateRealloc(llvm::Value * ptr, llvm::Value * size);
  • icGREP/icgrep-devel/icgrep/cc/cc_compiler.cpp

    r5267 r5283  
    3434PabloAST * CC_Compiler::compileCC(const std::string & canonicalName, const CC *cc, PabloBlock & block) {
    3535    PabloAST * const var = charset_expr(cc, block);
    36     var->setName(block.makeName(canonicalName));
     36    if (LLVM_LIKELY(isa<Statement>(var))) {
     37        cast<Statement>(var)->setName(block.makeName(canonicalName));
     38    }
    3739    return var;
    3840}
     
    4042PabloAST * CC_Compiler::compileCC(const std::string & canonicalName, const CC *cc, PabloBuilder & builder) {
    4143    PabloAST * const var = charset_expr(cc, builder);
    42     var->setName(builder.makeName(canonicalName));
     44    if (LLVM_LIKELY(isa<Statement>(var))) {
     45        cast<Statement>(var)->setName(builder.makeName(canonicalName));
     46    }
    4347    return var;
    4448}
  • icGREP/icgrep-devel/icgrep/editd/editd_cpu_kernel.cpp

    r5267 r5283  
    6060    Value * stideCarryArr = getScalarField(kernelStuctParam, "srideCarry");
    6161    Value * blockNo = getScalarField(kernelStuctParam, blockNoScalar);
    62    
     62
    6363    unsigned carryIdx = 0;
    6464
     
    113113
    114114editdCPUKernel::editdCPUKernel(IDISA::IDISA_Builder * b, unsigned dist, unsigned pattLen) :
    115 KernelBuilder(b, "editd_cpu",
     115BlockOrientedKernel(b, "editd_cpu",
    116116             {Binding{b->getStreamSetTy(4), "CCStream"}},
    117117             {Binding{b->getStreamSetTy(dist + 1), "ResultStream"}},
  • icGREP/icgrep-devel/icgrep/editd/editd_cpu_kernel.h

    r5267 r5283  
    1414namespace kernel {
    1515
    16 class editdCPUKernel : public KernelBuilder {
     16class editdCPUKernel : public BlockOrientedKernel {
    1717public:
    1818   
  • icGREP/icgrep-devel/icgrep/editd/editd_gpu_kernel.cpp

    r5267 r5283  
    117117
    118118editdGPUKernel::editdGPUKernel(IDISA::IDISA_Builder * b, unsigned dist, unsigned pattLen) :
    119 KernelBuilder(b, "editd_gpu",
     119BlockOrientedKernel(b, "editd_gpu",
    120120              {Binding{b->getStreamSetTy(4), "CCStream"}},
    121121              {Binding{b->getStreamSetTy(dist + 1), "ResultStream"}},
  • icGREP/icgrep-devel/icgrep/editd/editd_gpu_kernel.h

    r5267 r5283  
    1414namespace kernel {
    1515
    16 class editdGPUKernel : public KernelBuilder {
     16class editdGPUKernel : public BlockOrientedKernel {
    1717public:
    1818   
  • icGREP/icgrep-devel/icgrep/editd/editdscan_kernel.cpp

    r5267 r5283  
    9999
    100100editdScanKernel::editdScanKernel(IDISA::IDISA_Builder * iBuilder, unsigned dist) :
    101 KernelBuilder(iBuilder, "scanMatch",
     101BlockOrientedKernel(iBuilder, "scanMatch",
    102102              {Binding{iBuilder->getStreamSetTy(dist + 1), "matchResults"}},
    103103              {}, {}, {}, {}),
  • icGREP/icgrep-devel/icgrep/editd/editdscan_kernel.h

    r5267 r5283  
    1313namespace kernel {
    1414   
    15 class editdScanKernel : public KernelBuilder {
     15class editdScanKernel : public BlockOrientedKernel {
    1616public:
    1717    editdScanKernel(IDISA::IDISA_Builder * iBuilder, unsigned dist);
  • icGREP/icgrep-devel/icgrep/icgrep-devel.files

    r5268 r5283  
    5353kernels/streamset.cpp
    5454kernels/streamset.h
    55 kernels/symboltablepipeline.cpp
    56 kernels/symboltablepipeline.h
    5755pablo/analysis/pabloverifier.cpp
    5856pablo/analysis/pabloverifier.hpp
     
    219217wc.cpp
    220218CMakeLists.txt
     219cc/alphabet.cpp
     220cc/alphabet.h
     221kernels/cc_kernel.cpp
     222kernels/cc_kernel.h
     223kernels/deletion.cpp
     224kernels/deletion.h
     225kernels/interface.cpp
     226kernels/interface.h
     227kernels/kernel.cpp
     228kernels/kernel.h
     229kernels/mmap_kernel.cpp
     230kernels/mmap_kernel.h
     231kernels/p2s_kernel.cpp
     232kernels/p2s_kernel.h
     233kernels/pipeline.cpp
     234kernels/pipeline.h
     235kernels/radix64.cpp
     236kernels/radix64.h
     237kernels/s2p_kernel.cpp
     238kernels/s2p_kernel.h
     239kernels/scanmatchgen.cpp
     240kernels/scanmatchgen.h
     241kernels/stdin_kernel.cpp
     242kernels/stdin_kernel.h
     243kernels/stdout_kernel.cpp
     244kernels/stdout_kernel.h
     245kernels/streamset.cpp
     246kernels/streamset.h
     247kernels/evenodd.h
     248kernels/evenodd.cpp
  • icGREP/icgrep-devel/icgrep/kernels/cc_kernel.cpp

    r5267 r5283  
    2626    Value * self = getParameter(doBlockFunction, "self");
    2727    Value * blockNo = getScalarField(self, blockNoScalar);
    28    
     28
    2929    unsigned packCount = 8 * mCodeUnitSize; 
    3030    unsigned codeUnitWidth = 8 * mCodeUnitSize;
  • icGREP/icgrep-devel/icgrep/kernels/cc_kernel.h

    r5267 r5283  
    1515namespace kernel {
    1616
    17 class KernelBuilder;
    18 
    19 class DirectCharacterClassKernelBuilder : public KernelBuilder {
     17class DirectCharacterClassKernelBuilder : public BlockOrientedKernel {
    2018public:
    2119   
    2220    DirectCharacterClassKernelBuilder(IDISA::IDISA_Builder * iBuilder, std::string ccSetName, std::vector<re::CC *> charClasses, unsigned codeUnitSize)
    23     : KernelBuilder(iBuilder, std::move(ccSetName),
     21    : BlockOrientedKernel(iBuilder, std::move(ccSetName),
    2422                  {Binding{iBuilder->getStreamSetTy(1, 8 * codeUnitSize), "codeUnitStream"}},
    2523                  {Binding{iBuilder->getStreamSetTy(charClasses.size(), 1), "ccStream"}},
     
    2927    }
    3028   
    31    
     29    void generateDoBlockMethod() const override;
     30
    3231private:
    33     void generateDoBlockMethod() const override;
    3432    std::vector<re::CC *> mCharClasses;
    3533    unsigned mCodeUnitSize;
  • icGREP/icgrep-devel/icgrep/kernels/deletion.cpp

    r5261 r5283  
    123123
    124124DeletionKernel::DeletionKernel(IDISA::IDISA_Builder * iBuilder, unsigned fw, unsigned streamCount) :
    125 KernelBuilder(iBuilder, "del",
     125BlockOrientedKernel(iBuilder, "del",
    126126              {Binding{iBuilder->getStreamSetTy(streamCount), "inputStreamSet"},
    127127               Binding{iBuilder->getStreamSetTy(), "delMaskSet"}},
  • icGREP/icgrep-devel/icgrep/kernels/deletion.h

    r5267 r5283  
    2222namespace kernel {
    2323
    24 class DeletionKernel : public kernel::KernelBuilder {
     24class DeletionKernel : public BlockOrientedKernel {
    2525public:
    2626
  • icGREP/icgrep-devel/icgrep/kernels/evenodd.cpp

    r5282 r5283  
    6666
    6767EvenOddKernel::EvenOddKernel(IDISA::IDISA_Builder * builder)
    68 : KernelBuilder(builder, "EvenOdd", {Binding{builder->getStreamSetTy(8, 1), "BasisBits"}}, {Binding{builder->getStreamSetTy(2, 1), "even_odd"}}, {}, {}, {}) {
     68: BlockOrientedKernel(builder, "EvenOdd", {Binding{builder->getStreamSetTy(8, 1), "BasisBits"}}, {Binding{builder->getStreamSetTy(2, 1), "even_odd"}}, {}, {}, {}) {
    6969    setNoTerminateAttribute(true);
    7070    setDoBlockUpdatesProducedItemCountsAttribute(false);
  • icGREP/icgrep-devel/icgrep/kernels/evenodd.h

    r5282 r5283  
    1212namespace kernel {
    1313
    14 class EvenOddKernel : public KernelBuilder {
     14class EvenOddKernel : public BlockOrientedKernel {
    1515public:
    1616   
  • icGREP/icgrep-devel/icgrep/kernels/interface.h

    r5267 r5283  
    8080    KernelInterface(IDISA::IDISA_Builder * builder,
    8181                    std::string && kernelName,
    82                     std::vector<Binding> stream_inputs,
    83                     std::vector<Binding> stream_outputs,
    84                     std::vector<Binding> scalar_inputs,
    85                     std::vector<Binding> scalar_outputs,
    86                     std::vector<Binding> internal_scalars)
     82                    std::vector<Binding> && stream_inputs,
     83                    std::vector<Binding> && stream_outputs,
     84                    std::vector<Binding> && scalar_inputs,
     85                    std::vector<Binding> && scalar_outputs,
     86                    std::vector<Binding> && internal_scalars)
    8787    : iBuilder(builder)
    8888    , mKernelName(kernelName)
  • icGREP/icgrep-devel/icgrep/kernels/kernel.cpp

    r5276 r5283  
    2525using namespace parabix;
    2626
    27 KernelBuilder::KernelBuilder(IDISA::IDISA_Builder * builder,
    28                              std::string && kernelName,
    29                              std::vector<Binding> stream_inputs,
    30                              std::vector<Binding> stream_outputs,
    31                              std::vector<Binding> scalar_parameters,
    32                              std::vector<Binding> scalar_outputs,
    33                              std::vector<Binding> internal_scalars)
    34 : KernelInterface(builder, std::move(kernelName), stream_inputs, stream_outputs, scalar_parameters, scalar_outputs, internal_scalars)
    35 , mNoTerminateAttribute(false)
    36 , mDoBlockUpdatesProducedItemCountsAttribute(false) {
    37 
    38 }
    39 
    40 unsigned KernelBuilder::addScalar(Type * type, const std::string & name) {
     27unsigned KernelBuilder::addScalar(Type * const type, const std::string & name) {
    4128    if (LLVM_UNLIKELY(mKernelStateType != nullptr)) {
    4229        llvm::report_fatal_error("Cannot add kernel field " + name + " after kernel state finalized");
    4330    }
     31    if (LLVM_UNLIKELY(mKernelMap.count(name))) {
     32        llvm::report_fatal_error("Kernel already contains field " + name);
     33    }
    4434    const auto index = mKernelFields.size();
    4535    mKernelMap.emplace(name, index);
     36    mKernelFields.push_back(type);
     37    return index;
     38}
     39
     40unsigned KernelBuilder::addUnnamedScalar(Type * const type) {
     41    if (LLVM_UNLIKELY(mKernelStateType != nullptr)) {
     42        llvm::report_fatal_error("Cannot add unnamed kernel field after kernel state finalized");
     43    }
     44    const auto index = mKernelFields.size();
    4645    mKernelFields.push_back(type);
    4746    return index;
     
    151150
    152151//  The default finalBlock method simply dispatches to the doBlock routine.
    153 void KernelBuilder::generateFinalBlockMethod() const {
     152void BlockOrientedKernel::generateFinalBlockMethod() const {
    154153    auto savePoint = iBuilder->saveIP();
    155154    Module * m = iBuilder->getModule();
     
    169168// Note: this may be overridden to incorporate doBlock logic directly into
    170169// the doSegment function.
    171 void KernelBuilder::generateDoBlockLogic(Value * self, Value * /* blockNo */) const {
     170void BlockOrientedKernel::generateDoBlockLogic(Value * self, Value * /* blockNo */) const {
    172171    Function * doBlockFunction = iBuilder->getModule()->getFunction(mKernelName + doBlock_suffix);
    173172    iBuilder->CreateCall(doBlockFunction, self);
    174173}
    175174
    176 // Note: this may be overridden to incorporate doBlock logic directly into
    177 // the doSegment function.
    178 void KernelBuilder::generateDoBlockMethod() const {
    179     llvm::report_fatal_error(mKernelName + " DoBlock method called but not implemented");
    180 }
    181 
    182 
    183175//  The default doSegment method dispatches to the doBlock routine for
    184176//  each block of the given number of blocksToDo, and then updates counts.
    185 void KernelBuilder::generateDoSegmentMethod() const {
     177void BlockOrientedKernel::generateDoSegmentMethod() const {
    186178    generateDoBlockMethod();    // must be implemented by the KernelBuilder subtype
    187179    generateFinalBlockMethod(); // possibly overridden by the KernelBuilder subtype
    188 
    189  
    190180    auto savePoint = iBuilder->saveIP();
    191181    Module * m = iBuilder->getModule();
     
    201191    Constant * stride = ConstantInt::get(size_ty, iBuilder->getStride());
    202192    Value * strideBlocks = ConstantInt::get(size_ty, iBuilder->getStride() / iBuilder->getBitBlockWidth());
    203    
     193
    204194    Function::arg_iterator args = doSegmentFunction->arg_begin();
    205195    Value * self = &*(args++);
    206196    Value * doFinal = &*(args++);
    207    
     197
    208198    std::vector<Value *> producerPos;
    209199    producerPos.push_back(&*(args++));
     
    226216
    227217    iBuilder->SetInsertPoint(strideLoopBody);
    228     Value * blockNo = getScalarField(self, blockNoScalar);   
     218    Value * blockNo = getScalarField(self, blockNoScalar);
    229219
    230220    generateDoBlockLogic(self, blockNo);
     
    232222    stridesRemaining->addIncoming(iBuilder->CreateSub(stridesRemaining, ConstantInt::get(size_ty, 1)), strideLoopBody);
    233223    iBuilder->CreateBr(strideLoopCond);
    234    
     224
    235225    iBuilder->SetInsertPoint(stridesDone);
    236226    // Update counts for the full strides processed.
     
    243233        for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
    244234            Value * preProduced = getProducedItemCount(self, mStreamSetOutputs[i].name);
    245            
     235
    246236            setProducedItemCount(self, mStreamSetOutputs[i].name, iBuilder->CreateAdd(preProduced, segmentItemsProcessed));
    247237            //iBuilder->CallPrintInt(mKernelName + " produced ", iBuilder->CreateAdd(preProduced, segmentItemsProcessed));
    248238        }
    249239    }
    250    
     240
    251241    // Now conditionally perform the final block processing depending on the doFinal parameter.
    252242    iBuilder->CreateCondBr(doFinal, doFinalBlock, segmentDone);
     
    255245    Value * remainingItems = iBuilder->CreateSub(producerPos[0], getProcessedItemCount(self, mStreamSetInputs[0].name));
    256246    //iBuilder->CallPrintInt(mKernelName + " remainingItems", remainingItems);
    257    
     247
    258248    createFinalBlockCall(self, remainingItems);
    259249    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
     
    269259    setTerminationSignal(self);
    270260    iBuilder->CreateBr(segmentDone);
    271    
     261
    272262    iBuilder->SetInsertPoint(segmentDone);
    273263
     
    290280
    291281Value * KernelBuilder::getScalarFieldPtr(Value * self, const std::string & fieldName) const {
    292     return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(fieldName)});
     282    return getScalarFieldPtr(self, getScalarIndex(fieldName));
     283}
     284
     285Value * KernelBuilder::getScalarFieldPtr(Value * self, Value * index) const {
     286    return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), index});
    293287}
    294288
     
    297291}
    298292
    299 void KernelBuilder::setScalarField(Value * self, const std::string & fieldName, Value * newFieldVal) const {
    300     iBuilder->CreateStore(newFieldVal, getScalarFieldPtr(self, fieldName));
     293Value * KernelBuilder::getScalarField(Value * self, Value * index) const {
     294    return iBuilder->CreateLoad(getScalarFieldPtr(self, index));
     295}
     296
     297void KernelBuilder::setScalarField(Value * self, const std::string & fieldName, Value * value) const {
     298    iBuilder->CreateStore(value, getScalarFieldPtr(self, fieldName));
     299}
     300
     301void KernelBuilder::setScalarField(Value * self, Value * index, Value * value) const {
     302    iBuilder->CreateStore(value, getScalarFieldPtr(self, index));
    301303}
    302304
     
    323325}
    324326
    325 void KernelBuilder::setProcessedItemCount(Value * self, const std::string & ssName, Value * newCount) const {
    326     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(ssName + processedItemCountSuffix)});
    327     iBuilder->CreateStore(newCount, ptr);
    328 }
    329 
    330 void KernelBuilder::setProducedItemCount(Value * self, const std::string & ssName, Value * newCount) const {
    331     Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(ssName + producedItemCountSuffix)});
    332     iBuilder->CreateStore(newCount, ptr);
     327void 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
     332void 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);
    333335}
    334336
    335337void KernelBuilder::setTerminationSignal(Value * self) const {
    336338    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(terminationSignal)});
    337     //iBuilder->CallPrintInt(mKernelName + " setTermination", getScalarIndex(terminationSignal));
    338339    iBuilder->CreateStore(ConstantInt::get(iBuilder->getInt1Ty(), 1), ptr);
    339340}
     
    350351
    351352
    352 Value * KernelBuilder::getParameter(Function * f, const std::string & paramName) const {
    353     for (Function::arg_iterator argIter = f->arg_begin(), end = f->arg_end(); argIter != end; argIter++) {
    354         Value * arg = &*argIter;
    355         if (arg->getName() == paramName) return arg;
    356     }
    357     llvm::report_fatal_error("Method does not have parameter: " + paramName);
     353Argument * 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);
    358360}
    359361
     
    361363    const auto f = mStreamSetNameMap.find(name);
    362364    if (LLVM_UNLIKELY(f == mStreamSetNameMap.end())) {
    363         llvm::report_fatal_error("Kernel does not contain stream set: " + name);
     365        llvm::report_fatal_error("Kernel " + getName() + " does not contain stream set: " + name);
    364366    }
    365367    return f->second;
     
    424426}
    425427
     428KernelBuilder::KernelBuilder(IDISA::IDISA_Builder * builder,
     429                             std::string && kernelName,
     430                             std::vector<Binding> && stream_inputs,
     431                             std::vector<Binding> && stream_outputs,
     432                             std::vector<Binding> && scalar_parameters,
     433                             std::vector<Binding> && scalar_outputs,
     434                             std::vector<Binding> && internal_scalars)
     435: KernelInterface(builder, std::move(kernelName), std::move(stream_inputs), std::move(stream_outputs), std::move(scalar_parameters), std::move(scalar_outputs), std::move(internal_scalars))
     436, mNoTerminateAttribute(false)
     437, mDoBlockUpdatesProducedItemCountsAttribute(false) {
     438
     439}
     440
    426441KernelBuilder::~KernelBuilder() {
    427 }
     442
     443}
     444
     445BlockOrientedKernel::BlockOrientedKernel(IDISA::IDISA_Builder * builder,
     446                                         std::string && kernelName,
     447                                         std::vector<Binding> && stream_inputs,
     448                                         std::vector<Binding> && stream_outputs,
     449                                         std::vector<Binding> && scalar_parameters,
     450                                         std::vector<Binding> && scalar_outputs,
     451                                         std::vector<Binding> && internal_scalars)
     452: 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)) {
     453
     454}
     455
     456SegmentOrientedKernel::SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
     457                                             std::string && kernelName,
     458                                             std::vector<Binding> && stream_inputs,
     459                                             std::vector<Binding> && stream_outputs,
     460                                             std::vector<Binding> && scalar_parameters,
     461                                             std::vector<Binding> && scalar_outputs,
     462                                             std::vector<Binding> && internal_scalars)
     463: 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)) {
     464
     465}
  • icGREP/icgrep-devel/icgrep/kernels/kernel.h

    r5276 r5283  
    4545
    4646    llvm::Value * getBlockNo(llvm::Value * self) const;
     47
    4748    virtual llvm::Value * getProcessedItemCount(llvm::Value * self, const std::string & ssName) const override;
     49
    4850    virtual llvm::Value * getProducedItemCount(llvm::Value * self, const std::string & ssName) const override;
    4951   
     
    9092    KernelBuilder(IDISA::IDISA_Builder * builder,
    9193                    std::string && kernelName,
    92                     std::vector<Binding> stream_inputs,
    93                     std::vector<Binding> stream_outputs,
    94                     std::vector<Binding> scalar_parameters,
    95                     std::vector<Binding> scalar_outputs,
    96                     std::vector<Binding> internal_scalars);
     94                    std::vector<Binding> && stream_inputs,
     95                    std::vector<Binding> && stream_outputs,
     96                    std::vector<Binding> && scalar_parameters,
     97                    std::vector<Binding> && scalar_outputs,
     98                    std::vector<Binding> && internal_scalars);
    9799
    98100    //
     
    107109    // be added, the default method for preparing kernel state may be used.
    108110   
    109     void setNoTerminateAttribute(bool noTerminate = true) {mNoTerminateAttribute = noTerminate;}
    110     void setDoBlockUpdatesProducedItemCountsAttribute(bool doesUpdate = true) {mDoBlockUpdatesProducedItemCountsAttribute = doesUpdate;}
     111    void setNoTerminateAttribute(const bool noTerminate = true) {
     112        mNoTerminateAttribute = noTerminate;
     113    }
     114
     115    void setDoBlockUpdatesProducedItemCountsAttribute(const bool doesUpdate = true) {
     116        mDoBlockUpdatesProducedItemCountsAttribute = doesUpdate;
     117    }
    111118   
    112119    virtual void prepareKernel();
    113    
    114     // Each kernel builder subtype must provide its own logic for generating
    115     // doBlock calls.
    116     virtual void generateDoBlockMethod() const;
    117 
    118     virtual void generateDoBlockLogic(llvm::Value * self, llvm::Value * blockNo) const;
    119 
    120     // Each kernel builder subtypre must also specify the logic for processing the
    121     // final block of stream data, if there is any special processing required
    122     // beyond simply calling the doBlock function.   In the case that the final block
    123     // processing may be trivially implemented by dispatching to the doBlock method
    124     // without additional preparation, the default generateFinalBlockMethod need
    125     // not be overridden.
    126    
    127     virtual void generateFinalBlockMethod() const;
    128    
     120       
    129121    virtual void generateInitMethod() const;
    130122   
    131     virtual void generateDoSegmentMethod() const;
     123    virtual void generateDoSegmentMethod() const = 0;
    132124   
    133125    // Add an additional scalar field to the KernelState struct.
     
    135127    unsigned addScalar(llvm::Type * type, const std::string & name);
    136128
     129    unsigned addUnnamedScalar(llvm::Type * type);
     130
    137131    unsigned getScalarCount() const;
    138132
     
    146140    llvm::Value * getScalarField(llvm::Value * self, const std::string & fieldName) const;
    147141
     142    llvm::Value * getScalarField(llvm::Value * self, llvm::Value * index) const;
     143
    148144    // Set the value of a scalar field for a given instance.
    149     void setScalarField(llvm::Value * self, const std::string & fieldName, llvm::Value * newFieldVal) const;
    150    
     145    void setScalarField(llvm::Value * self, const std::string & fieldName, llvm::Value * value) const;
     146
     147    void setScalarField(llvm::Value * self, llvm::Value * index, llvm::Value * value) const;
     148
    151149    // Get a parameter by name.
    152     llvm::Value * getParameter(llvm::Function * f, const std::string & paramName) const;
     150    llvm::Argument * getParameter(llvm::Function * f, const std::string & name) const;
    153151
    154152    llvm::Value * getStream(llvm::Value * self, const std::string & name, llvm::Value * blockNo, llvm::Value * index) const;
     
    165163    llvm::Value * getScalarFieldPtr(llvm::Value * self, const std::string & name) const;
    166164
     165    llvm::Value * getScalarFieldPtr(llvm::Value * self, llvm::Value * index) const;
     166
    167167    llvm::Value * getStreamSetBufferPtr(llvm::Value * self, const std::string & name) const;
    168168
     169    llvm::Value * getStreamSetBufferPtr(llvm::Value * self, llvm::Value * index) const;
     170
    169171    llvm::Value * getStreamSetPtr(llvm::Value * self, const std::string & name, llvm::Value * blockNo) const;
    170172   
    171173    void setBlockNo(llvm::Value * self, llvm::Value * value) const;
    172174
    173     virtual void setProcessedItemCount(llvm::Value * self, const std::string & ssName, llvm::Value * newFieldVal) const;
    174 
    175     virtual void setProducedItemCount(llvm::Value * self, const std::string & ssName, llvm::Value * newFieldVal) const;
    176 
    177 
    178 private:
     175    virtual void setProcessedItemCount(llvm::Value * self, const std::string & name, llvm::Value * value) const;
     176
     177    virtual void setProducedItemCount(llvm::Value * self, const std::string & name, llvm::Value * value) const;
     178
     179protected:
    179180
    180181    const parabix::StreamSetBuffer * getStreamSetBuffer(const std::string & name) const;
     
    191192
    192193};
     194
     195class BlockOrientedKernel : public KernelBuilder {
     196protected:
     197
     198    // Each kernel builder subtype must provide its own logic for generating
     199    // doBlock calls.
     200    virtual void generateDoBlockMethod() const = 0;
     201
     202    virtual void generateDoBlockLogic(llvm::Value * self, llvm::Value * blockNo) const;
     203
     204    // Each kernel builder subtypre must also specify the logic for processing the
     205    // final block of stream data, if there is any special processing required
     206    // beyond simply calling the doBlock function.   In the case that the final block
     207    // processing may be trivially implemented by dispatching to the doBlock method
     208    // without additional preparation, the default generateFinalBlockMethod need
     209    // not be overridden.
     210
     211    virtual void generateFinalBlockMethod() const;
     212
     213    virtual void generateDoSegmentMethod() const final;
     214
     215    BlockOrientedKernel(IDISA::IDISA_Builder * builder,
     216                        std::string && kernelName,
     217                        std::vector<Binding> && stream_inputs,
     218                        std::vector<Binding> && stream_outputs,
     219                        std::vector<Binding> && scalar_parameters,
     220                        std::vector<Binding> && scalar_outputs,
     221                        std::vector<Binding> && internal_scalars);
     222
     223    virtual ~BlockOrientedKernel() { }
     224};
     225
     226class SegmentOrientedKernel : public KernelBuilder {
     227protected:
     228    SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
     229                          std::string && kernelName,
     230                          std::vector<Binding> && stream_inputs,
     231                          std::vector<Binding> && stream_outputs,
     232                          std::vector<Binding> && scalar_parameters,
     233                          std::vector<Binding> && scalar_outputs,
     234                          std::vector<Binding> && internal_scalars);
     235
     236    virtual ~SegmentOrientedKernel() { }
     237};
     238
     239
     240
    193241}
    194242#endif
  • icGREP/icgrep-devel/icgrep/kernels/mmap_kernel.cpp

    r5276 r5283  
    2828   
    2929   
    30     Function::arg_iterator args = doSegmentFunction->arg_begin();
     30    auto args = doSegmentFunction->arg_begin();
    3131    Value * self = &*(args++);
    3232   
     
    3535        fileItems = iBuilder->CreateUDiv(fileItems, iBuilder->getSize(mCodeUnitWidth/8));
    3636    }
    37     Value * produced = getProducedItemCount(self, "sourceBuffer");
    38    
     37    Value * produced = getProducedItemCount(self, "sourceBuffer");   
    3938    Value * nextProduced = iBuilder->CreateAdd(produced, segmentItems);
    4039    Value * lessThanFullSegment = iBuilder->CreateICmpULT(fileItems, nextProduced);
     
    5453
    5554MMapSourceKernel::MMapSourceKernel(IDISA::IDISA_Builder * iBuilder, unsigned blocksPerSegment, unsigned codeUnitWidth)
    56 : KernelBuilder(iBuilder, "mmap_source", {}, {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}}, {Binding{iBuilder->getSizeTy(), "fileSize"}}, {}, {})
     55: SegmentOrientedKernel(iBuilder, "mmap_source", {}, {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}}, {Binding{iBuilder->getSizeTy(), "fileSize"}}, {}, {})
    5756, mSegmentBlocks(blocksPerSegment)
    5857, mCodeUnitWidth(codeUnitWidth) {
  • icGREP/icgrep-devel/icgrep/kernels/mmap_kernel.h

    r5267 r5283  
    1515   pipeline. */
    1616   
    17 class MMapSourceKernel : public KernelBuilder {
     17class MMapSourceKernel : public SegmentOrientedKernel {
    1818public:
    1919    MMapSourceKernel(IDISA::IDISA_Builder * iBuilder, unsigned blocksPerSegment = 1, unsigned codeUnitWidth = 8);
  • icGREP/icgrep-devel/icgrep/kernels/p2s_kernel.cpp

    r5276 r5283  
    6666}
    6767
    68 P2SKernel::P2SKernel(IDISA::IDISA_Builder * iBuilder) :
    69     KernelBuilder(iBuilder, "p2s",
    70                   {Binding{iBuilder->getStreamSetTy(8, 1), "basisBits"}},
    71                   {Binding{iBuilder->getStreamSetTy(1, 8), "byteStream"}},
    72                   {}, {}, {}) {
    73 
    74     }
     68P2SKernel::P2SKernel(IDISA::IDISA_Builder * iBuilder)
     69: BlockOrientedKernel(iBuilder, "p2s",
     70              {Binding{iBuilder->getStreamSetTy(8, 1), "basisBits"}},
     71              {Binding{iBuilder->getStreamSetTy(1, 8), "byteStream"}},
     72              {}, {}, {}) {
     73
     74}
    7575   
    7676
     
    117117   
    118118P2SKernelWithCompressedOutput::P2SKernelWithCompressedOutput(IDISA::IDISA_Builder * iBuilder)
    119 : KernelBuilder(iBuilder, "p2s_compress",
     119: BlockOrientedKernel(iBuilder, "p2s_compress",
    120120              {Binding{iBuilder->getStreamSetTy(8, 1), "basisBits"}, Binding{iBuilder->getStreamSetTy(1, 1), "deletionCounts"}},
    121121              {Binding{iBuilder->getStreamSetTy(1, 8), "byteStream"}},
     
    134134    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", doBlockFunction, 0));
    135135    Value * self = getParameter(doBlockFunction, "self");
    136     Value * blockNo = getScalarField(self, blockNoScalar);   
    137    
     136    Value * blockNo = getScalarField(self, blockNoScalar);
     137
    138138    Value * hi_input[8];
    139139    for (unsigned j = 0; j < 8; ++j) {
     
    165165   
    166166
    167 P2S16Kernel::P2S16Kernel(IDISA::IDISA_Builder * iBuilder) :
    168     KernelBuilder(iBuilder, "p2s_16",
    169                   {Binding{iBuilder->getStreamSetTy(16, 1), "basisBits"}},
    170                   {Binding{iBuilder->getStreamSetTy(1, 16), "i16Stream"}},
    171                   {}, {}, {}) {
    172        
    173     }
     167P2S16Kernel::P2S16Kernel(IDISA::IDISA_Builder * iBuilder)
     168: BlockOrientedKernel(iBuilder, "p2s_16",
     169              {Binding{iBuilder->getStreamSetTy(16, 1), "basisBits"}},
     170              {Binding{iBuilder->getStreamSetTy(1, 16), "i16Stream"}},
     171              {}, {}, {}) {
     172
     173}
    174174
    175175   
     
    240240}
    241241   
    242 P2S16KernelWithCompressedOutput::P2S16KernelWithCompressedOutput(IDISA::IDISA_Builder * iBuilder) :
    243     KernelBuilder(iBuilder, "p2s_16_compress",
    244                   {Binding{iBuilder->getStreamSetTy(16, 1), "basisBits"}, Binding{iBuilder->getStreamSetTy(1, 1), "deletionCounts"}},
    245                   {Binding{iBuilder->getStreamSetTy(1, 16), "i16Stream"}},
    246                   {},
    247                   {},
    248                   {Binding{iBuilder->getSizeTy(), "unitsGenerated"}, Binding{iBuilder->getSizeTy(), "unitsWritten"}}) {
    249         setDoBlockUpdatesProducedItemCountsAttribute(true);
    250 }
    251    
    252    
    253 }
     242P2S16KernelWithCompressedOutput::P2S16KernelWithCompressedOutput(IDISA::IDISA_Builder * iBuilder)
     243: BlockOrientedKernel(iBuilder, "p2s_16_compress",
     244              {Binding{iBuilder->getStreamSetTy(16, 1), "basisBits"}, Binding{iBuilder->getStreamSetTy(1, 1), "deletionCounts"}},
     245              {Binding{iBuilder->getStreamSetTy(1, 16), "i16Stream"}},
     246              {},
     247              {},
     248              {Binding{iBuilder->getSizeTy(), "unitsGenerated"}, Binding{iBuilder->getSizeTy(), "unitsWritten"}}) {
     249    setDoBlockUpdatesProducedItemCountsAttribute(true);
     250}
     251   
     252   
     253}
  • icGREP/icgrep-devel/icgrep/kernels/p2s_kernel.h

    r5267 r5283  
    1212
    1313   
    14 class P2SKernel : public KernelBuilder {
     14class P2SKernel : public BlockOrientedKernel {
    1515public:
    1616    P2SKernel(IDISA::IDISA_Builder * iBuilder);
     
    2121};
    2222
    23 class P2SKernelWithCompressedOutput : public KernelBuilder {
     23class P2SKernelWithCompressedOutput : public BlockOrientedKernel {
    2424public:
    2525    P2SKernelWithCompressedOutput(IDISA::IDISA_Builder * iBuilder);   
     
    2929   
    3030
    31 class P2S16Kernel : public KernelBuilder {
     31class P2S16Kernel : public BlockOrientedKernel {
    3232public:
    3333    P2S16Kernel(IDISA::IDISA_Builder * iBuilder);   
     
    3838
    3939   
    40 class P2S16KernelWithCompressedOutput : public KernelBuilder {
     40class P2S16KernelWithCompressedOutput : public BlockOrientedKernel {
    4141public:
    4242    P2S16KernelWithCompressedOutput(IDISA::IDISA_Builder * iBuilder);
  • icGREP/icgrep-devel/icgrep/kernels/pipeline.cpp

    r5276 r5283  
    9696   
    9797    Module * m = iBuilder->getModule();
    98     Type * const size_ty = iBuilder->getSizeTy();
    9998    Type * const voidTy = iBuilder->getVoidTy();
    10099    PointerType * const voidPtrTy = iBuilder->getVoidPtrTy();
     
    108107    input->setName("input");
    109108
    110     unsigned threadNum = codegen::ThreadNum;
    111109
    112110     // Create the basic blocks for the thread function.
     
    118116    std::vector<BasicBlock *> segmentLoopBody;
    119117    for (unsigned i = 0; i < kernels.size(); i++) {
    120         std::string kname = kernels[i]->getName();
     118        auto kname = kernels[i]->getName();
    121119        segmentWait.push_back(BasicBlock::Create(iBuilder->getContext(), kname + "Wait", threadFunc, 0));
    122         segmentLoopBody.push_back(BasicBlock::Create(iBuilder->getContext(), "do_" + kname, threadFunc, 0));
     120        segmentLoopBody.push_back(BasicBlock::Create(iBuilder->getContext(), kname + "Do", threadFunc, 0));
    123121    }
    124122
     
    126124   
    127125    Value * sharedStruct = iBuilder->CreateBitCast(input, PointerType::get(sharedStructType, 0));
    128     Constant * myThreadId = ConstantInt::get(size_ty, id);
    129126    std::vector<Value *> instancePtrs;
    130127    for (unsigned k = 0; k < kernels.size(); k++) {
     
    136133
    137134    iBuilder->SetInsertPoint(segmentLoop);
    138     PHINode * segNo = iBuilder->CreatePHI(size_ty, 2, "segNo");
    139     segNo->addIncoming(myThreadId, entryBlock);
    140     Value * nextSegNo = iBuilder->CreateAdd(segNo, iBuilder->getSize(1));
    141     unsigned last_kernel = kernels.size() - 1;
     135    PHINode * segNo = iBuilder->CreatePHI(iBuilder->getSizeTy(), 2, "segNo");
     136    segNo->addIncoming(iBuilder->getSize(id), entryBlock);
     137    const unsigned last_kernel = kernels.size() - 1;
    142138    Value * doFinal = ConstantInt::getNullValue(iBuilder->getInt1Ty());
    143139   
     
    182178            doFinal = iBuilder->CreateOr(doFinal, terminated);
    183179        }
     180
     181        Value * nextSegNo = iBuilder->CreateAdd(segNo, iBuilder->getSize(1));
    184182        kernels[k]->releaseLogicalSegmentNo(instancePtrs[k], nextSegNo);
    185183        if (k == last_kernel) {
    186             segNo->addIncoming(iBuilder->CreateAdd(segNo, ConstantInt::get(size_ty, threadNum)), segmentLoopBody[last_kernel]);
     184            segNo->addIncoming(iBuilder->CreateAdd(segNo, iBuilder->getSize(codegen::ThreadNum)), segmentLoopBody[last_kernel]);
    187185            iBuilder->CreateCondBr(doFinal, exitThreadBlock, segmentLoop);
    188186        }
     
    210208void generateSegmentParallelPipeline(IDISA::IDISA_Builder * iBuilder, const std::vector<KernelBuilder *> & kernels) {
    211209   
    212     unsigned threadNum = codegen::ThreadNum;
     210    const unsigned threadNum = codegen::ThreadNum;
    213211   
    214212    Module * m = iBuilder->getModule();
  • icGREP/icgrep-devel/icgrep/kernels/radix64.cpp

    r5277 r5283  
    4141// a continous buffer for the full segment (number of blocks).
    4242
    43    
    44 expand3_4Kernel::expand3_4Kernel(IDISA::IDISA_Builder * iBuilder) :
    45     KernelBuilder(iBuilder, "expand3_4",
    46                   {Binding{iBuilder->getStreamSetTy(1, 8), "sourceStream"}},
    47                   {Binding{iBuilder->getStreamSetTy(1, 8), "expandedStream"}},
    48                   {}, {}, {}) {
    49         setDoBlockUpdatesProducedItemCountsAttribute(true);
    50     }
    51    
    52    
    5343void expand3_4Kernel::generateDoSegmentMethod() const {
    5444    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
     
    441431}
    442432
    443    
    444 radix64Kernel::radix64Kernel(IDISA::IDISA_Builder * iBuilder) :
    445     KernelBuilder(iBuilder, "radix64",
    446                   {Binding{iBuilder->getStreamSetTy(1, 8), "expandedStream"}},
    447                   {Binding{iBuilder->getStreamSetTy(1, 8), "radix64stream"}},
    448                   {}, {}, {}) {
    449         setDoBlockUpdatesProducedItemCountsAttribute(true);
    450 }
    451    
    452433void radix64Kernel::generateDoBlockMethod() const {
    453434    auto savePoint = iBuilder->saveIP();
     
    465446    iBuilder->restoreIP(savePoint);
    466447}
    467 
    468 base64Kernel::base64Kernel(IDISA::IDISA_Builder * iBuilder) :
    469     KernelBuilder(iBuilder, "base64",
    470                   {Binding{iBuilder->getStreamSetTy(1, 8), "radix64stream"}},
    471                   {Binding{iBuilder->getStreamSetTy(1, 8), "base64stream"}},
    472                   {}, {}, {}) {
    473         setDoBlockUpdatesProducedItemCountsAttribute(true);
    474     }
    475    
    476448
    477449void base64Kernel::generateDoBlockLogic(Value * self, Value * blockNo) const {       
     
    590562}
    591563
    592 }
     564expand3_4Kernel::expand3_4Kernel(IDISA::IDISA_Builder * iBuilder)
     565: SegmentOrientedKernel(iBuilder, "expand3_4",
     566              {Binding{iBuilder->getStreamSetTy(1, 8), "sourceStream"}},
     567              {Binding{iBuilder->getStreamSetTy(1, 8), "expandedStream"}},
     568              {}, {}, {}) {
     569    setDoBlockUpdatesProducedItemCountsAttribute(true);
     570}
     571
     572radix64Kernel::radix64Kernel(IDISA::IDISA_Builder * iBuilder)
     573: BlockOrientedKernel(iBuilder, "radix64", {Binding{iBuilder->getStreamSetTy(1, 8), "expandedStream"}}, {Binding{iBuilder->getStreamSetTy(1, 8), "radix64stream"}}, {}, {}, {}) {
     574    setDoBlockUpdatesProducedItemCountsAttribute(true);
     575}
     576
     577base64Kernel::base64Kernel(IDISA::IDISA_Builder * iBuilder)
     578: BlockOrientedKernel(iBuilder, "base64", {Binding{iBuilder->getStreamSetTy(1, 8), "radix64stream"}}, {Binding{iBuilder->getStreamSetTy(1, 8), "base64stream"}}, {}, {}, {}) {
     579    setDoBlockUpdatesProducedItemCountsAttribute(true);
     580}
     581
     582}
  • icGREP/icgrep-devel/icgrep/kernels/radix64.h

    r5277 r5283  
    1919    This is a useful preparatory transformation in various radix-64 encodings. */
    2020 
    21 class expand3_4Kernel : public KernelBuilder {
     21class expand3_4Kernel : public SegmentOrientedKernel {
    2222public:
    2323   
     
    2929};
    3030
    31 class radix64Kernel : public KernelBuilder {
     31class radix64Kernel : public BlockOrientedKernel {
    3232public:
    3333   
     
    3939};
    4040
    41 class base64Kernel : public KernelBuilder {
     41class base64Kernel : public BlockOrientedKernel {
    4242public:
    4343   
  • icGREP/icgrep-devel/icgrep/kernels/s2p_kernel.cpp

    r5261 r5283  
    192192
    193193S2PKernel::S2PKernel(IDISA::IDISA_Builder * builder)
    194 : KernelBuilder(builder, "s2p", {Binding{builder->getStreamSetTy(1, 8), "byteStream"}}, {Binding{builder->getStreamSetTy(8, 1), "basisBits"}}, {}, {}, {}) {
     194: BlockOrientedKernel(builder, "s2p", {Binding{builder->getStreamSetTy(1, 8), "byteStream"}}, {Binding{builder->getStreamSetTy(8, 1), "basisBits"}}, {}, {}, {}) {
    195195    setNoTerminateAttribute(true);
    196196    setDoBlockUpdatesProducedItemCountsAttribute(false);
  • icGREP/icgrep-devel/icgrep/kernels/s2p_kernel.h

    r5267 r5283  
    1212namespace kernel {
    1313
    14 class S2PKernel : public KernelBuilder {
     14class S2PKernel : public BlockOrientedKernel {
    1515public:
    1616   
  • icGREP/icgrep-devel/icgrep/kernels/scanmatchgen.h

    r5267 r5283  
    1414namespace kernel {
    1515   
    16 class ScanMatchKernel : public KernelBuilder {
     16class ScanMatchKernel : public BlockOrientedKernel {
    1717public:
    1818    ScanMatchKernel(IDISA::IDISA_Builder * iBuilder, GrepType grepType) :
    19     KernelBuilder(iBuilder, "scanMatch",
     19    BlockOrientedKernel(iBuilder, "scanMatch",
    2020                  {Binding{iBuilder->getStreamSetTy(2, 1), "matchResults"}},
    2121                    {},
  • icGREP/icgrep-devel/icgrep/kernels/stdin_kernel.cpp

    r5281 r5283  
    5151
    5252StdInKernel::StdInKernel(IDISA::IDISA_Builder * iBuilder, unsigned blocksPerSegment, unsigned codeUnitWidth)
    53 : KernelBuilder(iBuilder, "stdin_source", {}, {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {})
     53: SegmentOrientedKernel(iBuilder, "stdin_source", {}, {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {})
    5454, mSegmentBlocks(blocksPerSegment)
    5555, mCodeUnitWidth(codeUnitWidth) {
     
    123123   
    124124FileSource::FileSource(IDISA::IDISA_Builder * iBuilder, unsigned blocksPerSegment, unsigned codeUnitWidth)
    125 : KernelBuilder(iBuilder, "filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
     125: SegmentOrientedKernel(iBuilder, "filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
    126126                {Binding{iBuilder->getInt8PtrTy(), "fileName"}}, {}, {Binding{iBuilder->getFILEptrTy(), "IOstreamPtr"}})
    127127, mSegmentBlocks(blocksPerSegment)
  • icGREP/icgrep-devel/icgrep/kernels/stdin_kernel.h

    r5281 r5283  
    1414namespace kernel {
    1515
    16 class StdInKernel : public KernelBuilder {
     16class StdInKernel : public SegmentOrientedKernel {
    1717public:
    1818    StdInKernel(IDISA::IDISA_Builder * iBuilder, unsigned blocksPerSegment = 1, unsigned codeUnitWidth = 8);
     
    2727   
    2828
    29 class FileSource : public KernelBuilder {
     29class FileSource : public SegmentOrientedKernel {
    3030public:
    3131 
  • icGREP/icgrep-devel/icgrep/kernels/stdout_kernel.cpp

    r5280 r5283  
    4848
    4949StdOutKernel::StdOutKernel(IDISA::IDISA_Builder * iBuilder, unsigned codeUnitWidth)
    50 : KernelBuilder(iBuilder, "stdout", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {}, {})
     50: SegmentOrientedKernel(iBuilder, "stdout", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {}, {})
    5151, mCodeUnitWidth(codeUnitWidth) {
    5252    setNoTerminateAttribute(true);
     
    123123
    124124FileSink::FileSink(IDISA::IDISA_Builder * iBuilder, unsigned codeUnitWidth)
    125 : KernelBuilder(iBuilder, "filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
     125: SegmentOrientedKernel(iBuilder, "filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
    126126                {Binding{iBuilder->getInt8PtrTy(), "fileName"}}, {}, {Binding{iBuilder->getFILEptrTy(), "IOstreamPtr"}})
    127127, mCodeUnitWidth(codeUnitWidth) {
  • icGREP/icgrep-devel/icgrep/kernels/stdout_kernel.h

    r5280 r5283  
    1212namespace kernel {
    1313
    14 class StdOutKernel : public KernelBuilder {
     14class StdOutKernel : public SegmentOrientedKernel {
    1515public:
    1616
     
    2727
    2828
    29 class FileSink : public KernelBuilder {
     29class FileSink : public SegmentOrientedKernel {
    3030public:
    3131   
  • icGREP/icgrep-devel/icgrep/kernels/streamset.cpp

    r5276 r5283  
    4040    mStreamSetBufferPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetType, iBuilder->getSize(mBufferBlocks));
    4141}
    42 
    4342
    4443Value * StreamSetBuffer::getStream(Value * self, Value * blockNo, Value * index) const {
  • icGREP/icgrep-devel/icgrep/pablo/analysis/pabloverifier.cpp

    r5267 r5283  
    7373                throw std::runtime_error(str.str());
    7474            }
    75         } else if (isa<Var>(use)) {
    76             if (LLVM_UNLIKELY(isa<Branch>(expr))) {
     75        } else if (isa<Var>(expr)) {
     76            if (LLVM_UNLIKELY(isa<Branch>(use) || isa<PabloKernel>(use))) {
    7777                ++uses;
    7878            } else {
     
    8383                str << " is a user of ";
    8484                PabloPrinter::print(expr, str);
    85                 str << " but can only be a user of a Branch or Function.";
     85                str << " but can only be a user of a Branch or Kernel.";
    8686                throw std::runtime_error(str.str());
    8787            }
  • icGREP/icgrep-devel/icgrep/pablo/arithmetic.h

    r5267 r5283  
    3636protected:
    3737    Operator(const ClassTypeId typeId, llvm::Type * const type, PabloAST * const expr1, PabloAST * const expr2, Allocator & allocator)
    38     : PabloAST(typeId, type, nullptr, allocator)
     38    : PabloAST(typeId, type, allocator)
    3939    , mLH(expr1)
    4040    , mRH(expr2) {
  • icGREP/icgrep-devel/icgrep/pablo/branch.cpp

    r5267 r5283  
    33#include <pablo/pe_var.h>
    44#include <pablo/ps_assign.h>
     5#include <pablo/pablo_kernel.h>
     6
     7#include <llvm/Support/raw_ostream.h>
    58
    69using namespace llvm;
     
    2023    bool inside = false;
    2124    bool outside = false;
     25
    2226    for (const PabloAST * user : var->users()) {
    23         if (isa<Assign>(user)) {           
     27
     28        if (isa<Assign>(user)) {
    2429
    2530            const PabloBlock * const scope = cast<Assign>(user)->getParent();
    26 
    2731            // Is this Var assigned a value within the body of this branch?
    2832            for (const PabloBlock * test = scope; test; test = test->getPredecessor()) {
     
    6771                test = check->getParent();
    6872            }
     73        } else if (isa<PabloKernel>(user)) {
     74            if (inside) {
     75                return true;
     76            }
     77            outside = true;
    6978        }
    7079outer_loop: continue;
  • icGREP/icgrep-devel/icgrep/pablo/builder.cpp

    r5267 r5283  
    3737        return mPb->NAME(arg, mPrefix); \
    3838    } \
    39     inline __##NAME(PabloBlock * pb, const std::string & prefix) : mPb(pb), mPrefix(prefix) {} \
    40 private: \
    41     PabloBlock * mPb; \
    42     const std::string & mPrefix; \
     39    inline __##NAME(PabloBlock * pb, const llvm::StringRef & prefix) : mPb(pb), mPrefix(prefix) {} \
     40private: \
     41    PabloBlock * mPb; \
     42    const llvm::StringRef & mPrefix; \
    4343}; \
    4444__##NAME functor(mPb, prefix); \
     
    6262        return mPb->NAME(arg1, arg2, mPrefix); \
    6363    } \
    64     inline __##NAME(PabloBlock * pb, const std::string & prefix) : mPb(pb), mPrefix(prefix) {} \
    65 private: \
    66     PabloBlock * mPb; \
    67     const std::string & mPrefix; \
     64    inline __##NAME(PabloBlock * pb, const llvm::StringRef & prefix) : mPb(pb), mPrefix(prefix) {} \
     65private: \
     66    PabloBlock * mPb; \
     67    const llvm::StringRef & mPrefix; \
    6868}; \
    6969__##NAME functor(mPb, PREFIX); \
     
    8787        return mPb->NAME(arg1, arg2, arg3, mPrefix); \
    8888    } \
    89     inline __##NAME(PabloBlock * pb, const std::string & prefix) : mPb(pb), mPrefix(prefix) {} \
    90 private: \
    91     PabloBlock * mPb; \
    92     const std::string & mPrefix; \
     89    inline __##NAME(PabloBlock * pb, const llvm::StringRef & prefix) : mPb(pb), mPrefix(prefix) {} \
     90private: \
     91    PabloBlock * mPb; \
     92    const llvm::StringRef & mPrefix; \
    9393}; \
    9494__##NAME functor(mPb, PREFIX); \
     
    125125}
    126126
    127 PabloAST * PabloBuilder::createAdvance(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix) {
     127PabloAST * PabloBuilder::createAdvance(PabloAST * expr, PabloAST * shiftAmount, const llvm::StringRef & prefix) {
    128128    if (isa<Zeroes>(expr) || cast<Integer>(shiftAmount)->value() == 0) {
    129129        return expr;
     
    138138}
    139139
    140 Extract * PabloBuilder::createExtract(PabloAST * value, not_null<PabloAST *> index, const std::string & prefix) {
     140Extract * PabloBuilder::createExtract(PabloAST * value, not_null<PabloAST *> index, const llvm::StringRef & prefix) {
    141141    MAKE_NAMED_BINARY(createExtract, TypeId::Extract, prefix, value, index);
    142142    return cast<Extract>(result);
     
    151151}
    152152
    153 PabloAST * PabloBuilder::createLookahead(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix) {
     153PabloAST * PabloBuilder::createLookahead(PabloAST * expr, PabloAST * shiftAmount, const llvm::StringRef & prefix) {
    154154    if (isa<Zeroes>(expr) || cast<Integer>(shiftAmount)->value() == 0) {
    155155        return expr;
     
    173173}
    174174
    175 PabloAST * PabloBuilder::createNot(PabloAST * expr, const std::string & prefix) {
     175PabloAST * PabloBuilder::createNot(PabloAST * expr, const llvm::StringRef & prefix) {
    176176    if (isa<Ones>(expr)) {
    177177        return createZeroes(expr->getType());
     
    192192}
    193193
    194 PabloAST * PabloBuilder::createCount(PabloAST * expr, const std::string & prefix) {
     194PabloAST * PabloBuilder::createCount(PabloAST * expr, const llvm::StringRef & prefix) {
    195195    MAKE_NAMED_UNARY(createCount, TypeId::Count, prefix, expr);
    196196    return result;
     
    232232}
    233233
    234 PabloAST * PabloBuilder::createAnd(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
     234PabloAST * PabloBuilder::createAnd(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix) {
    235235    if (isa<Zeroes>(expr2) || isa<Ones>(expr1)) {
    236236        return expr2;
     
    310310}
    311311
    312 PabloAST * PabloBuilder::createOr(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
     312PabloAST * PabloBuilder::createOr(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix) {
    313313    if (isa<Zeroes>(expr1) || isa<Ones>(expr2)){
    314314        return expr2;
     
    380380}
    381381
    382 PabloAST * PabloBuilder::createXor(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
     382PabloAST * PabloBuilder::createXor(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix) {
    383383    if (expr1 == expr2) {
    384384        return createZeroes(expr1->getType());
     
    448448}
    449449
    450 PabloAST * PabloBuilder::createInFile(PabloAST * expr, const std::string & prefix) {
     450PabloAST * PabloBuilder::createInFile(PabloAST * expr, const llvm::StringRef & prefix) {
    451451    MAKE_NAMED_UNARY(createInFile, TypeId::InFile, prefix, expr);
    452452    return result;
     
    458458}
    459459
    460 PabloAST * PabloBuilder::createAtEOF(PabloAST * expr, const std::string & prefix) {
     460PabloAST * PabloBuilder::createAtEOF(PabloAST * expr, const llvm::StringRef & prefix) {
    461461    MAKE_NAMED_UNARY(createAtEOF, TypeId::AtEOF, prefix, expr);
    462462    return result;
     
    471471}
    472472
    473 PabloAST * PabloBuilder::createMatchStar(PabloAST * marker, PabloAST * charclass, const std::string & prefix) {
     473PabloAST * PabloBuilder::createMatchStar(PabloAST * marker, PabloAST * charclass, const llvm::StringRef & prefix) {
    474474    if (isa<Zeroes>(marker) || isa<Zeroes>(charclass)) {
    475475        return marker;
     
    487487}
    488488
    489 PabloAST * PabloBuilder::createScanThru(PabloAST * from, PabloAST * thru, const std::string & prefix) {
     489PabloAST * PabloBuilder::createScanThru(PabloAST * from, PabloAST * thru, const llvm::StringRef & prefix) {
    490490    if (isa<Zeroes>(from) || isa<Zeroes>(thru)) {
    491491        return from;
     
    520520}
    521521
    522 PabloAST * PabloBuilder::createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const std::string & prefix) {
     522PabloAST * PabloBuilder::createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const llvm::StringRef & prefix) {
    523523    if (isa<Ones>(condition)) {
    524524        return trueExpr;
  • icGREP/icgrep-devel/icgrep/pablo/builder.hpp

    r5267 r5283  
    6666    }
    6767
    68     inline Var * createVar(const std::string name, llvm::Type * const type = nullptr) {
     68    inline Var * createVar(const llvm::StringRef & name, llvm::Type * const type = nullptr) {
    6969        return createVar(makeName(name), type);
    7070    }
    7171
    72     inline Var * createVar(const std::string name, PabloAST * value) {
     72    inline Var * createVar(const llvm::StringRef & name, PabloAST * value) {
    7373        Var * var = createVar(name, value->getType());
    7474        createAssign(var, value);
     
    8686    }
    8787
    88     Extract * createExtract(PabloAST * value, not_null<PabloAST *> index, const std::string & prefix);
    89 
    90     inline Extract * createExtract(PabloAST * value, const int64_t index, const std::string & prefix) {
     88    Extract * createExtract(PabloAST * value, not_null<PabloAST *> index, const llvm::StringRef & prefix);
     89
     90    inline Extract * createExtract(PabloAST * value, const int64_t index, const llvm::StringRef & prefix) {
    9191        return createExtract(value, getInteger(index), prefix);
    9292    }
     
    9898    PabloAST * createAdvance(PabloAST * expr, PabloAST * shiftAmount);
    9999
    100     inline PabloAST * createAdvance(PabloAST * expr, const int64_t shiftAmount, const std::string & prefix) {
     100    inline PabloAST * createAdvance(PabloAST * expr, const int64_t shiftAmount, const llvm::StringRef & prefix) {
    101101        return createAdvance(expr, mPb->getInteger(shiftAmount), prefix);
    102102    }
    103103
    104     PabloAST * createAdvance(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix);
     104    PabloAST * createAdvance(PabloAST * expr, PabloAST * shiftAmount, const llvm::StringRef & prefix);
    105105
    106106    inline PabloAST * createLookahead(PabloAST * expr, const int64_t shiftAmount) {
     
    113113    PabloAST * createLookahead(PabloAST * expr, PabloAST * shiftAmount);
    114114
    115     inline PabloAST * createLookahead(PabloAST * expr, const int64_t shiftAmount, const std::string & prefix) {
     115    inline PabloAST * createLookahead(PabloAST * expr, const int64_t shiftAmount, const llvm::StringRef & prefix) {
    116116        if (shiftAmount == 0) {
    117117            return expr;
     
    120120    }
    121121
    122     PabloAST * createLookahead(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix);
     122    PabloAST * createLookahead(PabloAST * expr, PabloAST * shiftAmount, const llvm::StringRef & prefix);
    123123
    124124    PabloAST * createAssign(PabloAST * const variable, PabloAST * const value);
     
    126126    PabloAST * createAnd(PabloAST * expr1, PabloAST * expr2);
    127127
    128     PabloAST * createAnd(PabloAST * expr1, PabloAST * expr2, const std::string & prefix);
     128    PabloAST * createAnd(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix);
    129129
    130130    PabloAST * createNot(PabloAST * expr);
    131131
    132     PabloAST * createNot(PabloAST * expr, const std::string & prefix);
     132    PabloAST * createNot(PabloAST * expr, const llvm::StringRef & prefix);
    133133
    134134    PabloAST * createOr(PabloAST * expr1, PabloAST * expr2);
    135135
    136     PabloAST * createOr(PabloAST * expr1, PabloAST * expr2, const std::string & prefix);
     136    PabloAST * createOr(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix);
    137137
    138138    PabloAST * createXor(PabloAST * expr1, PabloAST * expr2);
    139139
    140     PabloAST * createXor(PabloAST * expr1, PabloAST * expr2, const std::string & prefix);
     140    PabloAST * createXor(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix);
    141141
    142142    PabloAST * createMatchStar(PabloAST * marker, PabloAST * charclass);
    143143
    144     PabloAST * createMatchStar(PabloAST * marker, PabloAST * charclass, const std::string & prefix);
     144    PabloAST * createMatchStar(PabloAST * marker, PabloAST * charclass, const llvm::StringRef & prefix);
    145145
    146146    PabloAST * createScanThru(PabloAST * from, PabloAST * thru);
    147147
    148     PabloAST * createScanThru(PabloAST * from, PabloAST * thru, const std::string & prefix);
     148    PabloAST * createScanThru(PabloAST * from, PabloAST * thru, const llvm::StringRef & prefix);
    149149
    150150    PabloAST * createScanTo(PabloAST * from, PabloAST * to) {
     
    152152    }
    153153
    154     PabloAST * createScanTo(PabloAST * from, PabloAST * to, const std::string & prefix) {
     154    PabloAST * createScanTo(PabloAST * from, PabloAST * to, const llvm::StringRef & prefix) {
    155155        return createScanThru(from, createNot(to), prefix);
    156156    }
     
    158158    PabloAST * createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr);
    159159
    160     PabloAST * createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const std::string & prefix);
     160    PabloAST * createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const llvm::StringRef & prefix);
    161161
    162162    PabloAST * createCount(PabloAST * expr);
    163163   
    164     PabloAST * createCount(PabloAST * expr, const std::string & prefix);
     164    PabloAST * createCount(PabloAST * expr, const llvm::StringRef & prefix);
    165165
    166166    PabloAST * createInFile(PabloAST * expr);
    167167   
    168     PabloAST * createInFile(PabloAST * expr, const std::string & prefix);
     168    PabloAST * createInFile(PabloAST * expr, const llvm::StringRef & prefix);
    169169   
    170170    PabloAST * createAtEOF(PabloAST * expr);
    171171   
    172     PabloAST * createAtEOF(PabloAST * expr, const std::string & prefix);
     172    PabloAST * createAtEOF(PabloAST * expr, const llvm::StringRef & prefix);
    173173   
    174174    PabloAST * createAdd(PabloAST * expr1, PabloAST * expr2);
     
    248248    }
    249249
    250     inline String * getName(const std::string & name) const {
     250    inline String * getName(const llvm::StringRef & name) const {
    251251        return mPb->getName(name);
    252252    }
    253253
    254     inline String * makeName(const std::string & prefix) const {
     254    inline String * makeName(const llvm::StringRef & prefix) const {
    255255        return mPb->makeName(prefix);
    256256    }
  • icGREP/icgrep-devel/icgrep/pablo/codegenstate.cpp

    r5270 r5283  
    5858}
    5959
    60 Count * PabloBlock::createCount(PabloAST * const expr, const std::string & prefix)  {
     60Count * PabloBlock::createCount(PabloAST * const expr, const llvm::StringRef & prefix)  {
    6161    Type * type = getParent()->getBuilder()->getSizeTy();
    6262    return insertAtInsertionPoint(new (mAllocator) Count(expr, makeName(prefix), type, mAllocator));
     
    7878        throw std::runtime_error("Var objects must have a String name");
    7979    }
    80     return mParent->makeVariable(name, type);
     80    return mParent->makeVariable(cast<String>(name), type);
    8181}
    8282
  • icGREP/icgrep-devel/icgrep/pablo/codegenstate.h

    r5267 r5283  
    6868    }
    6969
    70     Advance * createAdvance(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix) {
     70    Advance * createAdvance(PabloAST * expr, PabloAST * shiftAmount, const llvm::StringRef & prefix) {
    7171        return createAdvance(expr, shiftAmount, makeName(prefix));
    7272    }
     
    7878    }
    7979
    80     Lookahead * createLookahead(PabloAST * expr, PabloAST * shiftAmount, const std::string & prefix) {
     80    Lookahead * createLookahead(PabloAST * expr, PabloAST * shiftAmount, const llvm::StringRef & prefix) {
    8181        return createLookahead(expr, shiftAmount, makeName(prefix));
    8282    }
     
    9696    }
    9797
    98     Not * createNot(PabloAST * expr, const std::string & prefix) {
     98    Not * createNot(PabloAST * expr, const llvm::StringRef & prefix) {
    9999        return createNot(expr, makeName(prefix));
    100100    }
     
    102102    Not * createNot(PabloAST * expr, String * name);
    103103
    104     inline Var * createVar(const std::string & name, llvm::Type * const type = nullptr) {
     104    inline Var * createVar(const llvm::StringRef & name, llvm::Type * const type = nullptr) {
    105105        return createVar(makeName(name), type);
    106106    }
     
    112112    Count * createCount(PabloAST * expr);
    113113
    114     Count * createCount(PabloAST * expr, const std::string & prefix);
     114    Count * createCount(PabloAST * expr, const llvm::StringRef & prefix);
    115115
    116116    InFile * createInFile(PabloAST * expr) {
     
    118118    }
    119119
    120     InFile * createInFile(PabloAST * expr, const std::string & prefix) {
     120    InFile * createInFile(PabloAST * expr, const llvm::StringRef & prefix) {
    121121        return createInFile(expr, makeName(prefix));
    122122    }
     
    128128    }
    129129
    130     AtEOF * createAtEOF(PabloAST * expr, const std::string & prefix) {
     130    AtEOF * createAtEOF(PabloAST * expr, const llvm::StringRef & prefix) {
    131131        return createAtEOF(expr, makeName(prefix));
    132132    }
     
    138138    }
    139139
    140     Extract * createExtract(PabloAST * array, PabloAST * index, const std::string & prefix) {
     140    Extract * createExtract(PabloAST * array, PabloAST * index, const llvm::StringRef & prefix) {
    141141        return createExtract(array, index, makeName(prefix));
    142142    }
     
    146146    }
    147147
    148     Extract * createExtract(PabloAST * array, const int64_t index, const std::string & prefix) {
     148    Extract * createExtract(PabloAST * array, const int64_t index, const llvm::StringRef & prefix) {
    149149        return createExtract(array, getInteger(index), makeName(prefix));
    150150    }
     
    158158    }
    159159
    160     And * createAnd(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
     160    And * createAnd(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix) {
    161161        return createAnd(expr1, expr2, makeName(prefix));
    162162    }
     
    174174    }
    175175
    176     Or * createOr(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
     176    Or * createOr(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix) {
    177177        return createOr(expr1, expr2, makeName(prefix));
    178178    }
     
    190190    }
    191191
    192     Xor * createXor(PabloAST * expr1, PabloAST * expr2, const std::string & prefix) {
     192    Xor * createXor(PabloAST * expr1, PabloAST * expr2, const llvm::StringRef & prefix) {
    193193        return createXor(expr1, expr2, makeName(prefix));
    194194    }
     
    206206    }
    207207
    208     Sel * createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const std::string & prefix) {
     208    Sel * createSel(PabloAST * condition, PabloAST * trueExpr, PabloAST * falseExpr, const llvm::StringRef & prefix) {
    209209        return createSel(condition, trueExpr, falseExpr, makeName(prefix));
    210210    }
     
    222222    }
    223223
    224     MatchStar * createMatchStar(PabloAST * marker, PabloAST * charclass, const std::string & prefix) {
     224    MatchStar * createMatchStar(PabloAST * marker, PabloAST * charclass, const llvm::StringRef & prefix) {
    225225        return createMatchStar(marker, charclass, makeName(prefix));
    226226    }
     
    232232    }
    233233
    234     ScanThru * createScanThru(PabloAST * from, PabloAST * thru, const std::string & prefix) {
     234    ScanThru * createScanThru(PabloAST * from, PabloAST * thru, const llvm::StringRef & prefix) {
    235235        return createScanThru(from, thru, makeName(prefix));
    236236    }
     
    276276    }
    277277
    278     inline String * getName(const std::string & name) const {
     278    inline String * getName(const llvm::StringRef & name) const {
    279279        return mParent->getName(name);
    280280    }
    281281
    282     inline String * makeName(const std::string & prefix) const {
     282    inline String * makeName(const llvm::StringRef & prefix) const {
    283283        return mParent->makeName(prefix);
    284284    }
     
    295295
    296296    explicit PabloBlock(PabloKernel * const parent, Allocator & allocator) noexcept
    297     : PabloAST(PabloAST::ClassTypeId::Block, nullptr, nullptr, allocator)
     297    : PabloAST(PabloAST::ClassTypeId::Block, nullptr, allocator)
    298298    , mParent(parent)
    299299    , mBranch(nullptr)
  • icGREP/icgrep-devel/icgrep/pablo/optimizers/codemotionpass.cpp

    r5271 r5283  
    6060 * @brief findLCA
    6161 ** ------------------------------------------------------------------------------------------------------------- */
    62 inline PabloBlock * findLCA(PabloBlock * scope1, PabloBlock * scope2) {
     62inline PabloBlock * getLCA(PabloBlock * scope1, PabloBlock * scope2) {
    6363    int depth1 = depthOf(scope1);
    6464    int depth2 = depthOf(scope2);
     
    8686 * @brief ScopeSet
    8787 ** ------------------------------------------------------------------------------------------------------------- */
    88 struct ScopeSet : public std::vector<PabloBlock *> {
    89     inline void insert(PabloBlock * block) {
    90         const auto i = std::lower_bound(begin(), end(), block);
    91         if (i == end() || *i != block) {
    92             std::vector<PabloBlock *>::insert(i, block);
    93         }
     88template <typename T>
     89struct SetQueue : public std::vector<T> {
     90    inline void insert(T const item) {
     91        const auto i = std::lower_bound(std::vector<T>::begin(), std::vector<T>::end(), item);
     92        if (i == std::vector<T>::end() || *i != item) {
     93            std::vector<T>::insert(i, item);
     94        }
     95    }
     96    inline bool count(T const item) const {
     97        const auto i = std::lower_bound(std::vector<T>::begin(), std::vector<T>::end(), item);
     98        return (i != std::vector<T>::end() && *i == item);
    9499    }
    95100};
    96101
    97 /** ------------------------------------------------------------------------------------------------------------- *
    98  * @brief findScopeUsages
    99  ** ------------------------------------------------------------------------------------------------------------- */
    100 inline void findUsageScopes(PabloAST * expr, ScopeSet & scopes) {
     102using ScopeSet = SetQueue<PabloBlock *>;
     103
     104using UserSet = SetQueue<Statement *>;
     105
     106/** ------------------------------------------------------------------------------------------------------------- *
     107 * @brief getScopesOfAllUsers
     108 ** ------------------------------------------------------------------------------------------------------------- */
     109inline void getScopesOfAllUsers(PabloAST * expr, ScopeSet & scopes) {
    101110    for (PabloAST * use : expr->users()) {
    102         scopes.insert(cast<Statement>(use)->getParent());
    103     }
    104 }
    105 
    106 /** ------------------------------------------------------------------------------------------------------------- *
    107  * @brief isAcceptableTarget
    108  ** ------------------------------------------------------------------------------------------------------------- */
    109 inline PabloBlock * isAcceptableTarget(Statement * stmt, ScopeSet & scopes, PabloBlock * const block) {
    110     // Scan through this statement's users to see if they're all in a nested scope. If so,
    111     // find the least common ancestor of the scope blocks. If it is not the current scope,
    112     // then we can sink the instruction.
     111        if (LLVM_LIKELY(isa<Statement>(use))) {
     112            scopes.insert(cast<Statement>(use)->getParent());
     113        } else if (LLVM_UNLIKELY(isa<PabloKernel>(use))) {
     114            scopes.insert(cast<PabloKernel>(use)->getEntryBlock());
     115        }
     116    }
     117}
     118
     119/** ------------------------------------------------------------------------------------------------------------- *
     120 * @brief getInScopeDominatorsOfAllUsers
     121 ** ------------------------------------------------------------------------------------------------------------- */
     122inline void getInScopeDominatorsOfAllUsers(PabloAST * expr, UserSet & users, PabloBlock * const block) {
     123    for (PabloAST * use : expr->users()) {
     124        if (LLVM_LIKELY(isa<Statement>(use))) {
     125            Statement * user = cast<Statement>(use);
     126            PabloBlock * parent = user->getParent();
     127            while (parent != block) {
     128                assert (parent);
     129                user = parent->getBranch();
     130                parent = parent->getPredecessor();
     131            }
     132            users.insert(user);
     133        }
     134    }
     135}
     136
     137/** ------------------------------------------------------------------------------------------------------------- *
     138 * @brief sinkIfAcceptableTarget
     139 *
     140 * Scan through this statement's users to see whether they're all in a nested scope. If not, check whether the
     141 * statement can be moved past a branch statement within the same scope.
     142 ** ------------------------------------------------------------------------------------------------------------- */
     143inline void sinkIfAcceptableTarget(Statement * const stmt, PabloBlock * const block, ScopeSet & scopes, UserSet & users) {
    113144    assert (scopes.empty());
    114     if (isa<Assign>(stmt)) {
    115         return nullptr;
    116     } else if (isa<Branch>(stmt)) {
     145    if (LLVM_UNLIKELY(isa<Branch>(stmt))) {
    117146        for (Var * def : cast<Branch>(stmt)->getEscaped()) {
    118             findUsageScopes(def, scopes);
     147            getScopesOfAllUsers(def, scopes);
    119148        }
    120149    } else {
    121         findUsageScopes(stmt, scopes);
    122     }
     150        getScopesOfAllUsers(isa<Assign>(stmt) ? cast<Assign>(stmt)->getVariable() : stmt, scopes);
     151    }   
    123152    if (LLVM_UNLIKELY(scopes.empty())) {
    124         return nullptr;
     153        assert (!isa<Assign>(stmt));
     154        // should not occur unless we have a branch with no escaped vars or a statement
     155        // that has no users. In either event, the statement itself should be removed.
     156        stmt->eraseFromParent(true);
     157        return;
    125158    }
    126159    while (scopes.size() > 1) {
    127160        PabloBlock * scope1 = scopes.back(); scopes.pop_back();
    128161        PabloBlock * scope2 = scopes.back(); scopes.pop_back();
    129         scopes.insert(findLCA(scope1, scope2));
    130     }
    131     // If the LCA scope is nested within the block, return the LCA scope.
    132     // Otherwise return nullptr.
     162        scopes.insert(getLCA(scope1, scope2));
     163    }
    133164    PabloBlock * const scope = scopes.back(); scopes.clear();
    134     if (scope == block) {
    135         return nullptr;
    136     }
    137     PabloBlock * temp = scope;
    138     for (;;) {
    139         temp = temp->getPredecessor();
    140         if (temp == nullptr) {
    141             return nullptr;
    142         } else if (temp == block) {
    143             return scope;
     165    if (LLVM_LIKELY(scope == block)) {
     166        assert (users.empty());
     167        if (LLVM_UNLIKELY(isa<Branch>(stmt))) {
     168            for (Var * def : cast<Branch>(stmt)->getEscaped()) {
     169                getInScopeDominatorsOfAllUsers(def, users, block);
     170            }
     171        } else {
     172            getInScopeDominatorsOfAllUsers(isa<Assign>(stmt) ? cast<Assign>(stmt)->getVariable() : stmt, users, block);
     173        }
     174        Branch * branch = nullptr;
     175        Statement * temp = stmt;
     176        for (;;) {
     177            temp = temp->getNextNode();
     178            if (temp == nullptr || users.count(temp)) {
     179                if (branch) {
     180                    // we can move the statement past a branch within its current scope
     181                    stmt->insertAfter(branch);
     182                }
     183                break;
     184            }
     185            if (isa<Branch>(temp)) {
     186                branch = cast<Branch>(temp);
     187            }
     188        }
     189        users.clear();
     190    } else { // test whether the LCA scope is nested within this scope.
     191        PabloBlock * temp = scope;
     192        for (;;) {
     193            temp = temp->getPredecessor();
     194            if (temp == nullptr) {
     195                break;
     196            } else if (temp == block) {
     197                // we can move the statement into a nested scope
     198                stmt->insertBefore(scope->front());
     199                break;
     200            }
    144201        }
    145202    }
     
    151208inline void CodeMotionPass::sink(PabloBlock * const block) {
    152209    ScopeSet scopes;
     210    UserSet users;
    153211    Statement * stmt = block->back(); // note: reverse AST traversal
    154212    while (stmt) {
    155213        Statement * prevNode = stmt->getPrevNode();
    156         if (PabloBlock * scope = isAcceptableTarget(stmt, scopes, block)) {
    157             stmt->insertBefore(scope->front());
    158         }
     214        sinkIfAcceptableTarget(stmt, block, scopes, users);
    159215        stmt = prevNode;
    160216    }
     
    162218
    163219/** ------------------------------------------------------------------------------------------------------------- *
    164  * @brief hoistWhileLoopInvariants
     220 * @brief hoistLoopInvariants
    165221 ** ------------------------------------------------------------------------------------------------------------- */
    166222void CodeMotionPass::hoistLoopInvariants(While * loop) {
  • icGREP/icgrep-devel/icgrep/pablo/pabloAST.cpp

    r5270 r5283  
    232232    Statement * next = mNext;
    233233    if (LLVM_LIKELY(mParent != nullptr)) {
     234
     235
     236
    234237        if (LLVM_UNLIKELY(mParent->mFirst == this)) {
    235238            mParent->mFirst = mNext;
     
    300303    replaceAllUsesWith(expr);
    301304    return eraseFromParent(recursively);
     305}
     306
     307/** ------------------------------------------------------------------------------------------------------------- *
     308 * @brief setName
     309 ** ------------------------------------------------------------------------------------------------------------- */
     310void Statement::setName(const String * const name) noexcept {
     311    if (LLVM_UNLIKELY(name == nullptr)) {
     312        llvm::report_fatal_error("Statement name cannot be null!");
     313    }
     314    mName = name;
    302315}
    303316
  • icGREP/icgrep-devel/icgrep/pablo/pabloAST.h

    r5267 r5283  
    5656        , String
    5757        , Block
     58        , Kernel
    5859        // Arithmetic expressions
    5960        , Add
     
    102103    }
    103104
    104     inline const String * getName() const noexcept {
    105         return mName;
    106     }
    107 
    108     inline void setName(const String * const name) noexcept {
    109         mName = name;
    110     }
    111 
    112105    inline user_iterator user_begin() {
    113106        return mUsers.begin();
     
    151144
    152145protected:
    153     inline PabloAST(const ClassTypeId id, llvm::Type * const type, const String * name, Allocator & allocator)
     146    inline PabloAST(const ClassTypeId id, llvm::Type * const type, Allocator & allocator)
    154147    : mClassTypeId(id)
    155148    , mType(type)
    156     , mName(name)
    157149    , mUsers(allocator) {
    158150
     
    166158    const ClassTypeId       mClassTypeId;
    167159    llvm::Type *            mType;
    168     const String *          mName;
    169160    Users                   mUsers;
    170161};
     
    199190    void replaceUsesOfWith(PabloAST * const from, PabloAST * const to);
    200191
     192    const String & getName() const noexcept {
     193        return *mName;
     194    }
     195
     196    void setName(const String * const name) noexcept;
     197
    201198    inline PabloAST * getOperand(const unsigned index) const {
    202199        assert (index < getNumOperands());
     
    227224    virtual ~Statement() {}
    228225protected:
     226
    229227    explicit Statement(const ClassTypeId id, llvm::Type * const type, std::initializer_list<PabloAST *> operands, const String * const name, Allocator & allocator)
    230     : PabloAST(id, type, name, allocator)
     228    : PabloAST(id, type, allocator)
     229    , mOperands(operands.size())
     230    , mOperand(allocator.allocate(mOperands))
    231231    , mNext(nullptr)
    232232    , mPrev(nullptr)
    233     , mParent(nullptr)
    234     , mOperands(operands.size())
    235     , mOperand(allocator.allocate(mOperands)) {
     233    , mName(name)
     234    , mParent(nullptr) {
    236235        unsigned i = 0;
    237236        for (PabloAST * const value : operands) {
     
    242241        }
    243242    }
     243
    244244    explicit Statement(const ClassTypeId id, llvm::Type * const type, const unsigned reserved, const String * const name, Allocator & allocator)
    245     : PabloAST(id, type, name, allocator)
     245    : PabloAST(id, type, allocator)
     246    , mOperands(0)
     247    , mOperand(allocator.allocate(mOperands))
    246248    , mNext(nullptr)
    247249    , mPrev(nullptr)
    248     , mParent(nullptr)
    249     , mOperands(0)
    250     , mOperand(allocator.allocate(mOperands)) {
     250    , mName(name)
     251    , mParent(nullptr) {
    251252        std::memset(mOperand, 0, reserved * sizeof(PabloAST *));
    252253    }
     254
    253255    template<typename iterator>
    254256    explicit Statement(const ClassTypeId id, llvm::Type * const type, iterator begin, iterator end, const String * const name, Allocator & allocator)
    255     : PabloAST(id, type, name, allocator)
     257    : PabloAST(id, type, allocator)
     258    , mOperands(std::distance(begin, end))
     259    , mOperand(allocator.allocate(mOperands))
    256260    , mNext(nullptr)
    257261    , mPrev(nullptr)
    258     , mParent(nullptr)
    259     , mOperands(std::distance(begin, end))
    260     , mOperand(allocator.allocate(mOperands)) {
     262    , mName(name)
     263    , mParent(nullptr) {
    261264        unsigned i = 0;
    262265        for (auto value = begin; value != end; ++value, ++i) {
     
    266269        }
    267270    }
     271
    268272protected:   
     273    unsigned        mOperands;
     274    PabloAST **     mOperand;
    269275    Statement *     mNext;
    270276    Statement *     mPrev;
     277    const String *  mName;
    271278    PabloBlock *    mParent;
    272     unsigned        mOperands;
    273     PabloAST **     mOperand;
    274279};
    275280
  • icGREP/icgrep-devel/icgrep/pablo/pablo_compiler.cpp

    r5270 r5283  
    3535using TypeId = PabloAST::ClassTypeId;
    3636
     37inline static unsigned getAlignment(const Value * const ptr) {
     38    return ptr->getType()->getPrimitiveSizeInBits() / 8;
     39}
     40
     41inline static unsigned getPointerElementAlignment(const Value * const ptr) {
     42    return ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits() / 8;
     43}
     44
    3745void PabloCompiler::initializeKernelData() {
    3846    Examine();
     
    5260     
    5361    PabloBlock * const entryBlock = mKernel->getEntryBlock(); assert (entryBlock);
    54     mMarkerMap.emplace(entryBlock->createZeroes(), iBuilder->allZeroes());
    55     mMarkerMap.emplace(entryBlock->createOnes(), iBuilder->allOnes());
     62    mMarker.emplace(entryBlock->createZeroes(), iBuilder->allZeroes());
     63    mMarker.emplace(entryBlock->createOnes(), iBuilder->allOnes());
    5664
    5765    Value * const blockNo = mKernel->getScalarField(mSelf, blockNoScalar);
     
    5967    for (unsigned i = 0; i < mKernel->getNumOfInputs(); ++i) {
    6068        Var * var = mKernel->getInput(i);
    61         std::string name = var->getName()->to_string();
     69        std::string name = var->getName().str();
    6270        Value * input = nullptr;
    6371        if (var->getType()->isSingleValueType()) {
     
    6674            input = mKernel->getStreamSetPtr(mSelf, name, blockNo);
    6775        }
    68         mMarkerMap.emplace(var, input);
     76        mMarker.emplace(var, input);
    6977    }
    7078
    7179    for (unsigned i = 0; i < mKernel->getNumOfOutputs(); ++i) {
    7280        Var * var = mKernel->getOutput(i);
    73         std::string name = var->getName()->to_string();
     81        std::string name = var->getName().str();
    7482        Value * output = nullptr;
    7583        if (var->getType()->isSingleValueType()) {
     
    7886            output = mKernel->getStreamSetPtr(mSelf, name, blockNo);
    7987        }
    80         mMarkerMap.emplace(var, output);
     88        mMarker.emplace(var, output);
    8189    }
    8290
    8391    compileBlock(entryBlock);
    8492
    85     #ifdef PRINT_TIMING_INFORMATION
    86     const timestamp_t pablo_compilation_end = read_cycle_counter();
    87     std::cerr << "PABLO COMPILATION TIME: " << (pablo_compilation_end - pablo_compilation_start) << std::endl;
    88     #endif
    8993}
    9094
     
    103107        } else if (LLVM_UNLIKELY(isa<Branch>(stmt))) {
    104108            Examine(cast<Branch>(stmt)->getBody());
     109        } else if (LLVM_UNLIKELY(isa<Count>(stmt))) {
     110            mAccumulator.insert(std::make_pair(stmt, iBuilder->getInt32(mKernel->addUnnamedScalar(stmt->getType()))));
    105111        }
    106112    }   
     
    111117        compileStatement(statement);
    112118    }
    113 }
    114 
    115 static const llvm::StringRef EmptyString;
    116 
    117 inline const llvm::StringRef & getName(const PabloAST * expr) {
    118     if (expr->getName()) {
    119         return expr->getName()->value();
    120     }
    121     return EmptyString;
    122119}
    123120
     
    148145
    149146    for (const Var * var : ifStatement->getEscaped()) {
    150         auto f = mMarkerMap.find(var);
    151         if (LLVM_UNLIKELY(f == mMarkerMap.end())) {
     147        auto f = mMarker.find(var);
     148        if (LLVM_UNLIKELY(f == mMarker.end())) {
    152149            std::string tmp;
    153150            raw_string_ostream out(tmp);
     
    189186
    190187    for (const auto i : incoming) {
    191         const Var * var; Value * value;
    192         std::tie(var, value) = i;
    193 
    194         auto f = mMarkerMap.find(var);
    195         if (LLVM_UNLIKELY(f == mMarkerMap.end() || f->second == value)) {
     188        const Var * var; Value * incoming;
     189        std::tie(var, incoming) = i;
     190
     191        auto f = mMarker.find(var);
     192        if (LLVM_UNLIKELY(f == mMarker.end())) {
    196193            std::string tmp;
    197194            raw_string_ostream out(tmp);
     195            out << "PHINode creation error: ";
    198196            var->print(out);
    199             out << " was not assigned a value.";
     197            out << " was not assigned an outgoing value.";
    200198            llvm::report_fatal_error(out.str());
    201199        }
    202200
    203         Value * const next = f->second;
    204 
    205         assert (value->getType() == next->getType());
    206 
    207         PHINode * phi = iBuilder->CreatePHI(value->getType(), 2, getName(var));
    208         phi->addIncoming(value, ifEntryBlock);
    209         phi->addIncoming(next, ifExitBlock);
     201        Value * const outgoing = f->second;
     202        if (LLVM_UNLIKELY(incoming == outgoing)) {
     203            continue;
     204        }
     205
     206        if (LLVM_UNLIKELY(incoming->getType() != outgoing->getType())) {
     207            std::string tmp;
     208            raw_string_ostream out(tmp);
     209            out << "PHINode creation error: incoming type of ";
     210            var->print(out);
     211            out << " (";
     212            incoming->getType()->print(out);
     213            out << ") differs from the outgoing type (";
     214            outgoing->getType()->print(out);
     215            out << ") within ";
     216            ifStatement->print(out);
     217            llvm::report_fatal_error(out.str());
     218        }
     219
     220        PHINode * phi = iBuilder->CreatePHI(incoming->getType(), 2, var->getName());
     221        phi->addIncoming(incoming, ifEntryBlock);
     222        phi->addIncoming(outgoing, ifExitBlock);
    210223        f->second = phi;
    211 
    212         assert (mMarkerMap[var] == phi);
    213224    }   
    214225}
     
    252263    // for any Next nodes in the loop body, initialize to (a) pre-loop value.
    253264    for (const auto var : escaped) {
    254         auto f = mMarkerMap.find(var);
    255         if (LLVM_UNLIKELY(f == mMarkerMap.end())) {
     265        auto f = mMarker.find(var);
     266        if (LLVM_UNLIKELY(f == mMarker.end())) {
    256267            std::string tmp;
    257268            raw_string_ostream out(tmp);
     269            out << "PHINode creation error: ";
    258270            var->print(out);
    259271            out << " is uninitialized prior to entering ";
     
    262274        }
    263275        Value * entryValue = f->second;
    264         PHINode * phi = iBuilder->CreatePHI(entryValue->getType(), 2, getName(var));
     276        PHINode * phi = iBuilder->CreatePHI(entryValue->getType(), 2, var->getName());
    265277        phi->addIncoming(entryValue, whileEntryBlock);
    266278        f->second = phi;
    267         assert(mMarkerMap[var] == phi);
     279        assert(mMarker[var] == phi);
    268280        variants.emplace_back(var, phi);
    269281    }
     
    302314    // and for any variant nodes in the loop body
    303315    for (const auto variant : variants) {
    304         const Var * var; PHINode * phi;
    305         std::tie(var, phi) = variant;
    306         const auto f = mMarkerMap.find(var);
    307         if (LLVM_UNLIKELY(f == mMarkerMap.end() || f->second == phi)) {
     316        const Var * var; PHINode * incomingPhi;
     317        std::tie(var, incomingPhi) = variant;
     318        const auto f = mMarker.find(var);
     319        if (LLVM_UNLIKELY(f == mMarker.end())) {
    308320            std::string tmp;
    309321            raw_string_ostream out(tmp);
     322            out << "PHINode creation error: ";
    310323            var->print(out);
    311             out << " was not assigned a value.";
     324            out << " is no longer assigned a value.";
    312325            llvm::report_fatal_error(out.str());
    313326        }
    314         Value * exitValue = f->second;
    315         assert (phi->getType() == exitValue->getType());
    316         phi->addIncoming(exitValue, whileExitBlock);
    317         f->second = phi;
     327
     328        Value * const outgoingValue = f->second;
     329
     330        if (LLVM_UNLIKELY(incomingPhi->getType() != outgoingValue->getType())) {
     331            std::string tmp;
     332            raw_string_ostream out(tmp);
     333            out << "PHINode creation error: incoming type of ";
     334            var->print(out);
     335            out << " (";
     336            incomingPhi->getType()->print(out);
     337            out << ") differs from the outgoing type (";
     338            outgoingValue->getType()->print(out);
     339            out << ") within ";
     340            whileStatement->print(out);
     341            llvm::report_fatal_error(out.str());
     342        }
     343
     344        incomingPhi->addIncoming(outgoingValue, whileExitBlock);
     345        f->second = incomingPhi;
    318346    }
    319347
     
    351379
    352380            if (LLVM_UNLIKELY(storeInstRequired || isa<Extract>(expr))) {
    353                 const auto f = mMarkerMap.find(expr);
    354                 if (LLVM_UNLIKELY(f == mMarkerMap.end())) {
     381                const auto f = mMarker.find(expr);
     382                if (LLVM_UNLIKELY(f == mMarker.end())) {
    355383                    std::string tmp;
    356384                    raw_string_ostream out(tmp);
     
    362390                }
    363391                Value * const ptr = f->second;
    364 
    365                 assert (&(value->getContext()) == &(ptr->getContext()));
    366 
    367                 if (isa<Count>(cast<Assign>(stmt)->getValue())) {
    368                     Value * count = iBuilder->CreateLoad(ptr);
    369                     value = iBuilder->CreateTruncOrBitCast(value, count->getType());
    370                     value = iBuilder->CreateAdd(value, count);
    371                 }
    372 
    373                 const Type * const type = value->getType();
    374                 if (isa<VectorType>(type) || isa<IntegerType>(type)) {
    375                     const auto bitWidth = isa<VectorType>(type)
    376                             ? cast<VectorType>(type)->getBitWidth()
    377                             : cast<IntegerType>(type)->getBitWidth();
    378                     iBuilder->CreateAlignedStore(value, ptr, bitWidth / 8);
    379                 } else {
    380                     iBuilder->CreateStore(value, ptr);
    381                 }
     392                iBuilder->CreateAlignedStore(value, ptr, getAlignment(value));
     393                value = ptr;
    382394            }
    383395
     
    385397            Value * array = compileExpression(extract->getArray(), false);
    386398            Value * index = compileExpression(extract->getIndex());
    387             value = iBuilder->CreateGEP(array, {ConstantInt::getNullValue(index->getType()), index}, getName(stmt));
     399            value = iBuilder->CreateGEP(array, {ConstantInt::getNullValue(index->getType()), index}, stmt->getName());
    388400        } else if (isa<And>(stmt)) {
    389401            value = compileExpression(stmt->getOperand(0));
     
    433445            Value * const to_count = compileExpression(c->getExpr());
    434446            const unsigned counterSize = iBuilder->getSizeTy()->getBitWidth();
     447            const auto f = mAccumulator.find(c);
     448            if (LLVM_UNLIKELY(f == mAccumulator.end())) {
     449                llvm::report_fatal_error("Unknown accumulator: " + c->getName().str());
     450            }
     451            Value * ptr = mKernel->getScalarFieldPtr(mSelf, f->second);
     452            Value * count = iBuilder->CreateAlignedLoad(ptr, getPointerElementAlignment(ptr));
    435453            Value * const partial = iBuilder->simd_popcount(counterSize, to_count);
    436454            if (LLVM_UNLIKELY(counterSize <= 1)) {
     
    444462                }
    445463            }
     464            value = iBuilder->CreateAdd(value, count);
     465            iBuilder->CreateStore(value, ptr);
     466
    446467        } else if (const Lookahead * l = dyn_cast<Lookahead>(stmt)) {
    447468            PabloAST * const var = l->getExpr();
     
    460481            const unsigned bit_shift = (l->getAmount() % iBuilder->getBitBlockWidth());
    461482            const unsigned block_shift = (l->getAmount() / iBuilder->getBitBlockWidth());
    462             std::string inputName = var->getName()->to_string();;
     483            std::string inputName = cast<Var>(var)->getName().str();
    463484            Value * blockNo = mKernel->getScalarField(mSelf, blockNoScalar);
    464485            Value * lookAhead_blockPtr  = mKernel->getStreamSetPtr(mSelf, inputName, iBuilder->CreateAdd(blockNo, iBuilder->getSize(block_shift)));
     
    491512        }
    492513
    493         mMarkerMap[expr] = value;
     514        mMarker[expr] = value;
    494515        if (DebugOptionIsSet(DumpTrace)) {
    495             assert (expr->getName());
     516            const String & name = isa<Var>(expr) ? cast<Var>(expr)->getName() : cast<Statement>(expr)->getName();
    496517            if (value->getType()->isVectorTy()) {
    497                 iBuilder->CallPrintRegister(expr->getName()->to_string(), value);
     518                iBuilder->CallPrintRegister(name.str(), value);
    498519            } else if (value->getType()->isIntegerTy()) {
    499                 iBuilder->CallPrintInt(expr->getName()->to_string(), value);
     520                iBuilder->CallPrintInt(name.str(), value);
    500521            }
    501522        }
     
    514535        Value * lh = compileExpression(op->getLH());
    515536        Value * rh = compileExpression(op->getRH());
    516         assert (lh->getType() == rh->getType());
     537        if (LLVM_UNLIKELY(lh->getType() != rh->getType())) {
     538            std::string tmp;
     539            raw_string_ostream out(tmp);
     540            out << "Operator creation error: left hand type of ";
     541            expr->print(out);
     542            out << " (";
     543            lh->getType()->print(out);
     544            out << ") differs from right hand type (";
     545            rh->getType()->print(out);
     546            out << ")";
     547            llvm::report_fatal_error(out.str());
     548        }
    517549        switch (op->getClassTypeId()) {
    518550            case TypeId::Add:
     
    532564            case TypeId::NotEquals:
    533565                return iBuilder->CreateICmpNE(lh, rh);
    534             default:
    535                 break;
     566            default: break;
    536567        }
    537568        std::string tmp;
     
    541572        llvm::report_fatal_error(out.str());
    542573    }
    543     const auto f = mMarkerMap.find(expr);
    544     if (LLVM_UNLIKELY(f == mMarkerMap.end())) {
     574    const auto f = mMarker.find(expr);
     575    if (LLVM_UNLIKELY(f == mMarker.end())) {
    545576        std::string tmp;
    546577        llvm::raw_string_ostream out(tmp);
     578        out << "Compilation error: ";
    547579        expr->print(out);
    548580        out << " was used before definition!";
    549         throw std::runtime_error(out.str());
     581        llvm::report_fatal_error(out.str());
    550582    }
    551583    Value * value = f->second;
    552584    if (LLVM_UNLIKELY(isa<GetElementPtrInst>(value) && ensureLoaded)) {
    553         value = iBuilder->CreateBlockAlignedLoad(value);
     585        value = iBuilder->CreateAlignedLoad(value, getPointerElementAlignment(value));
    554586    }
    555587    return value;
     
    558590PabloCompiler::PabloCompiler(PabloKernel * kernel)
    559591: iBuilder(kernel->getBuilder())
     592, mKernel(kernel)
    560593, mCarryManager(new CarryManager(iBuilder))
    561 , mKernel(kernel)
    562594, mFunction(nullptr) {
    563595
  • icGREP/icgrep-devel/icgrep/pablo/pablo_compiler.h

    r5267 r5283  
    2727
    2828    using IntSet = boost::container::flat_set<unsigned>;
    29     using MarkerMap = std::unordered_map<const PabloAST *, llvm::Value *>;
     29
     30    using TranslationMap = std::unordered_map<const PabloAST *, llvm::Value *>;
    3031
    3132public:
     
    5354private:
    5455
    55     IDISA::IDISA_Builder *  iBuilder;
    56     CarryManager *          mCarryManager;
    57     PabloKernel *           mKernel;
    58     llvm::Value *           mSelf;
    59     llvm::Function *        mFunction;
    60     MarkerMap               mMarkerMap;
    61     IntSet                  mInputStreamOffset;
     56    IDISA::IDISA_Builder * const    iBuilder;
     57    PabloKernel * const             mKernel;
     58    CarryManager * const            mCarryManager;
     59    llvm::Value *                   mSelf;
     60    llvm::Function *                mFunction;
     61    TranslationMap                  mMarker;
     62    TranslationMap                  mAccumulator;
     63    IntSet                          mInputStreamOffset;
    6264
    6365};
  • icGREP/icgrep-devel/icgrep/pablo/pablo_kernel.cpp

    r5270 r5283  
    2222
    2323Var * PabloKernel::addInput(const std::string & name, Type * const type) {
    24     Var * param = new (mAllocator) Var(mSymbolTable->make(name, iBuilder), type, mAllocator, true);
     24    Var * param = new (mAllocator) Var(mSymbolTable->makeString(name, iBuilder), type, mAllocator, Var::ReadOnly);
     25    param->addUser(this);
    2526    mInputs.push_back(param);
     27    mVariables.push_back(param);
    2628    if (isa<ArrayType>(type) || isa<StreamType>(type)) {
    2729        mStreamSetInputs.emplace_back(type, name);
     
    3436
    3537Var * PabloKernel::addOutput(const std::string & name, Type * const type) {
    36     Var * result = new (mAllocator) Var(mSymbolTable->make(name, iBuilder), type, mAllocator, false);
     38    Var * result = new (mAllocator) Var(mSymbolTable->makeString(name, iBuilder), type, mAllocator, Var::ReadNone);
     39    result->addUser(this);
    3740    mOutputs.push_back(result);
     41    mVariables.push_back(result);
    3842    if (isa<ArrayType>(type) || isa<StreamType>(type)) {
    3943        mStreamSetOutputs.emplace_back(type, name);
     
    4549}
    4650
    47 Var * PabloKernel::makeVariable(PabloAST * name, Type * const type) {
     51Var * PabloKernel::makeVariable(String * name, Type * const type) {
    4852    Var * const var = new (mAllocator) Var(name, type, mAllocator);
    4953    mVariables.push_back(var);
     
    8185void PabloKernel::prepareKernel() {
    8286    mPabloCompiler->initializeKernelData();
    83     KernelBuilder::prepareKernel();
     87    BlockOrientedKernel::prepareKernel();
    8488}
    8589
     
    124128
    125129PabloKernel::PabloKernel(IDISA::IDISA_Builder * builder, std::string kernelName)
    126 : KernelBuilder(builder, std::move(kernelName), {}, {}, {}, {}, {Binding{builder->getBitBlockType(), "EOFbit"}, Binding{builder->getBitBlockType(), "EOFmask"}})
     130: BlockOrientedKernel(builder, std::move(kernelName), {}, {}, {}, {}, {Binding{builder->getBitBlockType(), "EOFbit"}, Binding{builder->getBitBlockType(), "EOFmask"}})
     131, PabloAST(PabloAST::ClassTypeId::Kernel, nullptr, mAllocator)
    127132, mPabloCompiler(new PabloCompiler(this))
    128133, mSymbolTable(new SymbolGenerator(mAllocator))
    129134, mEntryBlock(PabloBlock::Create(this)) {
    130 setDoBlockUpdatesProducedItemCountsAttribute(false);
     135    setDoBlockUpdatesProducedItemCountsAttribute(false);
    131136}
    132137
  • icGREP/icgrep-devel/icgrep/pablo/pablo_kernel.h

    r5267 r5283  
    88
    99#include <kernels/kernel.h>
     10#include <pablo/pabloAST.h>
    1011#include <pablo/symbol_generator.h>
    1112#include <util/slab_allocator.h>
     13#include <llvm/ADT/StringRef.h>
     14
    1215namespace IDISA { class IDISA_Builder; }
    1316namespace llvm { class Type; }
    1417namespace pablo { class Integer; }
    1518namespace pablo { class Ones; }
    16 namespace pablo { class PabloAST; }
    1719namespace pablo { class PabloBlock; }
    1820namespace pablo { class PabloCompiler; }
     
    2325namespace pablo {
    2426
    25 class PabloKernel : public kernel::KernelBuilder {
     27class PabloKernel : public kernel::BlockOrientedKernel, public PabloAST {
    2628
    2729    friend class PabloCompiler;
     
    3335    using Allocator = SlabAllocator<PabloAST *>;
    3436
     37    static inline bool classof(const PabloAST * e) {
     38        return e->getClassTypeId()  == PabloAST::ClassTypeId::Kernel;
     39    }
     40    static inline bool classof(const PabloKernel *) {
     41        return true;
     42    }
     43    static inline bool classof(const void *) {
     44        return false;
     45    }
     46
    3547    PabloKernel(IDISA::IDISA_Builder * builder, std::string kernelName);
    36     // At present only population count accumulator are supported,
    37     // using the pablo.Count operation.
    3848   
    3949    virtual ~PabloKernel();
     
    8191    }
    8292
    83     Var * makeVariable(PabloAST * name, llvm::Type * const type);
     93    Var * makeVariable(String * name, llvm::Type * const type);
    8494
    8595    Var * getVariable(const unsigned index) {
     
    113123    virtual void generateFinalBlockMethod() const override;
    114124
    115     inline String * getName(const std::string & name) const {
    116         return mSymbolTable->get(name, iBuilder);
     125    inline String * getName(const llvm::StringRef & name) const {
     126        return mSymbolTable->getString(name, iBuilder);
    117127    }
    118128
    119     inline String * makeName(const std::string & prefix) const {
    120         return mSymbolTable->make(prefix, iBuilder);
     129    inline String * makeName(const llvm::StringRef & prefix) const {
     130        return mSymbolTable->makeString(prefix, iBuilder);
    121131    }
    122132
  • icGREP/icgrep-devel/icgrep/pablo/pe_integer.h

    r5267 r5283  
    1616    static inline bool classof(const void *) {
    1717        return false;
    18     }
    19     virtual ~Integer(){
    20 
    21     }
     18    }   
    2219    inline IntTy value() const {
    2320        return mValue;
    2421    }
     22    virtual ~Integer(){ }
    2523protected:
    2624    Integer(const IntTy value, llvm::Type * type, Allocator & allocator) noexcept
    27     : PabloAST(ClassTypeId::Integer, type, nullptr, allocator)
     25    : PabloAST(ClassTypeId::Integer, type, allocator)
    2826    , mValue(value)
    2927    {
  • icGREP/icgrep-devel/icgrep/pablo/pe_ones.h

    r5267 r5283  
    3232protected:
    3333    Ones(llvm::Type * const type, Allocator & allocator)
    34     : PabloAST(ClassTypeId::Ones, type, nullptr, allocator) {
     34    : PabloAST(ClassTypeId::Ones, type, allocator) {
    3535    }
    3636};
  • icGREP/icgrep-devel/icgrep/pablo/pe_string.h

    r5270 r5283  
    77namespace pablo {
    88
    9 class String : public PabloAST {
     9class String : public PabloAST, public llvm::StringRef {
    1010    friend class SymbolGenerator;
    1111public:
    12     using StringAllocator = SlabAllocator<char>;
    13 
    1412    static inline bool classof(const PabloAST * e) {
    1513        return e->getClassTypeId() == ClassTypeId::String;
     
    1715    static inline bool classof(const void *) {
    1816        return false;
    19     }
    20     virtual ~String(){
     17    }
     18    virtual ~String() { }
     19protected:
     20    String(llvm::Type * type, const llvm::StringRef & str, Allocator & allocator) noexcept
     21    : PabloAST(ClassTypeId::String, type,  allocator)
     22    , llvm::StringRef(str.data(), str.size()) {
    2123
    2224    }
    23     inline const llvm::StringRef & value() const {
    24         return mValue;
    25     }
    26     inline std::string to_string() const {
    27         return mValue.str();
    28     }
    29     inline llvm::StringRef value() {
    30         return mValue;
    31     }
    32 protected:
    33     String(llvm::Type * type, const std::string & value, Allocator & allocator) noexcept
    34     : PabloAST(ClassTypeId::String, type, this, allocator)
    35     , mValue(duplicate(value, allocator)) {
    36 
    37     }
    38 
    39     inline const char * duplicate(const std::string & value, Allocator & allocator) {
    40         char * string = reinterpret_cast<char*>(allocator.allocate<char*>(value.length() + 1));
    41         std::memcpy(string, value.c_str(), value.length());
    42         string[value.length()] = '\0';
    43         return string;
    44     }
    45 private:
    46     const llvm::StringRef mValue;
    4725};
    4826
  • icGREP/icgrep-devel/icgrep/pablo/pe_var.h

    r5267 r5283  
    1919    friend class Statement;
    2020public:
     21
     22    enum Attribute {
     23        None = 0
     24        , ReadOnly = 1
     25        , ReadNone = 2
     26    };
     27
    2128    static inline bool classof(const PabloAST * e) {
    2229        return e->getClassTypeId() == ClassTypeId::Var;
     
    2633    }
    2734    bool isReadOnly() const {
    28         return mReadOnly;
     35        return mAttribute & Attribute::ReadOnly;
    2936    }
    3037    void setReadOnly(const bool value = true) {
    31         mReadOnly = value;
     38        if (value) {
     39            mAttribute |= Attribute::ReadOnly;
     40        } else {
     41            mAttribute &= ~(Attribute::ReadOnly);
     42        }
    3243    }
     44    bool isReadNone() const {
     45        return mAttribute & Attribute::ReadNone;
     46    }
     47    void setReadNone(const bool value = true) {
     48        if (value) {
     49            mAttribute |= Attribute::ReadNone;
     50        } else {
     51            mAttribute &= ~(Attribute::ReadNone);
     52        }
     53    }
     54
     55    const String & getName() const noexcept {
     56        return *mName;
     57    }
     58
    3359protected:
    34     Var(const PabloAST * name, llvm::Type * const type, Allocator & allocator, const bool readOnly = false)
    35     : PabloAST(ClassTypeId::Var, type, llvm::cast<String>(name), allocator)
    36     , mReadOnly(readOnly) {
     60    Var(const String * name, llvm::Type * const type, Allocator & allocator, const Attribute attr = Attribute::None)
     61    : PabloAST(ClassTypeId::Var, type, allocator)
     62    , mAttribute(attr)
     63    , mName(name) {
    3764
    3865    }
    3966private:
    40     bool mReadOnly;
     67    unsigned mAttribute;
     68    const String * const mName;
    4169};
    4270
  • icGREP/icgrep-devel/icgrep/pablo/pe_zeroes.h

    r5267 r5283  
    3333protected:
    3434    Zeroes(llvm::Type * const type, Allocator & allocator)
    35     : PabloAST(ClassTypeId::Zeroes, type, nullptr, allocator) {
     35    : PabloAST(ClassTypeId::Zeroes, type, allocator) {
    3636    }
    3737};
  • icGREP/icgrep-devel/icgrep/pablo/printer_pablos.cpp

    r5270 r5283  
    4343        out << " = ";
    4444        print(assign->getValue(), out);
    45     } else if (const If * ifNode = dyn_cast<If>(stmt)) {
    46         out << "If ";
    47         print(ifNode->getCondition(), out);
     45    } else if (const Branch * br = dyn_cast<Branch>(stmt)) {
     46        if (isa<If>(br)) {
     47            out << "If ";
     48        } else if (isa<While>(br)) {
     49            out << "While ";
     50        }
     51        print(br->getCondition(), out);
    4852        if (expandNested) {
    4953            out << ":\n";
    50             print(ifNode->getBody(), out, true, indent + BlockIndenting);
    51         }
    52     } else if (const While * whileNode = dyn_cast<While>(stmt)) {
    53         out << "While ";
    54         print(whileNode->getCondition(), out);
    55         if (expandNested) {
    56             out << ":\n";
    57             print(whileNode->getBody(), out, true, indent + BlockIndenting);
     54            print(br->getBody(), out, true, indent + BlockIndenting);
    5855        }
    5956    } else {
     
    144141        out << "1";
    145142    } else if (const Var * var = dyn_cast<Var>(expr)) {
    146         out << var->getName()->value();
     143        out << var->getName();
    147144    } else if (const If * ifstmt = dyn_cast<If>(expr)) {
    148145        out << "If ";
     
    188185        print(op->getRH(), out);
    189186    } else if (const Statement * stmt = dyn_cast<Statement>(expr)) {
    190         out << stmt->getName()->value();
     187        out << stmt->getName();
    191188    } else if (isa<Integer>(expr)) {
    192189        out << cast<Integer>(expr)->value();
  • icGREP/icgrep-devel/icgrep/pablo/symbol_generator.cpp

    r5238 r5283  
    55 */
    66
    7 #include <pablo/symbol_generator.h>
     7#include "symbol_generator.h"
    88#include <pablo/pe_string.h>
    99#include <pablo/pe_integer.h>
     
    1212namespace pablo {
    1313
    14 String * SymbolGenerator::get(const std::string name, IDISA::IDISA_Builder * builder) {
    15     if (LLVM_UNLIKELY(name.length() == 0)) {
     14String * SymbolGenerator::makeString(const llvm::StringRef prefix, IDISA::IDISA_Builder * builder) noexcept {
     15    auto f = mPrefixMap.find(prefix);
     16    if (f == mPrefixMap.end()) {   
     17        return getString(prefix, builder);
     18    } else { // this string already exists; make a new string using the given prefix
     19
     20        // TODO: check FormatInt from "https://github.com/fmtlib/fmt/blob/master/fmt/format.h" for faster integer conversion
     21
     22        size_t count = f->second++;
     23        size_t length = prefix.size() + 2;
     24        size_t digits = 10;
     25        while (LLVM_UNLIKELY(digits <= count)) {
     26            digits *= 10;
     27            length += 1;
     28        }
     29        char name[length];
     30        std::memcpy(name, prefix.data(), prefix.size());
     31        char * p = name + length - 1;
     32        while (count) {
     33            *p-- = (count % 10) + '0';
     34            count /= 10;
     35        }
     36        *p = '_';
     37        return makeString(llvm::StringRef(name, length), builder);
     38    }
     39}
     40
     41String * SymbolGenerator::getString(const llvm::StringRef name, IDISA::IDISA_Builder * builder) noexcept {
     42    if (LLVM_UNLIKELY(name.size() == 0)) {
    1643        throw std::runtime_error("symbol name cannot be 0-length");
    1744    }
    18     auto f = mStringMap.find(name);
    19     String * result = nullptr;
    20     if (f == mStringMap.end()) {
    21         result = new (mAllocator) String(builder->getInt8PtrTy(), name, mAllocator);
    22         assert (result);
    23         mStringMap.insert(std::make_pair(std::move(name), result));
     45    const auto f = mStringMap.find(name);
     46    if (LLVM_LIKELY(f == mStringMap.end())) {
     47        assert ("prefix cannot exist for a non-existant key!" && (mPrefixMap.count(name) == 0));
     48        // create an internal copy of this name to prevent a temporary string from being added to the maps
     49        char * const data = mAllocator.allocate<char>(name.size() + 1);
     50        std::memcpy(data, name.data(), name.size());
     51        data[name.size()] = '\0';
     52        llvm::StringRef duplicate(data, name.size());
     53        mPrefixMap.insert(std::make_pair(duplicate, 1));
     54        String * result = new (mAllocator) String(builder->getInt8PtrTy(), duplicate, mAllocator); assert (result);
     55        mStringMap.insert(std::make_pair(duplicate, result));
     56        return result;
    2457    }
    25     else {
    26         result = f->second;
    27     }
    28     return result;
     58    assert ("prefix must exist for a known key!" && (mPrefixMap.count(name) != 0));
     59    return f->second;
    2960}
    3061
    31 Integer * SymbolGenerator::getInteger(const integer_t value, IDISA::IDISA_Builder * builder) {
     62Integer * SymbolGenerator::getInteger(const IntTy value, IDISA::IDISA_Builder * builder) noexcept {
    3263    auto f = mIntegerMap.find(value);
    3364    Integer * result;
     
    3566        result = new (mAllocator) Integer(value, builder->getSizeTy(), mAllocator);
    3667        assert (result->value() == value);
    37         mIntegerMap.insert(std::make_pair(value, result));
     68        mIntegerMap.emplace(std::make_pair(value, result));
    3869    } else {
    3970        result = f->second;
     
    4273}
    4374
    44 String * SymbolGenerator::make(const std::string prefix, IDISA::IDISA_Builder * builder) {
    45     auto f = mPrefixMap.find(prefix);
    46     if (f == mPrefixMap.end()) {
    47         mPrefixMap.insert(std::make_pair(prefix, 1));
    48         return get(prefix, builder);
    49     } else {
    50         const unsigned count = f->second++;
    51         return get(prefix + '_' + std::to_string(count), builder);
    52     }
    5375}
    54 
    55 }
  • icGREP/icgrep-devel/icgrep/pablo/symbol_generator.h

    r5267 r5283  
    99
    1010#include <pablo/pabloAST.h>
    11 #include <unordered_map>
    12 #include <string>
     11#include <llvm/ADT/StringMap.h>
     12#include <boost/container/flat_map.hpp>
    1313
    1414namespace IDISA { class IDISA_Builder; }
     
    1919
    2020class SymbolGenerator {
    21     friend class PabloBlock;
     21    friend class PabloKernel;
    2222    using Allocator = PabloAST::Allocator;
    2323public:
    24     typedef int64_t integer_t;
    25     String * get(const std::string name, IDISA::IDISA_Builder * builder);
    26     String * make(const std::string prefix, IDISA::IDISA_Builder *builder);
    27     Integer * getInteger(const integer_t value, IDISA::IDISA_Builder * builder);
    28     SymbolGenerator(Allocator & allocator) : mAllocator(allocator) {}
    29     ~SymbolGenerator() = default;
     24    using IntTy = int64_t;
     25    String * getString(const llvm::StringRef name, IDISA::IDISA_Builder * builder) noexcept;
     26    String * makeString(const llvm::StringRef prefix, IDISA::IDISA_Builder * builder) noexcept;
     27    Integer * getInteger(const IntTy value, IDISA::IDISA_Builder * builder) noexcept;
     28    ~SymbolGenerator() { }
     29protected:
     30    SymbolGenerator(Allocator & allocator) : mAllocator(allocator) { }
    3031private:
    31     Allocator &                                 mAllocator;
    32     std::unordered_map<std::string, integer_t>  mPrefixMap;
    33     std::unordered_map<std::string, String *>   mStringMap;
    34     std::unordered_map<integer_t, Integer *>    mIntegerMap;
     32    Allocator &                                  mAllocator;
     33    llvm::StringMap<IntTy>                       mPrefixMap;
     34    llvm::StringMap<String *>                    mStringMap;
     35    boost::container::flat_map<IntTy, Integer *> mIntegerMap;
    3536};
     37
    3638
    3739}
Note: See TracChangeset for help on using the changeset viewer.