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]