1
Fork 0

Avoid pointless allocas for "nil" return values

By using "void" instead of "{}" as the LLVM type for nil, we can avoid
the alloca/store/load sequence for the return value, resulting in less
and simpler IR code.

This reduces compile times by about 10%.
This commit is contained in:
Björn Steinbrink 2013-06-20 16:42:44 +02:00
parent dc262d9aa7
commit 4fb2c09541
7 changed files with 49 additions and 31 deletions

View file

@ -1653,7 +1653,9 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
fcx.llenv = unsafe {
llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
};
if !ty::type_is_nil(substd_output_type) {
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
}
fcx
}
@ -1808,7 +1810,7 @@ pub fn build_return_block(fcx: fn_ctxt) {
let ret_cx = raw_block(fcx, false, fcx.llreturn);
// Return the value if this function immediate; otherwise, return void.
if fcx.has_immediate_return_value {
if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
Ret(ret_cx, Load(ret_cx, fcx.llretptr.get()))
} else {
RetVoid(ret_cx)
@ -2340,8 +2342,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
llvm::LLVMGetParam(llfdecl, env_arg as c_uint)
};
let args = ~[llenvarg];
let llresult = Call(bcx, main_llfn, args);
Store(bcx, llresult, fcx.llretptr.get());
Call(bcx, main_llfn, args);
build_return(bcx);
finish_fn(fcx, lltop);

View file

@ -179,6 +179,7 @@ impl FnType {
}
}
if bcx.fcx.llretptr.is_some() {
let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]);
let llretval = if self.ret_ty.cast {
let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty));
@ -191,4 +192,5 @@ impl FnType {
T_ptr(self.ret_ty.ty));
Store(bcx, llretval, llretptr);
}
}
}

View file

@ -60,6 +60,11 @@ impl ABIInfo for X86_ABIInfo {
cast: false,
ty: T_void(),
};
} else if !ret_def {
ret_ty = LLVMType {
cast: false,
ty: T_void()
};
}
return FnType {

View file

@ -297,7 +297,10 @@ pub fn build_closure(bcx0: block,
// the right thing):
let ret_true = match bcx.fcx.loop_ret {
Some((_, retptr)) => retptr,
None => bcx.fcx.llretptr.get()
None => match bcx.fcx.llretptr {
None => C_null(T_ptr(T_nil())),
Some(retptr) => retptr,
}
};
let ret_casted = PointerCast(bcx, ret_true, T_ptr(T_nil()));
let ret_datum = Datum {val: ret_casted, ty: ty::mk_nil(),

View file

@ -298,24 +298,27 @@ pub fn trans_cont(bcx: block, label_opt: Option<ident>) -> block {
pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
let _icx = bcx.insn_ctxt("trans_ret");
let mut bcx = bcx;
let retptr = match copy bcx.fcx.loop_ret {
let dest = match copy bcx.fcx.loop_ret {
Some((flagptr, retptr)) => {
// This is a loop body return. Must set continue flag (our retptr)
// to false, return flag to true, and then store the value in the
// parent's retptr.
Store(bcx, C_bool(true), flagptr);
Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
match e {
expr::SaveIn(match e {
Some(x) => PointerCast(bcx, retptr,
T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))),
None => retptr
})
}
None => match bcx.fcx.llretptr {
None => expr::Ignore,
Some(retptr) => expr::SaveIn(retptr),
}
None => bcx.fcx.llretptr.get()
};
match e {
Some(x) => {
bcx = expr::trans_into(bcx, x, expr::SaveIn(retptr));
bcx = expr::trans_into(bcx, x, dest);
}
_ => ()
}

View file

@ -127,7 +127,7 @@ fn shim_types(ccx: @mut CrateContext, id: ast::node_id) -> ShimTypes {
llsig: llsig,
ret_def: ret_def,
bundle_ty: bundle_ty,
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_nil()),
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void()),
fn_ty: fn_ty
}
}
@ -170,7 +170,7 @@ fn build_shim_fn_(ccx: @mut CrateContext,
tie_up_header_blocks(fcx, lltop);
let ret_cx = raw_block(fcx, false, fcx.llreturn);
Ret(ret_cx, C_null(T_nil()));
RetVoid(ret_cx);
return llshimfn;
}
@ -530,8 +530,10 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
store_inbounds(bcx, llargval, llargbundle, [0u, i]);
}
let llretptr = bcx.fcx.llretptr.get();
store_inbounds(bcx, llretptr, llargbundle, [0u, n]);
for bcx.fcx.llretptr.iter().advance |&retptr| {
store_inbounds(bcx, retptr, llargbundle, [0u, n]);
}
}
fn build_ret(bcx: block,
@ -539,8 +541,10 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
llargbundle: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::wrap::build_ret");
let arg_count = shim_types.fn_sig.inputs.len();
for bcx.fcx.llretptr.iter().advance |&retptr| {
let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]);
Store(bcx, Load(bcx, llretptr), bcx.fcx.llretptr.get());
Store(bcx, Load(bcx, llretptr), retptr);
}
build_return(bcx);
}
}
@ -1294,7 +1298,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
shim_types: &ShimTypes,
llargbundle: ValueRef,
llretval: ValueRef) {
if ty::type_is_immediate(shim_types.fn_sig.output) {
if bcx.fcx.llretptr.is_some() && ty::type_is_immediate(shim_types.fn_sig.output) {
// Write the value into the argument bundle.
let arg_count = shim_types.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx,

View file

@ -55,7 +55,7 @@ pub fn type_of_fn(cx: &mut CrateContext, inputs: &[ty::t], output: ty::t)
atys.push_all(type_of_explicit_args(cx, inputs));
// Use the output as the actual return value if it's immediate.
if output_is_immediate {
if output_is_immediate && !ty::type_is_nil(output) {
T_fn(atys, lloutputtype)
} else {
T_fn(atys, llvm::LLVMVoidTypeInContext(cx.llcx))
@ -352,7 +352,7 @@ pub fn llvm_type_name(cx: &CrateContext,
}
pub fn type_of_dtor(ccx: &mut CrateContext, self_ty: ty::t) -> TypeRef {
T_fn([T_ptr(type_of(ccx, self_ty))] /* self */, T_nil())
T_fn([T_ptr(type_of(ccx, self_ty))] /* self */, T_void())
}
pub fn type_of_rooted(ccx: &mut CrateContext, t: ty::t) -> TypeRef {
@ -364,5 +364,5 @@ pub fn type_of_rooted(ccx: &mut CrateContext, t: ty::t) -> TypeRef {
pub fn type_of_glue_fn(ccx: &CrateContext) -> TypeRef {
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
return T_fn([T_ptr(T_nil()), tydescpp, T_ptr(T_i8())], T_nil());
return T_fn([T_ptr(T_nil()), tydescpp, T_ptr(T_i8())], T_void());
}