about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-03-28 10:18:32 +0000
committerbors <bors@rust-lang.org>2025-03-28 10:18:32 +0000
commit2a06022951893fe5b5384f8dbd75b4e6e3b5cee0 (patch)
treec03e2eb1cf5ee8a760a01e53b150b74c033bc4b6
parente77a8f439cc87c5d67b007e9811578533de1de91 (diff)
parent5c82a59bd30815a942b64fa09e22dbe442edf56d (diff)
downloadrust-2a06022951893fe5b5384f8dbd75b4e6e3b5cee0.tar.gz
rust-2a06022951893fe5b5384f8dbd75b4e6e3b5cee0.zip
Auto merge of #138503 - bjorn3:string_merging, r=tmiasko
Avoid wrapping constant allocations in packed structs when not necessary

This way LLVM will set the string merging flag if the alloc is a nul terminated string, reducing binary sizes.

try-job: armhf-gnu
-rw-r--r--compiler/rustc_codegen_gcc/src/consts.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs7
-rw-r--r--tests/assembly/cstring-merging.rs27
-rw-r--r--tests/codegen/const-array.rs4
-rw-r--r--tests/codegen/debug-vtable.rs2
-rw-r--r--tests/codegen/external-no-mangle-statics.rs32
-rw-r--r--tests/codegen/link_section.rs2
-rw-r--r--tests/codegen/remap_path_prefix/main.rs2
-rw-r--r--tests/codegen/uninit-consts.rs6
9 files changed, 58 insertions, 25 deletions
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index c514b7a428b..474475f311f 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -364,6 +364,7 @@ pub fn const_alloc_to_gcc<'gcc>(
         llvals.push(cx.const_bytes(bytes));
     }
 
+    // FIXME(bjorn3) avoid wrapping in a struct when there is only a single element.
     cx.const_struct(&llvals, true)
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 62fa2884e0f..7675e75338a 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -129,7 +129,12 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
         append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range);
     }
 
-    cx.const_struct(&llvals, true)
+    // Avoid wrapping in a struct if there is only a single value. This ensures
+    // that LLVM is able to perform the string merging optimization if the constant
+    // is a valid C string. LLVM only considers bare arrays for this optimization,
+    // not arrays wrapped in a struct. LLVM handles this at:
+    // https://github.com/rust-lang/llvm-project/blob/acaea3d2bb8f351b740db7ebce7d7a40b9e21488/llvm/lib/Target/TargetLoweringObjectFile.cpp#L249-L280
+    if let &[data] = &*llvals { data } else { cx.const_struct(&llvals, true) }
 }
 
 fn codegen_static_initializer<'ll, 'tcx>(
diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs
new file mode 100644
index 00000000000..7436e241823
--- /dev/null
+++ b/tests/assembly/cstring-merging.rs
@@ -0,0 +1,27 @@
+//@ only-linux
+//@ assembly-output: emit-asm
+//@ compile-flags: --crate-type=lib -Copt-level=3 --edition 2024
+
+use std::ffi::CStr;
+
+// CHECK: .section .rodata.str1.1,"aMS"
+// CHECK: .Lanon.{{.+}}:
+// CHECK-NEXT: .asciz "foo"
+#[unsafe(no_mangle)]
+static CSTR: &[u8; 4] = b"foo\0";
+
+// CHECK-NOT: .section
+// CHECK: .Lanon.{{.+}}:
+// CHECK-NEXT: .asciz "bar"
+#[unsafe(no_mangle)]
+pub fn cstr() -> &'static CStr {
+    c"bar"
+}
+
+// CHECK-NOT: .section
+// CHECK: .Lanon.{{.+}}:
+// CHECK-NEXT: .asciz "baz"
+#[unsafe(no_mangle)]
+pub fn manual_cstr() -> &'static str {
+    "baz\0"
+}
diff --git a/tests/codegen/const-array.rs b/tests/codegen/const-array.rs
index e257d8acc08..b3df76c3d8e 100644
--- a/tests/codegen/const-array.rs
+++ b/tests/codegen/const-array.rs
@@ -2,7 +2,7 @@
 
 #![crate_type = "lib"]
 
-const LUT: [u8; 2] = [1, 1];
+const LUT: [u8; 4] = [1, 1, 1, 1];
 
 // CHECK-LABEL: @decode
 #[no_mangle]
@@ -11,5 +11,5 @@ pub fn decode(i: u8) -> u8 {
     // CHECK-NEXT: icmp
     // CHECK-NEXT: select
     // CHECK-NEXT: ret
-    if i < 2 { LUT[i as usize] } else { 2 }
+    if i < 4 { LUT[i as usize] } else { 2 }
 }
diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs
index b9808e4079b..8a7b1cc3c4b 100644
--- a/tests/codegen/debug-vtable.rs
+++ b/tests/codegen/debug-vtable.rs
@@ -15,7 +15,7 @@
 
 // Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
 // This helps debuggers more reliably map from dyn pointer to concrete type.
-// CHECK: @vtable.2 = private constant <{
+// CHECK: @vtable.2 = private constant [
 // CHECK: @vtable.3 = private constant <{
 // CHECK: @vtable.4 = private constant <{
 
