about summary refs log tree commit diff
path: root/compiler/rustc_codegen_llvm
diff options
context:
space:
mode:
authorSimonas Kazlauskas <git@kazlauskas.me>2021-03-28 00:11:24 +0200
committerSimonas Kazlauskas <git@kazlauskas.me>2021-04-03 00:00:29 +0300
commit2f000a78bf615b35c4837f920fb6adcad4848351 (patch)
tree3d0cd52de9151067789edfa6f2e6729712dd0256 /compiler/rustc_codegen_llvm
parent9b0edb7fddacd6a60a380c1ce59159de597ab270 (diff)
downloadrust-2f000a78bf615b35c4837f920fb6adcad4848351.tar.gz
rust-2f000a78bf615b35c4837f920fb6adcad4848351.zip
Manually set dso_local when its valid to do so
This should 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 obviously correct portion and what 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
Diffstat (limited to 'compiler/rustc_codegen_llvm')
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs19
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs41
4 files changed, 54 insertions, 8 deletions
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 64ebe585dd8..a0bd677fb9f 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -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);
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 367c1f4811c..b26969a5012 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -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.
@@ -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
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 82cd1be3b3b..84d4fbdec34 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1031,6 +1031,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);
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 992e83d08fc..fc1f364e9c6 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -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> {
@@ -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);
@@ -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;
+    }
+}