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

Last change on this file since 5597 was 5510, checked in by nmedfort, 2 years ago

Back up check-in. Should have no effect on current programs.

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