diff --git a/tests/codegen/external-no-mangle-statics.rs b/tests/codegen/external-no-mangle-statics.rs
index dc4eca8c7b4..49f42ee977d 100644
--- a/tests/codegen/external-no-mangle-statics.rs
+++ b/tests/codegen/external-no-mangle-statics.rs
@@ -6,72 +6,72 @@
 // `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
 // definitions
 
-// CHECK: @A = {{(dso_local )?}}local_unnamed_addr constant
+// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant
 #[no_mangle]
 static A: u8 = 0;
 
-// CHECK: @B = {{(dso_local )?}}local_unnamed_addr global
+// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global
 #[no_mangle]
 static mut B: u8 = 0;
 
-// CHECK: @C = {{(dso_local )?}}local_unnamed_addr constant
+// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant
 #[no_mangle]
 pub static C: u8 = 0;
 
-// CHECK: @D = {{(dso_local )?}}local_unnamed_addr global
+// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global
 #[no_mangle]
 pub static mut D: u8 = 0;
 
 mod private {
-    // CHECK: @E = {{(dso_local )?}}local_unnamed_addr constant
+    // CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     static E: u8 = 0;
 
-    // CHECK: @F = {{(dso_local )?}}local_unnamed_addr global
+    // CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     static mut F: u8 = 0;
 
-    // CHECK: @G = {{(dso_local )?}}local_unnamed_addr constant
+    // CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     pub static G: u8 = 0;
 
-    // CHECK: @H = {{(dso_local )?}}local_unnamed_addr global
+    // CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     pub static mut H: u8 = 0;
 }
 
 const HIDDEN: () = {
-    // CHECK: @I = {{(dso_local )?}}local_unnamed_addr constant
+    // CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     static I: u8 = 0;
 
-    // CHECK: @J = {{(dso_local )?}}local_unnamed_addr global
+    // CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     static mut J: u8 = 0;
 
-    // CHECK: @K = {{(dso_local )?}}local_unnamed_addr constant
+    // CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     pub static K: u8 = 0;
 
-    // CHECK: @L = {{(dso_local )?}}local_unnamed_addr global
+    // CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     pub static mut L: u8 = 0;
 };
 
 fn x() {
-    // CHECK: @M = {{(dso_local )?}}local_unnamed_addr constant
+    // CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     static M: fn() = x;
 
-    // CHECK: @N = {{(dso_local )?}}local_unnamed_addr global
+    // CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     static mut N: u8 = 0;
 
-    // CHECK: @O = {{(dso_local )?}}local_unnamed_addr constant
+    // CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     pub static O: u8 = 0;
 
-    // CHECK: @P = {{(dso_local )?}}local_unnamed_addr global
+    // CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     pub static mut P: u8 = 0;
 }
diff --git a/tests/codegen/link_section.rs b/tests/codegen/link_section.rs
index 196f5edb7d6..f62f6948079 100644
--- a/tests/codegen/link_section.rs
+++ b/tests/codegen/link_section.rs
@@ -3,7 +3,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK: @VAR1 = {{(dso_local )?}}constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
+// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one"
 #[no_mangle]
 #[link_section = ".test_one"]
 #[cfg(target_endian = "little")]
diff --git a/tests/codegen/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs
index bfbccfe0df8..7d17b3b67cf 100644
--- a/tests/codegen/remap_path_prefix/main.rs
+++ b/tests/codegen/remap_path_prefix/main.rs
@@ -12,7 +12,7 @@ mod aux_mod;
 include!("aux_mod.rs");
 
 // Here we check that the expansion of the file!() macro is mapped.
-// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>
+// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant [34 x i8] c"/the/src/remap_path_prefix/main.rs"
 pub static FILE_PATH: &'static str = file!();
 
 fn main() {
diff --git a/tests/codegen/uninit-consts.rs b/tests/codegen/uninit-consts.rs
index a58008e171e..bde71a35c47 100644
--- a/tests/codegen/uninit-consts.rs
+++ b/tests/codegen/uninit-consts.rs
@@ -11,15 +11,15 @@ pub struct PartiallyUninit {
     y: MaybeUninit<[u8; 10]>,
 }
 
-// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant <{ [10 x i8] }> undef
+// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant [10 x i8] undef
 
 // CHECK: [[PARTIALLY_UNINIT:@.*]] = private unnamed_addr constant <{ [4 x i8], [12 x i8] }> <{ [4 x i8] c"{{\\EF\\BE\\AD\\DE|\\DE\\AD\\BE\\EF}}", [12 x i8] undef }>, align 4
 
 // This shouldn't contain undef, since it contains more chunks
 // than the default value of uninit_const_chunk_threshold.
-// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant <{ [32768 x i8] }> <{ [32768 x i8] c"{{.+}}" }>, align 4
+// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant [32768 x i8] c"{{.+}}", align 4
 
-// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant <{ [16384 x i8] }> undef
+// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant [16384 x i8] undef
 
 // CHECK-LABEL: @fully_uninit
 #[no_mangle]