11use  std:: fmt; 
22
3+ use  itertools:: Either ; 
34use  rustc_abi as  abi; 
45use  rustc_abi:: { 
56    Align ,  BackendRepr ,  FIRST_VARIANT ,  FieldIdx ,  Primitive ,  Size ,  TagEncoding ,  VariantIdx ,  Variants , 
@@ -564,86 +565,127 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
564565            } 
565566        } 
566567    } 
568+ } 
567569
568-     /// Creates an incomplete operand containing the [`abi::Scalar`]s expected based 
569-      /// on the `layout` passed. This is for use with [`OperandRef::insert_field`] 
570-      /// later to set the necessary immediate(s). 
571-      /// 
572-      /// Returns `None` for `layout`s which cannot be built this way. 
573-      pub ( crate )  fn  builder ( 
574-         layout :  TyAndLayout < ' tcx > , 
575-     )  -> Option < OperandRef < ' tcx ,  Result < V ,  abi:: Scalar > > >  { 
576-         // Uninhabited types are weird, because for example `Result<!, !>` 
577-         // shows up as `FieldsShape::Primitive` and we need to be able to write 
578-         // a field into `(u32, !)`. We'll do that in an `alloca` instead. 
579-         if  layout. uninhabited  { 
580-             return  None ; 
581-         } 
570+ /// Each of these variants starts out as `Either::Right` when it's uninitialized, 
571+ /// then setting the field changes that to `Either::Left` with the backend value. 
572+ #[ derive( Debug ,  Copy ,  Clone ) ]  
573+ enum  OperandValueBuilder < V >  { 
574+     ZeroSized , 
575+     Immediate ( Either < V ,  abi:: Scalar > ) , 
576+     Pair ( Either < V ,  abi:: Scalar > ,  Either < V ,  abi:: Scalar > ) , 
577+     /// SIMD vectors need special handling because they're the only case where 
578+      /// a type with a (non-ZST) `Memory`-ABI field can be `Scalar`-ABI. 
579+      /// (Also you can't represent a vector type with just an `abi::Scalar`.) 
580+      Vector ( Either < V ,  ( ) > ) , 
581+ } 
582+ 
583+ /// Allows building up an `OperandRef` by setting fields one at a time. 
584+ #[ derive( Debug ,  Copy ,  Clone ) ]  
585+ pub ( super )  struct  OperandRefBuilder < ' tcx ,  V >  { 
586+     val :  OperandValueBuilder < V > , 
587+     layout :  TyAndLayout < ' tcx > , 
588+ } 
582589
590+ impl < ' a ,  ' tcx ,  V :  CodegenObject >  OperandRefBuilder < ' tcx ,  V >  { 
591+     /// Creates an uninitialized builder for an instance of the `layout`. 
592+      /// 
593+      /// ICEs for [`BackendRepr::Memory`] types (other than ZSTs), which should 
594+      /// be built up inside a [`PlaceRef`] instead as they need an allocated place 
595+      /// into which to write the values of the fields. 
596+      pub ( super )  fn  new ( layout :  TyAndLayout < ' tcx > )  -> Self  { 
583597        let  val = match  layout. backend_repr  { 
584-             BackendRepr :: Memory  {  .. }  if  layout. is_zst ( )  => OperandValue :: ZeroSized , 
585-             BackendRepr :: Scalar ( s)  => OperandValue :: Immediate ( Err ( s) ) , 
586-             BackendRepr :: ScalarPair ( a,  b)  => OperandValue :: Pair ( Err ( a) ,  Err ( b) ) , 
587-             BackendRepr :: Memory  {  .. }  | BackendRepr :: SimdVector  {  .. }  => return  None , 
598+             BackendRepr :: Memory  {  .. }  if  layout. is_zst ( )  => OperandValueBuilder :: ZeroSized , 
599+             BackendRepr :: Scalar ( s)  => OperandValueBuilder :: Immediate ( Either :: Right ( s) ) , 
600+             BackendRepr :: ScalarPair ( a,  b)  => { 
601+                 OperandValueBuilder :: Pair ( Either :: Right ( a) ,  Either :: Right ( b) ) 
602+             } 
603+             BackendRepr :: SimdVector  {  .. }  => OperandValueBuilder :: Vector ( Either :: Right ( ( ) ) ) , 
604+             BackendRepr :: Memory  {  .. }  => { 
605+                 bug ! ( "Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}" ) ; 
606+             } 
588607        } ; 
589-         Some ( OperandRef  {  val,  layout } ) 
608+         OperandRefBuilder  {  val,  layout } 
590609    } 
591- } 
592610
593- impl < ' a ,  ' tcx ,  V :  CodegenObject >  OperandRef < ' tcx ,  Result < V ,  abi:: Scalar > >  { 
594-     pub ( crate )  fn  insert_field < Bx :  BuilderMethods < ' a ,  ' tcx ,  Value  = V > > ( 
611+     pub ( super )  fn  insert_field < Bx :  BuilderMethods < ' a ,  ' tcx ,  Value  = V > > ( 
595612        & mut  self , 
596613        bx :  & mut  Bx , 
597-         v :  VariantIdx , 
598-         f :  FieldIdx , 
614+         variant :  VariantIdx , 
615+         field :  FieldIdx , 
599616        operand :  OperandRef < ' tcx ,  V > , 
600617    )  { 
601-         let  ( expect_zst,  is_zero_offset)  = if  let  abi:: FieldsShape :: Primitive  = self . layout . fields  { 
618+         if  let  OperandValue :: ZeroSized  = operand. val  { 
619+             // A ZST never adds any state, so just ignore it. 
620+             // This special-casing is worth it because of things like 
621+             // `Result<!, !>` where `Ok(never)` is legal to write, 
622+             // but the type shows as FieldShape::Primitive so we can't 
623+             // actually look at the layout for the field being set. 
624+             return ; 
625+         } 
626+ 
627+         let  is_zero_offset = if  let  abi:: FieldsShape :: Primitive  = self . layout . fields  { 
602628            // The other branch looking at field layouts ICEs for primitives, 
603629            // so we need to handle them separately. 
604-             // Multiple fields is possible for cases such as aggregating  
605-             // a thin pointer, where the second field is  the unit . 
630+             // Because we handled ZSTs above (like the metadata in a thin pointer),  
631+             // the only possibility is that we're setting  the one-and-only field . 
606632            assert ! ( !self . layout. is_zst( ) ) ; 
607-             assert_eq ! ( v ,  FIRST_VARIANT ) ; 
608-             let  first_field = f ==  FieldIdx :: ZERO ; 
609-             ( !first_field ,  first_field ) 
633+             assert_eq ! ( variant ,  FIRST_VARIANT ) ; 
634+             assert_eq ! ( field ,   FieldIdx :: ZERO ) ; 
635+             true 
610636        }  else  { 
611-             let  variant_layout = self . layout . for_variant ( bx. cx ( ) ,  v) ; 
612-             let  field_layout = variant_layout. field ( bx. cx ( ) ,  f. as_usize ( ) ) ; 
613-             let  field_offset = variant_layout. fields . offset ( f. as_usize ( ) ) ; 
614-             ( field_layout. is_zst ( ) ,  field_offset == Size :: ZERO ) 
637+             let  variant_layout = self . layout . for_variant ( bx. cx ( ) ,  variant) ; 
638+             let  field_offset = variant_layout. fields . offset ( field. as_usize ( ) ) ; 
639+             field_offset == Size :: ZERO 
615640        } ; 
616641
617-         let  mut  update = |tgt :  & mut  Result < V ,  abi:: Scalar > ,  src,  from_scalar| { 
618-             let  to_scalar = tgt. unwrap_err ( ) ; 
642+         let  mut  update = |tgt :  & mut  Either < V ,  abi:: Scalar > ,  src,  from_scalar| { 
643+             let  to_scalar = tgt. unwrap_right ( ) ; 
644+             // We transmute here (rather than just `from_immediate`) because in 
645+             // `Result<usize, *const ()>` the field of the `Ok` is an integer, 
646+             // but the corresponding scalar in the enum is a pointer. 
619647            let  imm = transmute_scalar ( bx,  src,  from_scalar,  to_scalar) ; 
620-             * tgt = Ok ( imm) ; 
648+             * tgt = Either :: Left ( imm) ; 
621649        } ; 
622650
623651        match  ( operand. val ,  operand. layout . backend_repr )  { 
624-             ( OperandValue :: ZeroSized ,  _)  if  expect_zst  => { } 
652+             ( OperandValue :: ZeroSized ,  _)  => unreachable ! ( "Handled above" ) , 
625653            ( OperandValue :: Immediate ( v) ,  BackendRepr :: Scalar ( from_scalar) )  => match  & mut  self . val  { 
626-                 OperandValue :: Immediate ( val @ Err ( _) )  if  is_zero_offset => { 
654+                 OperandValueBuilder :: Immediate ( val @ Either :: Right ( _) )  if  is_zero_offset => { 
627655                    update ( val,  v,  from_scalar) ; 
628656                } 
629-                 OperandValue :: Pair ( fst @ Err ( _) ,  _)  if  is_zero_offset => { 
657+                 OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) ,  _)  if  is_zero_offset => { 
630658                    update ( fst,  v,  from_scalar) ; 
631659                } 
632-                 OperandValue :: Pair ( _,  snd @ Err ( _) )  if  !is_zero_offset => { 
660+                 OperandValueBuilder :: Pair ( _,  snd @ Either :: Right ( _) )  if  !is_zero_offset => { 
633661                    update ( snd,  v,  from_scalar) ; 
634662                } 
635-                 _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) , 
663+                 _ => bug ! ( "Tried to insert {operand:?} into {variant:?}.{field:?} of {self:?}" ) , 
664+             } , 
665+             ( OperandValue :: Immediate ( v) ,  BackendRepr :: SimdVector  {  .. } )  => match  & mut  self . val  { 
666+                 OperandValueBuilder :: Vector ( val @ Either :: Right ( ( ) ) )  if  is_zero_offset => { 
667+                     * val = Either :: Left ( v) ; 
668+                 } 
669+                 _ => bug ! ( "Tried to insert {operand:?} into {variant:?}.{field:?} of {self:?}" ) , 
636670            } , 
637671            ( OperandValue :: Pair ( a,  b) ,  BackendRepr :: ScalarPair ( from_sa,  from_sb) )  => { 
638672                match  & mut  self . val  { 
639-                     OperandValue :: Pair ( fst @ Err ( _) ,  snd @ Err ( _) )  => { 
673+                     OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) ,  snd @ Either :: Right ( _) )  => { 
640674                        update ( fst,  a,  from_sa) ; 
641675                        update ( snd,  b,  from_sb) ; 
642676                    } 
643-                     _ => bug ! ( "Tried to insert {operand:?} into {v :?}.{f :?} of {self:?}" ) , 
677+                     _ => bug ! ( "Tried to insert {operand:?} into {variant :?}.{field :?} of {self:?}" ) , 
644678                } 
645679            } 
646-             _ => bug ! ( "Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}" ) , 
680+             ( OperandValue :: Ref ( place) ,  BackendRepr :: Memory  {  .. } )  => match  & mut  self . val  { 
681+                 OperandValueBuilder :: Vector ( val @ Either :: Right ( ( ) ) )  => { 
682+                     let  ibty = bx. cx ( ) . immediate_backend_type ( self . layout ) ; 
683+                     let  simd = bx. load_from_place ( ibty,  place) ; 
684+                     * val = Either :: Left ( simd) ; 
685+                 } 
686+                 _ => bug ! ( "Tried to insert {operand:?} into {variant:?}.{field:?} of {self:?}" ) , 
687+             } , 
688+             _ => bug ! ( "Operand cannot be used with `insert_field`: {operand:?}" ) , 
647689        } 
648690    } 
649691
@@ -656,45 +698,50 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result<V, abi::Scalar>> {
656698        let  field_offset = self . layout . fields . offset ( f. as_usize ( ) ) ; 
657699        let  is_zero_offset = field_offset == Size :: ZERO ; 
658700        match  & mut  self . val  { 
659-             OperandValue :: Immediate ( val @ Err ( _) )  if  is_zero_offset => { 
660-                 * val = Ok ( imm) ; 
701+             OperandValueBuilder :: Immediate ( val @ Either :: Right ( _) )  if  is_zero_offset => { 
702+                 * val = Either :: Left ( imm) ; 
661703            } 
662-             OperandValue :: Pair ( fst @ Err ( _) ,  _)  if  is_zero_offset => { 
663-                 * fst = Ok ( imm) ; 
704+             OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) ,  _)  if  is_zero_offset => { 
705+                 * fst = Either :: Left ( imm) ; 
664706            } 
665-             OperandValue :: Pair ( _,  snd @ Err ( _) )  if  !is_zero_offset => { 
666-                 * snd = Ok ( imm) ; 
707+             OperandValueBuilder :: Pair ( _,  snd @ Either :: Right ( _) )  if  !is_zero_offset => { 
708+                 * snd = Either :: Left ( imm) ; 
667709            } 
668710            _ => bug ! ( "Tried to insert {imm:?} into field {f:?} of {self:?}" ) , 
669711        } 
670712    } 
671713
672714    /// After having set all necessary fields, this converts the 
673-      /// `OperandValue<Result <V, _>>` (as obtained from [`OperandRef::builder`]) 
715+      /// `OperandValue<Either <V, _>>` (as obtained from [`OperandRef::builder`]) 
674716     /// to the normal `OperandValue<V>`. 
675717     /// 
676718     /// ICEs if any required fields were not set. 
677-      pub  fn  build ( & self ,  cx :  & impl  CodegenMethods < ' tcx ,  Value  = V > )  -> OperandRef < ' tcx ,  V >  { 
678-         let  OperandRef  {  val,  layout }  = * self ; 
719+      pub ( super )  fn  build ( & self ,  cx :  & impl  CodegenMethods < ' tcx ,  Value  = V > )  -> OperandRef < ' tcx ,  V >  { 
720+         let  OperandRefBuilder  {  val,  layout }  = * self ; 
679721
680722        // For something like `Option::<u32>::None`, it's expected that the 
681723        // payload scalar will not actually have been set, so this converts 
682724        // unset scalars to corresponding `undef` values so long as the scalar 
683725        // from the layout allows uninit. 
684-         let  unwrap = |r :  Result < V ,  abi:: Scalar > | match  r { 
685-             Ok ( v)  => v, 
686-             Err ( s)  if  s. is_uninit_valid ( )  => { 
726+         let  unwrap = |r :  Either < V ,  abi:: Scalar > | match  r { 
727+             Either :: Left ( v)  => v, 
728+             Either :: Right ( s)  if  s. is_uninit_valid ( )  => { 
687729                let  bty = cx. type_from_scalar ( s) ; 
688730                cx. const_undef ( bty) 
689731            } 
690-             Err ( _)  => bug ! ( "OperandRef::build called while fields are missing {self:?}" ) , 
732+             Either :: Right ( _)  => bug ! ( "OperandRef::build called while fields are missing {self:?}" ) , 
691733        } ; 
692734
693735        let  val = match  val { 
694-             OperandValue :: ZeroSized  => OperandValue :: ZeroSized , 
695-             OperandValue :: Immediate ( v)  => OperandValue :: Immediate ( unwrap ( v) ) , 
696-             OperandValue :: Pair ( a,  b)  => OperandValue :: Pair ( unwrap ( a) ,  unwrap ( b) ) , 
697-             OperandValue :: Ref ( _)  => bug ! ( ) , 
736+             OperandValueBuilder :: ZeroSized  => OperandValue :: ZeroSized , 
737+             OperandValueBuilder :: Immediate ( v)  => OperandValue :: Immediate ( unwrap ( v) ) , 
738+             OperandValueBuilder :: Pair ( a,  b)  => OperandValue :: Pair ( unwrap ( a) ,  unwrap ( b) ) , 
739+             OperandValueBuilder :: Vector ( v)  => match  v { 
740+                 Either :: Left ( v)  => OperandValue :: Immediate ( v) , 
741+                 Either :: Right ( ( ) )  => { 
742+                     bug ! ( "OperandRef::build called while fields are missing {self:?}" ) 
743+                 } 
744+             } , 
698745        } ; 
699746        OperandRef  {  val,  layout } 
700747    } 
0 commit comments