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

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

Continued refactoring work.

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