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

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

LLVM_VERSION_INTEGER allows ordered comparisons, initial preparation for LLVM 3.9.0

File size: 6.8 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#if LLVM_VERSION_INTEGER >= LLVM_3_9_0
25#include <llvm/Transforms/Scalar/GVN.h>
26#endif
27
28using namespace llvm;
29
30using StreamSetBuffer = parabix::StreamSetBuffer;
31
32NVPTXDriver::NVPTXDriver(std::string && moduleName)
33: Driver(std::move(moduleName)) {
34
35    InitializeAllTargets();
36    InitializeAllTargetMCs();
37    InitializeAllAsmPrinters();
38    InitializeAllAsmParsers();
39
40    PassRegistry * Registry = PassRegistry::getPassRegistry();
41    initializeCore(*Registry);
42    initializeCodeGen(*Registry);
43    initializeLoopStrengthReducePass(*Registry);
44    initializeLowerIntrinsicsPass(*Registry);
45#if LLVM_VERSION_INTEGER < LLVM_3_9_0
46    initializeUnreachableBlockElimPass(*Registry);
47#else
48    initializeUnreachableBlockElimLegacyPassPass(*Registry);
49#endif
50   
51    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");
52    mMainModule->setTargetTriple("nvptx64-nvidia-cuda");
53
54    iBuilder.reset(IDISA::GetIDISA_GPU_Builder(*mContext));
55    iBuilder->setModule(mMainModule);
56    iBuilder->CreateBaseFunctions();
57}
58
59void NVPTXDriver::makeKernelCall(kernel::Kernel * kb, const std::vector<parabix::StreamSetBuffer *> & inputs, const std::vector<parabix::StreamSetBuffer *> & outputs) {
60    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kb->getModule() == nullptr));
61    mPipeline.emplace_back(kb);
62    kb->bindPorts(inputs, outputs);
63    kb->setModule(mMainModule);
64}
65
66void NVPTXDriver::generatePipelineIR() {
67    // note: instantiation of all kernels must occur prior to initialization
68    for (const auto & k : mPipeline) {
69        k->addKernelDeclarations(iBuilder);
70    }
71    for (const auto & k : mPipeline) {
72        k->createInstance(iBuilder);
73    }
74    for (const auto & k : mPipeline) {
75        k->initializeInstance(iBuilder);
76    }
77   
78    generatePipelineLoop(iBuilder, mPipeline);
79   
80    for (const auto & k : mPipeline) {
81        k->finalizeInstance(iBuilder);
82    }
83}
84
85Function * NVPTXDriver::addLinkFunction(Module *, llvm::StringRef, FunctionType *, void *) const {
86    report_fatal_error("NVPTX does not support linked functions");
87}
88
89
90static int llvm2ptx(Module * M, std::string PTXFilename) {
91
92    std::unique_ptr<MIRParser> MIR;
93    Triple TheTriple(M->getTargetTriple());
94
95    if (TheTriple.getTriple().empty())
96        TheTriple.setTriple(sys::getDefaultTargetTriple());
97
98    // Get the target specific parser.
99    std::string Error;
100    const auto TheTarget = TargetRegistry::lookupTarget(codegen::MArch, TheTriple, Error);
101    if (!TheTarget) {
102        report_fatal_error(Error);
103    }
104
105    const auto CPUStr = codegen::getCPUStr();
106    const auto FeaturesStr = codegen::getFeaturesStr();
107
108    std::unique_ptr<TargetMachine> Target(
109                TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr,
110                                               codegen::Options, codegen::RelocModel, codegen::CMModel, codegen::OptLevel));
111
112    assert(Target && "Could not allocate target machine!");
113
114    // Figure out where we are going to send the output.
115    std::error_code EC;
116    sys::fs::OpenFlags OpenFlags = sys::fs::F_None | sys::fs::F_Text;
117    std::unique_ptr<tool_output_file> Out = llvm::make_unique<tool_output_file>(PTXFilename, EC, OpenFlags);
118    if (EC) {
119        errs() << EC.message() << '\n';
120        return 1;
121    }
122
123    // Build up all of the passes that we want to do to the module.
124    legacy::PassManager PM;
125
126    // Add an appropriate TargetLibraryInfo pass for the module's triple.
127    TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
128
129    PM.add(new TargetLibraryInfoWrapperPass(TLII));
130
131    // Add the target data from the target machine, if it exists, or the module.
132    M->setDataLayout(Target->createDataLayout());
133
134    // Override function attributes based on CPUStr, FeaturesStr, and command line
135    // flags.
136    codegen::setFunctionAttributes(CPUStr, FeaturesStr, *M);
137
138    {
139        raw_pwrite_stream *OS = &Out->os();
140
141        AnalysisID StartBeforeID = nullptr;
142        AnalysisID StartAfterID = nullptr;
143        AnalysisID StopAfterID = nullptr;
144        const PassRegistry *PR = PassRegistry::getPassRegistry();
145        // Ask the target to add backend passes as necessary.
146        if (Target->addPassesToEmitFile(PM, *OS, codegen::FileType, false, StartBeforeID,
147                                        StartAfterID, StopAfterID, MIR.get())) {
148            errs() << " target does not support generation of this file type!\n";
149            return 1;
150        }
151
152        PM.run(*M);
153    }
154    // Declare success.
155    Out->keep();
156
157    return 0;
158}
159
160void NVPTXDriver::finalizeObject() {
161
162    legacy::PassManager PM;
163    PM.add(createPromoteMemoryToRegisterPass()); //Force the use of mem2reg to promote stack variables.
164    PM.add(createReassociatePass());             //Reassociate expressions.
165    PM.add(createGVNPass());                     //Eliminate common subexpressions.
166    PM.add(createInstructionCombiningPass());    //Simple peephole optimizations and bit-twiddling.
167    PM.add(createCFGSimplificationPass());
168
169    for (kernel::Kernel * const kb : mPipeline) {
170        iBuilder->setKernel(kb);
171        kb->generateKernel(iBuilder);
172    }
173
174    Function * mainFunc = mMainModule->getFunction("Main");
175
176    MDNode * Node = MDNode::get(mMainModule->getContext(),
177                                {llvm::ValueAsMetadata::get(mainFunc),
178                                 MDString::get(mMainModule->getContext(), "kernel"), 
179                                 ConstantAsMetadata::get(ConstantInt::get(iBuilder->getInt32Ty(), 1))});
180    NamedMDNode *NMD = mMainModule->getOrInsertNamedMetadata("nvvm.annotations");
181    NMD->addOperand(Node);
182
183    PM.run(*mMainModule); 
184
185    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowIR))) {
186        mMainModule->dump();
187    }
188
189    const auto PTXFilename = mMainModule->getModuleIdentifier() + ".ptx";
190
191    llvm2ptx(mMainModule, PTXFilename);
192}
193
194void * NVPTXDriver::getMain() {
195    report_fatal_error("NVPTX must be executed by calling RunPTX");
196}
197
198NVPTXDriver::~NVPTXDriver() {
199}
Note: See TracBrowser for help on using the repository browser.