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

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

Continuation of work to simplify Kernel writing

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