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

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

Merged PabloFunction? and PabloKernel? classes. Updated projects where necessary.

File size: 10.2 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   
7#include <kernels/streamset.h>
8#include <vector>
9#include <IDISA/idisa_builder.h>
10#include <llvm/IR/Type.h>
11
12using namespace parabix;
13
14enum SS_struct_index {iProducer_pos = 0, iConsumer_pos = 1, iEnd_of_input = 2, iBuffer_ptr = 3};
15
16llvm::Value * StreamSetBuffer::getProducerPosPtr(Value * bufferStructPtr) {
17    return iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)});
18}
19
20void StreamSetBuffer::setProducerPos(Value * bufferStructPtr, llvm::Value * pos) {
21    iBuilder->CreateStore(pos, getProducerPosPtr(bufferStructPtr));
22}
23
24llvm::Value * StreamSetBuffer::getConsumerPosPtr(Value * bufferStructPtr) {
25    return iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)});
26}
27
28void StreamSetBuffer::setConsumerPos(Value * bufferStructPtr, Value * pos) {
29    iBuilder->CreateStore(pos, getConsumerPosPtr(bufferStructPtr));
30}
31
32llvm::Value * StreamSetBuffer::getEndOfInputPtr(Value * bufferStructPtr) {
33    return iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)});
34}
35
36void StreamSetBuffer::setEndOfInput(Value * bufferStructPtr) {
37    iBuilder->CreateStore(ConstantInt::get(iBuilder->getInt1Ty(), 1), getEndOfInputPtr(bufferStructPtr));
38}
39
40void StreamSetBuffer::allocateBuffer() {
41    Type * const size_ty = iBuilder->getSizeTy();
42    Type * const int1ty = iBuilder->getInt1Ty();
43    mStreamSetBufferPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetType, ConstantInt::get(iBuilder->getSizeTy(), mBufferBlocks));
44    mStreamSetStructPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetStructType);
45    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
46    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}));
47    iBuilder->CreateStore(ConstantInt::get(int1ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)}));
48    iBuilder->CreateStore(mStreamSetBufferPtr, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}));
49}
50
51// Single Block Buffer
52// For a single block buffer, the block pointer is always the buffer base pointer.
53llvm::Value * SingleBlockBuffer::getStreamSetBlockPointer(llvm::Value * bufferStructPtr, llvm::Value *) {
54    Value * handle = iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)});
55    return iBuilder->CreateLoad(handle);
56}
57
58
59// External File Buffer
60
61void ExternalFileBuffer::setStreamSetBuffer(llvm::Value * ptr, Value * fileSize) {
62   
63    Type * const size_ty = iBuilder->getSizeTy();
64    Type * const int1ty = iBuilder->getInt1Ty();
65   
66    PointerType * t = getStreamBufferPointerType();   
67    mStreamSetBufferPtr = iBuilder->CreatePointerBitCastOrAddrSpaceCast(ptr, t);
68   
69    mStreamSetStructPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetStructType);
70    iBuilder->CreateStore(fileSize, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
71    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}));
72    iBuilder->CreateStore(ConstantInt::get(int1ty, 1), 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
76void ExternalFileBuffer::setEmptyBuffer(llvm::Value * ptr) {
77   
78    Type * const size_ty = iBuilder->getSizeTy();
79    Type * const int1ty = iBuilder->getInt1Ty();
80   
81    PointerType * t = getStreamBufferPointerType();   
82    mStreamSetBufferPtr = iBuilder->CreatePointerBitCastOrAddrSpaceCast(ptr, t);
83   
84    mStreamSetStructPtr = iBuilder->CreateCacheAlignedAlloca(mStreamSetStructType);
85    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
86    iBuilder->CreateStore(ConstantInt::get(size_ty, 0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)}));
87    iBuilder->CreateStore(ConstantInt::get(int1ty,0), iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iEnd_of_input)}));
88    iBuilder->CreateStore(mStreamSetBufferPtr, iBuilder->CreateGEP(mStreamSetStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)}));
89}
90
91void ExternalFileBuffer::allocateBuffer() {
92    throw std::runtime_error("External buffers cannot be allocated.");
93}
94
95llvm::Value * ExternalFileBuffer::getStreamSetBlockPointer(llvm::Value * bufferStructPtr, llvm::Value * blockNo) {
96    Value * handle = iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)});
97    Value * bufPtr = iBuilder->CreateLoad(handle);
98    return iBuilder->CreateGEP(bufPtr, blockNo);
99}
100
101// Circular Stack Allocated Buffer
102
103llvm::Value * CircularBuffer::getStreamSetBlockPointer(llvm::Value * bufferStructPtr, llvm::Value * blockNo) {
104    assert (blockNo->getType()->isIntegerTy());
105
106    Value * handle = iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)});
107    Value * bufPtr = iBuilder->CreateLoad(handle);
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(bufPtr, offset);
117}
118
119llvm::Value * LinearCopybackBuffer::getStreamSetBlockPointer(llvm::Value * bufferStructPtr, llvm::Value * blockNo) {
120    Constant * blockWidth = ConstantInt::get(iBuilder->getSizeTy(), iBuilder->getStride());
121    Value * consumerPos_ptr = iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iConsumer_pos)});
122    Value * consumerPos = iBuilder->CreateLoad(consumerPos_ptr);
123    Value * consumerBlock = iBuilder->CreateUDiv(consumerPos, blockWidth);
124    Value * handle = iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)});
125    Value * bufPtr = iBuilder->CreateLoad(handle);
126    return iBuilder->CreateGEP(bufPtr, {iBuilder->CreateSub(blockNo, consumerBlock)});
127}
128
129void LinearCopybackBuffer::setConsumerPos(Value * bufferStructPtr, Value * new_consumer_pos) {
130    Type * const i1 = iBuilder->getInt1Ty();
131    Type * const i8 = iBuilder->getInt8Ty();
132    Type * const i32 = iBuilder->getInt32Ty();
133    Type * const i8_ptr = i8->getPointerTo(mAddrSpace);
134    IntegerType * const sizeTy = iBuilder->getSizeTy();
135
136    Module * const M = iBuilder->getModule();
137
138    Function * const memmoveFunc = cast<Function>(M->getOrInsertFunction("llvm.memmove.p0i8.p0i8.i" + std::to_string(sizeTy->getBitWidth()),
139                                                                  iBuilder->getVoidTy(), i8_ptr, i8_ptr, sizeTy, i32, i1, nullptr));
140    Function * const current = iBuilder->GetInsertBlock()->getParent();
141    BasicBlock * const copyBackBody = BasicBlock::Create(M->getContext(), "copy_back", current, 0);
142    BasicBlock * const setConsumerPosExit = BasicBlock::Create(M->getContext(), "setConsumerPos_done", current, 0);
143    Constant * const blockWidth = ConstantInt::get(sizeTy, iBuilder->getStride());
144
145    Constant * const one = ConstantInt::get(sizeTy, 1);
146
147    Value * const consumerPosPtr = getConsumerPosPtr(bufferStructPtr);
148    Value * const consumerPos = iBuilder->CreateLoad(consumerPosPtr);
149
150    // Ensure that the new consumer position is no less than the current position.
151    new_consumer_pos = iBuilder->CreateSelect(iBuilder->CreateICmpULT(new_consumer_pos, consumerPos), consumerPos, new_consumer_pos);
152    Value * producerPos = iBuilder->CreateLoad(iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iProducer_pos)}));
153
154    // Ensure that the new consumer position is no greater than the current producer position.
155    Value * new_pos_lt_producer_pos = iBuilder->CreateICmpULT(new_consumer_pos, producerPos);
156    new_consumer_pos = iBuilder->CreateSelect(new_pos_lt_producer_pos, new_consumer_pos, producerPos);
157
158    // Now, the new_consumer_pos is at most = to the producer_pos; if =, we're done.
159    iBuilder->CreateCondBr(new_pos_lt_producer_pos, copyBackBody, setConsumerPosExit);
160    iBuilder->SetInsertPoint(copyBackBody);
161   
162    Value * new_consumer_block = iBuilder->CreateUDiv(new_consumer_pos, blockWidth);
163    Value * lastProducerBlock = iBuilder->CreateUDiv(iBuilder->CreateSub(producerPos, one), blockWidth);
164    Value * copyBlocks = iBuilder->CreateAdd(iBuilder->CreateSub(lastProducerBlock, new_consumer_block), one);
165
166    DataLayout dl(iBuilder->getModule());
167
168    Constant * blockBytes = ConstantInt::get(sizeTy, dl.getTypeAllocSize(mStreamSetType) * iBuilder->getStride());
169
170    Value * copyLength = iBuilder->CreateMul(copyBlocks, blockBytes);
171
172    // Must copy back one full block for each of the streams in the stream set.
173    Value * handle = iBuilder->CreateGEP(bufferStructPtr, {iBuilder->getInt32(0), iBuilder->getInt32(iBuffer_ptr)});
174    Value * bufferPtr = iBuilder->CreateLoad(handle);
175    Value * const consumerBlock = iBuilder->CreateUDiv(consumerPos, blockWidth);
176    Value * copyFrom = iBuilder->CreateGEP(bufferPtr, {iBuilder->CreateSub(new_consumer_block, consumerBlock)});
177    Value * alignment = ConstantInt::get(iBuilder->getInt32Ty(), iBuilder->getBitBlockWidth() / 8);
178   
179    iBuilder->CreateCall(memmoveFunc, {iBuilder->CreateBitCast(bufferPtr, i8_ptr), iBuilder->CreateBitCast(copyFrom, i8_ptr), copyLength, alignment, ConstantInt::getNullValue(i1)});
180    iBuilder->CreateBr(setConsumerPosExit);
181    // Copy back done, store the new consumer position.
182    iBuilder->SetInsertPoint(setConsumerPosExit);
183
184    iBuilder->CreateStore(new_consumer_pos, consumerPosPtr);
185}   
Note: See TracBrowser for help on using the repository browser.