@@ -10,7 +10,7 @@ use crate::MemFlags;
10
10
use rustc_middle:: mir;
11
11
use rustc_middle:: mir:: Operand ;
12
12
use rustc_middle:: ty:: cast:: { CastTy , IntTy } ;
13
- use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf } ;
13
+ use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , TyAndLayout } ;
14
14
use rustc_middle:: ty:: { self , adjustment:: PointerCast , Instance , Ty , TyCtxt } ;
15
15
use rustc_span:: source_map:: { Span , DUMMY_SP } ;
16
16
use rustc_target:: abi:: { self , FIRST_VARIANT } ;
@@ -159,8 +159,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
159
159
debug_assert ! ( dst. layout. is_sized( ) ) ;
160
160
161
161
if src. layout . size != dst. layout . size
162
- || src. layout . abi == abi :: Abi :: Uninhabited
163
- || dst. layout . abi == abi :: Abi :: Uninhabited
162
+ || src. layout . abi . is_uninhabited ( )
163
+ || dst. layout . abi . is_uninhabited ( )
164
164
{
165
165
// In all of these cases it's UB to run this transmute, but that's
166
166
// known statically so might as well trap for it, rather than just
@@ -169,22 +169,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
169
169
return ;
170
170
}
171
171
172
- let size_in_bytes = src. layout . size . bytes ( ) ;
173
- if size_in_bytes == 0 {
174
- // Nothing to write
172
+ if let Some ( val) = self . codegen_transmute_operand ( bx, src, dst. layout ) {
173
+ val. store ( bx, dst) ;
175
174
return ;
176
175
}
177
176
178
177
match src. val {
179
- OperandValue :: Ref ( src_llval, meta, src_align) => {
180
- debug_assert_eq ! ( meta, None ) ;
181
- // For a place-to-place transmute, call `memcpy` directly so that
182
- // both arguments get the best-available alignment information.
183
- let bytes = bx. cx ( ) . const_usize ( size_in_bytes) ;
184
- let flags = MemFlags :: empty ( ) ;
185
- bx. memcpy ( dst. llval , dst. align , src_llval, src_align, bytes, flags) ;
178
+ OperandValue :: Ref ( ..) => {
179
+ span_bug ! (
180
+ self . mir. span,
181
+ "Operand path should have handled transmute \
182
+ from `Ref` {src:?} to place {dst:?}"
183
+ ) ;
186
184
}
187
- OperandValue :: Immediate ( _ ) | OperandValue :: Pair ( _ , _ ) => {
185
+ OperandValue :: Immediate ( .. ) | OperandValue :: Pair ( .. ) => {
188
186
// When we have immediate(s), the alignment of the source is irrelevant,
189
187
// so we can store them using the destination's alignment.
190
188
let llty = bx. backend_type ( src. layout ) ;
@@ -194,6 +192,94 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
194
192
}
195
193
}
196
194
195
+ /// Attempts to transmute an `OperandValue` to another `OperandValue`.
196
+ ///
197
+ /// Returns `None` for cases that can't work in that framework, such as for
198
+ /// `Immediate`->`Ref` that needs an `alloc` to get the location.
199
+ fn codegen_transmute_operand (
200
+ & mut self ,
201
+ bx : & mut Bx ,
202
+ operand : OperandRef < ' tcx , Bx :: Value > ,
203
+ cast : TyAndLayout < ' tcx > ,
204
+ ) -> Option < OperandValue < Bx :: Value > > {
205
+ // Callers already checked that the layout sizes match
206
+ debug_assert_eq ! ( operand. layout. size, cast. size) ;
207
+
208
+ let operand_kind = self . value_kind ( operand. layout ) ;
209
+ let cast_kind = self . value_kind ( cast) ;
210
+
211
+ match operand. val {
212
+ OperandValue :: Ref ( ptr, meta, align) => {
213
+ debug_assert_eq ! ( meta, None ) ;
214
+ debug_assert ! ( matches!( operand_kind, OperandValueKind :: Ref ) ) ;
215
+ let cast_bty = bx. backend_type ( cast) ;
216
+ let cast_ptr = bx. pointercast ( ptr, bx. type_ptr_to ( cast_bty) ) ;
217
+ let fake_place = PlaceRef :: new_sized_aligned ( cast_ptr, cast, align) ;
218
+ Some ( bx. load_operand ( fake_place) . val )
219
+ }
220
+ OperandValue :: Immediate ( imm) => {
221
+ let OperandValueKind :: Immediate ( in_scalar) = operand_kind else {
222
+ bug ! ( "Found {operand_kind:?} for operand {operand:?}" ) ;
223
+ } ;
224
+ if let OperandValueKind :: Immediate ( out_scalar) = cast_kind {
225
+ let cast_bty = bx. backend_type ( cast) ;
226
+ Some ( OperandValue :: Immediate ( Self :: transmute_immediate (
227
+ bx, imm, in_scalar, out_scalar, cast_bty,
228
+ ) ) )
229
+ } else {
230
+ None
231
+ }
232
+ }
233
+ OperandValue :: Pair ( imm_a, imm_b) => {
234
+ let OperandValueKind :: Pair ( in_a, in_b) = operand_kind else {
235
+ bug ! ( "Found {operand_kind:?} for operand {operand:?}" ) ;
236
+ } ;
237
+ if let OperandValueKind :: Pair ( out_a, out_b) = cast_kind {
238
+ let out_a_ibty = bx. scalar_pair_element_backend_type ( cast, 0 , false ) ;
239
+ let out_b_ibty = bx. scalar_pair_element_backend_type ( cast, 1 , false ) ;
240
+ Some ( OperandValue :: Pair (
241
+ Self :: transmute_immediate ( bx, imm_a, in_a, out_a, out_a_ibty) ,
242
+ Self :: transmute_immediate ( bx, imm_b, in_b, out_b, out_b_ibty) ,
243
+ ) )
244
+ } else {
245
+ None
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ /// Transmutes one of the immediates from an [`OperandValue::Immediate`]
252
+ /// or an [`OperandValue::Pair`] to an immediate of the target type.
253
+ ///
254
+ /// `to_backend_ty` must be the *non*-immediate backend type (so it will be
255
+ /// `i8`, not `i1`, for `bool`-like types.)
256
+ fn transmute_immediate (
257
+ bx : & mut Bx ,
258
+ mut imm : Bx :: Value ,
259
+ from_scalar : abi:: Scalar ,
260
+ to_scalar : abi:: Scalar ,
261
+ to_backend_ty : Bx :: Type ,
262
+ ) -> Bx :: Value {
263
+ use abi:: Primitive :: * ;
264
+ imm = bx. from_immediate ( imm) ;
265
+ imm = match ( from_scalar. primitive ( ) , to_scalar. primitive ( ) ) {
266
+ ( Int ( ..) | F32 | F64 , Int ( ..) | F32 | F64 ) => bx. bitcast ( imm, to_backend_ty) ,
267
+ ( Pointer ( ..) , Pointer ( ..) ) => bx. pointercast ( imm, to_backend_ty) ,
268
+ ( Int ( ..) , Pointer ( ..) ) => bx. inttoptr ( imm, to_backend_ty) ,
269
+ ( Pointer ( ..) , Int ( ..) ) => bx. ptrtoint ( imm, to_backend_ty) ,
270
+ ( F32 | F64 , Pointer ( ..) ) => {
271
+ let int_imm = bx. bitcast ( imm, bx. cx ( ) . type_isize ( ) ) ;
272
+ bx. inttoptr ( int_imm, to_backend_ty)
273
+ }
274
+ ( Pointer ( ..) , F32 | F64 ) => {
275
+ let int_imm = bx. ptrtoint ( imm, bx. cx ( ) . type_isize ( ) ) ;
276
+ bx. bitcast ( int_imm, to_backend_ty)
277
+ }
278
+ } ;
279
+ imm = bx. to_immediate_scalar ( imm, to_scalar) ;
280
+ imm
281
+ }
282
+
197
283
pub fn codegen_rvalue_unsized (
198
284
& mut self ,
199
285
bx : & mut Bx ,
@@ -396,7 +482,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
396
482
OperandValue :: Immediate ( newval)
397
483
}
398
484
mir:: CastKind :: Transmute => {
399
- bug ! ( "Transmute operand {:?} in `codegen_rvalue_operand`" , operand) ;
485
+ self . codegen_transmute_operand ( bx, operand, cast) . unwrap_or_else ( || {
486
+ bug ! ( "Unsupported transmute-as-operand of {operand:?} to {cast:?}" ) ;
487
+ } )
400
488
}
401
489
} ;
402
490
OperandRef { val, layout : cast }
@@ -739,10 +827,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
739
827
impl < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > FunctionCx < ' a , ' tcx , Bx > {
740
828
pub fn rvalue_creates_operand ( & self , rvalue : & mir:: Rvalue < ' tcx > , span : Span ) -> bool {
741
829
match * rvalue {
742
- mir:: Rvalue :: Cast ( mir:: CastKind :: Transmute , ..) =>
743
- // FIXME: Now that transmute is an Rvalue, it would be nice if
744
- // it could create `Immediate`s for scalars, where possible.
745
- false ,
830
+ mir:: Rvalue :: Cast ( mir:: CastKind :: Transmute , ref operand, cast_ty) => {
831
+ let operand_ty = operand. ty ( self . mir , self . cx . tcx ( ) ) ;
832
+ let cast_layout = self . cx . layout_of ( self . monomorphize ( cast_ty) ) ;
833
+ let operand_layout = self . cx . layout_of ( self . monomorphize ( operand_ty) ) ;
834
+ if operand_layout. size != cast_layout. size
835
+ || operand_layout. abi . is_uninhabited ( )
836
+ || cast_layout. abi . is_uninhabited ( )
837
+ {
838
+ // Send UB cases to the full form so the operand version can
839
+ // `bitcast` without worrying about malformed IR.
840
+ return false ;
841
+ }
842
+
843
+ match ( self . value_kind ( operand_layout) , self . value_kind ( cast_layout) ) {
844
+ // Can always load from a pointer as needed
845
+ ( OperandValueKind :: Ref , _) => true ,
846
+
847
+ // Need to generate an `alloc` to get a pointer from an immediate
848
+ ( OperandValueKind :: Immediate ( ..) | OperandValueKind :: Pair ( ..) , OperandValueKind :: Ref ) => false ,
849
+
850
+ // When we have scalar immediates, we can convert them as needed
851
+ ( OperandValueKind :: Immediate ( ..) , OperandValueKind :: Immediate ( ..) ) |
852
+ ( OperandValueKind :: Pair ( ..) , OperandValueKind :: Pair ( ..) ) => true ,
853
+
854
+ // Send mixings between scalars and pairs through the memory route
855
+ // FIXME: Maybe this could use insertvalue/extractvalue instead?
856
+ ( OperandValueKind :: Immediate ( ..) , OperandValueKind :: Pair ( ..) ) |
857
+ ( OperandValueKind :: Pair ( ..) , OperandValueKind :: Immediate ( ..) ) => false ,
858
+ }
859
+ }
746
860
mir:: Rvalue :: Ref ( ..) |
747
861
mir:: Rvalue :: CopyForDeref ( ..) |
748
862
mir:: Rvalue :: AddressOf ( ..) |
@@ -767,4 +881,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
767
881
768
882
// (*) this is only true if the type is suitable
769
883
}
884
+
885
+ /// Gets which variant of [`OperandValue`] is expected for a particular type.
886
+ fn value_kind ( & self , layout : TyAndLayout < ' tcx > ) -> OperandValueKind {
887
+ if self . cx . is_backend_immediate ( layout) {
888
+ debug_assert ! ( !self . cx. is_backend_scalar_pair( layout) ) ;
889
+ OperandValueKind :: Immediate ( match layout. abi {
890
+ abi:: Abi :: Scalar ( s) => s,
891
+ abi:: Abi :: Vector { element, .. } => element,
892
+ x => bug ! ( "Couldn't translate {x:?} as backend immediate" ) ,
893
+ } )
894
+ } else if self . cx . is_backend_scalar_pair ( layout) {
895
+ let abi:: Abi :: ScalarPair ( s1, s2) = layout. abi else {
896
+ bug ! ( "Couldn't translate {:?} as backend scalar pair" , layout. abi)
897
+ } ;
898
+ OperandValueKind :: Pair ( s1, s2)
899
+ } else {
900
+ OperandValueKind :: Ref
901
+ }
902
+ }
903
+ }
904
+
905
+ #[ derive( Debug , Copy , Clone ) ]
906
+ enum OperandValueKind {
907
+ Ref ,
908
+ Immediate ( abi:: Scalar ) ,
909
+ Pair ( abi:: Scalar , abi:: Scalar ) ,
770
910
}
0 commit comments