Skip to content

Commit f5b5425

Browse files
committed
Rollup merge of rust-lang#32738 - Aatch:mir-operand-fn-ret, r=arielb1
Handle operand temps for function calls Previously, all non-void function returns required an on-stack location for the value to be stored to. This code improves translation of function calls so this is no longer necessary.
2 parents c719117 + 73790f0 commit f5b5425

File tree

5 files changed

+188
-46
lines changed

5 files changed

+188
-46
lines changed

src/librustc/middle/region.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ impl fmt::Debug for CodeExtent {
4444

4545
ty::tls::with_opt(|opt_tcx| {
4646
if let Some(tcx) = opt_tcx {
47-
let data = tcx.region_maps.code_extents.borrow()[self.0 as usize];
48-
write!(f, "/{:?}", data)?;
47+
if let Some(data) = tcx.region_maps.code_extents.borrow().get(self.0 as usize) {
48+
write!(f, "/{:?}", data)?;
49+
}
4950
}
5051
Ok(())
5152
})?;

src/librustc/mir/visit.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ macro_rules! make_mir_visitor {
407407
self.visit_operand(arg);
408408
}
409409
if let Some((ref $($mutability)* destination, target)) = *destination {
410-
self.visit_lvalue(destination, LvalueContext::Store);
410+
self.visit_lvalue(destination, LvalueContext::Call);
411411
self.visit_branch(block, target);
412412
}
413413
cleanup.map(|t| self.visit_branch(block, t));
@@ -692,9 +692,12 @@ make_mir_visitor!(MutVisitor,mut);
692692

693693
#[derive(Copy, Clone, Debug)]
694694
pub enum LvalueContext {
695-
// Appears as LHS of an assignment or as dest of a call
695+
// Appears as LHS of an assignment
696696
Store,
697697

698+
// Dest of a call
699+
Call,
700+
698701
// Being dropped
699702
Drop,
700703

src/librustc_trans/mir/analyze.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl<'tcx> Visitor<'tcx> for TempAnalyzer {
105105
match *lvalue {
106106
mir::Lvalue::Temp(index) => {
107107
match context {
108+
LvalueContext::Call |
108109
LvalueContext::Consume => {
109110
}
110111
LvalueContext::Store |

src/librustc_trans/mir/block.rs

Lines changed: 146 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use llvm::{self, BasicBlockRef, ValueRef, OperandBundleDef};
1212
use rustc::ty;
1313
use rustc::mir::repr as mir;
14-
use abi::{Abi, FnType};
14+
use abi::{Abi, FnType, ArgType};
1515
use adt;
1616
use base;
1717
use build;
@@ -25,7 +25,7 @@ use type_of;
2525
use glue;
2626
use type_::Type;
2727

28-
use super::{MirContext, drop};
28+
use super::{MirContext, TempRef, drop};
2929
use super::lvalue::{LvalueRef, load_fat_ptr};
3030
use super::operand::OperandRef;
3131
use 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;
@@ -226,18 +211,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
226211
let mut llargs = Vec::with_capacity(arg_count);
227212

228213
// 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
236217
} else {
237-
Some(dest)
238-
}
218+
false
219+
};
220+
self.make_return_dest(&bcx, dest, &fn_ty.ret, &mut llargs, is_intrinsic)
239221
} else {
240-
None
222+
ReturnDest::Nothing
241223
};
242224

243225
// Split the rust-call tupled arguments off.
@@ -269,12 +251,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
269251
use expr::{Ignore, SaveIn};
270252
use intrinsic::trans_intrinsic_call;
271253

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")
278263
};
279264

280265
bcx.with_block(|bcx| {
@@ -292,6 +277,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
292277
// bcx.unreachable();
293278
}
294279
});
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+
295290
return;
296291
}
297292
Fn(f) => f,
@@ -321,9 +316,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
321316
if destination.is_some() {
322317
let ret_bcx = ret_bcx.build();
323318
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);
327324
for op in args {
328325
self.set_operand_dropped(&ret_bcx, op);
329326
}
@@ -333,9 +330,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
333330
let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle.as_ref());
334331
fn_ty.apply_attrs_callsite(llret);
335332
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);
339338
for op in args {
340339
self.set_operand_dropped(&bcx, op);
341340
}
@@ -544,4 +543,109 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
544543
pub fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef {
545544
self.blocks[bb.index()].llbb
546545
}
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)
547651
}

src/librustc_trans/mir/lvalue.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,39 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
207207
}
208208
}
209209

210+
// Perform an action using the given Lvalue.
211+
// If the Lvalue is an empty TempRef::Operand, then a temporary stack slot
212+
// is created first, then used as an operand to update the Lvalue.
213+
pub fn with_lvalue_ref<F, U>(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>,
214+
lvalue: &mir::Lvalue<'tcx>, f: F) -> U
215+
where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
216+
{
217+
match *lvalue {
218+
mir::Lvalue::Temp(idx) => {
219+
match self.temps[idx as usize] {
220+
TempRef::Lvalue(lvalue) => f(self, lvalue),
221+
TempRef::Operand(None) => {
222+
let lvalue_ty = self.mir.lvalue_ty(bcx.tcx(), lvalue);
223+
let lvalue = LvalueRef::alloca(bcx,
224+
lvalue_ty.to_ty(bcx.tcx()),
225+
"lvalue_temp");
226+
let ret = f(self, lvalue);
227+
let op = self.trans_load(bcx, lvalue.llval, lvalue_ty.to_ty(bcx.tcx()));
228+
self.temps[idx as usize] = TempRef::Operand(Some(op));
229+
ret
230+
}
231+
TempRef::Operand(Some(_)) => {
232+
bug!("Lvalue temp already set");
233+
}
234+
}
235+
}
236+
_ => {
237+
let lvalue = self.trans_lvalue(bcx, lvalue);
238+
f(self, lvalue)
239+
}
240+
}
241+
}
242+
210243
/// Adjust the bitwidth of an index since LLVM is less forgiving
211244
/// than we are.
212245
///

0 commit comments

Comments
 (0)