@@ -8,14 +8,16 @@ use crate::traits::*;
88use crate :: MemFlags ;
99
1010use rustc_hir as hir;
11- use rustc_middle:: mir:: { self , AggregateKind , Operand } ;
11+ use rustc_middle:: mir;
1212use rustc_middle:: ty:: cast:: { CastTy , IntTy } ;
1313use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , TyAndLayout } ;
1414use rustc_middle:: ty:: { self , adjustment:: PointerCoercion , Instance , Ty , TyCtxt } ;
1515use rustc_middle:: { bug, span_bug} ;
1616use rustc_session:: config:: OptLevel ;
1717use 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 ;
1921
2022impl < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > FunctionCx < ' a , ' tcx , Bx > {
2123 #[ instrument( level = "trace" , skip( self , bx) ) ]
@@ -581,7 +583,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
581583 self . codegen_place_to_pointer ( bx, place, mk_ref)
582584 }
583585
584- mir:: Rvalue :: CopyForDeref ( place) => self . codegen_operand ( bx, & Operand :: Copy ( place) ) ,
586+ mir:: Rvalue :: CopyForDeref ( place) => {
587+ self . codegen_operand ( bx, & mir:: Operand :: Copy ( place) )
588+ }
585589 mir:: Rvalue :: AddressOf ( mutability, place) => {
586590 let mk_ptr =
587591 move |tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > | Ty :: new_ptr ( tcx, ty, mutability) ;
@@ -739,11 +743,40 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
739743 }
740744 }
741745 mir:: Rvalue :: Repeat ( ..) => bug ! ( "{rvalue:?} in codegen_rvalue_operand" ) ,
742- mir:: Rvalue :: Aggregate ( ..) => {
743- // According to `rvalue_creates_operand`, only ZST
744- // aggregate rvalues are allowed to be operands.
746+ mir:: Rvalue :: Aggregate ( _, ref fields) => {
745747 let ty = rvalue. ty ( self . mir , self . cx . tcx ( ) ) ;
746- OperandRef :: zero_sized ( self . cx . layout_of ( self . monomorphize ( ty) ) )
748+ let ty = self . monomorphize ( ty) ;
749+ let layout = self . cx . layout_of ( ty) ;
750+
751+ // `rvalue_creates_operand` has arranged that we only get here if
752+ // we can build the aggregate immediate from the field immediates.
753+ let mut inputs = ArrayVec :: < Bx :: Value , 2 > :: new ( ) ;
754+ let mut input_scalars = ArrayVec :: < abi:: Scalar , 2 > :: new ( ) ;
755+ for field_idx in layout. fields . index_by_increasing_offset ( ) {
756+ let field_idx = FieldIdx :: from_usize ( field_idx) ;
757+ let op = self . codegen_operand ( bx, & fields[ field_idx] ) ;
758+ let values = op. val . immediates_or_place ( ) . left_or_else ( |p| {
759+ bug ! ( "Field {field_idx:?} is {p:?} making {layout:?}" ) ;
760+ } ) ;
761+ inputs. extend ( values) ;
762+ let scalars = self . value_kind ( op. layout ) . scalars ( ) . unwrap ( ) ;
763+ input_scalars. extend ( scalars) ;
764+ }
765+
766+ let output_scalars = self . value_kind ( layout) . scalars ( ) . unwrap ( ) ;
767+ itertools:: izip!( & mut inputs, input_scalars, output_scalars) . for_each (
768+ |( v, in_s, out_s) | {
769+ if in_s != out_s {
770+ // We have to be really careful about bool here, because
771+ // `(bool,)` stays i1 but `Cell<bool>` becomes i8.
772+ * v = bx. from_immediate ( * v) ;
773+ * v = bx. to_immediate_scalar ( * v, out_s) ;
774+ }
775+ } ,
776+ ) ;
777+
778+ let val = OperandValue :: from_immediates ( inputs) ;
779+ OperandRef { val, layout }
747780 }
748781 mir:: Rvalue :: ShallowInitBox ( ref operand, content_ty) => {
749782 let operand = self . codegen_operand ( bx, operand) ;
@@ -1051,16 +1084,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10511084 mir:: Rvalue :: ThreadLocalRef ( _) |
10521085 mir:: Rvalue :: Use ( ..) => // (*)
10531086 true ,
1054- // This always produces a `ty::RawPtr`, so will be Immediate or Pair
1055- mir:: Rvalue :: Aggregate ( box AggregateKind :: RawPtr ( ..) , ..) => true ,
10561087 // Arrays are always aggregates, so it's not worth checking anything here.
10571088 // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
10581089 mir:: Rvalue :: Repeat ( ..) => false ,
1059- mir:: Rvalue :: Aggregate ( ..) => {
1090+ mir:: Rvalue :: Aggregate ( ref kind, _) => {
1091+ let allowed_kind = match * * kind {
1092+ // This always produces a `ty::RawPtr`, so will be Immediate or Pair
1093+ mir:: AggregateKind :: RawPtr ( ..) => true ,
1094+ mir:: AggregateKind :: Array ( ..) => false ,
1095+ mir:: AggregateKind :: Tuple => true ,
1096+ mir:: AggregateKind :: Adt ( def_id, ..) => {
1097+ let adt_def = self . cx . tcx ( ) . adt_def ( def_id) ;
1098+ adt_def. is_struct ( ) && !adt_def. repr ( ) . simd ( )
1099+ }
1100+ mir:: AggregateKind :: Closure ( ..) => true ,
1101+ // FIXME: Can we do this for simple coroutines too?
1102+ mir:: AggregateKind :: Coroutine ( ..) | mir:: AggregateKind :: CoroutineClosure ( ..) => false ,
1103+ } ;
1104+ allowed_kind && {
10601105 let ty = rvalue. ty ( self . mir , self . cx . tcx ( ) ) ;
10611106 let ty = self . monomorphize ( ty) ;
1062- // For ZST this can be `OperandValueKind::ZeroSized`.
1063- self . cx . spanned_layout_of ( ty, span) . is_zst ( )
1107+ let layout = self . cx . spanned_layout_of ( ty, span) ;
1108+ !self . cx . is_backend_ref ( layout)
1109+ }
10641110 }
10651111 }
10661112
@@ -1102,3 +1148,14 @@ enum OperandValueKind {
11021148 Pair ( abi:: Scalar , abi:: Scalar ) ,
11031149 ZeroSized ,
11041150}
1151+
1152+ impl OperandValueKind {
1153+ fn scalars ( self ) -> Option < ArrayVec < abi:: Scalar , 2 > > {
1154+ Some ( match self {
1155+ OperandValueKind :: ZeroSized => ArrayVec :: new ( ) ,
1156+ OperandValueKind :: Immediate ( a) => ArrayVec :: from_iter ( [ a] ) ,
1157+ OperandValueKind :: Pair ( a, b) => [ a, b] . into ( ) ,
1158+ OperandValueKind :: Ref => return None ,
1159+ } )
1160+ }
1161+ }
0 commit comments