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

Last change on this file since 6237 was 6220, checked in by cameron, 7 months ago

Trace facility initial check-in

File size: 13.9 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/raw_ostream.h>              // for errs()
14#include <llvm/Support/CodeGen.h>                  // for Level, Level::None
15#include <llvm/Support/Compiler.h>                 // for LLVM_UNLIKELY
16#include <llvm/Support/TargetSelect.h>
17#include <llvm/Support/FileSystem.h>
18#include <llvm/Target/TargetMachine.h>             // for TargetMachine, Tar...
19#include <llvm/Target/TargetOptions.h>             // for TargetOptions
20#include <llvm/Transforms/Scalar.h>
21#if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 9, 0)
22#include <llvm/Transforms/Scalar/GVN.h>
23#endif
24#include <llvm/Transforms/Utils/Local.h>
25#include <toolchain/object_cache.h>
26#include <kernels/kernel_builder.h>
27#include <kernels/pipeline_builder.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;
58using kernel::PipelineKernel;
59using kernel::StreamSetBuffer;
60using kernel::StreamSetBuffers;
61using kernel::KernelBuilder;
62
63CPUDriver::CPUDriver(std::string && moduleName)
64: BaseDriver(std::move(moduleName))
65, mTarget(nullptr)
66#ifndef ORCJIT
67, mEngine(nullptr)
68#endif
69, mUnoptimizedIROutputStream(nullptr)
70, mIROutputStream(nullptr)
71, mASMOutputStream(nullptr) {
72
73    InitializeNativeTarget();
74    InitializeNativeTargetAsmPrinter();
75//    InitializeNativeTargetAsmParser();
76    llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
77
78
79    #ifdef ORCJIT
80    EngineBuilder builder;
81    #else
82    std::string errMessage;
83    EngineBuilder builder{std::unique_ptr<Module>(mMainModule)};
84    builder.setErrorStr(&errMessage);
85    builder.setUseOrcMCJITReplacement(true);
86    builder.setVerifyModules(false);
87    builder.setEngineKind(EngineKind::JIT);
88    #endif
89    builder.setTargetOptions(codegen::target_Options);
90    builder.setOptLevel(codegen::OptLevel);
91
92    StringMap<bool> HostCPUFeatures;
93    if (sys::getHostCPUFeatures(HostCPUFeatures)) {
94        std::vector<std::string> attrs;
95        for (auto &flag : HostCPUFeatures) {
96            if (flag.second) {
97                attrs.push_back("+" + flag.first().str());
98            }
99        }
100        builder.setMAttrs(attrs);
101    }
102
103    mTarget = builder.selectTarget();
104
105    if (mTarget == nullptr) {
106        throw std::runtime_error("Could not selectTarget");
107    }
108    #ifdef ORCJIT
109    mCompileLayer = make_unique<CompileLayerT>(mObjectLayer, orc::SimpleCompiler(*mTarget));
110    #else
111    mEngine = builder.create();
112    if (mEngine == nullptr) {
113        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
114    }
115    #endif
116    auto cache = ParabixObjectCache::getInstance();
117    if (cache) {
118        #ifdef ORCJIT
119        #if LLVM_VERSION_INTEGER < LLVM_VERSION_CODE(5, 0, 0)
120        mCompileLayer->setObjectCache(cache);
121        #else
122        mCompileLayer->getCompiler().setObjectCache(cache);
123        #endif
124        #else
125        mEngine->setObjectCache(cache);
126        #endif
127    }
128    auto triple = mTarget->getTargetTriple().getTriple();
129    const DataLayout DL(mTarget->createDataLayout());
130    mMainModule->setTargetTriple(triple);
131    mMainModule->setDataLayout(DL);
132    iBuilder.reset(IDISA::GetIDISA_Builder(*mContext));
133    iBuilder->setDriver(this);
134    iBuilder->setModule(mMainModule);
135}
136
137Function * CPUDriver::addLinkFunction(Module * mod, llvm::StringRef name, FunctionType * type, void * functionPtr) const {
138    if (LLVM_UNLIKELY(mod == nullptr)) {
139        report_fatal_error("addLinkFunction(" + name + ") cannot be called until after addKernelCall or makeKernelCall");
140    }
141    Function * f = mod->getFunction(name);
142    if (LLVM_UNLIKELY(f == nullptr)) {
143        f = Function::Create(type, Function::ExternalLinkage, name, mod);
144        #ifndef ORCJIT
145        mEngine->updateGlobalMapping(f, functionPtr);
146        #endif
147    } else if (LLVM_UNLIKELY(f->getType() != type->getPointerTo())) {
148        report_fatal_error("Cannot link " + name + ": a function with a different signature already exists with that name in " + mod->getName());
149    }
150    return f;
151}
152
153std::string CPUDriver::getMangledName(std::string s) {
154    #if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 9, 0)
155    DataLayout DL(mTarget->createDataLayout());
156    std::string MangledName;
157    raw_string_ostream MangledNameStream(MangledName);
158    Mangler::getNameWithPrefix(MangledNameStream, s, DL);
159    return MangledName;
160    #else
161    return s;
162    #endif
163}
164
165inline legacy::PassManager CPUDriver::preparePassManager() {
166
167    legacy::PassManager PM;
168
169    PassRegistry * Registry = PassRegistry::getPassRegistry();
170    initializeCore(*Registry);
171    initializeCodeGen(*Registry);
172    initializeLowerIntrinsicsPass(*Registry);
173
174    if (LLVM_UNLIKELY(codegen::ShowUnoptimizedIROption != codegen::OmittedOption)) {
175        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
176            if (!codegen::ShowUnoptimizedIROption.empty()) {
177                std::error_code error;
178                mUnoptimizedIROutputStream = make_unique<raw_fd_ostream>(codegen::ShowUnoptimizedIROption, error, sys::fs::OpenFlags::F_None);
179            } else {
180                mUnoptimizedIROutputStream = make_unique<raw_fd_ostream>(STDERR_FILENO, false, true);
181            }
182        }
183        PM.add(createPrintModulePass(*mUnoptimizedIROutputStream));
184    }
185    if (IN_DEBUG_MODE || LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::VerifyIR))) {
186        PM.add(createVerifierPass());
187    }
188    PM.add(createDeadCodeEliminationPass());        // Eliminate any trivially dead code
189    PM.add(createPromoteMemoryToRegisterPass());    // Promote stack variables to constants or PHI nodes
190    PM.add(createCFGSimplificationPass());          // Remove dead basic blocks and unnecessary branch statements / phi nodes
191    PM.add(createEarlyCSEPass());                   // Simple common subexpression elimination pass
192    PM.add(createInstructionCombiningPass());       // Simple peephole optimizations and bit-twiddling.
193    PM.add(createReassociatePass());                // Canonicalizes commutative expressions
194    PM.add(createGVNPass());                        // Global value numbering redundant expression elimination pass
195    PM.add(createCFGSimplificationPass());          // Repeat CFG Simplification to "clean up" any newly found redundant phi nodes
196    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::EnableAsserts))) {
197        PM.add(createRemoveRedundantAssertionsPass());
198        PM.add(createDeadCodeEliminationPass());
199        PM.add(createCFGSimplificationPass());
200    }
201    if (LLVM_UNLIKELY(!codegen::TraceOption.empty())) {
202        PM.add(createTracePass(iBuilder.get(), codegen::TraceOption));
203    }
204    if (LLVM_UNLIKELY(codegen::ShowIROption != codegen::OmittedOption)) {
205        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
206            if (!codegen::ShowIROption.empty()) {
207                std::error_code error;
208                mIROutputStream = make_unique<raw_fd_ostream>(codegen::ShowIROption, error, sys::fs::OpenFlags::F_None);
209            } else {
210                mIROutputStream = make_unique<raw_fd_ostream>(STDERR_FILENO, false, true);
211            }
212        }
213        PM.add(createPrintModulePass(*mIROutputStream));
214    }
215    #if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 7, 0)
216    if (LLVM_UNLIKELY(codegen::ShowASMOption != codegen::OmittedOption)) {
217        if (!codegen::ShowASMOption.empty()) {
218            std::error_code error;
219            mASMOutputStream = make_unique<raw_fd_ostream>(codegen::ShowASMOption, error, sys::fs::OpenFlags::F_None);
220        } else {
221            mASMOutputStream = make_unique<raw_fd_ostream>(STDERR_FILENO, false, true);
222        }
223        if (LLVM_UNLIKELY(mTarget->addPassesToEmitFile(PM, *mASMOutputStream, TargetMachine::CGFT_AssemblyFile))) {
224            report_fatal_error("LLVM error: could not add emit assembly pass");
225        }
226    }
227    #endif
228
229    return PM;
230}
231
232void CPUDriver::generateUncachedKernels() {
233    if (mUncachedKernel.empty()) return;
234    auto PM = preparePassManager();
235    for (auto & kernel : mUncachedKernel) {
236        kernel->prepareKernel(iBuilder);
237    }
238    mCachedKernel.reserve(mUncachedKernel.size());
239    for (auto & kernel : mUncachedKernel) {
240        kernel->generateKernel(iBuilder);
241        Module * const module = kernel->getModule(); assert (module);
242        module->setTargetTriple(mMainModule->getTargetTriple());
243        PM.run(*module);
244        mCachedKernel.emplace_back(kernel.release());
245    }
246    mUncachedKernel.clear();
247}
248
249void * CPUDriver::finalizeObject(llvm::Function * mainMethod) {
250
251    #ifdef ORCJIT
252    auto Resolver = llvm::orc::createLambdaResolver(
253        [&](const std::string &Name) {
254            auto Sym = mCompileLayer->findSymbol(Name, false);
255            if (!Sym) Sym = mCompileLayer->findSymbol(getMangledName(Name), false);
256            #if LLVM_VERSION_INTEGER <= LLVM_VERSION_CODE(3, 9, 1)
257            if (Sym) return Sym.toRuntimeDyldSymbol();
258            return RuntimeDyld::SymbolInfo(nullptr);
259            #else
260            if (Sym) return Sym;
261            return JITSymbol(nullptr);
262            #endif
263        },
264        [&](const std::string &Name) {
265            auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name);
266            if (!SymAddr) SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(getMangledName(Name));
267            #if LLVM_VERSION_INTEGER <= LLVM_VERSION_CODE(3, 9, 1)
268            if (SymAddr) return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported);
269            return RuntimeDyld::SymbolInfo(nullptr);
270            #else
271            if (SymAddr) return JITSymbol(SymAddr, JITSymbolFlags::Exported);
272            return JITSymbol(nullptr);
273            #endif
274        });
275    #endif
276
277    iBuilder->setModule(mMainModule);
278    #ifdef ORCJIT
279    std::vector<std::unique_ptr<Module>> moduleSet;
280    moduleSet.reserve(mCachedKernel.size());
281    #endif
282    for (const auto & kernel : mCachedKernel) {
283        if (LLVM_UNLIKELY(kernel->getModule() == nullptr)) {
284            report_fatal_error(kernel->getName() + " was neither loaded from cache nor generated prior to finalizeObject");
285        }
286        #ifndef ORCJIT
287        mEngine->addModule(std::unique_ptr<Module>(kernel->getModule()));
288        #else
289        moduleSet.push_back(std::unique_ptr<Module>(kernel->getModule()));
290        #endif
291    }
292    mCachedKernel.clear();
293    // compile any uncompiled kernel/method
294    #ifndef ORCJIT
295    mEngine->finalizeObject();
296    #else
297    moduleSet.push_back(std::unique_ptr<Module>(mMainModule);
298    mCompileLayer->addModuleSet(std::move(moduleSet), make_unique<SectionMemoryManager>(), std::move(Resolver));
299    #endif
300
301    // return the compiled main method
302    #ifndef ORCJIT
303    return mEngine->getPointerToFunction(mainMethod);
304    #else
305    auto MainSym = mCompileLayer->findSymbol(getMangledName(mMainMethod->getName()), false);
306    assert (MainSym && "Main not found");
307    return (void *)MainSym.getAddress();
308    #endif
309}
310
311bool CPUDriver::hasExternalFunction(llvm::StringRef functionName) const {
312    return RTDyldMemoryManager::getSymbolAddressInProcess(functionName);
313}
314
315CPUDriver::~CPUDriver() {
316    #ifndef ORCJIT
317    delete mEngine;
318    #endif
319    delete mTarget;
320}
321
322
323class TracePass : public ModulePass {
324public:
325    static char ID;
326    TracePass(kernel::KernelBuilder * kb, StringRef to_trace) : ModulePass(ID), iBuilder(kb), mToTrace(to_trace) { }
327   
328    virtual bool runOnModule(Module &M) override;
329private:
330    kernel::KernelBuilder * iBuilder;
331    StringRef mToTrace;
332};
333
334char TracePass::ID = 0;
335
336bool TracePass::runOnModule(Module & M) {
337    Module * saveModule = iBuilder->getModule();
338    iBuilder->setModule(&M);
339    bool modified = false;
340    for (auto & F : M) {
341        for (auto & B : F) {
342            for (BasicBlock::iterator i = B.begin(); i != B.end(); ) {
343                auto i0 = i;
344                ++i;
345                if (!isa<Value>(*i0)) continue;
346                StringRef theName = (*i0).getName();
347                if (theName.startswith(mToTrace)) {
348                    //errs() << theName << "\n";
349                    Type * t = (*i0).getType();
350                    //t->dump();
351                    if (t == iBuilder->getBitBlockType()) {
352                        iBuilder->SetInsertPoint(&B, i);
353                        iBuilder->CallPrintRegister(theName, &*i0);
354                        modified = true;
355                    }
356                    else if (t == iBuilder->getInt64Ty()) {
357                        iBuilder->SetInsertPoint(&B, i);
358                        iBuilder->CallPrintInt(theName, &*i0);
359                        modified = true;
360                    }
361                }
362            }
363        }
364    }
365    //if (modified) M.dump();
366    iBuilder->setModule(saveModule);
367    return modified;
368}
369
370ModulePass * CPUDriver::createTracePass(kernel::KernelBuilder * kb, StringRef to_trace) {
371    return new TracePass(iBuilder.get(), to_trace);
372}
373                   
Note: See TracBrowser for help on using the repository browser.