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

Last change on this file since 5915 was 5915, checked in by cameron, 11 months ago

ORCJIT for LLVM 3.9/4.0 initial check-in

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