From 55d2be673659dff5d43b2bd9483d7b5214a2f452 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Wed, 9 Sep 2026 13:52:30 -0700 Subject: [PATCH] Refactor CodeGen Pipeline Setup into a Single Function This patch refactors setup of the LegacyPassManager for CodeGen into a single function. This simplifies some things (lifetime for the LegacyPM object), but is primarily aimed at enabling rustc to use the new runCodeGenPipeline abstraction (introduced in LLVM 24) which handles all of these details within LLVM and additionally defaults to the NewPM when a target opts-in/the correct LLVM flag is passed. --- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 15 +---- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 63 +++++++++---------- 3 files changed, 31 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bdf1bb2f24f6d..21cf76a786502 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -71,17 +71,14 @@ fn write_output_file<'ll>( std::ptr::null() }; let result = unsafe { - let pm = llvm::LLVMCreatePassManager(); - llvm::LLVMAddAnalysisPasses(target, pm); - llvm::LLVMRustAddLibraryInfo(target, pm, m, no_builtins); llvm::LLVMRustWriteOutputFile( target, - pm, m, output_c.as_ptr(), dwo_output_ptr, file_type, verify_llvm_ir, + no_builtins, ) }; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d1cdf7bada0b1..471b13868b218 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -714,8 +714,6 @@ unsafe extern "C" { } #[repr(C)] pub(crate) struct Builder<'a>(InvariantOpaque<'a>); -#[repr(C)] -pub(crate) struct PassManager<'a>(InvariantOpaque<'a>); unsafe extern "C" { pub type TargetMachine; } @@ -1636,11 +1634,6 @@ unsafe extern "C" { /// Writes a module to the specified path. Returns 0 on success. pub(crate) fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int; - /// Creates a legacy pass manager -- only used for final codegen. - pub(crate) fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>; - - pub(crate) fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>); - pub(crate) fn LLVMGetHostCPUFeatures() -> *mut c_char; pub(crate) fn LLVMDisposeMessage(message: *mut c_char); @@ -2427,20 +2420,14 @@ unsafe extern "C" { pub(crate) fn LLVMRustDisposeMCSubtargetInfo(MCInfo: ptr::NonNull); - pub(crate) fn LLVMRustAddLibraryInfo<'a>( - T: &TargetMachine, - PM: &PassManager<'a>, - M: &'a Module, - DisableSimplifyLibCalls: bool, - ); pub(crate) fn LLVMRustWriteOutputFile<'a>( T: &'a TargetMachine, - PM: *mut PassManager<'a>, M: &'a Module, Output: *const c_char, DwoOutput: *const c_char, FileType: FileType, VerifyIR: bool, + DisableSimplifyLibCalls: bool, ) -> LLVMRustResult; pub(crate) fn LLVMRustOptimize<'a>( M: &'a Module, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index d181891cdfa54..d1f83de92c9e0 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -444,28 +444,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( return wrap(TM); } -// Unfortunately, the LLVM C API doesn't provide a way to create the -// TargetLibraryInfo pass, so we use this method to do so. -extern "C" void LLVMRustAddLibraryInfo(LLVMTargetMachineRef T, - LLVMPassManagerRef PMR, LLVMModuleRef M, - bool DisableSimplifyLibCalls) { - auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); - TargetOptions *Options = &unwrap(T)->Options; - auto TLII = TargetLibraryInfoImpl(TargetTriple); - if (DisableSimplifyLibCalls) - TLII.disableAllFunctions(); - unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII)); -#if LLVM_VERSION_GE(24, 0) - unwrap(PMR)->add(new RuntimeLibraryInfoWrapper( - Options->ExceptionModel, Options->EABIVersion, Options->MCOptions.ABIName, - Options->VecLib)); -#elif LLVM_VERSION_GE(22, 0) - unwrap(PMR)->add(new RuntimeLibraryInfoWrapper( - TargetTriple, Options->ExceptionModel, Options->FloatABIType, - Options->EABIVersion, Options->MCOptions.ABIName, Options->VecLib)); -#endif -} - extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) { // Initializing the command-line options more than once is not allowed. So, // check if they've already been initialized. (This could happen if we're @@ -495,10 +473,31 @@ static CodeGenFileType fromRust(LLVMRustFileType Type) { } extern "C" LLVMRustResult -LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, - LLVMModuleRef M, const char *Path, const char *DwoPath, - LLVMRustFileType RustFileType, bool VerifyIR) { - llvm::legacy::PassManager *PM = unwrap(PMR); +LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, + const char *Path, const char *DwoPath, + LLVMRustFileType RustFileType, bool VerifyIR, + bool DisableSimplifyLibCalls) { + llvm::legacy::PassManager PM; + + PM.add(createTargetTransformInfoWrapperPass( + unwrap(Target)->getTargetIRAnalysis())); + + auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); + TargetOptions *Options = &unwrap(Target)->Options; + auto TLII = TargetLibraryInfoImpl(TargetTriple); + if (DisableSimplifyLibCalls) + TLII.disableAllFunctions(); + PM.add(new TargetLibraryInfoWrapperPass(TLII)); +#if LLVM_VERSION_GE(24, 0) + PM.add(new RuntimeLibraryInfoWrapper( + Options->ExceptionModel, Options->EABIVersion, Options->MCOptions.ABIName, + Options->VecLib)); +#elif LLVM_VERSION_GE(22, 0) + PM.add(new RuntimeLibraryInfoWrapper( + TargetTriple, Options->ExceptionModel, Options->FloatABIType, + Options->EABIVersion, Options->MCOptions.ABIName, Options->VecLib)); +#endif + auto FileType = fromRust(RustFileType); std::string ErrorInfo; @@ -522,17 +521,13 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, return LLVMRustResult::Failure; } auto DBOS = buffer_ostream(DOS); - unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, !VerifyIR); - PM->run(*unwrap(M)); + unwrap(Target)->addPassesToEmitFile(PM, BOS, &DBOS, FileType, !VerifyIR); + PM.run(*unwrap(M)); } else { - unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, !VerifyIR); - PM->run(*unwrap(M)); + unwrap(Target)->addPassesToEmitFile(PM, BOS, nullptr, FileType, !VerifyIR); + PM.run(*unwrap(M)); } - // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output - // stream (OS), so the only real safe place to delete this is here? Don't we - // wish this was written in Rust? - LLVMDisposePassManager(PMR); return LLVMRustResult::Success; }