source: icGREP/icgrep-devel/icgrep/toolchain/NVPTXDriver.cpp @ 5486

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

Eliminated ExecutionEngine? memory leak. Intentionally broke compatibility with prior versions to ensure unchecked in projects are restructured.

File size: 8.3 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include "NVPTXDriver.h"
8#include <IR_Gen/idisa_target.h>
9#include <kernels/kernel_builder.h>
10#include <kernels/kernel.h>
11#include <llvm/Transforms/Scalar.h>
12#include <llvm/Transforms/Utils/Local.h>
13#include <toolchain/toolchain.h>
14#include <toolchain/pipeline.h>
15#include <llvm/Analysis/TargetLibraryInfo.h>
16#include <llvm/CodeGen/MIRParser/MIRParser.h>
17#include <llvm/IR/LegacyPassManager.h>
18#include <llvm/IR/Module.h>
19#include <llvm/Support/FileSystem.h>
20#include <llvm/Support/TargetRegistry.h>
21#include <llvm/Support/TargetSelect.h>
22#include <llvm/Support/ToolOutputFile.h>
23#include <llvm/Target/TargetMachine.h>
24
25using namespace llvm;
26
27using StreamSetBuffer = parabix::StreamSetBuffer;
28
29NVPTXDriver::NVPTXDriver(std::string && moduleName)
30: Driver(std::move(moduleName)) {
31
32    InitializeAllTargets();
33    InitializeAllTargetMCs();
34    InitializeAllAsmPrinters();
35    InitializeAllAsmParsers();
36
37    PassRegistry * Registry = PassRegistry::getPassRegistry();
38    initializeCore(*Registry);
39    initializeCodeGen(*Registry);
40    initializeLoopStrengthReducePass(*Registry);
41    initializeLowerIntrinsicsPass(*Registry);
42    initializeUnreachableBlockElimPass(*Registry);
43
44    mMainModule->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64");
45    mMainModule->setTargetTriple("nvptx64-nvidia-cuda");
46
47    iBuilder.reset(IDISA::GetIDISA_GPU_Builder(*mContext));
48    iBuilder->setModule(mMainModule);
49    iBuilder->CreateBaseFunctions();
50}
51
52void NVPTXDriver::makeKernelCall(kernel::Kernel * kb, const std::vector<parabix::StreamSetBuffer *> & inputs, const std::vector<parabix::StreamSetBuffer *> & outputs) {
53    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kb->getModule() == nullptr));
54    mPipeline.emplace_back(kb);
55    kb->bindPorts(inputs, outputs);
56    kb->setModule(iBuilder, mMainModule);
57}
58
59void NVPTXDriver::generatePipelineIR() {
60    #ifndef NDEBUG
61    if (LLVM_UNLIKELY(mPipeline.empty())) {
62        report_fatal_error("Pipeline cannot be empty");
63    } else {
64        for (auto i = mPipeline.begin(); i != mPipeline.end(); ++i) {
65            for (auto j = i; ++j != mPipeline.end(); ) {
66                if (LLVM_UNLIKELY(*i == *j)) {
67                    report_fatal_error("Kernel instances cannot occur twice in the pipeline");
68                }
69            }
70        }
71    }
72    #endif
73
74    // note: instantiation of all kernels must occur prior to initialization
75    for (const auto & k : mPipeline) {
76        k->addKernelDeclarations(iBuilder);
77    }
78    for (const auto & k : mPipeline) {
79        k->createInstance(iBuilder);
80    }
81    for (const auto & k : mPipeline) {
82        k->initializeInstance(iBuilder);
83    }
84   
85    generatePipelineLoop(iBuilder, mPipeline);
86   
87    for (const auto & k : mPipeline) {
88        k->finalizeInstance(iBuilder);
89    }
90}
91
92Function * NVPTXDriver::addLinkFunction(Module *, llvm::StringRef, FunctionType *, void *) const {
93    report_fatal_error("NVPTX does not support linked functions");
94}
95
96
97static int llvm2ptx(Module * M, std::string PTXFilename) {
98
99    std::unique_ptr<MIRParser> MIR;
100    Triple TheTriple(M->getTargetTriple());
101
102    if (TheTriple.getTriple().empty())
103        TheTriple.setTriple(sys::getDefaultTargetTriple());
104
105    // Get the target specific parser.
106    std::string Error;
107    const auto TheTarget = TargetRegistry::lookupTarget(codegen::MArch, TheTriple, Error);
108    if (!TheTarget) {
109        report_fatal_error(Error);
110    }
111
112    const auto CPUStr = codegen::getCPUStr();
113    const auto FeaturesStr = codegen::getFeaturesStr();
114
115    std::unique_ptr<TargetMachine> Target(
116                TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr,
117                                               codegen::Options, codegen::RelocModel, codegen::CMModel, codegen::OptLevel));
118
119    assert(Target && "Could not allocate target machine!");
120
121    // Figure out where we are going to send the output.
122    std::error_code EC;
123    sys::fs::OpenFlags OpenFlags = sys::fs::F_None | sys::fs::F_Text;
124    std::unique_ptr<tool_output_file> Out = llvm::make_unique<tool_output_file>(PTXFilename, EC, OpenFlags);
125    if (EC) {
126        errs() << EC.message() << '\n';
127        return 1;
128    }
129
130    // Build up all of the passes that we want to do to the module.
131    legacy::PassManager PM;
132
133    // Add an appropriate TargetLibraryInfo pass for the module's triple.
134    TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
135
136    PM.add(new TargetLibraryInfoWrapperPass(TLII));
137
138    // Add the target data from the target machine, if it exists, or the module.
139    M->setDataLayout(Target->createDataLayout());
140
141    // Override function attributes based on CPUStr, FeaturesStr, and command line
142    // flags.
143    codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M);
144
145    {
146        raw_pwrite_stream *OS = &Out->os();
147
148        AnalysisID StartBeforeID = nullptr;
149        AnalysisID StartAfterID = nullptr;
150        AnalysisID StopAfterID = nullptr;
151        const PassRegistry *PR = PassRegistry::getPassRegistry();
152        if (!codegen::RunPass.empty()) {
153            if (!codegen::StartAfter.empty() || !codegen::StopAfter.empty()) {
154                errs() << "start-after and/or stop-after passes are redundant when run-pass is specified.\n";
155                return 1;
156            }
157            const PassInfo *PI = PR->getPassInfo(codegen::RunPass);
158            if (!PI) {
159                errs() << "run-pass pass is not registered.\n";
160                return 1;
161            }
162            StopAfterID = StartBeforeID = PI->getTypeInfo();
163        } else {
164            if (!codegen::StartAfter.empty()) {
165                const PassInfo *PI = PR->getPassInfo(codegen::StartAfter);
166                if (!PI) {
167                    errs() << "start-after pass is not registered.\n";
168                    return 1;
169                }
170                StartAfterID = PI->getTypeInfo();
171            }
172            if (!codegen::StopAfter.empty()) {
173                const PassInfo *PI = PR->getPassInfo(codegen::StopAfter);
174                if (!PI) {
175                    errs() << "stop-after pass is not registered.\n";
176                    return 1;
177                }
178                StopAfterID = PI->getTypeInfo();
179            }
180        }
181
182        // Ask the target to add backend passes as necessary.
183        if (Target->addPassesToEmitFile(PM, *OS, codegen::FileType, false, StartBeforeID,
184                                        StartAfterID, StopAfterID, MIR.get())) {
185            errs() << " target does not support generation of this file type!\n";
186            return 1;
187        }
188
189        PM.run(*M);
190    }
191    // Declare success.
192    Out->keep();
193
194    return 0;
195}
196
197void NVPTXDriver::finalizeObject() {
198
199    legacy::PassManager PM;
200    PM.add(createPromoteMemoryToRegisterPass()); //Force the use of mem2reg to promote stack variables.
201    PM.add(createReassociatePass());             //Reassociate expressions.
202    PM.add(createGVNPass());                     //Eliminate common subexpressions.
203    PM.add(createInstructionCombiningPass());    //Simple peephole optimizations and bit-twiddling.
204    PM.add(createCFGSimplificationPass());
205
206    for (kernel::Kernel * const kb : mPipeline) {
207        iBuilder->setKernel(kb);
208        kb->generateKernel(iBuilder);
209    }
210
211    Function * mainFunc = mMainModule->getFunction("Main");
212
213    MDNode * Node = MDNode::get(mMainModule->getContext(),
214                                {llvm::ValueAsMetadata::get(mainFunc),
215                                 MDString::get(mMainModule->getContext(), "kernel"), 
216                                 ConstantAsMetadata::get(ConstantInt::get(iBuilder->getInt32Ty(), 1))});
217    NamedMDNode *NMD = mMainModule->getOrInsertNamedMetadata("nvvm.annotations");
218    NMD->addOperand(Node);
219
220    PM.run(*mMainModule); 
221
222    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowIR))) {
223        mMainModule->dump();
224    }
225
226    const auto PTXFilename = mMainModule->getModuleIdentifier() + ".ptx";
227
228    llvm2ptx(mMainModule, PTXFilename);
229}
230
231void * NVPTXDriver::getMain() {
232    report_fatal_error("NVPTX must be executed by calling RunPTX");
233}
234
235NVPTXDriver::~NVPTXDriver() {
236}
Note: See TracBrowser for help on using the repository browser.