source: icGREP/icgrep-devel/icgrep/kernels/random_stream.cpp @ 6297

Last change on this file since 6297 was 6261, checked in by nmedfort, 7 months ago

Work on OptimizationBranch?; revisited pipeline termination

File size: 5.2 KB
Line 
1/*
2 *  Copyright (c) 2018 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5#include "random_stream.h"
6#include <llvm/IR/Module.h>
7#include <kernels/kernel_builder.h>
8#include <kernels/streamset.h>
9#include <toolchain/toolchain.h>
10
11using namespace kernel;
12using namespace llvm;
13
14void RandomStreamKernel::generateInitializeMethod(const std::unique_ptr<kernel::KernelBuilder> & b) {
15    b->CreateSRandCall(b->getInt32(mSeed));
16}
17
18/* Generate the next segment of random values.   Input requirement:
19   the output buffer has a full segment of space available. */
20void RandomStreamKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> & b) {
21    const size_t randIntSize = 32;  // from standard C rand function
22    const size_t segmentItems = codegen::SegmentSize * codegen::BlockSize;
23    //
24    // The item width (mValueWidth) for the desired random value stream may
25    // be a single bit or any power of 2.   Determine the number of 32-bit values
26    // returned by rand that are necessary for a full segment of the random
27    // value stream.
28    const size_t segmentRandInts = segmentItems * mValueWidth/randIntSize;
29
30    BasicBlock * const entry = b->GetInsertBlock();
31    BasicBlock * const genNextRVsegment = b->CreateBasicBlock("genNextRVsegment");
32    BasicBlock * const genFinalRVsegment = b->CreateBasicBlock("genFinalRVsegment");
33    BasicBlock * const exit = b->CreateBasicBlock("exit");
34
35    Constant * strmLgthConst = ConstantInt::get(b->getSizeTy(), mStreamLength);
36    Constant * segmentItemConst = ConstantInt::get(b->getSizeTy(), segmentItems);
37    Constant * segmentRandIntConst = ConstantInt::get(b->getSizeTy(), segmentRandInts);
38    Value * produced = b->getProducedItemCount("randomValues");
39    Value * rvBuffer = b->getRawOutputPointer("randomValues", b->getInt32(0));
40    rvBuffer = b->CreateBitCast(rvBuffer, b->getInt32Ty()->getPointerTo());
41    Value * addFullSegment = b->CreateAdd(produced, segmentItemConst);
42    Value * moreToDoLater = b->CreateICmpULT(addFullSegment, strmLgthConst);
43    b->CreateCondBr(moreToDoLater, genNextRVsegment, genFinalRVsegment);
44
45    b->SetInsertPoint(genNextRVsegment);
46    PHINode* rvNumPHI = b->CreatePHI(b->getSizeTy(), 2);
47    rvNumPHI->addIncoming(b->getSize(0), entry);
48    // Use b->getBitBlockWidth()/randIntSize as an unroll factor
49    Value * rvNo = rvNumPHI;
50    for (unsigned i = 0; i < b->getBitBlockWidth()/randIntSize; i++) {
51        Value * randVal = b->CreateRandCall();
52        b->CreateStore(randVal, b->CreateGEP(rvBuffer, rvNo));
53        rvNo = b->CreateAdd(rvNo, b->getSize(1));
54    }
55    rvNumPHI->addIncoming(rvNo, genNextRVsegment);
56    b->CreateCondBr(b->CreateICmpULT(rvNo, segmentRandIntConst), genNextRVsegment, exit);
57
58    b->SetInsertPoint(genFinalRVsegment);
59    const size_t remainingItems = mStreamLength % segmentItems;
60    const size_t remainingBits = remainingItems * mValueWidth;
61    const size_t remainingFullRandInts = remainingBits/randIntSize;
62    const size_t partialRandInt = remainingBits % randIntSize;
63    const size_t zeroFill = (segmentItems - remainingItems) * mValueWidth/randIntSize;
64    if (remainingFullRandInts > 0) {
65        rvNumPHI = b->CreatePHI(b->getSizeTy(), 2);
66        rvNumPHI->addIncoming(b->getSize(0), entry);
67        rvNo = rvNumPHI;
68        Value * randVal = b->CreateRandCall();
69        b->CreateStore(randVal, b->CreateGEP(rvBuffer, rvNo));
70        rvNo = b->CreateAdd(rvNo, b->getSize(1));
71        rvNumPHI->addIncoming(rvNo, b->GetInsertBlock());
72        Value * moreToDo = b->CreateICmpULT(rvNo, ConstantInt::get(b->getSizeTy(), remainingFullRandInts));
73        BasicBlock * const finalSegmentExit = b->CreateBasicBlock("finalSegmentExit");
74        b->CreateCondBr(moreToDo, genFinalRVsegment, finalSegmentExit);
75        b->SetInsertPoint(finalSegmentExit);
76    }
77    if (partialRandInt > 0) {
78        Constant * mask = ConstantInt::get(b->getInt32Ty(), APInt::getLowBitsSet(randIntSize, partialRandInt));
79        Value * partialRV = b->CreateAnd(mask, b->CreateRandCall());
80        b->CreateStore(partialRV, b->CreateGEP(rvBuffer, rvNo));
81    }
82    if (zeroFill > 0) {
83        if (partialRandInt > 0) rvNo = b->CreateAdd(rvNo, b->getSize(1));
84        b->CreateMemZero(b->CreateGEP(rvBuffer, rvNo), b->getSize(zeroFill/8));
85    }
86    b->setTerminationSignal();
87    BasicBlock * finalBB = b->GetInsertBlock();
88    b->CreateBr(exit);
89    // The required random values have all been written, update the
90    // produced item count.
91    b->SetInsertPoint(exit);
92    PHINode* finalProducedPHI = b->CreatePHI(b->getSizeTy(), 2);
93    finalProducedPHI->addIncoming(addFullSegment, genNextRVsegment);
94    finalProducedPHI->addIncoming(strmLgthConst, finalBB);
95    b->setProducedItemCount("randomValues", finalProducedPHI);
96}
97
98RandomStreamKernel::RandomStreamKernel(const std::unique_ptr<kernel::KernelBuilder> & b, unsigned seed, unsigned valueWidth, size_t streamLength)
99: SegmentOrientedKernel(b, "rand" + std::to_string(valueWidth) + "_" + std::to_string(seed) + "_" + std::to_string(streamLength),
100// input
101{},
102// output
103{Binding{b->getStreamSetTy(1, valueWidth), "randomValues"}},
104// scalars
105{}, {}, {})
106, mSeed(seed)
107, mValueWidth(valueWidth)
108, mStreamLength(streamLength) {
109}
110
Note: See TracBrowser for help on using the repository browser.