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

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

Restructuring work for the Driver classes. Start of work to eliminate the memory leaks with the ExecutionEngine?. Replaced custom AlignedMalloc? with backend call to std::aligned_malloc. Salvaged some work on DistributionPass? for reevaluation.

File size: 8.3 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
23#ifndef NDEBUG
24#define IN_DEBUG_MODE true
25#else
26#define IN_DEBUG_MODE false
27#endif
28
29using namespace llvm;
30using Kernel = kernel::Kernel;
31using StreamSetBuffer = parabix::StreamSetBuffer;
32using KernelBuilder = kernel::KernelBuilder;
33
34ParabixDriver::ParabixDriver(std::string && moduleName)
35: Driver(std::move(moduleName))
36, mTarget(nullptr)
37, mEngine(nullptr)
38, mCache(nullptr) {
39
40    InitializeNativeTarget();
41    InitializeNativeTargetAsmPrinter();
42    InitializeNativeTargetAsmParser();
43
44    PassRegistry * Registry = PassRegistry::getPassRegistry();
45    initializeCore(*Registry);
46    initializeCodeGen(*Registry);
47    initializeLowerIntrinsicsPass(*Registry);
48
49    std::string errMessage;
50    EngineBuilder builder{std::unique_ptr<Module>(mMainModule)};
51    builder.setErrorStr(&errMessage);
52    builder.setUseOrcMCJITReplacement(true);
53    builder.setTargetOptions(codegen::Options);
54    builder.setVerifyModules(false);
55    builder.setOptLevel(codegen::OptLevel);
56
57    StringMap<bool> HostCPUFeatures;
58    if (sys::getHostCPUFeatures(HostCPUFeatures)) {
59        std::vector<std::string> attrs;
60        for (auto &flag : HostCPUFeatures) {
61            auto enabled = flag.second ? "+" : "-";
62            attrs.push_back(enabled + flag.first().str());
63        }
64        builder.setMAttrs(attrs);
65    }
66
67    mEngine = builder.create();
68    if (mEngine == nullptr) {
69        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
70    }
71    mTarget = builder.selectTarget();
72    if (LLVM_LIKELY(codegen::EnableObjectCache)) {
73        if (codegen::ObjectCacheDir.empty()) {
74            mCache = new ParabixObjectCache();
75        } else {
76            mCache = new ParabixObjectCache(codegen::ObjectCacheDir);
77        }
78        mEngine->setObjectCache(mCache);
79    }
80
81    mMainModule->setTargetTriple(mTarget->getTargetTriple().getTriple());
82
83    iBuilder.reset(IDISA::GetIDISA_Builder(*mContext, mMainModule->getTargetTriple()));
84    iBuilder->setDriver(this);
85    iBuilder->setModule(mMainModule);
86}
87
88void ParabixDriver::makeKernelCall(Kernel * kb, const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
89    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kb->getModule() == nullptr));
90    mPipeline.emplace_back(kb);
91    kb->bindPorts(inputs, outputs);
92    kb->makeModule(iBuilder);
93}
94
95void ParabixDriver::generatePipelineIR() {
96    #ifndef NDEBUG
97    if (LLVM_UNLIKELY(mPipeline.empty())) {
98        report_fatal_error("Pipeline cannot be empty");
99    } else {
100        for (auto i = mPipeline.begin(); i != mPipeline.end(); ++i) {
101            for (auto j = i; ++j != mPipeline.end(); ) {
102                if (LLVM_UNLIKELY(*i == *j)) {
103                    report_fatal_error("Kernel instances cannot occur twice in the pipeline");
104                }
105            }
106        }
107    }
108    #endif
109    // note: instantiation of all kernels must occur prior to initialization
110    for (const auto & k : mPipeline) {
111        k->addKernelDeclarations(iBuilder);
112    }
113    for (const auto & k : mPipeline) {
114        k->createInstance(iBuilder);
115    }
116    for (const auto & k : mPipeline) {
117        k->initializeInstance(iBuilder);
118    }
119    if (codegen::pipelineParallel) {
120        generateParallelPipeline(iBuilder, mPipeline);
121    } else if (codegen::segmentPipelineParallel) {
122        generateSegmentParallelPipeline(iBuilder, mPipeline);
123    } else {
124        codegen::ThreadNum = 1;
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    assert ("addKernelCall or makeKernelCall must be called before LinkFunction" && (mod != nullptr));
134    Function * const f = cast<Function>(mod->getOrInsertFunction(name, type));
135    mEngine->addGlobalMapping(f, functionPtr);
136    return f;
137}
138
139void ParabixDriver::linkAndFinalize() {
140
141    legacy::PassManager PM;
142    std::unique_ptr<raw_fd_ostream> IROutputStream(nullptr);
143    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowUnoptimizedIR))) {
144        if (codegen::IROutputFilename.empty()) {
145            IROutputStream.reset(new raw_fd_ostream(STDERR_FILENO, false, false));
146        } else {
147            std::error_code error;
148            IROutputStream.reset(new raw_fd_ostream(codegen::IROutputFilename, error, sys::fs::OpenFlags::F_None));
149        }
150        PM.add(createPrintModulePass(*IROutputStream));
151    }
152
153    if (IN_DEBUG_MODE || LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::VerifyIR))) {
154        PM.add(createVerifierPass());
155    }
156    PM.add(createPromoteMemoryToRegisterPass()); //Force the use of mem2reg to promote stack variables.
157    PM.add(createReassociatePass());             //Reassociate expressions.
158    PM.add(createGVNPass());                     //Eliminate common subexpressions.
159    PM.add(createInstructionCombiningPass());    //Simple peephole optimizations and bit-twiddling.
160    PM.add(createCFGSimplificationPass());
161    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowIR))) {
162        if (LLVM_LIKELY(IROutputStream == nullptr)) {
163            if (codegen::IROutputFilename.empty()) {
164                IROutputStream.reset(new raw_fd_ostream(STDERR_FILENO, false, false));
165            } else {
166                std::error_code error;
167                IROutputStream.reset(new raw_fd_ostream(codegen::IROutputFilename, error, sys::fs::OpenFlags::F_None));
168            }
169        }
170        PM.add(createPrintModulePass(*IROutputStream));
171    }
172
173    #ifndef USE_LLVM_3_6
174    std::unique_ptr<raw_fd_ostream> ASMOutputStream(nullptr);
175    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowASM))) {
176        if (codegen::ASMOutputFilename.empty()) {
177            ASMOutputStream.reset(new raw_fd_ostream(STDERR_FILENO, false, false));
178        } else {
179            std::error_code error;
180            ASMOutputStream.reset(new raw_fd_ostream(codegen::ASMOutputFilename, error, sys::fs::OpenFlags::F_None));
181        }
182        if (LLVM_UNLIKELY(mTarget->addPassesToEmitFile(PM, *ASMOutputStream, TargetMachine::CGFT_AssemblyFile))) {
183            report_fatal_error("LLVM error: could not add emit assembly pass");
184        }
185    }
186    #endif
187
188    Module * module = nullptr;
189
190    try {
191
192        for (Kernel * const kernel : mPipeline) {
193            iBuilder->setKernel(kernel);
194            module = kernel->getModule();
195            assert (module != mMainModule);
196            bool uncachedObject = true;
197            if (mCache && mCache->loadCachedObjectFile(iBuilder, kernel)) {
198                uncachedObject = false;
199            }
200            if (uncachedObject) {
201                module->setTargetTriple(mMainModule->getTargetTriple());
202                kernel->generateKernel(iBuilder);
203                PM.run(*module);
204            }
205            mEngine->addModule(std::unique_ptr<Module>(module));
206        }
207
208        iBuilder->setKernel(nullptr);
209        module = mMainModule;
210        PM.run(*mMainModule);
211        mEngine->finalizeObject();
212
213        if (mCache) mCache->cleanUpObjectCacheFiles();
214
215    } catch (const std::exception & e) {
216        report_fatal_error(e.what());
217    }
218
219}
220
221void * ParabixDriver::getPointerToMain() {
222    return mEngine->getPointerToNamedFunction("Main");
223}
224
225ParabixDriver::~ParabixDriver() {
226//    delete mEngine;
227    delete mCache;
228    delete mTarget;
229}
Note: See TracBrowser for help on using the repository browser.