source: icGREP/icgrep-devel/icgrep/toolchain/cpudriver.cpp @ 5841

Last change on this file since 5841 was 5841, checked in by cameron, 18 months ago

LLVM_VERSION_CODE macro, CC-multiplex option, performance bug fixes

File size: 9.2 KB
Line 
1#include "cpudriver.h"
2
3#include <IR_Gen/idisa_target.h>
4#include <toolchain/toolchain.h>
5#include <llvm/ExecutionEngine/ExecutionEngine.h>  // for EngineBuilder
6#include <llvm/IR/LegacyPassManager.h>             // for PassManager
7#include <llvm/IR/IRPrintingPasses.h>
8#include <llvm/InitializePasses.h>                 // for initializeCodeGen
9#include <llvm/PassRegistry.h>                     // for PassRegistry
10#include <llvm/Support/CodeGen.h>                  // for Level, Level::None
11#include <llvm/Support/Compiler.h>                 // for LLVM_UNLIKELY
12#include <llvm/Support/TargetSelect.h>
13#include <llvm/Support/FileSystem.h>
14#include <llvm/Target/TargetMachine.h>             // for TargetMachine, Tar...
15#include <llvm/Target/TargetOptions.h>             // for TargetOptions
16#include <llvm/Transforms/Scalar.h>
17#if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 9, 0)
18#include <llvm/Transforms/Scalar/GVN.h>
19#endif
20#include <llvm/Transforms/Utils/Local.h>
21#include <toolchain/object_cache.h>
22#include <toolchain/pipeline.h>
23#include <kernels/kernel_builder.h>
24#include <kernels/kernel.h>
25#include <llvm/IR/Verifier.h>
26
27#ifndef NDEBUG
28#define IN_DEBUG_MODE true
29#else
30#define IN_DEBUG_MODE false
31#endif
32
33using namespace llvm;
34using Kernel = kernel::Kernel;
35using StreamSetBuffer = parabix::StreamSetBuffer;
36using KernelBuilder = kernel::KernelBuilder;
37
38ParabixDriver::ParabixDriver(std::string && moduleName)
39: Driver(std::move(moduleName))
40, mTarget(nullptr)
41, mEngine(nullptr)
42, mCache(nullptr)
43, mIROutputStream(nullptr)
44, mASMOutputStream(nullptr) {
45
46    InitializeNativeTarget();
47    InitializeNativeTargetAsmPrinter();
48    InitializeNativeTargetAsmParser();
49
50    PassRegistry * Registry = PassRegistry::getPassRegistry();
51    initializeCore(*Registry);
52    initializeCodeGen(*Registry);
53    initializeLowerIntrinsicsPass(*Registry);
54
55    std::string errMessage;
56    EngineBuilder builder{std::unique_ptr<Module>(mMainModule)};
57    builder.setErrorStr(&errMessage);
58    builder.setUseOrcMCJITReplacement(true);
59    builder.setTargetOptions(codegen::Options);
60    builder.setVerifyModules(false);
61    builder.setOptLevel(codegen::OptLevel);
62
63    StringMap<bool> HostCPUFeatures;
64    if (sys::getHostCPUFeatures(HostCPUFeatures)) {
65        std::vector<std::string> attrs;
66        for (auto &flag : HostCPUFeatures) {
67            auto enabled = flag.second ? "+" : "-";
68            attrs.push_back(enabled + flag.first().str());
69        }
70        builder.setMAttrs(attrs);
71    }
72
73    mEngine = builder.create();
74    if (mEngine == nullptr) {
75        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
76    }
77    mTarget = builder.selectTarget();   
78    if (LLVM_LIKELY(codegen::EnableObjectCache)) {
79        if (codegen::ObjectCacheDir) {
80            mCache = new ParabixObjectCache(codegen::ObjectCacheDir);
81        } else {
82            mCache = new ParabixObjectCache();
83        }
84        mEngine->setObjectCache(mCache);
85    }
86    mMainModule->setTargetTriple(mTarget->getTargetTriple().getTriple());
87    iBuilder.reset(IDISA::GetIDISA_Builder(*mContext));
88    iBuilder->setDriver(this);
89    iBuilder->setModule(mMainModule);
90}
91
92void ParabixDriver::makeKernelCall(Kernel * kernel, const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
93    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kernel->getModule() == nullptr));
94    mPipeline.emplace_back(kernel);
95    kernel->bindPorts(inputs, outputs);
96    if (!mCache || !mCache->loadCachedObjectFile(iBuilder, kernel)) {
97        mUncachedKernel.push_back(kernel);
98    }
99    if (kernel->getModule() == nullptr) {
100        kernel->makeModule(iBuilder);
101    }
102    assert (kernel->getModule());
103}
104
105void ParabixDriver::generatePipelineIR() {
106
107    for (Kernel * const kernel : mUncachedKernel) {
108        kernel->prepareKernel(iBuilder);
109    }
110
111    // note: instantiation of all kernels must occur prior to initialization
112    for (Kernel * const k : mPipeline) {
113        k->addKernelDeclarations(iBuilder);
114    }
115    for (Kernel * const k : mPipeline) {
116        k->createInstance(iBuilder);
117    }
118    for (Kernel * const k : mPipeline) {
119        k->initializeInstance(iBuilder);
120    }
121    if (codegen::SegmentPipelineParallel) {
122        generateSegmentParallelPipeline(iBuilder, mPipeline);
123    } else {
124        generatePipelineLoop(iBuilder, mPipeline);
125    }
126    for (const auto & k : mPipeline) {
127        k->finalizeInstance(iBuilder);
128    }
129}
130
131Function * ParabixDriver::addLinkFunction(Module * mod, llvm::StringRef name, FunctionType * type, void * functionPtr) const {
132    if (LLVM_UNLIKELY(mod == nullptr)) {
133        report_fatal_error("addLinkFunction(" + name + ") cannot be called until after addKernelCall or makeKernelCall");
134    }
135    Function * f = mod->getFunction(name);
136    if (LLVM_UNLIKELY(f == nullptr)) {
137        f = Function::Create(type, Function::ExternalLinkage, name, mod);
138        mEngine->updateGlobalMapping(f, functionPtr);
139    } else if (LLVM_UNLIKELY(f->getType() != type->getPointerTo())) {
140        report_fatal_error("Cannot link " + name + ": a function with a different signature already exists with that name in " + mod->getName());
141    }
142    return f;
143}
144
145void ParabixDriver::finalizeObject() {
146
147    legacy::PassManager PM;
148    if (LLVM_UNLIKELY(codegen::ShowUnoptimizedIROption != codegen::OmittedOption)) {
149        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
150            if (codegen::ShowUnoptimizedIROption != "") {
151                std::error_code error;
152                mIROutputStream = new raw_fd_ostream(codegen::ShowUnoptimizedIROption, error, sys::fs::OpenFlags::F_None);
153            } else {
154                mIROutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
155            }
156        }
157        PM.add(createPrintModulePass(*mIROutputStream));
158    }
159    if (IN_DEBUG_MODE || LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::VerifyIR))) {
160        PM.add(createVerifierPass());
161    }
162    PM.add(createPromoteMemoryToRegisterPass());    // Promote stack variables to constants or PHI nodes
163    PM.add(createCFGSimplificationPass());          // Remove dead basic blocks and unnecessary branch statements / phi nodes
164    PM.add(createEarlyCSEPass());                   // Simple common subexpression elimination pass
165    PM.add(createInstructionCombiningPass());       // Simple peephole optimizations and bit-twiddling.
166    PM.add(createReassociatePass());                // Canonicalizes commutative expressions
167    PM.add(createGVNPass());                        // Global value numbering redundant expression elimination pass
168    PM.add(createCFGSimplificationPass());          // Repeat CFG Simplification to "clean up" any newly found redundant phi nodes
169
170    if (LLVM_UNLIKELY(codegen::ShowIROption != codegen::OmittedOption)) {
171        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
172            if (codegen::ShowIROption != "") {
173                std::error_code error;
174                mIROutputStream = new raw_fd_ostream(codegen::ShowIROption, error, sys::fs::OpenFlags::F_None);
175            } else {
176                mIROutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
177            }
178        }
179        PM.add(createPrintModulePass(*mIROutputStream));
180    }
181
182#if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 7, 0)
183    if (LLVM_UNLIKELY(codegen::ShowASMOption != codegen::OmittedOption)) {
184        if (codegen::ShowASMOption != "") {
185            std::error_code error;
186            mASMOutputStream = new raw_fd_ostream(codegen::ShowASMOption, error, sys::fs::OpenFlags::F_None);
187        } else {
188            mASMOutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
189        }
190        if (LLVM_UNLIKELY(mTarget->addPassesToEmitFile(PM, *mASMOutputStream, TargetMachine::CGFT_AssemblyFile))) {
191            report_fatal_error("LLVM error: could not add emit assembly pass");
192        }
193    }
194#endif
195
196    Module * module = nullptr;
197    try {
198        for (Kernel * const kernel : mUncachedKernel) {
199            iBuilder->setKernel(kernel);
200            kernel->generateKernel(iBuilder);
201            module = kernel->getModule(); assert (module);
202            module->setTargetTriple(mMainModule->getTargetTriple());
203            PM.run(*module);
204        }
205        module = mMainModule;
206        iBuilder->setKernel(nullptr);
207        PM.run(*mMainModule);
208        for (Kernel * const kernel : mPipeline) {
209            if (LLVM_UNLIKELY(kernel->getModule() == nullptr)) {
210                report_fatal_error(kernel->getName() + " was neither loaded from cache nor generated prior to finalizeObject");
211            }
212            mEngine->addModule(std::unique_ptr<Module>(kernel->getModule()));
213        }
214        mEngine->finalizeObject();
215    } catch (const std::exception & e) {
216        report_fatal_error(module->getName() + ": " + e.what());
217    }
218
219}
220
221bool ParabixDriver::hasExternalFunction(llvm::StringRef functionName) const {
222    return mEngine->getPointerToNamedFunction(functionName, false) != nullptr;
223}
224
225void * ParabixDriver::getMain() {
226    return mEngine->getPointerToNamedFunction("Main");
227}
228
229void ParabixDriver::performIncrementalCacheCleanupStep() {
230    if (mCache) mCache->performIncrementalCacheCleanupStep();
231}
232
233ParabixDriver::~ParabixDriver() {
234    delete mEngine;
235    delete mCache;
236    delete mTarget;
237    delete mIROutputStream;
238    delete mASMOutputStream;
239}
Note: See TracBrowser for help on using the repository browser.