@@ -158,17 +158,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
158158 debug_assert ! ( src. layout. is_sized( ) ) ;
159159 debug_assert ! ( dst. layout. is_sized( ) ) ;
160160
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-
172161 if let Some ( val) = self . codegen_transmute_operand ( bx, src, dst. layout ) {
173162 val. store ( bx, dst) ;
174163 return ;
@@ -202,8 +191,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
202191 operand : OperandRef < ' tcx , Bx :: Value > ,
203192 cast : TyAndLayout < ' tcx > ,
204193 ) -> 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+ }
207209
208210 let operand_kind = self . value_kind ( operand. layout ) ;
209211 let cast_kind = self . value_kind ( cast) ;
@@ -222,10 +224,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
222224 bug ! ( "Found {operand_kind:?} for operand {operand:?}" ) ;
223225 } ;
224226 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+ }
229241 } else {
230242 None
231243 }
@@ -234,12 +246,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
234246 let OperandValueKind :: Pair ( in_a, in_b) = operand_kind else {
235247 bug ! ( "Found {operand_kind:?} for operand {operand:?}" ) ;
236248 } ;
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+ {
238253 let out_a_ibty = bx. scalar_pair_element_backend_type ( cast, 0 , false ) ;
239254 let out_b_ibty = bx. scalar_pair_element_backend_type ( cast, 1 , false ) ;
240255 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) ,
243258 ) )
244259 } else {
245260 None
@@ -254,12 +269,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
254269 /// `to_backend_ty` must be the *non*-immediate backend type (so it will be
255270 /// `i8`, not `i1`, for `bool`-like types.)
256271 fn transmute_immediate (
272+ & self ,
257273 bx : & mut Bx ,
258274 mut imm : Bx :: Value ,
259275 from_scalar : abi:: Scalar ,
260276 to_scalar : abi:: Scalar ,
261277 to_backend_ty : Bx :: Type ,
262278 ) -> Bx :: Value {
279+ debug_assert_eq ! ( from_scalar. size( self . cx) , to_scalar. size( self . cx) ) ;
280+
263281 use abi:: Primitive :: * ;
264282 imm = bx. from_immediate ( imm) ;
265283 imm = match ( from_scalar. primitive ( ) , to_scalar. primitive ( ) ) {
@@ -831,14 +849,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
831849 let operand_ty = operand. ty ( self . mir , self . cx . tcx ( ) ) ;
832850 let cast_layout = self . cx . layout_of ( self . monomorphize ( cast_ty) ) ;
833851 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- }
842852
843853 match ( self . value_kind ( operand_layout) , self . value_kind ( cast_layout) ) {
844854 // Can always load from a pointer as needed
@@ -847,9 +857,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
847857 // Need to generate an `alloc` to get a pointer from an immediate
848858 ( OperandValueKind :: Immediate ( ..) | OperandValueKind :: Pair ( ..) , OperandValueKind :: Ref ) => false ,
849859
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 ) ,
853866
854867 // Send mixings between scalars and pairs through the memory route
855868 // FIXME: Maybe this could use insertvalue/extractvalue instead?
@@ -887,13 +900,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
887900 if self . cx . is_backend_immediate ( layout) {
888901 debug_assert ! ( !self . cx. is_backend_scalar_pair( layout) ) ;
889902 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" ) ,
893907 } )
894908 } else if self . cx . is_backend_scalar_pair ( layout) {
895909 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+ ) ;
897915 } ;
898916 OperandValueKind :: Pair ( s1, s2)
899917 } else {
@@ -902,9 +920,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
902920 }
903921}
904922
923+ /// The variants of this match [`OperandValue`], giving details about the
924+ /// backend values that will be held in that other type.
905925#[ derive( Debug , Copy , Clone ) ]
906926enum OperandValueKind {
907927 Ref ,
908- Immediate ( abi :: Scalar ) ,
928+ Immediate ( ScalarOrZst ) ,
909929 Pair ( abi:: Scalar , abi:: Scalar ) ,
910930}
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