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

Last change on this file since 6030 was 6030, checked in by cameron, 17 months ago

Eliminate dependency on llvm/CodeGen/CommandFlags.h

File size: 13.2 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/ExecutionEngine.h>  // for EngineBuilder
7#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
8
9#include <llvm/IR/LegacyPassManager.h>             // for PassManager
10#include <llvm/IR/IRPrintingPasses.h>
11#include <llvm/InitializePasses.h>                 // for initializeCodeGencd .
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#include "llvm/IR/Mangler.h"
30#ifdef ORCJIT
31#if LLVM_VERSION_INTEGER < LLVM_VERSION_CODE(4, 0, 0)
32#include <llvm/ExecutionEngine/Orc/JITSymbol.h>
33#else
34#include <llvm/ExecutionEngine/JITSymbol.h>
35#endif
36#include <llvm/ExecutionEngine/RuntimeDyld.h>
37#include <llvm/ExecutionEngine/SectionMemoryManager.h>
38#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
39#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
40#include <llvm/ExecutionEngine/Orc/IRTransformLayer.h>
41#include <llvm/ExecutionEngine/Orc/LambdaResolver.h>
42#if LLVM_VERSION_INTEGER < LLVM_VERSION_CODE(5, 0, 0)
43#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
44#else
45#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
46#endif
47#include <llvm/ExecutionEngine/Orc/GlobalMappingLayer.h>
48#endif
49
50#ifndef NDEBUG
51#define IN_DEBUG_MODE true
52#else
53#define IN_DEBUG_MODE false
54#endif
55
56using namespace llvm;
57using Kernel = kernel::Kernel;
58using StreamSetBuffer = parabix::StreamSetBuffer;
59using KernelBuilder = kernel::KernelBuilder;
60
61ParabixDriver::ParabixDriver(std::string && moduleName)
62: Driver(std::move(moduleName))
63, mTarget(nullptr)
64#ifndef ORCJIT
65, mEngine(nullptr)
66#endif
67, mCache(nullptr)
68, mUnoptimizedIROutputStream(nullptr)
69, mIROutputStream(nullptr)
70, mASMOutputStream(nullptr) {
71
72    InitializeNativeTarget();
73    InitializeNativeTargetAsmPrinter();
74    InitializeNativeTargetAsmParser();
75    llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
76   
77
78#ifdef ORCJIT
79    EngineBuilder builder;
80#else
81    std::string errMessage;
82    EngineBuilder builder{std::unique_ptr<Module>(mMainModule)};
83    builder.setErrorStr(&errMessage);
84    builder.setUseOrcMCJITReplacement(true);
85    builder.setVerifyModules(false);
86    builder.setEngineKind(EngineKind::JIT);
87#endif
88    builder.setTargetOptions(codegen::target_Options);
89    builder.setOptLevel(codegen::OptLevel);
90
91    StringMap<bool> HostCPUFeatures;
92    if (sys::getHostCPUFeatures(HostCPUFeatures)) {
93        std::vector<std::string> attrs;
94        for (auto &flag : HostCPUFeatures) {
95            if (flag.second) {
96                attrs.push_back("+" + flag.first().str());
97            }
98        }
99        builder.setMAttrs(attrs);
100    }
101
102    mTarget = builder.selectTarget();
103   
104    if (mTarget == nullptr) {
105        throw std::runtime_error("Could not selectTarget");
106    }
107    preparePassManager();
108
109#ifdef ORCJIT
110    mCompileLayer = make_unique<CompileLayerT>(mObjectLayer, orc::SimpleCompiler(*mTarget));
111#else
112    mEngine = builder.create();
113    if (mEngine == nullptr) {
114        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
115    }
116#endif
117    if (LLVM_LIKELY(codegen::EnableObjectCache)) {
118        if (codegen::ObjectCacheDir) {
119            mCache = new ParabixObjectCache(codegen::ObjectCacheDir);
120        } else {
121            mCache = new ParabixObjectCache();
122        }
123#ifdef ORCJIT
124#if LLVM_VERSION_INTEGER < LLVM_VERSION_CODE(5, 0, 0)
125        mCompileLayer->setObjectCache(mCache);
126#else
127        mCompileLayer->getCompiler().setObjectCache(mCache);
128#endif
129#else
130        mEngine->setObjectCache(mCache);
131#endif
132    }
133    auto triple = mTarget->getTargetTriple().getTriple();
134    const DataLayout DL(mTarget->createDataLayout());
135    mMainModule->setTargetTriple(triple);
136    mMainModule->setDataLayout(DL);
137    iBuilder.reset(IDISA::GetIDISA_Builder(*mContext));
138    iBuilder->setDriver(this);
139    iBuilder->setModule(mMainModule);
140}
141
142void ParabixDriver::makeKernelCall(Kernel * kernel, const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
143    assert ("makeKernelCall was already run on this kernel." && (kernel->getModule() == nullptr));
144    mPipeline.emplace_back(kernel);
145    kernel->bindPorts(inputs, outputs);
146    if (!mCache || !mCache->loadCachedObjectFile(iBuilder, kernel)) {
147        mUncachedKernel.push_back(kernel);
148    }
149    if (kernel->getModule() == nullptr) {
150        kernel->makeModule(iBuilder);
151    }
152    assert (kernel->getModule());
153}
154
155void ParabixDriver::generatePipelineIR() {
156
157    for (Kernel * const kernel : mUncachedKernel) {
158        kernel->prepareKernel(iBuilder);
159    }
160    // note: instantiation of all kernels must occur prior to initialization
161    for (Kernel * const k : mPipeline) {
162        k->addKernelDeclarations(iBuilder);
163    }
164    for (Kernel * const k : mPipeline) {
165        k->createInstance(iBuilder);
166    }
167    for (Kernel * const k : mPipeline) {
168        k->initializeInstance(iBuilder);
169    }
170    if (codegen::SegmentPipelineParallel) {
171        generateSegmentParallelPipeline(iBuilder, mPipeline);
172    } else {
173        generatePipelineLoop(iBuilder, mPipeline);
174    }
175    for (const auto & k : mPipeline) {
176        k->finalizeInstance(iBuilder);
177    }
178}
179
180
181Function * ParabixDriver::addLinkFunction(Module * mod, llvm::StringRef name, FunctionType * type, void * functionPtr) const {
182    if (LLVM_UNLIKELY(mod == nullptr)) {
183        report_fatal_error("addLinkFunction(" + name + ") cannot be called until after addKernelCall or makeKernelCall");
184    }
185    Function * f = mod->getFunction(name);
186    if (LLVM_UNLIKELY(f == nullptr)) {
187        f = Function::Create(type, Function::ExternalLinkage, name, mod);
188#ifdef ORCJIT
189#else
190        mEngine->updateGlobalMapping(f, functionPtr);
191#endif
192    } else if (LLVM_UNLIKELY(f->getType() != type->getPointerTo())) {
193        report_fatal_error("Cannot link " + name + ": a function with a different signature already exists with that name in " + mod->getName());
194    }
195    return f;
196}
197
198std::string ParabixDriver::getMangledName(std::string s) {
199    #if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 9, 0)
200    DataLayout DL(mTarget->createDataLayout());   
201    std::string MangledName;
202    raw_string_ostream MangledNameStream(MangledName);
203    Mangler::getNameWithPrefix(MangledNameStream, s, DL);
204    return MangledName;
205    #else
206    return s;
207    #endif
208}
209
210void ParabixDriver::preparePassManager() {
211    PassRegistry * Registry = PassRegistry::getPassRegistry();
212    initializeCore(*Registry);
213    initializeCodeGen(*Registry);
214    initializeLowerIntrinsicsPass(*Registry);
215   
216    if (LLVM_UNLIKELY(codegen::ShowUnoptimizedIROption != codegen::OmittedOption)) {
217        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
218            if (codegen::ShowUnoptimizedIROption != "") {
219                std::error_code error;
220                mUnoptimizedIROutputStream = make_unique<raw_fd_ostream>(codegen::ShowUnoptimizedIROption, error, sys::fs::OpenFlags::F_None);
221            } else {
222                mUnoptimizedIROutputStream = make_unique<raw_fd_ostream>(STDERR_FILENO, false, true);
223            }
224        }
225        mPassManager.add(createPrintModulePass(*mUnoptimizedIROutputStream));
226    }
227    if (IN_DEBUG_MODE || LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::VerifyIR))) {
228        mPassManager.add(createVerifierPass());
229    }
230    mPassManager.add(createPromoteMemoryToRegisterPass());    // Promote stack variables to constants or PHI nodes
231    mPassManager.add(createCFGSimplificationPass());          // Remove dead basic blocks and unnecessary branch statements / phi nodes
232    mPassManager.add(createEarlyCSEPass());                   // Simple common subexpression elimination pass
233    mPassManager.add(createInstructionCombiningPass());       // Simple peephole optimizations and bit-twiddling.
234    mPassManager.add(createReassociatePass());                // Canonicalizes commutative expressions
235    mPassManager.add(createGVNPass());                        // Global value numbering redundant expression elimination pass
236    mPassManager.add(createCFGSimplificationPass());          // Repeat CFG Simplification to "clean up" any newly found redundant phi nodes
237   
238    if (LLVM_UNLIKELY(codegen::ShowIROption != codegen::OmittedOption)) {
239        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
240            if (codegen::ShowIROption != "") {
241                std::error_code error;
242                mIROutputStream = make_unique<raw_fd_ostream>(codegen::ShowIROption, error, sys::fs::OpenFlags::F_None);
243            } else {
244                mIROutputStream = make_unique<raw_fd_ostream>(STDERR_FILENO, false, true);
245            }
246        }
247        mPassManager.add(createPrintModulePass(*mIROutputStream));
248    }
249   
250#if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 7, 0)
251    if (LLVM_UNLIKELY(codegen::ShowASMOption != codegen::OmittedOption)) {
252        if (codegen::ShowASMOption != "") {
253            std::error_code error;
254            mASMOutputStream = make_unique<raw_fd_ostream>(codegen::ShowASMOption, error, sys::fs::OpenFlags::F_None);
255        } else {
256            mASMOutputStream = make_unique<raw_fd_ostream>(STDERR_FILENO, false, true);
257        }
258        if (LLVM_UNLIKELY(mTarget->addPassesToEmitFile(mPassManager, *mASMOutputStream, TargetMachine::CGFT_AssemblyFile))) {
259            report_fatal_error("LLVM error: could not add emit assembly pass");
260        }
261    }
262#endif
263}
264
265void ParabixDriver::finalizeObject() {
266#ifdef ORCJIT
267    std::vector<std::unique_ptr<Module>> moduleSet;
268    auto Resolver = llvm::orc::createLambdaResolver(
269            [&](const std::string &Name) {
270                auto Sym = mCompileLayer->findSymbol(Name, false);
271                if (!Sym) Sym = mCompileLayer->findSymbol(getMangledName(Name), false);
272#if LLVM_VERSION_INTEGER <= LLVM_VERSION_CODE(3, 9, 1)
273                if (Sym) return Sym.toRuntimeDyldSymbol();
274                return RuntimeDyld::SymbolInfo(nullptr);
275#else
276                if (Sym) return Sym;
277                return JITSymbol(nullptr);
278#endif
279            },
280            [&](const std::string &Name) {
281                auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name);
282                if (!SymAddr) SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(getMangledName(Name));
283#if LLVM_VERSION_INTEGER <= LLVM_VERSION_CODE(3, 9, 1)
284                if (SymAddr) return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported);
285                return RuntimeDyld::SymbolInfo(nullptr);
286#else
287                if (SymAddr) return JITSymbol(SymAddr, JITSymbolFlags::Exported);
288                return JITSymbol(nullptr);
289#endif
290            });
291#endif
292   
293    Module * module = nullptr;
294    try {
295        for (Kernel * const kernel : mUncachedKernel) {
296            iBuilder->setKernel(kernel);
297            kernel->generateKernel(iBuilder);
298            module = kernel->getModule(); assert (module);
299            module->setTargetTriple(mMainModule->getTargetTriple());
300            mPassManager.run(*module);
301        }
302        module = mMainModule;
303        iBuilder->setKernel(nullptr);
304        mPassManager.run(*mMainModule);
305        for (Kernel * const kernel : mPipeline) {
306            if (LLVM_UNLIKELY(kernel->getModule() == nullptr)) {
307                report_fatal_error(kernel->getName() + " was neither loaded from cache nor generated prior to finalizeObject");
308            }
309#ifndef ORCJIT
310            mEngine->addModule(std::unique_ptr<Module>(kernel->getModule()));
311#else
312            moduleSet.push_back(std::unique_ptr<Module>(kernel->getModule()));
313#endif
314        }
315#ifndef ORCJIT
316            mEngine->finalizeObject();
317#else
318            moduleSet.push_back(std::unique_ptr<Module>(mMainModule));
319            auto handle = mCompileLayer->addModuleSet(std::move(moduleSet), make_unique<SectionMemoryManager>(), std::move(Resolver));
320#endif
321    } catch (const std::exception & e) {
322        report_fatal_error(module->getName() + ": " + e.what());
323    }
324
325}
326
327bool ParabixDriver::hasExternalFunction(llvm::StringRef functionName) const {
328    return RTDyldMemoryManager::getSymbolAddressInProcess(functionName);
329}
330
331void * ParabixDriver::getMain() {
332#ifndef ORCJIT
333    return mEngine->getPointerToNamedFunction("Main");
334#else
335    auto MainSym = mCompileLayer->findSymbol(getMangledName("Main"), false);
336    assert (MainSym && "Main not found");
337   
338    intptr_t main = (intptr_t) MainSym.getAddress();
339    return (void *) main;
340#endif
341}
342
343void ParabixDriver::performIncrementalCacheCleanupStep() {
344    if (mCache) mCache->performIncrementalCacheCleanupStep();
345}
346
347ParabixDriver::~ParabixDriver() {
348#ifndef ORCJIT
349    delete mEngine;
350#endif
351    delete mCache;
352    delete mTarget;
353 }
Note: See TracBrowser for help on using the repository browser.