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

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

Continued work on eliminating BlockNo?

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