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,105 @@ 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
+ /// Returns `None` for `layout`s which cannot be built this way.
580
+ pub ( crate ) fn builder (
581
+ layout : TyAndLayout < ' tcx > ,
582
+ ) -> Option < OperandRef < ' tcx , Result < V , abi:: Scalar > > > {
583
+ 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 ,
588
+ } ;
589
+ Some ( OperandRef { val, layout } )
590
+ }
591
+ }
592
+
593
+ impl < ' a , ' tcx , V : CodegenObject > OperandRef < ' tcx , Result < V , abi:: Scalar > > {
594
+ pub ( crate ) fn insert_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
595
+ & mut self ,
596
+ bx : & mut Bx ,
597
+ v : VariantIdx ,
598
+ f : FieldIdx ,
599
+ operand : OperandRef < ' tcx , V > ,
600
+ ) {
601
+ let ( expect_zst, is_zero_offset) = if let abi:: FieldsShape :: Primitive = self . layout . fields {
602
+ // The other branch looking at field layouts ICEs for primitives,
603
+ // 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.
606
+ assert ! ( !self . layout. is_zst( ) ) ;
607
+ assert_eq ! ( v, FIRST_VARIANT ) ;
608
+ let first_field = f == FieldIdx :: ZERO ;
609
+ ( !first_field, first_field)
610
+ } 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 )
615
+ } ;
616
+
617
+ let mut update = |tgt : & mut Result < V , abi:: Scalar > , src, from_scalar| {
618
+ let from_bty = bx. cx ( ) . type_from_scalar ( from_scalar) ;
619
+ let to_scalar = tgt. unwrap_err ( ) ;
620
+ let to_bty = bx. cx ( ) . type_from_scalar ( to_scalar) ;
621
+ let imm = transmute_immediate ( bx, src, from_scalar, from_bty, to_scalar, to_bty) ;
622
+ * tgt = Ok ( imm) ;
623
+ } ;
624
+
625
+ match ( operand. val , operand. layout . backend_repr ) {
626
+ ( OperandValue :: ZeroSized , _) if expect_zst => { }
627
+ ( OperandValue :: Immediate ( v) , BackendRepr :: Scalar ( from_scalar) ) => match & mut self . val {
628
+ OperandValue :: Immediate ( val @ Err ( _) ) if is_zero_offset => {
629
+ update ( val, v, from_scalar) ;
630
+ }
631
+ OperandValue :: Pair ( fst @ Err ( _) , _) if is_zero_offset => {
632
+ update ( fst, v, from_scalar) ;
633
+ }
634
+ OperandValue :: Pair ( _, snd @ Err ( _) ) if !is_zero_offset => {
635
+ update ( snd, v, from_scalar) ;
636
+ }
637
+ _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
638
+ } ,
639
+ ( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( from_sa, from_sb) ) => {
640
+ match & mut self . val {
641
+ OperandValue :: Pair ( fst @ Err ( _) , snd @ Err ( _) ) => {
642
+ update ( fst, a, from_sa) ;
643
+ update ( snd, b, from_sb) ;
644
+ }
645
+ _ => bug ! ( "Tried to insert {operand:?} into {v:?}.{f:?} of {self:?}" ) ,
646
+ }
647
+ }
648
+ _ => bug ! ( "Unsupported operand {operand:?} inserting into {v:?}.{f:?} of {self:?}" ) ,
649
+ }
650
+ }
651
+
652
+ /// After having set all necessary fields, this converts the
653
+ /// `OperandValue<Result<V, _>>` (as obtained from [`OperandRef::builder`])
654
+ /// to the normal `OperandValue<V>`.
655
+ ///
656
+ /// ICEs if any required fields were not set.
657
+ pub fn build ( & self ) -> OperandRef < ' tcx , V > {
658
+ let OperandRef { val, layout } = * self ;
659
+
660
+ let unwrap = |r : Result < V , abi:: Scalar > | match r {
661
+ Ok ( v) => v,
662
+ Err ( _) => bug ! ( "OperandRef::build called while fields are missing {self:?}" ) ,
663
+ } ;
664
+
665
+ let val = match val {
666
+ OperandValue :: ZeroSized => OperandValue :: ZeroSized ,
667
+ OperandValue :: Immediate ( v) => OperandValue :: Immediate ( unwrap ( v) ) ,
668
+ OperandValue :: Pair ( a, b) => OperandValue :: Pair ( unwrap ( a) , unwrap ( b) ) ,
669
+ OperandValue :: Ref ( _) => bug ! ( ) ,
670
+ } ;
671
+ OperandRef { val, layout }
672
+ }
598
673
}
599
674
600
675
impl < ' a , ' tcx , V : CodegenObject > OperandValue < V > {
0 commit comments