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

Last change on this file since 5292 was 5292, checked in by nmedfort, 3 years ago

Removed 'function' and 'self' parameters from generateXXXMethod() functions.

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