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

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

Restructuring step

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