authorgravatar for minyihh@uci.eduMin-Yih Hsu <minyihh@uci.edu> 2021-03-29 18:13:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-02 12:04:49-07:00
log0d53a2bff01750f9220bcc861d662b2c5f304506
tree9cb3a287166c1f88c595dca6b4842b3d101b897d
parentb85ef2300fa72f5f4c73b8eb9e14f0218ada592d

llvm new-pm: Port LLVM 11.x-based changes to LLVM 12.x

Now zig will use new PM for optimization by default.

1 files changed, 112 insertions(+), 93 deletions(-)

src/zig_llvm.cpp+112-93
...@@ -20,6 +20,7 @@...@@ -20,6 +20,7 @@
20#pragma GCC diagnostic ignored "-Winit-list-lifetime"20#pragma GCC diagnostic ignored "-Winit-list-lifetime"
21#endif21#endif
2222
23#include <llvm/Analysis/AliasAnalysis.h>
23#include <llvm/Analysis/TargetLibraryInfo.h>24#include <llvm/Analysis/TargetLibraryInfo.h>
24#include <llvm/Analysis/TargetTransformInfo.h>25#include <llvm/Analysis/TargetTransformInfo.h>
25#include <llvm/Bitcode/BitcodeWriter.h>26#include <llvm/Bitcode/BitcodeWriter.h>
...@@ -30,9 +31,12 @@...@@ -30,9 +31,12 @@
30#include <llvm/IR/Instructions.h>31#include <llvm/IR/Instructions.h>
31#include <llvm/IR/LegacyPassManager.h>32#include <llvm/IR/LegacyPassManager.h>
32#include <llvm/IR/Module.h>33#include <llvm/IR/Module.h>
34#include <llvm/IR/PassManager.h>
33#include <llvm/IR/Verifier.h>35#include <llvm/IR/Verifier.h>
34#include <llvm/InitializePasses.h>36#include <llvm/InitializePasses.h>
35#include <llvm/MC/SubtargetFeature.h>37#include <llvm/MC/SubtargetFeature.h>
38#include <llvm/Passes/PassBuilder.h>
39#include <llvm/Passes/StandardInstrumentations.h>
36#include <llvm/Object/Archive.h>40#include <llvm/Object/Archive.h>
37#include <llvm/Object/ArchiveWriter.h>41#include <llvm/Object/ArchiveWriter.h>
38#include <llvm/Object/COFF.h>42#include <llvm/Object/COFF.h>
...@@ -54,6 +58,9 @@...@@ -54,6 +58,9 @@
54#include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>58#include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
55#include <llvm/Transforms/Scalar.h>59#include <llvm/Transforms/Scalar.h>
56#include <llvm/Transforms/Utils.h>60#include <llvm/Transforms/Utils.h>
61#include <llvm/Transforms/Utils/AddDiscriminators.h>
62#include <llvm/Transforms/Utils/CanonicalizeAliases.h>
63#include <llvm/Transforms/Utils/NameAnonGlobals.h>
5764
58#include <lld/Common/Driver.h>65#include <lld/Common/Driver.h>
5966
...@@ -190,12 +197,12 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -190,12 +197,12 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
190{197{
191 TimePassesIsEnabled = time_report;198 TimePassesIsEnabled = time_report;
192199
193 raw_fd_ostream *dest_asm = nullptr;200 raw_fd_ostream *dest_asm_ptr = nullptr;
194 raw_fd_ostream *dest_bin = nullptr;201 raw_fd_ostream *dest_bin_ptr = nullptr;
195202
196 if (asm_filename) {203 if (asm_filename) {
197 std::error_code EC;204 std::error_code EC;
198 dest_asm = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None);205 dest_asm_ptr = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None);
199 if (EC) {206 if (EC) {
200 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());207 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
201 return true;208 return true;
...@@ -203,116 +210,128 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -203,116 +210,128 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
203 }210 }
204 if (bin_filename) {211 if (bin_filename) {
205 std::error_code EC;212 std::error_code EC;
206 dest_bin = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None);213 dest_bin_ptr = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None);
207 if (EC) {214 if (EC) {
208 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());215 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
209 return true;216 return true;
210 }217 }
211 }218 }
212219
213 TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref);220 std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),
214 target_machine->setO0WantsFastISel(true);221 dest_bin(dest_bin_ptr);
215222
216 Module* module = unwrap(module_ref);223 TargetMachine &target_machine = *reinterpret_cast<TargetMachine*>(targ_machine_ref);
217224 target_machine.setO0WantsFastISel(true);
218 PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder();225
219 if (PMBuilder == nullptr) {226 Module &module = *unwrap(module_ref);
220 *error_message = strdup("memory allocation failure");227
221 return true;228 PipelineTuningOptions pipeline_opts;
222 }229 pipeline_opts.LoopUnrolling = !is_debug;
223 PMBuilder->OptLevel = target_machine->getOptLevel();230 pipeline_opts.SLPVectorization = !is_debug;
224 PMBuilder->SizeLevel = is_small ? 2 : 0;231 pipeline_opts.LoopVectorization = !is_debug;
225232 pipeline_opts.LoopInterleaving = !is_debug;
226 PMBuilder->DisableTailCalls = is_debug;233
227 PMBuilder->DisableUnrollLoops = is_debug;234 PassInstrumentationCallbacks instr_callbacks;
228 PMBuilder->SLPVectorize = !is_debug;235 StandardInstrumentations std_instrumentations(false);
229 PMBuilder->LoopVectorize = !is_debug;236 std_instrumentations.registerCallbacks(instr_callbacks);
230 PMBuilder->LoopsInterleaved = !PMBuilder->DisableUnrollLoops;237
231 PMBuilder->RerollLoops = !is_debug;238 PassBuilder pass_builder(false, &target_machine, pipeline_opts,
232 // Leaving NewGVN as default (off) because when on it caused issue #673239 None, &instr_callbacks);
233 //PMBuilder->NewGVN = !is_debug;240 using OptimizationLevel = typename PassBuilder::OptimizationLevel;
234 PMBuilder->DisableGVNLoadPRE = is_debug;241
235 PMBuilder->VerifyInput = assertions_on;242 LoopAnalysisManager loop_am;
236 PMBuilder->VerifyOutput = assertions_on;243 FunctionAnalysisManager function_am;
237 PMBuilder->MergeFunctions = !is_debug;244 CGSCCAnalysisManager cgscc_am;
238 PMBuilder->PrepareForLTO = lto;245 ModuleAnalysisManager module_am;
239 PMBuilder->PrepareForThinLTO = false;246
240 PMBuilder->PerformThinLTO = false;247 // Register the AA manager first so that our version is the one used
241248 function_am.registerPass([&] {
242 TargetLibraryInfoImpl tlii(Triple(module->getTargetTriple()));249 return pass_builder.buildDefaultAAPipeline();
243 PMBuilder->LibraryInfo = &tlii;250 });
244251
245 if (is_debug) {252 Triple target_triple(module.getTargetTriple());
246 PMBuilder->Inliner = createAlwaysInlinerLegacyPass(false);253 auto tlii = std::make_unique<TargetLibraryInfoImpl>(target_triple);
247 } else {254 function_am.registerPass([&] { return TargetLibraryAnalysis(*tlii); });
248 target_machine->adjustPassManager(*PMBuilder);255
249256 pass_builder.registerModuleAnalyses(module_am);
250 PMBuilder->addExtension(PassManagerBuilder::EP_EarlyAsPossible, addDiscriminatorsPass);257 pass_builder.registerCGSCCAnalyses(cgscc_am);
251 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);258 pass_builder.registerFunctionAnalyses(function_am);
259 pass_builder.registerLoopAnalyses(loop_am);
260 pass_builder.crossRegisterProxies(loop_am, function_am,
261 cgscc_am, module_am);
262
263 if (!is_debug) {
264 pass_builder.registerPipelineStartEPCallback(
265 [](ModulePassManager &module_pm, OptimizationLevel OL) {
266 module_pm.addPass(
267 createModuleToFunctionPassAdaptor(AddDiscriminatorsPass()));
268 });
252 }269 }
253270
254 if (tsan) {271 if (tsan) {
255 PMBuilder->addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass);272 pass_builder.registerOptimizerLastEPCallback(
256 PMBuilder->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addThreadSanitizerPass);273 [](ModulePassManager &module_pm, OptimizationLevel level) {
274 // Will be enabled regardless of optimization level
275 module_pm.addPass(ThreadSanitizerPass());
276 });
257 }277 }
258278
259 // Set up the per-function pass manager.279 ModulePassManager module_pm;
260 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);280 // FIXME: NewPM can not detach speed level from size level
261 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);281 // we can't create something like "maximum speed level and optimal size level"
262 FPM.add(tliwp);282 // which is what the original code wanted to achieve
263 FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));283 OptimizationLevel opt_level;
264 if (assertions_on) {284 if (is_debug)
265 FPM.add(createVerifierPass());285 opt_level = OptimizationLevel::O0;
286 else if (is_small)
287 opt_level = OptimizationLevel::Oz;
288 else
289 opt_level = OptimizationLevel::O3;
290
291 if (lto) {
292 module_pm = pass_builder.buildLTOPreLinkDefaultPipeline(opt_level);
293 module_pm.addPass(CanonicalizeAliasesPass());
294 module_pm.addPass(NameAnonGlobalPass());
295 } else {
296 module_pm = pass_builder.buildPerModuleDefaultPipeline(opt_level);
266 }297 }
267 PMBuilder->populateFunctionPassManager(FPM);
268
269 {
270 // Set up the per-module pass manager.
271 legacy::PassManager MPM;
272 MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
273 PMBuilder->populateModulePassManager(MPM);
274
275 // Set output passes.
276 if (dest_bin && !lto) {
277 if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) {
278 *error_message = strdup("TargetMachine can't emit an object file");
279 return true;
280 }
281 }
282 if (dest_asm) {
283 if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) {
284 *error_message = strdup("TargetMachine can't emit an assembly file");
285 return true;
286 }
287 }
288
289 // run per function optimization passes
290 FPM.doInitialization();
291 for (Function &F : *module)
292 if (!F.isDeclaration())
293 FPM.run(F);
294 FPM.doFinalization();
295298
296 MPM.run(*module);299 // Unfortunately we don't have new PM for code generation
300 legacy::PassManager codegen_pm;
301 codegen_pm.add(
302 createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis()));
297303
298 if (llvm_ir_filename) {304 if (dest_bin && !lto) {
299 if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {305 if (target_machine.addPassesToEmitFile(codegen_pm, *dest_bin, nullptr, CGFT_ObjectFile)) {
300 return true;306 *error_message = strdup("TargetMachine can't emit an object file");
301 }307 return true;
302 }308 }
303 if (dest_bin && lto) {309 }
304 WriteBitcodeToFile(*module, *dest_bin);310 if (dest_asm) {
311 if (target_machine.addPassesToEmitFile(codegen_pm, *dest_asm, nullptr, CGFT_AssemblyFile)) {
312 *error_message = strdup("TargetMachine can't emit an assembly file");
313 return true;
305 }314 }
315 }
306316
307 if (time_report) {317 // optimization
308 TimerGroup::printAll(errs());318 module_pm.run(module, module_am);
309 }
310319
311 // MPM goes out of scope and writes to the out streams320 // code generation
321 codegen_pm.run(module);
322
323 if (llvm_ir_filename) {
324 if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) {
325 return true;
326 }
327 }
328 if (dest_bin && lto) {
329 WriteBitcodeToFile(module, *dest_bin);
312 }330 }
313331
314 delete dest_asm;332 if (time_report) {
315 delete dest_bin;333 TimerGroup::printAll(errs());
334 }
316335
317 return false;336 return false;
318}337}