Add support for basic return-by-alias to trans

Issue #918
This commit is contained in:
Marijn Haverbeke 2011-09-14 14:34:50 +02:00
parent 9a69ee79e0
commit 93d2a4f82a
4 changed files with 75 additions and 58 deletions

View file

@ -61,17 +61,18 @@ fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
// NB: must keep 4 fns in sync:
//
// - type_of_fn_full
// - type_of_fn
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
fn type_of_fn_full(cx: @crate_ctxt, sp: span, proto: ast::proto,
is_method: bool, inputs: [ty::arg], output: ty::t,
ty_param_count: uint) -> TypeRef {
fn type_of_fn(cx: @crate_ctxt, sp: span, proto: ast::proto,
is_method: bool, ret_ref: bool, inputs: [ty::arg],
output: ty::t, ty_param_count: uint) -> TypeRef {
let atys: [TypeRef] = [];
// Arg 0: Output pointer.
atys += [T_ptr(type_of_inner(cx, sp, output))];
let out_ty = T_ptr(type_of_inner(cx, sp, output));
atys += [ret_ref ? T_ptr(out_ty) : out_ty];
// Arg 1: task pointer.
atys += [T_taskptr(*cx)];
@ -97,17 +98,13 @@ fn type_of_fn_full(cx: @crate_ctxt, sp: span, proto: ast::proto,
ret T_fn(atys, llvm::LLVMVoidType());
}
fn type_of_fn(cx: @crate_ctxt, sp: span, proto: ast::proto, inputs: [ty::arg],
output: ty::t, ty_param_count: uint) -> TypeRef {
ret type_of_fn_full(cx, sp, proto, false, inputs, output, ty_param_count);
}
// Given a function type and a count of ty params, construct an llvm type
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
ty_param_count: uint) -> TypeRef {
let by_ref = ty::ty_fn_ret_style(cx.tcx, fty) == ast::return_ref;
ret type_of_fn(cx, sp, ty::ty_fn_proto(cx.tcx, fty),
ty::ty_fn_args(cx.tcx, fty), ty::ty_fn_ret(cx.tcx, fty),
ty_param_count);
false, by_ref, ty::ty_fn_args(cx.tcx, fty),
ty::ty_fn_ret(cx.tcx, fty), ty_param_count);
}
fn type_of_native_fn(cx: @crate_ctxt, sp: span, abi: ast::native_abi,
@ -2970,12 +2967,13 @@ fn trans_field(cx: @block_ctxt, sp: span, v: ValueRef, t0: ty::t,
vtbl = PointerCast(cx, vtbl, vtbl_type);
let v = GEP(r.bcx, vtbl, [C_int(0), C_int(ix as int)]);
let fn_ty: ty::t = ty::method_ty_to_fn_ty(bcx_tcx(cx), methods[ix]);
let tcx = bcx_tcx(cx);
let fn_ty: ty::t = ty::method_ty_to_fn_ty(tcx, methods[ix]);
let ret_ref = ty::ty_fn_ret_style(tcx, fn_ty) == ast::return_ref;
let ll_fn_ty =
type_of_fn_full(bcx_ccx(cx), sp, ty::ty_fn_proto(tcx, fn_ty),
true, ty::ty_fn_args(tcx, fn_ty),
ty::ty_fn_ret(tcx, fn_ty), 0u);
type_of_fn(bcx_ccx(cx), sp, ty::ty_fn_proto(tcx, fn_ty),
true, ret_ref, ty::ty_fn_args(tcx, fn_ty),
ty::ty_fn_ret(tcx, fn_ty), 0u);
v = PointerCast(r.bcx, v, T_ptr(T_ptr(ll_fn_ty)));
let lvo = lval_mem(r.bcx, v);
ret {llobj: some::<ValueRef>(r.val), method_ty: some::<ty::t>(fn_ty)
@ -3513,18 +3511,18 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
// NB: must keep 4 fns in sync:
//
// - type_of_fn_full
// - type_of_fn
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
lliterbody: option::t<ValueRef>, es: [@ast::expr], fn_ty: ty::t)
->
{bcx: @block_ctxt,
args: [ValueRef],
retslot: ValueRef,
to_zero: [{v: ValueRef, t: ty::t}],
to_revoke: [{v: ValueRef, t: ty::t}]} {
-> {bcx: @block_ctxt,
args: [ValueRef],
retslot: ValueRef,
to_zero: [{v: ValueRef, t: ty::t}],
to_revoke: [{v: ValueRef, t: ty::t}],
by_ref: bool} {
let args: [ty::arg] = ty::ty_fn_args(bcx_tcx(cx), fn_ty);
let llargs: [ValueRef] = [];
@ -3532,7 +3530,9 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
let to_zero = [];
let to_revoke = [];
let tcx = bcx_tcx(cx);
let bcx: @block_ctxt = cx;
let by_ref = ty::ty_fn_ret_style(tcx, fn_ty) == ast::return_ref;
// Arg 0: Output pointer.
// FIXME: test case looks like
@ -3544,22 +3544,25 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
args: [],
retslot: C_nil(),
to_zero: to_zero,
to_revoke: to_revoke};
to_revoke: to_revoke,
by_ref: by_ref};
}
let retty = ty::ty_fn_ret(bcx_tcx(cx), fn_ty);
let llretslot_res = alloc_ty(bcx, retty);
let retty = ty::ty_fn_ret(tcx, fn_ty);
let llretslot_res = if by_ref {
rslt(cx, alloca(cx, T_ptr(type_of_or_i8(cx, retty))))
} else { alloc_ty(bcx, retty) };
bcx = llretslot_res.bcx;
let llretslot = llretslot_res.val;
alt gen {
some(g) {
lazily_emit_all_generic_info_tydesc_glues(cx, g);
lltydescs = g.tydescs;
args = ty::ty_fn_args(bcx_tcx(cx), g.item_type);
retty = ty::ty_fn_ret(bcx_tcx(cx), g.item_type);
args = ty::ty_fn_args(tcx, g.item_type);
retty = ty::ty_fn_ret(tcx, g.item_type);
}
_ { }
}
if ty::type_contains_params(bcx_tcx(cx), retty) {
if ty::type_contains_params(tcx, retty) {
// It's possible that the callee has some generic-ness somewhere in
// its return value -- say a method signature within an obj or a fn
// type deep in a structure -- which the caller has a concrete view
@ -3583,8 +3586,8 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
none. { }
some(lli) {
let lli =
if ty::type_contains_params(bcx_tcx(cx), retty) {
let body_ty = ty::mk_iter_body_fn(bcx_tcx(cx), retty);
if ty::type_contains_params(tcx, retty) {
let body_ty = ty::mk_iter_body_fn(tcx, retty);
let body_llty = type_of_inner(bcx_ccx(cx), cx.sp, body_ty);
PointerCast(bcx, lli, T_ptr(body_llty))
} else { lli };
@ -3615,7 +3618,8 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
args: llargs,
retslot: llretslot,
to_zero: to_zero,
to_revoke: to_revoke};
to_revoke: to_revoke,
by_ref: by_ref};
}
fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
@ -3686,11 +3690,16 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
alt lliterbody {
none. {
if !ty::type_is_nil(bcx_tcx(cx), ret_ty) {
retval = load_if_immediate(bcx, llretslot, ret_ty);
// Retval doesn't correspond to anything really tangible
// in the frame, but it's a ref all the same, so we put a
// note here to drop it when we're done in this scope.
add_clean_temp(in_cx, retval, ret_ty);
if args_res.by_ref {
let retptr = Load(bcx, llretslot);
retval = load_if_immediate(bcx, retptr, ret_ty);
} else {
retval = load_if_immediate(bcx, llretslot, ret_ty);
// Retval doesn't correspond to anything really tangible
// in the frame, but it's a ref all the same, so we put a
// note here to drop it when we're done in this scope.
add_clean_temp(in_cx, retval, ret_ty);
}
}
}
some(_) {
@ -4386,7 +4395,7 @@ fn trans_ret(cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
bcx = lv.res.bcx;
if cx.fcx.ret_style == ast::return_ref {
assert lv.is_mem;
Store(bcx, cx.fcx.llretptr, lv.res.val);
Store(bcx, lv.res.val, cx.fcx.llretptr);
} else {
let is_local = alt x.node {
ast::expr_path(p) {
@ -4824,7 +4833,7 @@ fn mk_standard_basic_blocks(llfn: ValueRef) ->
// NB: must keep 4 fns in sync:
//
// - type_of_fn_full
// - type_of_fn
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
@ -4864,7 +4873,7 @@ fn new_fn_ctxt(cx: @local_ctxt, sp: span, llfndecl: ValueRef) -> @fn_ctxt {
// NB: must keep 4 fns in sync:
//
// - type_of_fn_full
// - type_of_fn
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
@ -5355,10 +5364,10 @@ fn decl_fn_and_pair_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
let llfty =
type_of_fn_from_ty(ccx, sp, node_type, std::vec::len(ty_params));
alt ty::struct(ccx.tcx, node_type) {
ty::ty_fn(proto, inputs, output, _, _) {
llfty =
type_of_fn(ccx, sp, proto, inputs, output,
std::vec::len::<ast::ty_param>(ty_params));
ty::ty_fn(proto, inputs, output, rs, _) {
llfty = type_of_fn(ccx, sp, proto, false,
rs == ast::return_ref, inputs, output,
vec::len(ty_params));
}
_ { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); }
}
@ -5396,9 +5405,8 @@ fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
let vecarg_ty: ty::arg =
{mode: ast::by_ref,
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
let llfty =
type_of_fn(ccx, sp, ast::proto_fn, [vecarg_ty],
ty::mk_nil(ccx.tcx), 0u);
let llfty = type_of_fn(ccx, sp, ast::proto_fn, false, false,
[vecarg_ty], ty::mk_nil(ccx.tcx), 0u);
let llfdecl = decl_fastcall_fn(ccx.llmod, "_rust_main", llfty);
let fcx = new_fn_ctxt(new_local_ctxt(ccx), sp, llfdecl);
@ -5499,7 +5507,8 @@ fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, ty_param_count: uint,
x: ty::t) -> TypeRef {
alt ty::struct(cx.tcx, x) {
ty::ty_native_fn(abi, args, out) {
ret type_of_fn(cx, sp, ast::proto_fn, args, out, ty_param_count);
ret type_of_fn(cx, sp, ast::proto_fn, false, false, args, out,
ty_param_count);
}
}
}

View file

@ -33,7 +33,7 @@ import syntax::print::pprust::{expr_to_str, path_to_str};
import bld = trans_build;
// FIXME: These should probably be pulled in here too.
import trans::{type_of_fn_full, drop_ty};
import trans::{type_of_fn, drop_ty};
obj namegen(mutable i: int) {
fn next(prefix: str) -> str { i += 1; ret prefix + int::str(i); }
@ -336,10 +336,9 @@ fn get_res_dtor(ccx: @crate_ctxt, sp: span, did: ast::def_id, inner_t: ty::t)
}
let params = csearch::get_type_param_count(ccx.sess.get_cstore(), did);
let f_t =
trans::type_of_fn(ccx, sp, ast::proto_fn,
[{mode: ast::by_ref, ty: inner_t}],
ty::mk_nil(ccx.tcx), params);
let f_t = type_of_fn(ccx, sp, ast::proto_fn, false, false,
[{mode: ast::by_ref, ty: inner_t}],
ty::mk_nil(ccx.tcx), params);
ret trans::get_extern_const(ccx.externs, ccx.llmod,
csearch::get_symbol(ccx.sess.get_cstore(),
did),

View file

@ -880,9 +880,9 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
let llfnty = T_nil();
alt ty::struct(cx.ccx.tcx, node_id_type(cx.ccx, m.node.id)) {
ty::ty_fn(proto, inputs, output, _, _) {
llfnty =
type_of_fn_full(cx.ccx, m.span, proto, true, inputs, output,
ty::ty_fn(proto, inputs, output, rs, _) {
llfnty = type_of_fn(cx.ccx, m.span, proto, true,
rs == ast::return_ref, inputs, output,
vec::len(ty_params));
}
}
@ -933,8 +933,8 @@ fn populate_self_stack(bcx: @block_ctxt, self_stack: ValueRef,
fn type_of_meth(ccx: @crate_ctxt, sp: span, m: @ty::method,
tps: [ast::ty_param]) -> TypeRef {
type_of_fn_full(ccx, sp, m.proto, true, m.inputs, m.output,
vec::len(tps))
type_of_fn(ccx, sp, m.proto, true, m.cf == ast::return_ref,
m.inputs, m.output, vec::len(tps))
}
//

View file

@ -118,6 +118,7 @@ export ty_fn;
export ty_fn_abi;
export ty_fn_proto;
export ty_fn_ret;
export ty_fn_ret_style;
export ty_int;
export ty_str;
export ty_vec;
@ -1609,6 +1610,14 @@ fn ty_fn_ret(cx: ctxt, fty: t) -> t {
}
}
fn ty_fn_ret_style(cx: ctxt, fty: t) -> ast::ret_style {
alt struct(cx, fty) {
ty::ty_fn(_, _, _, rs, _) { rs }
ty::ty_native_fn(_, _, _) { ast::return_val }
_ { cx.sess.bug("ty_fn_ret_style() called on non-fn type"); }
}
}
fn is_fn_ty(cx: ctxt, fty: t) -> bool {
alt struct(cx, fty) {
ty::ty_fn(_, _, _, _, _) { ret true; }