Skip to content

Commit ad0be00

Browse files
committed
librustc: Use separate stack slot for each return.
1 parent 6635fe7 commit ad0be00

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
@@ -1207,16 +1207,23 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
12071207
p
12081208
}
12091209

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

12221229
// NB: must keep 4 fns in sync:
@@ -1254,7 +1261,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
12541261
let mut fcx = FunctionContext {
12551262
llfn: llfndecl,
12561263
llenv: None,
1257-
llretptr: Cell::new(None),
1264+
llretslotptr: Cell::new(None),
12581265
alloca_insert_pt: Cell::new(None),
12591266
llreturn: Cell::new(None),
12601267
personality: Cell::new(None),
@@ -1298,12 +1305,12 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
12981305

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

@@ -1528,12 +1535,12 @@ pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
15281535

15291536
// Builds the return block for a function.
15301537
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
1531-
// Return the value if this function immediate; otherwise, return void.
1532-
if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
1538+
if fcx.llretslotptr.get().is_none() {
15331539
return RetVoid(ret_cx);
15341540
}
15351541

1536-
let retptr = Value(fcx.llretptr.get().unwrap());
1542+
let retslot = Load(ret_cx, fcx.llretslotptr.get().unwrap());
1543+
let retptr = Value(retslot);
15371544
let retval = match retptr.get_dominating_store(ret_cx) {
15381545
// If there's only a single store to the ret slot, we can directly return
15391546
// the value that was stored and omit the store and the alloca
@@ -1552,10 +1559,15 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
15521559
}
15531560
}
15541561
// Otherwise, load the return value from the ret slot
1555-
None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
1562+
None => load_ty(ret_cx, retslot, retty)
15561563
};
15571564

1558-
Ret(ret_cx, retval);
1565+
if fcx.caller_expects_out_pointer {
1566+
store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
1567+
RetVoid(ret_cx);
1568+
} else {
1569+
Ret(ret_cx, retval);
1570+
}
15591571
}
15601572

15611573
#[deriving(Clone, Eq, PartialEq)]
@@ -1651,10 +1663,10 @@ pub fn trans_closure(ccx: &CrateContext,
16511663
// emitting should be enabled.
16521664
debuginfo::start_emitting_source_locations(&fcx);
16531665

1654-
let dest = match fcx.llretptr.get() {
1655-
Some(e) => {expr::SaveIn(e)}
1666+
let dest = match fcx.llretslotptr.get() {
1667+
Some(_) => expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), block_ty), "iret_slot")),
16561668
None => {
1657-
assert!(type_is_zero_size(bcx.ccx(), block_ty))
1669+
assert!(type_is_zero_size(bcx.ccx(), block_ty));
16581670
expr::Ignore
16591671
}
16601672
};
@@ -1665,6 +1677,13 @@ pub fn trans_closure(ccx: &CrateContext,
16651677
// (trans_block, trans_expr, et cetera).
16661678
bcx = controlflow::trans_block(bcx, body, dest);
16671679

1680+
match dest {
1681+
expr::SaveIn(slot) => {
1682+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
1683+
}
1684+
_ => {}
1685+
}
1686+
16681687
match fcx.llreturn.get() {
16691688
Some(_) => {
16701689
Br(bcx, fcx.return_exit_block());
@@ -1832,16 +1851,18 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
18321851
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
18331852

18341853
if !type_is_zero_size(fcx.ccx, result_ty) {
1854+
let dest = alloca(bcx, type_of::type_of(bcx.ccx(), result_ty), "eret_slot");
18351855
let repr = adt::represent_type(ccx, result_ty);
18361856
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
18371857
let lldestptr = adt::trans_field_ptr(bcx,
18381858
&*repr,
1839-
fcx.llretptr.get().unwrap(),
1859+
dest,
18401860
disr,
18411861
i);
18421862
arg_datum.store_to(bcx, lldestptr);
18431863
}
1844-
adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
1864+
adt::trans_set_discr(bcx, &*repr, dest, disr);
1865+
Store(bcx, dest, fcx.llretslotptr.get().unwrap());
18451866
}
18461867

18471868
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
@@ -388,6 +388,10 @@ pub fn trans_unboxing_shim(bcx: &Block,
388388
for i in range(1, arg_types.len()) {
389389
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
390390
}
391+
let dest = match fcx.llretslotptr.get() {
392+
Some(_) => Some(expr::SaveIn(alloca(bcx, type_of::type_of(ccx, return_type), "ret_slot"))),
393+
None => None
394+
};
391395
bcx = trans_call_inner(bcx,
392396
None,
393397
function_type,
@@ -398,10 +402,13 @@ pub fn trans_unboxing_shim(bcx: &Block,
398402
}
399403
},
400404
ArgVals(llshimmedargs.as_slice()),
401-
match fcx.llretptr.get() {
402-
None => None,
403-
Some(llretptr) => Some(expr::SaveIn(llretptr)),
404-
}).bcx;
405+
dest).bcx;
406+
match dest {
407+
Some(expr::SaveIn(slot)) => {
408+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
409+
}
410+
_ => {}
411+
}
405412

406413
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
407414
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
@@ -580,16 +580,16 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
580580
ty::ty_fn_args(closure_ty)
581581
.as_slice());
582582
let mut llargs = Vec::new();
583-
match fcx.llretptr.get() {
584-
Some(llretptr) => {
585-
llargs.push(llretptr);
583+
match fcx.llretslotptr.get() {
584+
Some(llretslotptr) => {
585+
llargs.push(Load(bcx, llretslotptr));
586586
}
587587
None => {}
588588
}
589589
llargs.extend(args.iter().map(|arg| arg.val));
590590

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

src/librustc/middle/trans/common.rs

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

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

242242
// These pub elements: "hoisted basic blocks" containing
243243
// administrative activities that have to happen in only one place in
@@ -252,8 +252,8 @@ pub struct FunctionContext<'a> {
252252
pub personality: Cell<Option<ValueRef>>,
253253

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

259259
// 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
@@ -25,6 +25,7 @@ use middle::trans::debuginfo;
2525
use middle::trans::expr;
2626
use middle::trans::meth;
2727
use middle::trans::type_::Type;
28+
use middle::trans::type_of;
2829
use middle::ty;
2930
use middle::typeck::MethodCall;
3031
use util::ppaux::Repr;
@@ -456,13 +457,22 @@ pub fn trans_ret<'a>(bcx: &'a Block<'a>,
456457
let _icx = push_ctxt("trans_ret");
457458
let fcx = bcx.fcx;
458459
let mut bcx = bcx;
459-
let dest = match bcx.fcx.llretptr.get() {
460-
None => expr::Ignore,
461-
Some(retptr) => expr::SaveIn(retptr),
460+
let dest = match (fcx.llretslotptr.get(), e) {
461+
(Some(_), Some(e)) => {
462+
let ret_ty = expr_ty(bcx, &*e);
463+
expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), ret_ty), "ret_slot"))
464+
}
465+
_ => expr::Ignore,
462466
};
463467
match e {
464468
Some(x) => {
465469
bcx = expr::trans_into(bcx, &*x, dest);
470+
match dest {
471+
expr::SaveIn(slot) => {
472+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
473+
}
474+
_ => {}
475+
}
466476
}
467477
_ => {}
468478
}

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)