Skip to content

Commit 433f1f4

Browse files
authored
Rollup merge of #96215 - nikic:legacy-pm-removal, r=nagisa
Drop support for legacy PM with LLVM 15 LLVM 15 already removes some of the legacy PM APIs we're using. This patch forces use of NewPM with LLVM 15 (with `-Z new-llvm-pass-manager=no` throwing a warning) and stubs out various FFI methods with a report_fatal_error on LLVM 15. For LLVMPassManagerBuilderPopulateLTOPassManager() I went with adding our own wrapper, as the alternative would be to muck about with weak symbols, which seems to be non-trivial as far as cross-platform support is concerned (std has `weak!` for this purpose, but only as an internal utility.) Fixes #96072. Fixes #96362.
2 parents 50294f6 + 6dc0bcc commit 433f1f4

File tree

7 files changed

+131
-32
lines changed

7 files changed

+131
-32
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ pub(crate) fn run_pass_manager(
625625
if thin {
626626
llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
627627
} else {
628-
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(
628+
llvm::LLVMRustPassManagerBuilderPopulateLTOPassManager(
629629
b, pm, /* Internalize = */ False, /* RunInliner = */ True,
630630
);
631631
}

compiler/rustc_codegen_llvm/src/back/write.rs

+16-15
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,12 @@ pub(crate) unsafe fn optimize(
523523
let module_name = module.name.clone();
524524
let module_name = Some(&module_name[..]);
525525

526+
if let Some(false) = config.new_llvm_pass_manager && llvm_util::get_version() >= (15, 0, 0) {
527+
diag_handler.warn(
528+
"ignoring `-Z new-llvm-pass-manager=no`, which is no longer supported with LLVM 15",
529+
);
530+
}
531+
526532
if config.emit_no_opt_bc {
527533
let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
528534
let out = path_to_c_string(&out);
@@ -628,8 +634,8 @@ pub(crate) unsafe fn optimize(
628634
extra_passes.as_ptr(),
629635
extra_passes.len() as size_t,
630636
);
631-
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
632-
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
637+
llvm::LLVMRustPassManagerBuilderPopulateFunctionPassManager(b, fpm);
638+
llvm::LLVMRustPassManagerBuilderPopulateModulePassManager(b, mpm);
633639
});
634640

635641
have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto;
@@ -1085,7 +1091,7 @@ pub unsafe fn with_llvm_pmb(
10851091
// Create the PassManagerBuilder for LLVM. We configure it with
10861092
// reasonable defaults and prepare it to actually populate the pass
10871093
// manager.
1088-
let builder = llvm::LLVMPassManagerBuilderCreate();
1094+
let builder = llvm::LLVMRustPassManagerBuilderCreate();
10891095
let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1);
10901096
let inline_threshold = config.inline_threshold;
10911097
let pgo_gen_path = get_pgo_gen_path(config);
@@ -1102,14 +1108,9 @@ pub unsafe fn with_llvm_pmb(
11021108
pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
11031109
pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
11041110
pgo_sample_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
1111+
opt_size as c_int,
11051112
);
11061113

1107-
llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
1108-
1109-
if opt_size != llvm::CodeGenOptSizeNone {
1110-
llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
1111-
}
1112-
11131114
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
11141115

11151116
// Here we match what clang does (kinda). For O0 we only inline
@@ -1118,16 +1119,16 @@ pub unsafe fn with_llvm_pmb(
11181119
// thresholds copied from clang.
11191120
match (opt_level, opt_size, inline_threshold) {
11201121
(.., Some(t)) => {
1121-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t);
1122+
llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, t);
11221123
}
11231124
(llvm::CodeGenOptLevel::Aggressive, ..) => {
1124-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
1125+
llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 275);
11251126
}
11261127
(_, llvm::CodeGenOptSizeDefault, _) => {
1127-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
1128+
llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 75);
11281129
}
11291130
(_, llvm::CodeGenOptSizeAggressive, _) => {
1130-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
1131+
llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 25);
11311132
}
11321133
(llvm::CodeGenOptLevel::None, ..) => {
11331134
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
@@ -1136,12 +1137,12 @@ pub unsafe fn with_llvm_pmb(
11361137
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
11371138
}
11381139
(llvm::CodeGenOptLevel::Default, ..) => {
1139-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
1140+
llvm::LLVMRustPassManagerBuilderUseInlinerWithThreshold(builder, 225);
11401141
}
11411142
}
11421143

