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

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

AVX2 checking via getHostCPUFeatures

File size: 5.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
29using namespace llvm;
30
31namespace codegen {
32
33static cl::OptionCategory CodeGenOptions("Code Generation Options", "These options control code generation.");
34
35
36static cl::opt<bool> DumpGeneratedIR("dump-generated-IR", cl::init(false), cl::desc("Print LLVM IR generated by Pablo Compiler."), cl::cat(CodeGenOptions));
37static cl::opt<std::string> IROutputFilename("dump-generated-IR-output", cl::init(""), cl::desc("output IR filename"), cl::cat(CodeGenOptions));
38static cl::opt<bool> DumpASM("DumpASM", cl::init(false), cl::desc("Print Assembly Code."), cl::cat(CodeGenOptions));
39
40char OptLevel;
41static cl::opt<char, true> OptLevelOption("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] (default = '-O1')"), cl::location(OptLevel),
42                              cl::cat(CodeGenOptions), cl::Prefix, cl::ZeroOrMore, cl::init('1'));
43
44
45static cl::opt<bool> EnableObjectCache("enable-object-cache", cl::init(false), cl::desc("Enable object caching"), cl::cat(CodeGenOptions));
46
47static cl::opt<std::string> ObjectCacheDir("object-cache-dir", cl::init(""), cl::desc("Path to the object cache diretory"), cl::cat(CodeGenOptions));
48
49
50int BlockSize;
51int SegmentSize;
52
53static 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));
54static cl::opt<int, true> SegmentSizeOption("segment-size", cl::location(SegmentSize), cl::desc("Segment Size"), cl::value_desc("positive integer"), cl::init(1));
55
56const cl::OptionCategory * codegen_flags() {return &CodeGenOptions;}
57
58}
59
60
61void setAllFeatures(EngineBuilder &builder) {
62    llvm::StringMap<bool> HostCPUFeatures;
63    if (llvm::sys::getHostCPUFeatures(HostCPUFeatures)) {
64        std::vector<std::string> attrs;
65        for (auto &flag : HostCPUFeatures) {
66            auto enabled = flag.second ? "+" : "-";
67            attrs.push_back(enabled + flag.first().str());
68        }
69        builder.setMAttrs(attrs);
70    }
71}
72
73bool AVX2_available() {
74    llvm::StringMap<bool> HostCPUFeatures;
75    if (llvm::sys::getHostCPUFeatures(HostCPUFeatures)) {
76        auto f = HostCPUFeatures.find("avx2");
77        return ((f != HostCPUFeatures.end()) && f->second);
78    }
79    return false;
80}
81
82
83void WriteAssembly (llvm::TargetMachine *TM, Module * m) {
84    llvm::legacy::PassManager PM;
85
86    llvm::SmallString<128> Str;
87    llvm::raw_svector_ostream dest(Str); 
88
89    if (TM->addPassesToEmitFile( PM , dest , llvm::TargetMachine::CGFT_AssemblyFile ) ) {
90      std::cout << "addPassesToEmitFile failed\n";
91      exit(1);
92    }
93    PM.run(*m);
94    std::cerr << std::string( Str.c_str() ) << "\n";
95}
96
97ExecutionEngine * JIT_to_ExecutionEngine (Module * m) {
98
99    InitializeNativeTarget();
100    InitializeNativeTargetAsmPrinter();
101    InitializeNativeTargetAsmParser();
102
103    PassRegistry * Registry = PassRegistry::getPassRegistry();
104    initializeCore(*Registry);
105    initializeCodeGen(*Registry);
106    initializeLowerIntrinsicsPass(*Registry);
107
108    std::string errMessage;
109    EngineBuilder builder{std::unique_ptr<Module>(m)};
110    builder.setErrorStr(&errMessage);
111    TargetOptions opts = InitTargetOptionsFromCodeGenFlags();
112    builder.setTargetOptions(opts);
113    CodeGenOpt::Level optLevel = CodeGenOpt::Level::None;
114    switch (codegen::OptLevel) {
115        case '0': optLevel = CodeGenOpt::None; break;
116        case '1': optLevel = CodeGenOpt::Less; break;
117        case '2': optLevel = CodeGenOpt::Default; break;
118        case '3': optLevel = CodeGenOpt::Aggressive; break;
119        default: errs() << codegen::OptLevel << " is an invalid optimization level.\n";
120    }
121    builder.setOptLevel(optLevel);
122
123    setAllFeatures(builder);
124
125    if (LLVM_UNLIKELY(codegen::DumpGeneratedIR)) {
126        if (codegen::IROutputFilename.empty()) {
127            m->dump();
128        } else {
129            std::error_code error;
130            llvm::raw_fd_ostream out(codegen::IROutputFilename, error, sys::fs::OpenFlags::F_None);
131            m->print(out, nullptr);
132        }
133    }
134
135    if (codegen::DumpASM) {
136      WriteAssembly(builder.selectTarget(), m);
137    }
138    ExecutionEngine * engine = builder.create();
139    if (engine == nullptr) {
140        throw std::runtime_error("Could not create ExecutionEngine: " + errMessage);
141    }   
142    return engine;
143}
144
145void ApplyObjectCache(ExecutionEngine * e) {
146    ICGrepObjectCache * cache = nullptr;
147    if (codegen::EnableObjectCache) {
148        if (codegen::ObjectCacheDir.empty())
149            // Default is $HOME/.cache/icgrep
150            cache = new ICGrepObjectCache();
151        else
152            cache = new ICGrepObjectCache(codegen::ObjectCacheDir);
153        e->setObjectCache(cache);
154    }   
155}
156
157
Note: See TracBrowser for help on using the repository browser.