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

View file

@ -179,16 +179,18 @@ impl FnType {
} }
} }
let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]); if bcx.fcx.llretptr.is_some() {
let llretval = if self.ret_ty.cast { let llretval = load_inbounds(bcx, llargbundle, [ 0, arg_tys.len() ]);
let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty)); let llretval = if self.ret_ty.cast {
Load(bcx, retptr) let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty));
} else { Load(bcx, retptr)
Load(bcx, llretval) } else {
}; Load(bcx, llretval)
let llretptr = BitCast(bcx, };
bcx.fcx.llretptr.get(), let llretptr = BitCast(bcx,
T_ptr(self.ret_ty.ty)); bcx.fcx.llretptr.get(),
Store(bcx, llretval, llretptr); T_ptr(self.ret_ty.ty));
Store(bcx, llretval, llretptr);
}
} }
} }

View file

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

View file

@ -297,7 +297,10 @@ pub fn build_closure(bcx0: block,
// the right thing): // the right thing):
let ret_true = match bcx.fcx.loop_ret { let ret_true = match bcx.fcx.loop_ret {
Some((_, retptr)) => retptr, 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_casted = PointerCast(bcx, ret_true, T_ptr(T_nil()));
let ret_datum = Datum {val: ret_casted, ty: ty::mk_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 { pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
let _icx = bcx.insn_ctxt("trans_ret"); let _icx = bcx.insn_ctxt("trans_ret");
let mut bcx = bcx; let mut bcx = bcx;
let retptr = match copy bcx.fcx.loop_ret { let dest = match copy bcx.fcx.loop_ret {
Some((flagptr, retptr)) => { Some((flagptr, retptr)) => {
// This is a loop body return. Must set continue flag (our 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 // to false, return flag to true, and then store the value in the
// parent's retptr. // parent's retptr.
Store(bcx, C_bool(true), flagptr); Store(bcx, C_bool(true), flagptr);
Store(bcx, C_bool(false), bcx.fcx.llretptr.get()); Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
match e { expr::SaveIn(match e {
Some(x) => PointerCast(bcx, retptr, Some(x) => PointerCast(bcx, retptr,
T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))), T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))),
None => retptr None => retptr
} })
}
None => match bcx.fcx.llretptr {
None => expr::Ignore,
Some(retptr) => expr::SaveIn(retptr),
} }
None => bcx.fcx.llretptr.get()
}; };
match e { match e {
Some(x) => { 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, llsig: llsig,
ret_def: ret_def, ret_def: ret_def,
bundle_ty: bundle_ty, 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 fn_ty: fn_ty
} }
} }
@ -170,7 +170,7 @@ fn build_shim_fn_(ccx: @mut CrateContext,
tie_up_header_blocks(fcx, lltop); tie_up_header_blocks(fcx, lltop);
let ret_cx = raw_block(fcx, false, fcx.llreturn); let ret_cx = raw_block(fcx, false, fcx.llreturn);
Ret(ret_cx, C_null(T_nil())); RetVoid(ret_cx);
return llshimfn; return llshimfn;
} }
@ -530,8 +530,10 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
store_inbounds(bcx, llargval, llargbundle, [0u, i]); 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, fn build_ret(bcx: block,
@ -539,8 +541,10 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
llargbundle: ValueRef) { llargbundle: ValueRef) {
let _icx = bcx.insn_ctxt("foreign::wrap::build_ret"); let _icx = bcx.insn_ctxt("foreign::wrap::build_ret");
let arg_count = shim_types.fn_sig.inputs.len(); let arg_count = shim_types.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]); for bcx.fcx.llretptr.iter().advance |&retptr| {
Store(bcx, Load(bcx, llretptr), bcx.fcx.llretptr.get()); let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]);
Store(bcx, Load(bcx, llretptr), retptr);
}
build_return(bcx); build_return(bcx);
} }
} }
@ -1294,7 +1298,7 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
shim_types: &ShimTypes, shim_types: &ShimTypes,
llargbundle: ValueRef, llargbundle: ValueRef,
llretval: 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. // Write the value into the argument bundle.
let arg_count = shim_types.fn_sig.inputs.len(); let arg_count = shim_types.fn_sig.inputs.len();
let llretptr = load_inbounds(bcx, 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)); atys.push_all(type_of_explicit_args(cx, inputs));
// Use the output as the actual return value if it's immediate. // 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) T_fn(atys, lloutputtype)
} else { } else {
T_fn(atys, llvm::LLVMVoidTypeInContext(cx.llcx)) 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 { 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 { 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 { pub fn type_of_glue_fn(ccx: &CrateContext) -> TypeRef {
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type)); 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());
} }