source: icGREP/icgrep-devel/icgrep/pablo/pablo_kernel.cpp @ 6184

Last change on this file since 6184 was 6184, checked in by nmedfort, 8 months ago

Initial version of PipelineKernel? + revised StreamSet? model.

File size: 9.8 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 "pablo_kernel.h"
7#include <pablo/codegenstate.h>
8#include <pablo/pablo_compiler.h>
9#include <pablo/pe_var.h>
10#include <pablo/pe_zeroes.h>
11#include <pablo/pe_ones.h>
12#include <pablo/pablo_toolchain.h>
13#include <kernels/kernel_builder.h>
14#include <kernels/streamset.h>
15#include <llvm/IR/Module.h>
16
17#include <pablo/branch.h>
18#include <sys/stat.h>
19#include <fcntl.h>
20#include <llvm/Support/raw_ostream.h>
21
22using namespace kernel;
23using namespace IDISA;
24using namespace llvm;
25
26namespace pablo {
27
28Var * PabloKernel::getInputStreamVar(const std::string & name) {
29    Port port; unsigned index;
30    std::tie(port, index) = getStreamPort(name);
31    assert (port == Port::Input);
32    return mInputs[index];
33}
34
35std::vector<PabloAST *> PabloKernel::getInputStreamSet(const std::string & name) {
36    unsigned index; Port port;
37    std::tie(port, index) = getStreamPort(name);
38    assert (port == Port::Input);
39    const Binding & input = getInputStreamSetBinding(index);
40    const auto numOfStreams = IDISA::getNumOfStreams(input.getType());
41    std::vector<PabloAST *> inputSet(numOfStreams);
42    for (unsigned i = 0; i < numOfStreams; i++) {
43        inputSet[i] = mEntryScope->createExtract(mInputs[index], mEntryScope->getInteger(i));
44    }
45    return inputSet;
46}
47
48
49Var * PabloKernel::getOutputStreamVar(const std::string & name) {
50    Port port; unsigned index;
51    std::tie(port, index) = getStreamPort(name);
52    assert (port == Port::Output);
53    return mOutputs[index];
54}
55
56Var * PabloKernel::getOutputScalarVar(const std::string & name) {
57    for (Var * out : mScalarOutputVars) {
58        if (out->getName().equals(name)) {
59            return out;
60        }
61    }
62    report_fatal_error("Kernel does not contain scalar " + name);
63}
64
65Var * PabloKernel::makeVariable(const String * name, Type * const type) {
66    Var * const var = new (mAllocator) Var(name, type, mAllocator);
67    mVariables.push_back(var);
68    return var;
69}
70
71Zeroes * PabloKernel::getNullValue(Type * type) {
72    if (LLVM_LIKELY(type == nullptr)) {
73        type = getStreamTy();
74    }
75    for (PabloAST * constant : mConstants) {
76        if (isa<Zeroes>(constant) && constant->getType() == type) {
77            return cast<Zeroes>(constant);
78        }
79    }
80    Zeroes * value = new (mAllocator) Zeroes(type, mAllocator);
81    mConstants.push_back(value);
82    return value;
83}
84
85Ones * PabloKernel::getAllOnesValue(Type * type) {
86    if (LLVM_LIKELY(type == nullptr)) {
87        type = getStreamTy();
88    }
89    for (PabloAST * constant : mConstants) {
90        if (isa<Ones>(constant) && constant->getType() == type) {
91            return cast<Ones>(constant);
92        }
93    }
94    Ones * value = new (mAllocator) Ones(type, mAllocator);
95    mConstants.push_back(value);
96    return value;
97}
98
99void PabloKernel::addInternalKernelProperties(const std::unique_ptr<kernel::KernelBuilder> & b) {
100    mSizeTy = b->getSizeTy();
101    mStreamTy = b->getStreamTy();
102    mSymbolTable = new SymbolGenerator(b->getContext(), mAllocator);
103    mEntryScope = new (mAllocator) PabloBlock(this, mAllocator);
104    mContext = &b->getContext();
105    for (const Binding & ss : mInputStreamSets) {
106        Var * param = new (mAllocator) Var(makeName(ss.getName()), ss.getType(), mAllocator, Var::KernelInputParameter);
107        param->addUser(this);
108        mInputs.push_back(param);
109        mVariables.push_back(param);
110    }
111    for (const Binding & ss : mOutputStreamSets) {
112        Var * result = new (mAllocator) Var(makeName(ss.getName()), ss.getType(), mAllocator, Var::KernelOutputParameter);
113        result->addUser(this);
114        mOutputs.push_back(result);
115        mVariables.push_back(result);
116    }
117    for (const Binding & ss : mOutputScalars) {
118        Var * result = new (mAllocator) Var(makeName(ss.getName()), ss.getType(), mAllocator, Var::KernelOutputParameter);
119        result->addUser(this);
120        mOutputs.push_back(result);
121        mVariables.push_back(result);
122        mScalarOutputVars.push_back(result);
123        result->setScalar();
124    }
125    generatePabloMethod();   
126    pablo_function_passes(this);
127    mPabloCompiler = new PabloCompiler(this);
128    mPabloCompiler->initializeKernelData(b);
129    mSizeTy = nullptr;
130    mStreamTy = nullptr;   
131}
132
133void PabloKernel::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & iBuilder) {
134    mSizeTy = iBuilder->getSizeTy();
135    mStreamTy = iBuilder->getStreamTy();
136    mPabloCompiler->compile(iBuilder);
137    mSizeTy = nullptr;
138    mStreamTy = nullptr;
139}
140
141#if 0
142void PabloKernel::beginConditionalRegion(const std::unique_ptr<KernelBuilder> & b) {
143    mPabloCompiler->clearCarryData(b);
144}
145#endif
146
147void PabloKernel::generateFinalBlockMethod(const std::unique_ptr<KernelBuilder> & b, Value * const remainingBytes) {
148    // Standard Pablo convention for final block processing: set a bit marking
149    // the position just past EOF, as well as a mask marking all positions past EOF.
150    b->setScalarField("EOFbit", b->bitblock_set_bit(remainingBytes));
151    b->setScalarField("EOFmask", b->bitblock_mask_from(remainingBytes));
152    CreateDoBlockMethodCall(b);
153
154//    // TODO: clean this up. what if we have a subclass of block oriented kernels that has hooks for inserting code
155//    // before/after calling the do block logic? it would simplify the logic and hopefully allow easier use. Moreover
156//    // we may be able to convert some of the final block only scalars to stack oriented ones
157
158//    Value * const baseOutputItems = getRemainingItems(b);
159//    // clear all of the outputs past the EOF mark
160//    for (unsigned i = 0; i < mStreamSetOutputs.size(); ++i) {
161//        const Binding & output = mStreamSetOutputs[i];
162//        // TODO: test if this is a bitstream output
163//        Value * outputItems = baseOutputItems;
164//        for (const kernel::Attribute & attr : output.getAttributes()) {
165//            if (attr.isAdd()) {
166//                outputItems = b->CreateAdd(outputItems, b->getSize(attr.amount()));
167//                break;
168//            }
169//        }
170//        Value * const inFileMask = b->CreateNot(b->bitblock_mask_from(outputItems));
171//        BasicBlock * const zeroOutEntry = b->GetInsertBlock();
172//        BasicBlock * const zeroOutLoop = b->CreateBasicBlock();
173//        BasicBlock * const zeroOutExit = b->CreateBasicBlock();
174//        Value * const n = b->getOutputStreamSetCount(output.getName());
175//        b->CreateBr(zeroOutLoop);
176
177//        b->SetInsertPoint(zeroOutLoop);
178//        PHINode * const streamIndex = b->CreatePHI(b->getSizeTy(), 2);
179//        streamIndex->addIncoming(b->getSize(0), zeroOutEntry);
180//        Value * const ptr = b->getOutputStreamBlockPtr(output.getName(), streamIndex);
181//        Value * const value = b->CreateBlockAlignedLoad(ptr);
182//        b->CreateBlockAlignedStore(b->CreateAnd(value, inFileMask), ptr);
183//        Value * const nextStreamIndex = b->CreateAdd(streamIndex, b->getSize(1));
184//        streamIndex->addIncoming(nextStreamIndex, zeroOutLoop);
185//        b->CreateCondBr(b->CreateICmpNE(nextStreamIndex, n), zeroOutLoop, zeroOutExit);
186
187//        b->SetInsertPoint(zeroOutExit);
188//    }
189
190}
191
192void PabloKernel::generateFinalizeMethod(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) {
193    mPabloCompiler->releaseKernelData(iBuilder);
194
195    if (CompileOptionIsSet(PabloCompilationFlags::EnableProfiling)) {
196
197
198        Value * fd = iBuilder->CreateOpenCall(iBuilder->GetString("./" + getName() + ".profile"),
199                                              iBuilder->getInt32(O_WRONLY | O_CREAT | O_TRUNC),
200                                              iBuilder->getInt32(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH));
201
202        Function * dprintf = iBuilder->GetDprintf();
203
204
205
206        Value * profile = iBuilder->getScalarFieldPtr("profile");
207
208
209        unsigned branchCount = 0;
210
211        for (const auto bb : mPabloCompiler->mBasicBlock) {
212
213            std::string tmp;
214            raw_string_ostream str(tmp);
215            str << "%lu\t";
216            str << bb->getName();
217            str << "\n";
218
219            Value * taken = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(branchCount++)}));
220            iBuilder->CreateCall(dprintf, {fd, iBuilder->GetString(str.str()), taken});
221
222        }
223
224        iBuilder->CreateCloseCall(fd);
225    }
226
227}
228
229String * PabloKernel::makeName(const llvm::StringRef & prefix) const {
230    return mSymbolTable->makeString(prefix);
231}
232
233Integer * PabloKernel::getInteger(const int64_t value) const {
234    return mSymbolTable->getInteger(value);
235}
236
237llvm::IntegerType * PabloKernel::getInt1Ty() const {
238    return IntegerType::getInt1Ty(getModule()->getContext());
239}
240
241static inline std::string && annotateKernelNameWithPabloDebugFlags(std::string && name) {
242    if (DebugOptionIsSet(DumpTrace)) {
243        name += "_DumpTrace";
244    }
245    if (CompileOptionIsSet(EnableProfiling)) {
246        name += "_BranchProfiling";
247    }
248    return std::move(name);
249}
250
251PabloKernel::PabloKernel(const std::unique_ptr<KernelBuilder> & b,
252                         std::string && kernelName,
253                         std::vector<Binding> stream_inputs,
254                         std::vector<Binding> stream_outputs,
255                         std::vector<Binding> scalar_parameters,
256                         std::vector<Binding> scalar_outputs)
257: BlockOrientedKernel(annotateKernelNameWithPabloDebugFlags(std::move(kernelName)),
258                      std::move(stream_inputs), std::move(stream_outputs), 
259                      std::move(scalar_parameters), std::move(scalar_outputs),
260                      {Binding{b->getBitBlockType(), "EOFbit"}, Binding{b->getBitBlockType(), "EOFmask"}})
261, PabloAST(PabloAST::ClassTypeId::Kernel, nullptr, mAllocator)
262, mPabloCompiler(nullptr)
263, mSymbolTable(nullptr)
264, mEntryScope(nullptr)
265, mSizeTy(nullptr)
266, mStreamTy(nullptr)
267, mContext(nullptr) {
268
269}
270
271PabloKernel::~PabloKernel() {
272    delete mPabloCompiler;
273    delete mSymbolTable; 
274}
275
276}
Note: See TracBrowser for help on using the repository browser.