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

Last change on this file since 5852 was 5852, checked in by xwa163, 15 months ago
  1. Use MemCpy? instead of streamCpy when handling buffer CopyBack?
  2. Rollback change of kernel_builder
  3. Fix bug of SwizzledDeleteByPEXTkernel when input data file is large
  4. Add large test cases for character_deletion
File size: 27.7 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        VectorType * const blockTy = getBitBlockType();
263        PointerType * const blockPtrTy = blockTy->getPointerTo();
264
265        target = CreatePointerCast(target, blockPtrTy, "target");
266        source = CreatePointerCast(source, blockPtrTy, "source");
267
268        assert ((blockWidth % fieldWidth) == 0);
269
270        VectorType * const shiftTy = VectorType::get(fieldWidthTy, blockWidth / fieldWidth);
271        Constant * const width = getSize(blockWidth / itemWidth);
272        Constant * const ZERO = getSize(0);
273        Constant * const ONE = getSize(1);
274        BasicBlock * const entry = GetInsertBlock();
275
276        if (isConstantZero(targetOffset)) {
277
278            /*
279                                                BLOCKS
280
281                                          A     B     C     D
282               SOURCE STREAM        1  |aaa--|bbbBB|cccCC|  dDD|
283                                    2  |eee--|fffFF|gggGG|  hHH|
284                                    3  |iii--|jjjJJ|kkkKK|  lLL|
285
286
287                                          A     B     C     D
288               TARGET STREAM        1  |BBaaa|CCbbb|DDccc|    d|
289                                    2  |FFeee|GGfff|HHggg|    h|
290                                    3  |JJiii|KKjjj|LLkkk|    l|
291             */
292
293            Value * const blocksToCopy = CreateMul(CreateUDiv(itemsToCopy, width), n);
294            Value * const offset = CreateURem(sourceOffset, width);
295            Value * const offsetVector = simd_fill(fieldWidth, CreateTrunc(offset, fieldWidthTy));
296            Value * const remaining = CreateSub(width, offset);
297            Value * const remainingVector = simd_fill(fieldWidth, CreateTrunc(remaining, fieldWidthTy));
298
299            BasicBlock * const streamCopy = CreateBasicBlock(name + "PullCopy");
300            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "PullCopyRemaining");
301            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "PullCopyEnd");
302
303            CreateCondBr(CreateICmpNE(blocksToCopy, ZERO), streamCopy, streamCopyRemaining);
304
305            SetInsertPoint(streamCopy);
306            PHINode * const i = CreatePHI(getSizeTy(), 2);
307            i->addIncoming(n, entry);
308            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(i, n)), alignment);
309            prior = CreateBitCast(CreateLShr(CreateBitCast(prior, shiftTy), offsetVector), blockTy);
310            Value * value = CreateAlignedLoad(CreateGEP(source, i), alignment);
311            value = CreateBitCast(CreateShl(CreateBitCast(value, shiftTy), remainingVector), blockTy);
312            CreateAlignedStore(CreateOr(value, prior), CreateGEP(target, i), alignment);
313            Value * const next_i = CreateAdd(i, ONE);
314            i->addIncoming(next_i, streamCopy);
315            CreateCondBr(CreateICmpNE(next_i, blocksToCopy), streamCopy, streamCopyRemaining);
316
317            SetInsertPoint(streamCopyRemaining);
318            PHINode * const j = CreatePHI(getSizeTy(), 2);
319            j->addIncoming(blocksToCopy, entry);
320            j->addIncoming(blocksToCopy, streamCopy);
321            Value * final = CreateAlignedLoad(CreateGEP(source, j), alignment);
322            final = CreateBitCast(CreateLShr(CreateBitCast(final, shiftTy), offsetVector), blockTy);
323            CreateAlignedStore(final, CreateGEP(target, j), alignment);
324            Value * const next_j = CreateAdd(j, ONE);
325            j->addIncoming(next_j, streamCopyRemaining);
326            CreateCondBr(CreateICmpNE(next_j, CreateAdd(blocksToCopy, n)), streamCopyRemaining, streamCopyEnd);
327
328            SetInsertPoint(streamCopyEnd);
329
330        } else if (isConstantZero(sourceOffset)) {
331
332            /*
333                                                BLOCKS
334
335                                          A     B     C     D
336               SOURCE STREAM        1  |AAAaa|BBBaa|CCCcc|    d|
337                                    2  |EEEee|FFFff|GGGgg|    h|
338                                    3  |IIIii|JJJjj|KKKkk|    l|
339
340
341                                          A     B     C     D
342               TARGET STREAM        1  |aa---|bbAAA|ccBBB| dCCC|
343                                    2  |ee---|ffEEE|ggFFF| hGGG|
344                                    3  |ii---|jjIII|kkJJJ| lKKK|
345
346            */
347
348            BasicBlock * const streamCopy = CreateBasicBlock(name + "PushCopy");
349            BasicBlock * const streamCopyRemainingCond = CreateBasicBlock(name + "PushCopyRemainingCond");
350            BasicBlock * const streamCopyRemaining = CreateBasicBlock(name + "PushCopyRemaining");
351            BasicBlock * const streamCopyEnd = CreateBasicBlock(name + "PushCopyEnd");
352
353            Value * const pos = CreateURem(targetOffset, width);
354            Value * const copied = CreateSub(width, pos);
355            Value * const copiedVector = simd_fill(fieldWidth, CreateTrunc(copied, fieldWidthTy));
356            Value * const mask = CreateLShr(Constant::getAllOnesValue(shiftTy), copiedVector);
357            Value * const offsetVector = simd_fill(fieldWidth, CreateTrunc(pos, fieldWidthTy));
358
359            CreateBr(streamCopy);
360
361            SetInsertPoint(streamCopy);
362            PHINode * const i = CreatePHI(getSizeTy(), 2);
363            i->addIncoming(ZERO, entry);
364            Value * priorTargetValue = CreateAlignedLoad(CreateGEP(target, i), alignment);
365            priorTargetValue = CreateBitCast(CreateAnd(CreateBitCast(priorTargetValue, shiftTy), mask), blockTy);
366            Value * sourceValue = CreateAlignedLoad(CreateGEP(source, i), alignment);
367            sourceValue = CreateBitCast(CreateShl(CreateBitCast(sourceValue, shiftTy), offsetVector), blockTy);
368            CreateAlignedStore(CreateOr(sourceValue, priorTargetValue), CreateGEP(target, i), alignment);
369            Value * const next_i = CreateAdd(i, ONE);
370            i->addIncoming(next_i, streamCopy);
371            CreateCondBr(CreateICmpNE(next_i, n), streamCopy, streamCopyRemainingCond);
372
373            SetInsertPoint(streamCopyRemainingCond);
374            Value * const blocksToCopy = CreateMul(CreateUDiv(CreateSub(itemsToCopy, copied), width), n);
375            CreateCondBr(CreateICmpULT(copied, itemsToCopy), streamCopyRemaining, streamCopyEnd);
376
377            SetInsertPoint(streamCopyRemaining);
378            PHINode * const j = CreatePHI(getSizeTy(), 2);
379            j->addIncoming(n, streamCopyRemainingCond);
380            Value * prior = CreateAlignedLoad(CreateGEP(source, CreateSub(j, n)), alignment);
381            prior = CreateBitCast(CreateShl(CreateBitCast(prior, shiftTy), offsetVector), blockTy);
382            Value * value = CreateAlignedLoad(CreateGEP(source, j), alignment);
383            value = CreateBitCast(CreateLShr(CreateBitCast(value, shiftTy), copiedVector), blockTy);
384            CreateAlignedStore(CreateOr(value, prior), CreateGEP(target, j), alignment);
385            Value * const next_j = CreateAdd(j, ONE);
386            j->addIncoming(next_j, streamCopyRemaining);
387            CreateCondBr(CreateICmpNE(next_j, blocksToCopy), streamCopyRemaining, streamCopyEnd);
388
389            SetInsertPoint(streamCopyEnd);
390        }
391    }
392}
393
394Value * KernelBuilder::getConsumerLock(const std::string & name) {
395    return getScalarField(name + Kernel::CONSUMER_SUFFIX);
396}
397
398void KernelBuilder::setConsumerLock(const std::string & name, Value * value) {
399    setScalarField(name + Kernel::CONSUMER_SUFFIX, value);
400}
401
402Value * KernelBuilder::loadInputStreamBlock(const std::string & name, Value * streamIndex) {
403    return CreateBlockAlignedLoad(getInputStreamBlockPtr(name, streamIndex));
404}
405
406Value * KernelBuilder::getInputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
407    Value * const addr = mKernel->getStreamSetInputAddress(name);
408    if (addr) {
409        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
410    } else {
411        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
412        Value * const blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
413        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, true);
414    }
415}
416
417Value * KernelBuilder::loadInputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex) {
418    return CreateBlockAlignedLoad(getInputStreamPackPtr(name, streamIndex, packIndex));
419}
420
421Value * KernelBuilder::getInputStreamSetCount(const std::string & name) {
422    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
423    return buf->getStreamSetCount(this, getStreamHandle(name));
424}
425
426Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * const streamIndex, Value * const blockOffset) {
427    Value * const addr = mKernel->getStreamSetInputAddress(name);
428    if (addr) {
429        return CreateGEP(addr, {blockOffset, streamIndex});
430    } else {
431        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
432        Value * blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
433        blockIndex = CreateAdd(blockIndex, blockOffset);
434        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
435    }
436}
437
438Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex, Value * const blockOffset) {
439    Value * const addr = mKernel->getStreamSetOutputAddress(name);
440    if (addr) {
441        return CreateGEP(addr, {blockOffset, streamIndex});
442    } else {
443        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
444        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
445        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, false);
446    }
447}
448
449StoreInst * KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
450    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
451}
452
453Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
454    Value * const addr = mKernel->getStreamSetOutputAddress(name);
455    if (addr) {
456        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
457    } else {
458        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
459        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
460        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, false);
461    }
462}
463
464StoreInst * KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
465    return CreateBlockAlignedStore(toStore, getOutputStreamPackPtr(name, streamIndex, packIndex));
466}
467
468Value * KernelBuilder::getOutputStreamSetCount(const std::string & name) {
469    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
470    return buf->getStreamSetCount(this, getStreamHandle(name));
471}
472
473Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * absolutePosition) {
474    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
475    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
476}
477
478Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * absolutePosition) {
479    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
480    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
481}
482
483Value * KernelBuilder::getBaseAddress(const std::string & name) {
484    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamHandle(name));
485}
486
487void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
488    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamHandle(name), addr);
489}
490
491Value * KernelBuilder::getBufferedSize(const std::string & name) {
492    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamHandle(name));
493}
494
495void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
496    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamHandle(name), size);
497}
498
499Value * KernelBuilder::getCapacity(const std::string & name) {
500    return mKernel->getAnyStreamSetBuffer(name)->getCapacity(this, getStreamHandle(name));
501}
502
503void KernelBuilder::setCapacity(const std::string & name, Value * c) {
504    mKernel->getAnyStreamSetBuffer(name)->setCapacity(this, getStreamHandle(name), c);
505}
506
507Value * KernelBuilder::getBlockAddress(const std::string & name, Value * blockIndex) {
508    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
509    return buf->getBlockAddress(this, getStreamHandle(name), blockIndex);
510}
511
512void KernelBuilder::protectOutputStream(const std::string & name, const bool readOnly) {
513    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
514    Value * const handle = getStreamHandle(name);
515    Value * const base = buf->getBaseAddress(this, handle);
516    Value * sz = ConstantExpr::getSizeOf(buf->getType());
517    sz = CreateMul(sz, getInt64(buf->getBufferBlocks()));
518    sz = CreateMul(sz, CreateZExt(buf->getStreamSetCount(this, handle), getInt64Ty()));
519    CreateMProtect(base, sz, readOnly ? CBuilder::READ : (CBuilder::READ | CBuilder::WRITE));
520}
521   
522CallInst * KernelBuilder::createDoSegmentCall(const std::vector<Value *> & args) {
523    return mKernel->makeDoSegmentCall(*this, args);
524}
525
526Value * KernelBuilder::getAccumulator(const std::string & accumName) {
527    auto results = mKernel->mOutputScalarResult;
528    if (LLVM_UNLIKELY(results == nullptr)) {
529        report_fatal_error("Cannot get accumulator " + accumName + " until " + mKernel->getName() + " has terminated.");
530    }
531    const auto & outputs = mKernel->getScalarOutputs();
532    const auto n = outputs.size();
533    if (LLVM_UNLIKELY(n == 0)) {
534        report_fatal_error(mKernel->getName() + " has no output scalars.");
535    } else {
536        for (unsigned i = 0; i < n; ++i) {
537            const Binding & b = outputs[i];
538            if (b.getName() == accumName) {
539                if (n == 1) {
540                    return results;
541                } else {
542                    return CreateExtractValue(results, {i});
543                }
544            }
545        }
546        report_fatal_error(mKernel->getName() + " has no output scalar named " + accumName);
547    }
548}
549
550BasicBlock * KernelBuilder::CreateConsumerWait() {
551    const auto consumers = mKernel->getStreamOutputs();
552    BasicBlock * const entry = GetInsertBlock();
553    if (consumers.empty()) {
554        return entry;
555    } else {
556        Function * const parent = entry->getParent();
557        IntegerType * const sizeTy = getSizeTy();
558        ConstantInt * const zero = getInt32(0);
559        ConstantInt * const one = getInt32(1);
560        ConstantInt * const size0 = getSize(0);
561
562        Value * const segNo = acquireLogicalSegmentNo();
563        const auto n = consumers.size();
564        BasicBlock * load[n + 1];
565        BasicBlock * wait[n];
566        for (unsigned i = 0; i < n; ++i) {
567            load[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Load", parent);
568            wait[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Wait", parent);
569        }
570        load[n] = BasicBlock::Create(getContext(), "Resume", parent);
571        CreateBr(load[0]);
572        for (unsigned i = 0; i < n; ++i) {
573
574            SetInsertPoint(load[i]);
575            Value * const outputConsumers = getConsumerLock(consumers[i].getName());
576
577            Value * const consumerCount = CreateLoad(CreateGEP(outputConsumers, {zero, zero}));
578            Value * const consumerPtr = CreateLoad(CreateGEP(outputConsumers, {zero, one}));
579            Value * const noConsumers = CreateICmpEQ(consumerCount, size0);
580            CreateUnlikelyCondBr(noConsumers, load[i + 1], wait[i]);
581
582            SetInsertPoint(wait[i]);
583            PHINode * const consumerPhi = CreatePHI(sizeTy, 2);
584            consumerPhi->addIncoming(size0, load[i]);
585
586            Value * const conSegPtr = CreateLoad(CreateGEP(consumerPtr, consumerPhi));
587            Value * const processedSegmentCount = CreateAtomicLoadAcquire(conSegPtr);
588            Value * const ready = CreateICmpEQ(segNo, processedSegmentCount);
589            assert (ready->getType() == getInt1Ty());
590            Value * const nextConsumerIdx = CreateAdd(consumerPhi, CreateZExt(ready, sizeTy));
591            consumerPhi->addIncoming(nextConsumerIdx, wait[i]);
592            Value * const next = CreateICmpEQ(nextConsumerIdx, consumerCount);
593            CreateCondBr(next, load[i + 1], wait[i]);
594        }
595
596        BasicBlock * const exit = load[n];
597        SetInsertPoint(exit);
598        return exit;
599    }
600}
601
602}
Note: See TracBrowser for help on using the repository browser.