diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 52ffc321cbb6f..1a58d3754eb65 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -159,7 +159,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Furthermore, `align >= unsized_align`, and therefore we only need to do: // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align); - let full_size = bx.add(unsized_offset_unadjusted, unsized_size); + let unrounded_size = bx.unchecked_suadd(unsized_offset_unadjusted, unsized_size); // Issue #27023: must add any necessary padding to `size` // (to make it a multiple of `align`) before returning it. @@ -173,10 +173,14 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // `(size + (align-1)) & -align` let one = bx.const_usize(1); let addend = bx.sub(full_align, one); - let add = bx.add(full_size, addend); + let add = bx.add(unrounded_size, addend); let neg = bx.neg(full_align); let full_size = bx.and(add, neg); + // `round_up(x, a) >= x` for pow2 `a` (#152788). + let size_ge = bx.icmp(IntPredicate::IntUGE, full_size, unrounded_size); + bx.assume(size_ge); + (full_size, full_align) } _ => bug!("size_and_align_of_dst: {t} not supported"), diff --git a/tests/codegen-llvm/dst-size-of-val-not-zst.rs b/tests/codegen-llvm/dst-size-of-val-not-zst.rs new file mode 100644 index 0000000000000..6a5df6c2b44a3 --- /dev/null +++ b/tests/codegen-llvm/dst-size-of-val-not-zst.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ min-llvm-version: 21 +//@ needs-deterministic-layouts + +// Regression test for #152788. + +#![crate_type = "lib"] + +pub struct Foo(pub [u32; 3], pub T); + +// CHECK-LABEL: @size_of_val_dyn_not_zero +#[no_mangle] +pub fn size_of_val_dyn_not_zero(p: &Foo) -> bool { + // CHECK: ret i1 false + std::mem::size_of_val(p) == 0 +} + +// CHECK-LABEL: @size_of_val_slice_u8_not_zero +#[no_mangle] +pub fn size_of_val_slice_u8_not_zero(p: &Foo<[u8]>) -> bool { + // CHECK: ret i1 false + std::mem::size_of_val(p) == 0 +} + +// CHECK-LABEL: @size_of_val_slice_i32_not_zero +#[no_mangle] +pub fn size_of_val_slice_i32_not_zero(p: &Foo<[i32]>) -> bool { + // CHECK: ret i1 false + std::mem::size_of_val(p) == 0 +} diff --git a/tests/codegen-llvm/dst-vtable-align-1-elide-check.rs b/tests/codegen-llvm/dst-vtable-align-1-elide-check.rs new file mode 100644 index 0000000000000..8c94034969100 --- /dev/null +++ b/tests/codegen-llvm/dst-vtable-align-1-elide-check.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled +//@ min-llvm-version: 21 + +#![crate_type = "lib"] + +pub trait Trait { + fn f(&self); +} + +pub struct WrapperWithAlign1 { + x: u8, + y: T, +} + +pub struct Struct { + _field: i8, + dst: W, +} + +// CHECK-LABEL: @eliminates_runtime_check_when_align_1 +#[no_mangle] +pub fn eliminates_runtime_check_when_align_1( + x: &Struct>, +) -> &WrapperWithAlign1 { + // CHECK: load i{{[0-9]+}}, {{.+}} !range + // CHECK-NOT: llvm.umax + // CHECK-NOT: select + // CHECK: ret + &x.dst +} diff --git a/tests/codegen-llvm/dst-vtable-align-nonzero.rs b/tests/codegen-llvm/dst-vtable-align-nonzero.rs index 2eee91876683c..fbe2e7cf55571 100644 --- a/tests/codegen-llvm/dst-vtable-align-nonzero.rs +++ b/tests/codegen-llvm/dst-vtable-align-nonzero.rs @@ -3,18 +3,13 @@ #![crate_type = "lib"] #![feature(core_intrinsics)] -// This test checks that we annotate alignment loads from vtables with nonzero range metadata, -// and that this allows LLVM to eliminate redundant `align >= 1` checks. +// This test checks that we annotate alignment loads from vtables with nonzero range metadata. +// The companion LLVM-21-only fold check lives in `dst-vtable-align-1-elide-check.rs`. pub trait Trait { fn f(&self); } -pub struct WrapperWithAlign1 { - x: u8, - y: T, -} - pub struct WrapperWithAlign2 { x: u16, y: T, @@ -25,25 +20,11 @@ pub struct Struct { dst: W, } -// CHECK-LABEL: @eliminates_runtime_check_when_align_1 -#[no_mangle] -pub fn eliminates_runtime_check_when_align_1( - x: &Struct>, -) -> &WrapperWithAlign1 { - // CHECK: load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]] - // CHECK-NOT: llvm.umax - // CHECK-NOT: icmp - // CHECK-NOT: select - // CHECK: ret - &x.dst -} - // CHECK-LABEL: @does_not_eliminate_runtime_check_when_align_2 #[no_mangle] pub fn does_not_eliminate_runtime_check_when_align_2( x: &Struct>, ) -> &WrapperWithAlign2 { - // CHECK: [[X0:%[0-9]+]] = load [[USIZE]], {{.+}} !range [[RANGE_META]] // CHECK: {{icmp|llvm.umax}} // CHECK: ret &x.dst @@ -52,7 +33,7 @@ pub fn does_not_eliminate_runtime_check_when_align_2( // CHECK-LABEL: @align_load_from_align_of_val #[no_mangle] pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize { - // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]] + // CHECK: {{%[0-9]+}} = load [[USIZE:i[0-9]+]], {{.+}} !range [[RANGE_META:![0-9]+]] core::mem::align_of_val(x) }