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

Last change on this file since 5967 was 5967, checked in by nmedfort, 12 months ago

Updated LZ4SwizzledMatchCopy + minor changes

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