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

Last change on this file since 5298 was 5298, checked in by nmedfort, 2 years ago

Removed StreamType? in favour of 0-length VectorType?.

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