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

Last change on this file since 5620 was 5620, checked in by nmedfort, 19 months ago

Bug fixes for multigrep mode. Optional PabloKernel? branch hit counter added. Minor optimizations.

File size: 9.9 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 <llvm/IR/Module.h>
15
16#include <pablo/branch.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <llvm/Support/raw_ostream.h>
20
21using namespace kernel;
22using namespace parabix;
23using namespace IDISA;
24using namespace llvm;
25
26inline bool isStreamType(const Type * ty) {
27    if (ty->isArrayTy()) {
28        ty = ty->getArrayElementType();
29    }
30    if (ty->isVectorTy()) {
31        return (ty->getVectorNumElements() == 0);
32    }
33    return false;
34}
35
36namespace pablo {
37
38Var * PabloKernel::getInputStreamVar(const std::string & name) {
39    Port port; unsigned index;
40    std::tie(port, index) = getStreamPort(name);
41    assert (port == Port::Input);
42    return mInputs[index];
43}
44
45Var * PabloKernel::getOutputStreamVar(const std::string & name) {
46    Port port; unsigned index;
47    std::tie(port, index) = getStreamPort(name);
48    assert (port == Port::Output);
49    return mOutputs[index];
50}
51
52Var * PabloKernel::getOutputScalarVar(const std::string & name) {
53    const auto f = mScalarOutputNameMap.find(name);
54    if (LLVM_UNLIKELY(f == mScalarOutputNameMap.end())) {
55        report_fatal_error("Kernel does not contain scalar: " + name);
56    }
57    return f->second;
58}
59
60Var * PabloKernel::addInput(const std::string & name, Type * const type) {
61    Var * param = new (mAllocator) Var(makeName(name), type, mAllocator, Var::KernelInputParameter);
62    param->addUser(this);
63    mInputs.push_back(param);
64    mVariables.push_back(param);
65    if (isStreamType(type)) {
66        mStreamMap.emplace(name, std::make_pair(Port::Input, mStreamSetInputs.size()));
67        mStreamSetInputs.emplace_back(type, name);       
68    } else {
69        mScalarInputs.emplace_back(type, name);
70        param->setScalar();
71    }
72    assert (mStreamSetInputs.size() + mScalarInputs.size() == mInputs.size());
73    return param;
74}
75
76Var * PabloKernel::addOutput(const std::string & name, Type * const type) {
77    Var * result = new (mAllocator) Var(makeName(name), type, mAllocator, Var::KernelOutputParameter);
78    result->addUser(this);
79    mOutputs.push_back(result);
80    mVariables.push_back(result);
81    if (isStreamType(type)) {
82        mStreamMap.emplace(name, std::make_pair(Port::Output, mStreamSetOutputs.size()));
83        mStreamSetOutputs.emplace_back(type, name);
84    } else {
85        mScalarOutputs.emplace_back(type, name);
86        mScalarOutputNameMap.emplace(name, result);
87        result->setScalar();
88    }
89    assert (mStreamSetOutputs.size() + mScalarOutputs.size() == mOutputs.size());
90    return result;
91}
92
93Var * PabloKernel::makeVariable(String * name, Type * const type) {
94    Var * const var = new (mAllocator) Var(name, type, mAllocator);
95    mVariables.push_back(var);
96    return var;
97}
98
99Zeroes * PabloKernel::getNullValue(Type * type) {
100    if (LLVM_LIKELY(type == nullptr)) {
101        type = getStreamTy();
102    }
103    for (PabloAST * constant : mConstants) {
104        if (isa<Zeroes>(constant) && constant->getType() == type) {
105            return cast<Zeroes>(constant);
106        }
107    }
108    Zeroes * value = new (mAllocator) Zeroes(type, mAllocator);
109    mConstants.push_back(value);
110    return value;
111}
112
113Ones * PabloKernel::getAllOnesValue(Type * type) {
114    if (LLVM_LIKELY(type == nullptr)) {
115        type = getStreamTy();
116    }
117    for (PabloAST * constant : mConstants) {
118        if (isa<Ones>(constant) && constant->getType() == type) {
119            return cast<Ones>(constant);
120        }
121    }
122    Ones * value = new (mAllocator) Ones(type, mAllocator);
123    mConstants.push_back(value);
124    return value;
125}
126
127void PabloKernel::prepareKernel(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) {
128    mSizeTy = iBuilder->getSizeTy();
129    mStreamTy = iBuilder->getStreamTy();
130    generatePabloMethod();   
131    pablo_function_passes(this);
132    mPabloCompiler->initializeKernelData(iBuilder);
133    mSizeTy = nullptr;
134    mStreamTy = nullptr;
135    BlockOrientedKernel::prepareKernel(iBuilder);
136}
137
138void PabloKernel::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & iBuilder) {
139    mSizeTy = iBuilder->getSizeTy();
140    mStreamTy = iBuilder->getStreamTy();
141    mPabloCompiler->compile(iBuilder);
142    mSizeTy = nullptr;
143    mStreamTy = nullptr;
144}
145
146void PabloKernel::generateFinalBlockMethod(const std::unique_ptr<KernelBuilder> & iBuilder, Value * const remainingBytes) {
147    // Standard Pablo convention for final block processing: set a bit marking
148    // the position just past EOF, as well as a mask marking all positions past EOF.
149    iBuilder->setScalarField("EOFbit", iBuilder->bitblock_set_bit(remainingBytes));
150    iBuilder->setScalarField("EOFmask", iBuilder->bitblock_mask_from(remainingBytes));
151    CreateDoBlockMethodCall(iBuilder);
152}
153
154void PabloKernel::generateFinalizeMethod(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) {
155    mPabloCompiler->releaseKernelData(iBuilder);
156
157    if (CompileOptionIsSet(PabloCompilationFlags::EnableProfiling)) {
158
159
160        Value * fd = iBuilder->CreateOpenCall(iBuilder->GetString("./" + getName() + ".profile"),
161                                              iBuilder->getInt32(O_WRONLY | O_CREAT | O_TRUNC),
162                                              iBuilder->getInt32(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH));
163
164        Function * dprintf = iBuilder->GetDprintf();
165
166
167
168        Value * profile = iBuilder->getScalarFieldPtr("profile");
169
170
171        unsigned branchCount = 0;
172
173        for (const auto bb : mPabloCompiler->mBasicBlock) {
174
175            std::string tmp;
176            raw_string_ostream str(tmp);
177            str << "%lu\t";
178            str << bb->getName();
179            str << "\n";
180
181            Value * taken = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(branchCount++)}));
182            iBuilder->CreateCall(dprintf, {fd, iBuilder->GetString(str.str()), taken});
183
184        }
185
186//        Value * base = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(0)}));
187//        base = iBuilder->CreateUIToFP(base, iBuilder->getDoubleTy());
188
189//        unsigned branchCount = 0;
190//        std::function<void (const PabloBlock *)> writeProfile = [&](const PabloBlock * const scope) {
191//            for (const Statement * stmt : *scope) {
192//                if (isa<Branch>(stmt)) {
193
194//                    ++branchCount;
195
196//                    std::string tmp;
197//                    raw_string_ostream str(tmp);
198//                    str << "%3.3f\t";
199//                    str << mPabloCompiler->getBranchEntry(branchCount)->getName();
200//                    str << "\n";
201
202//                    Value * branches = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(branchCount)}));
203//                    branches = iBuilder->CreateUIToFP(branches, iBuilder->getDoubleTy());
204//                    Value * prob = iBuilder->CreateFDiv(branches, base);
205//                    iBuilder->CreateCall(dprintf, {fd, iBuilder->GetString(str.str()), prob});
206
207//                    writeProfile(cast<Branch>(stmt)->getBody());
208
209//                }
210//            }
211//        };
212
213//        writeProfile(getEntryBlock());
214        iBuilder->CreateCloseCall(fd);
215    }
216
217}
218
219String * PabloKernel::makeName(const llvm::StringRef & prefix) const {
220    return mSymbolTable->makeString(prefix);
221}
222
223Integer * PabloKernel::getInteger(const int64_t value) const {
224    return mSymbolTable->getInteger(value);
225}
226
227llvm::IntegerType * PabloKernel::getInt1Ty() const {
228    return IntegerType::getInt1Ty(getModule()->getContext());
229}
230
231static inline std::string && annotateKernelNameWithDebugFlags(std::string && name) {
232    if (DebugOptionIsSet(DumpTrace)) {
233        name += "_DumpTrace";
234    }
235    if (CompileOptionIsSet(EnableProfiling)) {
236        name += "_BranchProfiling";
237    }
238    return std::move(name);
239}
240
241PabloKernel::PabloKernel(const std::unique_ptr<KernelBuilder> & b,
242                         std::string && kernelName,
243                         std::vector<Binding> stream_inputs,
244                         std::vector<Binding> stream_outputs,
245                         std::vector<Binding> scalar_parameters,
246                         std::vector<Binding> scalar_outputs)
247: BlockOrientedKernel(annotateKernelNameWithDebugFlags(std::move(kernelName)),
248                      std::move(stream_inputs), std::move(stream_outputs), 
249                      std::move(scalar_parameters), std::move(scalar_outputs),
250                      {Binding{b->getBitBlockType(), "EOFbit"}, Binding{b->getBitBlockType(), "EOFmask"}})
251, PabloAST(PabloAST::ClassTypeId::Kernel, nullptr, mAllocator)
252, mPabloCompiler(new PabloCompiler(this))
253, mSymbolTable(new SymbolGenerator(b->getContext(), mAllocator))
254, mEntryBlock(PabloBlock::Create(this))
255, mSizeTy(nullptr)
256, mStreamTy(nullptr) {
257    prepareStreamSetNameMap();
258    for (const Binding & ss : mStreamSetInputs) {
259        Var * param = new (mAllocator) Var(makeName(ss.name), ss.type, mAllocator, Var::KernelInputParameter);
260        param->addUser(this);
261        mInputs.push_back(param);
262        mVariables.push_back(param);
263    }
264    for (const Binding & ss : mStreamSetOutputs) {
265        Var * result = new (mAllocator) Var(makeName(ss.name), ss.type, mAllocator, Var::KernelOutputParameter);
266        result->addUser(this);
267        mOutputs.push_back(result);
268        mVariables.push_back(result);
269    }
270    for (const Binding & ss : mScalarOutputs) {
271        Var * result = new (mAllocator) Var(makeName(ss.name), ss.type, mAllocator, Var::KernelOutputParameter);
272        result->addUser(this);
273        mOutputs.push_back(result);
274        mVariables.push_back(result);
275        mScalarOutputNameMap.emplace(ss.name, result);
276        result->setScalar();
277    }
278}
279
280PabloKernel::~PabloKernel() {
281    delete mPabloCompiler;
282    delete mSymbolTable; 
283}
284
285}
Note: See TracBrowser for help on using the repository browser.