11431144
f(builder);
1144-
llvm::LLVMPassManagerBuilderDispose(builder);
1145+
llvm::LLVMRustPassManagerBuilderDispose(builder);
11451146
}
11461147

11471148
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -1825,24 +1825,22 @@ extern "C" {
18251825

18261826
pub fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>);
18271827

1828-
pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
1829-
pub fn LLVMPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
1830-
pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: &PassManagerBuilder, Value: Bool);
1831-
pub fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: &PassManagerBuilder, Value: Bool);
1832-
pub fn LLVMPassManagerBuilderUseInlinerWithThreshold(
1828+
pub fn LLVMRustPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
1829+
pub fn LLVMRustPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
1830+
pub fn LLVMRustPassManagerBuilderUseInlinerWithThreshold(
18331831
PMB: &PassManagerBuilder,
18341832
threshold: c_uint,
18351833
);
1836-
pub fn LLVMPassManagerBuilderPopulateModulePassManager(
1834+
pub fn LLVMRustPassManagerBuilderPopulateModulePassManager(
18371835
PMB: &PassManagerBuilder,
18381836
PM: &PassManager<'_>,
18391837
);
18401838

1841-
pub fn LLVMPassManagerBuilderPopulateFunctionPassManager(
1839+
pub fn LLVMRustPassManagerBuilderPopulateFunctionPassManager(
18421840
PMB: &PassManagerBuilder,
18431841
PM: &PassManager<'_>,
18441842
);
1845-
pub fn LLVMPassManagerBuilderPopulateLTOPassManager(
1843+
pub fn LLVMRustPassManagerBuilderPopulateLTOPassManager(
18461844
PMB: &PassManagerBuilder,
18471845
PM: &PassManager<'_>,
18481846
Internalize: Bool,
@@ -2308,6 +2306,7 @@ extern "C" {
23082306
PGOGenPath: *const c_char,
23092307
PGOUsePath: *const c_char,
23102308
PGOSampleUsePath: *const c_char,
2309+
SizeLevel: c_int,
23112310
);
23122311
pub fn LLVMRustAddLibraryInfo<'a>(
23132312
PM: &PassManager<'a>,

compiler/rustc_codegen_llvm/src/llvm_util.rs

+5
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,11 @@ pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_a
542542
// The new pass manager is enabled by default for LLVM >= 13.
543543
// This matches Clang, which also enables it since Clang 13.
544544

545+
// Since LLVM 15, the legacy pass manager is no longer supported.
546+
if llvm_util::get_version() >= (15, 0, 0) {
547+
return true;
548+
}
549+
545550
// There are some perf issues with the new pass manager when targeting
546551
// s390x with LLVM 13, so enable the new pass manager only with LLVM 14.
547552
// See https://github.com/rust-lang/rust/issues/89609.

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+96-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ static LLVMRustPassKind toRust(PassKind Kind) {
107107
}
108108

109109
extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
110+
#if LLVM_VERSION_LT(15, 0)
110111
StringRef SR(PassName);
111112
PassRegistry *PR = PassRegistry::getPassRegistry();
112113

@@ -115,36 +116,59 @@ extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
115116
return wrap(PI->createPass());
116117
}
117118
return nullptr;
119+
#else
120+
report_fatal_error("Legacy PM not supported with LLVM 15");
121+
#endif
118122
}
119123

120124
extern "C" LLVMPassRef LLVMRustCreateAddressSanitizerFunctionPass(bool Recover) {
125+
#if LLVM_VERSION_LT(15, 0)
121126
const bool CompileKernel = false;
122127
const bool UseAfterScope = true;
123128

124129
return wrap(createAddressSanitizerFunctionPass(CompileKernel, Recover, UseAfterScope));
130+
#else
131+
report_fatal_error("Legacy PM not supported with LLVM 15");
132+
#endif
125133
}
126134

127135
extern "C" LLVMPassRef LLVMRustCreateModuleAddressSanitizerPass(bool Recover) {
136+
#if LLVM_VERSION_LT(15, 0)
128137
const bool CompileKernel = false;
129138

130139
return wrap(createModuleAddressSanitizerLegacyPassPass(CompileKernel, Recover));
140+
#else
141+
report_fatal_error("Legacy PM not supported with LLVM 15");
142+
#endif
131143
}
132144

133145
extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool Recover) {
146+
#if LLVM_VERSION_LT(15, 0)
134147
const bool CompileKernel = false;
135148

136149
return wrap(createMemorySanitizerLegacyPassPass(
137150
MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}));
151+
#else
152+
report_fatal_error("Legacy PM not supported with LLVM 15");
153+
#endif
138154
}
139155

140156
extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
157+
#if LLVM_VERSION_LT(15, 0)
141158
return wrap(createThreadSanitizerLegacyPassPass());
159+
#else
160+
report_fatal_error("Legacy PM not supported with LLVM 15");
161+
#endif
142162
}
143163

