source: icGREP/icgrep-devel/icgrep/kernels/kernel_builder.cpp @ 5755

Last change on this file since 5755 was 5755, checked in by nmedfort, 16 months ago

Bug fixes and simplified MultiBlockKernel? logic

File size: 27.0 KB
Line 
1#include "kernel_builder.h"
2#include <toolchain/toolchain.h>
3#include <kernels/kernel.h>
4#include <kernels/streamset.h>
5#include <llvm/Support/raw_ostream.h>
6#include <llvm/IR/Module.h>
7
8using namespace llvm;
9using namespace parabix;
10
11inline static bool is_power_2(const uint64_t n) {
12    return ((n & (n - 1)) == 0) && n;
13}
14
15namespace kernel {
16
17using Port = Kernel::Port;
18
19Value * KernelBuilder::getScalarFieldPtr(llvm::Value * const instance, Value * const index) {
20    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::EnableAsserts))) {
21        CreateAssert(instance, "getScalarFieldPtr: instance cannot be null!");
22    }
23    return CreateGEP(instance, {getInt32(0), index});
24}
25
26Value * KernelBuilder::getScalarFieldPtr(llvm::Value * const handle, const std::string & fieldName) {
27    return getScalarFieldPtr(handle, getInt32(mKernel->getScalarIndex(fieldName)));
28}
29
30llvm::Value * KernelBuilder::getScalarFieldPtr(llvm::Value * const index) {
31    return getScalarFieldPtr(mKernel->getInstance(), index);
32}
33
34llvm::Value *KernelBuilder:: getScalarFieldPtr(const std::string & fieldName) {
35    return getScalarFieldPtr(mKernel->getInstance(), fieldName);
36}
37
38Value * KernelBuilder::getScalarField(const std::string & fieldName) {
39    return CreateLoad(getScalarFieldPtr(fieldName), fieldName);
40}
41
42void KernelBuilder::setScalarField(const std::string & fieldName, Value * value) {
43    CreateStore(value, getScalarFieldPtr(fieldName));
44}
45
46Value * KernelBuilder::getStreamHandle(const std::string & name) {
47    Value * const ptr = getScalarField(name + Kernel::BUFFER_PTR_SUFFIX);
48    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::EnableAsserts))) {
49        CreateAssert(ptr, name + " handle cannot be null!");
50    }
51    return ptr;
52}
53
54LoadInst * KernelBuilder::acquireLogicalSegmentNo() {
55    return CreateAtomicLoadAcquire(getScalarFieldPtr(Kernel::LOGICAL_SEGMENT_NO_SCALAR));
56}
57
58void KernelBuilder::releaseLogicalSegmentNo(Value * nextSegNo) {
59    CreateAtomicStoreRelease(nextSegNo, getScalarFieldPtr(Kernel::LOGICAL_SEGMENT_NO_SCALAR));
60}
61
62Value * KernelBuilder::getCycleCountPtr() {
63    return getScalarFieldPtr(Kernel::CYCLECOUNT_SCALAR);
64}
65
66Value * KernelBuilder::getInternalItemCount(const std::string & name, const std::string & suffix) {
67    const ProcessingRate & rate = mKernel->getBinding(name).getRate();
68    Value * itemCount = nullptr;
69    if (LLVM_UNLIKELY(rate.isRelative())) {
70        Port port; unsigned index;
71        std::tie(port, index) = mKernel->getStreamPort(rate.getReference());
72        if (port == Port::Input) {
73            itemCount = getProcessedItemCount(rate.getReference());
74        } else {
75            itemCount = getProducedItemCount(rate.getReference());
76        }
77        const auto & r = rate.getRate();
78        if (r.numerator() != 1) {
79            itemCount = CreateMul(itemCount, ConstantInt::get(itemCount->getType(), r.numerator()));
80        }
81        if (r.denominator() != 1) {
82            itemCount = CreateExactUDiv(itemCount, ConstantInt::get(itemCount->getType(), r.denominator()));
83        }
84    } else {
85        itemCount = getScalarField(name + suffix);
86    }
87    return itemCount;
88}
89
90void KernelBuilder::setInternalItemCount(const std::string & name, const std::string & suffix, llvm::Value * const value) {
91    const ProcessingRate & rate = mKernel->getBinding(name).getRate();
92    if (LLVM_UNLIKELY(rate.isDerived())) {
93        report_fatal_error("Cannot set item count: " + name + " is a Derived rate");
94    }
95    if (codegen::DebugOptionIsSet(codegen::TraceCounts)) {
96        CallPrintIntToStderr(mKernel->getName() + ": " + name + suffix, value);
97    }
98    setScalarField(name + suffix, value);
99}
100
101
102Value * KernelBuilder::getAvailableItemCount(const std::string & name) {
103    const auto & inputs = mKernel->getStreamInputs();
104    for (unsigned i = 0; i < inputs.size(); ++i) {
105        if (inputs[i].getName() == name) {
106            return mKernel->getAvailableItemCount(i);
107        }
108    }
109    return nullptr;
110}
111
112Value * KernelBuilder::getTerminationSignal() {
113    if (mKernel->hasNoTerminateAttribute()) {
114        return getFalse();
115    }
116    return getScalarField(Kernel::TERMINATION_SIGNAL);
117}
118
119void KernelBuilder::setTerminationSignal(llvm::Value * const value) {
120    assert (!mKernel->hasNoTerminateAttribute());
121    assert (value->getType() == getInt1Ty());
122    if (codegen::DebugOptionIsSet(codegen::TraceCounts)) {
123        CallPrintIntToStderr(mKernel->getName() + ": setTerminationSignal", value);
124    }
125    setScalarField(Kernel::TERMINATION_SIGNAL, value);
126}
127
128Value * KernelBuilder::getLinearlyAccessibleItems(const std::string & name, Value * fromPosition, Value * avail, bool reverse) {
129    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
130    return buf->getLinearlyAccessibleItems(this, getStreamHandle(name), fromPosition, avail, reverse);
131}
132
133Value * KernelBuilder::getLinearlyWritableItems(const std::string & name, Value * fromPosition, bool reverse) {
134    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
135    return buf->getLinearlyWritableItems(this, getStreamHandle(name), fromPosition, reverse);
136}
137
138//Value * KernelBuilder::getLinearlyCopyableItems(const std::string & name, Value * fromPosition, bool reverse) {
139//    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
140//    return buf->getLinearlyCopyableItems(this, getStreamHandle(name), fromPosition, reverse);
141//}
142
143/** ------------------------------------------------------------------------------------------------------------- *
144 * @brief isConstantZero
145 ** ------------------------------------------------------------------------------------------------------------- */
146inline bool isConstantZero(Value * const v) {
147    return isa<ConstantInt>(v) && cast<ConstantInt>(v)->isNullValue();
148}
149
150/** ------------------------------------------------------------------------------------------------------------- *
151 * @brief isConstantOne
152 ** ------------------------------------------------------------------------------------------------------------- */
153inline bool isConstantOne(Value * const v) {
154    return isa<ConstantInt>(v) && cast<ConstantInt>(v)->isOne();
155}
156
157/** ------------------------------------------------------------------------------------------------------------- *
158 * @brief getItemWidth
159 ** ------------------------------------------------------------------------------------------------------------- */
160inline unsigned getItemWidth(const Type * ty) {
161    if (LLVM_LIKELY(isa<ArrayType>(ty))) {
162        ty = ty->getArrayElementType();
163    }
164    return cast<IntegerType>(ty->getVectorElementType())->getBitWidth();
165}
166
167/** ------------------------------------------------------------------------------------------------------------- *
168 * @brief getFieldWidth
169 ** ------------------------------------------------------------------------------------------------------------- */
170inline unsigned getFieldWidth(const unsigned bitWidth, const unsigned blockWidth) {
171    for (unsigned k = 16; k < blockWidth; k *= 2) {
172        if ((bitWidth & (k - 1)) != 0) {
173            return k / 2;
174        }
175    }
176    return blockWidth;
177}
178
179/** ------------------------------------------------------------------------------------------------------------- *
180 * @brief CreateStreamCpy
181 ** ------------------------------------------------------------------------------------------------------------- */
182void KernelBuilder::CreateStreamCpy(const std::string & name, Value * target, Value * targetOffset, Value * source, Value * sourceOffset, Value * itemsToCopy, const unsigned itemAlignment) {
183
184    assert (target && targetOffset);
185    assert (source && sourceOffset);
186    assert (target->getType() == source->getType());
187    assert (target->getType()->isPointerTy());
188
189    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
190
191    const auto itemWidth = getItemWidth(buf->getBaseType());
192    assert ("invalid item width" && is_power_2(itemWidth));
193    const auto blockWidth = getBitBlockWidth();
194
195    const auto fieldWidth = getFieldWidth(itemWidth * itemAlignment, blockWidth);
196    assert ("overflow error" && is_power_2(fieldWidth) && (itemWidth <= fieldWidth));
197
198    assert (isConstantZero(targetOffset) || isConstantZero(sourceOffset));
199
200    IntegerType * const fieldWidthTy = getIntNTy(fieldWidth / 8);
201
202    const auto alignment = fieldWidth / 8;
203
204    if (LLVM_LIKELY(itemWidth < fieldWidth)) {
205        Constant * const factor = getSize(fieldWidth / itemWidth);
206        CreateAssertZero(CreateURem(targetOffset, factor), "target offset is not a multiple of its field width");
207        targetOffset = CreateUDiv(targetOffset, factor);
208        CreateAssertZero(CreateURem(sourceOffset, factor), "source offset is not a multiple of its field width");
209        sourceOffset = CreateUDiv(sourceOffset, factor);
210    }
211
212    /*
213
214       Streams are conceptually modelled as:
215
216                                            BLOCKS
217
218                                      A     B     C     D
219           STREAM SET ELEMENT   1  |aaaaa|bbbbb|ccccc|dddd |
220                                2  |eeeee|fffff|ggggg|hhhh |
221                                3  |iiiii|jjjjj|kkkkk|llll |
222
223       But the memory layout is actually:
224
225           A_1   A_2   A_3   B_1   B_2   B_3   C_1   C_2   C_3   D_1   D_2   D_3
226
227         |aaaaa|eeeee|iiiii|bbbbb|fffff|jjjjj|ccccc|ggggg|kkkkk|dddd |hhhh |llll |
228
229
230       So if we're copying the entire stream set block or our stream set has one element, we can use memcpy.
231
232    */
233
234    Value * const n = buf->getStreamSetCount(this, getStreamHandle(name));
235    if (fieldWidth == blockWidth || isConstantOne(n) || (isConstantZero(targetOffset) && isConstantZero(sourceOffset))) {
236        PointerType * const fieldWidthPtrTy = fieldWidthTy->getPointerTo();
237        if (isConstantOne(n)) {
238            if (LLVM_LIKELY(itemWidth < 8)) {
239                itemsToCopy = CreateUDivCeil(itemsToCopy, getSize(8 / itemWidth));
240            } else if (LLVM_UNLIKELY(itemWidth > 8)) {
241                itemsToCopy = CreateMul(itemsToCopy, getSize(itemWidth / 8));
242            }
243        } else {
244            itemsToCopy = CreateMul(CreateUDivCeil(itemsToCopy, getSize(blockWidth / (8 * itemWidth))), n);
245        }
246        target = CreateGEP(CreatePointerCast(target, fieldWidthPtrTy), targetOffset);
247        source = CreateGEP(CreatePointerCast(source, fieldWidthPtrTy), sourceOffset);
248        CreateMemCpy(target, source, itemsToCopy, alignment);
249
250    } else { // either the target offset or source offset is non-zero but not both
251
252        VectorType * const blockTy = getBitBlockType();
253        PointerType * const blockPtrTy = blockTy->getPointerTo();
254
255        target = CreatePointerCast(target, blockPtrTy);
256        source = CreatePointerCast(source, blockPtrTy);
257
258        VectorType * const shiftTy = VectorType::get(fieldWidthTy, blockWidth / fieldWidth);
259        Constant * const width = getSize(blockWidth / itemWidth);
260        BasicBlock * const entry = GetInsertBlock();
261
262
263        if (isConstantZero(targetOffset)) {
264
265            /*
266                                                BLOCKS
267
268                                          A     B     C     D
269               SOURCE STREAM        1  |aaa--|bbbBB|cccCC|  dDD|
270                                    2  |eee--|fffFF|gggGG|  hHH|
271                                    3  |iii--|jjjJJ|kkkKK|  lLL|
272
273
274                                          A     B     C     D
275               TARGET STREAM        1  |BBaaa|CCbbb|DDccc|    d|
276                                    2  |FFeee|GGfff|HHggg|    h|
277                                    3  |JJiii|KKjjj|LLkkk|    l|
278             */
279
280            Value * const blocksToCopy = CreateMul(CreateUDiv(itemsToCopy, width), n);
281            Value * const offset = CreateURem(sourceOffset, width);
282            Value * const remaining = CreateSub(width, offset);
283            Value * const trailing = CreateURem(CreateAdd(sourceOffset, itemsToCopy), width);
284
285            BasicBlock * const streamCopy = CreateBasicBlock(name + "StreamCopy");
286            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "StreamCopyRemaining");
287            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "StreamCopyEnd");
288
289            CreateCondBr(CreateICmpNE(blocksToCopy, getSize(0)), streamCopy, streamCopyRemaining);
290
291            SetInsertPoint(streamCopy);
292            PHINode * const i = CreatePHI(getSizeTy(), 2);
293            i->addIncoming(n, entry);
294            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(i, n)), alignment);
295            prior = CreateLShr(CreateBitCast(prior, shiftTy), offset);
296            Value * value = CreateAlignedLoad(CreateGEP(source, i), alignment);
297            value = CreateShl(CreateBitCast(value, shiftTy), remaining);
298            Value * const result = CreateBitCast(CreateOr(value, prior), blockTy);
299            CreateAlignedStore(result, CreateGEP(target, i), alignment);
300            Value * const next_i = CreateAdd(i, getSize(1));
301            i->addIncoming(next_i, streamCopy);
302            CreateCondBr(CreateICmpNE(next_i, blocksToCopy), streamCopy, streamCopyRemaining);
303
304            SetInsertPoint(streamCopyRemaining);
305            PHINode * const j = CreatePHI(getSizeTy(), 2);
306            j->addIncoming(getSize(0), streamCopy);
307            Value * k = CreateAdd(blocksToCopy, j);
308            Value * final = CreateAlignedLoad(CreateGEP(source, k), alignment);
309            final = CreateLShr(CreateBitCast(prior, shiftTy), trailing);
310            CreateAlignedStore(final, CreateGEP(target, k), alignment);
311            Value * const next_j = CreateAdd(i, getSize(1));
312            i->addIncoming(next_j, streamCopyRemaining);
313            CreateCondBr(CreateICmpNE(next_j, n), streamCopyRemaining, streamCopyEnd);
314
315            SetInsertPoint(streamCopyEnd);
316
317        } else if (isConstantZero(sourceOffset)) {
318
319            /*
320                                                BLOCKS
321
322                                          A     B     C     D
323               SOURCE STREAM        1  |AAAaa|BBBaa|CCCcc|    d|
324                                    2  |EEEee|FFFff|GGGgg|    h|
325                                    3  |IIIii|JJJjj|KKKkk|    l|
326
327
328                                          A     B     C     D
329               TARGET STREAM        1  |aa---|bbAAA|ccBBB| dCCC|
330                                    2  |ee---|ffEEE|ggFFF| hGGG|
331                                    3  |ii---|jjIII|kkJJJ| lKKK|
332
333            */
334
335            BasicBlock * const streamCopy = CreateBasicBlock(name + "StreamCopy");
336            BasicBlock * const streamCopyRemainingCond = CreateBasicBlock(name + "StreamCopyRemainingCond");
337            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "StreamCopyRemaining");
338            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "StreamCopyEnd");
339
340            Value * const offset = CreateURem(targetOffset, width);
341            Value * const copied = CreateSub(width, offset);
342            Value * const mask = CreateLShr(Constant::getAllOnesValue(shiftTy), copied);
343
344            SetInsertPoint(streamCopy);
345            PHINode * const i = CreatePHI(getSizeTy(), 2);
346            i->addIncoming(getSize(0), entry);
347            Value * targetValue = CreateAlignedLoad(CreateGEP(target, i), alignment);
348            targetValue = CreateAnd(CreateBitCast(targetValue, shiftTy), mask);
349            Value * sourceValue = CreateAlignedLoad(CreateGEP(source, i), alignment);
350            sourceValue = CreateShl(CreateBitCast(sourceValue, shiftTy), offset);
351            CreateAlignedStore(CreateOr(sourceValue, targetValue), CreateGEP(source, i), alignment);
352            Value * const next_i = CreateAdd(i, getSize(1));
353            i->addIncoming(next_i, streamCopy);
354            CreateCondBr(CreateICmpNE(next_i, n), streamCopy, streamCopyRemainingCond);
355
356            SetInsertPoint(streamCopyRemainingCond);
357            Value * const blocksToCopy = CreateMul(CreateUDiv(CreateSub(itemsToCopy, copied), width), n);
358            CreateCondBr(CreateICmpULT(copied, itemsToCopy), streamCopyRemaining, streamCopyEnd);
359
360            SetInsertPoint(streamCopyRemaining);
361            PHINode * const j = CreatePHI(getSizeTy(), 2);
362            j->addIncoming(n, entry);
363            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(j, n)), alignment);
364            prior = CreateShl(CreateBitCast(prior, shiftTy), offset);
365            Value * value = CreateAlignedLoad(CreateGEP(source, j), alignment);
366            value = CreateLShr(CreateBitCast(value, shiftTy), copied);
367            Value * const result = CreateBitCast(CreateOr(value, prior), blockTy);
368            CreateAlignedStore(result, CreateGEP(target, j), alignment);
369            Value * const next_j = CreateAdd(j, getSize(1));
370            j->addIncoming(next_j, streamCopy);
371            CreateCondBr(CreateICmpNE(next_j, blocksToCopy), streamCopyRemaining, streamCopyEnd);
372
373            SetInsertPoint(streamCopyEnd);
374        }
375
376    }
377}
378
379void KernelBuilder::CreateCopyBack(const std::string & name, llvm::Value * from, llvm::Value * to) {
380    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
381    buf->genCopyBackLogic(this, getStreamHandle(name), from, to, name);
382}
383
384Value * KernelBuilder::getConsumerLock(const std::string & name) {
385    return getScalarField(name + Kernel::CONSUMER_SUFFIX);
386}
387
388void KernelBuilder::setConsumerLock(const std::string & name, Value * value) {
389    setScalarField(name + Kernel::CONSUMER_SUFFIX, value);
390}
391
392Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * streamIndex) {
393    Value * const addr = mKernel->getStreamSetInputAddress(name);
394    if (addr) {
395        return CreateGEP(addr, {getInt32(0), streamIndex});
396    } else {
397        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
398        Value * const blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
399        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
400    }
401}
402
403Value * KernelBuilder::loadInputStreamBlock(const std::string & name, Value * streamIndex) {
404    return CreateBlockAlignedLoad(getInputStreamBlockPtr(name, streamIndex));
405}
406
407Value * KernelBuilder::getInputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
408    Value * const addr = mKernel->getStreamSetInputAddress(name);
409    if (addr) {
410        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
411    } else {
412        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
413        Value * const blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
414        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, true);
415    }
416}
417
418Value * KernelBuilder::loadInputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex) {
419
420
421
422    return CreateBlockAlignedLoad(getInputStreamPackPtr(name, streamIndex, packIndex));
423}
424
425Value * KernelBuilder::getInputStreamSetCount(const std::string & name) {
426    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
427    return buf->getStreamSetCount(this, getStreamHandle(name));
428}
429
430Value * KernelBuilder::getAdjustedInputStreamBlockPtr(Value * blockAdjustment, const std::string & name, Value * streamIndex) {
431    Value * const addr = mKernel->getStreamSetInputAddress(name);
432    if (addr) {
433        return CreateGEP(addr, {blockAdjustment, streamIndex});
434    } else {
435        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
436        Value * blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
437        blockIndex = CreateAdd(blockIndex, blockAdjustment);
438        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
439    }
440}
441
442Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex) {
443    Value * const addr = mKernel->getStreamSetOutputAddress(name);
444    if (addr) {
445        return CreateGEP(addr, {getInt32(0), streamIndex});
446    } else {
447        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
448        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
449        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, false);
450    }
451}
452
453StoreInst * KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
454    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
455}
456
457Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
458    Value * const addr = mKernel->getStreamSetOutputAddress(name);
459    if (addr) {
460        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
461    } else {
462        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
463        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
464        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, false);
465    }
466}
467
468StoreInst * KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
469    return CreateBlockAlignedStore(toStore, getOutputStreamPackPtr(name, streamIndex, packIndex));
470}
471
472Value * KernelBuilder::getOutputStreamSetCount(const std::string & name) {
473    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
474    return buf->getStreamSetCount(this, getStreamHandle(name));
475}
476
477Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * absolutePosition) {
478    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
479    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
480}
481
482Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * absolutePosition) {
483    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
484    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
485}
486
487Value * KernelBuilder::getBaseAddress(const std::string & name) {
488    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamHandle(name));
489}
490
491void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
492    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamHandle(name), addr);
493}
494
495Value * KernelBuilder::getBufferedSize(const std::string & name) {
496    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamHandle(name));
497}
498
499void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
500    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamHandle(name), size);
501}
502
503Value * KernelBuilder::getCapacity(const std::string & name) {
504    return mKernel->getAnyStreamSetBuffer(name)->getCapacity(this, getStreamHandle(name));
505}
506
507void KernelBuilder::setCapacity(const std::string & name, Value * c) {
508    mKernel->getAnyStreamSetBuffer(name)->setCapacity(this, getStreamHandle(name), c);
509}
510
511Value * KernelBuilder::getBlockAddress(const std::string & name, Value * blockIndex) {
512    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
513    return buf->getBlockAddress(this, getStreamHandle(name), blockIndex);
514}
515
516void KernelBuilder::protectOutputStream(const std::string & name, const bool readOnly) {
517    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
518    Value * const handle = getStreamHandle(name);
519    Value * const base = buf->getBaseAddress(this, handle);
520    Value * sz = ConstantExpr::getSizeOf(buf->getType());
521    sz = CreateMul(sz, getInt64(buf->getBufferBlocks()));
522    sz = CreateMul(sz, CreateZExt(buf->getStreamSetCount(this, handle), getInt64Ty()));
523    CreateMProtect(base, sz, readOnly ? CBuilder::READ : (CBuilder::READ | CBuilder::WRITE));
524}
525   
526CallInst * KernelBuilder::createDoSegmentCall(const std::vector<Value *> & args) {
527    return mKernel->makeDoSegmentCall(*this, args);
528}
529
530Value * KernelBuilder::getAccumulator(const std::string & accumName) {
531    auto results = mKernel->mOutputScalarResult;
532    if (LLVM_UNLIKELY(results == nullptr)) {
533        report_fatal_error("Cannot get accumulator " + accumName + " until " + mKernel->getName() + " has terminated.");
534    }
535    const auto & outputs = mKernel->getScalarOutputs();
536    const auto n = outputs.size();
537    if (LLVM_UNLIKELY(n == 0)) {
538        report_fatal_error(mKernel->getName() + " has no output scalars.");
539    } else {
540        for (unsigned i = 0; i < n; ++i) {
541            const Binding & b = outputs[i];
542            if (b.getName() == accumName) {
543                if (n == 1) {
544                    return results;
545                } else {
546                    return CreateExtractValue(results, {i});
547                }
548            }
549        }
550        report_fatal_error(mKernel->getName() + " has no output scalar named " + accumName);
551    }
552}
553
554BasicBlock * KernelBuilder::CreateConsumerWait() {
555    const auto consumers = mKernel->getStreamOutputs();
556    BasicBlock * const entry = GetInsertBlock();
557    if (consumers.empty()) {
558        return entry;
559    } else {
560        Function * const parent = entry->getParent();
561        IntegerType * const sizeTy = getSizeTy();
562        ConstantInt * const zero = getInt32(0);
563        ConstantInt * const one = getInt32(1);
564        ConstantInt * const size0 = getSize(0);
565
566        Value * const segNo = acquireLogicalSegmentNo();
567        const auto n = consumers.size();
568        BasicBlock * load[n + 1];
569        BasicBlock * wait[n];
570        for (unsigned i = 0; i < n; ++i) {
571            load[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Load", parent);
572            wait[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Wait", parent);
573        }
574        load[n] = BasicBlock::Create(getContext(), "Resume", parent);
575        CreateBr(load[0]);
576        for (unsigned i = 0; i < n; ++i) {
577
578            SetInsertPoint(load[i]);
579            Value * const outputConsumers = getConsumerLock(consumers[i].getName());
580
581            Value * const consumerCount = CreateLoad(CreateGEP(outputConsumers, {zero, zero}));
582            Value * const consumerPtr = CreateLoad(CreateGEP(outputConsumers, {zero, one}));
583            Value * const noConsumers = CreateICmpEQ(consumerCount, size0);
584            CreateUnlikelyCondBr(noConsumers, load[i + 1], wait[i]);
585
586            SetInsertPoint(wait[i]);
587            PHINode * const consumerPhi = CreatePHI(sizeTy, 2);
588            consumerPhi->addIncoming(size0, load[i]);
589
590            Value * const conSegPtr = CreateLoad(CreateGEP(consumerPtr, consumerPhi));
591            Value * const processedSegmentCount = CreateAtomicLoadAcquire(conSegPtr);
592            Value * const ready = CreateICmpEQ(segNo, processedSegmentCount);
593            assert (ready->getType() == getInt1Ty());
594            Value * const nextConsumerIdx = CreateAdd(consumerPhi, CreateZExt(ready, sizeTy));
595            consumerPhi->addIncoming(nextConsumerIdx, wait[i]);
596            Value * const next = CreateICmpEQ(nextConsumerIdx, consumerCount);
597            CreateCondBr(next, load[i + 1], wait[i]);
598        }
599
600        BasicBlock * const exit = load[n];
601        SetInsertPoint(exit);
602        return exit;
603    }
604}
605
606}
Note: See TracBrowser for help on using the repository browser.