source: icGREP/icgrep-devel/icgrep/toolchain.cpp @ 5179

Last change on this file since 5179 was 5175, checked in by cameron, 3 years ago

Some tidy ups and changes to prepare for LLVM 3.9

File size: 7.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 <string>
8#include <iostream>
9#include <fstream>
10#include <sstream>
11
12#include <toolchain.h>
13#include <llvm/IR/Function.h>
14#include <llvm/IR/Module.h>
15#include <llvm/ExecutionEngine/ExecutionEngine.h>
16#include <llvm/ExecutionEngine/MCJIT.h>
17#include "llvm/IR/LegacyPassManager.h"
18
19#include <llvm/IRReader/IRReader.h>
20#include <llvm/Support/CommandLine.h>
21#include <llvm/CodeGen/CommandFlags.h>
22#include <llvm/Support/SourceMgr.h>
23#include <llvm/Support/TargetSelect.h>
24#include <llvm/Support/Host.h>
25#include <llvm/Support/raw_ostream.h>
26
27#include <object_cache.h>
28
29#ifdef CUDA_ENABLED
30#include <IDISA/llvm2ptx.h>
31#endif
32 
33using namespace llvm;
34
35namespace codegen {
36
37static cl::OptionCategory CodeGenOptions("Code Generation Options", "These options control code generation.");
38
39
40static cl::opt<bool> DumpGeneratedIR("dump-generated-IR", cl::init(false), cl::desc("Print LLVM IR generated by Pablo Compiler."), cl::cat(CodeGenOptions));
41static cl::opt<std::string> IROutputFilename("dump-generated-IR-output", cl::init(""), cl::desc("output IR filename"), cl::cat(CodeGenOptions));
42static cl::opt<bool> DumpASM("DumpASM", cl::init(false), cl::desc("Print Assembly Code."), cl::cat(CodeGenOptions));
43static cl::opt<std::string> ASMOutputFilename("asm-output", cl::init(""), cl::desc("output ASM filename"), cl::cat(CodeGenOptions));
44static cl::opt<bool> AsmVerbose("asm-verbose",
45                                cl::desc("Add comments to directives."),
46                                cl::init(true), cl::cat(CodeGenOptions));
47
48char OptLevel;
49static cl::opt<char, true> OptLevelOption("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] (default = '-O1')"), cl::location(OptLevel),
50                              cl::cat(CodeGenOptions), cl::Prefix, cl::ZeroOrMore, cl::init('1'));
51
52
53static cl::opt<bool> EnableObjectCache("enable-object-cache", cl::init(false), cl::desc("Enable object caching"), cl::cat(CodeGenOptions));
54
55static cl::opt<std::string> ObjectCacheDir("object-cache-dir", cl::init(""), cl::desc("Path to the object cache diretory"), cl::cat(CodeGenOptions));
56
57
58int BlockSize;
59int SegmentSize;
60int BufferSegments;
61int ThreadNum;
62
63static cl::opt<int, true> BlockSizeOption("BlockSize", cl::location(BlockSize), cl::init(0), cl::desc("specify a block size (defaults to widest SIMD register width in bits)."), cl::cat(CodeGenOptions));
64static cl::opt<int, true> SegmentSizeOption("segment-size", cl::location(SegmentSize), cl::desc("Segment Size"), cl::value_desc("positive integer"), cl::init(1));
65static cl::opt<int, true> BufferSegmentsOption("buffer-segments", cl::location(BufferSegments), cl::desc("Buffer Segments"), cl::value_desc("positive integer"), cl::init(1));
66static cl::opt<int, true> ThreadNumOption("thread-num", cl::location(ThreadNum), cl::desc("Number of threads used for segment pipeline parallel"), cl::value_desc("positive integer"), cl::init(2));
67
68const cl::OptionCategory * codegen_flags() {return &CodeGenOptions;}
69
70#ifdef CUDA_ENABLED
71bool NVPTX;
72static cl::opt<bool> USENVPTX("NVPTX", cl::desc("Run on GPU only."), cl::init(false));
73#endif
74
75}
76
77
78#ifdef CUDA_ENABLED
79void setNVPTXOption(){
80    codegen::NVPTX = codegen::USENVPTX;
81}
82
83void Compile2PTX (Module * m, std::string IRFilename, std::string PTXFilename) {
84    InitializeAllTargets();
85    InitializeAllTargetMCs();
86    InitializeAllAsmPrinters();
87    InitializeAllAsmParsers();
88
89    PassRegistry *Registry = PassRegistry::getPassRegistry();
90    initializeCore(*Registry);
91    initializeCodeGen(*Registry);
92    initializeLoopStrengthReducePass(*Registry);
93    initializeLowerIntrinsicsPass(*Registry);
94    initializeUnreachableBlockElimPass(*Registry);
95
96    std::error_code error;
97    llvm::raw_fd_ostream out(IRFilename, error, sys::fs::OpenFlags::F_None);
98    m->print(out, nullptr);
99
100    if (LLVM_UNLIKELY(codegen::DumpGeneratedIR))
101            m->dump();
102
103    llvm2ptx(IRFilename, PTXFilename);
104}
105#endif
106
107
108void setAllFeatures(EngineBuilder &builder) {
109    llvm::StringMap<bool> HostCPUFeatures;
110    if (llvm::sys::getHostCPUFeatures(HostCPUFeatures)) {
111        std::vector<std::string> attrs;
112        for (auto &flag : HostCPUFeatures) {
113            auto enabled = flag.second ? "+" : "-";
114            attrs.push_back(enabled + flag.first().str());
115        }
116        builder.setMAttrs(attrs);
117    }
118}
119
120bool AVX2_available() {
121    llvm::StringMap<bool> HostCPUFeatures;
122    if (llvm::sys::getHostCPUFeatures(HostCPUFeatures)) {
123        auto f = HostCPUFeatures.find("avx2");
124        return ((f != HostCPUFeatures.end()) && f->second);
125    }
126    return false;
127}
128
129
130void WriteAssembly (llvm::TargetMachine *TM, Module * m) {
131    llvm::legacy::PassManager PM;
132
133    llvm::SmallString<128> Str;
134    llvm::raw_svector_ostream dest(Str);
135
136    if (TM->addPassesToEmitFile(PM, dest, llvm::TargetMachine::CGFT_AssemblyFile ) ) {
137        throw std::runtime_error("LLVM error: addPassesToEmitFile failed.");
138    }
139    PM.run(*m);
140
141    if (codegen::ASMOutputFilename.empty()) {
142        errs() << Str;
143    } else {
144        std::error_code error;
145        llvm::raw_fd_ostream out(codegen::ASMOutputFilename, error, sys::fs::OpenFlags::F_None);
146        out << Str;
147    }
148}
149
150ExecutionEngine * JIT_to_ExecutionEngine (Module * m) {
151
152    InitializeNativeTarget();
153    InitializeNativeTargetAsmPrinter();
154    InitializeNativeTargetAsmParser();
155
156    PassRegistry * Registry = PassRegistry::getPassRegistry();
157    initializeCore(*Registry);
158    initializeCodeGen(*Registry);
159    initializeLowerIntrinsicsPass(*Registry);
160
161    std::string errMessage;
162    EngineBuilder builder{std::unique_ptr<Module>(m)};
163    builder.setErrorStr(&errMessage);
164    TargetOptions opts = InitTargetOptionsFromCodeGenFlags();
165    opts.MCOptions.AsmVerbose = codegen::AsmVerbose;
166
167    builder.setTargetOptions(opts);
168    builder.setVerifyModules(true);
169    CodeGenOpt::Level optLevel = CodeGenOpt::Level::None;
170    switch (codegen::OptLevel) {
171        case '0': optLevel = CodeGenOpt::None; break;
172        case '1': optLevel = CodeGenOpt::Less; break;
173        case '2': optLevel = CodeGenOpt::Default; break;
174        case '3': optLevel = CodeGenOpt::Aggressive; break;
175        default: errs() << codegen::OptLevel << " is an invalid optimization level.\n";
176    }
177    builder.setOptLevel(optLevel);
178
179    setAllFeatures(builder);
180
181    if (LLVM_UNLIKELY(codegen::DumpGeneratedIR)) {
182        if (codegen::IROutputFilename.empty()) {
183            m->dump();
184        } else {
185            std::error_code error;
186            llvm::raw_fd_ostream out(codegen::IROutputFilename, error, sys::fs::OpenFlags::F_None);
187            m->print(out, nullptr);
188        }
189    }
190
191    if (codegen::DumpASM) {
192      WriteAssembly(builder.selectTarget(), m);
193    }
194    ExecutionEngine * engine = builder.create();
195    if (engine == nullptr) {
196        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
197    }   
198    return engine;
199}
200
201void ApplyObjectCache(ExecutionEngine * e) {
202    ICGrepObjectCache * cache = nullptr;
203    if (codegen::EnableObjectCache) {
204        if (codegen::ObjectCacheDir.empty())
205            // Default is $HOME/.cache/icgrep
206            cache = new ICGrepObjectCache();
207        else
208            cache = new ICGrepObjectCache(codegen::ObjectCacheDir);
209        e->setObjectCache(cache);
210    }   
211}
212
213
Note: See TracBrowser for help on using the repository browser.