Skip to content

Commit

Permalink
Auto merge of #83592 - nagisa:nagisa/dso_local, r=davidtwco
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Apr 6, 2021
2 parents 8e6b478 + 2f000a7 commit 0c7d4ef
Show file tree
Hide file tree
Showing 30 changed files with 221 additions and 122 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
attributes::emit_uwtable(llfn, true);
}

// FIXME: none of these three functions interact with source level attributes.
set_frame_pointer_elimination(cx, llfn);
set_instrument_function(cx, llfn);
set_probestack(cx, llfn);
Expand Down
19 changes: 11 additions & 8 deletions compiler/rustc_codegen_llvm/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use tracing::debug;

use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
use rustc_middle::ty::{self, Instance, TypeFoldable};
use rustc_target::spec::RelocModel;

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

// MinGW: For backward compatibility we rely on the linker to decide whether it
// should use dllimport for functions.
if cx.use_dll_storage_attrs
&& tcx.is_dllimport_foreign_item(instance_def_id)
&& tcx.sess.target.env != "gnu"
{
unsafe {
// MinGW: For backward compatibility we rely on the linker to decide whether it
// should use dllimport for functions.
if cx.use_dll_storage_attrs
&& tcx.is_dllimport_foreign_item(instance_def_id)
&& tcx.sess.target.env != "gnu"
{
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
}

if cx.tcx.sess.relocation_model() == RelocModel::Static {
llvm::LLVMRustSetDSOLocal(llfn, true);
}
}

llfn
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ extern "C" {
pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_codegen_llvm/src/mono_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ pub use rustc_middle::mir::mono::MonoItem;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::{self, Instance, TypeFoldable};
use rustc_session::config::CrateType;
use rustc_target::abi::LayoutOf;
use rustc_target::spec::RelocModel;
use tracing::debug;

impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
Expand All @@ -35,6 +37,9 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
unsafe {
llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
if self.should_assume_dso_local(linkage, visibility) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}

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

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

unsafe {
if self.should_assume_dso_local(linkage, visibility) {
llvm::LLVMRustSetDSOLocal(lldecl, true);
}
}

self.instances.borrow_mut().insert(instance, lldecl);
}
}

impl CodegenCx<'ll, 'tcx> {
/// Whether a definition (NB: not declaration!) can be assumed to be local to a group of
/// libraries that form a single DSO or executable.
pub(crate) unsafe fn should_assume_dso_local(
&self,
linkage: Linkage,
visibility: Visibility,
) -> bool {
if matches!(linkage, Linkage::Internal | Linkage::Private) {
return true;
}

if visibility != Visibility::Default && linkage != Linkage::ExternalWeak {
return true;
}

// Static relocation model should force copy relocations everywhere.
if self.tcx.sess.relocation_model() == RelocModel::Static {
return true;
}

// Symbols from executables can't really be imported any further.
if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
return true;
}

return false;
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,10 @@ extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
LLVMSetVisibility(V, fromRust(RustVisibility));
}

extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) {
unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local);
}

struct LLVMRustModuleBuffer {
std::string data;
};
Expand Down
44 changes: 44 additions & 0 deletions src/test/assembly/static-relocation-model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// min-llvm-version: 12.0.0
// needs-llvm-components: aarch64 x86
// revisions:X64 A64
// assembly-output: emit-asm
// [X64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
// [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static

#![feature(no_core, lang_items)]
#![no_core]
#![crate_type="rlib"]

#[lang="sized"]
trait Sized {}

#[lang="copy"]
trait Copy {}

impl Copy for u8 {}

extern "C" {
fn chaenomeles();
}

// CHECK-LABEL: banana:
// x64: movb chaenomeles, %{{[a,z]+}}
// A64: adrp [[REG:[a-z0-9]+]], chaenomeles
// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles]
#[no_mangle]
pub fn banana() -> u8 {
unsafe {
*(chaenomeles as *mut u8)
}
}

// CHECK-LABEL: peach:
// x64: movb banana, %{{[a,z]+}}
// A64: adrp [[REG2:[a-z0-9]+]], banana
// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana]
#[no_mangle]
pub fn peach() -> u8 {
unsafe {
*(banana as *mut u8)
}
}
6 changes: 3 additions & 3 deletions src/test/codegen/abi-efiapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ trait Copy { }

//x86_64: define win64cc void @has_efiapi
//i686: define void @has_efiapi
//aarch64: define void @has_efiapi
//arm: define void @has_efiapi
//riscv: define void @has_efiapi
//aarch64: define dso_local void @has_efiapi
//arm: define dso_local void @has_efiapi
//riscv: define dso_local void @has_efiapi
#[no_mangle]
pub extern "efiapi" fn has_efiapi() {}
2 changes: 1 addition & 1 deletion src/test/codegen/abi-repr-ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub enum Type {
Type2 = 1
}

