Skip to content

Commit 68cbd6c

Browse files
committed
librustc: Use separate stack slot for each return.
1 parent 9dcf895 commit 68cbd6c

File tree

6 files changed

+81
-41
lines changed

6 files changed

+81
-41
lines changed

src/librustc/middle/trans/base.rs

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,16 +1210,23 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
12101210
p
12111211
}
12121212

1213-
// Creates and returns space for, or returns the argument representing, the
1214-
// slot where the return value of the function must go.
1215-
pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
1216-
-> ValueRef {
1213+
// Creates the alloca slot which holds the pointer to the slot for the final return value
1214+
pub fn make_return_slot_pointer(fcx: &FunctionContext, output_type: ty::t) -> ValueRef {
1215+
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
1216+
1217+
// Let's create the stack slot
1218+
let slot = AllocaFcx(fcx, lloutputtype.ptr_to(), "llretslotptr");
1219+
1220+
// and if we're using an out pointer, then store that in our newly made slot
12171221
if type_of::return_uses_outptr(fcx.ccx, output_type) {
1218-
get_param(fcx.llfn, 0)
1219-
} else {
1220-
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
1221-
AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
1222+
let outptr = get_param(fcx.llfn, 0);
1223+
1224+
let b = fcx.ccx.builder();
1225+
b.position_before(fcx.alloca_insert_pt.get().unwrap());
1226+
b.store(outptr, slot);
12221227
}
1228+
1229+
slot
12231230
}
12241231

12251232
// NB: must keep 4 fns in sync:
@@ -1258,7 +1265,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
12581265
let mut fcx = FunctionContext {
12591266
llfn: llfndecl,
12601267
llenv: None,
1261-
llretptr: Cell::new(None),
1268+
llretslotptr: Cell::new(None),
12621269
alloca_insert_pt: Cell::new(None),
12631270
llreturn: Cell::new(None),
12641271
personality: Cell::new(None),
@@ -1303,12 +1310,12 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
13031310

13041311
if !return_type_is_void(fcx.ccx, substd_output_type) {
13051312
// If the function returns nil/bot, there is no real return
1306-
// value, so do not set `llretptr`.
1313+
// value, so do not set `llretslotptr`.
13071314
if !skip_retptr || fcx.caller_expects_out_pointer {
1308-
// Otherwise, we normally allocate the llretptr, unless we
1315+
// Otherwise, we normally allocate the llretslotptr, unless we
13091316
// have been instructed to skip it for immediate return
13101317
// values.
1311-
fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
1318+
fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
13121319
}
13131320
}
13141321

@@ -1533,12 +1540,12 @@ pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
15331540

15341541
// Builds the return block for a function.
15351542
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
1536-
// Return the value if this function immediate; otherwise, return void.
1537-
if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
1543+
if fcx.llretslotptr.get().is_none() {
15381544
return RetVoid(ret_cx);
15391545
}
15401546

1541-
let retptr = Value(fcx.llretptr.get().unwrap());
1547+
let retslot = Load(ret_cx, fcx.llretslotptr.get().unwrap());
1548+
let retptr = Value(retslot);
15421549
let retval = match retptr.get_dominating_store(ret_cx) {
15431550
// If there's only a single store to the ret slot, we can directly return
15441551
// the value that was stored and omit the store and the alloca
@@ -1557,10 +1564,15 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
15571564
}
15581565
}
15591566
// Otherwise, load the return value from the ret slot
1560-
None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
1567+
None => load_ty(ret_cx, retslot, retty)
15611568
};
15621569

1563-
Ret(ret_cx, retval);
1570+
if fcx.caller_expects_out_pointer {
1571+
store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
1572+
RetVoid(ret_cx);
1573+
} else {
1574+
Ret(ret_cx, retval);
1575+
}
15641576
}
15651577

