Skip to content

Commit 2a06022

Browse files
committed
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
2 parents e77a8f4 + 5c82a59 commit 2a06022

File tree

9 files changed

+58
-25
lines changed

9 files changed

+58
-25
lines changed

compiler/rustc_codegen_gcc/src/consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ pub fn const_alloc_to_gcc<'gcc>(
364364
llvals.push(cx.const_bytes(bytes));
365365
}
366366

367+
// FIXME(bjorn3) avoid wrapping in a struct when there is only a single element.
367368
cx.const_struct(&llvals, true)
368369
}
369370

compiler/rustc_codegen_llvm/src/consts.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,12 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
129129
append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range);
130130
}
131131

132-
cx.const_struct(&llvals, true)
132+
// Avoid wrapping in a struct if there is only a single value. This ensures
133+
// that LLVM is able to perform the string merging optimization if the constant
134+
// is a valid C string. LLVM only considers bare arrays for this optimization,
135+
// not arrays wrapped in a struct. LLVM handles this at:
136+
// https://github.com/rust-lang/llvm-project/blob/acaea3d2bb8f351b740db7ebce7d7a40b9e21488/llvm/lib/Target/TargetLoweringObjectFile.cpp#L249-L280
137+
if let &[data] = &*llvals { data } else { cx.const_struct(&llvals, true) }
133138
}
134139

135140
fn codegen_static_initializer<'ll, 'tcx>(

tests/assembly/cstring-merging.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//@ only-linux
2+
//@ assembly-output: emit-asm
3+
//@ compile-flags: --crate-type=lib -Copt-level=3 --edition 2024
4+
5+
use std::ffi::CStr;
6+
7+
// CHECK: .section .rodata.str1.1,"aMS"
8+
// CHECK: .Lanon.{{.+}}:
9+
// CHECK-NEXT: .asciz "foo"
10+
#[unsafe(no_mangle)]
11+
static CSTR: &[u8; 4] = b"foo\0";
12+
13+
// CHECK-NOT: .section
14+
// CHECK: .Lanon.{{.+}}:
15+
// CHECK-NEXT: .asciz "bar"
16+
#[unsafe(no_mangle)]
17+
pub fn cstr() -> &'static CStr {
18+
c"bar"
19+
}
20+
21+
// CHECK-NOT: .section
22+
// CHECK: .Lanon.{{.+}}:
23+
// CHECK-NEXT: .asciz "baz"
24+
#[unsafe(no_mangle)]
25+
pub fn manual_cstr() -> &'static str {
26+
"baz\0"
27+
}

tests/codegen/const-array.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#![crate_type = "lib"]
44

5-
const LUT: [u8; 2] = [1, 1];
5+
const LUT: [u8; 4] = [1, 1, 1, 1];
66

77
// CHECK-LABEL: @decode
88
#[no_mangle]
@@ -11,5 +11,5 @@ pub fn decode(i: u8) -> u8 {
1111
// CHECK-NEXT: icmp
1212
// CHECK-NEXT: select
1313
// CHECK-NEXT: ret
14-
if i < 2 { LUT[i as usize] } else { 2 }
14+
if i < 4 { LUT[i as usize] } else { 2 }
1515
}

tests/codegen/debug-vtable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
1717
// This helps debuggers more reliably map from dyn pointer to concrete type.
18-
// CHECK: @vtable.2 = private constant <{
18+
// CHECK: @vtable.2 = private constant [
1919
// CHECK: @vtable.3 = private constant <{
2020
// CHECK: @vtable.4 = private constant <{
2121

tests/codegen/external-no-mangle-statics.rs

+16-16
Original file line numberDiff line numberDiff line change
@@ -6,72 +6,72 @@
66
// `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
77
// definitions
88

9-
// CHECK: @A = {{(dso_local )?}}local_unnamed_addr constant
9+
// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant
1010
#[no_mangle]
1111
static A: u8 = 0;
1212

13-
// CHECK: @B = {{(dso_local )?}}local_unnamed_addr global
13+
// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global
1414
#[no_mangle]
1515
static mut B: u8 = 0;
1616

17-
// CHECK: @C = {{(dso_local )?}}local_unnamed_addr constant
17+
// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant
1818
#[no_mangle]
1919
pub static C: u8 = 0;
2020

21-
// CHECK: @D = {{(dso_local )?}}local_unnamed_addr global
21+
// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global
2222
#[no_mangle]
2323
pub static mut D: u8 = 0;
2424

