Skip to content

Commit 0c7d4ef

Browse files
committed
Auto merge of #83592 - nagisa:nagisa/dso_local, r=davidtwco
Set dso_local for hidden, private and local items This should probably have no real effect in most cases, as e.g. `hidden` visibility already implies `dso_local` (or at least LLVM IR does not preserve the `dso_local` setting if the item is already `hidden`), but it should fix `-Crelocation-model=static` and improve codegen in executables. Note that this PR does not exhaustively port the logic in [clang], only the portion that is necessary to fix a regression from LLVM 12 that relates to `-Crelocation_model=static`. Fixes #83335 [clang]: https://github.com/llvm/llvm-project/blob/3001d080c813da20b329303bf8f45451480e5905/clang/lib/CodeGen/CodeGenModule.cpp#L945-L1039
2 parents 8e6b478 + 2f000a7 commit 0c7d4ef

30 files changed

+221
-122
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
254254
attributes::emit_uwtable(llfn, true);
255255
}
256256

257+
// FIXME: none of these three functions interact with source level attributes.
257258
set_frame_pointer_elimination(cx, llfn);
258259
set_instrument_function(cx, llfn);
259260
set_probestack(cx, llfn);

compiler/rustc_codegen_llvm/src/callee.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use tracing::debug;
1414

1515
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
1616
use rustc_middle::ty::{self, Instance, TypeFoldable};
17+
use rustc_target::spec::RelocModel;
1718

1819
/// Codegens a reference to a fn/method item, monomorphizing and
1920
/// inlining as it goes.
@@ -170,17 +171,19 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
170171
}
171172
}
172173
}
173-
}
174174

175-
// MinGW: For backward compatibility we rely on the linker to decide whether it
176-
// should use dllimport for functions.
177-
if cx.use_dll_storage_attrs
178-
&& tcx.is_dllimport_foreign_item(instance_def_id)
179-
&& tcx.sess.target.env != "gnu"
180-
{
181-
unsafe {
175+
// MinGW: For backward compatibility we rely on the linker to decide whether it
176+
// should use dllimport for functions.
177+
if cx.use_dll_storage_attrs
178+
&& tcx.is_dllimport_foreign_item(instance_def_id)
179+
&& tcx.sess.target.env != "gnu"
180+
{
182181
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
183182
}
183+
184+
if cx.tcx.sess.relocation_model() == RelocModel::Static {
185+
llvm::LLVMRustSetDSOLocal(llfn, true);
186+
}
184187
}
185188

186189
llfn

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ extern "C" {
10131013
pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
10141014
pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
10151015
pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
1016+
pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
10161017
pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
10171018
pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
10181019
pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);

compiler/rustc_codegen_llvm/src/mono_item.rs

+41
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ pub use rustc_middle::mir::mono::MonoItem;
1010
use rustc_middle::mir::mono::{Linkage, Visibility};
1111
use rustc_middle::ty::layout::FnAbiExt;
1212
use rustc_middle::ty::{self, Instance, TypeFoldable};
13+
use rustc_session::config::CrateType;
1314
use rustc_target::abi::LayoutOf;
15+
use rustc_target::spec::RelocModel;
1416
use tracing::debug;
1517

1618
impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -35,6 +37,9 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
3537
unsafe {
3638
llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
3739
llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
40+
if self.should_assume_dso_local(linkage, visibility) {
41+
llvm::LLVMRustSetDSOLocal(g, true);
42+
}
3843
}
3944

4045
self.instances.borrow_mut().insert(instance, g);
@@ -79,6 +84,42 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
7984

8085
attributes::from_fn_attrs(self, lldecl, instance);
8186

87+
unsafe {
88+
if self.should_assume_dso_local(linkage, visibility) {
89+
llvm::LLVMRustSetDSOLocal(lldecl, true);
90+
}
91+
}
92+
8293
self.instances.borrow_mut().insert(instance, lldecl);
8394
}
8495
}
96+
97+
impl CodegenCx<'ll, 'tcx> {
98+
/// Whether a definition (NB: not declaration!) can be assumed to be local to a group of
99+
/// libraries that form a single DSO or executable.
100+
pub(crate) unsafe fn should_assume_dso_local(
101+
&self,
102+
linkage: Linkage,
103+
visibility: Visibility,
104+
) -> bool {
105+
if matches!(linkage, Linkage::Internal | Linkage::Private) {
106+
return true;
107+
}
108+
109+
if visibility != Visibility::Default && linkage != Linkage::ExternalWeak {
110+
return true;
111+
}
112+
113+
// Static relocation model should force copy relocations everywhere.
114+
if self.tcx.sess.relocation_model() == RelocModel::Static {
115+
return true;
116+
}
117+
118+
// Symbols from executables can't really be imported any further.
119+
if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
120+
return true;
121+
}
122+
123+
return false;
124+
}
125+
}

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,10 @@ extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
16361636
LLVMSetVisibility(V, fromRust(RustVisibility));
16371637
}
16381638

