@@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem;
8
8
use rustc_middle:: mir:: { self , AssertKind , InlineAsmMacro , SwitchTargets , UnwindTerminateReason } ;
9
9
use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , ValidityRequirement } ;
10
10
use rustc_middle:: ty:: print:: { with_no_trimmed_paths, with_no_visible_paths} ;
11
- use rustc_middle:: ty:: { self , Instance , List , Ty } ;
11
+ use rustc_middle:: ty:: { self , Instance , Ty } ;
12
12
use rustc_middle:: { bug, span_bug} ;
13
13
use rustc_session:: config:: OptLevel ;
14
14
use rustc_span:: Span ;
@@ -941,37 +941,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
941
941
return merging_succ;
942
942
}
943
943
944
- let fn_abi = bx. fn_abi_of_instance ( instance, List :: empty ( ) ) ;
944
+ let result_layout =
945
+ self . cx . layout_of ( self . monomorphized_place_ty ( destination. as_ref ( ) ) ) ;
945
946
946
- let mut llargs = Vec :: with_capacity ( 1 ) ;
947
- let ret_dest = self . make_return_dest (
948
- bx,
949
- destination,
950
- & fn_abi. ret ,
951
- & mut llargs,
952
- Some ( intrinsic) ,
953
- ) ;
954
- let dest = match ret_dest {
955
- _ if fn_abi. ret . is_indirect ( ) => llargs[ 0 ] ,
956
- ReturnDest :: Nothing => bx. const_undef ( bx. type_ptr ( ) ) ,
957
- ReturnDest :: IndirectOperand ( dst, _) | ReturnDest :: Store ( dst) => {
958
- dst. val . llval
959
- }
960
- ReturnDest :: DirectOperand ( _) => {
961
- bug ! ( "Cannot use direct operand with an intrinsic call" )
947
+ let ( result, store_in_local) = if result_layout. is_zst ( ) {
948
+ (
949
+ PlaceRef :: new_sized ( bx. const_undef ( bx. type_ptr ( ) ) , result_layout) ,
950
+ None ,
951
+ )
952
+ } else if let Some ( local) = destination. as_local ( ) {
953
+ match self . locals [ local] {
954
+ LocalRef :: Place ( dest) => ( dest, None ) ,
955
+ LocalRef :: UnsizedPlace ( _) => bug ! ( "return type must be sized" ) ,
956
+ LocalRef :: PendingOperand => {
957
+ // Currently, intrinsics always need a location to store
958
+ // the result, so we create a temporary `alloca` for the
959
+ // result.
960
+ let tmp = PlaceRef :: alloca ( bx, result_layout) ;
961
+ tmp. storage_live ( bx) ;
962
+ ( tmp, Some ( local) )
963
+ }
964
+ LocalRef :: Operand ( _) => {
965
+ bug ! ( "place local already assigned to" ) ;
966
+ }
962
967
}
968
+ } else {
969
+ ( self . codegen_place ( bx, destination. as_ref ( ) ) , None )
963
970
} ;
964
971
972
+ if result. val . align < result. layout . align . abi {
973
+ // Currently, MIR code generation does not create calls
974
+ // that store directly to fields of packed structs (in
975
+ // fact, the calls it creates write only to temps).
976
+ //
977
+ // If someone changes that, please update this code path
978
+ // to create a temporary.
979
+ span_bug ! ( self . mir. span, "can't directly store to unaligned value" ) ;
980
+ }
981
+
965
982
let args: Vec < _ > =
966
983
args. iter ( ) . map ( |arg| self . codegen_operand ( bx, & arg. node ) ) . collect ( ) ;
967
984
968
- let result = PlaceRef :: new_sized ( dest, fn_abi. ret . layout ) ;
969
-
970
985
match self . codegen_intrinsic_call ( bx, instance, & args, result, source_info)
971
986
{
972
987
Ok ( ( ) ) => {
973
- if let ReturnDest :: IndirectOperand ( dst, _) = ret_dest {
974
- self . store_return ( bx, ret_dest, & fn_abi. ret , dst. val . llval ) ;
988
+ if let Some ( local) = store_in_local {
989
+ let op = bx. load_operand ( result) ;
990
+ result. storage_dead ( bx) ;
991
+ self . overwrite_local ( local, LocalRef :: Operand ( op) ) ;
992
+ self . debug_introduce_local ( bx, local) ;
975
993
}
976
994
977
995
return if let Some ( target) = target {
@@ -1026,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1026
1044
// We still need to call `make_return_dest` even if there's no `target`, since
1027
1045
// `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited,
1028
1046
// and `make_return_dest` adds the return-place indirect pointer to `llargs`.
1029
- let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs, None ) ;
1047
+ let return_dest = self . make_return_dest ( bx, destination, & fn_abi. ret , & mut llargs) ;
1030
1048
let destination = target. map ( |target| ( return_dest, target) ) ;
1031
1049
1032
1050
// Split the rust-call tupled arguments off.
@@ -1834,7 +1852,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1834
1852
dest : mir:: Place < ' tcx > ,
1835
1853
fn_ret : & ArgAbi < ' tcx , Ty < ' tcx > > ,
1836
1854
llargs : & mut Vec < Bx :: Value > ,
1837
- intrinsic : Option < ty:: IntrinsicDef > ,
1838
1855
) -> ReturnDest < ' tcx , Bx :: Value > {
1839
1856
// If the return is ignored, we can just return a do-nothing `ReturnDest`.
1840
1857
if fn_ret. is_ignore ( ) {
@@ -1854,13 +1871,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1854
1871
tmp. storage_live ( bx) ;
1855
1872
llargs. push ( tmp. val . llval ) ;
1856
1873
ReturnDest :: IndirectOperand ( tmp, index)
1857
- } else if intrinsic. is_some ( ) {
1858
- // Currently, intrinsics always need a location to store
1859
- // the result, so we create a temporary `alloca` for the
1860
- // result.
1861
- let tmp = PlaceRef :: alloca ( bx, fn_ret. layout ) ;
1862
- tmp. storage_live ( bx) ;
1863
- ReturnDest :: IndirectOperand ( tmp, index)
1864
1874
} else {
1865
1875
ReturnDest :: DirectOperand ( index)
1866
1876
} ;
@@ -1870,7 +1880,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1870
1880
}
1871
1881
}
1872
1882
} else {
1873
- self . codegen_place ( bx, mir :: PlaceRef { local : dest. local , projection : dest . projection } )
1883
+ self . codegen_place ( bx, dest. as_ref ( ) )
1874
1884
} ;
1875
1885
if fn_ret. is_indirect ( ) {
1876
1886
if dest. val . align < dest. layout . align . abi {
0 commit comments