2525
mod private {
26-
// CHECK: @E = {{(dso_local )?}}local_unnamed_addr constant
26+
// CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant
2727
#[no_mangle]
2828
static E: u8 = 0;
2929

30-
// CHECK: @F = {{(dso_local )?}}local_unnamed_addr global
30+
// CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global
3131
#[no_mangle]
3232
static mut F: u8 = 0;
3333

34-
// CHECK: @G = {{(dso_local )?}}local_unnamed_addr constant
34+
// CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant
3535
#[no_mangle]
3636
pub static G: u8 = 0;
3737

38-
// CHECK: @H = {{(dso_local )?}}local_unnamed_addr global
38+
// CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global
3939
#[no_mangle]
4040
pub static mut H: u8 = 0;
4141
}
4242

4343
const HIDDEN: () = {
44-
// CHECK: @I = {{(dso_local )?}}local_unnamed_addr constant
44+
// CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant
4545
#[no_mangle]
4646
static I: u8 = 0;
4747

48-
// CHECK: @J = {{(dso_local )?}}local_unnamed_addr global
48+
// CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global
4949
#[no_mangle]
5050
static mut J: u8 = 0;
5151

52-
// CHECK: @K = {{(dso_local )?}}local_unnamed_addr constant
52+
// CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant
5353
#[no_mangle]
5454
pub static K: u8 = 0;
5555

56-
// CHECK: @L = {{(dso_local )?}}local_unnamed_addr global
56+
// CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global
5757
#[no_mangle]
5858
pub static mut L: u8 = 0;
5959
};
6060

6161
fn x() {
62-
// CHECK: @M = {{(dso_local )?}}local_unnamed_addr constant
62+
// CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant
6363
#[no_mangle]
6464
static M: fn() = x;
6565

66-
// CHECK: @N = {{(dso_local )?}}local_unnamed_addr global
66+
// CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global
6767
#[no_mangle]
6868
static mut N: u8 = 0;
6969

70-
// CHECK: @O = {{(dso_local )?}}local_unnamed_addr constant
70+
// CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant
7171
#[no_mangle]
7272
pub static O: u8 = 0;
7373

74-
// CHECK: @P = {{(dso_local )?}}local_unnamed_addr global
74+
// CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global
7575
#[no_mangle]
7676
pub static mut P: u8 = 0;
7777
}

tests/codegen/link_section.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#![crate_type = "lib"]
55

6-
// CHECK: @VAR1 = {{(dso_local )?}}constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
6+
// CHECK: @VAR1 = {{(dso_local )?}}constant [4 x i8] c"\01\00\00\00", section ".test_one"
77
#[no_mangle]
88
#[link_section = ".test_one"]
99
#[cfg(target_endian = "little")]

tests/codegen/remap_path_prefix/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod aux_mod;
1212
include!("aux_mod.rs");
1313

1414
// Here we check that the expansion of the file!() macro is mapped.
15-
// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>
15+
// CHECK: @alloc_5761061597a97f66e13ef2ff92712c4b = private unnamed_addr constant [34 x i8] c"/the/src/remap_path_prefix/main.rs"
1616
pub static FILE_PATH: &'static str = file!();
1717

1818
fn main() {

tests/codegen/uninit-consts.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ pub struct PartiallyUninit {
1111
y: MaybeUninit<[u8; 10]>,
1212
}
1313

14-
// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant <{ [10 x i8] }> undef
14+
// CHECK: [[FULLY_UNINIT:@.*]] = private unnamed_addr constant [10 x i8] undef
1515

1616
// 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
1717

1818
// This shouldn't contain undef, since it contains more chunks
1919
// than the default value of uninit_const_chunk_threshold.
20-
// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant <{ [32768 x i8] }> <{ [32768 x i8] c"{{.+}}" }>, align 4
20+
// CHECK: [[UNINIT_PADDING_HUGE:@.*]] = private unnamed_addr constant [32768 x i8] c"{{.+}}", align 4
2121

22-
// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant <{ [16384 x i8] }> undef
22+
// CHECK: [[FULLY_UNINIT_HUGE:@.*]] = private unnamed_addr constant [16384 x i8] undef
2323

2424
// CHECK-LABEL: @fully_uninit
2525
#[no_mangle]

0 commit comments

Comments
 (0)