// CHECK: define signext i8 @test()
// CHECK: define{{( dso_local)?}} signext i8 @test()
#[no_mangle]
pub extern "C" fn test() -> Type {
Type::Type1
Expand Down
18 changes: 11 additions & 7 deletions src/test/codegen/abi-sysv64.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
// Checks if the correct annotation for the sysv64 ABI is passed to
// llvm. Also checks that the abi-sysv64 feature gate allows usage
// of the sysv64 abi.

// ignore-arm
// ignore-aarch64
// ignore-riscv64 sysv64 not supported

// compile-flags: -C no-prepopulate-passes
//
// needs-llvm-components: x86
// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu

#![crate_type = "lib"]
#![no_core]
#![feature(abi_x86_interrupt, no_core, lang_items)]

#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}

// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi
#[no_mangle]
pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 {
a * 2
a
}
17 changes: 10 additions & 7 deletions src/test/codegen/abi-x86-interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@
// llvm. Also checks that the abi_x86_interrupt feature gate allows usage
// of the x86-interrupt abi.

// ignore-arm
// ignore-aarch64
// ignore-riscv64 x86-interrupt is not supported

// compile-flags: -C no-prepopulate-passes
// needs-llvm-components: x86
// compile-flags: -C no-prepopulate-passes --target=x86_64-unknown-linux-gnu

#![crate_type = "lib"]
#![feature(abi_x86_interrupt)]
#![no_core]
#![feature(abi_x86_interrupt, no_core, lang_items)]

#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}

// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
#[no_mangle]
pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 {
a * 2
a
}
16 changes: 8 additions & 8 deletions src/test/codegen/cdylib-external-inline-fns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,42 @@

#![crate_type = "cdylib"]

// CHECK: define void @a()
// CHECK: define{{( dso_local)?}} void @a()
#[no_mangle]
#[inline]
pub extern "C" fn a() {}

// CHECK: define void @b()
// CHECK: define{{( dso_local)?}} void @b()
#[export_name = "b"]
#[inline]
pub extern "C" fn b() {}

// CHECK: define void @c()
// CHECK: define{{( dso_local)?}} void @c()
#[no_mangle]
#[inline]
extern "C" fn c() {}

// CHECK: define void @d()
// CHECK: define{{( dso_local)?}} void @d()
#[export_name = "d"]
#[inline]
extern "C" fn d() {}

// CHECK: define void @e()
// CHECK: define{{( dso_local)?}} void @e()
#[no_mangle]
#[inline(always)]
pub extern "C" fn e() {}

// CHECK: define void @f()
// CHECK: define{{( dso_local)?}} void @f()
#[export_name = "f"]
#[inline(always)]
pub extern "C" fn f() {}

// CHECK: define void @g()
// CHECK: define{{( dso_local)?}} void @g()
#[no_mangle]
#[inline(always)]
extern "C" fn g() {}

// CHECK: define void @h()
// CHECK: define{{( dso_local)?}} void @h()
#[export_name = "h"]
#[inline(always)]
extern "C" fn h() {}
3 changes: 1 addition & 2 deletions src/test/codegen/dealloc-no-unwind.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//
// no-system-llvm
// compile-flags: -O

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

#[no_mangle]
pub fn a(a: Box<i32>) {
// CHECK-LABEL: define void @a
// CHECK-LABEL: define{{.*}}void @a
// CHECK: call void @__rust_dealloc
// CHECK-NEXT: call void @foo
let _a = A;
Expand Down
24 changes: 12 additions & 12 deletions src/test/codegen/external-no-mangle-fns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,30 @@
#![crate_type = "lib"]
#![no_std]

// CHECK: define void @a()
// CHECK: define{{( dso_local)?}} void @a()
#[no_mangle]
fn a() {}

// CHECK: define void @b()
// CHECK: define{{( dso_local)?}} void @b()
#[no_mangle]
pub fn b() {}

mod private {
// CHECK: define void @c()
// CHECK: define{{( dso_local)?}} void @c()
#[no_mangle]
fn c() {}

// CHECK: define void @d()
// CHECK: define{{( dso_local)?}} void @d()
#[no_mangle]
pub fn d() {}
}

const HIDDEN: () = {
// CHECK: define void @e()
// CHECK: define{{( dso_local)?}} void @e()
#[no_mangle]
fn e() {}

// CHECK: define void @f()
// CHECK: define{{( dso_local)?}} void @f()
#[no_mangle]
pub fn f() {}
};
Expand All @@ -38,13 +38,13 @@ const HIDDEN: () = {
// CHECK-NEXT: define internal
#[inline(never)]
fn x() {
// CHECK: define void @g()
// CHECK: define{{( dso_local)?}} void @g()
#[no_mangle]
fn g() {
x();
}

// CHECK: define void @h()
// CHECK: define{{( dso_local)?}} void @h()
#[no_mangle]
pub fn h() {}

Expand All @@ -54,22 +54,22 @@ fn x() {
}
}

// CHECK: define void @i()
// CHECK: define{{( dso_local)?}} void @i()
#[no_mangle]
#[inline]
fn i() {}

// CHECK: define void @j()
// CHECK: define{{( dso_local)?}} void @j()
#[no_mangle]
#[inline]
pub fn j() {}

// CHECK: define void @k()
// CHECK: define{{( dso_local)?}} void @k()
#[no_mangle]
#[inline(always)]
fn k() {}

// CHECK: define void @l()
// CHECK: define{{( dso_local)?}} void @l()
#[no_mangle]
#[inline(always)]
pub fn l() {}
Loading

0 comments on commit 0c7d4ef

Please sign in to comment.