about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMiguel Ojeda <ojeda@kernel.org>2022-05-29 01:10:44 +0200
committerMiguel Ojeda <ojeda@kernel.org>2023-07-21 22:01:50 +0200
commit74b8d324eb77a8f337b35dc68ac91b0c2c06debc (patch)
treef16c499a07a18b5ed768bf0a4ec472d01be7a5a2
parentc3c5a5c5f7a0cf9acdfe60440a1e1fa68a1c1278 (diff)
downloadrust-74b8d324eb77a8f337b35dc68ac91b0c2c06debc.tar.gz
rust-74b8d324eb77a8f337b35dc68ac91b0c2c06debc.zip
Support `.comment` section like GCC/Clang (`!llvm.ident`)
Both GCC and Clang write by default a `.comment` section with compiler
information:

```txt
$ gcc -c -xc /dev/null && readelf -p '.comment' null.o

String dump of section '.comment':
  [     1]  GCC: (GNU) 11.2.0

$ clang -c -xc /dev/null && readelf -p '.comment' null.o

String dump of section '.comment':
  [     1]  clang version 14.0.1 (https://github.com/llvm/llvm-project.git c62053979489ccb002efe411c3af059addcb5d7d)
```

They also implement the `-Qn` flag to avoid doing so:

```txt
$ gcc -Qn -c -xc /dev/null && readelf -p '.comment' null.o
readelf: Warning: Section '.comment' was not dumped because it does not exist!

$ clang -Qn -c -xc /dev/null && readelf -p '.comment' null.o
readelf: Warning: Section '.comment' was not dumped because it does not exist!
```

So far, `rustc` only does it for WebAssembly targets and only
when debug info is enabled:

```txt
$ echo 'fn main(){}' | rustc --target=wasm32-unknown-unknown --emit=llvm-ir -Cdebuginfo=2 - && grep llvm.ident rust_out.ll
!llvm.ident = !{!27}
```

In the RFC part of this PR it was decided to always add
the information, which gets us closer to other popular compilers.
An opt-out flag like GCC and Clang may be added later on if deemed
necessary.

Implementation-wise, this covers both `ModuleLlvm::new()` and
`ModuleLlvm::new_metadata()` cases by moving the addition to
`context::create_module` and adds a few test cases.

ThinLTO also sees the `llvm.ident` named metadata duplicated (in
temporary outputs), so this deduplicates it like it is done for
`wasm.custom_sections`. The tests also check this duplication does
not take place.

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs15
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp5
-rw-r--r--tests/codegen/llvm-ident.rs15
-rw-r--r--tests/run-make/comment-section/Makefile15
-rw-r--r--tests/run-make/llvm-ident/Makefile19
6 files changed, 72 insertions, 15 deletions
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index e1e0a442845..5bf641055c5 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -33,6 +33,7 @@ use rustc_target::abi::{
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
 use smallvec::SmallVec;
 
+use libc::c_uint;
 use std::cell::{Cell, RefCell};
 use std::ffi::CStr;
 use std::str;
@@ -349,6 +350,23 @@ pub unsafe fn create_module<'ll>(
         );
     }
 
+    // Insert `llvm.ident` metadata.
+    //
+    // On the wasm targets it will get hooked up to the "producer" sections
+    // `processed-by` information.
+    let rustc_producer =
+        format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
+    let name_metadata = llvm::LLVMMDStringInContext(
+        llcx,
+        rustc_producer.as_ptr().cast(),
+        rustc_producer.as_bytes().len() as c_uint,
+    );
+    llvm::LLVMAddNamedMetadataOperand(
+        llmod,
+        cstr!("llvm.ident").as_ptr(),
+        llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
+    );
+
     llmod
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index c6996f2e16a..905e0e541a8 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -888,21 +888,6 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
             llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, llvm_gcov_ident.as_ptr(), val);
         }
 
