From cbf748993f59682f60dfe620eafea24124f737fb Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 29 Nov 2018 23:05:23 +0100 Subject: [PATCH 1/2] Enable -mergefunc-use-aliases If the Rust LLVM fork is used, enable the -mergefunc-use-aliases flag, which will create aliases for merged functions, rather than inserting a call from one to the other. A number of codegen tests needed to be adjusted, because functions that previously fell below the thunk limit are now being merged. Merging is prevented either using -C no-prepopulate-passes, or by making the functions non-identical. I expect that this is going to break something, somewhere, because it isn't able to deal with aliases properly, but we won't find out until we try :) This fixes #52651. --- src/librustc_codegen_llvm/llvm/ffi.rs | 1 + src/librustc_codegen_llvm/llvm_util.rs | 3 +++ src/rustllvm/PassWrapper.cpp | 2 +- src/rustllvm/RustWrapper.cpp | 8 ++++++++ src/test/codegen/export-no-mangle.rs | 2 ++ src/test/codegen/external-no-mangle-fns.rs | 4 ++-- src/test/codegen/issue-45222.rs | 4 ++-- src/test/codegen/match-optimizes-away.rs | 3 ++- 8 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index f1a966d765438..9eefeca70cf7a 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1358,6 +1358,7 @@ extern "C" { pub fn LLVMRustDebugMetadataVersion() -> u32; pub fn LLVMRustVersionMajor() -> u32; pub fn LLVMRustVersionMinor() -> u32; + pub fn LLVMRustIsRustLLVM() -> bool; pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32); diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 267d7e0d54b63..fdb6373bea1fe 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -70,6 +70,9 @@ unsafe fn configure_llvm(sess: &Session) { if sess.opts.debugging_opts.disable_instrumentation_preinliner { add("-disable-preinline"); } + if llvm::LLVMRustIsRustLLVM() { + add("-mergefunc-use-aliases"); + } for arg in &sess.opts.cg.llvm_args { add(&(*arg)); diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 06de0d6509bab..aa420bf6100c7 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -284,7 +284,7 @@ static Optional fromRust(LLVMRustRelocMode RustReloc) { report_fatal_error("Bad RelocModel."); } -#if LLVM_RUSTLLVM +#ifdef LLVM_RUSTLLVM /// getLongestEntryLength - Return the length of the longest entry in the table. /// static size_t getLongestEntryLength(ArrayRef Table) { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index b6e07942f8667..6dcd32fe4d719 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -533,6 +533,14 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } +extern "C" bool LLVMRustIsRustLLVM() { +#ifdef LLVM_RUSTLLVM + return 1; +#else + return 0; +#endif +} + extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name, uint32_t Value) { unwrap(M)->addModuleFlag(Module::Warning, Name, Value); diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs index 3546284f9a3c5..95587d9d84cf0 100644 --- a/src/test/codegen/export-no-mangle.rs +++ b/src/test/codegen/export-no-mangle.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -C no-prepopulate-passes + #![crate_type = "lib"] mod private { diff --git a/src/test/codegen/external-no-mangle-fns.rs b/src/test/codegen/external-no-mangle-fns.rs index 3f092b802f99a..5823285259602 100644 --- a/src/test/codegen/external-no-mangle-fns.rs +++ b/src/test/codegen/external-no-mangle-fns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -O +// compile-flags: -C no-prepopulate-passes // `#[no_mangle]`d functions always have external linkage, i.e. no `internal` in their `define`s #![crate_type = "lib"] @@ -43,7 +43,7 @@ const HIDDEN: () = { }; // The surrounding item should not accidentally become external -// CHECK: define internal {{.*}} void @_ZN22external_no_mangle_fns1x +// CHECK: define internal{{.*}} void @_ZN22external_no_mangle_fns1x #[inline(never)] fn x() { // CHECK: define void @g() diff --git a/src/test/codegen/issue-45222.rs b/src/test/codegen/issue-45222.rs index 30a03243f0151..3544786e2e60a 100644 --- a/src/test/codegen/issue-45222.rs +++ b/src/test/codegen/issue-45222.rs @@ -69,6 +69,6 @@ fn foo3r(n: u64) -> u64 { // CHECK-LABEL: @check_foo3r #[no_mangle] pub fn check_foo3r() -> u64 { - // CHECK: ret i64 500005000000000 - foo3r(100000) + // CHECK: ret i64 500050000000 + foo3r(10000) } diff --git a/src/test/codegen/match-optimizes-away.rs b/src/test/codegen/match-optimizes-away.rs index d7b779374314d..2136b176eac9b 100644 --- a/src/test/codegen/match-optimizes-away.rs +++ b/src/test/codegen/match-optimizes-away.rs @@ -14,6 +14,7 @@ pub enum Three { A, B, C } +#[repr(u16)] pub enum Four { A, B, C, D } #[no_mangle] @@ -32,7 +33,7 @@ pub fn three_valued(x: Three) -> Three { pub fn four_valued(x: Four) -> Four { // CHECK-LABEL: @four_valued // CHECK-NEXT: {{^.*:$}} - // CHECK-NEXT: ret i8 %0 + // CHECK-NEXT: ret i16 %0 match x { Four::A => Four::A, Four::B => Four::B, From 850d2f1af0224cf1d442a66c33470791a2597888 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 2 Dec 2018 14:41:39 +0100 Subject: [PATCH 2/2] Run name-anon-globals after all other passes name-anon-globals should always be run at the very end of the pass pipeline, as optimization passes (in particular mergefunc) may introduce new anonymous globals. I believe we did not run into this earlier because it requires the rather specific combination of a) mergefunc merging two weak functions b) compilation not using thinlto. --- src/librustc_codegen_llvm/back/write.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 7945d381760a1..a7e53faab21e8 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -371,15 +371,16 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, .unwrap_or(llvm::CodeGenOptLevel::None); let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || (cgcx.lto != Lto::Fat && cgcx.opts.debugging_opts.cross_lang_lto.enabled()); + with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { + llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); + llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); + }); + have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto; if using_thin_buffers && !prepare_for_thin_lto { assert!(addpass("name-anon-globals")); have_name_anon_globals_pass = true; } - with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { - llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); - llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); - }) } for pass in &config.passes {