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

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

UntilN kernel rewritten to use new MultiBlock? system

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
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::loadInputStreamBlock(const std::string & name, Value * streamIndex) {
404    return CreateBlockAlignedLoad(getInputStreamBlockPtr(name, streamIndex));
405}
406
407Value * KernelBuilder::getInputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
408    Value * const addr = mKernel->getStreamSetInputAddress(name);
409    if (addr) {
410        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
411    } else {
412        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
413        Value * const blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
414        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, true);
415    }
416}
417
418Value * KernelBuilder::loadInputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex) {
419    return CreateBlockAlignedLoad(getInputStreamPackPtr(name, streamIndex, packIndex));
420}
421
422Value * KernelBuilder::getInputStreamSetCount(const std::string & name) {
423    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
424    return buf->getStreamSetCount(this, getStreamHandle(name));
425}
426
427Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * const streamIndex, Value * const blockOffset) {
428    Value * const addr = mKernel->getStreamSetInputAddress(name);
429    if (addr) {
430        return CreateGEP(addr, {blockOffset, streamIndex});
431    } else {
432        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
433        Value * blockIndex = CreateLShr(getProcessedItemCount(name), std::log2(getBitBlockWidth()));
434        blockIndex = CreateAdd(blockIndex, blockOffset);
435        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, true);
436    }
437}
438
439Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex, Value * const blockOffset) {
440    Value * const addr = mKernel->getStreamSetOutputAddress(name);
441    if (addr) {
442        return CreateGEP(addr, {blockOffset, streamIndex});
443    } else {
444        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
445        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
446        return buf->getStreamBlockPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, false);
447    }
448}
449
450StoreInst * KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
451    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
452}
453
454Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
455    Value * const addr = mKernel->getStreamSetOutputAddress(name);
456    if (addr) {
457        return CreateGEP(addr, {getInt32(0), streamIndex, packIndex});
458    } else {
459        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
460        Value * const blockIndex = CreateLShr(getProducedItemCount(name), std::log2(getBitBlockWidth()));
461        return buf->getStreamPackPtr(this, getStreamHandle(name), getBaseAddress(name), streamIndex, blockIndex, packIndex, false);
462    }
463}
464
465StoreInst * KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
466    return CreateBlockAlignedStore(toStore, getOutputStreamPackPtr(name, streamIndex, packIndex));
467}
468
469Value * KernelBuilder::getOutputStreamSetCount(const std::string & name) {
470    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
471    return buf->getStreamSetCount(this, getStreamHandle(name));
472}
473
474Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * absolutePosition) {
475    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
476    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
477}
478
479Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * absolutePosition) {
480    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
481    return buf->getRawItemPointer(this, getStreamHandle(name), absolutePosition);
482}
483
484Value * KernelBuilder::getBaseAddress(const std::string & name) {
485    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamHandle(name));
486}
487
488void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
489    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamHandle(name), addr);
490}
491
492Value * KernelBuilder::getBufferedSize(const std::string & name) {
493    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamHandle(name));
494}
495
496void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
497    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamHandle(name), size);
498}
499
500Value * KernelBuilder::getCapacity(const std::string & name) {
501    return mKernel->getAnyStreamSetBuffer(name)->getCapacity(this, getStreamHandle(name));
502}
503
504void KernelBuilder::setCapacity(const std::string & name, Value * c) {
505    mKernel->getAnyStreamSetBuffer(name)->setCapacity(this, getStreamHandle(name), c);
506}
507
508Value * KernelBuilder::getBlockAddress(const std::string & name, Value * blockIndex) {
509    const StreamSetBuffer * const buf = mKernel->getAnyStreamSetBuffer(name);
510    return buf->getBlockAddress(this, getStreamHandle(name), blockIndex);
511}
512
513void KernelBuilder::protectOutputStream(const std::string & name, const bool readOnly) {
514    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
515    Value * const handle = getStreamHandle(name);
516    Value * const base = buf->getBaseAddress(this, handle);
517    Value * sz = ConstantExpr::getSizeOf(buf->getType());
518    sz = CreateMul(sz, getInt64(buf->getBufferBlocks()));
519    sz = CreateMul(sz, CreateZExt(buf->getStreamSetCount(this, handle), getInt64Ty()));
520    CreateMProtect(base, sz, readOnly ? CBuilder::READ : (CBuilder::READ | CBuilder::WRITE));
521}
522   
523CallInst * KernelBuilder::createDoSegmentCall(const std::vector<Value *> & args) {
524    return mKernel->makeDoSegmentCall(*this, args);
525}
526
527Value * KernelBuilder::getAccumulator(const std::string & accumName) {
528    auto results = mKernel->mOutputScalarResult;
529    if (LLVM_UNLIKELY(results == nullptr)) {
530        report_fatal_error("Cannot get accumulator " + accumName + " until " + mKernel->getName() + " has terminated.");
531    }
532    const auto & outputs = mKernel->getScalarOutputs();
533    const auto n = outputs.size();
534    if (LLVM_UNLIKELY(n == 0)) {
535        report_fatal_error(mKernel->getName() + " has no output scalars.");
536    } else {
537        for (unsigned i = 0; i < n; ++i) {
538            const Binding & b = outputs[i];
539            if (b.getName() == accumName) {
540                if (n == 1) {
541                    return results;
542                } else {
543                    return CreateExtractValue(results, {i});
544                }
545            }
546        }
547        report_fatal_error(mKernel->getName() + " has no output scalar named " + accumName);
548    }
549}
550
551BasicBlock * KernelBuilder::CreateConsumerWait() {
552    const auto consumers = mKernel->getStreamOutputs();
553    BasicBlock * const entry = GetInsertBlock();
554    if (consumers.empty()) {
555        return entry;
556    } else {
557        Function * const parent = entry->getParent();
558        IntegerType * const sizeTy = getSizeTy();
559        ConstantInt * const zero = getInt32(0);
560        ConstantInt * const one = getInt32(1);
561        ConstantInt * const size0 = getSize(0);
562
563        Value * const segNo = acquireLogicalSegmentNo();
564        const auto n = consumers.size();
565        BasicBlock * load[n + 1];
566        BasicBlock * wait[n];
567        for (unsigned i = 0; i < n; ++i) {
568            load[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Load", parent);
569            wait[i] = BasicBlock::Create(getContext(), consumers[i].getName() + "Wait", parent);
570        }
571        load[n] = BasicBlock::Create(getContext(), "Resume", parent);
572        CreateBr(load[0]);
573        for (unsigned i = 0; i < n; ++i) {
574
575            SetInsertPoint(load[i]);
576            Value * const outputConsumers = getConsumerLock(consumers[i].getName());
577
578            Value * const consumerCount = CreateLoad(CreateGEP(outputConsumers, {zero, zero}));
579            Value * const consumerPtr = CreateLoad(CreateGEP(outputConsumers, {zero, one}));
580            Value * const noConsumers = CreateICmpEQ(consumerCount, size0);
581            CreateUnlikelyCondBr(noConsumers, load[i + 1], wait[i]);
582
583            SetInsertPoint(wait[i]);
584            PHINode * const consumerPhi = CreatePHI(sizeTy, 2);
585            consumerPhi->addIncoming(size0, load[i]);
586
587            Value * const conSegPtr = CreateLoad(CreateGEP(consumerPtr, consumerPhi));
588            Value * const processedSegmentCount = CreateAtomicLoadAcquire(conSegPtr);
589            Value * const ready = CreateICmpEQ(segNo, processedSegmentCount);
590            assert (ready->getType() == getInt1Ty());
591            Value * const nextConsumerIdx = CreateAdd(consumerPhi, CreateZExt(ready, sizeTy));
592            consumerPhi->addIncoming(nextConsumerIdx, wait[i]);
593            Value * const next = CreateICmpEQ(nextConsumerIdx, consumerCount);
594            CreateCondBr(next, load[i + 1], wait[i]);
595        }
596
597        BasicBlock * const exit = load[n];
598        SetInsertPoint(exit);
599        return exit;
600    }
601}
602
603}
Note: See TracBrowser for help on using the repository browser.