Skip to content

Commit 6be5114

Browse files
committed
Auto merge of rust-lang#123425 - jieyouxu:array-imm-noundef-param, r=<try>
Add `noundef` metadata for fits-in-target-pointer-size array immediate arguments `noundef` is only added if the small array immediate fits in the target pointer size and if optimizations are enabled. Closes rust-lang#123183.
2 parents 98efd80 + 31abdb2 commit 6be5114

File tree

2 files changed

+120
-2
lines changed

2 files changed

+120
-2
lines changed

compiler/rustc_ty_utils/src/abi.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
88
use rustc_session::config::OptLevel;
99
use rustc_span::def_id::DefId;
1010
use rustc_target::abi::call::{
11-
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
12-
RiscvInterruptKind,
11+
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, Conv, FnAbi, PassMode, Reg,
12+
RegKind, RiscvInterruptKind,
1313
};
1414
use rustc_target::abi::*;
1515
use rustc_target::spec::abi::Abi as SpecAbi;
@@ -784,6 +784,29 @@ fn fn_abi_adjust_for_abi<'tcx>(
784784
// an LLVM aggregate type for this leads to bad optimizations,
785785
// so we pick an appropriately sized integer type instead.
786786
arg.cast_to(Reg { kind: RegKind::Integer, size });
787+
788+
// Let's see if we can add a `noundef`. This is only legal for arrays, definitely
789+
// not for unions. This is also legal for `#[repr(transparent)] struct` or
790+
// `#[repr(transparent)] enum` containing array.
791+
let is_transparent_array =
792+
if arg.layout.is_transparent::<LayoutCx<'tcx, TyCtxt<'tcx>>>()
793+
&& let Some((_, layout)) = arg.layout.non_1zst_field(cx)
794+
&& layout.ty.is_array()
795+
{
796+
true
797+
} else {
798+
false
799+
};
800+
801+
if arg.layout.ty.is_array() || is_transparent_array {
802+
// Fixup arg attribute with `noundef`.
803+
let PassMode::Cast { ref mut cast, .. } = &mut arg.mode else {
804+
bug!("this cannot fail because of the previous cast_to `Reg`");
805+
};
806+
807+
let box CastTarget { ref mut attrs, .. } = cast;
808+
attrs.set(ArgAttribute::NoUndef);
809+
}
787810
}
788811

