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

Last change on this file since 5436 was 5436, checked in by nmedfort, 2 years ago

Continued refactoring work. PabloKernel? now abstract base type with a 'generatePabloMethod' hook to generate Pablo code.

File size: 11.7 KB
Line 
1#include "kernel_builder.h"
2#include <kernels/kernel.h>
3#include <kernels/streamset.h>
4
5using namespace llvm;
6using namespace parabix;
7
8using Value = Value;
9
10namespace kernel {
11
12Value * KernelBuilder::getScalarFieldPtr(Value * const index) {
13    return CreateGEP(mKernel->getInstance(), {getInt32(0), index});
14}
15
16Value * KernelBuilder::getScalarFieldPtr(const std::string & fieldName) {
17    return getScalarFieldPtr(getInt32(mKernel->getScalarIndex(fieldName)));
18}
19
20Value * KernelBuilder::getScalarField(const std::string & fieldName) {
21    return CreateLoad(getScalarFieldPtr(fieldName), fieldName);
22}
23
24void KernelBuilder::setScalarField(const std::string & fieldName, Value * value) {
25    CreateStore(value, getScalarFieldPtr(fieldName));
26}
27
28Value * KernelBuilder::getStreamSetBufferPtr(const std::string & name) {
29    return getScalarField(name + Kernel::BUFFER_PTR_SUFFIX);
30}
31
32LoadInst * KernelBuilder::acquireLogicalSegmentNo() {
33    return CreateAtomicLoadAcquire(getScalarFieldPtr(Kernel::LOGICAL_SEGMENT_NO_SCALAR));
34}
35
36void KernelBuilder::releaseLogicalSegmentNo(Value * nextSegNo) {
37    CreateAtomicStoreRelease(nextSegNo, getScalarFieldPtr(Kernel::LOGICAL_SEGMENT_NO_SCALAR));
38}
39
40Value * KernelBuilder::getProducedItemCount(const std::string & name, Value * doFinal) {
41    Kernel::Port port; unsigned index;
42    std::tie(port, index) = mKernel->getStreamPort(name);
43    assert (port == Kernel::Port::Output);
44    const auto rate = mKernel->getStreamOutput(index).rate;
45    if (rate.isExact()) {
46        const auto & refSet = rate.referenceStreamSet();
47        std::string principalField;
48        if (refSet.empty()) {
49            const auto & principleSet = mKernel->getStreamOutput(0).name;
50            if (mKernel->getStreamInputs().empty()) {
51                principalField = principleSet + Kernel::PRODUCED_ITEM_COUNT_SUFFIX;
52            } else {
53                principalField = principleSet + Kernel::PROCESSED_ITEM_COUNT_SUFFIX;
54            }
55        } else {
56            std::tie(port, index) = mKernel->getStreamPort(refSet);
57            if (port == Kernel::Port::Input) {
58               principalField = refSet + Kernel::PROCESSED_ITEM_COUNT_SUFFIX;
59            } else {
60               principalField = refSet + Kernel::PRODUCED_ITEM_COUNT_SUFFIX;
61            }
62        }
63        Value * const principleCount = getScalarField(principalField);
64        return rate.CreateRatioCalculation(this, principleCount, doFinal);
65    }
66    return getScalarField(name + Kernel::PRODUCED_ITEM_COUNT_SUFFIX);
67}
68
69Value * KernelBuilder::getProcessedItemCount(const std::string & name) {
70    Kernel::Port port; unsigned index;
71    std::tie(port, index) = mKernel->getStreamPort(name);
72    assert (port == Kernel::Port::Input);
73    const auto & rate = mKernel->getStreamInput(index).rate;
74    if (rate.isExact()) {
75        std::string refSet = rate.referenceStreamSet();
76        if (refSet.empty()) {
77            refSet = mKernel->getStreamInput(0).name;
78        }
79        Value * const principleCount = getScalarField(refSet + Kernel::PROCESSED_ITEM_COUNT_SUFFIX);
80        return rate.CreateRatioCalculation(this, principleCount);
81    }
82    return getScalarField(name + Kernel::PROCESSED_ITEM_COUNT_SUFFIX);
83}
84
85Value * KernelBuilder::getAvailableItemCount(const std::string & name) {
86//    for (unsigned i = 0; i < mStreamSetInputs.size(); ++i) {
87//        if (mStreamSetInputs[i].name == name) {
88//            return mAvailableItemCount[i];
89//        }
90//    }
91    return nullptr;
92}
93
94Value * KernelBuilder::getConsumedItemCount(const std::string & name) {
95    return getScalarField(name + Kernel::CONSUMED_ITEM_COUNT_SUFFIX);
96}
97
98void KernelBuilder::setProducedItemCount(const std::string & name, Value * value) {
99    setScalarField(name + Kernel::PRODUCED_ITEM_COUNT_SUFFIX, value);
100}
101
102void KernelBuilder::setProcessedItemCount(const std::string & name, Value * value) {
103    setScalarField(name + Kernel::PROCESSED_ITEM_COUNT_SUFFIX, value);
104}
105
106void KernelBuilder::setConsumedItemCount(const std::string & name, Value * value) {
107    setScalarField(name + Kernel::CONSUMED_ITEM_COUNT_SUFFIX, value);
108}
109
110Value * KernelBuilder::getTerminationSignal() {
111    return getScalarField(Kernel::TERMINATION_SIGNAL);
112}
113
114void KernelBuilder::setTerminationSignal() {
115    setScalarField(Kernel::TERMINATION_SIGNAL, getTrue());
116}
117
118Value * KernelBuilder::getLinearlyAccessibleItems(const std::string & name, Value * fromPosition) {
119    Value * instance = getStreamSetBufferPtr(name);
120    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
121    return buf->getLinearlyAccessibleItems(this, instance, fromPosition);
122}
123
124Value * KernelBuilder::getConsumerLock(const std::string & name) {
125    return getScalarField(name + Kernel::CONSUMER_SUFFIX);
126}
127
128void KernelBuilder::setConsumerLock(const std::string & name, Value * value) {
129    setScalarField(name + Kernel::CONSUMER_SUFFIX, value);
130}
131
132inline Value * KernelBuilder::computeBlockIndex(Value * itemCount) {
133    const auto divisor = getBitBlockWidth();
134    if (LLVM_LIKELY((divisor & (divisor - 1)) == 0)) {
135        return CreateLShr(itemCount, std::log2(divisor));
136    } else {
137        return CreateUDiv(itemCount, getSize(divisor));
138    }
139}
140
141Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * streamIndex) {
142    Value * const blockIndex = computeBlockIndex(getProcessedItemCount(name));
143    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
144    return buf->getStreamBlockPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, true);
145}
146
147Value * KernelBuilder::loadInputStreamBlock(const std::string & name, Value * streamIndex) {
148    return CreateBlockAlignedLoad(getInputStreamBlockPtr(name, streamIndex));
149}
150
151Value * KernelBuilder::getInputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
152    Value * const blockIndex = computeBlockIndex(getProcessedItemCount(name));
153    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
154    return buf->getStreamPackPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, packIndex, true);
155}
156
157Value * KernelBuilder::loadInputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex) {
158    return CreateBlockAlignedLoad(getInputStreamPackPtr(name, streamIndex, packIndex));
159}
160
161Value * KernelBuilder::getInputStreamSetCount(const std::string & name) {
162    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
163    return buf->getStreamSetCount(this, getStreamSetBufferPtr(name));
164}
165
166Value * KernelBuilder::getAdjustedInputStreamBlockPtr(Value * blockAdjustment, const std::string & name, Value * streamIndex) {
167    Value * const blockIndex = CreateAdd(computeBlockIndex(getProcessedItemCount(name)), blockAdjustment);
168    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
169    return buf->getStreamBlockPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, true);
170}
171
172Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex) {
173    Value * const blockIndex = computeBlockIndex(getProducedItemCount(name));
174    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
175    return buf->getStreamBlockPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, false);
176}
177
178void KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
179    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
180}
181
182Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
183    Value * const blockIndex = computeBlockIndex(getProducedItemCount(name));
184    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
185    return buf->getStreamPackPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, packIndex, false);
186}
187
188void KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
189    return CreateBlockAlignedStore(toStore, getOutputStreamPackPtr(name, streamIndex, packIndex));
190}
191
192Value * KernelBuilder::getOutputStreamSetCount(const std::string & name) {
193    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
194    return buf->getStreamSetCount(this, getStreamSetBufferPtr(name));
195}
196
197Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * streamIndex, Value * absolutePosition) {
198    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
199    return buf->getRawItemPointer(this, getStreamSetBufferPtr(name), streamIndex, absolutePosition);
200}
201
202Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * streamIndex, Value * absolutePosition) {
203    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
204    return buf->getRawItemPointer(this, getStreamSetBufferPtr(name), streamIndex, absolutePosition);
205}
206
207Value * KernelBuilder::getBaseAddress(const std::string & name) {
208    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamSetBufferPtr(name));
209}
210
211void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
212    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamSetBufferPtr(name), addr);
213}
214
215Value * KernelBuilder::getBufferedSize(const std::string & name) {
216    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamSetBufferPtr(name));
217}
218
219void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
220    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamSetBufferPtr(name), size);
221}
222
223BasicBlock * KernelBuilder::CreateWaitForConsumers() {
224    const auto consumers = mKernel->getStreamOutputs();
225    BasicBlock * const entry = GetInsertBlock();
226    if (consumers.empty()) {
227        return entry;
228    } else {
229        Function * const parent = entry->getParent();
230        IntegerType * const sizeTy = getSizeTy();
231        ConstantInt * const zero = getInt32(0);
232        ConstantInt * const one = getInt32(1);
233        ConstantInt * const size0 = getSize(0);
234
235        Value * const segNo = acquireLogicalSegmentNo();
236        const auto n = consumers.size();
237        BasicBlock * load[n + 1];
238        BasicBlock * wait[n];
239        for (unsigned i = 0; i < n; ++i) {
240            load[i] = BasicBlock::Create(getContext(), consumers[i].name + "Load", parent);
241            wait[i] = BasicBlock::Create(getContext(), consumers[i].name + "Wait", parent);
242        }
243        load[n] = BasicBlock::Create(getContext(), "Resume", parent);
244        CreateBr(load[0]);
245        for (unsigned i = 0; i < n; ++i) {
246
247            SetInsertPoint(load[i]);
248            Value * const outputConsumers = getConsumerLock(consumers[i].name);
249
250            Value * const consumerCount = CreateLoad(CreateGEP(outputConsumers, {zero, zero}));
251            Value * const consumerPtr = CreateLoad(CreateGEP(outputConsumers, {zero, one}));
252            Value * const noConsumers = CreateICmpEQ(consumerCount, size0);
253            CreateUnlikelyCondBr(noConsumers, load[i + 1], wait[i]);
254
255            SetInsertPoint(wait[i]);
256            PHINode * const consumerPhi = CreatePHI(sizeTy, 2);
257            consumerPhi->addIncoming(size0, load[i]);
258
259            Value * const conSegPtr = CreateLoad(CreateGEP(consumerPtr, consumerPhi));
260            Value * const processedSegmentCount = CreateAtomicLoadAcquire(conSegPtr);
261            Value * const ready = CreateICmpEQ(segNo, processedSegmentCount);
262            assert (ready->getType() == getInt1Ty());
263            Value * const nextConsumerIdx = CreateAdd(consumerPhi, CreateZExt(ready, sizeTy));
264            consumerPhi->addIncoming(nextConsumerIdx, wait[i]);
265            Value * const next = CreateICmpEQ(nextConsumerIdx, consumerCount);
266            CreateCondBr(next, load[i + 1], wait[i]);
267        }
268
269        BasicBlock * const exit = load[n];
270        SetInsertPoint(exit);
271        return exit;
272    }
273}
274
275}
Note: See TracBrowser for help on using the repository browser.