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;
@@ -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 } ;
@@ -191,25 +191,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
191191
192192 if intrinsic == Some ( "transmute" ) {
193193 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- }
194+ self . with_lvalue_ref ( & bcx, dest, |this, dest| {
195+ this. trans_transmute ( & bcx, & args[ 0 ] , dest) ;
196+ } ) ;
209197
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) ;
213198 self . set_operand_dropped ( & bcx, & args[ 0 ] ) ;
214199 funclet_br ( bcx, self . llblock ( target) ) ;
215200 return ;
@@ -227,17 +212,71 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
227212
228213 // Prepare the return value destination
229214 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
236- } else {
237- Some ( dest)
215+ match * d {
216+ // Handle temporary lvalues, specifically Operand ones, as
217+ // they don't have allocas
218+ mir:: Lvalue :: Temp ( idx) => {
219+ let lvalue_ty = self . mir . lvalue_ty ( bcx. tcx ( ) , d) ;
220+ let ret_ty = lvalue_ty. to_ty ( bcx. tcx ( ) ) ;
221+ match self . temps [ idx as usize ] {
222+ TempRef :: Lvalue ( dest) => {
223+ if fn_ty. ret . is_indirect ( ) {
224+ llargs. push ( dest. llval ) ;
225+ ReturnDest :: Nothing
226+ } else if fn_ty. ret . is_ignore ( ) {
227+ ReturnDest :: Nothing
228+ } else {
229+ ReturnDest :: Store ( dest. llval )
230+ }
231+ }
232+ TempRef :: Operand ( None ) => {
233+ let is_intrinsic = if let Intrinsic = callee. data {
234+ true
235+ } else {
236+ false
237+ } ;
238+
239+ if fn_ty. ret . is_indirect ( ) {
240+ // Odd, but possible, case, we have an operand temporary,
241+ // but the calling convention has an indirect return.
242+ let tmp = bcx. with_block ( |bcx| {
243+ base:: alloc_ty ( bcx, ret_ty, "tmp_ret" )
244+ } ) ;
245+ llargs. push ( tmp) ;
246+ ReturnDest :: IndirectOperand ( tmp, idx)
247+ } else if is_intrinsic {
248+ // Currently, intrinsics always need a location to store
249+ // the result. so we create a temporary alloca for the
250+ // result
251+ let tmp = bcx. with_block ( |bcx| {
252+ base:: alloc_ty ( bcx, ret_ty, "tmp_ret" )
253+ } ) ;
254+ ReturnDest :: IndirectOperand ( tmp, idx)
255+ } else if fn_ty. ret . is_ignore ( ) {
256+ ReturnDest :: Nothing
257+ } else {
258+ ReturnDest :: DirectOperand ( idx)
259+ }
260+ }
261+ TempRef :: Operand ( Some ( _) ) => {
262+ bug ! ( "lvalue temp already assigned to" ) ;
263+ }
264+ }
265+ }
266+ _ => {
267+ let dest = self . trans_lvalue ( & bcx, d) ;
268+ if fn_ty. ret . is_indirect ( ) {
269+ llargs. push ( dest. llval ) ;
270+ ReturnDest :: Nothing
271+ } else if fn_ty. ret . is_ignore ( ) {
272+ ReturnDest :: Nothing
273+ } else {
274+ ReturnDest :: Store ( dest. llval )
275+ }
276+ }
238277 }
239278 } else {
240- None
279+ ReturnDest :: Nothing
241280 } ;
242281
243282 // Split the rust-call tupled arguments off.
@@ -269,12 +308,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
269308 use expr:: { Ignore , SaveIn } ;
270309 use intrinsic:: trans_intrinsic_call;
271310
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[ ..] )
311+ let ( dest, llargs) = match ret_dest {
312+ _ if fn_ty. ret . is_indirect ( ) => {
313+ ( SaveIn ( llargs[ 0 ] ) , & llargs[ 1 ..] )
314+ }
315+ ReturnDest :: Nothing => ( Ignore , & llargs[ ..] ) ,
316+ ReturnDest :: IndirectOperand ( dst, _) |
317+ ReturnDest :: Store ( dst) => ( SaveIn ( dst) , & llargs[ ..] ) ,
318+ ReturnDest :: DirectOperand ( _) =>
319+ bug ! ( "Cannot use direct operand with an intrinsic call" )
278320 } ;
279321
280322 bcx. with_block ( |bcx| {
@@ -292,6 +334,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
292334 // bcx.unreachable();
293335 }
294336 } ) ;
337+
338+ if let ReturnDest :: IndirectOperand ( dst, _) = ret_dest {
339+ // Make a fake operand for store_return
340+ let op = OperandRef {
341+ val : OperandValue :: Ref ( dst) ,
342+ ty : sig. 0 . output . unwrap ( )
343+ } ;
344+ self . store_return ( & bcx, ret_dest, fn_ty. ret , op) ;
345+ }
346+
295347 return ;
296348 }
297349 Fn ( f) => f,
@@ -321,9 +373,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
321373 if destination. is_some ( ) {
322374 let ret_bcx = ret_bcx. build ( ) ;
323375 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- }
376+ let op = OperandRef {
377+ val : OperandValue :: Immediate ( invokeret) ,
378+ ty : sig. 0 . output . unwrap ( )
379+ } ;
380+ self . store_return ( & ret_bcx, ret_dest, fn_ty. ret , op) ;
327381 for op in args {
328382 self . set_operand_dropped ( & ret_bcx, op) ;
329383 }
@@ -333,9 +387,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
333387 let llret = bcx. call ( fn_ptr, & llargs, cleanup_bundle. as_ref ( ) ) ;
334388 fn_ty. apply_attrs_callsite ( llret) ;
335389 if let Some ( ( _, target) ) = * destination {
336- if let Some ( ret_dest) = ret_dest {
337- fn_ty. ret . store ( & bcx, llret, ret_dest. llval ) ;
338- }
390+ let op = OperandRef {
391+ val : OperandValue :: Immediate ( llret) ,
392+ ty : sig. 0 . output . unwrap ( )
393+ } ;
394+ self . store_return ( & bcx, ret_dest, fn_ty. ret , op) ;
339395 for op in args {
340396 self . set_operand_dropped ( & bcx, op) ;
341397 }
@@ -544,4 +600,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
544600 pub fn llblock ( & self , bb : mir:: BasicBlock ) -> BasicBlockRef {
545601 self . blocks [ bb. index ( ) ] . llbb
546602 }
603+
604+ fn trans_transmute ( & mut self , bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
605+ src : & mir:: Operand < ' tcx > , dst : LvalueRef < ' tcx > ) {
606+ let mut val = self . trans_operand ( bcx, src) ;
607+ if let ty:: TyFnDef ( def_id, substs, _) = val. ty . sty {
608+ let llouttype = type_of:: type_of ( bcx. ccx ( ) , dst. ty . to_ty ( bcx. tcx ( ) ) ) ;
609+ let out_type_size = llbitsize_of_real ( bcx. ccx ( ) , llouttype) ;
610+ if out_type_size != 0 {
611+ // FIXME #19925 Remove this hack after a release cycle.
612+ let f = Callee :: def ( bcx. ccx ( ) , def_id, substs) ;
613+ let datum = f. reify ( bcx. ccx ( ) ) ;
614+ val = OperandRef {
615+ val : OperandValue :: Immediate ( datum. val ) ,
616+ ty : datum. ty
617+ } ;
618+ }
619+ }
620+
621+ let llty = type_of:: type_of ( bcx. ccx ( ) , val. ty ) ;
622+ let cast_ptr = bcx. pointercast ( dst. llval , llty. ptr_to ( ) ) ;
623+ self . store_operand ( bcx, cast_ptr, val) ;
624+ }
625+
626+ // Stores the return value of a function call into it's final location.
627+ fn store_return ( & mut self ,
628+ bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
629+ dest : ReturnDest ,
630+ ret_ty : ArgType ,
631+ op : OperandRef < ' tcx > ) {
632+ use self :: ReturnDest :: * ;
633+
634+ match dest {
635+ Nothing => ( ) ,
636+ Store ( dst) => ret_ty. store ( bcx, op. immediate ( ) , dst) ,
637+ IndirectOperand ( tmp, idx) => {
638+ let op = self . trans_load ( bcx, tmp, op. ty ) ;
639+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
640+ }
641+ DirectOperand ( idx) => {
642+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
643+ }
644+ }
645+ }
646+ }
647+
648+ enum ReturnDest {
649+ // Do nothing, the return value is indirect or ignored
650+ Nothing ,
651+ // Store the return value to the pointer
652+ Store ( ValueRef ) ,
653+ // Stores an indirect return value to an operand temporary lvalue
654+ IndirectOperand ( ValueRef , u32 ) ,
655+ // Stores a direct return value to an operand temporary lvalue
656+ DirectOperand ( u32 )
547657}
0 commit comments