librustc: Use separate stack slot for each return.
This commit is contained in:
parent
9dcf89567e
commit
68cbd6c929
@ -1210,16 +1210,23 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
|
||||
p
|
||||
}
|
||||
|
||||
// Creates and returns space for, or returns the argument representing, the
|
||||
// slot where the return value of the function must go.
|
||||
pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
|
||||
-> ValueRef {
|
||||
// Creates the alloca slot which holds the pointer to the slot for the final return value
|
||||
pub fn make_return_slot_pointer(fcx: &FunctionContext, output_type: ty::t) -> ValueRef {
|
||||
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
|
||||
|
||||
// Let's create the stack slot
|
||||
let slot = AllocaFcx(fcx, lloutputtype.ptr_to(), "llretslotptr");
|
||||
|
||||
// and if we're using an out pointer, then store that in our newly made slot
|
||||
if type_of::return_uses_outptr(fcx.ccx, output_type) {
|
||||
get_param(fcx.llfn, 0)
|
||||
} else {
|
||||
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
|
||||
AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
|
||||
let outptr = get_param(fcx.llfn, 0);
|
||||
|
||||
let b = fcx.ccx.builder();
|
||||
b.position_before(fcx.alloca_insert_pt.get().unwrap());
|
||||
b.store(outptr, slot);
|
||||
}
|
||||
|
||||
slot
|
||||
}
|
||||
|
||||
// NB: must keep 4 fns in sync:
|
||||
@ -1258,7 +1265,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
|
||||
let mut fcx = FunctionContext {
|
||||
llfn: llfndecl,
|
||||
llenv: None,
|
||||
llretptr: Cell::new(None),
|
||||
llretslotptr: Cell::new(None),
|
||||
alloca_insert_pt: Cell::new(None),
|
||||
llreturn: Cell::new(None),
|
||||
personality: Cell::new(None),
|
||||
@ -1303,12 +1310,12 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
|
||||
|
||||
if !return_type_is_void(fcx.ccx, substd_output_type) {
|
||||
// If the function returns nil/bot, there is no real return
|
||||
// value, so do not set `llretptr`.
|
||||
// value, so do not set `llretslotptr`.
|
||||
if !skip_retptr || fcx.caller_expects_out_pointer {
|
||||
// Otherwise, we normally allocate the llretptr, unless we
|
||||
// Otherwise, we normally allocate the llretslotptr, unless we
|
||||
// have been instructed to skip it for immediate return
|
||||
// values.
|
||||
fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
|
||||
fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1533,12 +1540,12 @@ pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
|
||||
|
||||
// Builds the return block for a function.
|
||||
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
|
||||
// Return the value if this function immediate; otherwise, return void.
|
||||
if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
|
||||
if fcx.llretslotptr.get().is_none() {
|
||||
return RetVoid(ret_cx);
|
||||
}
|
||||
|
||||
let retptr = Value(fcx.llretptr.get().unwrap());
|
||||
let retslot = Load(ret_cx, fcx.llretslotptr.get().unwrap());
|
||||
let retptr = Value(retslot);
|
||||
let retval = match retptr.get_dominating_store(ret_cx) {
|
||||
// If there's only a single store to the ret slot, we can directly return
|
||||
// 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) {
|
||||
}
|
||||
}
|
||||
// Otherwise, load the return value from the ret slot
|
||||
None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
|
||||
None => load_ty(ret_cx, retslot, retty)
|
||||
};
|
||||
|
||||
Ret(ret_cx, retval);
|
||||
if fcx.caller_expects_out_pointer {
|
||||
store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
|
||||
RetVoid(ret_cx);
|
||||
} else {
|
||||
Ret(ret_cx, retval);
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, PartialEq)]
|
||||
@ -1658,10 +1670,10 @@ pub fn trans_closure(ccx: &CrateContext,
|
||||
// emitting should be enabled.
|
||||
debuginfo::start_emitting_source_locations(&fcx);
|
||||
|
||||
let dest = match fcx.llretptr.get() {
|
||||
Some(e) => {expr::SaveIn(e)}
|
||||
let dest = match fcx.llretslotptr.get() {
|
||||
Some(_) => expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), block_ty), "iret_slot")),
|
||||
None => {
|
||||
assert!(type_is_zero_size(bcx.ccx(), block_ty))
|
||||
assert!(type_is_zero_size(bcx.ccx(), block_ty));
|
||||
expr::Ignore
|
||||
}
|
||||
};
|
||||
@ -1672,6 +1684,13 @@ pub fn trans_closure(ccx: &CrateContext,
|
||||
// (trans_block, trans_expr, et cetera).
|
||||
bcx = controlflow::trans_block(bcx, body, dest);
|
||||
|
||||
match dest {
|
||||
expr::SaveIn(slot) => {
|
||||
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match fcx.llreturn.get() {
|
||||
Some(_) => {
|
||||
Br(bcx, fcx.return_exit_block());
|
||||
@ -1841,16 +1860,18 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
|
||||
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
|
||||
|
||||
if !type_is_zero_size(fcx.ccx, result_ty) {
|
||||
let dest = alloca(bcx, type_of::type_of(bcx.ccx(), result_ty), "eret_slot");
|
||||
let repr = adt::represent_type(ccx, result_ty);
|
||||
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
|
||||
let lldestptr = adt::trans_field_ptr(bcx,
|
||||
&*repr,
|
||||
fcx.llretptr.get().unwrap(),
|
||||
dest,
|
||||
disr,
|
||||
i);
|
||||
arg_datum.store_to(bcx, lldestptr);
|
||||
}
|
||||
adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
|
||||
adt::trans_set_discr(bcx, &*repr, dest, disr);
|
||||
Store(bcx, dest, fcx.llretslotptr.get().unwrap());
|
||||
}
|
||||
|
||||
finish_fn(&fcx, bcx, result_ty);
|
||||
|
@ -389,6 +389,10 @@ pub fn trans_unboxing_shim(bcx: &Block,
|
||||
for i in range(1, arg_types.len()) {
|
||||
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
|
||||
}
|
||||
let dest = match fcx.llretslotptr.get() {
|
||||
Some(_) => Some(expr::SaveIn(alloca(bcx, type_of::type_of(ccx, return_type), "ret_slot"))),
|
||||
None => None
|
||||
};
|
||||
bcx = trans_call_inner(bcx,
|
||||
None,
|
||||
function_type,
|
||||
@ -399,10 +403,13 @@ pub fn trans_unboxing_shim(bcx: &Block,
|
||||
}
|
||||
},
|
||||
ArgVals(llshimmedargs.as_slice()),
|
||||
match fcx.llretptr.get() {
|
||||
None => None,
|
||||
Some(llretptr) => Some(expr::SaveIn(llretptr)),
|
||||
}).bcx;
|
||||
dest).bcx;
|
||||
match dest {
|
||||
Some(expr::SaveIn(slot)) => {
|
||||
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
|
||||
finish_fn(&fcx, bcx, return_type);
|
||||
|
@ -582,16 +582,16 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
|
||||
ty::ty_fn_args(closure_ty)
|
||||
.as_slice());
|
||||
let mut llargs = Vec::new();
|
||||
match fcx.llretptr.get() {
|
||||
Some(llretptr) => {
|
||||
llargs.push(llretptr);
|
||||
match fcx.llretslotptr.get() {
|
||||
Some(llretslotptr) => {
|
||||
llargs.push(Load(bcx, llretslotptr));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
llargs.extend(args.iter().map(|arg| arg.val));
|
||||
|
||||
let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
|
||||
if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
|
||||
if type_is_zero_size(ccx, f.sig.output) || fcx.llretslotptr.get().is_some() {
|
||||
RetVoid(bcx);
|
||||
} else {
|
||||
Ret(bcx, retval);
|
||||
|
@ -240,11 +240,11 @@ pub struct FunctionContext<'a> {
|
||||
// The environment argument in a closure.
|
||||
pub llenv: Option<ValueRef>,
|
||||
|
||||
// The place to store the return value. If the return type is immediate,
|
||||
// this is an alloca in the function. Otherwise, it's the hidden first
|
||||
// parameter to the function. After function construction, this should
|
||||
// always be Some.
|
||||
pub llretptr: Cell<Option<ValueRef>>,
|
||||
// A pointer to where to store the return value. If the return type is
|
||||
// immediate, this points to an alloca in the function. Otherwise, it's a
|
||||
// pointer to the hidden first parameter of the function. After function
|
||||
// construction, this should always be Some.
|
||||
pub llretslotptr: Cell<Option<ValueRef>>,
|
||||
|
||||
// These pub elements: "hoisted basic blocks" containing
|
||||
// administrative activities that have to happen in only one place in
|
||||
@ -259,8 +259,8 @@ pub struct FunctionContext<'a> {
|
||||
pub personality: Cell<Option<ValueRef>>,
|
||||
|
||||
// True if the caller expects this fn to use the out pointer to
|
||||
// return. Either way, your code should write into llretptr, but if
|
||||
// this value is false, llretptr will be a local alloca.
|
||||
// return. Either way, your code should write into the slot llretslotptr
|
||||
// points to, but if this value is false, that slot will be a local alloca.
|
||||
pub caller_expects_out_pointer: bool,
|
||||
|
||||
// Maps arguments to allocas created for them in llallocas.
|
||||
|
@ -26,6 +26,7 @@
|
||||
use middle::trans::expr;
|
||||
use middle::trans::meth;
|
||||
use middle::trans::type_::Type;
|
||||
use middle::trans::type_of;
|
||||
use middle::ty;
|
||||
use middle::typeck::MethodCall;
|
||||
use util::ppaux::Repr;
|
||||
@ -462,13 +463,22 @@ pub fn trans_ret<'a>(bcx: &'a Block<'a>,
|
||||
let _icx = push_ctxt("trans_ret");
|
||||
let fcx = bcx.fcx;
|
||||
let mut bcx = bcx;
|
||||
let dest = match bcx.fcx.llretptr.get() {
|
||||
None => expr::Ignore,
|
||||
Some(retptr) => expr::SaveIn(retptr),
|
||||
let dest = match (fcx.llretslotptr.get(), e) {
|
||||
(Some(_), Some(e)) => {
|
||||
let ret_ty = expr_ty(bcx, &*e);
|
||||
expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), ret_ty), "ret_slot"))
|
||||
}
|
||||
_ => expr::Ignore,
|
||||
};
|
||||
match e {
|
||||
Some(x) => {
|
||||
bcx = expr::trans_into(bcx, &*x, dest);
|
||||
match dest {
|
||||
expr::SaveIn(slot) => {
|
||||
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -321,7 +321,9 @@ pub fn visit_ty(&mut self, t: ty::t) {
|
||||
let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
|
||||
let arg = BitCast(bcx, arg, llptrty);
|
||||
let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
|
||||
Store(bcx, ret, fcx.llretptr.get().unwrap());
|
||||
let ret_alloca = alloca(bcx, Type::i64(ccx), "ret_slot");
|
||||
Store(bcx, ret, ret_alloca);
|
||||
Store(bcx, ret_alloca, fcx.llretslotptr.get().unwrap());
|
||||
match fcx.llreturn.get() {
|
||||
Some(llreturn) => Br(bcx, llreturn),
|
||||
None => {}
|
||||
|
Loading…
Reference in New Issue
Block a user