789812
// If we deduced that this parameter was read-only, add that to the attribute list now.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Check that small array immediates that fits in target pointer size in argument position have
2+
// `noundef` parameter metadata. Note that the `noundef` parameter metadata is only applied if:
3+
// - `!arg.layout.is_unsized() && size <= Pointer(AddressSpace::DATA).size(cx)`
4+
// - optimizations are turned on.
5+
//
6+
// ignore-tidy-linelength
7+
//@ only-64bit (presence of noundef depends on pointer width)
8+
//@ compile-flags: -C no-prepopulate-passes -O
9+
#![crate_type = "lib"]
10+
11+
// CHECK: define noundef i64 @replace_short_array_u64x1(ptr noalias noundef align 8 dereferenceable(8) %r, i64 noundef %0)
12+
#[no_mangle]
13+
pub fn replace_short_array_u64x1(r: &mut [u64; 1], v: [u64; 1]) -> [u64; 1] {
14+
std::mem::replace(r, v)
15+
}
16+
17+
// CHECK: define noundef i32 @replace_short_array_u32x1(ptr noalias noundef align 4 dereferenceable(4) %r, i32 noundef %0)
18+
#[no_mangle]
19+
pub fn replace_short_array_u32x1(r: &mut [u32; 1], v: [u32; 1]) -> [u32; 1] {
20+
std::mem::replace(r, v)
21+
}
22+
23+
// CHECK: define noundef i64 @replace_short_array_u32x2(ptr noalias noundef align 4 dereferenceable(8) %r, i64 noundef %0)
24+
#[no_mangle]
25+
pub fn replace_short_array_u32x2(r: &mut [u32; 2], v: [u32; 2]) -> [u32; 2] {
26+
std::mem::replace(r, v)
27+
}
28+
29+
// CHECK: define noundef i16 @replace_short_array_u16x1(ptr noalias noundef align 2 dereferenceable(2) %r, i16 noundef %0)
30+
#[no_mangle]
31+
pub fn replace_short_array_u16x1(r: &mut [u16; 1], v: [u16; 1]) -> [u16; 1] {
32+
std::mem::replace(r, v)
33+
}
34+
35+
// CHECK: define noundef i32 @replace_short_array_u16x2(ptr noalias noundef align 2 dereferenceable(4) %r, i32 noundef %0)
36+
#[no_mangle]
37+
pub fn replace_short_array_u16x2(r: &mut [u16; 2], v: [u16; 2]) -> [u16; 2] {
38+
std::mem::replace(r, v)
39+
}
40+
41+
// CHECK: define noundef i48 @replace_short_array_u16x3(ptr noalias noundef align 2 dereferenceable(6) %r, i48 noundef %0)
42+
#[no_mangle]
43+
pub fn replace_short_array_u16x3(r: &mut [u16; 3], v: [u16; 3]) -> [u16; 3] {
44+
std::mem::replace(r, v)
45+
}
46+
47+
// CHECK: define noundef i64 @replace_short_array_u16x4(ptr noalias noundef align 2 dereferenceable(8) %r, i64 noundef %0)
48+
#[no_mangle]
49+
pub fn replace_short_array_u16x4(r: &mut [u16; 4], v: [u16; 4]) -> [u16; 4] {
50+
std::mem::replace(r, v)
51+
}
52+
53+
// CHECK: define noundef i8 @replace_short_array_u8x1(ptr noalias noundef align 1 dereferenceable(1) %r, i8 noundef %0)
54+
#[no_mangle]
55+
pub fn replace_short_array_u8x1(r: &mut [u8; 1], v: [u8; 1]) -> [u8; 1] {
56+
std::mem::replace(r, v)
57+
}
58+
59+
// CHECK: define noundef i16 @replace_short_array_u8x2(ptr noalias noundef align 1 dereferenceable(2) %r, i16 noundef %0)
60+
#[no_mangle]
61+
pub fn replace_short_array_u8x2(r: &mut [u8; 2], v: [u8; 2]) -> [u8; 2] {
62+
std::mem::replace(r, v)
63+
}
64+
65+
// CHECK: define noundef i24 @replace_short_array_u8x3(ptr noalias noundef align 1 dereferenceable(3) %r, i24 noundef %0)
66+
#[no_mangle]
67+
pub fn replace_short_array_u8x3(r: &mut [u8; 3], v: [u8; 3]) -> [u8; 3] {
68+
std::mem::replace(r, v)
69+
}
70+
71+
// CHECK: define noundef i64 @replace_short_array_u8x8(ptr noalias noundef align 1 dereferenceable(8) %r, i64 noundef %0)
72+
#[no_mangle]
73+
pub fn replace_short_array_u8x8(r: &mut [u8; 8], v: [u8; 8]) -> [u8; 8] {
74+
std::mem::replace(r, v)
75+
}
76+
77+
#[repr(transparent)]
78+
pub struct Foo([u8; 4]);
79+
80+
// CHECK: define noundef i32 @replace_repr_transparent_struct_short_array(ptr noalias noundef align 1 dereferenceable(4) %r, i32 noundef %0)
81+
#[no_mangle]
82+
pub fn replace_repr_transparent_struct_short_array(r: &mut Foo, v: Foo) -> Foo {
83+
std::mem::replace(r, v)
84+
}
85+
86+
#[repr(transparent)]
87+
pub enum Bar {
88+
Default([u8; 4])
89+
}
90+
91+
// CHECK: define noundef i32 @replace_repr_transparent_enum_short_array(ptr noalias noundef align 1 dereferenceable(4) %r, i32 noundef %0)
92+
#[no_mangle]
93+
pub fn replace_repr_transparent_enum_short_array(r: &mut Bar, v: Bar) -> Bar {
94+
std::mem::replace(r, v)
95+
}

0 commit comments

Comments
 (0)