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:
parent
dc262d9aa7
commit
4fb2c09541
7 changed files with 49 additions and 31 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue