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

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

Compilation bug fix for CreateStreamCpy?. Needs more testing.

File size: 28.2 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 if (LLVM_UNLIKELY(rate.isPopCount())) {
85        Port port; unsigned index;
86        std::tie(port, index) = mKernel->getStreamPort(rate.getReference());
87
88
89
90
91    } else {
92        itemCount = getScalarField(name + suffix);
93    }
94    return itemCount;
95}
96
97void KernelBuilder::setInternalItemCount(const std::string & name, const std::string & suffix, llvm::Value * const value) {
98    const ProcessingRate & rate = mKernel->getBinding(name).getRate();
99    if (LLVM_UNLIKELY(rate.isDerived())) {
100        report_fatal_error("Cannot set item count: " + name + " is a Derived rate");
101    }
102    if (codegen::DebugOptionIsSet(codegen::TraceCounts)) {
103        CallPrintIntToStderr(mKernel->getName() + ": " + name + suffix, value);
104    }
105    setScalarField(name + suffix, value);
106}
107
108
109Value * KernelBuilder::getAvailableItemCount(const std::string & name) {
110    const auto & inputs = mKernel->getStreamInputs();
111    for (unsigned i = 0; i < inputs.size(); ++i) {
112        if (inputs[i].getName() == name) {
113            return mKernel->getAvailableItemCount(i);
114        }
115    }
116    return nullptr;
117}
118
119Value * KernelBuilder::getTerminationSignal() {
120    return CreateICmpNE(getScalarField(Kernel::TERMINATION_SIGNAL), getSize(0));
121}
122
123void KernelBuilder::setTerminationSignal(llvm::Value * const value) {
124    assert (value->getType() == getInt1Ty());
125    if (codegen::DebugOptionIsSet(codegen::TraceCounts)) {
126        CallPrintIntToStderr(mKernel->getName() + ": setTerminationSignal", value);
127    }
128    setScalarField(Kernel::TERMINATION_SIGNAL, CreateZExt(value, getSizeTy()));
129}
130
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);
134}
135
136Value * KernelBuilder::getLinearlyWritableItems(const std::string & name, Value * fromPosition, bool reverse) {
137    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
138    return buf->getLinearlyWritableItems(this, getStreamHandle(name), fromPosition, getConsumedItemCount(name), reverse);
139}
140
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) {
169    for (unsigned k = 16; k <= blockWidth; k *= 2) {
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());
186    assert (isConstantZero(targetOffset) || isConstantZero(sourceOffset));
187
188    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
189
190    const auto itemWidth = getItemWidth(buf->getBaseType());
191    assert ("invalid item width" && is_power_2(itemWidth));
192    const auto blockWidth = getBitBlockWidth();
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.
195    const auto fieldWidth = getFieldWidth(itemWidth * itemAlignment, blockWidth);
196    const auto alignment = (fieldWidth + 7) / 8;
197
198    if (LLVM_LIKELY(itemWidth < fieldWidth)) {
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);
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       One compilication here is when the BlockSize of a stream is not equal to the BitBlockWidth.
233
234
235    */
236
237    Type * const fieldWidthTy = getIntNTy(fieldWidth);
238
239    Value * const n = buf->getStreamSetCount(this, getStreamHandle(name));
240
241    if (isConstantOne(n) || fieldWidth == blockWidth || (isConstantZero(targetOffset) && isConstantZero(sourceOffset))) {
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 {
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);
255        }
256        PointerType * const ptrTy = fieldWidthTy->getPointerTo();
257        target = CreateGEP(CreatePointerCast(target, ptrTy), targetOffset);
258        source = CreateGEP(CreatePointerCast(source, ptrTy), sourceOffset);
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
266        target = CreatePointerCast(target, blockPtrTy, "target");
267        source = CreatePointerCast(source, blockPtrTy, "source");
268
269        assert ((blockWidth % fieldWidth) == 0);
270
271        VectorType * const shiftTy = VectorType::get(fieldWidthTy, blockWidth / fieldWidth);
272        Constant * const width = getSize(blockWidth / itemWidth);
273        Constant * const ZERO = getSize(0);
274        Constant * const ONE = getSize(1);
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);
296            Value * const offsetVector = simd_fill(fieldWidth, CreateTrunc(offset, fieldWidthTy));
297            Value * const remaining = CreateSub(width, offset);
298            Value * const remainingVector = simd_fill(fieldWidth, CreateTrunc(remaining, fieldWidthTy));
299
300            BasicBlock * const streamCopy = CreateBasicBlock(name + "PullCopy");
301            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "PullCopyRemaining");
302            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "PullCopyEnd");
303
304            CreateCondBr(CreateICmpNE(blocksToCopy, ZERO), streamCopy, streamCopyRemaining);
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);
310            prior = CreateBitCast(CreateLShr(CreateBitCast(prior, shiftTy), offsetVector), blockTy);
311            Value * value = CreateAlignedLoad(CreateGEP(source, i), alignment);
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);
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);
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);
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
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");
353
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));
359
360            CreateBr(streamCopy);
361
362            SetInsertPoint(streamCopy);
363            PHINode * const i = CreatePHI(getSizeTy(), 2);
364            i->addIncoming(ZERO, entry);
365            Value * priorTargetValue = CreateAlignedLoad(CreateGEP(target, i), alignment);
366            priorTargetValue = CreateBitCast(CreateAnd(CreateBitCast(priorTargetValue, shiftTy), mask), blockTy);
367            Value * sourceValue = CreateAlignedLoad(CreateGEP(source, i), alignment);
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);
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);
380            j->addIncoming(n, streamCopyRemainingCond);
381            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(j, n)), alignment);
382            prior = CreateBitCast(CreateShl(CreateBitCast(prior, shiftTy), offsetVector), blockTy);
383            Value * value = CreateAlignedLoad(CreateGEP(source, j), alignment);
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);
388            CreateCondBr(CreateICmpNE(next_j, blocksToCopy), streamCopyRemaining, streamCopyEnd);
389
390            SetInsertPoint(streamCopyEnd);
391        }
392    }
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
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});
407    } else {
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);
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) {
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);
426    }
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);
435    return buf->getStreamSetCount(this, getStreamHandle(name));
436}
437
438Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * const streamIndex, Value * const blockOffset) {
439    Value * const addr = mKernel->getStreamSetInputAddress(name);
440    if (addr) {
441        return CreateGEP(addr, {blockOffset, streamIndex});
442    } else {
443        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
444        Value * blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
445        blockIndex = CreateAdd(blockIndex, blockOffset);
446        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
447    }
448}
449
450Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex) {
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);
458    }
459}
460
461StoreInst * KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
462    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
463}
464
465Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
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);
473    }
474}
475
476StoreInst * KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
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);
482    return buf->getStreamSetCount(this, getStreamHandle(name));
483}
484
485Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * absolutePosition) {
486    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
487    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
488}
489
490Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * absolutePosition) {
491    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
492    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
493}
494
495Value * KernelBuilder::getBaseAddress(const std::string & name) {
496    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamHandle(name));
497}
498
499void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
500    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamHandle(name), addr);
501}
502
503Value * KernelBuilder::getBufferedSize(const std::string & name) {
504    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamHandle(name));
505}
506
507void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
508    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamHandle(name), size);
509}
510
511Value * KernelBuilder::getCapacity(const std::string & name) {
512    return mKernel->getAnyStreamSetBuffer(name)->getCapacity(this, getStreamHandle(name));
513}
514
515void KernelBuilder::setCapacity(const std::string & name, Value * c) {
516    mKernel->getAnyStreamSetBuffer(name)->setCapacity(this, getStreamHandle(name), c);
517}
518
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}
533   
534CallInst * KernelBuilder::createDoSegmentCall(const std::vector<Value *> & args) {
535    return mKernel->makeDoSegmentCall(*this, args);
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];
550            if (b.getName() == accumName) {
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() {
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) {
579            load[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Load", parent);
580            wait[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Wait", parent);
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]);
587            Value * const outputConsumers = getConsumerLock(consumers[i].getName());
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.