1111use llvm:: { self , BasicBlockRef , ValueRef , OperandBundleDef } ;
1212use rustc:: ty;
1313use rustc:: mir:: repr as mir;
14- use abi:: { Abi , FnType } ;
14+ use abi:: { Abi , FnType , ArgType } ;
1515use adt;
1616use base;
1717use build;
1818use callee:: { Callee , CalleeData , Fn , Intrinsic , NamedTupleConstructor , Virtual } ;
19- use common:: { self , Block , BlockAndBuilder , C_undef } ;
19+ use common:: { self , type_is_fat_ptr , Block , BlockAndBuilder , C_undef } ;
2020use debuginfo:: DebugLoc ;
2121use Disr ;
2222use machine:: { llalign_of_min, llbitsize_of_real} ;
@@ -25,7 +25,7 @@ use type_of;
2525use glue;
2626use type_:: Type ;
2727
28- use super :: { MirContext , drop} ;
28+ use super :: { MirContext , TempRef , drop} ;
2929use super :: lvalue:: { LvalueRef , load_fat_ptr} ;
3030use super :: operand:: OperandRef ;
3131use super :: operand:: OperandValue :: { self , FatPtr , Immediate , Ref } ;
@@ -169,6 +169,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
169169 _ => bug ! ( "{} is not callable" , callee. ty)
170170 } ;
171171
172+ let sig = bcx. tcx ( ) . erase_late_bound_regions ( sig) ;
173+
172174 // Handle intrinsics old trans wants Expr's for, ourselves.
173175 let intrinsic = match ( & callee. ty . sty , & callee. data ) {
174176 ( & ty:: TyFnDef ( def_id, _, _) , & Intrinsic ) => {
@@ -191,31 +193,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
191193
192194 if intrinsic == Some ( "transmute" ) {
193195 let & ( ref dest, target) = destination. as_ref ( ) . unwrap ( ) ;
194- let dst = self . trans_lvalue ( & bcx, dest) ;
195- let mut val = self . trans_operand ( & bcx, & args[ 0 ] ) ;
196- if let ty:: TyFnDef ( def_id, substs, _) = val. ty . sty {
197- let llouttype = type_of:: type_of ( bcx. ccx ( ) , dst. ty . to_ty ( bcx. tcx ( ) ) ) ;
198- let out_type_size = llbitsize_of_real ( bcx. ccx ( ) , llouttype) ;
199- if out_type_size != 0 {
200- // FIXME #19925 Remove this hack after a release cycle.
201- let f = Callee :: def ( bcx. ccx ( ) , def_id, substs) ;
202- let datum = f. reify ( bcx. ccx ( ) ) ;
203- val = OperandRef {
204- val : OperandValue :: Immediate ( datum. val ) ,
205- ty : datum. ty
206- } ;
207- }
208- }
196+ self . with_lvalue_ref ( & bcx, dest, |this, dest| {
197+ this. trans_transmute ( & bcx, & args[ 0 ] , dest) ;
198+ } ) ;
209199
210- let llty = type_of:: type_of ( bcx. ccx ( ) , val. ty ) ;
211- let cast_ptr = bcx. pointercast ( dst. llval , llty. ptr_to ( ) ) ;
212- self . store_operand ( & bcx, cast_ptr, val) ;
213200 self . set_operand_dropped ( & bcx, & args[ 0 ] ) ;
214201 funclet_br ( bcx, self . llblock ( target) ) ;
215202 return ;
216203 }
217204
218- let extra_args = & args[ sig. 0 . inputs . len ( ) ..] ;
205+ let extra_args = & args[ sig. inputs . len ( ) ..] ;
219206 let extra_args = extra_args. iter ( ) . map ( |op_arg| {
220207 self . mir . operand_ty ( bcx. tcx ( ) , op_arg)
221208 } ) . collect :: < Vec < _ > > ( ) ;
@@ -226,18 +213,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
226213 let mut llargs = Vec :: with_capacity ( arg_count) ;
227214
228215 // Prepare the return value destination
229- let ret_dest = if let Some ( ( ref d, _) ) = * destination {
230- let dest = self . trans_lvalue ( & bcx, d) ;
231- if fn_ty. ret . is_indirect ( ) {
232- llargs. push ( dest. llval ) ;
233- None
234- } else if fn_ty. ret . is_ignore ( ) {
235- None
216+ let ret_dest = if let Some ( ( ref dest, _) ) = * destination {
217+ let is_intrinsic = if let Intrinsic = callee. data {
218+ true
236219 } else {
237- Some ( dest)
238- }
220+ false
221+ } ;
222+ self . make_return_dest ( & bcx, dest, & fn_ty. ret , & mut llargs, is_intrinsic)
239223 } else {
240- None
224+ ReturnDest :: Nothing
241225 } ;
242226
243227 // Split the rust-call tupled arguments off.
@@ -269,29 +253,42 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
269253 use expr:: { Ignore , SaveIn } ;
270254 use intrinsic:: trans_intrinsic_call;
271255
272- let ( dest, llargs) = if fn_ty. ret . is_indirect ( ) {
273- ( SaveIn ( llargs[ 0 ] ) , & llargs[ 1 ..] )
274- } else if let Some ( dest) = ret_dest {
275- ( SaveIn ( dest. llval ) , & llargs[ ..] )
276- } else {
277- ( Ignore , & llargs[ ..] )
256+ let ( dest, llargs) = match ret_dest {
257+ _ if fn_ty. ret . is_indirect ( ) => {
258+ ( SaveIn ( llargs[ 0 ] ) , & llargs[ 1 ..] )
259+ }
260+ ReturnDest :: Nothing => ( Ignore , & llargs[ ..] ) ,
261+ ReturnDest :: IndirectOperand ( dst, _) |
262+ ReturnDest :: Store ( dst) => ( SaveIn ( dst) , & llargs[ ..] ) ,
263+ ReturnDest :: DirectOperand ( _) =>
264+ bug ! ( "Cannot use direct operand with an intrinsic call" )
278265 } ;
279266
280267 bcx. with_block ( |bcx| {
281- let res = trans_intrinsic_call ( bcx, callee. ty , & fn_ty,
268+ trans_intrinsic_call ( bcx, callee. ty , & fn_ty,
282269 ArgVals ( llargs) , dest,
283270 DebugLoc :: None ) ;
284- let bcx = res. bcx . build ( ) ;
285- if let Some ( ( _, target) ) = * destination {
286- for op in args {
287- self . set_operand_dropped ( & bcx, op) ;
288- }
289- funclet_br ( bcx, self . llblock ( target) ) ;
290- } else {
291- // trans_intrinsic_call already used Unreachable.
292- // bcx.unreachable();
293- }
294271 } ) ;
272+
273+ if let ReturnDest :: IndirectOperand ( dst, _) = ret_dest {
274+ // Make a fake operand for store_return
275+ let op = OperandRef {
276+ val : OperandValue :: Ref ( dst) ,
277+ ty : sig. output . unwrap ( )
278+ } ;
279+ self . store_return ( & bcx, ret_dest, fn_ty. ret , op) ;
280+ }
281+
282+ if let Some ( ( _, target) ) = * destination {
283+ for op in args {
284+ self . set_operand_dropped ( & bcx, op) ;
285+ }
286+ funclet_br ( bcx, self . llblock ( target) ) ;
287+ } else {
288+ // trans_intrinsic_call already used Unreachable.
289+ // bcx.unreachable();
290+ }
291+
295292 return ;
296293 }
297294 Fn ( f) => f,
@@ -321,9 +318,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
321318 if destination. is_some ( ) {
322319 let ret_bcx = ret_bcx. build ( ) ;
323320 ret_bcx. at_start ( |ret_bcx| {
324- if let Some ( ret_dest) = ret_dest {
325- fn_ty. ret . store ( & ret_bcx, invokeret, ret_dest. llval ) ;
326- }
321+ let op = OperandRef {
322+ val : OperandValue :: Immediate ( invokeret) ,
323+ ty : sig. output . unwrap ( )
324+ } ;
325+ self . store_return ( & ret_bcx, ret_dest, fn_ty. ret , op) ;
327326 for op in args {
328327 self . set_operand_dropped ( & ret_bcx, op) ;
329328 }
@@ -333,9 +332,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
333332 let llret = bcx. call ( fn_ptr, & llargs, cleanup_bundle. as_ref ( ) ) ;
334333 fn_ty. apply_attrs_callsite ( llret) ;
335334 if let Some ( ( _, target) ) = * destination {
336- if let Some ( ret_dest) = ret_dest {
337- fn_ty. ret . store ( & bcx, llret, ret_dest. llval ) ;
338- }
335+ let op = OperandRef {
336+ val : OperandValue :: Immediate ( llret) ,
337+ ty : sig. output . unwrap ( )
338+ } ;
339+ self . store_return ( & bcx, ret_dest, fn_ty. ret , op) ;
339340 for op in args {
340341 self . set_operand_dropped ( & bcx, op) ;
341342 }
@@ -544,4 +545,122 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
544545 pub fn llblock ( & self , bb : mir:: BasicBlock ) -> BasicBlockRef {
545546 self . blocks [ bb. index ( ) ] . llbb
546547 }
548+
549+ fn make_return_dest ( & mut self , bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
550+ dest : & mir:: Lvalue < ' tcx > , fn_ret_ty : & ArgType ,
551+ llargs : & mut Vec < ValueRef > , is_intrinsic : bool ) -> ReturnDest {
552+ // If the return is ignored, we can just return a do-nothing ReturnDest
553+ if fn_ret_ty. is_ignore ( ) {
554+ return ReturnDest :: Nothing ;
555+ }
556+ let dest = match * dest {
557+ mir:: Lvalue :: Temp ( idx) => {
558+ let lvalue_ty = self . mir . lvalue_ty ( bcx. tcx ( ) , dest) ;
559+ let lvalue_ty = bcx. monomorphize ( & lvalue_ty) ;
560+ let ret_ty = lvalue_ty. to_ty ( bcx. tcx ( ) ) ;
561+ match self . temps [ idx as usize ] {
562+ TempRef :: Lvalue ( dest) => dest,
563+ TempRef :: Operand ( None ) => {
564+ // Handle temporary lvalues, specifically Operand ones, as
565+ // they don't have allocas
566+ return if fn_ret_ty. is_indirect ( ) {
567+ // Odd, but possible, case, we have an operand temporary,
568+ // but the calling convention has an indirect return.
569+ let tmp = bcx. with_block ( |bcx| {
570+ base:: alloc_ty ( bcx, ret_ty, "tmp_ret" )
571+ } ) ;
572+ llargs. push ( tmp) ;
573+ ReturnDest :: IndirectOperand ( tmp, idx)
574+ } else if is_intrinsic {
575+ // Currently, intrinsics always need a location to store
576+ // the result. so we create a temporary alloca for the
577+ // result
578+ let tmp = bcx. with_block ( |bcx| {
579+ base:: alloc_ty ( bcx, ret_ty, "tmp_ret" )
580+ } ) ;
581+ ReturnDest :: IndirectOperand ( tmp, idx)
582+ } else {
583+ ReturnDest :: DirectOperand ( idx)
584+ } ;
585+ }
586+ TempRef :: Operand ( Some ( _) ) => {
587+ bug ! ( "lvalue temp already assigned to" ) ;
588+ }
589+ }
590+ }
591+ _ => self . trans_lvalue ( bcx, dest)
592+ } ;
593+ if fn_ret_ty. is_indirect ( ) {
594+ llargs. push ( dest. llval ) ;
595+ ReturnDest :: Nothing
596+ } else {
597+ ReturnDest :: Store ( dest. llval )
598+ }
599+ }
600+
601+ fn trans_transmute ( & mut self , bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
602+ src : & mir:: Operand < ' tcx > , dst : LvalueRef < ' tcx > ) {
603+ let mut val = self . trans_operand ( bcx, src) ;
604+ if let ty:: TyFnDef ( def_id, substs, _) = val. ty . sty {
605+ let llouttype = type_of:: type_of ( bcx. ccx ( ) , dst. ty . to_ty ( bcx. tcx ( ) ) ) ;
606+ let out_type_size = llbitsize_of_real ( bcx. ccx ( ) , llouttype) ;
607+ if out_type_size != 0 {
608+ // FIXME #19925 Remove this hack after a release cycle.
609+ let f = Callee :: def ( bcx. ccx ( ) , def_id, substs) ;
610+ let datum = f. reify ( bcx. ccx ( ) ) ;
611+ val = OperandRef {
612+ val : OperandValue :: Immediate ( datum. val ) ,
613+ ty : datum. ty
614+ } ;
615+ }
616+ }
617+
618+ let llty = type_of:: type_of ( bcx. ccx ( ) , val. ty ) ;
619+ let cast_ptr = bcx. pointercast ( dst. llval , llty. ptr_to ( ) ) ;
620+ self . store_operand ( bcx, cast_ptr, val) ;
621+ }
622+
623+ // Stores the return value of a function call into it's final location.
624+ fn store_return ( & mut self ,
625+ bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
626+ dest : ReturnDest ,
627+ ret_ty : ArgType ,
628+ op : OperandRef < ' tcx > ) {
629+ use self :: ReturnDest :: * ;
630+
631+ match dest {
632+ Nothing => ( ) ,
633+ Store ( dst) => ret_ty. store ( bcx, op. immediate ( ) , dst) ,
634+ IndirectOperand ( tmp, idx) => {
635+ let op = self . trans_load ( bcx, tmp, op. ty ) ;
636+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
637+ }
638+ DirectOperand ( idx) => {
639+ let op = if type_is_fat_ptr ( bcx. tcx ( ) , op. ty ) {
640+ let llval = op. immediate ( ) ;
641+ let ptr = bcx. extract_value ( llval, 0 ) ;
642+ let meta = bcx. extract_value ( llval, 1 ) ;
643+
644+ OperandRef {
645+ val : OperandValue :: FatPtr ( ptr, meta) ,
646+ ty : op. ty
647+ }
648+ } else {
649+ op
650+ } ;
651+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
652+ }
653+ }
654+ }
655+ }
656+
657+ enum ReturnDest {
658+ // Do nothing, the return value is indirect or ignored
659+ Nothing ,
660+ // Store the return value to the pointer
661+ Store ( ValueRef ) ,
662+ // Stores an indirect return value to an operand temporary lvalue
663+ IndirectOperand ( ValueRef , u32 ) ,
664+ // Stores a direct return value to an operand temporary lvalue
665+ DirectOperand ( u32 )
547666}
0 commit comments