@@ -158,17 +158,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
158
158
debug_assert ! ( src. layout. is_sized( ) ) ;
159
159
debug_assert ! ( dst. layout. is_sized( ) ) ;
160
160
161
- if src. layout . size != dst. layout . size
162
- || src. layout . abi . is_uninhabited ( )
163
- || dst. layout . abi . is_uninhabited ( )
164
- {
165
- // In all of these cases it's UB to run this transmute, but that's
166
- // known statically so might as well trap for it, rather than just
167
- // making it unreachable.
168
- bx. abort ( ) ;
169
- return ;
170
- }
171
-
172
161
if let Some ( val) = self . codegen_transmute_operand ( bx, src, dst. layout ) {
173
162
val. store ( bx, dst) ;
174
163
return ;
@@ -202,8 +191,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
202
191
operand : OperandRef < ' tcx , Bx :: Value > ,
203
192
cast : TyAndLayout < ' tcx > ,
204
193
) -> Option < OperandValue < Bx :: Value > > {
205
- // Callers already checked that the layout sizes match
206
- debug_assert_eq ! ( operand. layout. size, cast. size) ;
194
+ // Check for transmutes that are always UB.
195
+ if operand. layout . size != cast. size
196
+ || operand. layout . abi . is_uninhabited ( )
197
+ || cast. abi . is_uninhabited ( )
198
+ {
199
+ if !operand. layout . abi . is_uninhabited ( ) {
200
+ // Since this is known statically and the input could have existed
201
+ // without already having hit UB, might as well trap for it.
202
+ bx. abort ( ) ;
203
+ }
204
+
205
+ // Because this transmute is UB, return something easy to generate,
206
+ // since it's fine that later uses of the value are probably UB.
207
+ return Some ( OperandValue :: poison ( bx, cast) ) ;
208
+ }
207
209
208
210
let operand_kind = self . value_kind ( operand. layout ) ;
209
211
let cast_kind = self . value_kind ( cast) ;
@@ -222,10 +224,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
222
224
bug ! ( "Found {operand_kind:?} for operand {operand:?}" ) ;
223
225
} ;
224
226
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
- ) ) )
227
+ match ( in_scalar, out_scalar) {
228
+ ( ScalarOrZst :: Zst , ScalarOrZst :: Zst ) => {
229
+ Some ( OperandRef :: new_zst ( bx, cast) . val )
230
+ }
231
+ ( ScalarOrZst :: Scalar ( in_scalar) , ScalarOrZst :: Scalar ( out_scalar) )
232
+ if in_scalar. size ( self . cx ) == out_scalar. size ( self . cx ) =>
233
+ {
234
+ let cast_bty = bx. backend_type ( cast) ;
235
+ Some ( OperandValue :: Immediate (
236
+ self . transmute_immediate ( bx, imm, in_scalar, out_scalar, cast_bty) ,
237
+ ) )
238
+ }
239
+ _ => None ,
240
+ }
229
241
} else {
230
242
None
231
243
}
@@ -234,12 +246,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
234
246
let OperandValueKind :: Pair ( in_a, in_b) = operand_kind else {
235
247
bug ! ( "Found {operand_kind:?} for operand {operand:?}" ) ;
236
248
} ;
237
- if let OperandValueKind :: Pair ( out_a, out_b) = cast_kind {
249
+ if let OperandValueKind :: Pair ( out_a, out_b) = cast_kind
250
+ && in_a. size ( self . cx ) == out_a. size ( self . cx )
251
+ && in_b. size ( self . cx ) == out_b. size ( self . cx )
252
+ {
238
253
let out_a_ibty = bx. scalar_pair_element_backend_type ( cast, 0 , false ) ;
239
254
let out_b_ibty = bx. scalar_pair_element_backend_type ( cast, 1 , false ) ;
240
255
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) ,
256
+ self . transmute_immediate ( bx, imm_a, in_a, out_a, out_a_ibty) ,
257
+ self . transmute_immediate ( bx, imm_b, in_b, out_b, out_b_ibty) ,
243
258
) )
244
259
} else {
245
260
None
@@ -254,12 +269,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
254
269
/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
255
270
/// `i8`, not `i1`, for `bool`-like types.)
256
271
fn transmute_immediate (
272
+ & self ,
257
273
bx : & mut Bx ,
258
274
mut imm : Bx :: Value ,
259
275
from_scalar : abi:: Scalar ,
260
276
to_scalar : abi:: Scalar ,
261
277
to_backend_ty : Bx :: Type ,
262
278
) -> Bx :: Value {
279
+ debug_assert_eq ! ( from_scalar. size( self . cx) , to_scalar. size( self . cx) ) ;
280
+
263
281
use abi:: Primitive :: * ;
264
282
imm = bx. from_immediate ( imm) ;
265
283
imm = match ( from_scalar. primitive ( ) , to_scalar. primitive ( ) ) {
@@ -831,14 +849,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
831
849
let operand_ty = operand. ty ( self . mir , self . cx . tcx ( ) ) ;
832
850
let cast_layout = self . cx . layout_of ( self . monomorphize ( cast_ty) ) ;
833
851
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
852
843
853
match ( self . value_kind ( operand_layout) , self . value_kind ( cast_layout) ) {
844
854
// Can always load from a pointer as needed
@@ -847,9 +857,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
847
857
// Need to generate an `alloc` to get a pointer from an immediate
848
858
( OperandValueKind :: Immediate ( ..) | OperandValueKind :: Pair ( ..) , OperandValueKind :: Ref ) => false ,
849
859
850
- // When we have scalar immediates, we can convert them as needed
851
- ( OperandValueKind :: Immediate ( ..) , OperandValueKind :: Immediate ( ..) ) |
852
- ( OperandValueKind :: Pair ( ..) , OperandValueKind :: Pair ( ..) ) => true ,
860
+ // When we have scalar immediates, we can only convert things
861
+ // where the sizes match, to avoid endianness questions.
862
+ ( OperandValueKind :: Immediate ( a) , OperandValueKind :: Immediate ( b) ) =>
863
+ a. size ( self . cx ) == b. size ( self . cx ) ,
864
+ ( OperandValueKind :: Pair ( a0, a1) , OperandValueKind :: Pair ( b0, b1) ) =>
865
+ a0. size ( self . cx ) == b0. size ( self . cx ) && a1. size ( self . cx ) == b1. size ( self . cx ) ,
853
866
854
867
// Send mixings between scalars and pairs through the memory route
855
868
// FIXME: Maybe this could use insertvalue/extractvalue instead?
@@ -887,13 +900,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
887
900
if self . cx . is_backend_immediate ( layout) {
888
901
debug_assert ! ( !self . cx. is_backend_scalar_pair( layout) ) ;
889
902
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" ) ,
903
+ abi:: Abi :: Scalar ( s) => ScalarOrZst :: Scalar ( s) ,
904
+ abi:: Abi :: Vector { element, .. } => ScalarOrZst :: Scalar ( element) ,
905
+ _ if layout. is_zst ( ) => ScalarOrZst :: Zst ,
906
+ x => span_bug ! ( self . mir. span, "Couldn't translate {x:?} as backend immediate" ) ,
893
907
} )
894
908
} else if self . cx . is_backend_scalar_pair ( layout) {
895
909
let abi:: Abi :: ScalarPair ( s1, s2) = layout. abi else {
896
- bug ! ( "Couldn't translate {:?} as backend scalar pair" , layout. abi)
910
+ span_bug ! (
911
+ self . mir. span,
912
+ "Couldn't translate {:?} as backend scalar pair" ,
913
+ layout. abi,
914
+ ) ;
897
915
} ;
898
916
OperandValueKind :: Pair ( s1, s2)
899
917
} else {
@@ -902,9 +920,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
902
920
}
903
921
}
904
922
923
+ /// The variants of this match [`OperandValue`], giving details about the
924
+ /// backend values that will be held in that other type.
905
925
#[ derive( Debug , Copy , Clone ) ]
906
926
enum OperandValueKind {
907
927
Ref ,
908
- Immediate ( abi :: Scalar ) ,
928
+ Immediate ( ScalarOrZst ) ,
909
929
Pair ( abi:: Scalar , abi:: Scalar ) ,
910
930
}
931
+
932
+ #[ derive( Debug , Copy , Clone ) ]
933
+ enum ScalarOrZst {
934
+ Zst ,
935
+ Scalar ( abi:: Scalar ) ,
936
+ }
937
+
938
+ impl ScalarOrZst {
939
+ pub fn size ( self , cx : & impl abi:: HasDataLayout ) -> abi:: Size {
940
+ match self {
941
+ ScalarOrZst :: Zst => abi:: Size :: ZERO ,
942
+ ScalarOrZst :: Scalar ( s) => s. size ( cx) ,
943
+ }
944
+ }
945
+ }
0 commit comments