Proteus
Programmable JIT compilation and optimization for C/C++ using LLVM
Loading...
Searching...
No Matches
CoreLLVM.hpp
Go to the documentation of this file.
1#ifndef PROTEUS_CORE_LLVM_HPP
2#define PROTEUS_CORE_LLVM_HPP
3
4static_assert(__cplusplus >= 201703L,
5 "This header requires C++17 or later due to LLVM.");
6
7#include <llvm/CodeGen/CommandFlags.h>
8#include <llvm/IR/DebugInfo.h>
9#include <llvm/IR/Module.h>
10#include <llvm/IR/PassManager.h>
11#include <llvm/Linker/Linker.h>
12#include <llvm/MC/TargetRegistry.h>
13#include <llvm/Passes/PassBuilder.h>
14#include <llvm/Support/TargetSelect.h>
15#include <llvm/Target/TargetMachine.h>
16
17#if LLVM_VERSION_MAJOR == 18
18#include <llvm/TargetParser/SubtargetFeature.h>
19// This convoluted logic below is because AMD ROCm 5.7.1 identifies as LLVM 17
20// but includes the header SubtargetFeature.h to a different directory than
21// upstream LLVM 17. We basically detect if it's the HIP version and include it
22// from the expected MC directory, otherwise from TargetParser.
23#elif LLVM_VERSION_MAJOR == 17
24#if defined(__HIP_PLATFORM_HCC__) || defined(HIP_VERSION_MAJOR)
25#include <llvm/MC/SubtargetFeature.h>
26#else
27#include <llvm/TargetParser/SubtargetFeature.h>
28#endif
29#else
30#define STRINGIFY_HELPER(x) #x
31#define STRINGIFY(x) STRINGIFY_HELPER(x)
32#error "Unsupported LLVM version " STRINGIFY(LLVM_VERSION)
33#endif
34#include <llvm/Transforms/IPO/GlobalDCE.h>
35#include <llvm/Transforms/IPO/Internalize.h>
36#include <llvm/Transforms/IPO/StripDeadPrototypes.h>
37#include <llvm/Transforms/IPO/StripSymbols.h>
38#include <llvm/Transforms/Utils/ModuleUtils.h>
39
40#include "proteus/Error.h"
41
42namespace proteus {
43using namespace llvm;
44
45namespace detail {
46
47inline Expected<std::unique_ptr<TargetMachine>>
48createTargetMachine(Module &M, StringRef Arch, unsigned OptLevel = 3) {
49 Triple TT(M.getTargetTriple());
50 auto CGOptLevel = CodeGenOpt::getLevel(OptLevel);
51 if (CGOptLevel == std::nullopt)
52 PROTEUS_FATAL_ERROR("Invalid opt level");
53
54 std::string Msg;
55 const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
56 if (!T)
57 return make_error<StringError>(Msg, inconvertibleErrorCode());
58
59 SubtargetFeatures Features;
60 Features.getDefaultSubtargetFeatures(TT);
61
62 std::optional<Reloc::Model> RelocModel;
63 if (M.getModuleFlag("PIC Level"))
64 RelocModel =
65 M.getPICLevel() == PICLevel::NotPIC ? Reloc::Static : Reloc::PIC_;
66
67 std::optional<CodeModel::Model> CodeModel = M.getCodeModel();
68
69 // Use default target options.
70 // TODO: Customize based on AOT compilation flags or by creating a
71 // constructor that sets target options based on the triple.
72 TargetOptions Options;
73 std::unique_ptr<TargetMachine> TM(T->createTargetMachine(
74 M.getTargetTriple(), Arch, Features.getString(), Options, RelocModel,
75 CodeModel, CGOptLevel.value()));
76 if (!TM)
77 return make_error<StringError>("Failed to create target machine",
78 inconvertibleErrorCode());
79 return TM;
80}
81
82inline void runOptimizationPassPipeline(Module &M, StringRef Arch,
83 char OptLevel = '3',
84 unsigned CodegenOptLevel = 3) {
85 PipelineTuningOptions PTO;
86
87 std::optional<PGOOptions> PGOOpt;
88 auto TM = createTargetMachine(M, Arch, CodegenOptLevel);
89 if (auto Err = TM.takeError())
90 report_fatal_error(std::move(Err));
91 TargetLibraryInfoImpl TLII(Triple(M.getTargetTriple()));
92
93 PassBuilder PB(TM->get(), PTO, PGOOpt, nullptr);
94 LoopAnalysisManager LAM;
95 FunctionAnalysisManager FAM;
96 CGSCCAnalysisManager CGAM;
97 ModuleAnalysisManager MAM;
98
99 FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
100
101 PB.registerModuleAnalyses(MAM);
102 PB.registerCGSCCAnalyses(CGAM);
103 PB.registerFunctionAnalyses(FAM);
104 PB.registerLoopAnalyses(LAM);
105 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
106
107 OptimizationLevel OptSetting;
108 switch (OptLevel) {
109 case '0':
110 OptSetting = OptimizationLevel::O0;
111 break;
112 case '1':
113 OptSetting = OptimizationLevel::O1;
114 break;
115 case '2':
116 OptSetting = OptimizationLevel::O2;
117 break;
118 case '3':
119 OptSetting = OptimizationLevel::O3;
120 break;
121 case 's':
122 OptSetting = OptimizationLevel::Os;
123 break;
124 case 'z':
125 OptSetting = OptimizationLevel::Oz;
126 break;
127 default:
128 PROTEUS_FATAL_ERROR("Unsupported optimization level " + OptLevel);
129 };
130
131 ModulePassManager Passes = PB.buildPerModuleDefaultPipeline(OptSetting);
132 Passes.run(M, MAM);
133}
134
135} // namespace detail
136
139 InitializeAllTargetInfos();
140 InitializeAllTargets();
141 InitializeAllTargetMCs();
142 InitializeAllAsmParsers();
143 InitializeAllAsmPrinters();
144 }
145};
146
147inline void optimizeIR(Module &M, StringRef Arch, char OptLevel,
148 unsigned CodegenOptLevel) {
149 detail::runOptimizationPassPipeline(M, Arch, OptLevel, CodegenOptLevel);
150}
151
152inline std::unique_ptr<Module>
153linkModules(LLVMContext &Ctx,
154 SmallVector<std::unique_ptr<Module>> &LinkedModules) {
155 if (LinkedModules.empty())
156 PROTEUS_FATAL_ERROR("Expected jit module");
157
158 auto LinkedModule = std::make_unique<llvm::Module>("JitModule", Ctx);
159 Linker IRLinker(*LinkedModule);
160 // Link in all the proteus-enabled extracted modules.
161 for (auto &LinkedM : LinkedModules) {
162 // Returns true if linking failed.
163 if (IRLinker.linkInModule(std::move(LinkedM)))
164 PROTEUS_FATAL_ERROR("Linking failed");
165 }
166
167 return LinkedModule;
168}
169
170inline void runCleanupPassPipeline(Module &M) {
171 PassBuilder PB;
172 LoopAnalysisManager LAM;
173 FunctionAnalysisManager FAM;
174 CGSCCAnalysisManager CGAM;
175 ModuleAnalysisManager MAM;
176
177 PB.registerModuleAnalyses(MAM);
178 PB.registerCGSCCAnalyses(CGAM);
179 PB.registerFunctionAnalyses(FAM);
180 PB.registerLoopAnalyses(LAM);
181 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
182
183 ModulePassManager Passes;
184 Passes.addPass(GlobalDCEPass());
185 // Passes.addPass(StripDeadDebugInfoPass());
186 Passes.addPass(StripDeadPrototypesPass());
187
188 Passes.run(M, MAM);
189
190 StripDebugInfo(M);
191}
192
193inline void pruneIR(Module &M, bool UnsetExternallyInitialized = true) {
194 // Remove llvm.global.annotations now that we have read them.
195 if (auto *GlobalAnnotations = M.getGlobalVariable("llvm.global.annotations"))
196 M.eraseGlobalVariable(GlobalAnnotations);
197
198 // Remove llvm.compiler.used
199 if (auto *CompilerUsed = M.getGlobalVariable("llvm.compiler.used"))
200 M.eraseGlobalVariable(CompilerUsed);
201
202 // Remove the __clang_gpu_used_external used in HIP RDC compilation and its
203 // uses in llvm.used, llvm.compiler.used.
204 SmallVector<GlobalVariable *> GlobalsToErase;
205 for (auto &GV : M.globals()) {
206 auto Name = GV.getName();
207 if (Name.starts_with("__clang_gpu_used_external") ||
208 Name.starts_with("_jit_bitcode") || Name.starts_with("__hip_cuid")) {
209 GlobalsToErase.push_back(&GV);
210 removeFromUsedLists(M, [&GV](Constant *C) {
211 if (auto *Global = dyn_cast<GlobalVariable>(C))
212 return Global == &GV;
213 return false;
214 });
215 }
216 }
217 for (auto *GV : GlobalsToErase) {
218 M.eraseGlobalVariable(GV);
219 }
220
221 // Remove externaly_initialized attributes.
222 if (UnsetExternallyInitialized)
223 for (auto &GV : M.globals())
224 if (GV.isExternallyInitialized())
225 GV.setExternallyInitialized(false);
226}
227
228inline void internalize(Module &M, StringRef PreserveFunctionName) {
229 auto *F = M.getFunction(PreserveFunctionName);
230 // Internalize others besides the kernel function.
231 internalizeModule(M, [&F](const GlobalValue &GV) {
232 // Do not internalize the kernel function.
233 if (&GV == F)
234 return true;
235
236 // Internalize everything else.
237 return false;
238 });
239}
240
241} // namespace proteus
242
244
245#endif
#define PROTEUS_FATAL_ERROR(x)
Definition Error.h:4
Expected< std::unique_ptr< TargetMachine > > createTargetMachine(Module &M, StringRef Arch, unsigned OptLevel=3)
Definition CoreLLVM.hpp:48
void runOptimizationPassPipeline(Module &M, StringRef Arch, char OptLevel='3', unsigned CodegenOptLevel=3)
Definition CoreLLVM.hpp:82
Definition JitEngine.cpp:20
std::unique_ptr< Module > linkModules(LLVMContext &Ctx, SmallVector< std::unique_ptr< Module > > &LinkedModules)
Definition CoreLLVM.hpp:153
void optimizeIR(Module &M, StringRef Arch, char OptLevel, unsigned CodegenOptLevel)
Definition CoreLLVM.hpp:147
void pruneIR(Module &M, bool UnsetExternallyInitialized=true)
Definition CoreLLVM.hpp:193
void internalize(Module &M, StringRef PreserveFunctionName)
Definition CoreLLVM.hpp:228
void runCleanupPassPipeline(Module &M)
Definition CoreLLVM.hpp:170
Definition CoreLLVM.hpp:137
InitLLVMTargets()
Definition CoreLLVM.hpp:138