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

Last change on this file since 5782 was 5782, checked in by nmedfort, 17 months ago

Initial check-in of LookAhead? support; modified LineBreakKernel? to compute CR+LF using LookAhead?(1) + misc. fixes.

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