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

Last change on this file since 5303 was 5303, checked in by cameron, 3 years ago

Refined copy-back buffers, use copyback in p2s_compressed; stdout/filesink mods for circular buffers

File size: 10.0 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 <assert.h>                // for assert
9#include <llvm/IR/Type.h>          // for Type
10#include <stdexcept>               // for runtime_error
11#include <llvm/IR/BasicBlock.h>    // for BasicBlock
12#include <llvm/IR/Constants.h>     // for ConstantInt
13#include <llvm/IR/DataLayout.h>    // for DataLayout
14#include <llvm/IR/DerivedTypes.h>  // for IntegerType (ptr only), PointerType
15#include <llvm/IR/Module.h>        // for Module
16#include <llvm/IR/Value.h>         // for Value
17namespace llvm { class Constant; }
18namespace llvm { class Function; }
19
20using namespace parabix;
21using namespace llvm;
22using namespace IDISA;
23
24Type * resolveVectorTy(IDISA_Builder * const b, Type * type) {
25    if (LLVM_LIKELY(type->isVectorTy() && type->getVectorNumElements() == 0)) {
26        type = type->getVectorElementType();
27        if (LLVM_LIKELY(type->isIntegerTy())) {
28            const auto fieldWidth = cast<IntegerType>(type)->getBitWidth();
29            type = b->getBitBlockType();
30            if (fieldWidth != 1) {
31                type = llvm::ArrayType::get(type, fieldWidth);
32            }
33        }
34    }
35    return type;
36}
37
38Type * StreamSetBuffer::resolveStreamSetBufferType(Type * const type) const {
39    if (type->isArrayTy()) {
40        return ArrayType::get(resolveVectorTy(iBuilder, type->getArrayElementType()), type->getArrayNumElements());
41    } else if (type->isVectorTy()) {
42        return resolveVectorTy(iBuilder, type);
43    }
44    return type;
45}
46
47void StreamSetBuffer::allocateBuffer() {
48    mStreamSetBufferPtr = iBuilder->CreateCacheAlignedAlloca(getType(), iBuilder->getSize(mBufferBlocks));
49}
50
51Value * StreamSetBuffer::getStream(Value * self, Value * blockNo, Value * index) const {
52    return iBuilder->CreateGEP(getStreamSetPtr(self, blockNo), {iBuilder->getInt32(0), index});
53}
54
55Value * StreamSetBuffer::getStream(Value * self, Value * blockNo, Value * index1, Value * index2) const {
56    return iBuilder->CreateGEP(getStreamSetPtr(self, blockNo), {iBuilder->getInt32(0), index1, index2});
57}
58
59Value * StreamSetBuffer::getStreamView(llvm::Type * type, llvm::Value * self, Value * blockNo, llvm::Value * index) const {
60    return iBuilder->CreateGEP(iBuilder->CreatePointerCast(getStreamSetPtr(self, blockNo), type), index, "view");
61}
62
63Value * StreamSetBuffer::getLinearlyAccessibleItems(llvm::Value * fromPosition) const {
64    if (isa<ArrayType>(mStreamSetType) && dyn_cast<ArrayType>(mStreamSetType)->getNumElements() > 1) {
65        Constant * stride = iBuilder->getSize(iBuilder->getStride());
66        return iBuilder->CreateSub(stride, iBuilder->CreateURem(fromPosition, stride));
67    }
68    else {
69        Constant * bufSize = iBuilder->getSize(mBufferBlocks * iBuilder->getStride());
70        return iBuilder->CreateSub(bufSize, iBuilder->CreateURem(fromPosition, bufSize));
71    }
72}
73
74
75// Single Block Buffer
76
77// For a single block buffer, the block pointer is always the buffer base pointer.
78Value * SingleBlockBuffer::getStreamSetPtr(Value * self, Value *) const {
79    return self;
80}
81
82// External File Buffer
83void ExternalFileBuffer::setStreamSetBuffer(Value * ptr, Value * /* fileSize */) {
84    mStreamSetBufferPtr = iBuilder->CreatePointerBitCastOrAddrSpaceCast(ptr, getPointerType());
85}
86
87void ExternalFileBuffer::setEmptyBuffer(Value * ptr) {   
88    mStreamSetBufferPtr = iBuilder->CreatePointerBitCastOrAddrSpaceCast(ptr, getPointerType());
89}
90
91void ExternalFileBuffer::allocateBuffer() {
92    throw std::runtime_error("External buffers cannot be allocated.");
93}
94
95Value * ExternalFileBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
96    return iBuilder->CreateGEP(self, blockNo);
97}
98
99Value * ExternalFileBuffer::getLinearlyAccessibleItems(llvm::Value * fromPosition) const {
100    throw std::runtime_error("External buffers: getLinearlyAccessibleItems not supported.");
101}
102
103// Circular Buffer
104
105Value * CircularBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
106    assert (blockNo->getType()->isIntegerTy());
107
108    Value * offset = nullptr;
109    if (mBufferBlocks == 1) {
110        offset = ConstantInt::getNullValue(iBuilder->getSizeTy());
111    } else if ((mBufferBlocks & (mBufferBlocks - 1)) == 0) { // is power of 2
112        offset = iBuilder->CreateAnd(blockNo, ConstantInt::get(blockNo->getType(), mBufferBlocks - 1));
113    } else {
114        offset = iBuilder->CreateURem(blockNo, ConstantInt::get(blockNo->getType(), mBufferBlocks));
115    }
116    return iBuilder->CreateGEP(self, offset);
117}
118
119
120// CircularCopybackBuffer Buffer
121
122void CircularCopybackBuffer::allocateBuffer() {
123    mStreamSetBufferPtr = iBuilder->CreateCacheAlignedAlloca(getType(), iBuilder->getSize(mBufferBlocks + mOverflowBlocks));
124}
125
126void CircularCopybackBuffer::createCopyBack(Value * self, Value * overFlowItems) const {
127    Function * f = iBuilder->GetInsertBlock()->getParent();
128    BasicBlock * wholeBlockCopy = BasicBlock::Create(iBuilder->getContext(), "wholeBlockCopy", f, 0);
129    BasicBlock * partialBlockCopy = BasicBlock::Create(iBuilder->getContext(), "partialBlockCopy", f, 0);
130    BasicBlock * copyBackDone = BasicBlock::Create(iBuilder->getContext(), "copyBackDone", f, 0);
131    Type * i8ptr = iBuilder->getInt8PtrTy();
132    unsigned numStreams = getType()->getArrayNumElements();
133    auto elemTy = getType()->getArrayElementType();
134    unsigned fieldWidth = isa<ArrayType>(elemTy) ? elemTy->getArrayNumElements() : 1;
135    Constant * blockSize = iBuilder->getSize(iBuilder->getBitBlockWidth());
136    Value * overFlowAreaPtr = iBuilder->CreateGEP(self, iBuilder->getSize(mBufferBlocks));
137    Value * overFlowBlocks = iBuilder->CreateUDiv(overFlowItems, blockSize);
138    Value * partialItems = iBuilder->CreateURem(overFlowItems, blockSize);
139    iBuilder->CreateCondBr(iBuilder->CreateICmpUGT(overFlowBlocks, iBuilder->getSize(0)), wholeBlockCopy, partialBlockCopy);
140    iBuilder->SetInsertPoint(wholeBlockCopy);
141    unsigned alignment = iBuilder->getBitBlockWidth() / 8;
142    Constant * blockBytes = iBuilder->getSize(fieldWidth * iBuilder->getBitBlockWidth()/8);
143    Value * copyLength = iBuilder->CreateMul(overFlowBlocks, blockBytes);
144    iBuilder->CreateMemMove(iBuilder->CreateBitCast(self, i8ptr), iBuilder->CreateBitCast(overFlowAreaPtr, i8ptr), copyLength, alignment);
145    iBuilder->CreateCondBr(iBuilder->CreateICmpUGT(partialItems, iBuilder->getSize(0)), partialBlockCopy, copyBackDone);
146    iBuilder->SetInsertPoint(partialBlockCopy);
147    Value * partialBlockTargetPtr = iBuilder->CreateGEP(self, overFlowBlocks);
148    Value * partialBlockSourcePtr = iBuilder->CreateGEP(overFlowAreaPtr, overFlowBlocks);
149    Value * copyBits = iBuilder->CreateMul(overFlowItems, iBuilder->getSize(fieldWidth));
150    Value * copyBytes = iBuilder->CreateUDiv(iBuilder->CreateAdd(copyBits, iBuilder->getSize(7)), iBuilder->getSize(8));
151    for (unsigned strm = 0; strm < numStreams; strm++) {
152        Value * strmTargetPtr = iBuilder->CreateGEP(partialBlockTargetPtr, {iBuilder->getInt32(0), iBuilder->getInt32(strm)});
153        Value * strmSourcePtr = iBuilder->CreateGEP(partialBlockSourcePtr, {iBuilder->getInt32(0), iBuilder->getInt32(strm)});
154        iBuilder->CreateMemMove(iBuilder->CreateBitCast(strmTargetPtr, i8ptr), iBuilder->CreateBitCast(strmSourcePtr, i8ptr), copyBytes, alignment);
155    }
156    iBuilder->CreateBr(copyBackDone);
157    iBuilder->SetInsertPoint(copyBackDone);
158}
159
160Value * CircularCopybackBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
161    assert (blockNo->getType()->isIntegerTy());
162   
163    Value * offset = nullptr;
164    if (mBufferBlocks == 1) {
165        offset = ConstantInt::getNullValue(iBuilder->getSizeTy());
166    } else if ((mBufferBlocks & (mBufferBlocks - 1)) == 0) { // is power of 2
167        offset = iBuilder->CreateAnd(blockNo, ConstantInt::get(blockNo->getType(), mBufferBlocks - 1));
168    } else {
169        offset = iBuilder->CreateURem(blockNo, ConstantInt::get(blockNo->getType(), mBufferBlocks));
170    }
171    return iBuilder->CreateGEP(self, offset);
172}
173
174
175
176// Expandable Buffer
177
178Value * ExpandableBuffer::getStreamSetPtr(Value * self, Value * blockNo) const {
179    return nullptr;
180}
181
182llvm::Value * ExpandableBuffer::getStream(llvm::Value * self, llvm::Value * blockNo, llvm::Value * index) const {
183    return nullptr;
184}
185
186llvm::Value * ExpandableBuffer::getStream(llvm::Value * self, llvm::Value * blockNo, Value *index1, Value *index2) const {
187    return nullptr;
188}
189
190llvm::Value * ExpandableBuffer::getStreamView(llvm::Type * type, llvm::Value * self, llvm::Value * blockNo, llvm::Value * index) const {
191    return nullptr;
192}
193
194// Constructors
195
196SingleBlockBuffer::SingleBlockBuffer(IDISA::IDISA_Builder * b, llvm::Type * type)
197: StreamSetBuffer(BufferKind::BlockBuffer, b, type, 1, 0) {
198
199}
200
201ExternalFileBuffer::ExternalFileBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, unsigned AddressSpace)
202: StreamSetBuffer(BufferKind::ExternalFileBuffer, b, type, 0, AddressSpace) {
203
204}
205
206CircularBuffer::CircularBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace)
207: StreamSetBuffer(BufferKind::CircularBuffer, b, type, bufferBlocks, AddressSpace) {
208
209}
210
211CircularCopybackBuffer::CircularCopybackBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace)
212: StreamSetBuffer(BufferKind::CircularCopybackBuffer, b, type, bufferBlocks, AddressSpace), mOverflowBlocks(overflowBlocks) {
213
214}
215
216
217ExpandableBuffer::ExpandableBuffer(IDISA::IDISA_Builder * b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace)
218: StreamSetBuffer(BufferKind::ExpandableBuffer, b, type, bufferBlocks, AddressSpace) {
219
220}
221
222Value * ExpandableBuffer::getLinearlyAccessibleItems(llvm::Value * fromPosition) const {
223    throw std::runtime_error("Expandable buffers: getLinearlyAccessibleItems not supported.");
224}
225
226
227StreamSetBuffer::StreamSetBuffer(BufferKind k, IDISA::IDISA_Builder * b, Type * type, unsigned blocks, unsigned AddressSpace)
228: mBufferKind(k)
229, iBuilder(b)
230, mStreamSetType(resolveStreamSetBufferType(type))
231, mBufferBlocks(blocks)
232, mAddressSpace(AddressSpace)
233, mStreamSetBufferPtr(nullptr)
234, mBaseStreamSetType(type) {
235
236}
Note: See TracBrowser for help on using the repository browser.