]> git.lizzy.rs Git - rust.git/commitdiff
Always use llvm.used for coverage symbols
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 20 Aug 2021 19:13:18 +0000 (21:13 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Sat, 21 Aug 2021 08:08:05 +0000 (10:08 +0200)
This follows what clang does in CoverageMappingGen. Using just
llvm.compiler.used is insufficient at least for MSVC targets.

compiler/rustc_codegen_llvm/src/base.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_ssa/src/traits/misc.rs
compiler/rustc_codegen_ssa/src/traits/statics.rs
src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt

index a9f43880ef6b8def05c761b568e2c53dc7895239..a6bdbd11899deab8bb81cba65f3b8a7889d13bea 100644 (file)
@@ -162,11 +162,13 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm
                 cx.coverageinfo_finalize();
             }
 
-            // Create the llvm.compiler.used variable
-            // This variable has type [N x i8*] and is stored in the llvm.metadata section
+            // Create the llvm.used and llvm.compiler.used variables.
             if !cx.used_statics().borrow().is_empty() {
                 cx.create_used_variable()
             }
+            if !cx.compiler_used_statics().borrow().is_empty() {
+                cx.create_compiler_used_variable()
+            }
 
             // Finalize debuginfo
             if cx.sess().opts.debuginfo != DebugInfo::None {
index 7b14c1791748f04e0aa5e00eb65a5f7fbbec5d1a..e1baf95e1d9e5c0325f9addcc3abf471b579aeaf 100644 (file)
@@ -474,14 +474,27 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             }
 
             if attrs.flags.contains(CodegenFnAttrFlags::USED) {
-                self.add_used_global(g);
+                // The semantics of #[used] in Rust only require the symbol to make it into the
+                // object file. It is explicitly allowed for the linker to strip the symbol if it
+                // is dead. As such, use llvm.compiler.used instead of llvm.used.
+                // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
+                // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
+                // in some versions of the gold linker.
+                self.add_compiler_used_global(g);
             }
         }
     }
 
-    /// Add a global value to a list to be stored in the `llvm.compiler.used` variable, an array of i8*.
+    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
     fn add_used_global(&self, global: &'ll Value) {
         let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
         self.used_statics.borrow_mut().push(cast);
     }
+
+    /// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
+    /// an array of i8*.
+    fn add_compiler_used_global(&self, global: &'ll Value) {
+        let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
+        self.compiler_used_statics.borrow_mut().push(cast);
+    }
 }
index 9c0220d3448e6aa0a33a1c59b75f31b496115b5b..35c866d48a41b489ca4a2ce200ecbce082041914 100644 (file)
@@ -71,9 +71,13 @@ pub struct CodegenCx<'ll, 'tcx> {
     /// to constants.)
     pub statics_to_rauw: RefCell<Vec<(&'ll Value, &'ll Value)>>,
 
+    /// Statics that will be placed in the llvm.used variable
+    /// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
+    pub used_statics: RefCell<Vec<&'ll Value>>,
+
     /// Statics that will be placed in the llvm.compiler.used variable
     /// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
-    pub used_statics: RefCell<Vec<&'ll Value>>,
+    pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
 
     /// Mapping of non-scalar types to llvm types and field remapping if needed.
     pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,
@@ -325,6 +329,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             const_globals: Default::default(),
             statics_to_rauw: RefCell::new(Vec::new()),
             used_statics: RefCell::new(Vec::new()),
+            compiler_used_statics: RefCell::new(Vec::new()),
             type_lowering: Default::default(),
             scalar_lltypes: Default::default(),
             pointee_infos: Default::default(),
@@ -347,6 +352,18 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
         self.coverage_cx.as_ref()
     }
+
+    fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
+        let section = cstr!("llvm.metadata");
+        let array = self.const_array(&self.type_ptr_to(self.type_i8()), values);
+
+        unsafe {
+            let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
+            llvm::LLVMSetInitializer(g, array);
+            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+            llvm::LLVMSetSection(g, section.as_ptr());
+        }
+    }
 }
 
 impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -437,6 +454,10 @@ fn used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
         &self.used_statics
     }
 
