11use std:: fmt;
22
3- use arrayvec:: ArrayVec ;
4- use either:: Either ;
53use 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+ } ;
77use rustc_middle:: mir:: interpret:: { Pointer , Scalar , alloc_range} ;
88use rustc_middle:: mir:: { self , ConstValue } ;
99use rustc_middle:: ty:: Ty ;
@@ -13,6 +13,7 @@ use rustc_session::config::OptLevel;
1313use tracing:: { debug, instrument} ;
1414
1515use super :: place:: { PlaceRef , PlaceValue } ;
16+ use super :: rvalue:: transmute_immediate;
1617use super :: { FunctionCx , LocalRef } ;
1718use crate :: common:: IntPredicate ;
1819use crate :: traits:: * ;
@@ -69,31 +70,6 @@ pub enum OperandValue<V> {
6970}
7071
7172impl < 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-
9773 /// Treat this value as a pointer and return the data pointer and
9874 /// optional metadata as backend values.
9975 ///
@@ -595,6 +571,105 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
595571 }
596572 }
597573 }
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+ }
598673}
599674
600675impl < ' a , ' tcx , V : CodegenObject > OperandValue < V > {
0 commit comments