@@ -8,10 +8,10 @@ use crate::traits::*;
88use crate :: MemFlags ;
99
1010use rustc_middle:: mir;
11- use rustc_middle:: mir:: interpret:: { ConstValue , Pointer , Scalar } ;
11+ use rustc_middle:: mir:: interpret:: { alloc_range , ConstValue , Pointer , Scalar } ;
1212use rustc_middle:: ty:: layout:: { LayoutOf , TyAndLayout } ;
1313use rustc_middle:: ty:: Ty ;
14- use rustc_target:: abi:: { Abi , Align , Size } ;
14+ use rustc_target:: abi:: { self , Abi , Align , Size } ;
1515
1616use std:: fmt;
1717
@@ -115,13 +115,82 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
115115 OperandValue :: Pair ( a_llval, b_llval)
116116 }
117117 ConstValue :: ByRef { alloc, offset } => {
118- return bx . load_operand ( bx . from_const_alloc ( layout, alloc, offset) ) ;
118+ return Self :: from_const_alloc ( bx , layout, alloc, offset) ;
119119 }
120120 } ;
121121
122122 OperandRef { val, layout }
123123 }
124124
125+ fn from_const_alloc < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
126+ bx : & mut Bx ,
127+ layout : TyAndLayout < ' tcx > ,
128+ alloc : rustc_middle:: mir:: interpret:: ConstAllocation < ' tcx > ,
129+ offset : Size ,
130+ ) -> Self {
131+ let alloc_align = alloc. inner ( ) . align ;
132+ assert_eq ! ( alloc_align, layout. align. abi) ;
133+ let ty = bx. type_ptr_to ( bx. cx ( ) . backend_type ( layout) ) ;
134+
135+ let read_scalar = |start, size, s : abi:: Scalar , ty| {
136+ let val = alloc
137+ . 0
138+ . read_scalar (
139+ bx,
140+ alloc_range ( start, size) ,
141+ /*read_provenance*/ matches ! ( s. primitive( ) , abi:: Pointer ( _) ) ,
142+ )
143+ . unwrap ( ) ;
144+ bx. scalar_to_backend ( val, s, ty)
145+ } ;
146+
147+ // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point.
148+ // However, `MaybeUninit<u64>` is considered a `Scalar` as far as its layout is concerned --
149+ // and yet cannot be represented by an interpreter `Scalar`, since we have to handle the
150+ // case where some of the bytes are initialized and others are not. So, we need an extra
151+ // check that walks over the type of `mplace` to make sure it is truly correct to treat this
152+ // like a `Scalar` (or `ScalarPair`).
153+ match layout. abi {
154+ Abi :: Scalar ( s @ abi:: Scalar :: Initialized { .. } ) => {
155+ let size = s. size ( bx) ;
156+ assert_eq ! ( size, layout. size, "abi::Scalar size does not match layout size" ) ;
157+ let val = read_scalar ( Size :: ZERO , size, s, ty) ;
158+ OperandRef { val : OperandValue :: Immediate ( val) , layout }
159+ }
160+ Abi :: ScalarPair (
161+ a @ abi:: Scalar :: Initialized { .. } ,
162+ b @ abi:: Scalar :: Initialized { .. } ,
163+ ) => {
164+ let ( a_size, b_size) = ( a. size ( bx) , b. size ( bx) ) ;
165+ let b_offset = a_size. align_to ( b. align ( bx) . abi ) ;
166+ assert ! ( b_offset. bytes( ) > 0 ) ;
167+ let a_val = read_scalar (
168+ Size :: ZERO ,
169+ a_size,
170+ a,
171+ bx. scalar_pair_element_backend_type ( layout, 0 , true ) ,
172+ ) ;
173+ let b_val = read_scalar (
174+ b_offset,
175+ b_size,
176+ b,
177+ bx. scalar_pair_element_backend_type ( layout, 1 , true ) ,
178+ ) ;
179+ OperandRef { val : OperandValue :: Pair ( a_val, b_val) , layout }
180+ }
181+ _ if layout. is_zst ( ) => OperandRef :: new_zst ( bx, layout) ,
182+ _ => {
183+ // Neither a scalar nor scalar pair. Load from a place
184+ let init = bx. const_data_from_alloc ( alloc) ;
185+ let base_addr = bx. static_addr_of ( init, alloc_align, None ) ;
186+
187+ let llval = bx. const_ptr_byte_offset ( base_addr, offset) ;
188+ let llval = bx. const_bitcast ( llval, ty) ;
189+ bx. load_operand ( PlaceRef :: new_sized ( llval, layout) )
190+ }
191+ }
192+ }
193+
125194 /// Asserts that this operand refers to a scalar and returns
126195 /// a reference to its value.
127196 pub fn immediate ( self ) -> V {
0 commit comments