From be01f42f73137129f5998e626e0639270066f5c9 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 21 Aug 2021 22:20:32 +0200 Subject: [PATCH 1/4] Enable new pass manager on LLVM 13 The new pass manager is enabled by default in clang since Clang/LLVM 13. While the discussion about this is still ongoing (https://lists.llvm.org/pipermail/llvm-dev/2021-August/152305.html) it's expected that support for the legacy pass manager will be dropped either in LLVM 14 or 15. This switches us to use the new pass manager if LLVM >= 13 is used. --- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 791604a18273d..92199f611bad0 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -370,8 +370,9 @@ fn get_pgo_use_path(config: &ModuleConfig) -> Option { } pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { - // The new pass manager is disabled by default. - config.new_llvm_pass_manager.unwrap_or(false) + // The new pass manager is enabled by default for LLVM >= 13. + // This matches Clang, which also enables it since Clang 13. + config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0)) } pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( From 074bbc6b878f6afc5d6cfd1b5cce1e03588d8184 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 13 Sep 2021 18:18:59 +0200 Subject: [PATCH 2/4] Use correct pipeline for LTO at O0 Unlike the pre-link piplines, the LTO pipelines do support O0, and using them is required to avoid leaving behind undefined references for the linker. --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 1a0cfd5888593..48eb50953a957 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1004,7 +1004,10 @@ LLVMRustOptimizeWithNewPassManager( #endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { - if (OptLevel == OptimizationLevel::O0) { + // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead. + // At the same time, the LTO pipelines do support O0 and using them is required. + bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; + if (OptLevel == OptimizationLevel::O0 && !IsLTO) { #if LLVM_VERSION_GE(12, 0) for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); From 31834434a0bf9c9c98db328c4adc9b356b805dde Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 14 Sep 2021 20:16:22 +0200 Subject: [PATCH 3/4] Make expectation in panic-in-drop-abort.rs test more precise Check whether a call/invoke of the function exists, but don't match a leftover function declaration. Also remove the CHECK-LABELs: In panic-in-drop=unwind mode the call will not actually be in either of those functions, so remove the restriction and look for any calls. --- src/test/codegen/panic-in-drop-abort.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/codegen/panic-in-drop-abort.rs b/src/test/codegen/panic-in-drop-abort.rs index 62d093507ddee..0d19351a33d1f 100644 --- a/src/test/codegen/panic-in-drop-abort.rs +++ b/src/test/codegen/panic-in-drop-abort.rs @@ -3,6 +3,8 @@ // Ensure that unwinding code paths are eliminated from the output after // optimization. +// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output + #![crate_type = "lib"] use std::any::Any; use std::mem::forget; @@ -35,8 +37,6 @@ impl Drop for AssertNeverDrop { } } -// CHECK-LABEL: normal_drop -// CHECK-NOT: should_not_appear_in_output #[no_mangle] pub fn normal_drop(x: ExternDrop) { let guard = AssertNeverDrop; @@ -44,8 +44,6 @@ pub fn normal_drop(x: ExternDrop) { forget(guard); } -// CHECK-LABEL: indirect_drop -// CHECK-NOT: should_not_appear_in_output #[no_mangle] pub fn indirect_drop(x: Box) { let guard = AssertNeverDrop; From 51203dc1c40393b864af70d0bc50b6c4f4ea34e4 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 25 Sep 2021 12:39:20 +0200 Subject: [PATCH 4/4] Pin panic-in-drop=abort test to old pass manager --- src/test/codegen/panic-in-drop-abort.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/codegen/panic-in-drop-abort.rs b/src/test/codegen/panic-in-drop-abort.rs index 0d19351a33d1f..39f73c4e3967e 100644 --- a/src/test/codegen/panic-in-drop-abort.rs +++ b/src/test/codegen/panic-in-drop-abort.rs @@ -1,8 +1,15 @@ -// compile-flags: -Z panic-in-drop=abort -O +// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no // Ensure that unwinding code paths are eliminated from the output after // optimization. +// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen +// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that +// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we +// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC +// targets. We should either forbid longjmps, or not assume nounwind, making this optimization +// incompatible with the current behavior of running cleanuppads on longjmp unwinding. + // CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output #![crate_type = "lib"]