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

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

ShowIR, ShowASM, ShowUnoptimizedIR options can set filename: -ShowIR=myIRfile

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