1639+
extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) {
1640+
unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local);
1641+
}
1642+
16391643
struct LLVMRustModuleBuffer {
16401644
std::string data;
16411645
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// min-llvm-version: 12.0.0
2+
// needs-llvm-components: aarch64 x86
3+
// revisions:X64 A64
4+
// assembly-output: emit-asm
5+
// [X64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
6+
// [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static
7+
8+
#![feature(no_core, lang_items)]
9+
#![no_core]
10+
#![crate_type="rlib"]
11+
12+
#[lang="sized"]
13+
trait Sized {}
14+
15+
#[lang="copy"]
16+
trait Copy {}
17+
18+
impl Copy for u8 {}
19+
20+
extern "C" {
21+
fn chaenomeles();
22+
}
23+
24+
// CHECK-LABEL: banana:
25+
// x64: movb chaenomeles, %{{[a,z]+}}
26+
// A64: adrp [[REG:[a-z0-9]+]], chaenomeles
27+
// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles]
28+
#[no_mangle]
29+
pub fn banana() -> u8 {
30+
unsafe {
31+
*(chaenomeles as *mut u8)
32+
}
33+
}
34+
35+
// CHECK-LABEL: peach:
36+
// x64: movb banana, %{{[a,z]+}}
37+
// A64: adrp [[REG2:[a-z0-9]+]], banana
38+
// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana]
39+
#[no_mangle]
40+
pub fn peach() -> u8 {
41+
unsafe {
42+
*(banana as *mut u8)
43+
}
44+
}

src/test/codegen/abi-efiapi.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ trait Copy { }
2323

2424
//x86_64: define win64cc void @has_efiapi
2525
//i686: define void @has_efiapi
26-
//aarch64: define void @has_efiapi
27-
//arm: define void @has_efiapi
28-
//riscv: define void @has_efiapi
26+
//aarch64: define dso_local void @has_efiapi
27+
//arm: define dso_local void @has_efiapi
28+
//riscv: define dso_local void @has_efiapi
2929
#[no_mangle]
3030
pub extern "efiapi" fn has_efiapi() {}

src/test/codegen/abi-repr-ext.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub enum Type {
66
Type2 = 1
77
}
88

9-
// CHECK: define signext i8 @test()
9+
// CHECK: define{{( dso_local)?}} signext i8 @test()
1010
#[no_mangle]
1111
pub extern "C" fn test() -> Type {
1212
Type::Type1

src/test/codegen/abi-sysv64.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
// Checks if the correct annotation for the sysv64 ABI is passed to
22
// llvm. Also checks that the abi-sysv64 feature gate allows usage
33
// of the sysv64 abi.
4-
5-
// ignore-arm
6-
// ignore-aarch64
7-
// ignore-riscv64 sysv64 not supported
8-
9-
// compile-flags: -C no-prepopulate-passes
4+
//
5+
// needs-llvm-components: x86
6+
// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
107

118
#![crate_type = "lib"]
9+
#![no_core]
10+
#![feature(abi_x86_interrupt, no_core, lang_items)]
11+
12+
#[lang = "sized"]
13+
trait Sized {}
14+
#[lang = "copy"]
15+
trait Copy {}
1216

1317
// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
1418
#[no_mangle]
1519
pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 {
16-
a * 2
20+
a
1721
}

src/test/codegen/abi-x86-interrupt.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22
// llvm. Also checks that the abi_x86_interrupt feature gate allows usage
33
// of the x86-interrupt abi.
44

5-
// ignore-arm
6-
// ignore-aarch64
7-
// ignore-riscv64 x86-interrupt is not supported
8-
9-
// compile-flags: -C no-prepopulate-passes
5+
// needs-llvm-components: x86
6+
// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu
107

118
#![crate_type = "lib"]
12-
#![feature(abi_x86_interrupt)]
9+
#![no_core]
10+
#![feature(abi_x86_interrupt, no_core, lang_items)]
11+
12+
#[lang = "sized"]
13+
trait Sized {}
14+
#[lang = "copy"]
15+
trait Copy {}
1316

1417
// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
1518
#[no_mangle]
1619
pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 {
17-
a * 2
20+
a
1821
}

src/test/codegen/cdylib-external-inline-fns.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,42 @@
22

33
#![crate_type = "cdylib"]
44

5-
// CHECK: define void @a()
5+
// CHECK: define{{( dso_local)?}} void @a()
66
#[no_mangle]
77
#[inline]
88
pub extern "C" fn a() {}
99

10-
// CHECK: define void @b()
10+
// CHECK: define{{( dso_local)?}} void @b()
1111
#[export_name = "b"]
1212
#[inline]
1313
pub extern "C" fn b() {}
1414

15-
// CHECK: define void @c()
15+
// CHECK: define{{( dso_local)?}} void @c()
1616
#[no_mangle]
1717
#[inline]
1818
extern "C" fn c() {}
1919

20-
// CHECK: define void @d()
20+
// CHECK: define{{( dso_local)?}} void @d()
2121
#[export_name = "d"]
2222
#[inline]
2323
extern "C" fn d() {}
2424

25-
// CHECK: define void @e()
25+
// CHECK: define{{( dso_local)?}} void @e()
2626
#[no_mangle]
2727
#[inline(always)]
2828
pub extern "C" fn e() {}
2929

30-
// CHECK: define void @f()
30+
// CHECK: define{{( dso_local)?}} void @f()
3131
#[export_name = "f"]
3232
#[inline(always)]
3333
pub extern "C" fn f() {}
3434

35-
// CHECK: define void @g()
35+
// CHECK: define{{( dso_local)?}} void @g()
3636
#[no_mangle]
3737
#[inline(always)]
3838
extern "C" fn g() {}
3939

40-
// CHECK: define void @h()
40+
// CHECK: define{{( dso_local)?}} void @h()
4141
#[export_name = "h"]
4242
#[inline(always)]
4343
extern "C" fn h() {}

src/test/codegen/dealloc-no-unwind.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//
21
// no-system-llvm
32
// compile-flags: -O
43

@@ -15,7 +14,7 @@ impl Drop for A {
1514

1615
#[no_mangle]
1716
pub fn a(a: Box<i32>) {
18-
// CHECK-LABEL: define void @a
17+
// CHECK-LABEL: define{{.*}}void @a
1918
// CHECK: call void @__rust_dealloc
2019
// CHECK-NEXT: call void @foo
2120
let _a = A;

src/test/codegen/external-no-mangle-fns.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,30 @@
44
#![crate_type = "lib"]
55
#![no_std]
66

7-
// CHECK: define void @a()
7+
// CHECK: define{{( dso_local)?}} void @a()
88
#[no_mangle]
99
fn a() {}
1010

11-
// CHECK: define void @b()
11+
// CHECK: define{{( dso_local)?}} void @b()
1212
#[no_mangle]
1313
pub fn b() {}
1414

1515
mod private {
16-
// CHECK: define void @c()
16+
// CHECK: define{{( dso_local)?}} void @c()
1717
#[no_mangle]
1818
fn c() {}
1919

20-
// CHECK: define void @d()
20+
// CHECK: define{{( dso_local)?}} void @d()
2121
#[no_mangle]
2222
pub fn d() {}
2323
}
2424

2525
const HIDDEN: () = {
26-
// CHECK: define void @e()
26+
// CHECK: define{{( dso_local)?}} void @e()
2727
#[no_mangle]
2828
fn e() {}
2929

30-
// CHECK: define void @f()
30+
// CHECK: define{{( dso_local)?}} void @f()
3131
#[no_mangle]
3232
pub fn f() {}
3333
};
@@ -38,13 +38,13 @@ const HIDDEN: () = {
3838
// CHECK-NEXT: define internal
3939
#[inline(never)]
4040
fn x() {
41-
// CHECK: define void @g()
41+
// CHECK: define{{( dso_local)?}} void @g()
4242
#[no_mangle]
4343
fn g() {
4444
x();
4545
}
4646

47-
// CHECK: define void @h()
47+
// CHECK: define{{( dso_local)?}} void @h()
4848
#[no_mangle]
4949
pub fn h() {}
5050

@@ -54,22 +54,22 @@ fn x() {
5454
}
5555
}
5656

57-
// CHECK: define void @i()
57+
// CHECK: define{{( dso_local)?}} void @i()
5858
#[no_mangle]
5959
#[inline]
6060
fn i() {}
6161

62-
// CHECK: define void @j()
62+
// CHECK: define{{( dso_local)?}} void @j()
6363
#[no_mangle]
6464
#[inline]
6565
pub fn j() {}
6666

67-
// CHECK: define void @k()
67+
// CHECK: define{{( dso_local)?}} void @k()
6868
#[no_mangle]
6969
#[inline(always)]
7070
fn k() {}
7171

72-
// CHECK: define void @l()
72+
// CHECK: define{{( dso_local)?}} void @l()
7373
#[no_mangle]
7474
#[inline(always)]
7575
pub fn l() {}

0 commit comments

Comments
 (0)