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

Last change on this file since 5751 was 5706, checked in by nmedfort, 23 months ago

First stage of MultiBlockKernel? and pipeline restructuring

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::addInternalKernelProperties(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}
136
137void PabloKernel::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & iBuilder) {
138    mSizeTy = iBuilder->getSizeTy();
139    mStreamTy = iBuilder->getStreamTy();
140    mPabloCompiler->compile(iBuilder);
141    mSizeTy = nullptr;
142    mStreamTy = nullptr;
143}
144
145void PabloKernel::generateFinalBlockMethod(const std::unique_ptr<KernelBuilder> & iBuilder, Value * const remainingBytes) {
146    // Standard Pablo convention for final block processing: set a bit marking
147    // the position just past EOF, as well as a mask marking all positions past EOF.
148    iBuilder->setScalarField("EOFbit", iBuilder->bitblock_set_bit(remainingBytes));
149    iBuilder->setScalarField("EOFmask", iBuilder->bitblock_mask_from(remainingBytes));
150    CreateDoBlockMethodCall(iBuilder);
151}
152
153void PabloKernel::generateFinalizeMethod(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) {
154    mPabloCompiler->releaseKernelData(iBuilder);
155
156    if (CompileOptionIsSet(PabloCompilationFlags::EnableProfiling)) {
157
158
159        Value * fd = iBuilder->CreateOpenCall(iBuilder->GetString("./" + getName() + ".profile"),
160                                              iBuilder->getInt32(O_WRONLY | O_CREAT | O_TRUNC),
161                                              iBuilder->getInt32(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH));
162
163        Function * dprintf = iBuilder->GetDprintf();
164
165
166
167        Value * profile = iBuilder->getScalarFieldPtr("profile");
168
169
170        unsigned branchCount = 0;
171
172        for (const auto bb : mPabloCompiler->mBasicBlock) {
173
174            std::string tmp;
175            raw_string_ostream str(tmp);
176            str << "%lu\t";
177            str << bb->getName();
178            str << "\n";
179
180            Value * taken = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(branchCount++)}));
181            iBuilder->CreateCall(dprintf, {fd, iBuilder->GetString(str.str()), taken});
182
183        }
184
185//        Value * base = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(0)}));
186//        base = iBuilder->CreateUIToFP(base, iBuilder->getDoubleTy());
187
188//        unsigned branchCount = 0;
189//        std::function<void (const PabloBlock *)> writeProfile = [&](const PabloBlock * const scope) {
190//            for (const Statement * stmt : *scope) {
191//                if (isa<Branch>(stmt)) {
192
193//                    ++branchCount;
194
195//                    std::string tmp;
196//                    raw_string_ostream str(tmp);
197//                    str << "%3.3f\t";
198//                    str << mPabloCompiler->getBranchEntry(branchCount)->getName();
199//                    str << "\n";
200
201//                    Value * branches = iBuilder->CreateLoad(iBuilder->CreateGEP(profile, {iBuilder->getInt32(0), iBuilder->getInt32(branchCount)}));
202//                    branches = iBuilder->CreateUIToFP(branches, iBuilder->getDoubleTy());
203//                    Value * prob = iBuilder->CreateFDiv(branches, base);
204//                    iBuilder->CreateCall(dprintf, {fd, iBuilder->GetString(str.str()), prob});
205
206//                    writeProfile(cast<Branch>(stmt)->getBody());
207
208//                }
209//            }
210//        };
211
212//        writeProfile(getEntryBlock());
213        iBuilder->CreateCloseCall(fd);
214    }
215
216}
217
218String * PabloKernel::makeName(const llvm::StringRef & prefix) const {
219    return mSymbolTable->makeString(prefix);
220}
221
222Integer * PabloKernel::getInteger(const int64_t value) const {
223    return mSymbolTable->getInteger(value);
224}
225
226llvm::IntegerType * PabloKernel::getInt1Ty() const {
227    return IntegerType::getInt1Ty(getModule()->getContext());
228}
229
230static inline std::string && annotateKernelNameWithDebugFlags(std::string && name) {
231    if (DebugOptionIsSet(DumpTrace)) {
232        name += "_DumpTrace";
233    }
234    if (CompileOptionIsSet(EnableProfiling)) {
235        name += "_BranchProfiling";
236    }
237    return std::move(name);
238}
239
240PabloKernel::PabloKernel(const std::unique_ptr<KernelBuilder> & b,
241                         std::string && kernelName,
242                         std::vector<Binding> stream_inputs,
243                         std::vector<Binding> stream_outputs,
244                         std::vector<Binding> scalar_parameters,
245                         std::vector<Binding> scalar_outputs)
246: BlockOrientedKernel(annotateKernelNameWithDebugFlags(std::move(kernelName)),
247                      std::move(stream_inputs), std::move(stream_outputs), 
248                      std::move(scalar_parameters), std::move(scalar_outputs),
249                      {Binding{b->getBitBlockType(), "EOFbit"}, Binding{b->getBitBlockType(), "EOFmask"}})
250, PabloAST(PabloAST::ClassTypeId::Kernel, nullptr, mAllocator)
251, mPabloCompiler(new PabloCompiler(this))
252, mSymbolTable(new SymbolGenerator(b->getContext(), mAllocator))
253, mEntryBlock(PabloBlock::Create(this))
254, mSizeTy(nullptr)
255, mStreamTy(nullptr) {
256    prepareStreamSetNameMap();
257    for (const Binding & ss : mStreamSetInputs) {
258        Var * param = new (mAllocator) Var(makeName(ss.getName()), ss.getType(), mAllocator, Var::KernelInputParameter);
259        param->addUser(this);
260        mInputs.push_back(param);
261        mVariables.push_back(param);
262    }
263    for (const Binding & ss : mStreamSetOutputs) {
264        Var * result = new (mAllocator) Var(makeName(ss.getName()), ss.getType(), mAllocator, Var::KernelOutputParameter);
265        result->addUser(this);
266        mOutputs.push_back(result);
267        mVariables.push_back(result);
268    }
269    for (const Binding & ss : mScalarOutputs) {
270        Var * result = new (mAllocator) Var(makeName(ss.getName()), ss.getType(), mAllocator, Var::KernelOutputParameter);
271        result->addUser(this);
272        mOutputs.push_back(result);
273        mVariables.push_back(result);
274        mScalarOutputNameMap.emplace(ss.getName(), result);
275        result->setScalar();
276    }
277}
278
279PabloKernel::~PabloKernel() {
280    delete mPabloCompiler;
281    delete mSymbolTable; 
282}
283
284}
Note: See TracBrowser for help on using the repository browser.