Skip to content

Commit 57a2597

Browse files
committed
Auto merge of rust-lang#123425 - jieyouxu:array-imm-noundef-param, r=davidtwco,DianQK
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 1dea922 + 6bf21cf commit 57a2597

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed

compiler/rustc_ty_utils/src/abi.rs

+31-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,21 @@ 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. Note that `#[repr(transparent)]`
791+
// can contain other `#[repr(transparent)]` structs or enums, which can eventually
792+
// contain an array!
793+
if arg.layout.ty.is_array() || is_transparent_array(cx, arg.layout) {
794+
// Fixup arg attribute with `noundef`.
795+
let PassMode::Cast { ref mut cast, .. } = &mut arg.mode else {
796+
bug!("this cannot fail because of the previous cast_to `Reg`");
797+
};
798+
799+
let box CastTarget { ref mut attrs, .. } = cast;
800+
attrs.set(ArgAttribute::NoUndef);
801+
}
787802
}
788803

789804
// If we deduced that this parameter was read-only, add that to the attribute list now.
@@ -819,6 +834,20 @@ fn fn_abi_adjust_for_abi<'tcx>(
819834
Ok(())
820835
}
821836

837+
fn is_transparent_array<'tcx>(
838+
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
839+
outermost_layout: TyAndLayout<'tcx>,
840+
) -> bool {
841+
let mut adt_layout = outermost_layout;
842+
// Recursively walk a layout, seeing through all `#[repr(transparent)]` layers.
843+
while adt_layout.is_transparent::<LayoutCx<'tcx, TyCtxt<'tcx>>>()
844+
&& let Some((_, layout)) = adt_layout.non_1zst_field(cx)
845+
{
846+
adt_layout = layout;
847+
}
848+
adt_layout.ty.is_array()
849+
}
850+
822851
#[tracing::instrument(level = "debug", skip(cx))]
823852
fn make_thin_self_ptr<'tcx>(
824853
cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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+
//@ only-64bit (presence of noundef depends on pointer width)
7+
//@ compile-flags: -C no-prepopulate-passes -O
8+
#![crate_type = "lib"]
9+
10+
// CHECK: define noundef i64 @short_array_u64x1(i64 noundef %{{.*}})
11+
#[no_mangle]
12+
pub fn short_array_u64x1(v: [u64; 1]) -> [u64; 1] {
13+
v
14+
}
15+
16+
// CHECK: define noundef i32 @short_array_u32x1(i32 noundef %{{.*}})
17+
#[no_mangle]
18+
pub fn short_array_u32x1(v: [u32; 1]) -> [u32; 1] {
19+
v
20+
}
21+
22+
// CHECK: define noundef i64 @short_array_u32x2(i64 noundef %{{.*}})
23+
#[no_mangle]
24+
pub fn short_array_u32x2(v: [u32; 2]) -> [u32; 2] {
25+
v
26+
}
27+
28+
// CHECK: define noundef i16 @short_array_u16x1(i16 noundef %{{.*}})
29+
#[no_mangle]
30+
pub fn short_array_u16x1(v: [u16; 1]) -> [u16; 1] {
31+
v
32+
}
33+
34+
// CHECK: define noundef i32 @short_array_u16x2(i32 noundef %{{.*}})
35+
#[no_mangle]
36+
pub fn short_array_u16x2(v: [u16; 2]) -> [u16; 2] {
37+
v
38+
}
39+
40+
// CHECK: define noundef i48 @short_array_u16x3(i48 noundef %{{.*}})
41+
#[no_mangle]
42+
pub fn short_array_u16x3(v: [u16; 3]) -> [u16; 3] {
43+
v
44+
}
45+
46+
// CHECK: define noundef i64 @short_array_u16x4(i64 noundef %{{.*}})
47+
#[no_mangle]
48+
pub fn short_array_u16x4(v: [u16; 4]) -> [u16; 4] {
49+
v
50+
}
51+
52+
// CHECK: define noundef i8 @short_array_u8x1(i8 noundef %{{.*}})
53+
#[no_mangle]
54+
pub fn short_array_u8x1(v: [u8; 1]) -> [u8; 1] {
55+
v
56+
}
57+
58+
// CHECK: define noundef i16 @short_array_u8x2(i16 noundef %{{.*}})
59+
#[no_mangle]
60+
pub fn short_array_u8x2(v: [u8; 2]) -> [u8; 2] {
61+
v
62+
}
63+
64+
// CHECK: define noundef i24 @short_array_u8x3(i24 noundef %{{.*}})
65+
#[no_mangle]
66+
pub fn short_array_u8x3(v: [u8; 3]) -> [u8; 3] {
67+
v
68+
}
69+
70+
// CHECK: define noundef i64 @short_array_u8x8(i64 noundef %{{.*}})
71+
#[no_mangle]
72+
pub fn short_array_u8x8(v: [u8; 8]) -> [u8; 8] {
73+
v
74+
}
75+
76+
#[repr(transparent)]
77+
pub struct Foo([u8; 4]);
78+
79+
// CHECK: define noundef i32 @repr_transparent_struct_short_array(i32 noundef %{{.*}})
80+
#[no_mangle]
81+
pub fn repr_transparent_struct_short_array(v: Foo) -> Foo {
82+
v
83+
}
84+
85+
#[repr(transparent)]
86+
pub enum Bar {
87+
Default([u8; 4]),
88+
}
89+
90+
// CHECK: define noundef i32 @repr_transparent_enum_short_array(i32 noundef %{{.*}})
91+
#[no_mangle]
92+
pub fn repr_transparent_enum_short_array(v: Bar) -> Bar {
93+
v
94+
}
95+
96+
#[repr(transparent)]
97+
pub struct Owo([u8; 4]);
98+
99+
#[repr(transparent)]
100+
pub struct Uwu(Owo);
101+
102+
#[repr(transparent)]
103+
pub struct Oowoo(Uwu);
104+
105+
// CHECK: define noundef i32 @repr_transparent_nested_struct_short_array(i32 noundef %{{.*}})
106+
#[no_mangle]
107+
pub fn repr_transparent_nested_struct_short_array(v: Oowoo) -> Oowoo {
108+
v
109+
}
110+
111+
// # Negative examples
112+
113+
// This inner struct is *not* `#[repr(transparent)]`, so we must not emit `noundef` for the outer
114+
// struct.
115+
pub struct NotTransparent([u8; 4]);
116+
117+
#[repr(transparent)]
118+
pub struct Transparent(NotTransparent);
119+
120+
// CHECK-LABEL: not_all_transparent_nested_struct_short_array
121+
// CHECK-NOT: noundef
122+
#[no_mangle]
123+
pub fn not_all_transparent_nested_struct_short_array(v: Transparent) -> Transparent {
124+
v
125+
}

0 commit comments

Comments
 (0)