@@ -895,6 +895,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
895895 & mut self ,
896896 instance : ty:: Instance < ' tcx > ,
897897 args : & [ OperandRef < ' tcx , Self :: Value > ] ,
898+ return_slot : ReturnSlot < Self :: Value > ,
898899 _is_cleanup : bool ,
899900 ) -> Self :: Value {
900901 let tcx = self . tcx ( ) ;
@@ -909,10 +910,15 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
909910 assert ! ( !fn_sig. c_variadic( ) ) ;
910911
911912 let ret_layout = self . layout_of ( fn_sig. output ( ) ) ;
912- let llreturn_ty = if ret_layout. is_zst ( ) {
913- self . type_void ( )
913+ let ( llreturn_ty, return_struct_fields) = if ret_layout. is_zst ( ) {
914+ ( self . type_void ( ) , vec ! [ ] )
915+ } else if ret_layout. is_aggregate ( ) {
916+ let fields =
917+ rustc_codegen_ssa:: mir:: intrinsic_return_struct_non_zst_fields ( self . cx , ret_layout) ;
918+ let llvm_fields = fields. iter ( ) . copied ( ) . map ( |( t, _) | t) . collect :: < Vec < _ > > ( ) ;
919+ ( self . type_struct ( & llvm_fields, false ) , fields)
914920 } else {
915- ret_layout. immediate_llvm_type ( self )
921+ ( ret_layout. immediate_llvm_type ( self ) , vec ! [ ] )
916922 } ;
917923
918924 let mut llargument_tys = Vec :: with_capacity ( fn_sig. inputs ( ) . len ( ) ) ;
@@ -996,14 +1002,33 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
9961002 )
9971003 } ;
9981004
999- let src_ty = self . val_ty ( llret) ;
1000- let dest_ty = llreturn_ty;
1001- assert ! (
1002- can_autocast( self , dest_ty, src_ty) ,
1003- "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
1004- ) ;
1005+ if return_struct_fields. is_empty ( ) {
1006+ let src_ty = self . val_ty ( llret) ;
1007+ let dest_ty = llreturn_ty;
1008+ assert ! (
1009+ can_autocast( self , dest_ty, src_ty) ,
1010+ "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
1011+ ) ;
10051012
1006- autocast ( self , llret, src_ty, dest_ty)
1013+ autocast ( self , llret, src_ty, dest_ty)
1014+ } else {
1015+ let fields = return_struct_fields. into_iter ( ) . enumerate ( ) . map ( |( i, ( dest_ty, offset) ) | {
1016+ let value = self . extract_value ( llret, i as u64 ) ;
1017+ let src_ty = self . val_ty ( value) ;
1018+ assert ! (
1019+ can_autocast( self , dest_ty, src_ty) ,
1020+ "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
1021+ ) ;
1022+ let value = autocast ( self , value, src_ty, dest_ty) ;
1023+ ( offset, value)
1024+ } ) . collect ( ) ;
1025+ rustc_codegen_ssa:: mir:: store_intrinsic_return_struct (
1026+ self ,
1027+ ret_layout,
1028+ return_slot,
1029+ fields,
1030+ )
1031+ }
10071032 }
10081033
10091034 fn abort_immediate ( & mut self ) {
@@ -1089,23 +1114,6 @@ fn can_autocast<'ll>(cx: &CodegenCx<'ll, '_>, rust_ty: &'ll Type, llvm_ty: &'ll
10891114 }
10901115
10911116 match cx. type_kind ( llvm_ty) {
1092- // Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust
1093- // due to auto field-alignment in non-packed structs (packed structs are represented in LLVM
1094- // as, well, packed structs, so they won't match with those either)
1095- TypeKind :: Struct if cx. type_kind ( rust_ty) == TypeKind :: Struct => {
1096- let rust_element_tys = cx. struct_element_types ( rust_ty) ;
1097- let llvm_element_tys = cx. struct_element_types ( llvm_ty) ;
1098-
1099- if rust_element_tys. len ( ) != llvm_element_tys. len ( ) {
1100- return false ;
1101- }
1102-
1103- iter:: zip ( rust_element_tys, llvm_element_tys) . all (
1104- |( rust_element_ty, llvm_element_ty) | {
1105- can_autocast ( cx, rust_element_ty, llvm_element_ty)
1106- } ,
1107- )
1108- }
11091117 TypeKind :: Vector => {
11101118 let llvm_element_ty = cx. element_type ( llvm_ty) ;
11111119 let element_count = cx. vector_length ( llvm_ty) as u64 ;
@@ -1152,19 +1160,6 @@ fn autocast<'ll>(
11521160 return val;
11531161 }
11541162 match ( bx. type_kind ( src_ty) , bx. type_kind ( dest_ty) ) {
1155- // re-pack structs
1156- ( TypeKind :: Struct , TypeKind :: Struct ) => {
1157- let mut ret = bx. const_poison ( dest_ty) ;
1158- for ( idx, ( src_element_ty, dest_element_ty) ) in
1159- iter:: zip ( bx. struct_element_types ( src_ty) , bx. struct_element_types ( dest_ty) )
1160- . enumerate ( )
1161- {
1162- let elt = bx. extract_value ( val, idx as u64 ) ;
1163- let casted_elt = autocast ( bx, elt, src_element_ty, dest_element_ty) ;
1164- ret = bx. insert_value ( ret, casted_elt, idx as u64 ) ;
1165- }
1166- ret
1167- }
11681163 // cast from the i1xN vector type to the primitive type
11691164 ( TypeKind :: Vector , TypeKind :: Integer ) if bx. element_type ( src_ty) == bx. type_i1 ( ) => {
11701165 let vector_length = bx. vector_length ( src_ty) as u64 ;
@@ -1258,9 +1253,17 @@ fn intrinsic_fn<'ll, 'tcx>(
12581253 let llvm_argument_tys = bx. func_params_types ( llvm_fn_ty) ;
12591254 let llvm_is_variadic = bx. func_is_variadic ( llvm_fn_ty) ;
12601255
1256+ let ( rust_return_tys, llvm_return_tys) = if bx. type_kind ( rust_return_ty) == TypeKind :: Struct
1257+ && bx. type_kind ( llvm_return_ty) == TypeKind :: Struct
1258+ {
1259+ ( bx. struct_element_types ( rust_return_ty) , bx. struct_element_types ( llvm_return_ty) )
1260+ } else {
1261+ ( vec ! [ rust_return_ty] , vec ! [ llvm_return_ty] )
1262+ } ;
12611263 let is_correct_signature = !llvm_is_variadic
12621264 && rust_argument_tys. len ( ) == llvm_argument_tys. len ( )
1263- && iter:: once ( ( rust_return_ty, llvm_return_ty) )
1265+ && rust_return_tys. len ( ) == llvm_return_tys. len ( )
1266+ && iter:: zip ( rust_return_tys, llvm_return_tys)
12641267 . chain ( iter:: zip ( rust_argument_tys, llvm_argument_tys) )
12651268 . all ( |( rust_ty, llvm_ty) | can_autocast ( bx, rust_ty, llvm_ty) ) ;
12661269
0 commit comments