144164
extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
165+
#if LLVM_VERSION_LT(15, 0)
145166
const bool CompileKernel = false;
146167

147168
return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
169+
#else
170+
report_fatal_error("Legacy PM not supported with LLVM 15");
171+
#endif
148172
}
149173

150174
extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
@@ -154,23 +178,84 @@ extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
154178
}
155179

156180
extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
181+
#if LLVM_VERSION_LT(15, 0)
157182
assert(RustPass);
158183
Pass *Pass = unwrap(RustPass);
159184
PassManagerBase *PMB = unwrap(PMR);
160185
PMB->add(Pass);
186+
#else
187+
report_fatal_error("Legacy PM not supported with LLVM 15");
188+
#endif
189+
}
190+
191+
extern "C" LLVMPassManagerBuilderRef LLVMRustPassManagerBuilderCreate() {
192+
#if LLVM_VERSION_LT(15, 0)
193+
return LLVMPassManagerBuilderCreate();
194+
#else
195+
report_fatal_error("Legacy PM not supported with LLVM 15");
196+
#endif
197+
}
198+
199+
extern "C" void LLVMRustPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB) {
200+
#if LLVM_VERSION_LT(15, 0)
201+
LLVMPassManagerBuilderDispose(PMB);
202+
#else
203+
report_fatal_error("Legacy PM not supported with LLVM 15");
204+
#endif
205+
}
206+
207+
extern "C" void LLVMRustPassManagerBuilderPopulateFunctionPassManager(
208+
LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
209+
#if LLVM_VERSION_LT(15, 0)
210+
LLVMPassManagerBuilderPopulateFunctionPassManager(PMB, PM);
211+
#else
212+
report_fatal_error("Legacy PM not supported with LLVM 15");
213+
#endif
214+
}
215+
216+
extern "C" void LLVMRustPassManagerBuilderPopulateModulePassManager(
217+
LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM) {
218+
#if LLVM_VERSION_LT(15, 0)
219+
LLVMPassManagerBuilderPopulateModulePassManager(PMB, PM);
220+
#else
221+
report_fatal_error("Legacy PM not supported with LLVM 15");
222+
#endif
223+
}
224+
225+
extern "C" void LLVMRustPassManagerBuilderPopulateLTOPassManager(
226+
LLVMPassManagerBuilderRef PMB, LLVMPassManagerRef PM, bool Internalize, bool RunInliner) {
227+
#if LLVM_VERSION_LT(15, 0)
228+
LLVMPassManagerBuilderPopulateLTOPassManager(PMB, PM, Internalize, RunInliner);
229+
#else
230+
report_fatal_error("Legacy PM not supported with LLVM 15");
231+
#endif
161232
}
162233