-        // Insert `llvm.ident` metadata on the wasm targets since that will
-        // get hooked up to the "producer" sections `processed-by` information.
-        if tcx.sess.target.is_like_wasm {
-            let name_metadata = llvm::LLVMMDStringInContext(
-                debug_context.llcontext,
-                rustc_producer.as_ptr().cast(),
-                rustc_producer.as_bytes().len() as c_uint,
-            );
-            llvm::LLVMAddNamedMetadataOperand(
-                debug_context.llmod,
-                cstr!("llvm.ident").as_ptr(),
-                llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
-            );
-        }
-
         return unit_metadata;
     };
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index e5fb6b0953f..71df17c9ce7 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1366,6 +1366,11 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
     if (WasmCustomSections)
       WasmCustomSections->eraseFromParent();
 
+    // `llvm.ident` named metadata also gets duplicated.
+    auto *llvmIdent = (*MOrErr)->getNamedMetadata("llvm.ident");
+    if (llvmIdent)
+      llvmIdent->eraseFromParent();
+
     return MOrErr;
   };
   bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
diff --git a/tests/codegen/llvm-ident.rs b/tests/codegen/llvm-ident.rs
new file mode 100644
index 00000000000..927f0d602ad
--- /dev/null
+++ b/tests/codegen/llvm-ident.rs
@@ -0,0 +1,15 @@
+// Verifies that the `!llvm.ident` named metadata is emitted.
+//
+// revisions: NONE OPT DEBUG
+//
+// [OPT] compile-flags: -Copt-level=2
+// [DEBUG] compile-flags: -Cdebuginfo=2
+
+// The named metadata should contain a single metadata node (see
+// `LLVMRustPrepareThinLTOImport` for details).
+// CHECK: !llvm.ident = !{![[ID:[0-9]+]]}
+
+// In addition, check that the metadata node has the expected content.
+// CHECK: ![[ID]] = !{!"rustc version 1.{{.*}}"}
+
+fn main() {}
diff --git a/tests/run-make/comment-section/Makefile b/tests/run-make/comment-section/Makefile
new file mode 100644
index 00000000000..9f810063cc8
--- /dev/null
+++ b/tests/run-make/comment-section/Makefile
@@ -0,0 +1,15 @@
+include ../tools.mk
+
+# only-linux
+
+all:
+	echo 'fn main(){}' | $(RUSTC) - --emit=link,obj -Csave-temps --target=$(TARGET)
+
+	# Check linked output has a `.comment` section with the expected content.
+	readelf -p '.comment' $(TMPDIR)/rust_out | $(CGREP) -F 'rustc version 1.'
+
+	# Check all object files (including temporary outputs) have a `.comment`
+	# section with the expected content.
+	set -e; for f in $(TMPDIR)/*.o; do \
+		readelf -p '.comment' $$f | $(CGREP) -F 'rustc version 1.'; \
+	done
diff --git a/tests/run-make/llvm-ident/Makefile b/tests/run-make/llvm-ident/Makefile
new file mode 100644
index 00000000000..e583e6018e0
--- /dev/null
+++ b/tests/run-make/llvm-ident/Makefile
@@ -0,0 +1,19 @@
+include ../tools.mk
+
+# only-linux
+
+all:
+	# `-Ccodegen-units=16 -Copt-level=2` is used here to trigger thin LTO
+	# across codegen units to test deduplication of the named metadata
+	# (see `LLVMRustPrepareThinLTOImport` for details).
+	echo 'fn main(){}' | $(RUSTC) - --emit=link,obj -Csave-temps -Ccodegen-units=16 -Copt-level=2 --target=$(TARGET)
+
+	# `llvm-dis` is used here since `--emit=llvm-ir` does not emit LLVM IR
+	# for temporary outputs.
+	"$(LLVM_BIN_DIR)"/llvm-dis $(TMPDIR)/*.bc
+
+	# Check LLVM IR files (including temporary outputs) have `!llvm.ident`
+	# named metadata, reusing the related codegen test.
+	set -e; for f in $(TMPDIR)/*.ll; do \
+		$(LLVM_FILECHECK) --input-file $$f ../../codegen/llvm-ident.rs; \
+	done