@@ -8,10 +8,10 @@ use crate::traits::*;
8
8
use crate :: MemFlags ;
9
9
10
10
use rustc_middle:: mir;
11
- use rustc_middle:: mir:: interpret:: { ConstValue , Pointer , Scalar } ;
11
+ use rustc_middle:: mir:: interpret:: { alloc_range , ConstValue , Pointer , Scalar } ;
12
12
use rustc_middle:: ty:: layout:: { LayoutOf , TyAndLayout } ;
13
13
use rustc_middle:: ty:: Ty ;
14
- use rustc_target:: abi:: { Abi , Align , Size } ;
14
+ use rustc_target:: abi:: { self , Abi , Align , Size } ;
15
15
16
16
use std:: fmt;
17
17
@@ -115,13 +115,82 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
115
115
OperandValue :: Pair ( a_llval, b_llval)
116
116
}
117
117
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) ;
119
119
}
120
120
} ;
121
121
122
122
OperandRef { val, layout }
123
123
}
124
124
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
+
125
194
/// Asserts that this operand refers to a scalar and returns
126
195
/// a reference to its value.
127
196
pub fn immediate ( self ) -> V {
0 commit comments