1
1
use std:: fmt;
2
2
3
- use arrayvec:: ArrayVec ;
4
- use either:: Either ;
5
3
use rustc_abi as abi;
6
- use rustc_abi:: { Align , BackendRepr , FIRST_VARIANT , Primitive , Size , TagEncoding , Variants } ;
4
+ use rustc_abi:: {
5
+ Align , BackendRepr , FIRST_VARIANT , FieldIdx , Primitive , Size , TagEncoding , VariantIdx , Variants ,
6
+ } ;
7
7
use rustc_middle:: mir:: interpret:: { Pointer , Scalar , alloc_range} ;
8
8
use rustc_middle:: mir:: { self , ConstValue } ;
9
9
use rustc_middle:: ty:: Ty ;
@@ -13,6 +13,7 @@ use rustc_session::config::OptLevel;
13
13
use tracing:: { debug, instrument} ;
14
14
15
15
use super :: place:: { PlaceRef , PlaceValue } ;
16
+ use super :: rvalue:: transmute_immediate;
16
17
use super :: { FunctionCx , LocalRef } ;
17
18
use crate :: common:: IntPredicate ;
18
19
use crate :: traits:: * ;
@@ -69,31 +70,6 @@ pub enum OperandValue<V> {
69
70
}
70
71
71
72
impl < V : CodegenObject > OperandValue < V > {
72
- /// If this is ZeroSized/Immediate/Pair, return an array of the 0/1/2 values.
73
- /// If this is Ref, return the place.
74
- #[ inline]
75
- pub ( crate ) fn immediates_or_place ( self ) -> Either < ArrayVec < V , 2 > , PlaceValue < V > > {
76
- match self {
77
- OperandValue :: ZeroSized => Either :: Left ( ArrayVec :: new ( ) ) ,
78
- OperandValue :: Immediate ( a) => Either :: Left ( ArrayVec :: from_iter ( [ a] ) ) ,
79
- OperandValue :: Pair ( a, b) => Either :: Left ( [ a, b] . into ( ) ) ,
80
- OperandValue :: Ref ( p) => Either :: Right ( p) ,
81
- }
82
- }
83
-
84
- /// Given an array of 0/1/2 immediate values, return ZeroSized/Immediate/Pair.
85
- #[ inline]
86
- pub ( crate ) fn from_immediates ( immediates : ArrayVec < V , 2 > ) -> Self {
87
- let mut it = immediates. into_iter ( ) ;
88
- let Some ( a) = it. next ( ) else {
89
- return OperandValue :: ZeroSized ;
90
- } ;
91
- let Some ( b) = it. next ( ) else {
92
- return OperandValue :: Immediate ( a) ;
93
- } ;
94
- OperandValue :: Pair ( a, b)
95
- }
96
-
97
73
/// Treat this value as a pointer and return the data pointer and
98
74
/// optional metadata as backend values.
99
75
///
@@ -595,6 +571,115 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
595
571
}
596
572
}
597
573
}
574
+
575
+ /// Creates an incomplete operand containing the [`abi::Scalar`]s expected based
576
+ /// on the `layout` passed. This is for use with [`OperandRef::insert_field`]
577
+ /// later to set the necessary immediate(s).
578
+ ///
579
+ /// ICEs on types for which [`OperandRef::supports_builder`] returns false.
580
+ pub ( crate ) fn builder ( layout : TyAndLayout < ' tcx > ) -> OperandRef < ' tcx , Result < V , abi:: Scalar > > {
581
+ let val = match layout. backend_repr {
582
+ BackendRepr :: Memory { .. } if layout. is_zst ( ) => OperandValue :: ZeroSized ,
583
+ BackendRepr :: Scalar ( s) => OperandValue :: Immediate ( Err ( s) ) ,
584
+ BackendRepr :: ScalarPair ( a, b) => OperandValue :: Pair ( Err ( a) , Err ( b) ) ,
585
+ _ => bug ! ( "Cannot use type in operand builder: {layout:?}" ) ,
586
+ } ;
587
+ OperandRef { val, layout }
588
+ }
589
+
590
+ /// Determines whether [`OperandRef::builder`] is supported for this `layout`.
591
+ ///
592
+ /// Only needed by [`FunctionCx::rvalue_creates_operand`], but here so the
593
+ /// two `match`es are proximate in implementation.
594
+ pub ( crate ) fn supports_builder ( layout : TyAndLayout < ' tcx > ) -> bool {
595
+ match layout. backend_repr {
596
+ BackendRepr :: Memory { .. } if layout. is_zst ( ) => true ,
597
+ BackendRepr :: Scalar ( _) | BackendRepr :: ScalarPair ( _, _) => true ,
598
+ BackendRepr :: Memory { .. } | BackendRepr :: SimdVector { .. } => false ,
599
+ }
600
+ }
601
+ }
602
+
603
+ impl < ' a , ' tcx , V : CodegenObject > OperandRef < ' tcx , Result < V , abi:: Scalar > > {
604
+ pub ( crate ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
605
+ & mut self ,
606
+ bx : & mut Bx ,
607
+ v : VariantIdx ,
608
+ f : FieldIdx ,
609
+ operand : OperandRef < ' tcx , V > ,
610
+ ) {
611
+ let ( expect_zst, is_zero_offset) = if let abi:: FieldsShape :: Primitive = self . layout . fields {
612
+ // The other branch looking at field layouts ICEs for primitives,
613
+ // so we need to handle them separately.
614
+ // Multiple fields is possible for cases such as aggregating
615
+ // a thin pointer, where the second field is the unit.
616
+ assert ! ( !self . layout. is_zst( ) ) ;
617
+ assert_eq ! ( v, FIRST_VARIANT ) ;
618
+ let first_field = f == FieldIdx :: ZERO ;
619
+ ( !first_field, first_field)
620
+ } else {
621
+ let variant_layout = self . layout . for_variant ( bx. cx ( ) , v) ;
622
+ let field_layout = variant_layout. field ( bx. cx ( ) , f. as_usize ( ) ) ;
623
+ let field_offset = variant_layout. fields . offset ( f. as_usize ( ) ) ;
624
+ ( field_layout. is_zst ( ) , field_offset == Size :: ZERO )
625
+ } ;
626
+
627
+ let mut update = |tgt : & mut Result < V , abi:: Scalar > , src, from_scalar| {
628
+ let from_bty = bx. cx ( ) . type_from_scalar ( from_scalar) ;
629
+ let to_scalar = tgt. unwrap_err ( ) ;
630
+ let to_bty = bx. cx ( ) . type_from_scalar ( to_scalar) ;
631
+ let imm = transmute_immediate ( bx, src, from_scalar, from_bty, to_scalar, to_bty) ;
632
+ * tgt = Ok ( imm) ;
633
+ } ;
634
+
635
+ match ( operand. val , operand. layout . backend_repr ) {
636
+ ( OperandValue :: ZeroSized , _) if expect_zst => { }
637
+ ( OperandValue :: Immediate ( v) , BackendRepr :: Scalar ( from_scalar) ) => match & mut self . val {
638
+ OperandValue :: Immediate ( val @ Err ( _) ) if is_zero_offset => {
639
+ update ( val, v, from_scalar) ;
640
+ }
641
+ OperandValue :: Pair ( fst @ Err ( _) , _) if is_zero_offset => {
642
+ update ( fst, v, from_scalar) ;
643
+ }
644
+ OperandValue :: Pair ( _, snd @ Err ( _) ) if !is_zero_offset => {
645
+ update ( snd, v, from_scalar) ;
646
+ }
647
+ _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
648
+ } ,
649
+ ( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( from_sa, from_sb) ) => {
650
+ match & mut self . val {
651
+ OperandValue :: Pair ( fst @ Err ( _) , snd @ Err ( _) ) => {
652
+ update ( fst, a, from_sa) ;
653
+ update ( snd, b, from_sb) ;
654
+ }
655
+ _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
656
+ }
657
+ }
658
+ _ => bug ! ( "Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}" ) ,
659
+ }
660
+ }
661
+
662
+ /// After having set all necessary fields, this converts the
663
+ /// `OperandValue<Result<V, _>>` (as obtained from [`OperandRef::builder`])
664
+ /// to the normal `OperandValue<V>`.
665
+ ///
666
+ /// ICEs if any required fields were not set.
667
+ pub fn build ( & self ) -> OperandRef < ' tcx , V > {
668
+ let OperandRef { val, layout } = * self ;
669
+
670
+ let unwrap = |r : Result < V , abi:: Scalar > | match r {
671
+ Ok ( v) => v,
672
+ Err ( _) => bug ! ( "OperandRef::build called while fields are missing {self:?}" ) ,
673
+ } ;
674
+
675
+ let val = match val {
676
+ OperandValue :: ZeroSized => OperandValue :: ZeroSized ,
677
+ OperandValue :: Immediate ( v) => OperandValue :: Immediate ( unwrap ( v) ) ,
678
+ OperandValue :: Pair ( a, b) => OperandValue :: Pair ( unwrap ( a) , unwrap ( b) ) ,
679
+ OperandValue :: Ref ( _) => bug ! ( ) ,
680
+ } ;
681
+ OperandRef { val, layout }
682
+ }
598
683
}
599
684
600
685
impl < ' a , ' tcx , V : CodegenObject > OperandValue < V > {
0 commit comments