source: icGREP/icgrep-devel/icgrep/kernels/kernel.cpp @ 5299

Last change on this file since 5299 was 5299, checked in by cameron, 2 years ago

Ability to set input/output signatures for Pablo functions in the constructor

File size: 23.7 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5
6#include "kernel.h"
7#include <toolchain.h>
8#include <kernels/streamset.h>
9#include <llvm/IR/Constants.h>
10#include <llvm/IR/Function.h>
11#include <llvm/IR/Instructions.h>
12#include <llvm/IR/Module.h>
13#include <llvm/Support/raw_ostream.h>
14
15static const auto BLOCK_NO_SCALAR = "blockNo";
16
17static const auto DO_BLOCK_SUFFIX = "_DoBlock";
18
19static const auto FINAL_BLOCK_SUFFIX = "_FinalBlock";
20
21static const auto LOGICAL_SEGMENT_NO_SCALAR = "logicalSegNo";
22
23static const auto PROCESSED_ITEM_COUNT_SUFFIX = "_processedItemCount";
24
25static const auto PRODUCED_ITEM_COUNT_SUFFIX = "_producedItemCount";
26
27static const auto TERMINATION_SIGNAL = "terminationSignal";
28
29static const auto BUFFER_PTR_SUFFIX = "_bufferPtr";
30
31static const auto BLOCK_MASK_SUFFIX = "_blkMask";
32
33using namespace llvm;
34using namespace kernel;
35using namespace parabix;
36
37unsigned KernelBuilder::addScalar(Type * const type, const std::string & name) {
38    if (LLVM_UNLIKELY(mKernelStateType != nullptr)) {
39        llvm::report_fatal_error("Cannot add kernel field " + name + " after kernel state finalized");
40    }
41    if (LLVM_UNLIKELY(mKernelMap.count(name))) {
42        llvm::report_fatal_error("Kernel already contains field " + name);
43    }
44    const auto index = mKernelFields.size();
45    mKernelMap.emplace(name, index);
46    mKernelFields.push_back(type);
47    return index;
48}
49
50unsigned KernelBuilder::addUnnamedScalar(Type * const type) {
51    if (LLVM_UNLIKELY(mKernelStateType != nullptr)) {
52        llvm::report_fatal_error("Cannot add unnamed kernel field after kernel state finalized");
53    }
54    const auto index = mKernelFields.size();
55    mKernelFields.push_back(type);
56    return index;
57}
58
59void KernelBuilder::prepareKernelSignature() {
60    unsigned blockSize = iBuilder->getBitBlockWidth();
61    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
62        mStreamSetNameMap.emplace(mStreamSetInputs[i].name, i);
63    }
64    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
65        mStreamSetNameMap.emplace(mStreamSetOutputs[i].name, mStreamSetInputs.size() + i);
66    }
67}
68   
69void KernelBuilder::prepareKernel() {
70    if (LLVM_UNLIKELY(mKernelStateType != nullptr)) {
71        llvm::report_fatal_error("Cannot prepare kernel after kernel state finalized");
72    }
73    if (mStreamSetInputs.size() != mStreamSetInputBuffers.size()) {
74        std::string tmp;
75        raw_string_ostream out(tmp);
76        out << "kernel contains " << mStreamSetInputBuffers.size() << " input buffers for "
77        << mStreamSetInputs.size() << " input stream sets.";
78        throw std::runtime_error(out.str());
79    }
80    if (mStreamSetOutputs.size() != mStreamSetOutputBuffers.size()) {
81        std::string tmp;
82        raw_string_ostream out(tmp);
83        out << "kernel contains " << mStreamSetOutputBuffers.size() << " output buffers for "
84        << mStreamSetOutputs.size() << " output stream sets.";
85        throw std::runtime_error(out.str());
86    }
87    unsigned blockSize = iBuilder->getBitBlockWidth();
88    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
89        if ((mStreamSetInputBuffers[i]->getBufferSize() > 0) && (mStreamSetInputBuffers[i]->getBufferSize() < codegen::SegmentSize + (blockSize + mLookAheadPositions - 1)/blockSize)) {
90            llvm::report_fatal_error("Kernel preparation: Buffer size too small " + mStreamSetInputs[i].name);
91        }
92        mScalarInputs.push_back(Binding{mStreamSetInputBuffers[i]->getPointerType(), mStreamSetInputs[i].name + BUFFER_PTR_SUFFIX});
93        addScalar(iBuilder->getSizeTy(), mStreamSetInputs[i].name + PROCESSED_ITEM_COUNT_SUFFIX);
94    }
95    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
96        mScalarInputs.push_back(Binding{mStreamSetOutputBuffers[i]->getPointerType(), mStreamSetOutputs[i].name + BUFFER_PTR_SUFFIX});
97        addScalar(iBuilder->getSizeTy(), mStreamSetOutputs[i].name + PRODUCED_ITEM_COUNT_SUFFIX);
98    }
99    for (auto binding : mScalarInputs) {
100        addScalar(binding.type, binding.name);
101    }
102    for (auto binding : mScalarOutputs) {
103        addScalar(binding.type, binding.name);
104    }
105    if (mStreamSetNameMap.empty()) prepareKernelSignature();
106    for (auto binding : mInternalScalars) {
107        addScalar(binding.type, binding.name);
108    }
109    addScalar(iBuilder->getSizeTy(), BLOCK_NO_SCALAR);
110    addScalar(iBuilder->getSizeTy(), LOGICAL_SEGMENT_NO_SCALAR);
111    addScalar(iBuilder->getInt1Ty(), TERMINATION_SIGNAL);
112    mKernelStateType = StructType::create(iBuilder->getContext(), mKernelFields, getName());
113}
114
115std::unique_ptr<Module> KernelBuilder::createKernelModule(const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
116    auto saveModule = iBuilder->getModule();
117    auto savePoint = iBuilder->saveIP();
118    auto module = make_unique<Module>(getName() + "_" + iBuilder->getBitBlockTypeName(), iBuilder->getContext());
119    iBuilder->setModule(module.get());
120    generateKernel(inputs, outputs);
121    iBuilder->setModule(saveModule);
122    iBuilder->restoreIP(savePoint);
123    return module;
124}
125
126void KernelBuilder::generateKernel(const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
127    auto savePoint = iBuilder->saveIP();
128    Module * const m = iBuilder->getModule();
129    mStreamSetInputBuffers.assign(inputs.begin(), inputs.end());
130    mStreamSetOutputBuffers.assign(outputs.begin(), outputs.end());
131    prepareKernel(); // possibly overridden by the KernelBuilder subtype
132    addKernelDeclarations(m);
133    callGenerateInitMethod();
134    generateInternalMethods();
135    callGenerateDoSegmentMethod();
136    // Implement the accumulator get functions
137    for (auto binding : mScalarOutputs) {
138        Function * f = getAccumulatorFunction(binding.name);
139        iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "get_" + binding.name, f));
140        Value * self = &*(f->arg_begin());
141        Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(binding.name)});
142        Value * retVal = iBuilder->CreateLoad(ptr);
143        iBuilder->CreateRet(retVal);
144    }
145    iBuilder->restoreIP(savePoint);
146}
147
148void KernelBuilder::callGenerateDoSegmentMethod() {
149    mCurrentFunction = getDoSegmentFunction();
150    iBuilder->SetInsertPoint(CreateBasicBlock(getName() + "_entry"));
151    auto args = mCurrentFunction->arg_begin();
152    mSelf = &*(args++);
153    Value * doFinal = &*(args++);
154    std::vector<Value *> producerPos;
155    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
156        producerPos.push_back(&*(args++));
157    }
158    assert (args == mCurrentFunction->arg_end());
159    generateDoSegmentMethod(doFinal, producerPos); // must be overridden by the KernelBuilder subtype
160    iBuilder->CreateRetVoid();
161}
162
163void KernelBuilder::callGenerateInitMethod() {
164    mCurrentFunction = getInitFunction();
165    iBuilder->SetInsertPoint(CreateBasicBlock("Init_entry"));
166    Function::arg_iterator args = mCurrentFunction->arg_begin();
167    mSelf = &*(args++);
168    iBuilder->CreateStore(ConstantAggregateZero::get(mKernelStateType), mSelf);
169    for (auto binding : mScalarInputs) {
170        Value * param = &*(args++);
171        Value * ptr = iBuilder->CreateGEP(mSelf, {iBuilder->getInt32(0), getScalarIndex(binding.name)});
172        iBuilder->CreateStore(param, ptr);
173    }
174    generateInitMethod();
175    iBuilder->CreateRetVoid();
176}
177
178ConstantInt * KernelBuilder::getScalarIndex(const std::string & name) const {
179    const auto f = mKernelMap.find(name);
180    if (LLVM_UNLIKELY(f == mKernelMap.end())) {
181        llvm::report_fatal_error("Kernel does not contain scalar: " + name);
182    }
183    return iBuilder->getInt32(f->second);
184}
185
186unsigned KernelBuilder::getScalarCount() const {
187    return mKernelFields.size();
188}
189
190Value * KernelBuilder::getScalarFieldPtr(llvm::Value * instance, Value * index) const {
191    return iBuilder->CreateGEP(instance, {iBuilder->getInt32(0), index});
192}
193
194Value * KernelBuilder::getScalarFieldPtr(llvm::Value * instance, const std::string & fieldName) const {
195    return getScalarFieldPtr(instance, getScalarIndex(fieldName));
196}
197
198Value * KernelBuilder::getScalarField(Value * instance, const std::string & fieldName) const {
199    return iBuilder->CreateLoad(getScalarFieldPtr(instance, fieldName));
200}
201
202Value * KernelBuilder::getScalarField(Value * instance, Value * index) const {
203    return iBuilder->CreateLoad(getScalarFieldPtr(instance, index));
204}
205
206void KernelBuilder::setScalarField(Value * instance, const std::string & fieldName, Value * value) const {
207    iBuilder->CreateStore(value, getScalarFieldPtr(instance, fieldName));
208}
209
210void KernelBuilder::setScalarField(Value * instance, Value * index, Value * value) const {
211    iBuilder->CreateStore(value, getScalarFieldPtr(instance, index));
212}
213
214Value * KernelBuilder::getProcessedItemCount(Value * instance, const std::string & name) const {
215    return getScalarField(instance, name + PROCESSED_ITEM_COUNT_SUFFIX);
216}
217
218Value * KernelBuilder::getProducedItemCount(Value * instance, const std::string & name) const {
219    return getScalarField(instance, name + PRODUCED_ITEM_COUNT_SUFFIX);
220}
221
222void KernelBuilder::setProcessedItemCount(Value * instance, const std::string & name, Value * value) const {
223    setScalarField(instance, name + PROCESSED_ITEM_COUNT_SUFFIX, value);
224}
225
226void KernelBuilder::setProducedItemCount(Value * instance, const std::string & name, Value * value) const {
227    setScalarField(instance, name + PRODUCED_ITEM_COUNT_SUFFIX, value);
228}
229
230Value * KernelBuilder::getTerminationSignal(Value * instance) const {
231    return getScalarField(instance, TERMINATION_SIGNAL);
232}
233
234void KernelBuilder::setTerminationSignal(Value * instance) const {
235    setScalarField(instance, TERMINATION_SIGNAL, iBuilder->getInt1(true));
236}
237
238LoadInst * KernelBuilder::acquireLogicalSegmentNo(llvm::Value * instance) const {
239    return iBuilder->CreateAtomicLoadAcquire(getScalarFieldPtr(instance, LOGICAL_SEGMENT_NO_SCALAR));
240}
241
242void KernelBuilder::releaseLogicalSegmentNo(Value * instance, Value * newCount) const {
243    iBuilder->CreateAtomicStoreRelease(newCount, getScalarFieldPtr(instance, LOGICAL_SEGMENT_NO_SCALAR));
244}
245
246Value * KernelBuilder::getBlockNo() const {
247    return getScalarField(mSelf, BLOCK_NO_SCALAR);
248}
249
250void KernelBuilder::setBlockNo(Value * value) const {
251    setScalarField(mSelf, BLOCK_NO_SCALAR, value);
252}
253
254llvm::Value * KernelBuilder::getInputStream(const std::string & name, llvm::Value * index) const {
255    Value * ic = getProcessedItemCount(name);
256    const StreamSetBuffer * buf = getStreamSetBuffer(name);
257    ic = iBuilder->CreateUDiv(ic, iBuilder->getSize(iBuilder->getBitBlockWidth()));
258    return buf->getStream(getStreamSetBufferPtr(name), ic, index);
259}
260
261llvm::Value * KernelBuilder::getInputStream(const std::string & name, llvm::Value * index1, llvm::Value * index2) const {
262    Value * ic = getProcessedItemCount(name);
263    const StreamSetBuffer * buf = getStreamSetBuffer(name);
264    ic = iBuilder->CreateUDiv(ic, iBuilder->getSize(iBuilder->getBitBlockWidth()));
265    return buf->getStream(getStreamSetBufferPtr(name), ic, index1, index2);
266}
267
268llvm::Value * KernelBuilder::getOutputStream(const std::string & name, llvm::Value * index) const {
269    Value * ic = getProducedItemCount(name);
270    const StreamSetBuffer * buf = getStreamSetBuffer(name);
271    ic = iBuilder->CreateUDiv(ic, iBuilder->getSize(iBuilder->getBitBlockWidth()));
272    return buf->getStream(getStreamSetBufferPtr(name), ic, index);
273}
274
275llvm::Value * KernelBuilder::getOutputStream(const std::string & name, llvm::Value * index1, llvm::Value * index2) const {
276    Value * ic = getProducedItemCount(name);
277    const StreamSetBuffer * buf = getStreamSetBuffer(name);
278    ic = iBuilder->CreateUDiv(ic, iBuilder->getSize(iBuilder->getBitBlockWidth()));
279    return buf->getStream(getStreamSetBufferPtr(name), ic, index1, index2);
280}
281
282Value * KernelBuilder::getStreamView(llvm::Type * type, const std::string & name, Value * blockNo, Value * index) const {
283    return getStreamSetBuffer(name)->getStreamView(type, getStreamSetBufferPtr(name), blockNo, index);
284}
285
286unsigned KernelBuilder::getStreamSetIndex(const std::string & name) const {
287    const auto f = mStreamSetNameMap.find(name);
288    if (LLVM_UNLIKELY(f == mStreamSetNameMap.end())) {
289        llvm::report_fatal_error("Kernel " + getName() + " does not contain stream set: " + name);
290    }
291    return f->second;
292}
293
294inline const StreamSetBuffer * KernelBuilder::getStreamSetBuffer(const std::string & name) const {
295    const unsigned structIdx = getStreamSetIndex(name);
296    if (structIdx < mStreamSetInputs.size()) {
297        return mStreamSetInputBuffers[structIdx];
298    } else {
299        return mStreamSetOutputBuffers[structIdx - mStreamSetInputs.size()];
300    }
301}
302
303inline Value * KernelBuilder::getStreamSetBufferPtr(const std::string & name) const {
304    return getScalarField(getSelf(), name + BUFFER_PTR_SUFFIX);
305}
306
307inline Value * KernelBuilder::getStreamSetBufferPtr(llvm::Value * index) const {
308    return getScalarField(getSelf(), index);
309}
310
311Argument * KernelBuilder::getParameter(Function * const f, const std::string & name) const {
312    for (auto & arg : f->getArgumentList()) {
313        if (arg.getName().equals(name)) {
314            return &arg;
315        }
316    }
317    llvm::report_fatal_error(f->getName() + " does not have parameter " + name);
318}
319
320Value * KernelBuilder::createDoSegmentCall(const std::vector<llvm::Value *> & args) const {
321    return iBuilder->CreateCall(getDoSegmentFunction(), args);
322}
323
324Value * KernelBuilder::createGetAccumulatorCall(Value * self, const std::string & accumName) const {
325    return iBuilder->CreateCall(getAccumulatorFunction(accumName), {self});
326}
327
328Value * KernelBuilder::getStreamSetPtr(const std::string & name, Value * blockNo) const {
329    return getStreamSetBuffer(name)->getStreamSetPtr(getStreamSetBufferPtr(name), blockNo);
330}
331
332BasicBlock * KernelBuilder::CreateBasicBlock(std::string && name) const {
333    return BasicBlock::Create(iBuilder->getContext(), name, mCurrentFunction);
334}
335
336void KernelBuilder::createInstance() {
337    if (LLVM_UNLIKELY(mKernelStateType == nullptr)) {
338        llvm::report_fatal_error("Cannot create kernel instance before calling prepareKernel()");
339    }
340    mKernelInstance = iBuilder->CreateCacheAlignedAlloca(mKernelStateType);
341    std::vector<Value *> init_args = {mKernelInstance};
342    for (auto a : mInitialArguments) {
343        init_args.push_back(a);
344    }
345    for (auto b : mStreamSetInputBuffers) {
346        init_args.push_back(b->getStreamSetBasePtr());
347    }
348    for (auto b : mStreamSetOutputBuffers) {
349        init_args.push_back(b->getStreamSetBasePtr());
350    }
351    Function * initMethod = getInitFunction();
352    iBuilder->CreateCall(initMethod, init_args);
353}
354
355//  The default finalBlock method simply dispatches to the doBlock routine.
356void BlockOrientedKernel::generateFinalBlockMethod(Value * remainingBytes) {
357//    std::vector<Value *> args = {self};
358//    for (Argument & arg : function->getArgumentList()){
359//        args.push_back(&arg);
360//    }
361    CreateDoBlockMethodCall();
362}
363
364//  The default doSegment method dispatches to the doBlock routine for
365//  each block of the given number of blocksToDo, and then updates counts.
366void BlockOrientedKernel::generateDoSegmentMethod(Value * doFinal, const std::vector<Value *> & producerPos) {
367
368    BasicBlock * const entryBlock = iBuilder->GetInsertBlock();
369    BasicBlock * const strideLoopCond = CreateBasicBlock(getName() + "_strideLoopCond");
370    BasicBlock * const strideLoopBody = CreateBasicBlock(getName() + "_strideLoopBody");
371    BasicBlock * const stridesDone = CreateBasicBlock(getName() + "_stridesDone");
372    BasicBlock * const doFinalBlock = CreateBasicBlock(getName() + "_doFinalBlock");
373    BasicBlock * const segmentDone = CreateBasicBlock(getName() + "_segmentDone");
374
375    ConstantInt * stride = iBuilder->getSize(iBuilder->getStride());
376    ConstantInt * strideBlocks = iBuilder->getSize(iBuilder->getStride() / iBuilder->getBitBlockWidth());
377
378    Value * availablePos = producerPos[0];
379    for (unsigned i = 1; i < mStreamSetInputs.size(); i++) {
380        Value * p = producerPos[i];
381        availablePos = iBuilder->CreateSelect(iBuilder->CreateICmpULT(availablePos, p), availablePos, p);
382    }
383
384    Value * processed = getProcessedItemCount(mStreamSetInputs[0].name);
385    Value * itemsAvail = iBuilder->CreateSub(availablePos, processed);
386    Value * stridesToDo = iBuilder->CreateUDiv(itemsAvail, stride);
387    iBuilder->CreateBr(strideLoopCond);
388
389    iBuilder->SetInsertPoint(strideLoopCond);
390    PHINode * stridesRemaining = iBuilder->CreatePHI(iBuilder->getSizeTy(), 2, "stridesRemaining");
391    stridesRemaining->addIncoming(stridesToDo, entryBlock);
392    Value * notDone = iBuilder->CreateICmpNE(stridesRemaining, iBuilder->getSize(0));
393    iBuilder->CreateCondBr(notDone, strideLoopBody, stridesDone);
394
395    iBuilder->SetInsertPoint(strideLoopBody);
396    Value * blockNo = getBlockNo();
397
398    CreateDoBlockMethodCall();
399
400    setBlockNo(iBuilder->CreateAdd(blockNo, strideBlocks));
401
402    // Update counts
403
404    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
405        Value * processed = getProcessedItemCount(mStreamSetInputs[i].name);
406        processed = iBuilder->CreateAdd(processed, stride);
407        setProcessedItemCount(mStreamSetInputs[i].name, processed);
408    }
409
410    if (!mDoBlockUpdatesProducedItemCountsAttribute) {
411        for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
412            Value * produced = getProducedItemCount(mStreamSetOutputs[i].name);
413            produced = iBuilder->CreateAdd(produced, stride);
414            setProducedItemCount(mStreamSetOutputs[i].name, produced);
415        }
416    }
417
418    stridesRemaining->addIncoming(iBuilder->CreateSub(stridesRemaining, iBuilder->getSize(1)), strideLoopBody);
419    iBuilder->CreateBr(strideLoopCond);
420
421    iBuilder->SetInsertPoint(stridesDone);
422
423    // Now conditionally perform the final block processing depending on the doFinal parameter.
424    iBuilder->CreateCondBr(doFinal, doFinalBlock, segmentDone);
425    iBuilder->SetInsertPoint(doFinalBlock);
426
427    Value * remainingItems = iBuilder->CreateSub(producerPos[0], getProcessedItemCount(mStreamSetInputs[0].name));
428
429    CreateDoFinalBlockMethodCall(remainingItems);
430
431    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
432        Value * preProcessed = getProcessedItemCount(mStreamSetInputs[i].name);
433        setProcessedItemCount(mStreamSetInputs[i].name, iBuilder->CreateAdd(preProcessed, remainingItems));
434    }
435    if (!mDoBlockUpdatesProducedItemCountsAttribute) {
436        for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
437            Value * preProduced = getProducedItemCount(mStreamSetOutputs[i].name);
438            setProducedItemCount(mStreamSetOutputs[i].name, iBuilder->CreateAdd(preProduced, remainingItems));
439        }
440    }
441    setTerminationSignal();
442    iBuilder->CreateBr(segmentDone);
443
444    iBuilder->SetInsertPoint(segmentDone);
445
446}
447
448void BlockOrientedKernel::generateInternalMethods() {
449
450    callGenerateDoBlockMethod();
451
452    callGenerateDoFinalBlockMethod();
453}
454
455void BlockOrientedKernel::callGenerateDoBlockMethod() {
456    mCurrentFunction = getDoBlockFunction();
457    auto args = mCurrentFunction->arg_begin();
458    mSelf = &(*args);
459    iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
460    generateDoBlockMethod(); // must be implemented by the KernelBuilder subtype
461    iBuilder->CreateRetVoid();
462}
463
464
465void BlockOrientedKernel::callGenerateDoFinalBlockMethod() {
466    mCurrentFunction = getDoFinalBlockFunction();
467    auto args = mCurrentFunction->arg_begin();
468    mSelf = &(*args++);
469    Value * const remainingBytes = &(*args);
470    iBuilder->SetInsertPoint(CreateBasicBlock("entry"));
471    generateFinalBlockMethod(remainingBytes); // possibly overridden by the KernelBuilder subtype
472    iBuilder->CreateRetVoid();
473}
474
475Function * BlockOrientedKernel::getDoBlockFunction() const {
476    const auto name = getName() + DO_BLOCK_SUFFIX;
477    Function * const f = iBuilder->getModule()->getFunction(name);
478    if (LLVM_UNLIKELY(f == nullptr)) {
479        llvm::report_fatal_error("Cannot find " + name);
480    }
481    return f;
482}
483
484CallInst * BlockOrientedKernel::CreateDoBlockMethodCall() const {
485    return iBuilder->CreateCall(getDoBlockFunction(), mSelf);
486}
487
488Function * BlockOrientedKernel::getDoFinalBlockFunction() const {
489    const auto name = getName() + FINAL_BLOCK_SUFFIX;
490    Function * const f = iBuilder->getModule()->getFunction(name);
491    if (LLVM_UNLIKELY(f == nullptr)) {
492        llvm::report_fatal_error("Cannot find " + name);
493    }
494    return f;
495}
496
497CallInst * BlockOrientedKernel::CreateDoFinalBlockMethodCall(Value * remainingItems) const {
498    return iBuilder->CreateCall(getDoFinalBlockFunction(), {mSelf, remainingItems});
499}
500
501void BlockOrientedKernel::addAdditionalKernelDeclarations(Module * m, PointerType * selfType) {
502    // Create the doBlock and finalBlock function prototypes
503    FunctionType * const doBlockType = FunctionType::get(iBuilder->getVoidTy(), {selfType}, false);
504    Function * const doBlock = Function::Create(doBlockType, GlobalValue::ExternalLinkage, getName() + DO_BLOCK_SUFFIX, m);
505    doBlock->setCallingConv(CallingConv::C);
506    doBlock->setDoesNotThrow();
507    doBlock->setDoesNotCapture(1);
508    auto args = doBlock->arg_begin();
509    args->setName("self");
510    assert ((++args) == doBlock->arg_end());
511
512    FunctionType * const finalBlockType = FunctionType::get(iBuilder->getVoidTy(), {selfType, iBuilder->getSizeTy()}, false);
513    Function * const finalBlock = Function::Create(finalBlockType, GlobalValue::ExternalLinkage, getName() + FINAL_BLOCK_SUFFIX, m);
514    finalBlock->setCallingConv(CallingConv::C);
515    finalBlock->setDoesNotThrow();
516    finalBlock->setDoesNotCapture(1);
517    args = finalBlock->arg_begin();
518    args->setName("self");
519    (++args)->setName("remainingBytes");
520    assert ((++args) == finalBlock->arg_end());
521}
522
523// CONSTRUCTOR
524KernelBuilder::KernelBuilder(IDISA::IDISA_Builder * builder,
525                             std::string && kernelName,
526                             std::vector<Binding> && stream_inputs,
527                             std::vector<Binding> && stream_outputs,
528                             std::vector<Binding> && scalar_parameters,
529                             std::vector<Binding> && scalar_outputs,
530                             std::vector<Binding> && internal_scalars)
531: 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))
532, mNoTerminateAttribute(false)
533, mDoBlockUpdatesProducedItemCountsAttribute(false) {
534
535}
536
537KernelBuilder::~KernelBuilder() { }
538
539// CONSTRUCTOR
540BlockOrientedKernel::BlockOrientedKernel(IDISA::IDISA_Builder * builder,
541                                         std::string && kernelName,
542                                         std::vector<Binding> && stream_inputs,
543                                         std::vector<Binding> && stream_outputs,
544                                         std::vector<Binding> && scalar_parameters,
545                                         std::vector<Binding> && scalar_outputs,
546                                         std::vector<Binding> && internal_scalars)
547: 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)) {
548
549}
550
551
552
553
554// CONSTRUCTOR
555SegmentOrientedKernel::SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
556                                             std::string && kernelName,
557                                             std::vector<Binding> && stream_inputs,
558                                             std::vector<Binding> && stream_outputs,
559                                             std::vector<Binding> && scalar_parameters,
560                                             std::vector<Binding> && scalar_outputs,
561                                             std::vector<Binding> && internal_scalars)
562: 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)) {
563
564}
Note: See TracBrowser for help on using the repository browser.