bcx.fcx().alloca(type_of::type_of(bcx.ccx(), ty), name)
}
-impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
- // Builds the return block for a function.
- pub fn build_return_block(&self, ret_cx: &BlockAndBuilder<'a, 'tcx>) {
- if self.llretslotptr.is_none() || self.fn_ty.ret.is_indirect() {
- return ret_cx.ret_void();
- }
-
- let retslot = self.llretslotptr.unwrap();
- let retptr = Value(retslot);
- let llty = self.fn_ty.ret.original_ty;
- match (retptr.get_dominating_store(ret_cx), self.fn_ty.ret.cast) {
- // 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.
- // However, we only want to do this when there is no cast needed.
- (Some(s), None) => {
- let mut retval = s.get_operand(0).unwrap().get();
- s.erase_from_parent();
-
- if retptr.has_no_uses() {
- retptr.erase_from_parent();
- }
-
- if self.fn_ty.ret.is_indirect() {
- ret_cx.store(retval, get_param(self.llfn, 0));
- ret_cx.ret_void()
- } else {
- if llty == Type::i1(self.ccx) {
- retval = ret_cx.trunc(retval, llty);
- }
- ret_cx.ret(retval)
- }
- }
- (_, cast_ty) if self.fn_ty.ret.is_indirect() => {
- // Otherwise, copy the return value to the ret slot.
- assert_eq!(cast_ty, None);
- let llsz = llsize_of(self.ccx, self.fn_ty.ret.ty);
- let llalign = llalign_of_min(self.ccx, self.fn_ty.ret.ty);
- call_memcpy(&ret_cx, get_param(self.llfn, 0),
- retslot, llsz, llalign as u32);
- ret_cx.ret_void()
- }
- (_, Some(cast_ty)) => {
- let load = ret_cx.load(ret_cx.pointercast(retslot, cast_ty.ptr_to()));
- let llalign = llalign_of_min(self.ccx, self.fn_ty.ret.ty);
- unsafe {
- llvm::LLVMSetAlignment(load, llalign);
- }
- ret_cx.ret(load)
- }
- (_, None) => {
- let retval = if llty == Type::i1(self.ccx) {
- let val = ret_cx.load_range_assert(retslot, 0, 2, llvm::False);
- ret_cx.trunc(val, llty)
- } else {
- ret_cx.load(retslot)
- };
- ret_cx.ret(retval)
- }
- }
- }
-}
-
pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
let _s = if ccx.sess().trans_stats() {
let mut instance_name = String::new();
let fcx = FunctionContext::new(ccx, llfndecl, fn_ty, None, false);
let bcx = fcx.get_entry_block();
-
if !fcx.fn_ty.ret.is_ignore() {
- let dest = fcx.llretslotptr.unwrap();
+ // But if there are no nested returns, we skip the indirection
+ // and have a single retslot
+ let dest = if fcx.fn_ty.ret.is_indirect() {
+ get_param(fcx.llfn, 0)
+ } else {
+ // We create an alloca to hold a pointer of type `ret.original_ty`
+ // which will hold the pointer to the right alloca which has the
+ // final ret value
+ fcx.alloca(fcx.fn_ty.ret.memory_ty(ccx), "sret_slot")
+ };
let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
let mut arg_idx = 0;
}
}
adt::trans_set_discr(&bcx, sig.output(), dest, disr);
- }
- fcx.build_return_block(&bcx);
+ if fcx.fn_ty.ret.is_indirect() {
+ bcx.ret_void();
+ return;
+ }
+
+ if let Some(cast_ty) = fcx.fn_ty.ret.cast {
+ let load = bcx.load(bcx.pointercast(dest, cast_ty.ptr_to()));
+ let llalign = llalign_of_min(fcx.ccx, fcx.fn_ty.ret.ty);
+ unsafe {
+ llvm::LLVMSetAlignment(load, llalign);
+ }
+ bcx.ret(load)
+ } else {
+ let llty = fcx.fn_ty.ret.original_ty;
+ let retval = if llty == Type::i1(fcx.ccx) {
+ let val = bcx.load_range_assert(dest, 0, 2, llvm::False);
+ bcx.trunc(val, llty)
+ } else {
+ bcx.load(dest)
+ };
+ bcx.ret(retval)
+ }
+ } else {
+ bcx.ret_void();
+ }
}
pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
pub use self::CalleeData::*;
-use llvm::{self, ValueRef, get_params};
+use llvm::{self, ValueRef, get_param, get_params};
use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
let fn_ret = callee.ty.fn_ret();
let fn_ty = callee.direct_fn_type(bcx.ccx(), &[]);
- let first_llarg = if fn_ty.ret.is_indirect() {
- fcx.llretslotptr
+ let first_llarg = if fn_ty.ret.is_indirect() && !fcx.fn_ty.ret.is_ignore() {
+ Some(get_param(fcx.llfn, 0))
} else {
None
};
}
fn_ty.apply_attrs_callsite(llret);
- if !fn_ty.ret.is_indirect() {
- if let Some(llretslot) = fcx.llretslotptr {
- fn_ty.ret.store(&bcx, llret, llretslot);
- }
- }
-
if fn_ret.0.is_never() {
bcx.unreachable();
}
self_scope.trans(&bcx);
- fcx.build_return_block(&bcx);
+
+ if fcx.fn_ty.ret.is_indirect() || fcx.fn_ty.ret.is_ignore() {
+ bcx.ret_void();
+ } else {
+ bcx.ret(llret);
+ }
ccx.instances().borrow_mut().insert(method_instance, lloncefn);
data: Fn(llfnpointer),
ty: bare_fn_ty
};
- callee.call(&bcx, &llargs[(self_idx + 1)..], fcx.llretslotptr, None);
- fcx.build_return_block(&bcx);
+ let fn_ret = callee.ty.fn_ret();
+ let fn_ty = callee.direct_fn_type(ccx, &[]);
+
+ let mut args = Vec::new();
+
+ if fn_ty.ret.is_indirect() {
+ if !fn_ty.ret.is_ignore() {
+ args.push(get_param(fcx.llfn, 0));
+ }
+ }
+ args.extend_from_slice(&llargs[(self_idx + 1)..]);
+
+ let llret = bcx.call(llfnpointer, &args, None);
+ fn_ty.apply_attrs_callsite(llret);
+
+ if fn_ret.0.is_never() {
+ bcx.unreachable();
+ }
+
+ if fn_ty.ret.is_indirect() || fcx.fn_ty.ret.is_ignore() {
+ bcx.ret_void();
+ } else {
+ bcx.ret(llret);
+ }
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
llfn