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 ;
@@ -227,17 +212,71 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
227
212
228
213
// Prepare the return value destination
229
214
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
+ }
238
277
}
239
278
} else {
240
- None
279
+ ReturnDest :: Nothing
241
280
} ;
242
281
243
282
// Split the rust-call tupled arguments off.
@@ -269,12 +308,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
269
308
use expr:: { Ignore , SaveIn } ;
270
309
use intrinsic:: trans_intrinsic_call;
271
310
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" )
278
320
} ;
279
321
280
322
bcx. with_block ( |bcx| {
@@ -292,6 +334,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
292
334
// bcx.unreachable();
293
335
}
294
336
} ) ;
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
+
295
347
return ;
296
348
}
297
349
Fn ( f) => f,
@@ -321,9 +373,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
321
373
if destination. is_some ( ) {
322
374
let ret_bcx = ret_bcx. build ( ) ;
323
375
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) ;
327
381
for op in args {
328
382
self . set_operand_dropped ( & ret_bcx, op) ;
329
383
}
@@ -333,9 +387,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
333
387
let llret = bcx. call ( fn_ptr, & llargs, cleanup_bundle. as_ref ( ) ) ;
334
388
fn_ty. apply_attrs_callsite ( llret) ;
335
389
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) ;
339
395
for op in args {
340
396
self . set_operand_dropped ( & bcx, op) ;
341
397
}
@@ -544,4 +600,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
544
600
pub fn llblock ( & self , bb : mir:: BasicBlock ) -> BasicBlockRef {
545
601
self . blocks [ bb. index ( ) ] . llbb
546
602
}
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 )
547
657
}
0 commit comments