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

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

Start of work to simplify kernel writing. Removed generateDoBlockLogic method.

File size: 22.4 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    generateInitMethod();       // possibly overridden by the KernelBuilder subtype
120    generateDoSegmentMethod();
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
135// Default init method, possibly overridden if special init actions required.
136void KernelBuilder::generateInitMethod() const {
137    auto savePoint = iBuilder->saveIP();
138    Module * const m = iBuilder->getModule();
139    Function * initFunction = m->getFunction(mKernelName + init_suffix);
140    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "Init_entry", initFunction, 0));   
141    Function::arg_iterator args = initFunction->arg_begin();
142    Value * self = &*(args++);
143    iBuilder->CreateStore(ConstantAggregateZero::get(mKernelStateType), self);
144    for (auto binding : mScalarInputs) {
145        Value * param = &*(args++);
146        Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(binding.name)});
147        iBuilder->CreateStore(param, ptr);
148    }
149    iBuilder->CreateRetVoid();
150    iBuilder->restoreIP(savePoint);
151}
152
153ConstantInt * KernelBuilder::getScalarIndex(const std::string & name) const {
154    const auto f = mKernelMap.find(name);
155    if (LLVM_UNLIKELY(f == mKernelMap.end())) {
156        llvm::report_fatal_error("Kernel does not contain scalar: " + name);
157    }
158    return iBuilder->getInt32(f->second);
159}
160
161unsigned KernelBuilder::getScalarCount() const {
162    return mKernelFields.size();
163}
164
165Value * KernelBuilder::getScalarFieldPtr(Value * self, const std::string & fieldName) const {
166    return getScalarFieldPtr(self, getScalarIndex(fieldName));
167}
168
169Value * KernelBuilder::getScalarFieldPtr(Value * self, Value * index) const {
170    return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), index});
171}
172
173Value * KernelBuilder::getScalarField(Value * self, const std::string & fieldName) const {
174    return iBuilder->CreateLoad(getScalarFieldPtr(self, fieldName));
175}
176
177Value * KernelBuilder::getScalarField(Value * self, Value * index) const {
178    return iBuilder->CreateLoad(getScalarFieldPtr(self, index));
179}
180
181void KernelBuilder::setScalarField(Value * self, const std::string & fieldName, Value * value) const {
182    iBuilder->CreateStore(value, getScalarFieldPtr(self, fieldName));
183}
184
185void KernelBuilder::setScalarField(Value * self, Value * index, Value * value) const {
186    iBuilder->CreateStore(value, getScalarFieldPtr(self, index));
187}
188
189LoadInst * KernelBuilder::acquireLogicalSegmentNo(Value * self) const {
190    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(logicalSegmentNoScalar)});
191    return iBuilder->CreateAtomicLoadAcquire(ptr);
192}
193
194Value * KernelBuilder::getProcessedItemCount(Value * self, const std::string & ssName) const {
195    return getScalarField(self, ssName + processedItemCountSuffix);
196}
197
198Value * KernelBuilder::getProducedItemCount(Value * self, const std::string & ssName) const {
199    return getScalarField(self, ssName + producedItemCountSuffix);
200}
201
202Value * KernelBuilder::getTerminationSignal(Value * self) const {
203    return getScalarField(self, terminationSignal);
204}
205
206void KernelBuilder::releaseLogicalSegmentNo(Value * self, Value * newCount) const {
207    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(logicalSegmentNoScalar)});
208    iBuilder->CreateAtomicStoreRelease(newCount, ptr);
209}
210
211void KernelBuilder::setProcessedItemCount(Value * self, const std::string & name, Value * value) const {
212    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(name + processedItemCountSuffix)});
213    iBuilder->CreateStore(value, ptr);
214}
215
216void KernelBuilder::setProducedItemCount(Value * self, const std::string & name, Value * value) const {
217    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(name + producedItemCountSuffix)});
218    iBuilder->CreateStore(value, ptr);
219}
220
221void KernelBuilder::setTerminationSignal(Value * self) const {
222    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(terminationSignal)});
223    iBuilder->CreateStore(ConstantInt::get(iBuilder->getInt1Ty(), 1), ptr);
224}
225
226Value * KernelBuilder::getBlockNo(Value * self) const {
227    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
228    return iBuilder->CreateLoad(ptr);
229}
230
231void KernelBuilder::setBlockNo(Value * self, Value * value) const {
232    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
233    iBuilder->CreateStore(value, ptr);
234}
235
236
237Argument * KernelBuilder::getParameter(Function * const f, const std::string & name) const {
238    for (auto & arg : f->getArgumentList()) {
239        if (arg.getName().equals(name)) {
240            return &arg;
241        }
242    }
243    llvm::report_fatal_error(f->getName() + " does not have parameter " + name);
244}
245
246unsigned KernelBuilder::getStreamSetIndex(const std::string & name) const {
247    const auto f = mStreamSetNameMap.find(name);
248    if (LLVM_UNLIKELY(f == mStreamSetNameMap.end())) {
249        llvm::report_fatal_error("Kernel " + getName() + " does not contain stream set: " + name);
250    }
251    return f->second;
252}
253
254Value * KernelBuilder::getStreamSetBufferPtr(Value * self, const std::string & name) const {
255    return getScalarField(self, name + bufferPtrSuffix);
256}
257
258inline const StreamSetBuffer * KernelBuilder::getStreamSetBuffer(const std::string & name) const {
259    const unsigned structIdx = getStreamSetIndex(name);
260    if (structIdx < mStreamSetInputs.size()) {
261        return mStreamSetInputBuffers[structIdx];
262    } else {
263        return mStreamSetOutputBuffers[structIdx - mStreamSetInputs.size()];
264    }
265}
266
267Value * KernelBuilder::getStreamSetPtr(Value * self, const std::string & name, Value * blockNo) const {
268    return getStreamSetBuffer(name)->getStreamSetPtr(getStreamSetBufferPtr(self, name), blockNo);
269}
270
271Value * KernelBuilder::getStream(Value * self, const std::string & name, Value * blockNo, Value * index) const {
272    return getStreamSetBuffer(name)->getStream(getStreamSetBufferPtr(self, name), blockNo, index);
273}
274
275Value * KernelBuilder::getStream(Value * self, const std::string & name, Value * blockNo, Value * index1, Value * index2) const {
276    assert (index1->getType() == index2->getType());
277    return getStreamSetBuffer(name)->getStream(getStreamSetBufferPtr(self, name), blockNo, index1, index2);
278}
279
280Value * KernelBuilder::getStreamView(Value * self, const std::string & name, Value * blockNo, Value * index) const {
281    return getStreamSetBuffer(name)->getStreamView(getStreamSetBufferPtr(self, name), blockNo, index);
282}
283
284Value * KernelBuilder::getStreamView(llvm::Type * type, Value * self, const std::string & name, Value * blockNo, Value * index) const {
285    return getStreamSetBuffer(name)->getStreamView(type, getStreamSetBufferPtr(self, name), blockNo, index);
286}
287
288void KernelBuilder::createInstance() {
289    if (LLVM_UNLIKELY(mKernelStateType == nullptr)) {
290        llvm::report_fatal_error("Cannot create kernel instance before calling prepareKernel()");
291    }
292    mKernelInstance = iBuilder->CreateCacheAlignedAlloca(mKernelStateType);
293    Module * m = iBuilder->getModule();
294    std::vector<Value *> init_args = {mKernelInstance};
295    for (auto a : mInitialArguments) {
296        init_args.push_back(a);
297    }
298    for (auto b : mStreamSetInputBuffers) {
299        init_args.push_back(b->getStreamSetBasePtr());
300    }
301    for (auto b : mStreamSetOutputBuffers) {
302        init_args.push_back(b->getStreamSetBasePtr());
303    }
304    std::string initFnName = mKernelName + init_suffix;
305    Function * initMethod = m->getFunction(initFnName);
306    if (initMethod == nullptr) {
307        llvm::report_fatal_error("Cannot find " + initFnName);
308    }
309    iBuilder->CreateCall(initMethod, init_args);
310}
311
312//  The default finalBlock method simply dispatches to the doBlock routine.
313void BlockOrientedKernel::generateFinalBlockMethod(Function * function, Value * self, Value * /* remainingBytes */, Value * /* blockNo */) const {
314//    std::vector<Value *> args = {self};
315//    for (Argument & arg : function->getArgumentList()){
316//        args.push_back(&arg);
317//    }
318    iBuilder->CreateCall(getDoBlockFunction(), { self });
319}
320
321//  The default doSegment method dispatches to the doBlock routine for
322//  each block of the given number of blocksToDo, and then updates counts.
323void BlockOrientedKernel::generateDoSegmentMethod() const {
324    auto savePoint = iBuilder->saveIP();
325
326    callGenerateDoBlockMethod();
327
328    callGenerateDoFinalBlockMethod();
329
330    Module * m = iBuilder->getModule();
331    Function * doSegmentFunction = m->getFunction(mKernelName + doSegment_suffix);
332    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), mKernelName + "_entry", doSegmentFunction, 0));
333    BasicBlock * entryBlock = iBuilder->GetInsertBlock();
334    BasicBlock * strideLoopCond = BasicBlock::Create(iBuilder->getContext(), mKernelName + "_strideLoopCond", doSegmentFunction, 0);
335    BasicBlock * strideLoopBody = BasicBlock::Create(iBuilder->getContext(), mKernelName + "_strideLoopBody", doSegmentFunction, 0);
336    BasicBlock * stridesDone = BasicBlock::Create(iBuilder->getContext(), mKernelName + "_stridesDone", doSegmentFunction, 0);
337    BasicBlock * doFinalBlock = BasicBlock::Create(iBuilder->getContext(), mKernelName + "_doFinalBlock", doSegmentFunction, 0);
338    BasicBlock * segmentDone = BasicBlock::Create(iBuilder->getContext(), mKernelName + "_segmentDone", doSegmentFunction, 0);
339    Type * const size_ty = iBuilder->getSizeTy();
340
341    ConstantInt * stride = iBuilder->getSize(iBuilder->getStride());
342    ConstantInt * strideBlocks = iBuilder->getSize(iBuilder->getStride() / iBuilder->getBitBlockWidth());
343
344    Function::arg_iterator args = doSegmentFunction->arg_begin();
345    Value * self = &*(args++);
346    Value * doFinal = &*(args++);
347
348    std::vector<Value *> producerPos;
349    producerPos.push_back(&*(args++));
350    Value * availablePos = producerPos[0];
351    for (unsigned i = 1; i < mStreamSetInputs.size(); i++) {
352        Value * p = &*(args++);
353        producerPos.push_back(p);
354        availablePos = iBuilder->CreateSelect(iBuilder->CreateICmpULT(availablePos, p), availablePos, p);
355    }
356    Value * processed = getProcessedItemCount(self, mStreamSetInputs[0].name);
357    Value * itemsAvail = iBuilder->CreateSub(availablePos, processed);
358    Value * stridesToDo = iBuilder->CreateUDiv(itemsAvail, stride);
359    iBuilder->CreateBr(strideLoopCond);
360
361    iBuilder->SetInsertPoint(strideLoopCond);
362    PHINode * stridesRemaining = iBuilder->CreatePHI(size_ty, 2, "stridesRemaining");
363    stridesRemaining->addIncoming(stridesToDo, entryBlock);
364    Value * notDone = iBuilder->CreateICmpUGT(stridesRemaining, ConstantInt::get(size_ty, 0));
365    iBuilder->CreateCondBr(notDone, strideLoopBody, stridesDone);
366
367    iBuilder->SetInsertPoint(strideLoopBody);
368    Value * blockNo = getBlockNo(self);
369
370    iBuilder->CreateCall(getDoBlockFunction(), self);
371
372    setBlockNo(self, iBuilder->CreateAdd(blockNo, strideBlocks));
373    stridesRemaining->addIncoming(iBuilder->CreateSub(stridesRemaining, ConstantInt::get(size_ty, 1)), strideLoopBody);
374    iBuilder->CreateBr(strideLoopCond);
375
376    iBuilder->SetInsertPoint(stridesDone);
377    // Update counts for the full strides processed.
378    Value * segmentItemsProcessed = iBuilder->CreateMul(stridesToDo, stride);
379    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
380        Value * preProcessed = getProcessedItemCount(self, mStreamSetInputs[i].name);
381        setProcessedItemCount(self, mStreamSetInputs[i].name, iBuilder->CreateAdd(preProcessed, segmentItemsProcessed));
382    }
383    if (!mDoBlockUpdatesProducedItemCountsAttribute) {
384        for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
385            Value * preProduced = getProducedItemCount(self, mStreamSetOutputs[i].name);
386            setProducedItemCount(self, mStreamSetOutputs[i].name, iBuilder->CreateAdd(preProduced, segmentItemsProcessed));
387        }
388    }
389
390    // Now conditionally perform the final block processing depending on the doFinal parameter.
391    iBuilder->CreateCondBr(doFinal, doFinalBlock, segmentDone);
392    iBuilder->SetInsertPoint(doFinalBlock);
393
394    Value * remainingItems = iBuilder->CreateSub(producerPos[0], getProcessedItemCount(self, mStreamSetInputs[0].name));
395
396    iBuilder->CreateCall(getDoFinalBlockFunction(), {self, remainingItems});
397
398    // createFinalBlockCall(self, remainingItems);
399    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
400        Value * preProcessed = getProcessedItemCount(self, mStreamSetInputs[i].name);
401        setProcessedItemCount(self, mStreamSetInputs[i].name, iBuilder->CreateAdd(preProcessed, remainingItems));
402    }
403    if (!mDoBlockUpdatesProducedItemCountsAttribute) {
404        for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
405            Value * preProduced = getProducedItemCount(self, mStreamSetOutputs[i].name);
406            setProducedItemCount(self, mStreamSetOutputs[i].name, iBuilder->CreateAdd(preProduced, remainingItems));
407        }
408    }
409    setTerminationSignal(self);
410    iBuilder->CreateBr(segmentDone);
411
412    iBuilder->SetInsertPoint(segmentDone);
413
414    iBuilder->CreateRetVoid();
415    iBuilder->restoreIP(savePoint);
416}
417
418void BlockOrientedKernel::callGenerateDoBlockMethod() const {
419    Function * f = getDoBlockFunction();
420    Value * const self = getParameter(f, "self"); assert (self);
421    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", f));
422    generateDoBlockMethod(f, self, getBlockNo(self)); // must be implemented by the KernelBuilder subtype
423    iBuilder->CreateRetVoid();
424//    #ifndef NDEBUG
425//    llvm::verifyFunction(*f, &errs());
426//    #endif
427}
428
429void BlockOrientedKernel::callGenerateDoFinalBlockMethod() const {
430    Function * f = getDoFinalBlockFunction();
431    Value * const self = getParameter(f, "self"); assert (self);
432    Value * remainingBytes = getParameter(f, "remainingBytes"); assert (remainingBytes);
433    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", f));
434    generateFinalBlockMethod(f, self, remainingBytes, getBlockNo(self)); // possibly overridden by the KernelBuilder subtype
435    iBuilder->CreateRetVoid();
436//    #ifndef NDEBUG
437//    llvm::verifyFunction(*f, &errs());
438//    #endif
439}
440
441Function * BlockOrientedKernel::getDoBlockFunction() const {
442    return iBuilder->getModule()->getFunction(mKernelName + doBlock_suffix);
443}
444
445Function * BlockOrientedKernel::getDoFinalBlockFunction() const {
446    return iBuilder->getModule()->getFunction(mKernelName + finalBlock_suffix);
447}
448
449// CONSTRUCTOR
450KernelBuilder::KernelBuilder(IDISA::IDISA_Builder * builder,
451                             std::string && kernelName,
452                             std::vector<Binding> && stream_inputs,
453                             std::vector<Binding> && stream_outputs,
454                             std::vector<Binding> && scalar_parameters,
455                             std::vector<Binding> && scalar_outputs,
456                             std::vector<Binding> && internal_scalars)
457: 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))
458, mNoTerminateAttribute(false)
459, mDoBlockUpdatesProducedItemCountsAttribute(false) {
460
461}
462
463KernelBuilder::~KernelBuilder() { }
464
465// CONSTRUCTOR
466BlockOrientedKernel::BlockOrientedKernel(IDISA::IDISA_Builder * builder,
467                                         std::string && kernelName,
468                                         std::vector<Binding> && stream_inputs,
469                                         std::vector<Binding> && stream_outputs,
470                                         std::vector<Binding> && scalar_parameters,
471                                         std::vector<Binding> && scalar_outputs,
472                                         std::vector<Binding> && internal_scalars)
473: 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)) {
474
475}
476
477// CONSTRUCTOR
478SegmentOrientedKernel::SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
479                                             std::string && kernelName,
480                                             std::vector<Binding> && stream_inputs,
481                                             std::vector<Binding> && stream_outputs,
482                                             std::vector<Binding> && scalar_parameters,
483                                             std::vector<Binding> && scalar_outputs,
484                                             std::vector<Binding> && internal_scalars)
485: 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)) {
486
487}
Note: See TracBrowser for help on using the repository browser.