diff options
| -rw-r--r-- | src/librustc/middle/trans/base.rs | 65 | ||||
| -rw-r--r-- | src/librustc/middle/trans/callee.rs | 15 | ||||
| -rw-r--r-- | src/librustc/middle/trans/closure.rs | 8 | ||||
| -rw-r--r-- | src/librustc/middle/trans/common.rs | 14 | ||||
| -rw-r--r-- | src/librustc/middle/trans/controlflow.rs | 16 | ||||
| -rw-r--r-- | src/librustc/middle/trans/reflect.rs | 4 |
6 files changed, 81 insertions, 41 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 242a820c997..9c304f839db 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index f186af48321..3bea9d64462 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -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); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 98b2ebb70f3..dc77edf2706 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -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); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 84f380e862a..6aca8fe8e41 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -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. diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 2fd2e69cfc3..b9644b11453 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -26,6 +26,7 @@ use middle::trans::debuginfo; 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()); + } + _ => {} + } } _ => {} } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index eb0d77da551..35ac0b27071 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -321,7 +321,9 @@ impl<'a, 'b> Reflector<'a, 'b> { 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 => {} |
