1
1
use std:: fmt;
2
2
3
+ use itertools:: Either ;
3
4
use rustc_abi as abi;
4
5
use rustc_abi:: {
5
6
Align , BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , TagEncoding , VariantIdx , Variants ,
@@ -564,86 +565,127 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
564
565
}
565
566
}
566
567
}
568
+ }
567
569
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
+ }
582
589
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 {
583
597
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
+ }
588
607
} ;
589
- Some ( OperandRef { val, layout } )
608
+ OperandRefBuilder { val, layout }
590
609
}
591
- }
592
610
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 > > (
595
612
& mut self ,
596
613
bx : & mut Bx ,
597
- v : VariantIdx ,
598
- f : FieldIdx ,
614
+ variant : VariantIdx ,
615
+ field : FieldIdx ,
599
616
operand : OperandRef < ' tcx , V > ,
600
617
) {
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 {
602
628
// The other branch looking at field layouts ICEs for primitives,
603
629
// 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 .
606
632
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
610
636
} 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
615
640
} ;
616
641
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.
619
647
let imm = transmute_scalar ( bx, src, from_scalar, to_scalar) ;
620
- * tgt = Ok ( imm) ;
648
+ * tgt = Either :: Left ( imm) ;
621
649
} ;
622
650
623
651
match ( operand. val , operand. layout . backend_repr ) {
624
- ( OperandValue :: ZeroSized , _) if expect_zst => { }
652
+ ( OperandValue :: ZeroSized , _) => unreachable ! ( "Handled above" ) ,
625
653
( 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 => {
627
655
update ( val, v, from_scalar) ;
628
656
}
629
- OperandValue :: Pair ( fst @ Err ( _) , _) if is_zero_offset => {
657
+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , _) if is_zero_offset => {
630
658
update ( fst, v, from_scalar) ;
631
659
}
632
- OperandValue :: Pair ( _, snd @ Err ( _) ) if !is_zero_offset => {
660
+ OperandValueBuilder :: Pair ( _, snd @ Either :: Right ( _) ) if !is_zero_offset => {
633
661
update ( snd, v, from_scalar) ;
634
662
}
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:?}" ) ,
636
670
} ,
637
671
( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( from_sa, from_sb) ) => {
638
672
match & mut self . val {
639
- OperandValue :: Pair ( fst @ Err ( _) , snd @ Err ( _) ) => {
673
+ OperandValueBuilder :: Pair ( fst @ Either :: Right ( _) , snd @ Either :: Right ( _) ) => {
640
674
update ( fst, a, from_sa) ;
641
675
update ( snd, b, from_sb) ;
642
676
}
643
- _ => bug ! ( "Tried to insert {operand:?} into {v :?}.{f :?} of {self:?}" ) ,
677
+ _ => bug ! ( "Tried to insert {operand:?} into {variant :?}.{field :?} of {self:?}" ) ,
644
678
}
645
679
}
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:?}" ) ,
647
689
}
648
690
}
649
691
@@ -656,45 +698,50 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, Result<V, abi::Scalar>> {
656
698
let field_offset = self . layout . fields . offset ( f. as_usize ( ) ) ;
657
699
let is_zero_offset = field_offset == Size :: ZERO ;
658
700
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) ;
661
703
}
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) ;
664
706
}
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) ;
667
709
}
668
710
_ => bug ! ( "Tried to insert {imm:?} into field {f:?} of {self:?}" ) ,
669
711
}
670
712
}
671
713
672
714
/// 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`])
674
716
/// to the normal `OperandValue<V>`.
675
717
///
676
718
/// 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 ;
679
721
680
722
// For something like `Option::<u32>::None`, it's expected that the
681
723
// payload scalar will not actually have been set, so this converts
682
724
// unset scalars to corresponding `undef` values so long as the scalar
683
725
// 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 ( ) => {
687
729
let bty = cx. type_from_scalar ( s) ;
688
730
cx. const_undef ( bty)
689
731
}
690
- Err ( _) => bug ! ( "OperandRef::build called while fields are missing {self:?}" ) ,
732
+ Either :: Right ( _) => bug ! ( "OperandRef::build called while fields are missing {self:?}" ) ,
691
733
} ;
692
734
693
735
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
+ } ,
698
745
} ;
699
746
OperandRef { val, layout }
700
747
}
0 commit comments