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

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

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

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