163234
extern "C"
164235
void LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
165236
LLVMPassManagerBuilderRef PMBR,
166237
LLVMPassManagerRef PMR
167238
) {
239+
#if LLVM_VERSION_LT(15, 0)
168240
unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
241+
#else
242+
report_fatal_error("Legacy PM not supported with LLVM 15");
243+
#endif
244+
}
245+
246+
extern "C" void LLVMRustPassManagerBuilderUseInlinerWithThreshold(
247+
LLVMPassManagerBuilderRef PMB, unsigned Threshold) {
248+
#if LLVM_VERSION_LT(15, 0)
249+
LLVMPassManagerBuilderUseInlinerWithThreshold(PMB, Threshold);
250+
#else
251+
report_fatal_error("Legacy PM not supported with LLVM 15");
252+
#endif
169253
}
170254

171255
extern "C"
172256
void LLVMRustAddLastExtensionPasses(
173257
LLVMPassManagerBuilderRef PMBR, LLVMPassRef *Passes, size_t NumPasses) {
258+
#if LLVM_VERSION_LT(15, 0)
174259
auto AddExtensionPasses = [Passes, NumPasses](
175260
const PassManagerBuilder &Builder, PassManagerBase &PM) {
176261
for (size_t I = 0; I < NumPasses; I++) {
@@ -183,6 +268,9 @@ void LLVMRustAddLastExtensionPasses(
183268
AddExtensionPasses);
184269
unwrap(PMBR)->addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
185270
AddExtensionPasses);
271+
#else
272+
report_fatal_error("Legacy PM not supported with LLVM 15");
273+
#endif
186274
}
187275

188276
#ifdef LLVM_COMPONENT_X86
@@ -533,12 +621,16 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
533621
extern "C" void LLVMRustConfigurePassManagerBuilder(
534622
LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
535623
bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
536-
const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath) {
624+
const char* PGOGenPath, const char* PGOUsePath, const char* PGOSampleUsePath,
625+
int SizeLevel) {
626+
#if LLVM_VERSION_LT(15, 0)
537627
unwrap(PMBR)->MergeFunctions = MergeFunctions;
538628
unwrap(PMBR)->SLPVectorize = SLPVectorize;
539629
unwrap(PMBR)->OptLevel = fromRust(OptLevel);
540630
unwrap(PMBR)->LoopVectorize = LoopVectorize;
541631
unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
632+
unwrap(PMBR)->SizeLevel = SizeLevel;
633+
unwrap(PMBR)->DisableUnrollLoops = SizeLevel != 0;
542634

543635
if (PGOGenPath) {
544636
assert(!PGOUsePath && !PGOSampleUsePath);
@@ -550,6 +642,9 @@ extern "C" void LLVMRustConfigurePassManagerBuilder(
550642
} else if (PGOSampleUsePath) {
551643
unwrap(PMBR)->PGOSampleUse = PGOSampleUsePath;
552644
}
645+
#else
646+
report_fatal_error("Legacy PM not supported with LLVM 15");
647+
#endif
553648
}
554649

555650
// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "llvm/IR/GlobalVariable.h"
77
#include "llvm/IR/Instructions.h"
88
#include "llvm/IR/Intrinsics.h"
9+
#include "llvm/IR/Mangler.h"
910
#include "llvm/Object/Archive.h"
1011
#include "llvm/Object/COFFImportFile.h"
1112
#include "llvm/Object/ObjectFile.h"

src/test/codegen/panic-in-drop-abort.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no
1+
// compile-flags: -Z panic-in-drop=abort -O
2+
// ignore-msvc
23

34
// Ensure that unwinding code paths are eliminated from the output after
45
// optimization.
56

6-
// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen
7-
// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that
8-
// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we
9-
// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC
10-
// targets. We should either forbid longjmps, or not assume nounwind, making this optimization
11-
// incompatible with the current behavior of running cleanuppads on longjmp unwinding.
7+
// This test uses ignore-msvc, because the expected optimization does not happen on targets using
8+
// SEH exceptions with the new LLVM pass manager anymore, see
9+
// https://github.com/llvm/llvm-project/issues/51311.
1210

1311
// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output
1412

0 commit comments

Comments
 (0)