Repository navigation
Description
The following rust
pub struct Foo<T: ?Sized>(pub [u32; 3], pub T);
#[unsafe(no_mangle)]
pub fn demo(p: &Foo<dyn std::fmt::Debug>) -> bool {
std::mem::size_of_val(p) == 0
}currently https://rust.godbolt.org/z/r1d5n6Phe optimizes to
define noundef zeroext i1 @demo(ptr noundef nonnull readnone align 4 captures(none) %p.0, ptr noalias noundef readonly align 8 captures(none) dereferenceable(32) %p.1) unnamed_addr #0 {
start:
%0 = getelementptr inbounds nuw i8, ptr %p.1, i64 8
%1 = load i64, ptr %0, align 8, !range !3, !invariant.load !4
%2 = getelementptr inbounds nuw i8, ptr %p.1, i64 16
%3 = load i64, ptr %2, align 8, !range !5, !invariant.load !4
%4 = tail call i64 @llvm.umax.i64(i64 %3, i64 4)
%5 = add nuw i64 %1, 11
%6 = add i64 %5, %4
%7 = sub i64 0, %4
%8 = and i64 %6, %7
%_0 = icmp eq i64 %8, 0
ret i1 %_0
}but clearly that type has to be at least 12 bytes no matter what.
Why does that matter? Well, whenever you drop a Box it needs to check for ZSTs before calling the allocator. So that check should optimize out in these cases, but it doesn't today.
Filed here because we're probably not telling LLVM enough to be able to do that itself. #152786 will give it a bit more information, but probably not enough to solve this.
For some DSTs it does optimize, notably
pub fn demo_simpleslice(p: &Foo<[i32]>) -> bool {
std::mem::size_of_val(p) == 0
}optimizes to false.
However, this one
pub fn demo_lessalignedslice(p: &Foo<[u8]>) -> bool {
std::mem::size_of_val(p) == 0
}doesn't today https://rust.godbolt.org/z/nnhGKz767
define noundef zeroext i1 @demo_lessalignedslice(ptr noalias noundef readonly align 4 captures(none) dereferenceable(12) %p.0, i64 noundef %p.1) unnamed_addr #0 {
start:
%0 = add i64 %p.1, 15
%_0 = icmp ult i64 %0, 4
ret i1 %_0
}(That last one might get fixed with #152786, though, because the icmp can only be true if it wraps, which definitely can't happen.)
Activity
scottmcm commentedon Feb 18, 2026
Ideas to try:
1..=isize::MIN.unsigned_abs()TKanX commentedon Feb 19, 2026
@rustbot claim
Rollup merge of rust-lang#152843 - TKanX:bugfix/152788-codegen-dst-si…
asquared31415 commentedon Jul 27, 2026
in #159921 I noticed that
&Dstwith a user defined ADT doesn't get range metadata on the length argument, even though slices&[T]do, and so attempted to add that range metadata to all&Dstcases. I found that it significantly regressedsize_of_valcalculations (due to a shortcoming of LLVM, but i'm not sure exactly if or how it should be addressed upstream)In particular the regression is
With my changes to emit range metadata on the length argument, the IR emitted with
no-prepopulate-passesis:(note the range starts at a value low enough to prove that the aligned size after adding the static header will not wrap)
with passes, LLVM "optimizes" that to
The merging of
adds is nice, and thenuw nsw, but thatandis significantly worse, it's the same constant as-4, but with bit 63 cleared. When generating assembly code, LLVM ends up using this same constant, which on x86 is significantly worse.Current codegen without range metadata emits
the
andis a very short instruction, only four bytes in total, using a sign extended one byte immediate.The codegen when adding range metadata does
which uses 11 bytes for the
movabsalone, since it uses a full 8 byte immediate, and it's now using rax and rcx for intermediate calculation, instead of only rax.The range information does allow LLVM to prove the output range, as can be seen in the optimized IR,
range(i64 4, 9223372036854775805)exists on the output. This allows LLVM to optimize this specific case of checking against0orisize::MAX, but it may not be worth the regressions to size calculation.asquared31415 commentedon Jul 27, 2026
Ideally LLVM would propagate the range information on the output without modifying the constant used for the
and, but I'm certain it's not so simple, this transformation is likely useful in some cases.scottmcm commentedon Jul 28, 2026
You should file that as an LLVM issue -- if adding
rangemetadata makes codegen worse, that's something to fix there.(Also be sure to try with LLVM23, hopefully coming very soon.)
EDIT: oh, might just be #149673 aka llvm/llvm-project#196786