@@ -565,86 +565,127 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
565565 }
566566 }
567567 }
568+ }
568569
569- /// Creates an incomplete operand containing the [`abi::Scalar`]s expected based
570- /// on the `layout` passed. This is for use with [`OperandRef::insert_field`]
571- /// later to set the necessary immediate(s), one-by-one converting all the `Right` to `Left`.
572- ///
573- /// Returns `None` for `layout`s which cannot be built this way.
574- pub ( crate ) fn builder (
575- layout : TyAndLayout < ' tcx > ,
576- ) -> Option < OperandRef < ' tcx , Either < V , abi:: Scalar > > > {
577- // Uninhabited types are weird, because for example `Result<!, !>`
578- // shows up as `FieldsShape::Primitive` and we need to be able to write
579- // a field into `(u32, !)`. We'll do that in an `alloca` instead.
580- if layout. uninhabited {
581- return None ;
582- }
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+ }
583589
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 {
584597 let val = match layout. backend_repr {
585- BackendRepr :: Memory { .. } if layout. is_zst ( ) => OperandValue :: ZeroSized ,
586- BackendRepr :: Scalar ( s) => OperandValue :: Immediate ( Either :: Right ( s) ) ,
587- BackendRepr :: ScalarPair ( a, b) => OperandValue :: Pair ( Either :: Right ( a) , Either :: Right ( b) ) ,
588- 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+ }
589607 } ;
590- Some ( OperandRef { val, layout } )
608+ OperandRefBuilder { val, layout }
591609 }
592- }
593610
594- impl < ' a , ' tcx , V : CodegenObject > OperandRef < ' tcx , Either < V , abi:: Scalar > > {
595- pub ( crate ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
611+ pub ( super ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
596612 & mut self ,
597613 bx : & mut Bx ,
598- v : VariantIdx ,
599- f : FieldIdx ,
614+ variant : VariantIdx ,
615+ field : FieldIdx ,
600616 operand : OperandRef < ' tcx , V > ,
601617 ) {
602- 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 {
603628 // The other branch looking at field layouts ICEs for primitives,
604629 // so we need to handle them separately.
605- // Multiple fields is possible for cases such as aggregating
606- // 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 .
607632 assert ! ( !self . layout. is_zst( ) ) ;
608- assert_eq ! ( v , FIRST_VARIANT ) ;
609- let first_field = f == FieldIdx :: ZERO ;
610- ( !first_field , first_field )
633+ assert_eq ! ( variant , FIRST_VARIANT ) ;
634+ assert_eq ! ( field , FieldIdx :: ZERO ) ;
635+ true
611636 } else {
612- let variant_layout = self . layout . for_variant ( bx. cx ( ) , v) ;
613- let field_layout = variant_layout. field ( bx. cx ( ) , f. as_usize ( ) ) ;
614- let field_offset = variant_layout. fields . offset ( f. as_usize ( ) ) ;
615- ( 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
616640 } ;
617641
618642 let mut update = |tgt : & mut Either < V , abi:: Scalar > , src, from_scalar| {
619643 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.
620647 let imm = transmute_scalar ( bx, src, from_scalar, to_scalar) ;
621648 * tgt = Either :: Left ( imm) ;
622649 } ;
623650
624651 match ( operand. val , operand. layout . backend_repr ) {
625- ( OperandValue :: ZeroSized , _) if expect_zst => { }
652+ ( OperandValue :: ZeroSized , _) => unreachable ! ( "Handled above" ) ,
626653 ( OperandValue :: Immediate ( v) , BackendRepr :: Scalar ( from_scalar) ) => match & mut self . val {
627- OperandValue :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
654+ OperandValueBuilder :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
628655 update ( val, v, from_scalar) ;
629656 }
630- OperandValue :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
657+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
631658 update ( fst, v, from_scalar) ;
632659 }
633- OperandValue :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
660+ OperandValueBuilder :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
634661 update ( snd, v, from_scalar) ;
635662 }
636- _ => 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:?}" ) ,
637670 } ,
638671 ( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( from_sa, from_sb) ) => {
639672 match & mut self . val {
640- OperandValue :: Pair ( fst @ Either :: Right ( _) , snd @ Either :: Right ( _) ) => {
673+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , snd @ Either :: Right ( _) ) => {
641674 update ( fst, a, from_sa) ;
642675 update ( snd, b, from_sb) ;
643676 }
644- _ => bug ! ( "Tried to insert {operand:?} into {v :?}.{f :?} of {self:?}" ) ,
677+ _ => bug ! ( "Tried to insert {operand:?} into {variant :?}.{field :?} of {self:?}" ) ,
645678 }
646679 }
647- _ => 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:?}" ) ,
648689 }
649690 }
650691
@@ -657,13 +698,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either<V, abi::Scalar>> {
657698 let field_offset = self . layout . fields . offset ( f. as_usize ( ) ) ;
658699 let is_zero_offset = field_offset == Size :: ZERO ;
659700 match & mut self . val {
660- OperandValue :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
701+ OperandValueBuilder :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
661702 * val = Either :: Left ( imm) ;
662703 }
663- OperandValue :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
704+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
664705 * fst = Either :: Left ( imm) ;
665706 }
666- OperandValue :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
707+ OperandValueBuilder :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
667708 * snd = Either :: Left ( imm) ;
668709 }
669710 _ => bug ! ( "Tried to insert {imm:?} into field {f:?} of {self:?}" ) ,
@@ -675,8 +716,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either<V, abi::Scalar>> {
675716 /// to the normal `OperandValue<V>`.
676717 ///
677718 /// ICEs if any required fields were not set.
678- pub fn build ( & self , cx : & impl CodegenMethods < ' tcx , Value = V > ) -> OperandRef < ' tcx , V > {
679- 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 ;
680721
681722 // For something like `Option::<u32>::None`, it's expected that the
682723 // payload scalar will not actually have been set, so this converts
@@ -692,10 +733,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either<V, abi::Scalar>> {
692733 } ;
693734
694735 let val = match val {
695- OperandValue :: ZeroSized => OperandValue :: ZeroSized ,
696- OperandValue :: Immediate ( v) => OperandValue :: Immediate ( unwrap ( v) ) ,
697- OperandValue :: Pair ( a, b) => OperandValue :: Pair ( unwrap ( a) , unwrap ( b) ) ,
698- 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+ } ,
699745 } ;
700746 OperandRef { val, layout }
701747 }
0 commit comments