@@ -8,14 +8,16 @@ use crate::traits::*;
8
8
use crate :: MemFlags ;
9
9
10
10
use rustc_hir as hir;
11
- use rustc_middle:: mir:: { self , AggregateKind , Operand } ;
11
+ use rustc_middle:: mir;
12
12
use rustc_middle:: ty:: cast:: { CastTy , IntTy } ;
13
13
use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , TyAndLayout } ;
14
14
use rustc_middle:: ty:: { self , adjustment:: PointerCoercion , Instance , Ty , TyCtxt } ;
15
15
use rustc_middle:: { bug, span_bug} ;
16
16
use rustc_session:: config:: OptLevel ;
17
17
use rustc_span:: { Span , DUMMY_SP } ;
18
- use rustc_target:: abi:: { self , FIRST_VARIANT } ;
18
+ use rustc_target:: abi:: { self , FieldIdx , FIRST_VARIANT } ;
19
+
20
+ use arrayvec:: ArrayVec ;
19
21
20
22
impl < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > FunctionCx < ' a , ' tcx , Bx > {
21
23
#[ instrument( level = "trace" , skip( self , bx) ) ]
@@ -579,7 +581,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
579
581
self . codegen_place_to_pointer ( bx, place, mk_ref)
580
582
}
581
583
582
- mir:: Rvalue :: CopyForDeref ( place) => self . codegen_operand ( bx, & Operand :: Copy ( place) ) ,
584
+ mir:: Rvalue :: CopyForDeref ( place) => {
585
+ self . codegen_operand ( bx, & mir:: Operand :: Copy ( place) )
586
+ }
583
587
mir:: Rvalue :: AddressOf ( mutability, place) => {
584
588
let mk_ptr =
585
589
move |tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > | Ty :: new_ptr ( tcx, ty, mutability) ;
@@ -736,11 +740,41 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
736
740
_ => bug ! ( "RawPtr operands {data:?} {meta:?}" ) ,
737
741
}
738
742
}
739
- mir:: Rvalue :: Repeat ( ..) | mir:: Rvalue :: Aggregate ( ..) => {
740
- // According to `rvalue_creates_operand`, only ZST
741
- // aggregate rvalues are allowed to be operands.
743
+ mir:: Rvalue :: Repeat ( ..) => bug ! ( "{rvalue:?} in codegen_rvalue_operand" ) ,
744
+ mir:: Rvalue :: Aggregate ( _, ref fields) => {
742
745
let ty = rvalue. ty ( self . mir , self . cx . tcx ( ) ) ;
743
- OperandRef :: zero_sized ( self . cx . layout_of ( self . monomorphize ( ty) ) )
746
+ let ty = self . monomorphize ( ty) ;
747
+ let layout = self . cx . layout_of ( ty) ;
748
+
749
+ // `rvalue_creates_operand` has arranged that we only get here if
750
+ // we can build the aggregate immediate from the field immediates.
751
+ let mut inputs = ArrayVec :: < Bx :: Value , 2 > :: new ( ) ;
752
+ let mut input_scalars = ArrayVec :: < abi:: Scalar , 2 > :: new ( ) ;
753
+ for field_idx in layout. fields . index_by_increasing_offset ( ) {
754
+ let field_idx = FieldIdx :: from_usize ( field_idx) ;
755
+ let op = self . codegen_operand ( bx, & fields[ field_idx] ) ;
756
+ let values = op. val . immediates_or_place ( ) . left_or_else ( |p| {
757
+ bug ! ( "Field {field_idx:?} is {p:?} making {layout:?}" ) ;
758
+ } ) ;
759
+ inputs. extend ( values) ;
760
+ let scalars = self . value_kind ( op. layout ) . scalars ( ) . unwrap ( ) ;
761
+ input_scalars. extend ( scalars) ;
762
+ }
763
+
764
+ let output_scalars = self . value_kind ( layout) . scalars ( ) . unwrap ( ) ;
765
+ itertools:: izip!( & mut inputs, input_scalars, output_scalars) . for_each (
766
+ |( v, in_s, out_s) | {
767
+ if in_s != out_s {
768
+ // We have to be really careful about bool here, because
769
+ // `(bool,)` stays i1 but `Cell<bool>` becomes i8.
770
+ * v = bx. from_immediate ( * v) ;
771
+ * v = bx. to_immediate_scalar ( * v, out_s) ;
772
+ }
773
+ } ,
774
+ ) ;
775
+
776
+ let val = OperandValue :: from_immediates ( inputs) ;
777
+ OperandRef { val, layout }
744
778
}
745
779
mir:: Rvalue :: ShallowInitBox ( ref operand, content_ty) => {
746
780
let operand = self . codegen_operand ( bx, operand) ;
@@ -1047,14 +1081,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1047
1081
mir:: Rvalue :: ThreadLocalRef ( _) |
1048
1082
mir:: Rvalue :: Use ( ..) => // (*)
1049
1083
true ,
1050
- // This always produces a `ty::RawPtr`, so will be Immediate or Pair
1051
- mir:: Rvalue :: Aggregate ( box AggregateKind :: RawPtr ( ..) , ..) => true ,
1052
- mir:: Rvalue :: Repeat ( ..) |
1053
- mir:: Rvalue :: Aggregate ( ..) => {
1084
+ // Arrays are always aggregates, so it's not worth checking anything here.
1085
+ // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
1086
+ mir:: Rvalue :: Repeat ( ..) => false ,
1087
+ mir:: Rvalue :: Aggregate ( ref kind, _) => {
1088
+ let allowed_kind = match * * kind {
1089
+ // This always produces a `ty::RawPtr`, so will be Immediate or Pair
1090
+ mir:: AggregateKind :: RawPtr ( ..) => true ,
1091
+ mir:: AggregateKind :: Array ( ..) => false ,
1092
+ mir:: AggregateKind :: Tuple => true ,
1093
+ mir:: AggregateKind :: Adt ( def_id, ..) => {
1094
+ let adt_def = self . cx . tcx ( ) . adt_def ( def_id) ;
1095
+ adt_def. is_struct ( ) && !adt_def. repr ( ) . simd ( )
1096
+ }
1097
+ mir:: AggregateKind :: Closure ( ..) => true ,
1098
+ // FIXME: Can we do this for simple coroutines too?
1099
+ mir:: AggregateKind :: Coroutine ( ..) | mir:: AggregateKind :: CoroutineClosure ( ..) => false ,
1100
+ } ;
1101
+ allowed_kind && {
1054
1102
let ty = rvalue. ty ( self . mir , self . cx . tcx ( ) ) ;
1055
1103
let ty = self . monomorphize ( ty) ;
1056
- // For ZST this can be `OperandValueKind::ZeroSized`.
1057
- self . cx . spanned_layout_of ( ty, span) . is_zst ( )
1104
+ let layout = self . cx . spanned_layout_of ( ty, span) ;
1105
+ !self . cx . is_backend_ref ( layout)
1106
+ }
1058
1107
}
1059
1108
}
1060
1109
@@ -1096,3 +1145,14 @@ enum OperandValueKind {
1096
1145
Pair ( abi:: Scalar , abi:: Scalar ) ,
1097
1146
ZeroSized ,
1098
1147
}
1148
+
1149
+ impl OperandValueKind {
1150
+ fn scalars ( self ) -> Option < ArrayVec < abi:: Scalar , 2 > > {
1151
+ Some ( match self {
1152
+ OperandValueKind :: ZeroSized => ArrayVec :: new ( ) ,
1153
+ OperandValueKind :: Immediate ( a) => ArrayVec :: from_iter ( [ a] ) ,
1154
+ OperandValueKind :: Pair ( a, b) => [ a, b] . into ( ) ,
1155
+ OperandValueKind :: Ref => return None ,
1156
+ } )
1157
+ }
1158
+ }
0 commit comments