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

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

Compilation bug fix for CreateStreamCpy?. Needs more testing.

File size: 28.2 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() {
[5793]120    return CreateICmpNE(getScalarField(Kernel::TERMINATION_SIGNAL), getSize(0));
[5435]121}
122
[5706]123void KernelBuilder::setTerminationSignal(llvm::Value * const value) {
124    assert (value->getType() == getInt1Ty());
[5637]125    if (codegen::DebugOptionIsSet(codegen::TraceCounts)) {
[5706]126        CallPrintIntToStderr(mKernel->getName() + ": setTerminationSignal", value);
[5637]127    }
[5793]128    setScalarField(Kernel::TERMINATION_SIGNAL, CreateZExt(value, getSizeTy()));
[5435]129}
130
[5706]131Value * KernelBuilder::getLinearlyAccessibleItems(const std::string & name, Value * fromPosition, Value * avail, bool reverse) {
132    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
133    return buf->getLinearlyAccessibleItems(this, getStreamHandle(name), fromPosition, avail, reverse);
[5435]134}
135
[5706]136Value * KernelBuilder::getLinearlyWritableItems(const std::string & name, Value * fromPosition, bool reverse) {
137    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
[5782]138    return buf->getLinearlyWritableItems(this, getStreamHandle(name), fromPosition, getConsumedItemCount(name), reverse);
[5435]139}
140
[5755]141/** ------------------------------------------------------------------------------------------------------------- *
142 * @brief isConstantZero
143 ** ------------------------------------------------------------------------------------------------------------- */
144inline bool isConstantZero(Value * const v) {
145    return isa<ConstantInt>(v) && cast<ConstantInt>(v)->isNullValue();
146}
147
148/** ------------------------------------------------------------------------------------------------------------- *
149 * @brief isConstantOne
150 ** ------------------------------------------------------------------------------------------------------------- */
151inline bool isConstantOne(Value * const v) {
152    return isa<ConstantInt>(v) && cast<ConstantInt>(v)->isOne();
153}
154
155/** ------------------------------------------------------------------------------------------------------------- *
156 * @brief getItemWidth
157 ** ------------------------------------------------------------------------------------------------------------- */
158inline unsigned getItemWidth(const Type * ty) {
159    if (LLVM_LIKELY(isa<ArrayType>(ty))) {
160        ty = ty->getArrayElementType();
161    }
162    return cast<IntegerType>(ty->getVectorElementType())->getBitWidth();
163}
164
165/** ------------------------------------------------------------------------------------------------------------- *
166 * @brief getFieldWidth
167 ** ------------------------------------------------------------------------------------------------------------- */
168inline unsigned getFieldWidth(const unsigned bitWidth, const unsigned blockWidth) {
[5757]169    for (unsigned k = 16; k <= blockWidth; k *= 2) {
[5755]170        if ((bitWidth & (k - 1)) != 0) {
171            return k / 2;
172        }
173    }
174    return blockWidth;
175}
176
177/** ------------------------------------------------------------------------------------------------------------- *
178 * @brief CreateStreamCpy
179 ** ------------------------------------------------------------------------------------------------------------- */
180void KernelBuilder::CreateStreamCpy(const std::string & name, Value * target, Value * targetOffset, Value * source, Value * sourceOffset, Value * itemsToCopy, const unsigned itemAlignment) {
181
182    assert (target && targetOffset);
183    assert (source && sourceOffset);
184    assert (target->getType() == source->getType());
185    assert (target->getType()->isPointerTy());
[5757]186    assert (isConstantZero(targetOffset) || isConstantZero(sourceOffset));
[5755]187
[5706]188    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
[5793]189
[5755]190    const auto itemWidth = getItemWidth(buf->getBaseType());
191    assert ("invalid item width" && is_power_2(itemWidth));
192    const auto blockWidth = getBitBlockWidth();
[5757]193    // Although our item width may be n bits, if we know we're always processing m items per block, our field width
194    // (w.r.t the stream copy) would be n*m. By taking this into account we can optimize and simplify the copy code.
[5755]195    const auto fieldWidth = getFieldWidth(itemWidth * itemAlignment, blockWidth);
[5793]196    const auto alignment = (fieldWidth + 7) / 8;
[5827]197
[5755]198    if (LLVM_LIKELY(itemWidth < fieldWidth)) {
[5793]199        const auto factor = fieldWidth / itemWidth;
200        Constant * const FACTOR = getSize(factor);
201        if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::EnableAsserts))) {
202            ConstantInt * const ALIGNMENT = getSize(alignment);
203            const auto kernelName = mKernel->getName()+ ": " + name;
204            CreateAssertZero(CreateURem(CreatePtrToInt(target, getSizeTy()), ALIGNMENT), kernelName + " target is misaligned (" + std::to_string(alignment) + ")");
205            CreateAssertZero(CreateURem(targetOffset, FACTOR), kernelName + " target offset is misaligned (" + std::to_string(factor) + ")");
206            CreateAssertZero(CreateURem(CreatePtrToInt(source, getSizeTy()), ALIGNMENT), kernelName + " source is misaligned (" + std::to_string(alignment) + ")");
207            CreateAssertZero(CreateURem(sourceOffset, FACTOR), kernelName + " source offset is misaligned (" + std::to_string(factor) + ")");
208        }
209        targetOffset = CreateUDiv(targetOffset, FACTOR);
210        sourceOffset = CreateUDiv(sourceOffset, FACTOR);
[5755]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
[5782]232       One compilication here is when the BlockSize of a stream is not equal to the BitBlockWidth.
233
234
[5755]235    */
236
[5757]237    Type * const fieldWidthTy = getIntNTy(fieldWidth);
238
[5755]239    Value * const n = buf->getStreamSetCount(this, getStreamHandle(name));
[5827]240
[5757]241    if (isConstantOne(n) || fieldWidth == blockWidth || (isConstantZero(targetOffset) && isConstantZero(sourceOffset))) {
[5755]242        if (isConstantOne(n)) {
243            if (LLVM_LIKELY(itemWidth < 8)) {
244                itemsToCopy = CreateUDivCeil(itemsToCopy, getSize(8 / itemWidth));
245            } else if (LLVM_UNLIKELY(itemWidth > 8)) {
246                itemsToCopy = CreateMul(itemsToCopy, getSize(itemWidth / 8));
247            }
248        } else {
[5757]249            if (LLVM_LIKELY(blockWidth > (itemWidth * 8))) {
250                itemsToCopy = CreateUDivCeil(itemsToCopy, getSize(blockWidth / (8 * itemWidth)));
251            } else if (LLVM_LIKELY(blockWidth < (itemWidth * 8))) {
252                itemsToCopy = CreateUDivCeil(CreateMul(itemsToCopy, getSize(8)), getSize(blockWidth / itemWidth));
253            }
254            itemsToCopy = CreateMul(itemsToCopy, n);
[5755]255        }
[5757]256        PointerType * const ptrTy = fieldWidthTy->getPointerTo();
257        target = CreateGEP(CreatePointerCast(target, ptrTy), targetOffset);
258        source = CreateGEP(CreatePointerCast(source, ptrTy), sourceOffset);
[5755]259        CreateMemCpy(target, source, itemsToCopy, alignment);
260
261    } else { // either the target offset or source offset is non-zero but not both
262
263        VectorType * const blockTy = getBitBlockType();
264        PointerType * const blockPtrTy = blockTy->getPointerTo();
265
[5827]266        target = CreatePointerCast(target, blockPtrTy, "target");
267        source = CreatePointerCast(source, blockPtrTy, "source");
[5755]268
[5757]269        assert ((blockWidth % fieldWidth) == 0);
270
[5755]271        VectorType * const shiftTy = VectorType::get(fieldWidthTy, blockWidth / fieldWidth);
272        Constant * const width = getSize(blockWidth / itemWidth);
[5827]273        Constant * const ZERO = getSize(0);
274        Constant * const ONE = getSize(1);
[5755]275        BasicBlock * const entry = GetInsertBlock();
276
277        if (isConstantZero(targetOffset)) {
278
279            /*
280                                                BLOCKS
281
282                                          A     B     C     D
283               SOURCE STREAM        1  |aaa--|bbbBB|cccCC|  dDD|
284                                    2  |eee--|fffFF|gggGG|  hHH|
285                                    3  |iii--|jjjJJ|kkkKK|  lLL|
286
287
288                                          A     B     C     D
289               TARGET STREAM        1  |BBaaa|CCbbb|DDccc|    d|
290                                    2  |FFeee|GGfff|HHggg|    h|
291                                    3  |JJiii|KKjjj|LLkkk|    l|
292             */
293
294            Value * const blocksToCopy = CreateMul(CreateUDiv(itemsToCopy, width), n);
295            Value * const offset = CreateURem(sourceOffset, width);
[5827]296            Value * const offsetVector = simd_fill(fieldWidth, CreateTrunc(offset, fieldWidthTy));
[5755]297            Value * const remaining = CreateSub(width, offset);
[5827]298            Value * const remainingVector = simd_fill(fieldWidth, CreateTrunc(remaining, fieldWidthTy));
[5755]299
[5827]300            BasicBlock * const streamCopy = CreateBasicBlock(name + "PullCopy");
301            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "PullCopyRemaining");
302            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "PullCopyEnd");
[5755]303
[5827]304            CreateCondBr(CreateICmpNE(blocksToCopy, ZERO), streamCopy, streamCopyRemaining);
[5755]305
306            SetInsertPoint(streamCopy);
307            PHINode * const i = CreatePHI(getSizeTy(), 2);
308            i->addIncoming(n, entry);
309            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(i, n)), alignment);
[5827]310            prior = CreateBitCast(CreateLShr(CreateBitCast(prior, shiftTy), offsetVector), blockTy);
[5755]311            Value * value = CreateAlignedLoad(CreateGEP(source, i), alignment);
[5827]312            value = CreateBitCast(CreateShl(CreateBitCast(value, shiftTy), remainingVector), blockTy);
313            CreateAlignedStore(CreateOr(value, prior), CreateGEP(target, i), alignment);
314            Value * const next_i = CreateAdd(i, ONE);
[5755]315            i->addIncoming(next_i, streamCopy);
316            CreateCondBr(CreateICmpNE(next_i, blocksToCopy), streamCopy, streamCopyRemaining);
317
318            SetInsertPoint(streamCopyRemaining);
319            PHINode * const j = CreatePHI(getSizeTy(), 2);
[5827]320            j->addIncoming(blocksToCopy, entry);
321            j->addIncoming(blocksToCopy, streamCopy);
322            Value * final = CreateAlignedLoad(CreateGEP(source, j), alignment);
323            final = CreateBitCast(CreateLShr(CreateBitCast(final, shiftTy), offsetVector), blockTy);
324            CreateAlignedStore(final, CreateGEP(target, j), alignment);
325            Value * const next_j = CreateAdd(j, ONE);
326            j->addIncoming(next_j, streamCopyRemaining);
327            CreateCondBr(CreateICmpNE(next_j, CreateAdd(blocksToCopy, n)), streamCopyRemaining, streamCopyEnd);
[5755]328
329            SetInsertPoint(streamCopyEnd);
330
331        } else if (isConstantZero(sourceOffset)) {
332
333            /*
334                                                BLOCKS
335
336                                          A     B     C     D
337               SOURCE STREAM        1  |AAAaa|BBBaa|CCCcc|    d|
338                                    2  |EEEee|FFFff|GGGgg|    h|
339                                    3  |IIIii|JJJjj|KKKkk|    l|
340
341
342                                          A     B     C     D
343               TARGET STREAM        1  |aa---|bbAAA|ccBBB| dCCC|
344                                    2  |ee---|ffEEE|ggFFF| hGGG|
345                                    3  |ii---|jjIII|kkJJJ| lKKK|
346
347            */
348
[5827]349            BasicBlock * const streamCopy = CreateBasicBlock(name + "PushCopy");
350            BasicBlock * const streamCopyRemainingCond = CreateBasicBlock(name + "PushCopyRemainingCond");
351            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "PushCopyRemaining");
352            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "PushCopyEnd");
[5755]353
[5827]354            Value * const pos = CreateURem(targetOffset, width);
355            Value * const copied = CreateSub(width, pos);
356            Value * const copiedVector = simd_fill(fieldWidth, CreateTrunc(copied, fieldWidthTy));
357            Value * const mask = CreateLShr(Constant::getAllOnesValue(shiftTy), copiedVector);
358            Value * const offsetVector = simd_fill(fieldWidth, CreateTrunc(pos, fieldWidthTy));
[5755]359
[5827]360            CreateBr(streamCopy);
361
[5755]362            SetInsertPoint(streamCopy);
363            PHINode * const i = CreatePHI(getSizeTy(), 2);
[5827]364            i->addIncoming(ZERO, entry);
365            Value * priorTargetValue = CreateAlignedLoad(CreateGEP(target, i), alignment);
366            priorTargetValue = CreateBitCast(CreateAnd(CreateBitCast(priorTargetValue, shiftTy), mask), blockTy);
[5755]367            Value * sourceValue = CreateAlignedLoad(CreateGEP(source, i), alignment);
[5827]368            sourceValue = CreateBitCast(CreateShl(CreateBitCast(sourceValue, shiftTy), offsetVector), blockTy);
369            CreateAlignedStore(CreateOr(sourceValue, priorTargetValue), CreateGEP(target, i), alignment);
370            Value * const next_i = CreateAdd(i, ONE);
[5755]371            i->addIncoming(next_i, streamCopy);
372            CreateCondBr(CreateICmpNE(next_i, n), streamCopy, streamCopyRemainingCond);
373
374            SetInsertPoint(streamCopyRemainingCond);
375            Value * const blocksToCopy = CreateMul(CreateUDiv(CreateSub(itemsToCopy, copied), width), n);
376            CreateCondBr(CreateICmpULT(copied, itemsToCopy), streamCopyRemaining, streamCopyEnd);
377
378            SetInsertPoint(streamCopyRemaining);
379            PHINode * const j = CreatePHI(getSizeTy(), 2);
[5827]380            j->addIncoming(n, streamCopyRemainingCond);
[5755]381            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(j, n)), alignment);
[5827]382            prior = CreateBitCast(CreateShl(CreateBitCast(prior, shiftTy), offsetVector), blockTy);
[5755]383            Value * value = CreateAlignedLoad(CreateGEP(source, j), alignment);
[5827]384            value = CreateBitCast(CreateLShr(CreateBitCast(value, shiftTy), copiedVector), blockTy);
385            CreateAlignedStore(CreateOr(value, prior), CreateGEP(target, j), alignment);
386            Value * const next_j = CreateAdd(j, ONE);
387            j->addIncoming(next_j, streamCopyRemaining);
[5755]388            CreateCondBr(CreateICmpNE(next_j, blocksToCopy), streamCopyRemaining, streamCopyEnd);
389
390            SetInsertPoint(streamCopyEnd);
391        }
392    }
[5435]393}
394
395Value * KernelBuilder::getConsumerLock(const std::string & name) {
396    return getScalarField(name + Kernel::CONSUMER_SUFFIX);
397}
398
399void KernelBuilder::setConsumerLock(const std::string & name, Value * value) {
400    setScalarField(name + Kernel::CONSUMER_SUFFIX, value);
401}
402
[5755]403Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * streamIndex) {
404    Value * const addr = mKernel->getStreamSetInputAddress(name);
405    if (addr) {
406        return CreateGEP(addr, {getInt32(0), streamIndex});
[5435]407    } else {
[5755]408        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
409        Value * const blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
410        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
[5435]411    }
412}
413
414Value * KernelBuilder::loadInputStreamBlock(const std::string & name, Value * streamIndex) {
415    return CreateBlockAlignedLoad(getInputStreamBlockPtr(name, streamIndex));
416}
417
418Value * KernelBuilder::getInputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
[5755]419    Value * const addr = mKernel->getStreamSetInputAddress(name);
420    if (addr) {
421        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
422    } else {
423        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
424        Value * const blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
425        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, true);
[5706]426    }
[5435]427}
428
429Value * KernelBuilder::loadInputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex) {
430    return CreateBlockAlignedLoad(getInputStreamPackPtr(name, streamIndex, packIndex));
431}
432
433Value * KernelBuilder::getInputStreamSetCount(const std::string & name) {
434    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
[5706]435    return buf->getStreamSetCount(this, getStreamHandle(name));
[5435]436}
437
[5782]438Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * const streamIndex, Value * const blockOffset) {
[5755]439    Value * const addr = mKernel->getStreamSetInputAddress(name);
440    if (addr) {
[5782]441        return CreateGEP(addr, {blockOffset, streamIndex});
[5755]442    } else {
443        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
444        Value * blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
[5782]445        blockIndex = CreateAdd(blockIndex, blockOffset);
[5755]446        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
[5706]447    }
[5435]448}
449
450Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex) {
[5755]451    Value * const addr = mKernel->getStreamSetOutputAddress(name);
452    if (addr) {
453        return CreateGEP(addr, {getInt32(0), streamIndex});
454    } else {
455        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
456        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
457        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, false);
[5706]458    }
[5435]459}
460
[5493]461StoreInst * KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
[5435]462    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
463}
464
465Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
[5755]466    Value * const addr = mKernel->getStreamSetOutputAddress(name);
467    if (addr) {
468        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
469    } else {
470        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
471        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
472        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, false);
[5706]473    }
[5435]474}
475
[5493]476StoreInst * KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
[5435]477    return CreateBlockAlignedStore(toStore, getOutputStreamPackPtr(name, streamIndex, packIndex));
478}
479
480Value * KernelBuilder::getOutputStreamSetCount(const std::string & name) {
481    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
[5706]482    return buf->getStreamSetCount(this, getStreamHandle(name));
[5435]483}
484
[5706]485Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * absolutePosition) {
[5435]486    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
[5706]487    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
[5435]488}
489
[5706]490Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * absolutePosition) {
[5435]491    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
[5706]492    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
[5435]493}
494
495Value * KernelBuilder::getBaseAddress(const std::string & name) {
[5706]496    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamHandle(name));
[5435]497}
498
499void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
[5706]500    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamHandle(name), addr);
[5435]501}
502
503Value * KernelBuilder::getBufferedSize(const std::string & name) {
[5706]504    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamHandle(name));
[5435]505}
506
507void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
[5706]508    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamHandle(name), size);
[5435]509}
510
[5501]511Value * KernelBuilder::getCapacity(const std::string & name) {
[5706]512    return mKernel->getAnyStreamSetBuffer(name)->getCapacity(this, getStreamHandle(name));
[5501]513}
514
515void KernelBuilder::setCapacity(const std::string & name, Value * c) {
[5706]516    mKernel->getAnyStreamSetBuffer(name)->setCapacity(this, getStreamHandle(name), c);
[5501]517}
518
[5755]519Value * KernelBuilder::getBlockAddress(const std::string & name, Value * blockIndex) {
520    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
521    return buf->getBlockAddress(this, getStreamHandle(name), blockIndex);
522}
523
524void KernelBuilder::protectOutputStream(const std::string & name, const bool readOnly) {
525    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
526    Value * const handle = getStreamHandle(name);
527    Value * const base = buf->getBaseAddress(this, handle);
528    Value * sz = ConstantExpr::getSizeOf(buf->getType());
529    sz = CreateMul(sz, getInt64(buf->getBufferBlocks()));
530    sz = CreateMul(sz, CreateZExt(buf->getStreamSetCount(this, handle), getInt64Ty()));
531    CreateMProtect(base, sz, readOnly ? CBuilder::READ : (CBuilder::READ | CBuilder::WRITE));
532}
[5501]533   
[5440]534CallInst * KernelBuilder::createDoSegmentCall(const std::vector<Value *> & args) {
[5706]535    return mKernel->makeDoSegmentCall(*this, args);
[5440]536}
537
538Value * KernelBuilder::getAccumulator(const std::string & accumName) {
539    auto results = mKernel->mOutputScalarResult;
540    if (LLVM_UNLIKELY(results == nullptr)) {
541        report_fatal_error("Cannot get accumulator " + accumName + " until " + mKernel->getName() + " has terminated.");
542    }
543    const auto & outputs = mKernel->getScalarOutputs();
544    const auto n = outputs.size();
545    if (LLVM_UNLIKELY(n == 0)) {
546        report_fatal_error(mKernel->getName() + " has no output scalars.");
547    } else {
548        for (unsigned i = 0; i < n; ++i) {
549            const Binding & b = outputs[i];
[5706]550            if (b.getName() == accumName) {
[5440]551                if (n == 1) {
552                    return results;
553                } else {
554                    return CreateExtractValue(results, {i});
555                }
556            }
557        }
558        report_fatal_error(mKernel->getName() + " has no output scalar named " + accumName);
559    }
560}
561
562BasicBlock * KernelBuilder::CreateConsumerWait() {
[5435]563    const auto consumers = mKernel->getStreamOutputs();
564    BasicBlock * const entry = GetInsertBlock();
565    if (consumers.empty()) {
566        return entry;
567    } else {
568        Function * const parent = entry->getParent();
569        IntegerType * const sizeTy = getSizeTy();
570        ConstantInt * const zero = getInt32(0);
571        ConstantInt * const one = getInt32(1);
572        ConstantInt * const size0 = getSize(0);
573
574        Value * const segNo = acquireLogicalSegmentNo();
575        const auto n = consumers.size();
576        BasicBlock * load[n + 1];
577        BasicBlock * wait[n];
578        for (unsigned i = 0; i < n; ++i) {
[5706]579            load[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Load", parent);
580            wait[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Wait", parent);
[5435]581        }
582        load[n] = BasicBlock::Create(getContext(), "Resume", parent);
583        CreateBr(load[0]);
584        for (unsigned i = 0; i < n; ++i) {
585
586            SetInsertPoint(load[i]);
[5706]587            Value * const outputConsumers = getConsumerLock(consumers[i].getName());
[5435]588
589            Value * const consumerCount = CreateLoad(CreateGEP(outputConsumers, {zero, zero}));
590            Value * const consumerPtr = CreateLoad(CreateGEP(outputConsumers, {zero, one}));
591            Value * const noConsumers = CreateICmpEQ(consumerCount, size0);
592            CreateUnlikelyCondBr(noConsumers, load[i + 1], wait[i]);
593
594            SetInsertPoint(wait[i]);
595            PHINode * const consumerPhi = CreatePHI(sizeTy, 2);
596            consumerPhi->addIncoming(size0, load[i]);
597
598            Value * const conSegPtr = CreateLoad(CreateGEP(consumerPtr, consumerPhi));
599            Value * const processedSegmentCount = CreateAtomicLoadAcquire(conSegPtr);
600            Value * const ready = CreateICmpEQ(segNo, processedSegmentCount);
601            assert (ready->getType() == getInt1Ty());
602            Value * const nextConsumerIdx = CreateAdd(consumerPhi, CreateZExt(ready, sizeTy));
603            consumerPhi->addIncoming(nextConsumerIdx, wait[i]);
604            Value * const next = CreateICmpEQ(nextConsumerIdx, consumerCount);
605            CreateCondBr(next, load[i + 1], wait[i]);
606        }
607
608        BasicBlock * const exit = load[n];
609        SetInsertPoint(exit);
610        return exit;
611    }
612}
613
614}
Note: See TracBrowser for help on using the repository browser.