@@ -5,11 +5,11 @@ use arrayvec::ArrayVec;
55use either:: Either ;
66use rustc_abi as abi;
77use rustc_abi:: { Align , BackendRepr , Size } ;
8- use rustc_middle:: bug;
98use rustc_middle:: mir:: interpret:: { Pointer , Scalar , alloc_range} ;
109use rustc_middle:: mir:: { self , ConstValue } ;
1110use rustc_middle:: ty:: Ty ;
1211use rustc_middle:: ty:: layout:: { LayoutOf , TyAndLayout } ;
12+ use rustc_middle:: { bug, span_bug} ;
1313use tracing:: debug;
1414
1515use super :: place:: { PlaceRef , PlaceValue } ;
@@ -352,79 +352,81 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
352352
353353 pub ( crate ) fn extract_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
354354 & self ,
355+ fx : & mut FunctionCx < ' a , ' tcx , Bx > ,
355356 bx : & mut Bx ,
356357 i : usize ,
357358 ) -> Self {
358359 let field = self . layout . field ( bx. cx ( ) , i) ;
359360 let offset = self . layout . fields . offset ( i) ;
360361
361- let mut val = match ( self . val , self . layout . backend_repr ) {
362- // If the field is ZST, it has no data.
363- _ if field. is_zst ( ) => OperandValue :: ZeroSized ,
362+ let val = if field. size == self . layout . size
363+ && let Some ( field_val) = fx. codegen_transmute_operand ( bx, * self , field)
364+ {
365+ assert_eq ! ( offset. bytes( ) , 0 ) ;
366+ field_val
367+ } else if field. is_zst ( ) {
368+ OperandValue :: ZeroSized
369+ } else {
370+ let ( in_scalar, imm) = match ( self . val , self . layout . backend_repr ) {
371+ // Extract a scalar component from a pair.
372+ ( OperandValue :: Pair ( a_llval, b_llval) , BackendRepr :: ScalarPair ( a, b) ) => {
373+ if offset. bytes ( ) == 0 {
374+ assert_eq ! ( field. size, a. size( bx. cx( ) ) ) ;
375+ ( Some ( a) , a_llval)
376+ } else {
377+ assert_eq ! ( offset, a. size( bx. cx( ) ) . align_to( b. align( bx. cx( ) ) . abi) ) ;
378+ assert_eq ! ( field. size, b. size( bx. cx( ) ) ) ;
379+ ( Some ( b) , b_llval)
380+ }
381+ }
364382
365- // Newtype of a scalar, scalar pair or vector.
366- ( OperandValue :: Immediate ( _) | OperandValue :: Pair ( ..) , _)
367- if field. size == self . layout . size =>
368- {
369- assert_eq ! ( offset. bytes( ) , 0 ) ;
370- self . val
371- }
383+ // `#[repr(simd)]` types are also immediate.
384+ ( OperandValue :: Immediate ( llval) , BackendRepr :: Vector { .. } ) => {
385+ ( None , bx. extract_element ( llval, bx. cx ( ) . const_usize ( i as u64 ) ) )
386+ }
372387
373- // Extract a scalar component from a pair.
374- ( OperandValue :: Pair ( a_llval, b_llval) , BackendRepr :: ScalarPair ( a, b) ) => {
375- if offset. bytes ( ) == 0 {
376- assert_eq ! ( field. size, a. size( bx. cx( ) ) ) ;
377- OperandValue :: Immediate ( a_llval)
378- } else {
379- assert_eq ! ( offset, a. size( bx. cx( ) ) . align_to( b. align( bx. cx( ) ) . abi) ) ;
380- assert_eq ! ( field. size, b. size( bx. cx( ) ) ) ;
381- OperandValue :: Immediate ( b_llval)
388+ _ => {
389+ span_bug ! ( fx. mir. span, "OperandRef::extract_field({:?}): not applicable" , self )
382390 }
383- }
391+ } ;
392+ OperandValue :: Immediate ( match field. backend_repr {
393+ BackendRepr :: Vector { .. } => imm,
394+ BackendRepr :: Scalar ( out_scalar) => {
395+ let Some ( in_scalar) = in_scalar else {
396+ span_bug ! (
397+ fx. mir. span,
398+ "OperandRef::extract_field({:?}): missing input scalar for output scalar" ,
399+ self
400+ )
401+ } ;
402+ if in_scalar != out_scalar {
403+ // If the backend and backend_immediate types might differ,
404+ // flip back to the backend type then to the new immediate.
405+ // This avoids nop truncations, but still handles things like
406+ // Bools in union fields needs to be truncated.
407+ let backend = bx. from_immediate ( imm) ;
408+ bx. to_immediate_scalar ( backend, out_scalar)
409+ } else {
410+ imm
411+ }
412+ }
413+ // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
414+ BackendRepr :: Memory { sized : true } => {
415+ assert_matches ! ( self . layout. backend_repr, BackendRepr :: Vector { .. } ) ;
384416
385- // `#[repr(simd)]` types are also immediate.
386- ( OperandValue :: Immediate ( llval) , BackendRepr :: Vector { .. } ) => {
387- OperandValue :: Immediate ( bx. extract_element ( llval, bx. cx ( ) . const_usize ( i as u64 ) ) )
388- }
417+ let llfield_ty = bx. cx ( ) . backend_type ( field) ;
389418
390- _ => bug ! ( "OperandRef::extract_field({:?}): not applicable" , self ) ,
419+ // Can't bitcast an aggregate, so round trip through memory.
420+ let llptr = bx. alloca ( field. size , field. align . abi ) ;
421+ bx. store ( imm, llptr, field. align . abi ) ;
422+ bx. load ( llfield_ty, llptr, field. align . abi )
423+ }
424+ BackendRepr :: Uninhabited
425+ | BackendRepr :: ScalarPair ( _, _)
426+ | BackendRepr :: Memory { sized : false } => bug ! ( ) ,
427+ } )
391428 } ;
392429
393- match ( & mut val, field. backend_repr ) {
394- ( OperandValue :: ZeroSized , _) => { }
395- (
396- OperandValue :: Immediate ( llval) ,
397- BackendRepr :: Scalar ( _) | BackendRepr :: ScalarPair ( ..) | BackendRepr :: Vector { .. } ,
398- ) => {
399- // Bools in union fields needs to be truncated.
400- * llval = bx. to_immediate ( * llval, field) ;
401- }
402- ( OperandValue :: Pair ( a, b) , BackendRepr :: ScalarPair ( a_abi, b_abi) ) => {
403- // Bools in union fields needs to be truncated.
404- * a = bx. to_immediate_scalar ( * a, a_abi) ;
405- * b = bx. to_immediate_scalar ( * b, b_abi) ;
406- }
407- // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
408- ( OperandValue :: Immediate ( llval) , BackendRepr :: Memory { sized : true } ) => {
409- assert_matches ! ( self . layout. backend_repr, BackendRepr :: Vector { .. } ) ;
410-
411- let llfield_ty = bx. cx ( ) . backend_type ( field) ;
412-
413- // Can't bitcast an aggregate, so round trip through memory.
414- let llptr = bx. alloca ( field. size , field. align . abi ) ;
415- bx. store ( * llval, llptr, field. align . abi ) ;
416- * llval = bx. load ( llfield_ty, llptr, field. align . abi ) ;
417- }
418- (
419- OperandValue :: Immediate ( _) ,
420- BackendRepr :: Uninhabited | BackendRepr :: Memory { sized : false } ,
421- ) => {
422- bug ! ( )
423- }
424- ( OperandValue :: Pair ( ..) , _) => bug ! ( ) ,
425- ( OperandValue :: Ref ( ..) , _) => bug ! ( ) ,
426- }
427-
428430 OperandRef { val, layout : field }
429431 }
430432}
@@ -587,7 +589,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
587589 "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
588590 but tried to access field {f:?} of pointer {o:?}",
589591 ) ;
590- o = o. extract_field ( bx, f. index ( ) ) ;
592+ o = o. extract_field ( self , bx, f. index ( ) ) ;
591593 }
592594 mir:: ProjectionElem :: Index ( _)
593595 | mir:: ProjectionElem :: ConstantIndex { .. } => {
0 commit comments