Omit unused implicit argument if return type is immediate.

This commit is contained in:
Tom Lee 2013-05-21 23:17:04 -07:00
parent dbc57584bd
commit 67283eaad2
11 changed files with 131 additions and 110 deletions

View file

@ -1593,7 +1593,7 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
impl_id: Option<ast::def_id>,
param_substs: Option<@param_substs>,
sp: Option<span>)
-> fn_ctxt {
-> (fn_ctxt, bool) {
for param_substs.each |p| { p.validate(); }
debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \
@ -1611,11 +1611,13 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
ty::subst_tps(ccx.tcx, substs.tys, substs.self_ty, output_type)
}
};
let is_immediate = ty::type_is_immediate(substd_output_type);
let imm = ty::type_is_immediate(substd_output_type);
let fcx = @mut fn_ctxt_ {
llfn: llfndecl,
llenv: unsafe { llvm::LLVMGetParam(llfndecl, 1u as c_uint) },
llenv: unsafe {
llvm::LLVMGetParam(llfndecl, arg_env(imm) as c_uint)
},
llretptr: None,
llstaticallocas: llbbs.sa,
llloadenv: None,
@ -1623,7 +1625,7 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
llself: None,
personality: None,
loop_ret: None,
has_immediate_return_value: is_immediate,
has_immediate_return_value: imm,
llargs: @mut HashMap::new(),
lllocals: @mut HashMap::new(),
llupvars: @mut HashMap::new(),
@ -1636,7 +1638,7 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext,
};
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
fcx
(fcx, imm)
}
pub fn new_fn_ctxt(ccx: @CrateContext,
@ -1644,7 +1646,7 @@ pub fn new_fn_ctxt(ccx: @CrateContext,
llfndecl: ValueRef,
output_type: ty::t,
sp: Option<span>)
-> fn_ctxt {
-> (fn_ctxt, bool) {
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp)
}
@ -1664,7 +1666,8 @@ pub fn new_fn_ctxt(ccx: @CrateContext,
// field of the fn_ctxt with
pub fn create_llargs_for_fn_args(cx: fn_ctxt,
self_arg: self_arg,
args: &[ast::arg])
args: &[ast::arg],
ret_imm: bool)
-> ~[ValueRef] {
let _icx = cx.insn_ctxt("create_llargs_for_fn_args");
@ -1690,7 +1693,7 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt,
// llvm::LLVMGetParam for each argument.
vec::from_fn(args.len(), |i| {
unsafe {
let arg_n = first_real_arg + i;
let arg_n = arg_pos(ret_imm, i);
let arg = &args[i];
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
@ -1829,15 +1832,15 @@ pub fn trans_closure(ccx: @CrateContext,
param_substs.repr(ccx.tcx));
// Set up arguments to the function.
let fcx = new_fn_ctxt_w_id(ccx,
path,
llfndecl,
id,
output_type,
impl_id,
param_substs,
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
let (fcx, imm) = new_fn_ctxt_w_id(ccx,
path,
llfndecl,
id,
output_type,
impl_id,
param_substs,
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs, imm);
// Set the fixed stack segment flag if necessary.
if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
@ -1962,16 +1965,16 @@ pub fn trans_enum_variant(ccx: @CrateContext,
ty_param_substs,
None,
ty::node_id_to_type(ccx.tcx, enum_id));
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
variant.node.id,
enum_ty,
None,
param_substs,
None);
let (fcx, imm) = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
variant.node.id,
enum_ty,
None,
param_substs,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, imm);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
@ -2041,16 +2044,16 @@ pub fn trans_tuple_struct(ccx: @CrateContext,
ty_to_str(ccx.tcx, ctor_ty)))
};
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
ctor_id,
tup_ty,
None,
param_substs,
None);
let (fcx, imm) = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
ctor_id,
tup_ty,
None,
param_substs,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, imm);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
@ -2293,19 +2296,21 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
fn create_main(ccx: @CrateContext, main_llfn: ValueRef) -> ValueRef {
let nt = ty::mk_nil();
let llfty = type_of_fn(ccx, [], nt);
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
lib::llvm::CCallConv, llfty);
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
let (fcx, _) = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
// Call main.
let lloutputarg = C_null(T_ptr(T_i8()));
let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) };
let args = ~[lloutputarg, llenvarg];
let llenvarg = unsafe {
llvm::LLVMGetParam(llfdecl, arg_env(true) as c_uint)
};
let args = ~[llenvarg];
let llresult = Call(bcx, main_llfn, args);
Store(bcx, llresult, fcx.llretptr.get());
@ -2347,8 +2352,6 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
trans_external_path(ccx, start_def_id, start_fn_type);
}
let retptr = llvm::LLVMBuildAlloca(bld, T_i8(), noname());
let crate_map = ccx.crate_map;
let opaque_crate_map = llvm::LLVMBuildPointerCast(bld,
crate_map,
@ -2371,7 +2374,6 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
bld, rust_main, T_ptr(T_i8()), noname());
~[
retptr,
C_null(T_opaque_box_ptr(ccx)),
opaque_rust_main,
llvm::LLVMGetParam(llfn, 0),
@ -2384,7 +2386,6 @@ pub fn create_entry_wrapper(ccx: @CrateContext,
debug!("using user-defined start fn");
let args = {
~[
retptr,
C_null(T_opaque_box_ptr(ccx)),
llvm::LLVMGetParam(llfn, 0 as c_uint),
llvm::LLVMGetParam(llfn, 1 as c_uint),

View file

@ -132,7 +132,8 @@ pub impl FnType {
bcx: block,
ret_ty: TypeRef,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
llargbundle: ValueRef,
ret_imm: bool) {
let mut atys = /*bad*/copy self.arg_tys;
let mut attrs = /*bad*/copy self.attrs;
let mut j = 0u;

View file

@ -510,11 +510,7 @@ pub fn trans_call_inner(in_cx: block,
let mut llargs = ~[];
if ty::type_is_immediate(ret_ty) {
unsafe {
llargs.push(llvm::LLVMGetUndef(T_ptr(T_i8())));
}
} else {
if !ty::type_is_immediate(ret_ty) {
llargs.push(llretslot);
}

View file

@ -660,8 +660,26 @@ pub fn mk_block(llbb: BasicBlockRef, parent: Option<block>, kind: block_kind,
@mut block_(llbb, parent, kind, is_lpad, node_info, fcx)
}
// First two args are retptr, env
pub static first_real_arg: uint = 2u;
pub fn arg_pos(ret_imm: bool, arg: uint) -> uint {
if ret_imm {
arg + 1u
} else {
arg + 2u
}
}
pub fn arg_out(ret_imm: bool) -> uint {
assert!(ret_imm);
0u
}
pub fn arg_env(ret_imm: bool) -> uint {
if !ret_imm {
1u
} else {
0u
}
}
pub struct Result {
bcx: block,
@ -962,8 +980,7 @@ pub fn T_tydesc(targ_cfg: @session::config) -> TypeRef {
let tydescpp = T_ptr(T_ptr(tydesc));
let pvoid = T_ptr(T_i8());
let glue_fn_ty =
T_ptr(T_fn([T_ptr(T_nil()), T_ptr(T_nil()), tydescpp,
pvoid], T_void()));
T_ptr(T_fn([T_ptr(T_nil()), tydescpp, pvoid], T_void()));
let int_type = T_int(targ_cfg);
let elems =

View file

@ -150,9 +150,14 @@ fn build_shim_fn_(ccx: @CrateContext,
ccx.llmod, shim_name, tys.shim_fn_ty);
// Declare the body of the shim function:
let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
let (fcx, imm) = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
//
// FIXME [#6575] this seems to be making the assumption that the first
// implicit argument is always available?
//
let llargbundle = get_param(llshimfn, 0u);
let llargvals = arg_builder(bcx, tys, llargbundle);
@ -174,7 +179,8 @@ fn build_shim_fn_(ccx: @CrateContext,
type wrap_arg_builder<'self> = &'self fn(bcx: block,
tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef);
llargbundle: ValueRef,
ret_imm: bool);
type wrap_ret_builder<'self> = &'self fn(bcx: block,
tys: &ShimTypes,
@ -189,7 +195,7 @@ fn build_wrap_fn_(ccx: @CrateContext,
arg_builder: wrap_arg_builder,
ret_builder: wrap_ret_builder) {
let _icx = ccx.insn_ctxt("foreign::build_wrap_fn_");
let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
let (fcx, imm) = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
// Patch up the return type if it's not immediate and we're returning via
// the C ABI.
@ -204,7 +210,7 @@ fn build_wrap_fn_(ccx: @CrateContext,
// Allocate the struct and write the arguments into it.
let llargbundle = alloca(bcx, tys.bundle_ty);
arg_builder(bcx, tys, llwrapfn, llargbundle);
arg_builder(bcx, tys, llwrapfn, llargbundle, imm);
// Create call itself.
let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8()));
@ -432,16 +438,16 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
cc: lib::llvm::CallConv) {
debug!("build_direct_fn(%s)", *link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let (fcx, imm) = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc);
let ty = ty::lookup_item_type(ccx.tcx,
ast_util::local_def(item.id)).ty;
let ret_ty = ty::ty_fn_ret(ty);
let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
get_param(decl, i + first_real_arg)
get_param(decl, arg_pos(imm, i))
});
let retval = Call(bcx, llbasefn, args);
let ret_ty = ty::ty_fn_ret(ty);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
@ -458,18 +464,18 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
cc: lib::llvm::CallConv) {
debug!("build_fast_ffi_fn(%s)", *link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let (fcx, imm) = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
let llbasefn = base_fn(ccx, *link_name(ccx, item), tys, cc);
set_no_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
let ty = ty::lookup_item_type(ccx.tcx,
ast_util::local_def(item.id)).ty;
let ret_ty = ty::ty_fn_ret(ty);
let args = vec::from_fn(ty::ty_fn_args(ty).len(), |i| {
get_param(decl, i + first_real_arg)
get_param(decl, arg_pos(imm, i))
});
let retval = Call(bcx, llbasefn, args);
let ret_ty = ty::ty_fn_ret(ty);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
@ -508,13 +514,13 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
fn build_args(bcx: block,
tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
llargbundle: ValueRef,
ret_imm: bool) {
let _icx = bcx.insn_ctxt("foreign::wrap::build_args");
let ccx = bcx.ccx();
let n = tys.llsig.llarg_tys.len();
let implicit_args = first_real_arg; // return + env
for uint::range(0, n) |i| {
let mut llargval = get_param(llwrapfn, i + implicit_args);
let mut llargval = get_param(llwrapfn, arg_pos(ret_imm, i));
// In some cases, Rust will pass a pointer which the
// native C type doesn't have. In that case, just
@ -552,14 +558,14 @@ pub fn trans_intrinsic(ccx: @CrateContext,
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
let fcx = new_fn_ctxt_w_id(ccx,
path,
decl,
item.id,
output_type,
None,
Some(substs),
Some(item.span));
let (fcx, imm) = new_fn_ctxt_w_id(ccx,
path,
decl,
item.id,
output_type,
None,
Some(substs),
Some(item.span));
// Set the fixed stack segment flag if necessary.
if attr::attrs_contains_name(attributes, "fixed_stack_segment") {
@ -568,6 +574,7 @@ pub fn trans_intrinsic(ccx: @CrateContext,
let mut bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let first_real_arg = arg_pos(imm, 0u);
match *ccx.sess.str_of(item.ident) {
~"atomic_cxchg" => {
let old = AtomicCmpXchg(bcx,
@ -1269,8 +1276,6 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
if !ty::type_is_immediate(tys.fn_sig.output) {
let llretptr = load_inbounds(bcx, llargbundle, [0u, n]);
llargvals.push(llretptr);
} else {
llargvals.push(C_null(T_ptr(T_i8())));
}
let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx()));
@ -1351,12 +1356,14 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
fn build_args(bcx: block,
tys: &ShimTypes,
llwrapfn: ValueRef,
llargbundle: ValueRef) {
llargbundle: ValueRef,
ret_imm: bool) {
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args");
tys.fn_ty.build_wrap_args(bcx,
tys.llsig.llret_ty,
llwrapfn,
llargbundle);
llargbundle,
ret_imm);
}
fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) {

View file

@ -19,6 +19,7 @@ use back::link::*;
use driver::session;
use lib;
use lib::llvm::{llvm, ValueRef, TypeRef, True};
use lib::llvm::type_to_str;
use middle::trans::adt;
use middle::trans::base::*;
use middle::trans::callee;
@ -381,8 +382,9 @@ pub fn call_tydesc_glue_full(bcx: block,
}
};
Call(bcx, llfn, [C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
C_null(T_ptr(T_ptr(bcx.ccx().tydesc_type))), llrawptr]);
Call(bcx, llfn, [C_null(T_ptr(T_nil())),
C_null(T_ptr(T_ptr(bcx.ccx().tydesc_type))),
llrawptr]);
}
// See [Note-arg-mode]
@ -483,17 +485,16 @@ pub fn trans_struct_drop(bcx: block,
};
// Class dtors have no explicit args, so the params should
// just consist of the output pointer and the environment
// (self)
assert_eq!(params.len(), 2);
// just consist of the environment (self)
assert_eq!(params.len(), 1);
// Take a reference to the class (because it's using the Drop trait),
// do so now.
let llval = alloca(bcx, val_ty(v0));
Store(bcx, v0, llval);
let self_arg = PointerCast(bcx, llval, params[1]);
let args = ~[C_null(T_ptr(T_i8())), self_arg];
let self_arg = PointerCast(bcx, llval, params[0]);
let args = ~[self_arg];
Call(bcx, dtor_addr, args);
@ -726,7 +727,7 @@ pub fn make_generic_glue_inner(ccx: @CrateContext,
helper: glue_helper)
-> ValueRef {
let _icx = ccx.insn_ctxt("make_generic_glue_inner");
let fcx = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None);
let (fcx, imm) = new_fn_ctxt(ccx, ~[], llfn, ty::mk_nil(), None);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
ccx.stats.n_glues_created += 1u;
// All glue functions take values passed *by alias*; this is a
@ -739,7 +740,7 @@ pub fn make_generic_glue_inner(ccx: @CrateContext,
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, 3u as c_uint) };
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, arg_pos(true, 1u) as c_uint) };
helper(bcx, llrawptr0, t);
finish_fn(fcx, lltop);
return llfn;

View file

@ -287,13 +287,18 @@ pub impl Reflector {
let llfty = type_of_fn(ccx, [opaqueptrty], ty::mk_int());
let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
let arg = unsafe {
llvm::LLVMGetParam(llfdecl, first_real_arg as c_uint)
//
// we know the return type of llfdecl is an int here, so
// no need for a special check to see if the return type
// is immediate.
//
llvm::LLVMGetParam(llfdecl, arg_pos(true, 0u) as c_uint)
};
let fcx = new_fn_ctxt(ccx,
~[],
llfdecl,
ty::mk_uint(),
None);
let (fcx, _) = new_fn_ctxt(ccx,
~[],
llfdecl,
ty::mk_uint(),
None);
let bcx = top_scope_block(fcx, None);
let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, repr, arg);

View file

@ -46,9 +46,6 @@ pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::t], output: ty::t)
let lloutputtype = type_of(cx, output);
if !output_is_immediate {
atys.push(T_ptr(lloutputtype));
} else {
// FIXME #6575: Eliminate this.
atys.push(T_ptr(T_i8()));
}
// Arg 1: Environment
@ -334,9 +331,7 @@ pub fn llvm_type_name(cx: @CrateContext,
}
pub fn type_of_dtor(ccx: @CrateContext, self_ty: ty::t) -> TypeRef {
T_fn([T_ptr(T_i8()), // output pointer
T_ptr(type_of(ccx, self_ty))], // self arg
T_nil())
T_fn([T_ptr(type_of(ccx, self_ty))] /* self */, T_nil())
}
pub fn type_of_rooted(ccx: @CrateContext, t: ty::t) -> TypeRef {
@ -349,5 +344,5 @@ pub fn type_of_rooted(ccx: @CrateContext, t: ty::t) -> TypeRef {
pub fn type_of_glue_fn(ccx: @CrateContext, t: ty::t) -> TypeRef {
let tydescpp = T_ptr(T_ptr(ccx.tydesc_type));
let llty = T_ptr(type_of(ccx, t));
return T_fn([T_ptr(T_nil()), T_ptr(T_nil()), tydescpp, llty], T_nil());
return T_fn([T_ptr(T_nil()), tydescpp, llty], T_nil());
}

View file

@ -731,10 +731,10 @@ rust_task_deref(rust_task *task) {
// Must call on rust stack.
extern "C" CDECL void
rust_call_tydesc_glue(void *root, size_t *tydesc, size_t glue_index) {
void (*glue_fn)(void *, void *, void *, void *) =
(void (*)(void *, void *, void *, void *))tydesc[glue_index];
void (*glue_fn)(void *, void *, void *) =
(void (*)(void *, void *, void *))tydesc[glue_index];
if (glue_fn)
glue_fn(0, 0, 0, root);
glue_fn(0, 0, root);
}
// Don't run on the Rust stack!
@ -754,7 +754,7 @@ public:
virtual void run() {
record_sp_limit(0);
fn.f(NULL, fn.env, NULL);
fn.f(fn.env, NULL);
}
};

View file

@ -162,9 +162,7 @@ void task_start_wrapper(spawn_args *a)
bool threw_exception = false;
try {
// The first argument is the return pointer; as the task fn
// must have void return type, we can safely pass 0.
a->f(0, a->envptr, a->argptr);
a->f(a->envptr, a->argptr);
} catch (rust_task *ex) {
assert(ex == task && "Expected this task to be thrown for unwinding");
threw_exception = true;
@ -185,7 +183,7 @@ void task_start_wrapper(spawn_args *a)
if(env) {
// free the environment (which should be a unique closure).
const type_desc *td = env->td;
td->drop_glue(NULL, NULL, NULL, box_body(env));
td->drop_glue(NULL, NULL, box_body(env));
task->kernel->region()->free(env);
}

View file

@ -21,11 +21,11 @@ struct rust_opaque_box;
// - the main function: has a NULL environment, but uses the void* arg
// - unique closures of type fn~(): have a non-NULL environment, but
// no arguments (and hence the final void*) is harmless
typedef void (*CDECL spawn_fn)(void*, rust_opaque_box*, void *);
typedef void (*CDECL spawn_fn)(rust_opaque_box*, void *);
struct type_desc;
typedef void CDECL (glue_fn)(void *, void *, const type_desc **, void *);
typedef void CDECL (glue_fn)(void *, const type_desc **, void *);
// Corresponds to the boxed data in the @ region. The body follows the
// header; you can obtain a ptr via box_body() below.