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

Last change on this file since 5731 was 5731, checked in by cameron, 15 months ago

LLVM_VERSION_INTEGER allows ordered comparisons, initial preparation for LLVM 3.9.0

File size: 9.1 KB
Line 
1#include "cpudriver.h"
2
3#include <IR_Gen/idisa_target.h>
4#include <toolchain/toolchain.h>
5#include <llvm/ExecutionEngine/ExecutionEngine.h>  // for EngineBuilder
6#include <llvm/IR/LegacyPassManager.h>             // for PassManager
7#include <llvm/IR/IRPrintingPasses.h>
8#include <llvm/InitializePasses.h>                 // for initializeCodeGen
9#include <llvm/PassRegistry.h>                     // for PassRegistry
10#include <llvm/Support/CodeGen.h>                  // for Level, Level::None
11#include <llvm/Support/Compiler.h>                 // for LLVM_UNLIKELY
12#include <llvm/Support/TargetSelect.h>
13#include <llvm/Target/TargetMachine.h>             // for TargetMachine, Tar...
14#include <llvm/Target/TargetOptions.h>             // for TargetOptions
15#include <llvm/Transforms/Scalar.h>
16#if LLVM_VERSION_INTEGER >= LLVM_3_9_0
17#include <llvm/Transforms/Scalar/GVN.h>
18#endif
19#include <llvm/Transforms/Utils/Local.h>
20#include <toolchain/object_cache.h>
21#include <toolchain/pipeline.h>
22#include <kernels/kernel_builder.h>
23#include <kernels/kernel.h>
24#include <llvm/IR/Verifier.h>
25
26#ifndef NDEBUG
27#define IN_DEBUG_MODE true
28#else
29#define IN_DEBUG_MODE false
30#endif
31
32using namespace llvm;
33using Kernel = kernel::Kernel;
34using StreamSetBuffer = parabix::StreamSetBuffer;
35using KernelBuilder = kernel::KernelBuilder;
36
37ParabixDriver::ParabixDriver(std::string && moduleName)
38: Driver(std::move(moduleName))
39, mTarget(nullptr)
40, mEngine(nullptr)
41, mCache(nullptr)
42, mIROutputStream(nullptr)
43, mASMOutputStream(nullptr) {
44
45    InitializeNativeTarget();
46    InitializeNativeTargetAsmPrinter();
47    InitializeNativeTargetAsmParser();
48
49    PassRegistry * Registry = PassRegistry::getPassRegistry();
50    initializeCore(*Registry);
51    initializeCodeGen(*Registry);
52    initializeLowerIntrinsicsPass(*Registry);
53
54    std::string errMessage;
55    EngineBuilder builder{std::unique_ptr<Module>(mMainModule)};
56    builder.setErrorStr(&errMessage);
57    builder.setUseOrcMCJITReplacement(true);
58    builder.setTargetOptions(codegen::Options);
59    builder.setVerifyModules(false);
60    builder.setOptLevel(codegen::OptLevel);
61
62    StringMap<bool> HostCPUFeatures;
63    if (sys::getHostCPUFeatures(HostCPUFeatures)) {
64        std::vector<std::string> attrs;
65        for (auto &flag : HostCPUFeatures) {
66            auto enabled = flag.second ? "+" : "-";
67            attrs.push_back(enabled + flag.first().str());
68        }
69        builder.setMAttrs(attrs);
70    }
71
72    mEngine = builder.create();
73    if (mEngine == nullptr) {
74        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
75    }
76    mTarget = builder.selectTarget();   
77    if (LLVM_LIKELY(codegen::EnableObjectCache)) {
78        if (codegen::ObjectCacheDir) {
79            mCache = new ParabixObjectCache(codegen::ObjectCacheDir);
80        } else {
81            mCache = new ParabixObjectCache();
82        }
83        mEngine->setObjectCache(mCache);
84    }
85    mMainModule->setTargetTriple(mTarget->getTargetTriple().getTriple());
86    iBuilder.reset(IDISA::GetIDISA_Builder(*mContext));
87    iBuilder->setDriver(this);
88    iBuilder->setModule(mMainModule);
89}
90
91void ParabixDriver::makeKernelCall(Kernel * kernel, const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
92    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kernel->getModule() == nullptr));
93    mPipeline.emplace_back(kernel);
94    kernel->bindPorts(inputs, outputs);
95    if (!mCache || !mCache->loadCachedObjectFile(iBuilder, kernel)) {
96        mUncachedKernel.push_back(kernel);
97    }
98    if (kernel->getModule() == nullptr) {
99        kernel->makeModule(iBuilder);
100    }
101    assert (kernel->getModule());
102}
103
104void ParabixDriver::generatePipelineIR() {
105
106    for (Kernel * const kernel : mUncachedKernel) {
107        kernel->prepareKernel(iBuilder);
108    }
109
110    // note: instantiation of all kernels must occur prior to initialization
111    for (Kernel * const k : mPipeline) {
112        k->addKernelDeclarations(iBuilder);
113    }
114    for (Kernel * const k : mPipeline) {
115        k->createInstance(iBuilder);
116    }
117    for (Kernel * const k : mPipeline) {
118        k->initializeInstance(iBuilder);
119    }
120    if (codegen::PipelineParallel) {
121        generateParallelPipeline(iBuilder, mPipeline);
122    } else if (codegen::SegmentPipelineParallel) {
123        generateSegmentParallelPipeline(iBuilder, mPipeline);
124    } else {
125        generatePipelineLoop(iBuilder, mPipeline);
126    }
127    for (const auto & k : mPipeline) {
128        k->finalizeInstance(iBuilder);
129    }
130}
131
132Function * ParabixDriver::addLinkFunction(Module * mod, llvm::StringRef name, FunctionType * type, void * functionPtr) const {
133    if (LLVM_UNLIKELY(mod == nullptr)) {
134        report_fatal_error("addLinkFunction(" + name + ") cannot be called until after addKernelCall or makeKernelCall");
135    }
136    Function * f = mod->getFunction(name);
137    if (LLVM_UNLIKELY(f == nullptr)) {
138        f = Function::Create(type, Function::ExternalLinkage, name, mod);
139        mEngine->updateGlobalMapping(f, functionPtr);
140    } else if (LLVM_UNLIKELY(f->getType() != type->getPointerTo())) {
141        report_fatal_error("Cannot link " + name + ": a function with a different signature already exists with that name in " + mod->getName());
142    }
143    return f;
144}
145
146void ParabixDriver::finalizeObject() {
147
148    legacy::PassManager PM;
149    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowUnoptimizedIR))) {
150        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
151            if (codegen::IROutputFilename) {
152                std::error_code error;
153                mIROutputStream = new raw_fd_ostream(codegen::IROutputFilename, error, sys::fs::OpenFlags::F_None);
154            } else {
155                mIROutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
156            }
157        }
158        PM.add(createPrintModulePass(*mIROutputStream));
159    }
160    if (IN_DEBUG_MODE || LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::VerifyIR))) {
161        PM.add(createVerifierPass());
162    }
163    PM.add(createPromoteMemoryToRegisterPass());    // Promote stack variables to constants or PHI nodes
164    PM.add(createCFGSimplificationPass());          // Remove dead basic blocks and unnecessary branch statements / phi nodes
165    PM.add(createEarlyCSEPass());                   // Simple common subexpression elimination pass
166    PM.add(createInstructionCombiningPass());       // Simple peephole optimizations and bit-twiddling.
167    PM.add(createReassociatePass());                // Canonicalizes commutative expressions
168    PM.add(createGVNPass());                        // Global value numbering redundant expression elimination pass
169    PM.add(createCFGSimplificationPass());          // Repeat CFG Simplification to "clean up" any newly found redundant phi nodes
170
171    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowIR))) {
172        if (LLVM_LIKELY(mIROutputStream == nullptr)) {
173            if (codegen::IROutputFilename) {
174                std::error_code error;
175                mIROutputStream = new raw_fd_ostream(codegen::IROutputFilename, error, sys::fs::OpenFlags::F_None);
176            } else {
177                mIROutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
178            }
179        }
180        PM.add(createPrintModulePass(*mIROutputStream));
181    }
182
183#if LLVM_VERSION_INTEGER >= LLVM_3_7_0
184    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowASM))) {
185        if (codegen::ASMOutputFilename) {
186            std::error_code error;
187            mASMOutputStream = new raw_fd_ostream(codegen::ASMOutputFilename, error, sys::fs::OpenFlags::F_None);
188        } else {
189            mASMOutputStream = new raw_fd_ostream(STDERR_FILENO, false, true);
190        }
191        if (LLVM_UNLIKELY(mTarget->addPassesToEmitFile(PM, *mASMOutputStream, TargetMachine::CGFT_AssemblyFile))) {
192            report_fatal_error("LLVM error: could not add emit assembly pass");
193        }
194    }
195#endif
196
197    Module * module = nullptr;
198    try {
199        for (Kernel * const kernel : mUncachedKernel) {
200            iBuilder->setKernel(kernel);
201            kernel->generateKernel(iBuilder);
202            module = kernel->getModule(); assert (module);
203            module->setTargetTriple(mMainModule->getTargetTriple());
204            PM.run(*module);
205        }
206        module = mMainModule;
207        iBuilder->setKernel(nullptr);
208        PM.run(*mMainModule);
209        for (Kernel * const kernel : mPipeline) {
210            if (LLVM_UNLIKELY(kernel->getModule() == nullptr)) {
211                report_fatal_error(kernel->getName() + " was neither loaded from cache nor generated prior to finalizeObject");
212            }
213            mEngine->addModule(std::unique_ptr<Module>(kernel->getModule()));
214        }
215        mEngine->finalizeObject();
216        if (mCache) mCache->cleanUpObjectCacheFiles();
217    } catch (const std::exception & e) {
218        report_fatal_error(module->getName() + ": " + e.what());
219    }
220
221}
222
223bool ParabixDriver::hasExternalFunction(llvm::StringRef functionName) const {
224    return mEngine->getPointerToNamedFunction(functionName, false) != nullptr;
225}
226
227void * ParabixDriver::getMain() {
228    return mEngine->getPointerToNamedFunction("Main");
229}
230
231ParabixDriver::~ParabixDriver() {
232    delete mEngine;
233    delete mCache;
234    delete mTarget;
235    delete mIROutputStream;
236    delete mASMOutputStream;
237}
Note: See TracBrowser for help on using the repository browser.