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
This commit is contained in:
commit
2a06022951
9 changed files with 58 additions and 25 deletions
|
@ -364,6 +364,7 @@ pub fn const_alloc_to_gcc<'gcc>(
|
||||||
llvals.push(cx.const_bytes(bytes));
|
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)
|
cx.const_struct(&llvals, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,12 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
|
||||||
append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range);
|
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>(
|
fn codegen_static_initializer<'ll, 'tcx>(
|
||||||
|
|
27
tests/assembly/cstring-merging.rs
Normal file
27
tests/assembly/cstring-merging.rs
Normal file
|
@ -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"
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
const LUT: [u8; 2] = [1, 1];
|
const LUT: [u8; 4] = [1, 1, 1, 1];
|
||||||
|
|
||||||
// CHECK-LABEL: @decode
|
// CHECK-LABEL: @decode
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -11,5 +11,5 @@ pub fn decode(i: u8) -> u8 {
|
||||||
// CHECK-NEXT: icmp
|
// CHECK-NEXT: icmp
|
||||||
// CHECK-NEXT: select
|
// CHECK-NEXT: select
|
||||||
// CHECK-NEXT: ret
|
// CHECK-NEXT: ret
|
||||||
if i < 2 { LUT[i as usize] } else { 2 }
|
if i < 4 { LUT[i as usize] } else { 2 }
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
|
// 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.
|
// 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.3 = private constant <{
|
||||||
// CHECK: @vtable.4 = private constant <{
|
// CHECK: @vtable.4 = private constant <{
|
||||||
|
|
||||||
|
|
|
@ -6,72 +6,72 @@
|
||||||
// `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
|
// `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
|
||||||
// definitions
|
// definitions
|
||||||
|
|
||||||
// CHECK: @A = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @A = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static A: u8 = 0;
|
static A: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @B = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @B = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut B: u8 = 0;
|
static mut B: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @C = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @C = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static C: u8 = 0;
|
pub static C: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @D = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @D = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut D: u8 = 0;
|
pub static mut D: u8 = 0;
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
// CHECK: @E = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @E = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static E: u8 = 0;
|
static E: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @F = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @F = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut F: u8 = 0;
|
static mut F: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @G = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @G = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static G: u8 = 0;
|
pub static G: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @H = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @H = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut H: u8 = 0;
|
pub static mut H: u8 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HIDDEN: () = {
|
const HIDDEN: () = {
|
||||||
// CHECK: @I = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @I = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static I: u8 = 0;
|
static I: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @J = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @J = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut J: u8 = 0;
|
static mut J: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @K = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @K = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static K: u8 = 0;
|
pub static K: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @L = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @L = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut L: u8 = 0;
|
pub static mut L: u8 = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn x() {
|
fn x() {
|
||||||
// CHECK: @M = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @M = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static M: fn() = x;
|
static M: fn() = x;
|
||||||
|
|
||||||
// CHECK: @N = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @N = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut N: u8 = 0;
|
static mut N: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @O = {{(dso_local )?}}local_unnamed_addr constant
|
// CHECK-DAG: @O = {{(dso_local )?}}local_unnamed_addr constant
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static O: u8 = 0;
|
pub static O: u8 = 0;
|
||||||
|
|
||||||
// CHECK: @P = {{(dso_local )?}}local_unnamed_addr global
|
// CHECK-DAG: @P = {{(dso_local )?}}local_unnamed_addr global
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut P: u8 = 0;
|
pub static mut P: u8 = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![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]
|
#[no_mangle]
|
||||||
#[link_section = ".test_one"]
|
#[link_section = ".test_one"]
|
||||||
#[cfg(target_endian = "little")]
|
#[cfg(target_endian = "little")]
|
||||||
|
|
|
@ -12,7 +12,7 @@ mod aux_mod;
|
||||||
include!("aux_mod.rs");
|
include!("aux_mod.rs");
|
||||||
|
|
||||||
// Here we check that the expansion of the file!() macro is mapped.
|
// 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!();
|
pub static FILE_PATH: &'static str = file!();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -11,15 +11,15 @@ pub struct PartiallyUninit {
|
||||||
y: MaybeUninit<[u8; 10]>,
|
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
|
// 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
|
// This shouldn't contain undef, since it contains more chunks
|
||||||
// than the default value of uninit_const_chunk_threshold.
|
// 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
|
// CHECK-LABEL: @fully_uninit
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue