11
11
use llvm:: { self , BasicBlockRef , ValueRef , OperandBundleDef } ;
12
12
use rustc:: ty;
13
13
use rustc:: mir:: repr as mir;
14
- use abi:: { Abi , FnType } ;
14
+ use abi:: { Abi , FnType , ArgType } ;
15
15
use adt;
16
16
use base;
17
17
use build;
@@ -25,7 +25,7 @@ use type_of;
25
25
use glue;
26
26
use type_:: Type ;
27
27
28
- use super :: { MirContext , drop} ;
28
+ use super :: { MirContext , TempRef , drop} ;
29
29
use super :: lvalue:: { LvalueRef , load_fat_ptr} ;
30
30
use super :: operand:: OperandRef ;
31
31
use super :: operand:: OperandValue :: { self , FatPtr , Immediate , Ref } ;
@@ -191,25 +191,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
191
191
192
192
if intrinsic == Some ( "transmute" ) {
193
193
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
+ } ) ;
209
197
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) ;
213
198
self . set_operand_dropped ( & bcx, & args[ 0 ] ) ;
214
199
funclet_br ( bcx, self . llblock ( target) ) ;
215
200
return ;
@@ -226,18 +211,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
226
211
let mut llargs = Vec :: with_capacity ( arg_count) ;
227
212
228
213
// 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
214
+ let ret_dest = if let Some ( ( ref dest, _) ) = * destination {
215
+ let is_intrinsic = if let Intrinsic = callee. data {
216
+ true
236
217
} else {
237
- Some ( dest)
238
- }
218
+ false
219
+ } ;
220
+ self . make_return_dest ( & bcx, dest, & fn_ty. ret , & mut llargs, is_intrinsic)
239
221
} else {
240
- None
222
+ ReturnDest :: Nothing
241
223
} ;
242
224
243
225
// Split the rust-call tupled arguments off.
@@ -269,12 +251,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
269
251
use expr:: { Ignore , SaveIn } ;
270
252
use intrinsic:: trans_intrinsic_call;
271
253
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[ ..] )
254
+ let ( dest, llargs) = match ret_dest {
255
+ _ if fn_ty. ret . is_indirect ( ) => {
256
+ ( SaveIn ( llargs[ 0 ] ) , & llargs[ 1 ..] )
257
+ }
258
+ ReturnDest :: Nothing => ( Ignore , & llargs[ ..] ) ,
259
+ ReturnDest :: IndirectOperand ( dst, _) |
260
+ ReturnDest :: Store ( dst) => ( SaveIn ( dst) , & llargs[ ..] ) ,
261
+ ReturnDest :: DirectOperand ( _) =>
262
+ bug ! ( "Cannot use direct operand with an intrinsic call" )
278
263
} ;
279
264
280
265
bcx. with_block ( |bcx| {
@@ -292,6 +277,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
292
277
// bcx.unreachable();
293
278
}
294
279
} ) ;
280
+
281
+ if let ReturnDest :: IndirectOperand ( dst, _) = ret_dest {
282
+ // Make a fake operand for store_return
283
+ let op = OperandRef {
284
+ val : OperandValue :: Ref ( dst) ,
285
+ ty : sig. 0 . output . unwrap ( )
286
+ } ;
287
+ self . store_return ( & bcx, ret_dest, fn_ty. ret , op) ;
288
+ }
289
+
295
290
return ;
296
291
}
297
292
Fn ( f) => f,
@@ -321,9 +316,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
321
316
if destination. is_some ( ) {
322
317
let ret_bcx = ret_bcx. build ( ) ;
323
318
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
- }
319
+ let op = OperandRef {
320
+ val : OperandValue :: Immediate ( invokeret) ,
321
+ ty : sig. 0 . output . unwrap ( )
322
+ } ;
323
+ self . store_return ( & ret_bcx, ret_dest, fn_ty. ret , op) ;
327
324
for op in args {
328
325
self . set_operand_dropped ( & ret_bcx, op) ;
329
326
}
@@ -333,9 +330,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
333
330
let llret = bcx. call ( fn_ptr, & llargs, cleanup_bundle. as_ref ( ) ) ;
334
331
fn_ty. apply_attrs_callsite ( llret) ;
335
332
if let Some ( ( _, target) ) = * destination {
336
- if let Some ( ret_dest) = ret_dest {
337
- fn_ty. ret . store ( & bcx, llret, ret_dest. llval ) ;
338
- }
333
+ let op = OperandRef {
334
+ val : OperandValue :: Immediate ( llret) ,
335
+ ty : sig. 0 . output . unwrap ( )
336
+ } ;
337
+ self . store_return ( & bcx, ret_dest, fn_ty. ret , op) ;
339
338
for op in args {
340
339
self . set_operand_dropped ( & bcx, op) ;
341
340
}
@@ -544,4 +543,109 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
544
543
pub fn llblock ( & self , bb : mir:: BasicBlock ) -> BasicBlockRef {
545
544
self . blocks [ bb. index ( ) ] . llbb
546
545
}
546
+
547
+ fn make_return_dest ( & mut self , bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
548
+ dest : & mir:: Lvalue < ' tcx > , fn_ret_ty : & ArgType ,
549
+ llargs : & mut Vec < ValueRef > , is_intrinsic : bool ) -> ReturnDest {
550
+ // If the return is ignored, we can just return a do-nothing ReturnDest
551
+ if fn_ret_ty. is_ignore ( ) {
552
+ return ReturnDest :: Nothing ;
553
+ }
554
+ let dest = match * dest {
555
+ mir:: Lvalue :: Temp ( idx) => {
556
+ let lvalue_ty = self . mir . lvalue_ty ( bcx. tcx ( ) , dest) ;
557
+ let ret_ty = lvalue_ty. to_ty ( bcx. tcx ( ) ) ;
558
+ match self . temps [ idx as usize ] {
559
+ TempRef :: Lvalue ( dest) => dest,
560
+ TempRef :: Operand ( None ) => {
561
+ // Handle temporary lvalues, specifically Operand ones, as
562
+ // they don't have allocas
563
+ return if fn_ret_ty. is_indirect ( ) {
564
+ // Odd, but possible, case, we have an operand temporary,
565
+ // but the calling convention has an indirect return.
566
+ let tmp = bcx. with_block ( |bcx| {
567
+ base:: alloc_ty ( bcx, ret_ty, "tmp_ret" )
568
+ } ) ;
569
+ llargs. push ( tmp) ;
570
+ ReturnDest :: IndirectOperand ( tmp, idx)
571
+ } else if is_intrinsic {
572
+ // Currently, intrinsics always need a location to store
573
+ // the result. so we create a temporary alloca for the
574
+ // result
575
+ let tmp = bcx. with_block ( |bcx| {
576
+ base:: alloc_ty ( bcx, ret_ty, "tmp_ret" )
577
+ } ) ;
578
+ ReturnDest :: IndirectOperand ( tmp, idx)
579
+ } else {
580
+ ReturnDest :: DirectOperand ( idx)
581
+ } ;
582
+ }
583
+ TempRef :: Operand ( Some ( _) ) => {
584
+ bug ! ( "lvalue temp already assigned to" ) ;
585
+ }
586
+ }
587
+ }
588
+ _ => self . trans_lvalue ( bcx, dest)
589
+ } ;
590
+ if fn_ret_ty. is_indirect ( ) {
591
+ llargs. push ( dest. llval ) ;
592
+ ReturnDest :: Nothing
593
+ } else {
594
+ ReturnDest :: Store ( dest. llval )
595
+ }
596
+ }
597
+
598
+ fn trans_transmute ( & mut self , bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
599
+ src : & mir:: Operand < ' tcx > , dst : LvalueRef < ' tcx > ) {
600
+ let mut val = self . trans_operand ( bcx, src) ;
601
+ if let ty:: TyFnDef ( def_id, substs, _) = val. ty . sty {
602
+ let llouttype = type_of:: type_of ( bcx. ccx ( ) , dst. ty . to_ty ( bcx. tcx ( ) ) ) ;
603
+ let out_type_size = llbitsize_of_real ( bcx. ccx ( ) , llouttype) ;
604
+ if out_type_size != 0 {
605
+ // FIXME #19925 Remove this hack after a release cycle.
606
+ let f = Callee :: def ( bcx. ccx ( ) , def_id, substs) ;
607
+ let datum = f. reify ( bcx. ccx ( ) ) ;
608
+ val = OperandRef {
609
+ val : OperandValue :: Immediate ( datum. val ) ,
610
+ ty : datum. ty
611
+ } ;
612
+ }
613
+ }
614
+
615
+ let llty = type_of:: type_of ( bcx. ccx ( ) , val. ty ) ;
616
+ let cast_ptr = bcx. pointercast ( dst. llval , llty. ptr_to ( ) ) ;
617
+ self . store_operand ( bcx, cast_ptr, val) ;
618
+ }
619
+
620
+ // Stores the return value of a function call into it's final location.
621
+ fn store_return ( & mut self ,
622
+ bcx : & BlockAndBuilder < ' bcx , ' tcx > ,
623
+ dest : ReturnDest ,
624
+ ret_ty : ArgType ,
625
+ op : OperandRef < ' tcx > ) {
626
+ use self :: ReturnDest :: * ;
627
+
628
+ match dest {
629
+ Nothing => ( ) ,
630
+ Store ( dst) => ret_ty. store ( bcx, op. immediate ( ) , dst) ,
631
+ IndirectOperand ( tmp, idx) => {
632
+ let op = self . trans_load ( bcx, tmp, op. ty ) ;
633
+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
634
+ }
635
+ DirectOperand ( idx) => {
636
+ self . temps [ idx as usize ] = TempRef :: Operand ( Some ( op) ) ;
637
+ }
638
+ }
639
+ }
640
+ }
641
+
642
+ enum ReturnDest {
643
+ // Do nothing, the return value is indirect or ignored
644
+ Nothing ,
645
+ // Store the return value to the pointer
646
+ Store ( ValueRef ) ,
647
+ // Stores an indirect return value to an operand temporary lvalue
648
+ IndirectOperand ( ValueRef , u32 ) ,
649
+ // Stores a direct return value to an operand temporary lvalue
650
+ DirectOperand ( u32 )
547
651
}
0 commit comments