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

Last change on this file since 5501 was 5501, checked in by cameron, 22 months ago

setCapacity/getCapacity/getLinearlyAvailableItems for SourceBuffer?

File size: 15.2 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(llvm::Value * instance, Value * const index) {
13    assert (instance);
14    CreateAssert(instance, "instance cannot be null!");
15    return CreateGEP(instance, {getInt32(0), index});
16}
17
18Value * KernelBuilder::getScalarFieldPtr(llvm::Value * instance, const std::string & fieldName) {
19    return getScalarFieldPtr(instance, getInt32(mKernel->getScalarIndex(fieldName)));
20}
21
22llvm::Value * KernelBuilder::getScalarFieldPtr(llvm::Value * index) {
23    return getScalarFieldPtr(mKernel->getInstance(), index);
24}
25
26llvm::Value *KernelBuilder:: getScalarFieldPtr(const std::string & fieldName) {
27    return getScalarFieldPtr(mKernel->getInstance(), fieldName);
28}
29
30Value * KernelBuilder::getScalarField(const std::string & fieldName) {
31    return CreateLoad(getScalarFieldPtr(fieldName), fieldName);
32}
33
34void KernelBuilder::setScalarField(const std::string & fieldName, Value * value) {
35    CreateStore(value, getScalarFieldPtr(fieldName));
36}
37
38Value * KernelBuilder::getStreamSetBufferPtr(const std::string & name) {
39    Value * const ptr = getScalarField(name + Kernel::BUFFER_PTR_SUFFIX);
40    CreateAssert(ptr, name + " cannot be null!");
41    return ptr;
42}
43
44LoadInst * KernelBuilder::acquireLogicalSegmentNo() {
45    return CreateAtomicLoadAcquire(getScalarFieldPtr(Kernel::LOGICAL_SEGMENT_NO_SCALAR));
46}
47
48void KernelBuilder::releaseLogicalSegmentNo(Value * nextSegNo) {
49    CreateAtomicStoreRelease(nextSegNo, getScalarFieldPtr(Kernel::LOGICAL_SEGMENT_NO_SCALAR));
50}
51
52Value * KernelBuilder::getProducedItemCount(const std::string & name, Value * doFinal) {
53    Kernel::Port port; unsigned index;
54    std::tie(port, index) = mKernel->getStreamPort(name);
55    assert (port == Kernel::Port::Output);
56    const auto rate = mKernel->getStreamOutput(index).rate;
57    if (rate.isExact()) {
58        const auto & refSet = rate.referenceStreamSet();
59        std::string principalField;
60        if (refSet.empty()) {
61            if (mKernel->getStreamInputs().empty()) {
62                principalField = mKernel->getStreamOutput(0).name + Kernel::PRODUCED_ITEM_COUNT_SUFFIX;
63            } else {
64                principalField = mKernel->getStreamInput(0).name + Kernel::PROCESSED_ITEM_COUNT_SUFFIX;
65            }
66        } else {
67            std::tie(port, index) = mKernel->getStreamPort(refSet);
68            if (port == Kernel::Port::Input) {
69               principalField = refSet + Kernel::PROCESSED_ITEM_COUNT_SUFFIX;
70            } else {
71               principalField = refSet + Kernel::PRODUCED_ITEM_COUNT_SUFFIX;
72            }
73        }
74        Value * const principleCount = getScalarField(principalField);
75        return rate.CreateRatioCalculation(this, principleCount, doFinal);
76    }
77    return getScalarField(name + Kernel::PRODUCED_ITEM_COUNT_SUFFIX);
78}
79
80Value * KernelBuilder::getProcessedItemCount(const std::string & name) {
81    Kernel::Port port; unsigned index;
82    std::tie(port, index) = mKernel->getStreamPort(name);
83    assert (port == Kernel::Port::Input);
84    const auto & rate = mKernel->getStreamInput(index).rate;
85    if (rate.isExact()) {
86        std::string refSet = rate.referenceStreamSet();
87        if (refSet.empty()) {
88            refSet = mKernel->getStreamInput(0).name;
89        }
90        Value * const principleCount = getScalarField(refSet + Kernel::PROCESSED_ITEM_COUNT_SUFFIX);
91        return rate.CreateRatioCalculation(this, principleCount);
92    }
93    return getScalarField(name + Kernel::PROCESSED_ITEM_COUNT_SUFFIX);
94}
95
96Value * KernelBuilder::getAvailableItemCount(const std::string & name) {
97    const auto & inputs = mKernel->getStreamInputs();
98    for (unsigned i = 0; i < inputs.size(); ++i) {
99        if (inputs[i].name == name) {
100            return mKernel->getAvailableItemCount(i);
101        }
102    }
103    return nullptr;
104}
105
106Value * KernelBuilder::getConsumedItemCount(const std::string & name) {
107    return getScalarField(name + Kernel::CONSUMED_ITEM_COUNT_SUFFIX);
108}
109
110void KernelBuilder::setProducedItemCount(const std::string & name, Value * value) {
111    setScalarField(name + Kernel::PRODUCED_ITEM_COUNT_SUFFIX, value);
112}
113
114void KernelBuilder::setProcessedItemCount(const std::string & name, Value * value) {
115    setScalarField(name + Kernel::PROCESSED_ITEM_COUNT_SUFFIX, value);
116}
117
118void KernelBuilder::setConsumedItemCount(const std::string & name, Value * value) {
119    setScalarField(name + Kernel::CONSUMED_ITEM_COUNT_SUFFIX, value);
120}
121
122Value * KernelBuilder::getTerminationSignal() {
123    return getScalarField(Kernel::TERMINATION_SIGNAL);
124}
125
126void KernelBuilder::setTerminationSignal() {
127    setScalarField(Kernel::TERMINATION_SIGNAL, getTrue());
128}
129
130Value * KernelBuilder::getLinearlyAccessibleItems(const std::string & name, Value * fromPosition) {
131    Kernel::Port port; unsigned index;
132    std::tie(port, index) = mKernel->getStreamPort(name);
133    if (port == Kernel::Port::Input) {
134        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
135        return buf->getLinearlyAccessibleItems(this, getStreamSetBufferPtr(name), fromPosition);
136    }
137    else {
138        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
139        return buf->getLinearlyAccessibleItems(this, getStreamSetBufferPtr(name), fromPosition);
140    }
141}
142
143Value * KernelBuilder::getLinearlyAccessibleBlocks(const std::string & name, Value * fromBlock) {
144    Kernel::Port port; unsigned index;
145    std::tie(port, index) = mKernel->getStreamPort(name);
146    if (port == Kernel::Port::Input) {
147        const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
148        return buf->getLinearlyAccessibleBlocks(this, getStreamSetBufferPtr(name), fromBlock);
149    } else {
150        const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
151        return buf->getLinearlyAccessibleBlocks(this, getStreamSetBufferPtr(name), fromBlock);
152    }
153}
154
155Value * KernelBuilder::getLinearlyWritableItems(const std::string & name, Value * fromPosition) {
156    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
157    return buf->getLinearlyWritableItems(this, getStreamSetBufferPtr(name), fromPosition);
158}
159
160Value * KernelBuilder::getLinearlyWritableBlocks(const std::string & name, Value * fromBlock) {
161    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
162    return buf->getLinearlyWritableBlocks(this, getStreamSetBufferPtr(name), fromBlock);
163}
164
165Value * KernelBuilder::getConsumerLock(const std::string & name) {
166    return getScalarField(name + Kernel::CONSUMER_SUFFIX);
167}
168
169void KernelBuilder::setConsumerLock(const std::string & name, Value * value) {
170    setScalarField(name + Kernel::CONSUMER_SUFFIX, value);
171}
172
173inline Value * KernelBuilder::computeBlockIndex(Value * itemCount) {
174    const auto divisor = getBitBlockWidth();
175    if (LLVM_LIKELY((divisor & (divisor - 1)) == 0)) {
176        return CreateLShr(itemCount, std::log2(divisor));
177    } else {
178        return CreateUDiv(itemCount, getSize(divisor));
179    }
180}
181
182Value * KernelBuilder::getInputStreamBlockPtr(const std::string & name, Value * streamIndex) {
183    Value * const blockIndex = computeBlockIndex(getProcessedItemCount(name));
184    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
185    return buf->getStreamBlockPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, true);
186}
187
188Value * KernelBuilder::loadInputStreamBlock(const std::string & name, Value * streamIndex) {
189    return CreateBlockAlignedLoad(getInputStreamBlockPtr(name, streamIndex));
190}
191
192Value * KernelBuilder::getInputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
193    Value * const blockIndex = computeBlockIndex(getProcessedItemCount(name));
194    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
195    return buf->getStreamPackPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, packIndex, true);
196}
197
198Value * KernelBuilder::loadInputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex) {
199    return CreateBlockAlignedLoad(getInputStreamPackPtr(name, streamIndex, packIndex));
200}
201
202Value * KernelBuilder::getInputStreamSetCount(const std::string & name) {
203    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
204    return buf->getStreamSetCount(this, getStreamSetBufferPtr(name));
205}
206
207Value * KernelBuilder::getAdjustedInputStreamBlockPtr(Value * blockAdjustment, const std::string & name, Value * streamIndex) {
208    Value * const blockIndex = CreateAdd(computeBlockIndex(getProcessedItemCount(name)), blockAdjustment);
209    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
210    return buf->getStreamBlockPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, true);
211}
212
213Value * KernelBuilder::getOutputStreamBlockPtr(const std::string & name, Value * streamIndex) {
214    Value * const blockIndex = computeBlockIndex(getProducedItemCount(name));
215    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
216    return buf->getStreamBlockPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, false);
217}
218
219StoreInst * KernelBuilder::storeOutputStreamBlock(const std::string & name, Value * streamIndex, Value * toStore) {
220    return CreateBlockAlignedStore(toStore, getOutputStreamBlockPtr(name, streamIndex));
221}
222
223Value * KernelBuilder::getOutputStreamPackPtr(const std::string & name, Value * streamIndex, Value * packIndex) {
224    Value * const blockIndex = computeBlockIndex(getProducedItemCount(name));
225    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
226    return buf->getStreamPackPtr(this, getStreamSetBufferPtr(name), streamIndex, blockIndex, packIndex, false);
227}
228
229StoreInst * KernelBuilder::storeOutputStreamPack(const std::string & name, Value * streamIndex, Value * packIndex, Value * toStore) {
230    return CreateBlockAlignedStore(toStore, getOutputStreamPackPtr(name, streamIndex, packIndex));
231}
232
233Value * KernelBuilder::getOutputStreamSetCount(const std::string & name) {
234    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
235    return buf->getStreamSetCount(this, getStreamSetBufferPtr(name));
236}
237
238Value * KernelBuilder::getRawInputPointer(const std::string & name, Value * streamIndex, Value * absolutePosition) {
239    const StreamSetBuffer * const buf = mKernel->getInputStreamSetBuffer(name);
240    return buf->getRawItemPointer(this, getStreamSetBufferPtr(name), streamIndex, absolutePosition);
241}
242
243Value * KernelBuilder::getRawOutputPointer(const std::string & name, Value * streamIndex, Value * absolutePosition) {
244    const StreamSetBuffer * const buf = mKernel->getOutputStreamSetBuffer(name);
245    return buf->getRawItemPointer(this, getStreamSetBufferPtr(name), streamIndex, absolutePosition);
246}
247
248Value * KernelBuilder::getBaseAddress(const std::string & name) {
249    return mKernel->getAnyStreamSetBuffer(name)->getBaseAddress(this, getStreamSetBufferPtr(name));
250}
251
252void KernelBuilder::setBaseAddress(const std::string & name, Value * const addr) {
253    return mKernel->getAnyStreamSetBuffer(name)->setBaseAddress(this, getStreamSetBufferPtr(name), addr);
254}
255
256Value * KernelBuilder::getBufferedSize(const std::string & name) {
257    return mKernel->getAnyStreamSetBuffer(name)->getBufferedSize(this, getStreamSetBufferPtr(name));
258}
259
260void KernelBuilder::setBufferedSize(const std::string & name, Value * size) {
261    mKernel->getAnyStreamSetBuffer(name)->setBufferedSize(this, getStreamSetBufferPtr(name), size);
262}
263
264
265Value * KernelBuilder::getCapacity(const std::string & name) {
266    return mKernel->getAnyStreamSetBuffer(name)->getCapacity(this, getStreamSetBufferPtr(name));
267}
268
269void KernelBuilder::setCapacity(const std::string & name, Value * c) {
270    mKernel->getAnyStreamSetBuffer(name)->setCapacity(this, getStreamSetBufferPtr(name), c);
271}
272
273   
274CallInst * KernelBuilder::createDoSegmentCall(const std::vector<Value *> & args) {
275    Function * const doSegment = mKernel->getDoSegmentFunction(getModule());
276    assert (doSegment->getArgumentList().size() == args.size());
277    return CreateCall(doSegment, args);
278}
279
280Value * KernelBuilder::getAccumulator(const std::string & accumName) {
281    auto results = mKernel->mOutputScalarResult;
282    if (LLVM_UNLIKELY(results == nullptr)) {
283        report_fatal_error("Cannot get accumulator " + accumName + " until " + mKernel->getName() + " has terminated.");
284    }
285    const auto & outputs = mKernel->getScalarOutputs();
286    const auto n = outputs.size();
287    if (LLVM_UNLIKELY(n == 0)) {
288        report_fatal_error(mKernel->getName() + " has no output scalars.");
289    } else {
290        for (unsigned i = 0; i < n; ++i) {
291            const Binding & b = outputs[i];
292            if (b.name == accumName) {
293                if (n == 1) {
294                    return results;
295                } else {
296                    return CreateExtractValue(results, {i});
297                }
298            }
299        }
300        report_fatal_error(mKernel->getName() + " has no output scalar named " + accumName);
301    }
302}
303
304BasicBlock * KernelBuilder::CreateConsumerWait() {
305    const auto consumers = mKernel->getStreamOutputs();
306    BasicBlock * const entry = GetInsertBlock();
307    if (consumers.empty()) {
308        return entry;
309    } else {
310        Function * const parent = entry->getParent();
311        IntegerType * const sizeTy = getSizeTy();
312        ConstantInt * const zero = getInt32(0);
313        ConstantInt * const one = getInt32(1);
314        ConstantInt * const size0 = getSize(0);
315
316        Value * const segNo = acquireLogicalSegmentNo();
317        const auto n = consumers.size();
318        BasicBlock * load[n + 1];
319        BasicBlock * wait[n];
320        for (unsigned i = 0; i < n; ++i) {
321            load[i] = BasicBlock::Create(getContext(), consumers[i].name + "Load", parent);
322            wait[i] = BasicBlock::Create(getContext(), consumers[i].name + "Wait", parent);
323        }
324        load[n] = BasicBlock::Create(getContext(), "Resume", parent);
325        CreateBr(load[0]);
326        for (unsigned i = 0; i < n; ++i) {
327
328            SetInsertPoint(load[i]);
329            Value * const outputConsumers = getConsumerLock(consumers[i].name);
330
331            Value * const consumerCount = CreateLoad(CreateGEP(outputConsumers, {zero, zero}));
332            Value * const consumerPtr = CreateLoad(CreateGEP(outputConsumers, {zero, one}));
333            Value * const noConsumers = CreateICmpEQ(consumerCount, size0);
334            CreateUnlikelyCondBr(noConsumers, load[i + 1], wait[i]);
335
336            SetInsertPoint(wait[i]);
337            PHINode * const consumerPhi = CreatePHI(sizeTy, 2);
338            consumerPhi->addIncoming(size0, load[i]);
339
340            Value * const conSegPtr = CreateLoad(CreateGEP(consumerPtr, consumerPhi));
341            Value * const processedSegmentCount = CreateAtomicLoadAcquire(conSegPtr);
342            Value * const ready = CreateICmpEQ(segNo, processedSegmentCount);
343            assert (ready->getType() == getInt1Ty());
344            Value * const nextConsumerIdx = CreateAdd(consumerPhi, CreateZExt(ready, sizeTy));
345            consumerPhi->addIncoming(nextConsumerIdx, wait[i]);
346            Value * const next = CreateICmpEQ(nextConsumerIdx, consumerCount);
347            CreateCondBr(next, load[i + 1], wait[i]);
348        }
349
350        BasicBlock * const exit = load[n];
351        SetInsertPoint(exit);
352        return exit;
353    }
354}
355
356}
Note: See TracBrowser for help on using the repository browser.