Inline and cleanup build_return_block

This commit is contained in:
Mark Simulacrum 2016-12-18 09:07:35 -07:00
parent 515d14f094
commit 97a2096e5e
4 changed files with 87 additions and 81 deletions

View File

@ -564,68 +564,6 @@ pub fn alloc_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, ty: Ty<'tcx>, name: &
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();
@ -683,9 +621,17 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
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;
@ -703,9 +649,32 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
}
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> {

View File

@ -16,7 +16,7 @@
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;
@ -390,8 +390,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
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
};
@ -409,17 +409,16 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
}
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);
@ -539,9 +538,31 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
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

View File

@ -201,7 +201,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
// type, so we don't need to explicitly cast the function parameter.
let bcx = make_drop_glue(bcx, get_param(llfn, 0), g);
fcx.build_return_block(&bcx);
bcx.ret_void();
}
fn trans_custom_dtor<'a, 'tcx>(mut bcx: BlockAndBuilder<'a, 'tcx>,

View File

@ -85,8 +85,24 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
let bcx = fcx.get_entry_block();
let llargs = get_params(fcx.llfn);
callee.call(&bcx, &llargs[fcx.fn_ty.ret.is_indirect() as usize..], 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();
args.extend_from_slice(&llargs);
let llret = bcx.call(callee.reify(ccx), &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);
}
llfn
}