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

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

CPU driver progress

File size: 14.5 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
234void ParabixDriver::preparePassManager() {
235    PassRegistry * Registry = PassRegistry::getPassRegistry();
236    initializeCore(*Registry);
237    initializeCodeGen(*Registry);
238    initializeLowerIntrinsicsPass(*Registry);
239   
240    if (LLVM_UNLIKELY(codegen::ShowUnoptimizedIROption != codegen::OmittedOption)) {
241        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
242            if (codegen::ShowUnoptimizedIROption != "") {
243                std::error_code error;
244                mIROutputStream = new raw_fd_ostream(codegen::ShowUnoptimizedIROption, error, sys::fs::OpenFlags::F_None);
245            } else {
246                mIROutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
247            }
248        }
249        mPassManager.add(createPrintModulePass(*mIROutputStream));
250    }
251    if (IN_DEBUG_MODE || LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::VerifyIR))) {
252        mPassManager.add(createVerifierPass());
253    }
254    mPassManager.add(createPromoteMemoryToRegisterPass());    // Promote stack variables to constants or PHI nodes
255    mPassManager.add(createCFGSimplificationPass());          // Remove dead basic blocks and unnecessary branch statements / phi nodes
256    mPassManager.add(createEarlyCSEPass());                   // Simple common subexpression elimination pass
257    mPassManager.add(createInstructionCombiningPass());       // Simple peephole optimizations and bit-twiddling.
258    mPassManager.add(createReassociatePass());                // Canonicalizes commutative expressions
259    mPassManager.add(createGVNPass());                        // Global value numbering redundant expression elimination pass
260    mPassManager.add(createCFGSimplificationPass());          // Repeat CFG Simplification to "clean up" any newly found redundant phi nodes
261   
262    if (LLVM_UNLIKELY(codegen::ShowIROption != codegen::OmittedOption)) {
263        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
264            if (codegen::ShowIROption != "") {
265                std::error_code error;
266                mIROutputStream = new raw_fd_ostream(codegen::ShowIROption, error, sys::fs::OpenFlags::F_None);
267            } else {
268                mIROutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
269            }
270        }
271        mPassManager.add(createPrintModulePass(*mIROutputStream));
272    }
273   
274#if LLVM_VERSION_INTEGER >= LLVM_VERSION_CODE(3, 7, 0)
275    if (LLVM_UNLIKELY(codegen::ShowASMOption != codegen::OmittedOption)) {
276        if (codegen::ShowASMOption != "") {
277            std::error_code error;
278            mASMOutputStream = new raw_fd_ostream(codegen::ShowASMOption, error, sys::fs::OpenFlags::F_None);
279        } else {
280            mASMOutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
281        }
282        if (LLVM_UNLIKELY(mTarget->addPassesToEmitFile(mPassManager, *mASMOutputStream, TargetMachine::CGFT_AssemblyFile))) {
283            report_fatal_error("LLVM error: could not add emit assembly pass");
284        }
285    }
286#endif
287}
288
289void ParabixDriver::finalizeObject() {
290#ifdef ORCJIT
291    std::vector<std::unique_ptr<Module>> moduleSet;
292    auto Resolver = llvm::orc::createLambdaResolver(
293            [&](const std::string &Name) {
294                auto Sym = mCompileLayer->findSymbol(Name, false);
295#if LLVM_VERSION_INTEGER <= LLVM_VERSION_CODE(3, 9, 1)
296                if (Sym) return Sym.toRuntimeDyldSymbol();
297                return RuntimeDyld::SymbolInfo(nullptr);
298#else
299                if (Sym) return Sym;
300                return JITSymbol(nullptr);
301#endif
302            },
303            [&](const std::string &Name) {
304                auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name);
305                if (!SymAddr) SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(iBuilder->getMangledName(Name));
306#if LLVM_VERSION_INTEGER <= LLVM_VERSION_CODE(3, 9, 1)
307                if (SymAddr) return RuntimeDyld::SymbolInfo(SymAddr, JITSymbolFlags::Exported);
308                return RuntimeDyld::SymbolInfo(nullptr);
309#else
310                if (SymAddr) return JITSymbol(SymAddr, JITSymbolFlags::Exported);
311                return JITSymbol(nullptr);
312#endif
313            });
314#endif
315   
316    Module * module = nullptr;
317    try {
318        for (Kernel * const kernel : mUncachedKernel) {
319            iBuilder->setKernel(kernel);
320            kernel->generateKernel(iBuilder);
321            module = kernel->getModule(); assert (module);
322            module->setTargetTriple(mMainModule->getTargetTriple());
323#ifndef ORCJIT
324            mPassManager.run(*module);
325#endif
326        }
327        module = mMainModule;
328        iBuilder->setKernel(nullptr);
329        //mPassManager.run(*mMainModule);
330        for (Kernel * const kernel : mPipeline) {
331            if (LLVM_UNLIKELY(kernel->getModule() == nullptr)) {
332                report_fatal_error(kernel->getName() + " was neither loaded from cache nor generated prior to finalizeObject");
333            }
334#ifndef ORCJIT
335            mEngine->addModule(std::unique_ptr<Module>(kernel->getModule()));
336#else
337            moduleSet.push_back(std::unique_ptr<Module>(kernel->getModule()));
338#endif
339        }
340#ifndef ORCJIT
341            mEngine->finalizeObject();
342#else
343            moduleSet.push_back(std::unique_ptr<Module>(mMainModule));
344            auto handle = mCompileLayer->addModuleSet(std::move(moduleSet), make_unique<SectionMemoryManager>(), std::move(Resolver));
345#endif
346    } catch (const std::exception & e) {
347        report_fatal_error(module->getName() + ": " + e.what());
348    }
349
350}
351
352bool ParabixDriver::hasExternalFunction(llvm::StringRef functionName) const {
353    return RTDyldMemoryManager::getSymbolAddressInProcess(functionName);
354}
355
356void * ParabixDriver::getMain() {
357#ifndef ORCJIT
358    return mEngine->getPointerToNamedFunction("Main");
359#else
360    auto MainSym = mCompileLayer->findSymbol(iBuilder->getMangledName("Main"), false);
361    assert (MainSym && "Main not found");
362   
363    intptr_t main = (intptr_t) MainSym.getAddress();
364    return (void *) main;
365#endif
366}
367
368void ParabixDriver::performIncrementalCacheCleanupStep() {
369    if (mCache) mCache->performIncrementalCacheCleanupStep();
370}
371
372ParabixDriver::~ParabixDriver() {
373#ifndef ORCJIT
374    delete mEngine;
375#endif
376    delete mCache;
377    delete mTarget;
378    delete mIROutputStream;
379    delete mASMOutputStream;
380 }
Note: See TracBrowser for help on using the repository browser.