@@ -9,8 +9,8 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt};
9
9
use rustc_session:: config:: OptLevel ;
10
10
use rustc_span:: def_id:: DefId ;
11
11
use rustc_target:: abi:: call:: {
12
- ArgAbi , ArgAttribute , ArgAttributes , ArgExtension , Conv , FnAbi , PassMode , Reg , RegKind ,
13
- RiscvInterruptKind ,
12
+ ArgAbi , ArgAttribute , ArgAttributes , ArgExtension , CastTarget , Conv , FnAbi , PassMode , Reg ,
13
+ RegKind , RiscvInterruptKind ,
14
14
} ;
15
15
use rustc_target:: abi:: * ;
16
16
use rustc_target:: spec:: abi:: Abi as SpecAbi ;
@@ -787,6 +787,19 @@ fn fn_abi_adjust_for_abi<'tcx>(
787
787
// an LLVM aggregate type for this leads to bad optimizations,
788
788
// so we pick an appropriately sized integer type instead.
789
789
arg. cast_to ( Reg { kind : RegKind :: Integer , size } ) ;
790
+
791
+ // Now we see if we are allowed to annotate the small immediate argument with
792
+ // `noundef`. This is only legal for small aggregates that do not have padding. For
793
+ // instance, all unions are allowed `undef` so we must not annotate union (or
794
+ // anything that contain unions) immediates with `noundef`.
795
+ if can_annotate_small_immediate_argument_with_noundef ( cx, arg. layout ) {
796
+ // Fixup arg attribute with `noundef`.
797
+ let PassMode :: Cast { ref mut cast, .. } = & mut arg. mode else {
798
+ bug ! ( "this cannot fail because of the previous cast_to `Reg`" ) ;
799
+ } ;
800
+ let box CastTarget { ref mut attrs, .. } = cast;
801
+ attrs. set ( ArgAttribute :: NoUndef ) ;
802
+ }
790
803
}
791
804
792
805
// If we deduced that this parameter was read-only, add that to the attribute list now.
@@ -822,6 +835,44 @@ fn fn_abi_adjust_for_abi<'tcx>(
822
835
Ok ( ( ) )
823
836
}
824
837
838
+ fn can_annotate_small_immediate_argument_with_noundef < ' tcx > (
839
+ cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
840
+ outermost_layout : TyAndLayout < ' tcx > ,
841
+ ) -> bool {
842
+ fn allowed_repr_rust < ' tcx > ( candidate_ty : Ty < ' tcx > ) -> bool {
843
+ match candidate_ty. kind ( ) {
844
+ ty:: Adt ( def, _) if def. repr ( ) . rust ( ) && !def. is_union ( ) => true ,
845
+ ty:: Array ( elem_ty, _) if allowed_repr_rust ( * elem_ty) => true ,
846
+ t => t. is_primitive ( ) ,
847
+ }
848
+ }
849
+
850
+ fn is_transparent_or_rust_wrapper < ' tcx > ( layout : TyAndLayout < ' tcx > ) -> bool {
851
+ return layout. is_transparent :: < LayoutCx < ' tcx , TyCtxt < ' tcx > > > ( )
852
+ || allowed_repr_rust ( layout. ty ) ;
853
+ }
854
+
855
+ if outermost_layout. ty . is_union ( ) {
856
+ return false ;
857
+ }
858
+
859
+ let mut innermost_layout = outermost_layout;
860
+ // Recursively peel away wrapper layers.
861
+ while is_transparent_or_rust_wrapper ( innermost_layout) {
862
+ let Some ( ( _, layout) ) = innermost_layout. non_1zst_field ( cx) else {
863
+ break ;
864
+ } ;
865
+
866
+ if layout. ty . is_union ( ) {
867
+ return false ;
868
+ }
869
+
870
+ innermost_layout = layout;
871
+ }
872
+
873
+ allowed_repr_rust ( innermost_layout. ty )
874
+ }
875
+
825
876
#[ tracing:: instrument( level = "debug" , skip( cx) ) ]
826
877
fn make_thin_self_ptr < ' tcx > (
827
878
cx : & ( impl HasTyCtxt < ' tcx > + HasParamEnv < ' tcx > ) ,
0 commit comments