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

Last change on this file was 6273, checked in by nmedfort, 7 months ago

More work on optimization branch. First stage of stateless kernel optimization

File size: 9.8 KB
RevLine 
[5057]1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5
[5260]6#include "pablo_kernel.h"
[5227]7#include <pablo/codegenstate.h>
[5059]8#include <pablo/pablo_compiler.h>
[5202]9#include <pablo/pe_var.h>
[5267]10#include <pablo/pe_zeroes.h>
11#include <pablo/pe_ones.h>
[5418]12#include <pablo/pablo_toolchain.h>
[5436]13#include <kernels/kernel_builder.h>
[5843]14#include <kernels/streamset.h>
[5440]15#include <llvm/IR/Module.h>
[5057]16
[5620]17#include <pablo/branch.h>
18#include <sys/stat.h>
19#include <fcntl.h>
20#include <llvm/Support/raw_ostream.h>
21
[5059]22using namespace kernel;
[5217]23using namespace IDISA;
[5267]24using namespace llvm;
[5057]25
[5464]26namespace pablo {
27
[5398]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];
[5299]33}
34
[5843]35std::vector<PabloAST *> PabloKernel::getInputStreamSet(const std::string & name) {
[6184]36    unsigned index; Port port;
[5843]37    std::tie(port, index) = getStreamPort(name);
38    assert (port == Port::Input);
[6184]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++) {
[5843]43        inputSet[i] = mEntryScope->createExtract(mInputs[index], mEntryScope->getInteger(i));
44    }
45    return inputSet;
46}
47
48
[5398]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];
[5299]54}
55
[5398]56Var * PabloKernel::getOutputScalarVar(const std::string & name) {
[5828]57    for (Var * out : mScalarOutputVars) {
58        if (out->getName().equals(name)) {
59            return out;
60        }
[5300]61    }
[5828]62    report_fatal_error("Kernel does not contain scalar " + name);
[5300]63}
64
[5836]65Var * PabloKernel::makeVariable(const String * name, Type * const type) {
[5230]66    Var * const var = new (mAllocator) Var(name, type, mAllocator);
[5217]67    mVariables.push_back(var);
68    return var;
69}
[5204]70
[5217]71Zeroes * PabloKernel::getNullValue(Type * type) {
[5446]72    if (LLVM_LIKELY(type == nullptr)) {
73        type = getStreamTy();
[5217]74    }
75    for (PabloAST * constant : mConstants) {
76        if (isa<Zeroes>(constant) && constant->getType() == type) {
77            return cast<Zeroes>(constant);
[5202]78        }
[5057]79    }
[5230]80    Zeroes * value = new (mAllocator) Zeroes(type, mAllocator);
[5217]81    mConstants.push_back(value);
82    return value;
[5057]83}
84
[5217]85Ones * PabloKernel::getAllOnesValue(Type * type) {
[5446]86    if (LLVM_LIKELY(type == nullptr)) {
87        type = getStreamTy();
[5217]88    }
89    for (PabloAST * constant : mConstants) {
90        if (isa<Ones>(constant) && constant->getType() == type) {
91            return cast<Ones>(constant);
92        }
93    }
[5230]94    Ones * value = new (mAllocator) Ones(type, mAllocator);
[5217]95    mConstants.push_back(value);
96    return value;
[5202]97}
98
[5828]99void PabloKernel::addInternalKernelProperties(const std::unique_ptr<kernel::KernelBuilder> & b) {
100    mSizeTy = b->getSizeTy();
101    mStreamTy = b->getStreamTy();
[6228]102    mSymbolTable.reset(new SymbolGenerator(b->getContext(), mAllocator));
[5836]103    mEntryScope = new (mAllocator) PabloBlock(this, mAllocator);
[5828]104    mContext = &b->getContext();
[6184]105    for (const Binding & ss : mInputStreamSets) {
[5828]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    }
[6184]111    for (const Binding & ss : mOutputStreamSets) {
[5828]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    }
[6184]117    for (const Binding & ss : mOutputScalars) {
[5828]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    }
[6228]125    generatePabloMethod();
[5436]126    pablo_function_passes(this);
[6228]127    mPabloCompiler.reset(new PabloCompiler(this));
[5828]128    mPabloCompiler->initializeKernelData(b);
[5446]129    mSizeTy = nullptr;
[6228]130    mStreamTy = nullptr;
[5062]131}
[5059]132
[5440]133void PabloKernel::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & iBuilder) {
[5446]134    mSizeTy = iBuilder->getSizeTy();
135    mStreamTy = iBuilder->getStreamTy();
[5435]136    mPabloCompiler->compile(iBuilder);
[5446]137    mSizeTy = nullptr;
138    mStreamTy = nullptr;
[5057]139}
140
[5828]141#if 0
142void PabloKernel::beginConditionalRegion(const std::unique_ptr<KernelBuilder> & b) {
143    mPabloCompiler->clearCarryData(b);
144}
145#endif
146
[5985]147void PabloKernel::generateFinalBlockMethod(const std::unique_ptr<KernelBuilder> & b, Value * const remainingBytes) {
[5057]148    // Standard Pablo convention for final block processing: set a bit marking
[5121]149    // the position just past EOF, as well as a mask marking all positions past EOF.
[5985]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
[5057]190}
[5217]191
[5486]192void PabloKernel::generateFinalizeMethod(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) {
193    mPabloCompiler->releaseKernelData(iBuilder);
[5620]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
[5486]227}
228
[5436]229String * PabloKernel::makeName(const llvm::StringRef & prefix) const {
[5440]230    return mSymbolTable->makeString(prefix);
[5436]231}
232
233Integer * PabloKernel::getInteger(const int64_t value) const {
[5440]234    return mSymbolTable->getInteger(value);
[5436]235}
236
[5446]237llvm::IntegerType * PabloKernel::getInt1Ty() const {
238    return IntegerType::getInt1Ty(getModule()->getContext());
239}
240
[6184]241static inline std::string && annotateKernelNameWithPabloDebugFlags(std::string && name) {
[5454]242    if (DebugOptionIsSet(DumpTrace)) {
243        name += "_DumpTrace";
244    }
[5620]245    if (CompileOptionIsSet(EnableProfiling)) {
246        name += "_BranchProfiling";
247    }
248    return std::move(name);
[5454]249}
250
[5436]251PabloKernel::PabloKernel(const std::unique_ptr<KernelBuilder> & b,
[5454]252                         std::string && kernelName,
[5310]253                         std::vector<Binding> stream_inputs,
254                         std::vector<Binding> stream_outputs,
255                         std::vector<Binding> scalar_parameters,
256                         std::vector<Binding> scalar_outputs)
[6261]257: BlockOrientedKernel(b, annotateKernelNameWithPabloDebugFlags(std::move(kernelName)),
[6228]258                      std::move(stream_inputs), std::move(stream_outputs),
[6273]259                      std::move(scalar_parameters), std::move(scalar_outputs), {})
[5299]260, PabloAST(PabloAST::ClassTypeId::Kernel, nullptr, mAllocator)
[6228]261, mPabloCompiler()
262, mSymbolTable()
[5836]263, mEntryScope(nullptr)
[5446]264, mSizeTy(nullptr)
[5828]265, mStreamTy(nullptr)
266, mContext(nullptr) {
[6273]267    addLocalScalar(b->getBitBlockType(), "EOFbit");
268    addLocalScalar(b->getBitBlockType(), "EOFmask");
[5299]269}
270
[6228]271PabloKernel::~PabloKernel() { }
[5217]272
[5464]273}
Note: See TracBrowser for help on using the repository browser.