@@ -565,118 +565,159 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
565
565
}
566
566
}
567
567
}
568
+ }
568
569
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
+ /// `repr(simd)` types need special handling because they each have a non-empty
578
+ /// array field (which uses [`OperandValue::Ref`]) despite the SIMD type itself
579
+ /// using [`OperandValue::Immediate`] which for any other kind of type would
580
+ /// mean that its one non-ZST field would also be [`OperandValue::Immediate`].
581
+ Vector ( Either < V , ( ) > ) ,
582
+ }
583
583
584
+ /// Allows building up an `OperandRef` by setting fields one at a time.
585
+ #[ derive( Debug , Copy , Clone ) ]
586
+ pub ( super ) struct OperandRefBuilder < ' tcx , V > {
587
+ val : OperandValueBuilder < V > ,
588
+ layout : TyAndLayout < ' tcx > ,
589
+ }
590
+
591
+ impl < ' a , ' tcx , V : CodegenObject > OperandRefBuilder < ' tcx , V > {
592
+ /// Creates an uninitialized builder for an instance of the `layout`.
593
+ ///
594
+ /// ICEs for [`BackendRepr::Memory`] types (other than ZSTs), which should
595
+ /// be built up inside a [`PlaceRef`] instead as they need an allocated place
596
+ /// into which to write the values of the fields.
597
+ pub ( super ) fn new ( layout : TyAndLayout < ' tcx > ) -> Self {
584
598
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 ,
599
+ BackendRepr :: Memory { .. } if layout. is_zst ( ) => OperandValueBuilder :: ZeroSized ,
600
+ BackendRepr :: Scalar ( s) => OperandValueBuilder :: Immediate ( Either :: Right ( s) ) ,
601
+ BackendRepr :: ScalarPair ( a, b) => {
602
+ OperandValueBuilder :: Pair ( Either :: Right ( a) , Either :: Right ( b) )
603
+ }
604
+ BackendRepr :: SimdVector { .. } => OperandValueBuilder :: Vector ( Either :: Right ( ( ) ) ) ,
605
+ BackendRepr :: Memory { .. } => {
606
+ bug ! ( "Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}" ) ;
607
+ }
589
608
} ;
590
- Some ( OperandRef { val, layout } )
609
+ OperandRefBuilder { val, layout }
591
610
}
592
- }
593
611
594
- impl < ' a , ' tcx , V : CodegenObject > OperandRef < ' tcx , Either < V , abi:: Scalar > > {
595
- pub ( crate ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
612
+ pub ( super ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
596
613
& mut self ,
597
614
bx : & mut Bx ,
598
- v : VariantIdx ,
599
- f : FieldIdx ,
615
+ variant : VariantIdx ,
616
+ field : FieldIdx ,
600
617
operand : OperandRef < ' tcx , V > ,
601
618
) {
602
- let ( expect_zst, is_zero_offset) = if let abi:: FieldsShape :: Primitive = self . layout . fields {
619
+ if let OperandValue :: ZeroSized = operand. val {
620
+ // A ZST never adds any state, so just ignore it.
621
+ // This special-casing is worth it because of things like
622
+ // `Result<!, !>` where `Ok(never)` is legal to write,
623
+ // but the type shows as FieldShape::Primitive so we can't
624
+ // actually look at the layout for the field being set.
625
+ return ;
626
+ }
627
+
628
+ let is_zero_offset = if let abi:: FieldsShape :: Primitive = self . layout . fields {
603
629
// The other branch looking at field layouts ICEs for primitives,
604
630
// 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 .
631
+ // Because we handled ZSTs above (like the metadata in a thin pointer),
632
+ // the only possibility is that we're setting the one-and-only field .
607
633
assert ! ( !self . layout. is_zst( ) ) ;
608
- assert_eq ! ( v , FIRST_VARIANT ) ;
609
- let first_field = f == FieldIdx :: ZERO ;
610
- ( !first_field , first_field )
634
+ assert_eq ! ( variant , FIRST_VARIANT ) ;
635
+ assert_eq ! ( field , FieldIdx :: ZERO ) ;
636
+ true
611
637
} 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 )
638
+ let variant_layout = self . layout . for_variant ( bx. cx ( ) , variant) ;
639
+ let field_offset = variant_layout. fields . offset ( field. as_usize ( ) ) ;
640
+ field_offset == Size :: ZERO
616
641
} ;
617
642
618
643
let mut update = |tgt : & mut Either < V , abi:: Scalar > , src, from_scalar| {
619
644
let to_scalar = tgt. unwrap_right ( ) ;
645
+ // We transmute here (rather than just `from_immediate`) because in
646
+ // `Result<usize, *const ()>` the field of the `Ok` is an integer,
647
+ // but the corresponding scalar in the enum is a pointer.
620
648
let imm = transmute_scalar ( bx, src, from_scalar, to_scalar) ;
621
649
* tgt = Either :: Left ( imm) ;
622
650
} ;
623
651
624
652
match ( operand. val , operand. layout . backend_repr ) {
625
- ( OperandValue :: ZeroSized , _) if expect_zst => { }
653
+ ( OperandValue :: ZeroSized , _) => unreachable ! ( "Handled above" ) ,
626
654
( OperandValue :: Immediate ( v) , BackendRepr :: Scalar ( from_scalar) ) => match & mut self . val {
627
- OperandValue :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
655
+ OperandValueBuilder :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
628
656
update ( val, v, from_scalar) ;
629
657
}
630
- OperandValue :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
658
+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
631
659
update ( fst, v, from_scalar) ;
632
660
}
633
- OperandValue :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
661
+ OperandValueBuilder :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
634
662
update ( snd, v, from_scalar) ;
635
663
}
636
- _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
664
+ _ => bug ! ( "Tried to insert {operand:?} into {variant:?}.{field:?} of {self:?}" ) ,
665
+ } ,
666
+ ( OperandValue :: Immediate ( v) , BackendRepr :: SimdVector { .. } ) => match & mut self . val {
667
+ OperandValueBuilder :: Vector ( val @ Either :: Right ( ( ) ) ) if is_zero_offset => {
668
+ * val = Either :: Left ( v) ;
669
+ }
670
+ _ => bug ! ( "Tried to insert {operand:?} into {variant:?}.{field:?} of {self:?}" ) ,
637
671
} ,
638
672
( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( from_sa, from_sb) ) => {
639
673
match & mut self . val {
640
- OperandValue :: Pair ( fst @ Either :: Right ( _) , snd @ Either :: Right ( _) ) => {
674
+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , snd @ Either :: Right ( _) ) => {
641
675
update ( fst, a, from_sa) ;
642
676
update ( snd, b, from_sb) ;
643
677
}
644
- _ => bug ! ( "Tried to insert {operand:?} into {v :?}.{f :?} of {self:?}" ) ,
678
+ _ => bug ! ( "Tried to insert {operand:?} into {variant :?}.{field :?} of {self:?}" ) ,
645
679
}
646
680
}
647
- _ => bug ! ( "Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}" ) ,
681
+ ( OperandValue :: Ref ( place) , BackendRepr :: Memory { .. } ) => match & mut self . val {
682
+ OperandValueBuilder :: Vector ( val @ Either :: Right ( ( ) ) ) => {
683
+ let ibty = bx. cx ( ) . immediate_backend_type ( self . layout ) ;
684
+ let simd = bx. load_from_place ( ibty, place) ;
685
+ * val = Either :: Left ( simd) ;
686
+ }
687
+ _ => bug ! ( "Tried to insert {operand:?} into {variant:?}.{field:?} of {self:?}" ) ,
688
+ } ,
689
+ _ => bug ! ( "Operand cannot be used with `insert_field`: {operand:?}" ) ,
648
690
}
649
691
}
650
692
651
693
/// Insert the immediate value `imm` for field `f` in the *type itself*,
652
694
/// rather than into one of the variants.
653
695
///
654
- /// Most things want [`OperandRef ::insert_field`] instead, but this one is
696
+ /// Most things want [`Self ::insert_field`] instead, but this one is
655
697
/// necessary for writing things like enum tags that aren't in any variant.
656
698
pub ( super ) fn insert_imm ( & mut self , f : FieldIdx , imm : V ) {
657
699
let field_offset = self . layout . fields . offset ( f. as_usize ( ) ) ;
658
700
let is_zero_offset = field_offset == Size :: ZERO ;
659
701
match & mut self . val {
660
- OperandValue :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
702
+ OperandValueBuilder :: Immediate ( val @ Either :: Right ( _) ) if is_zero_offset => {
661
703
* val = Either :: Left ( imm) ;
662
704
}
663
- OperandValue :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
705
+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
664
706
* fst = Either :: Left ( imm) ;
665
707
}
666
- OperandValue :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
708
+ OperandValueBuilder :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
667
709
* snd = Either :: Left ( imm) ;
668
710
}
669
711
_ => bug ! ( "Tried to insert {imm:?} into field {f:?} of {self:?}" ) ,
670
712
}
671
713
}
672
714
673
- /// After having set all necessary fields, this converts the
674
- /// `OperandValue<Either<V, _>>` (as obtained from [`OperandRef::builder`])
675
- /// to the normal `OperandValue<V>`.
715
+ /// After having set all necessary fields, this converts the builder back
716
+ /// to the normal `OperandRef`.
676
717
///
677
718
/// 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 ;
680
721
681
722
// For something like `Option::<u32>::None`, it's expected that the
682
723
// payload scalar will not actually have been set, so this converts
@@ -692,10 +733,22 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Either<V, abi::Scalar>> {
692
733
} ;
693
734
694
735
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
+ if let BackendRepr :: SimdVector { element, .. } = layout. backend_repr
743
+ && element. is_uninit_valid ( )
744
+ => {
745
+ let bty = cx. immediate_backend_type ( layout) ;
746
+ OperandValue :: Immediate ( cx. const_undef ( bty) )
747
+ }
748
+ Either :: Right ( ( ) ) => {
749
+ bug ! ( "OperandRef::build called while fields are missing {self:?}" )
750
+ }
751
+ } ,
699
752
} ;
700
753
OperandRef { val, layout }
701
754
}
0 commit comments