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

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

Move getMangleName into cpudriver to avoid dangling reference

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