source: icGREP/icgrep-devel/icgrep/kernels/streamset.cpp @ 5260

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

Changes working towards simplifying accessing stream elements + some modifications to simplify include / forward declarations within the CodeGen? library.

File size: 13.5 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5
6#include "streamset.h"
7#include <IR_Gen/idisa_builder.h>  // for IDISA_Builder
8#include <IR_Gen/types/streamtype.h>
9#include <assert.h>                // for assert
10#include <llvm/IR/Type.h>          // for Type
11#include <stdexcept>               // for runtime_error
12#include <llvm/IR/BasicBlock.h>    // for BasicBlock
13#include <llvm/IR/Constants.h>     // for ConstantInt
14#include <llvm/IR/DataLayout.h>    // for DataLayout
15#include <llvm/IR/DerivedTypes.h>  // for IntegerType (ptr only), PointerType
16#include <llvm/IR/Module.h>        // for Module
17#include <llvm/IR/Value.h>         // for Value
18namespace llvm { class Constant; }
19namespace llvm { class Function; }
20
21using namespace parabix;
22using namespace llvm;
23using namespace IDISA;
24
25enum SS_struct_index {iProducer_pos = 0, iConsumer_pos = 1, iEnd_of_input = 2, iBuffer_ptr = 3};
26
27Value * StreamSetBuffer::getProducerPosPtr(Value * self) const {
28    return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)});
29}
30
31void StreamSetBuffer::setProducerPos(Value * self, Value * pos) const {
32    iBuilder->CreateStore(pos, getProducerPosPtr(self));
33}
34
35Value * StreamSetBuffer::getConsumerPosPtr(Value * self) const {
36    return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)});
37}
38
39void StreamSetBuffer::setConsumerPos(Value * self, Value * pos) const {
40    iBuilder->CreateStore(pos, getConsumerPosPtr(self));
41}
42
43Value * StreamSetBuffer::getEndOfInputPtr(Value * self) const {
44    return iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)});
45}
46
47void StreamSetBuffer::setEndOfInput(Value * self) const {
48    iBuilder->CreateStore(ConstantInt::get(iBuilder->getInt1Ty(), 1), getEndOfInputPtr(self));
49}
50
51Type * StreamSetBuffer::resolveStreamTypes(Type * type) {
52    if (auto ty = dyn_cast<ArrayType>(type)) {
53        unsigned numElems = ty->getNumElements();
54        auto elemTy = ty->getElementType();
55        if (isa<StreamType>(elemTy)) {
56            return ArrayType::get(cast<StreamType>(elemTy)->resolveType(iBuilder), numElems);
57        }
58    }
59    else if (auto ty = dyn_cast<StreamType>(type)) {
60        return ty->resolveType(iBuilder);
61    }
62    return type;
63}
64
65void StreamSetBuffer::allocateBuffer() {
66    Type * const sizeTy = iBuilder->getSizeTy();
67    Type * const int1ty = iBuilder->getInt1Ty();
68    mStreamSetBufferPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetType, iBuilder->getSize(mBufferBlocks));
69    mStreamSetStructPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetStructType);
70    iBuilder->CreateStore(ConstantInt::get(sizeTy, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
71    iBuilder->CreateStore(ConstantInt::get(sizeTy, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}));
72    iBuilder->CreateStore(ConstantInt::get(int1ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)}));
73    iBuilder->CreateStore(mStreamSetBufferPtr, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}));
74}
75
76
77Value * StreamSetBuffer::getStream(Value * self, Value * blockNo, Value * index) const {
78    return iBuilder->CreateGEP(getStreamSetPtr(self, blockNo), {iBuilder->getInt32(0), index});
79}
80
81Value * StreamSetBuffer::getStream(Value * self, Value * blockNo, Value * index1, Value * index2) const {
82    return iBuilder->CreateGEP(getStreamSetPtr(self, blockNo), {iBuilder->getInt32(0), index1, index2});
83}
84
85Value * StreamSetBuffer::getStreamView(llvm::Value * self, Value * blockNo, llvm::Value * index) const {
86    return iBuilder->CreateGEP(getStreamSetPtr(self, blockNo), index, "view");
87}
88
89Value * StreamSetBuffer::getStreamView(llvm::Type * type, llvm::Value * self, Value * blockNo, llvm::Value * index) const {
90    return iBuilder->CreateGEP(iBuilder->CreatePointerCast(getStreamSetPtr(self, blockNo), type), index, "view");
91}
92
93// Single Block Buffer
94
95// For a single block buffer, the block pointer is always the buffer base pointer.
96Value * SingleBlockBuffer::getStreamSetPtr(Value * self, Value *) const {
97    return iBuilder->CreateLoad(iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}), "sb");
98}
99
100// External File Buffer
101void ExternalFileBuffer::setStreamSetBuffer(Value * ptr, Value * fileSize) {
102   
103    Type * const size_ty = iBuilder->getSizeTy();
104    Type * const int1ty = iBuilder->getInt1Ty();
105   
106    PointerType * t = getStreamBufferPointerType();   
107    mStreamSetBufferPtr = iBuilder->CreatePointerBitCastOrAddrSpaceCast(ptr, t);
108   
109    mStreamSetStructPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetStructType);
110    iBuilder->CreateStore(fileSize, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
111    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}));
112    iBuilder->CreateStore(ConstantInt::get(int1ty, 1), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)}));
113    iBuilder->CreateStore(mStreamSetBufferPtr, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}));
114}
115
116void ExternalFileBuffer::setEmptyBuffer(Value * ptr) {
117   
118    Type * const size_ty = iBuilder->getSizeTy();
119    Type * const int1ty = iBuilder->getInt1Ty();
120   
121    PointerType * t = getStreamBufferPointerType();   
122    mStreamSetBufferPtr = iBuilder->CreatePointerBitCastOrAddrSpaceCast(ptr, t);
123   
124    mStreamSetStructPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetStructType);
125    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
126    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}));
127    iBuilder->CreateStore(ConstantInt::get(int1ty,0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)}));
128    iBuilder->CreateStore(mStreamSetBufferPtr, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}));
129}
130
131void ExternalFileBuffer::allocateBuffer() {
132    throw std::runtime_error("External buffers cannot be allocated.");
133}
134
135Value * ExternalFileBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
136    Value * handle = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}, "ef");
137    Value * bufPtr = iBuilder->CreateLoad(handle);
138    return iBuilder->CreateGEP(bufPtr, blockNo);
139}
140
141// Circular Buffer
142
143Value * CircularBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
144    assert (blockNo->getType()->isIntegerTy());
145
146    Value * handle = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}, "cb");
147    Value * bufPtr = iBuilder->CreateLoad(handle);
148    Value * offset = nullptr;
149    if (mBufferBlocks == 1) {
150        offset = ConstantInt::getNullValue(iBuilder->getSizeTy());
151    } else if ((mBufferBlocks & (mBufferBlocks - 1)) == 0) { // is power of 2
152        offset = iBuilder->CreateAnd(blockNo, ConstantInt::get(blockNo->getType(), mBufferBlocks - 1));
153    } else {
154        offset = iBuilder->CreateURem(blockNo, ConstantInt::get(blockNo->getType(), mBufferBlocks));
155    }
156    return iBuilder->CreateGEP(bufPtr, offset);
157}
158
159// Linear Copyback Buffer
160
161Value * LinearCopybackBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
162    Value * consumerPos_ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}, "lcb.c");
163    Value * consumerPos = iBuilder->CreateLoad(consumerPos_ptr);
164    Value * consumerBlock = iBuilder->CreateUDiv(consumerPos, iBuilder->getSize(iBuilder->getStride()));
165    consumerBlock = iBuilder->CreateZExtOrTrunc(consumerBlock, blockNo->getType());
166    Value * handle = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}, "lcb.p");
167    Value * bufPtr = iBuilder->CreateLoad(handle);
168    return iBuilder->CreateGEP(bufPtr, iBuilder->CreateSub(blockNo, consumerBlock));
169}
170
171void LinearCopybackBuffer::setConsumerPos(Value * self, Value * newConsumerPos) const {
172    Type * const i8 = iBuilder->getInt8Ty();
173    Type * const i8_ptr = i8->getPointerTo(mAddrSpace);
174    IntegerType * const sizeTy = iBuilder->getSizeTy();
175
176    Module * const M = iBuilder->getModule();
177
178    Function * const current = iBuilder->GetInsertBlock()->getParent();
179    BasicBlock * const copyBackBody = BasicBlock::Create(M->getContext(), "copy_back", current, 0);
180    BasicBlock * const setConsumerPosExit = BasicBlock::Create(M->getContext(), "setConsumerPos_done", current, 0);
181    Constant * const blockWidth = ConstantInt::get(sizeTy, iBuilder->getStride());
182
183    Constant * const one = ConstantInt::get(sizeTy, 1);
184
185    Value * const consumerPosPtr = getConsumerPosPtr(self);
186    Value * const consumerPos = iBuilder->CreateLoad(consumerPosPtr);
187
188    // Ensure that the new consumer position is no less than the current position.
189    newConsumerPos = iBuilder->CreateSelect(iBuilder->CreateICmpULT(newConsumerPos, consumerPos), consumerPos, newConsumerPos);
190    Value * producerPos = iBuilder->CreateLoad(iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
191
192    // Ensure that the new consumer position is no greater than the current producer position.
193    Value * new_pos_lt_producer_pos = iBuilder->CreateICmpULT(newConsumerPos, producerPos);
194    newConsumerPos = iBuilder->CreateSelect(new_pos_lt_producer_pos, newConsumerPos, producerPos);
195
196    // Now, the new_consumer_pos is at most = to the producer_pos; if =, we're done.
197    iBuilder->CreateCondBr(new_pos_lt_producer_pos, copyBackBody, setConsumerPosExit);
198    iBuilder->SetInsertPoint(copyBackBody);
199   
200    Value * new_consumer_block = iBuilder->CreateUDiv(newConsumerPos, blockWidth);
201    Value * lastProducerBlock = iBuilder->CreateUDiv(iBuilder->CreateSub(producerPos, one), blockWidth);
202    Value * copyBlocks = iBuilder->CreateAdd(iBuilder->CreateSub(lastProducerBlock, new_consumer_block), one);
203
204    DataLayout dl(iBuilder->getModule());
205
206    Constant * blockBytes = ConstantInt::get(sizeTy, dl.getTypeAllocSize(mStreamSetType) * iBuilder->getStride());
207
208    Value * copyLength = iBuilder->CreateMul(copyBlocks, blockBytes);
209
210    // Must copy back one full block for each of the streams in the stream set.
211    Value * handle = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)});
212    Value * bufferPtr = iBuilder->CreateLoad(handle);
213    Value * const consumerBlock = iBuilder->CreateUDiv(consumerPos, blockWidth);
214    Value * copyFrom = iBuilder->CreateGEP(bufferPtr, iBuilder->CreateSub(new_consumer_block, consumerBlock));
215    unsigned alignment = iBuilder->getBitBlockWidth() / 8;
216    iBuilder->CreateMemMove(iBuilder->CreateBitCast(bufferPtr, i8_ptr), iBuilder->CreateBitCast(copyFrom, i8_ptr), copyLength, alignment);
217    iBuilder->CreateBr(setConsumerPosExit);
218    // Copy back done, store the new consumer position.
219    iBuilder->SetInsertPoint(setConsumerPosExit);
220
221    iBuilder->CreateStore(newConsumerPos, consumerPosPtr);
222}
223
224// Expandable Buffer
225
226Value * ExpandableBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
227    return nullptr;
228}
229
230llvm::Value * ExpandableBuffer::getStream(llvm::Value * self, llvm::Value * blockNo, llvm::Value * index) const {
231    return nullptr;
232}
233
234llvm::Value * ExpandableBuffer::getStream(llvm::Value * self, llvm::Value * blockNo, Value *index1, Value *index2) const {
235    return nullptr;
236}
237
238llvm::Value * ExpandableBuffer::getStreamView(llvm::Value * self, llvm::Value * blockNo, llvm::Value * index) const {
239    return nullptr;
240}
241
242llvm::Value * ExpandableBuffer::getStreamView(llvm::Type * type, llvm::Value * self, llvm::Value * blockNo, llvm::Value * index) const {
243    return nullptr;
244}
245
246
247// Constructors
248
249SingleBlockBuffer::SingleBlockBuffer(IDISA::IDISA_Builder * b, llvm::Type * type)
250: StreamSetBuffer(BufferKind::BlockBuffer, b, type, 1, 0) {
251
252}
253
254ExternalFileBuffer::ExternalFileBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, unsigned AddressSpace)
255: StreamSetBuffer(BufferKind::ExternalFileBuffer, b, type, 0, AddressSpace) {
256
257}
258
259CircularBuffer::CircularBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace)
260: StreamSetBuffer(BufferKind::CircularBuffer, b, type, bufferBlocks, AddressSpace) {
261
262}
263
264LinearCopybackBuffer::LinearCopybackBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace)
265: StreamSetBuffer(BufferKind::LinearCopybackBuffer, b, type, bufferBlocks, AddressSpace) {
266
267}
268
269ExpandableBuffer::ExpandableBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace)
270: StreamSetBuffer(BufferKind::ExpandableBuffer, b, type, bufferBlocks, AddressSpace) {
271
272}
273
274StreamSetBuffer::StreamSetBuffer(BufferKind k, IDISA::IDISA_Builder * b, Type * type, unsigned blocks, unsigned AddressSpace)
275: mBufferKind(k)
276, iBuilder(b)
277, mStreamSetType(resolveStreamTypes(type))
278, mBufferBlocks(blocks)
279, mAddrSpace(AddressSpace)
280, mStreamSetBufferPtr(nullptr)
281, mStreamSetStructPtr(nullptr)
282, mStreamSetStructType(StructType::get(b->getContext(),
283                        {{b->getSizeTy(),
284                          b->getSizeTy(),
285                          b->getInt1Ty(),
286                          PointerType::get(mStreamSetType, AddressSpace)}})) {
287
288}
Note: See TracBrowser for help on using the repository browser.