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

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

Partial removal of BlockNo?

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