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

Last change on this file since 5458 was 5458, checked in by lindanl, 2 years ago

Add NVPTX driver.

File size: 5.2 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 <toolchain/toolchain.h>
11#include <IR_Gen/llvm2ptx.h>
12#include <llvm/Transforms/Scalar.h>
13
14
15using namespace llvm;
16using namespace parabix;
17
18using Kernel = kernel::Kernel;
19using KernelBuilder = kernel::KernelBuilder;
20
21
22NVPTXDriver::NVPTXDriver(std::string && moduleName)
23: mContext(new llvm::LLVMContext())
24, mMainModule(new Module(moduleName, *mContext))
25, iBuilder(nullptr)
26, mTarget(nullptr)
27, mEngine(nullptr) {
28
29    InitializeAllTargets();
30    InitializeAllTargetMCs();
31    InitializeAllAsmPrinters();
32    InitializeAllAsmParsers();
33
34    PassRegistry *Registry = PassRegistry::getPassRegistry();
35    initializeCore(*Registry);
36    initializeCodeGen(*Registry);
37    initializeLoopStrengthReducePass(*Registry);
38    initializeLowerIntrinsicsPass(*Registry);
39    initializeUnreachableBlockElimPass(*Registry);
40
41    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");
42    mMainModule->setTargetTriple("nvptx64-nvidia-cuda");
43    codegen::BlockSize = 64;
44
45    iBuilder.reset(IDISA::GetIDISA_GPU_Builder(*mContext));
46    iBuilder->setModule(mMainModule);
47    iBuilder->CreateBaseFunctions();
48}
49
50ExternalBuffer * NVPTXDriver::addExternalBuffer(std::unique_ptr<ExternalBuffer> b) {
51    mOwnedBuffers.emplace_back(std::move(b));
52    return cast<ExternalBuffer>(mOwnedBuffers.back().get());
53}
54
55StreamSetBuffer * NVPTXDriver::addBuffer(std::unique_ptr<StreamSetBuffer> b) {
56    b->allocateBuffer(iBuilder);
57    mOwnedBuffers.emplace_back(std::move(b));
58    return mOwnedBuffers.back().get();
59}
60
61kernel::Kernel * NVPTXDriver::addKernelInstance(std::unique_ptr<kernel::Kernel> kb) {
62    mOwnedKernels.emplace_back(std::move(kb));
63    return mOwnedKernels.back().get();
64}
65
66void NVPTXDriver::addKernelCall(Kernel & kb, const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
67    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kb.getModule() == nullptr));
68    mPipeline.emplace_back(&kb);
69    kb.bindPorts(inputs, outputs);
70    kb.setModule(iBuilder, mMainModule);
71}
72
73void NVPTXDriver::makeKernelCall(Kernel * kb, const std::vector<StreamSetBuffer *> & inputs, const std::vector<StreamSetBuffer *> & outputs) {
74    assert ("addKernelCall or makeKernelCall was already run on this kernel." && (kb->getModule() == nullptr));
75    mPipeline.emplace_back(kb);   
76    kb->bindPorts(inputs, outputs);
77    kb->setModule(iBuilder, mMainModule);
78}
79
80void NVPTXDriver::generatePipelineIR() {
81    #ifndef NDEBUG
82    if (LLVM_UNLIKELY(mPipeline.empty())) {
83        report_fatal_error("Pipeline cannot be empty");
84    } else {
85        for (auto i = mPipeline.begin(); i != mPipeline.end(); ++i) {
86            for (auto j = i; ++j != mPipeline.end(); ) {
87                if (LLVM_UNLIKELY(*i == *j)) {
88                    report_fatal_error("Kernel instances cannot occur twice in the pipeline");
89                }
90            }
91        }
92    }
93    #endif
94
95    // note: instantiation of all kernels must occur prior to initialization
96    for (const auto & k : mPipeline) {
97        k->addKernelDeclarations(iBuilder);
98    }
99    for (const auto & k : mPipeline) {
100        k->createInstance(iBuilder);
101    }
102    for (const auto & k : mPipeline) {
103        k->initializeInstance(iBuilder);
104    }
105   
106    generatePipelineLoop(iBuilder, mPipeline);
107   
108    for (const auto & k : mPipeline) {
109        k->finalizeInstance(iBuilder);
110    }
111}
112
113void NVPTXDriver::finalizeAndCompile(Function * mainFunc, std::string IRFilename, std::string PTXFilename) {
114
115    legacy::PassManager PM;
116    PM.add(createPromoteMemoryToRegisterPass()); //Force the use of mem2reg to promote stack variables.
117    PM.add(createReassociatePass());             //Reassociate expressions.
118    PM.add(createGVNPass());                     //Eliminate common subexpressions.
119    PM.add(createInstructionCombiningPass());    //Simple peephole optimizations and bit-twiddling.
120    PM.add(createCFGSimplificationPass());
121
122    for (kernel::Kernel * const kb : mPipeline) {
123        iBuilder->setKernel(kb);
124        kb->generateKernel(iBuilder);
125    }
126
127    MDNode * Node = MDNode::get(mMainModule->getContext(),
128                                {llvm::ValueAsMetadata::get(mainFunc),
129                                 MDString::get(mMainModule->getContext(), "kernel"), 
130                                 ConstantAsMetadata::get(ConstantInt::get(iBuilder->getInt32Ty(), 1))});
131    NamedMDNode *NMD = mMainModule->getOrInsertNamedMetadata("nvvm.annotations");
132    NMD->addOperand(Node);
133
134    PM.run(*mMainModule); 
135
136    std::error_code error;
137    raw_fd_ostream out(IRFilename, error, sys::fs::OpenFlags::F_None);
138    mMainModule->print(out, nullptr);
139
140    if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::ShowIR)))
141            mMainModule->dump();
142
143    llvm2ptx(IRFilename, PTXFilename);
144}
145
146const std::unique_ptr<kernel::KernelBuilder> & NVPTXDriver::getBuilder() {
147    return iBuilder;
148}
149
150NVPTXDriver::~NVPTXDriver() {
151}
Note: See TracBrowser for help on using the repository browser.