+    fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
+        &self.compiler_used_statics
+    }
+
     fn set_frame_pointer_type(&self, llfn: &'ll Value) {
         attributes::set_frame_pointer_type(self, llfn)
     }
@@ -447,23 +468,14 @@ fn apply_target_cpu_attr(&self, llfn: &'ll Value) {
     }
 
     fn create_used_variable(&self) {
-        // The semantics of #[used] in Rust only require the symbol to make it into the object
-        // file. It is explicitly allowed for the linker to strip the symbol if it is dead.
-        // As such, use llvm.compiler.used instead of llvm.used.
-        // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
-        // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs in
-        // some versions of the gold linker.
-        let name = cstr!("llvm.compiler.used");
-        let section = cstr!("llvm.metadata");
-        let array =
-            self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow());
+        self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow());
+    }
 
-        unsafe {
-            let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
-            llvm::LLVMSetInitializer(g, array);
-            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
-            llvm::LLVMSetSection(g, section.as_ptr());
-        }
+    fn create_compiler_used_variable(&self) {
+        self.create_used_variable_impl(
+            cstr!("llvm.compiler.used"),
+            &*self.compiler_used_statics.borrow(),
+        );
     }
 
     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
index 46f2adbe55209aa7aea62dbc7c8e2e13e346cf4b..4266e42ec2b50359dfe1574bf9e06e5473bf2a92 100644 (file)
@@ -16,9 +16,11 @@ fn vtables(
     fn sess(&self) -> &Session;
     fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>;
     fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
+    fn compiler_used_statics(&self) -> &RefCell<Vec<Self::Value>>;
     fn set_frame_pointer_type(&self, llfn: Self::Function);
     fn apply_target_cpu_attr(&self, llfn: Self::Function);
     fn create_used_variable(&self);
+    fn create_compiler_used_variable(&self);
     /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>;
 }
index 817fc02d166a35ba9dff5e61e3087e9628d59c3b..a2a3cb56c78062f34196314999482f66e5f1a4b4 100644 (file)
@@ -6,17 +6,15 @@ pub trait StaticMethods: BackendTypes {
     fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
     fn codegen_static(&self, def_id: DefId, is_mutable: bool);
 
-    /// Mark the given global value as "used", to prevent a backend from potentially removing a
-    /// static variable that may otherwise appear unused.
-    ///
-    /// Static variables in Rust can be annotated with the `#[used]` attribute to direct the `rustc`
-    /// compiler to mark the variable as a "used global".
-    ///
-    /// ```no_run
-    /// #[used]
-    /// static FOO: u32 = 0;
-    /// ```
+    /// Mark the given global value as "used", to prevent the compiler and linker from potentially
+    /// removing a static variable that may otherwise appear unused.
     fn add_used_global(&self, global: Self::Value);
+
+    /// Same as add_used_global(), but only prevent the compiler from potentially removing an
+    /// otherwise unused symbol. The linker is still permitted to drop it.
+    ///
+    /// This corresponds to the semantics of the `#[used]` attribute.
+    fn add_compiler_used_global(&self, global: Self::Value);
 }
 
 pub trait StaticBuilderMethods: BackendTypes {
index 973f695e36dd6e6bf29f79cd8e2981fa95d29f9b..8e5f210468773cd91c97eea4ea6f14c302380e8f 100644 (file)
@@ -28,11 +28,8 @@ CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
 CHECK:        @__llvm_prf_nm = private constant
 CHECK-SAME:   section "[[INSTR_PROF_NAME]]", align 1
 
-CHECK:        @llvm.compiler.used = appending global
-CHECK-SAME:   i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
-WINDOWS-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*)
-CHECK-SAME:   section "llvm.metadata"
 CHECK:        @llvm.used = appending global
+CHECK-SAME:   i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*)
 CHECK-SAME:   i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0)
 CHECK-SAME:   section "llvm.metadata"