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

Last change on this file since 5239 was 5238, checked in by cameron, 3 years ago

IR_Gen subdirectory for all IR generation utility functions

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