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;
18
18
use 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 } ;
20
20
use debuginfo:: DebugLoc ;
21
21
use Disr ;
22
22
use machine:: { llalign_of_min, llbitsize_of_real} ;
@@ -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 } ;
@@ -169,6 +169,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
169
169
_ => bug ! ( "{} is not callable" , callee. ty)
170
170
} ;
171
171
172
+ let sig = bcx. tcx ( ) . erase_late_bound_regions ( sig) ;
173
+
172
174
// Handle intrinsics old trans wants Expr's for, ourselves.
173
175
let intrinsic = match ( & callee. ty . sty , & callee. data ) {
174
176
( & ty:: TyFnDef ( def_id, _, _) , & Intrinsic ) => {
@@ -191,31 +193,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
191
193
192
194
if intrinsic == Some ( "transmute" ) {
193
195
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
+ } ) ;
209
199
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
200
self . set_operand_dropped ( & bcx, & args[ 0 ] ) ;
214
201
funclet_br ( bcx, self . llblock ( target) ) ;
215
202
return ;
216
203
}
217
204
218
- let extra_args = & args[ sig. 0 . inputs . len ( ) ..] ;
205
+ let extra_args = & args[ sig. inputs . len ( ) ..] ;
219
206
let extra_args = extra_args. iter ( ) . map ( |op_arg| {
220
207
self . mir . operand_ty ( bcx. tcx ( ) , op_arg)
221
208
} ) . collect :: < Vec < _ > > ( ) ;
@@ -226,18 +213,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
226
213
let mut llargs = Vec :: with_capacity ( arg_count) ;
227
214
228
215
// 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
236
219
} else {
237
- Some ( dest)
238
- }
220
+ false
221
+ } ;
222
+ self . make_return_dest ( & bcx, dest, & fn_ty. ret , & mut llargs, is_intrinsic)
239
223
} else {
240
- None
224
+ ReturnDest :: Nothing
241
225
} ;
242
226
243
227
// Split the rust-call tupled arguments off.
@@ -269,29 +253,42 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
269
253
use expr:: { Ignore , SaveIn } ;
270
254
use intrinsic:: trans_intrinsic_call;
271
255
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" )
278
265
} ;
279
266
280
267
bcx. with_block ( |bcx| {
281
- let res = trans_intrinsic_call ( bcx, callee. ty , & fn_ty,
268
+ trans_intrinsic_call ( bcx, callee. ty , & fn_ty,
282
269
ArgVals ( llargs) , dest,
283
270
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
- }
294
271
} ) ;
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
+
295
292
return ;
296
293
}
297
294
Fn ( f) => f,
@@ -321,9 +318,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
321
318
if destination. is_some ( ) {
322
319
let ret_bcx = ret_bcx. build ( ) ;
323
320
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) ;
327
326
for op in args {
328
327
self . set_operand_dropped ( & ret_bcx, op) ;
329
328
}
@@ -333,9 +332,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
333
332
let llret = bcx. call ( fn_ptr, & llargs, cleanup_bundle. as_ref ( ) ) ;
334
333
fn_ty. apply_attrs_callsite ( llret) ;
335
334
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) ;
339
340
for op in args {
340
341
self . set_operand_dropped ( & bcx, op) ;
341
342
}
@@ -544,4 +545,122 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
544
545
pub fn llblock ( & self , bb : mir:: BasicBlock ) -> BasicBlockRef {
545
546
self . blocks [ bb. index ( ) ] . llbb
546
547
}
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 )
547
666
}
0 commit comments