@@ -852,63 +852,74 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
852
852
op : OperandRef < ' tcx > ) {
853
853
use self :: ReturnDest :: * ;
854
854
855
- match dest {
856
- Nothing => ( ) ,
855
+ // Handle the simple cases that don't require casts, first.
856
+ let llcast_ty = match dest {
857
+ Nothing => return ,
857
858
Store ( dst) => {
858
859
if let Some ( llcast_ty) = ret_ty. cast {
859
- let ccx = bcx. ccx ( ) ;
860
- // The actual return type is a struct, but the ABI
861
- // adaptation code has cast it into some scalar type. The
862
- // code that follows is the only reliable way I have
863
- // found to do a transform like i64 -> {i32,i32}.
864
- // Basically we dump the data onto the stack then memcpy it.
865
- //
866
- // Other approaches I tried:
867
- // - Casting rust ret pointer to the foreign type and using Store
868
- // is (a) unsafe if size of foreign type > size of rust type and
869
- // (b) runs afoul of strict aliasing rules, yielding invalid
870
- // assembly under -O (specifically, the store gets removed).
871
- // - Truncating foreign type to correct integral type and then
872
- // bitcasting to the struct type yields invalid cast errors.
873
-
874
- // We instead thus allocate some scratch space...
875
- let llscratch = bcx. alloca ( llcast_ty, "fn_ret_cast" ) ;
876
- bcx. with_block ( |bcx| base:: call_lifetime_start ( bcx, llscratch) ) ;
877
-
878
- // ...where we first store the value...
879
- bcx. store ( op. immediate ( ) , llscratch) ;
880
-
881
- // ...and then memcpy it to the intended destination.
882
- base:: call_memcpy ( bcx,
883
- bcx. pointercast ( dst, Type :: i8p ( ccx) ) ,
884
- bcx. pointercast ( llscratch, Type :: i8p ( ccx) ) ,
885
- C_uint ( ccx, llsize_of_store ( ccx, ret_ty. original_ty ) ) ,
886
- cmp:: min ( llalign_of_min ( ccx, ret_ty. original_ty ) ,
887
- llalign_of_min ( ccx, llcast_ty) ) as u32 ) ;
888
-
889
- bcx. with_block ( |bcx| base:: call_lifetime_end ( bcx, llscratch) ) ;
860
+ llcast_ty
890
861
} else {
891
862
ret_ty. store ( bcx, op. immediate ( ) , dst) ;
863
+ return ;
892
864
}
893
865
}
894
866
IndirectOperand ( tmp, idx) => {
895
867
let op = self . trans_load ( bcx, tmp, op. ty ) ;
896
868
self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
869
+ return ;
897
870
}
898
871
DirectOperand ( idx) => {
899
- // If there is a cast, we have to store and reload.
900
- let op = if ret_ty. cast . is_some ( ) {
901
- let tmp = bcx. with_block ( |bcx| {
902
- base:: alloc_ty ( bcx, op. ty , "tmp_ret" )
903
- } ) ;
904
- ret_ty. store ( bcx, op. immediate ( ) , tmp) ;
905
- self . trans_load ( bcx, tmp, op. ty )
872
+ if let Some ( llcast_ty) = ret_ty. cast {
873
+ llcast_ty
906
874
} else {
907
- op. unpack_if_pair ( bcx)
908
- } ;
875
+ let op = op. unpack_if_pair ( bcx) ;
876
+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
877
+ return ;
878
+ }
879
+ }
880
+ } ;
881
+
882
+ // The actual return type is a struct, but the ABI
883
+ // adaptation code has cast it into some scalar type. The
884
+ // code that follows is the only reliable way I have
885
+ // found to do a transform like i64 -> {i32,i32}.
886
+ // Basically we dump the data onto the stack then memcpy it.
887
+ //
888
+ // Other approaches I tried:
889
+ // - Casting rust ret pointer to the foreign type and using Store
890
+ // is (a) unsafe if size of foreign type > size of rust type and
891
+ // (b) runs afoul of strict aliasing rules, yielding invalid
892
+ // assembly under -O (specifically, the store gets removed).
893
+ // - Truncating foreign type to correct integral type and then
894
+ // bitcasting to the struct type yields invalid cast errors.
895
+
896
+ // We instead thus allocate some scratch space...
897
+ let llscratch = bcx. alloca ( llcast_ty, "fn_ret_cast" ) ;
898
+ bcx. with_block ( |bcx| base:: call_lifetime_start ( bcx, llscratch) ) ;
899
+
900
+ // ...where we first store the value...
901
+ bcx. store ( op. immediate ( ) , llscratch) ;
902
+
903
+ let ccx = bcx. ccx ( ) ;
904
+ match dest {
905
+ Store ( dst) => {
906
+ // ...and then memcpy it to the intended destination.
907
+ base:: call_memcpy ( bcx,
908
+ bcx. pointercast ( dst, Type :: i8p ( ccx) ) ,
909
+ bcx. pointercast ( llscratch, Type :: i8p ( ccx) ) ,
910
+ C_uint ( ccx, llsize_of_store ( ccx, ret_ty. original_ty ) ) ,
911
+ cmp:: min ( llalign_of_min ( ccx, ret_ty. original_ty ) ,
912
+ llalign_of_min ( ccx, llcast_ty) ) as u32 ) ;
913
+ }
914
+ DirectOperand ( idx) => {
915
+ let llptr = bcx. pointercast ( llscratch, ret_ty. original_ty . ptr_to ( ) ) ;
916
+ let op = self . trans_load ( bcx, llptr, op. ty ) ;
909
917
self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
910
918
}
919
+ Nothing | IndirectOperand ( _, _) => bug ! ( )
911
920
}
921
+
922
+ bcx. with_block ( |bcx| base:: call_lifetime_end ( bcx, llscratch) ) ;
912
923
}
913
924
}
914
925
0 commit comments