15661578
#[deriving(Clone, Eq, PartialEq)]
@@ -1658,10 +1670,10 @@ pub fn trans_closure(ccx: &CrateContext,
16581670
// emitting should be enabled.
16591671
debuginfo::start_emitting_source_locations(&fcx);
16601672

1661-
let dest = match fcx.llretptr.get() {
1662-
Some(e) => {expr::SaveIn(e)}
1673+
let dest = match fcx.llretslotptr.get() {
1674+
Some(_) => expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), block_ty), "iret_slot")),
16631675
None => {
1664-
assert!(type_is_zero_size(bcx.ccx(), block_ty))
1676+
assert!(type_is_zero_size(bcx.ccx(), block_ty));
16651677
expr::Ignore
16661678
}
16671679
};
@@ -1672,6 +1684,13 @@ pub fn trans_closure(ccx: &CrateContext,
16721684
// (trans_block, trans_expr, et cetera).
16731685
bcx = controlflow::trans_block(bcx, body, dest);
16741686

1687+
match dest {
1688+
expr::SaveIn(slot) => {
1689+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
1690+
}
1691+
_ => {}
1692+
}
1693+
16751694
match fcx.llreturn.get() {
16761695
Some(_) => {
16771696
Br(bcx, fcx.return_exit_block());
@@ -1841,16 +1860,18 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
18411860
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
18421861

18431862
if !type_is_zero_size(fcx.ccx, result_ty) {
1863+
let dest = alloca(bcx, type_of::type_of(bcx.ccx(), result_ty), "eret_slot");
18441864
let repr = adt::represent_type(ccx, result_ty);
18451865
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
18461866
let lldestptr = adt::trans_field_ptr(bcx,
18471867
&*repr,
1848-
fcx.llretptr.get().unwrap(),
1868+
dest,
18491869
disr,
18501870
i);
18511871
arg_datum.store_to(bcx, lldestptr);
18521872
}
1853-
adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
1873+
adt::trans_set_discr(bcx, &*repr, dest, disr);
1874+
Store(bcx, dest, fcx.llretslotptr.get().unwrap());
18541875
}
18551876

18561877
finish_fn(&fcx, bcx, result_ty);

src/librustc/middle/trans/callee.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ pub fn trans_unboxing_shim(bcx: &Block,
389389
for i in range(1, arg_types.len()) {
390390
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
391391
}
392+
let dest = match fcx.llretslotptr.get() {
393+
Some(_) => Some(expr::SaveIn(alloca(bcx, type_of::type_of(ccx, return_type), "ret_slot"))),
394+
None => None
395+
};
392396
bcx = trans_call_inner(bcx,
393397
None,
394398
function_type,
@@ -399,10 +403,13 @@ pub fn trans_unboxing_shim(bcx: &Block,
399403
}
400404
},
401405
ArgVals(llshimmedargs.as_slice()),
402-
match fcx.llretptr.get() {
403-
None => None,
404-
Some(llretptr) => Some(expr::SaveIn(llretptr)),
405-
}).bcx;
406+
dest).bcx;
407+
match dest {
408+
Some(expr::SaveIn(slot)) => {
409+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
410+
}
411+
_ => {}
412+
}
406413

407414
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
408415
finish_fn(&fcx, bcx, return_type);

src/librustc/middle/trans/closure.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -582,16 +582,16 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
582582
ty::ty_fn_args(closure_ty)
583583
.as_slice());
584584
let mut llargs = Vec::new();
585-
match fcx.llretptr.get() {
586-
Some(llretptr) => {
587-
llargs.push(llretptr);
585+
match fcx.llretslotptr.get() {
586+
Some(llretslotptr) => {
587+
llargs.push(Load(bcx, llretslotptr));
588588
}
589589
None => {}
590590
}
591591
llargs.extend(args.iter().map(|arg| arg.val));
592592

593593
let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
594-
if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
594+
if type_is_zero_size(ccx, f.sig.output) || fcx.llretslotptr.get().is_some() {
595595
RetVoid(bcx);
596596
} else {
597597
Ret(bcx, retval);

src/librustc/middle/trans/common.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,11 @@ pub struct FunctionContext<'a> {
240240
// The environment argument in a closure.
241241
pub llenv: Option<ValueRef>,
242242

243-
// The place to store the return value. If the return type is immediate,
244-
// this is an alloca in the function. Otherwise, it's the hidden first
245-
// parameter to the function. After function construction, this should
246-
// always be Some.
247-
pub llretptr: Cell<Option<ValueRef>>,
243+
// A pointer to where to store the return value. If the return type is
244+
// immediate, this points to an alloca in the function. Otherwise, it's a
245+
// pointer to the hidden first parameter of the function. After function
246+
// construction, this should always be Some.
247+
pub llretslotptr: Cell<Option<ValueRef>>,
248248

249249
// These pub elements: "hoisted basic blocks" containing
250250
// administrative activities that have to happen in only one place in
@@ -259,8 +259,8 @@ pub struct FunctionContext<'a> {
259259
pub personality: Cell<Option<ValueRef>>,
260260

261261
// True if the caller expects this fn to use the out pointer to
262-
// return. Either way, your code should write into llretptr, but if
263-
// this value is false, llretptr will be a local alloca.
262+
// return. Either way, your code should write into the slot llretslotptr
263+
// points to, but if this value is false, that slot will be a local alloca.
264264
pub caller_expects_out_pointer: bool,
265265

266266
// Maps arguments to allocas created for them in llallocas.

src/librustc/middle/trans/controlflow.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use middle::trans::debuginfo;
2626
use middle::trans::expr;
2727
use middle::trans::meth;
2828
use middle::trans::type_::Type;
29+
use middle::trans::type_of;
2930
use middle::ty;
3031
use middle::typeck::MethodCall;
3132
use util::ppaux::Repr;
@@ -462,13 +463,22 @@ pub fn trans_ret<'a>(bcx: &'a Block<'a>,
462463
let _icx = push_ctxt("trans_ret");
463464
let fcx = bcx.fcx;
464465
let mut bcx = bcx;
465-
let dest = match bcx.fcx.llretptr.get() {
466-
None => expr::Ignore,
467-
Some(retptr) => expr::SaveIn(retptr),
466+
let dest = match (fcx.llretslotptr.get(), e) {
467+
(Some(_), Some(e)) => {
468+
let ret_ty = expr_ty(bcx, &*e);
469+
expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), ret_ty), "ret_slot"))
470+
}
471+
_ => expr::Ignore,
468472
};
469473
match e {
470474
Some(x) => {
471475
bcx = expr::trans_into(bcx, &*x, dest);
476+
match dest {
477+
expr::SaveIn(slot) => {
478+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
479+
}
480+
_ => {}
481+
}
472482
}
473483
_ => {}
474484
}

src/librustc/middle/trans/reflect.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ impl<'a, 'b> Reflector<'a, 'b> {
321321
let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
322322
let arg = BitCast(bcx, arg, llptrty);
323323
let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
324-
Store(bcx, ret, fcx.llretptr.get().unwrap());
324+
let ret_alloca = alloca(bcx, Type::i64(ccx), "ret_slot");
325+
Store(bcx, ret, ret_alloca);
326+
Store(bcx, ret_alloca, fcx.llretslotptr.get().unwrap());
325327
match fcx.llreturn.get() {
326328
Some(llreturn) => Br(bcx, llreturn),
327329
None => {}

0 commit comments

Comments
 (0)