Use uniform pair representation of functions everywhere, including static functions.

This commit is contained in:
Graydon Hoare 2011-01-05 15:31:35 -08:00
parent 4fca7d61dd
commit 5d2a6c73ca
2 changed files with 132 additions and 38 deletions

View file

@ -42,6 +42,25 @@ const uint LLVMColdCallConv = 9u;
const uint LLVMX86StdcallCallConv = 64u;
const uint LLVMX86FastcallCallConv = 65u;
const uint LLVMExternalLinkage = 0u;
const uint LLVMAvailableExternallyLinkage = 1u;
const uint LLVMLinkOnceAnyLinkage = 2u;
const uint LLVMLinkOnceODRLinkage = 3u;
const uint LLVMWeakAnyLinkage = 4u;
const uint LLVMWeakODRLinkage = 5u;
const uint LLVMAppendingLinkage = 6u;
const uint LLVMInternalLinkage = 7u;
const uint LLVMPrivateLinkage = 8u;
const uint LLVMDLLImportLinkage = 9u;
const uint LLVMDLLExportLinkage = 10u;
const uint LLVMExternalWeakLinkage = 11u;
const uint LLVMGhostLinkage = 12u;
const uint LLVMCommonLinkage = 13u;
const uint LLVMLinkerPrivateLinkage = 14u;
const uint LLVMLinkerPrivateWeakLinkage = 15u;
// Consts for the LLVM IntPredicate type, pre-cast to uint.
// FIXME: as above.

View file

@ -67,6 +67,8 @@ state type crate_ctxt = rec(session.session sess,
hashmap[ast.def_id, ValueRef] item_ids,
hashmap[ast.def_id, @ast.item] items,
hashmap[ast.def_id, @tag_info] tags,
hashmap[ast.def_id, ValueRef] fn_pairs,
hashmap[ast.def_id,()] obj_methods,
hashmap[@ty.t, ValueRef] tydescs,
vec[ast.obj_field] obj_fields,
@glue_fns glues,
@ -193,7 +195,7 @@ fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
False);
}
fn T_closure(TypeRef tfn) -> TypeRef {
fn T_fn_pair(TypeRef tfn) -> TypeRef {
ret T_struct(vec(T_ptr(tfn),
T_ptr(T_box(T_nil()))));
}
@ -389,7 +391,7 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t) -> TypeRef {
ret T_struct(tys);
}
case (ty.ty_fn(?args, ?out)) {
ret type_of_fn(cx, args, out);
ret T_fn_pair(type_of_fn(cx, args, out));
}
case (ty.ty_obj(?meths)) {
auto th = mk_type_handle();
@ -500,6 +502,8 @@ fn C_str(@crate_ctxt cx, str s) -> ValueRef {
_str.buf(cx.names.next("str")));
llvm.LLVMSetInitializer(g, sc);
llvm.LLVMSetGlobalConstant(g, True);
llvm.LLVMSetLinkage(g, lib.llvm.LLVMPrivateLinkage
as llvm.Linkage);
ret g;
}
@ -679,6 +683,8 @@ fn make_tydesc(@crate_ctxt cx, @ty.t t) {
auto gvar = llvm.LLVMAddGlobal(cx.llmod, val_ty(tydesc), _str.buf(name));
llvm.LLVMSetInitializer(gvar, tydesc);
llvm.LLVMSetGlobalConstant(gvar, True);
llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
as llvm.Linkage);
cx.tydescs.insert(t, gvar);
}
@ -1725,17 +1731,22 @@ fn trans_name(@block_ctxt cx, &ast.name n, &option.t[ast.def] dopt)
ret lval_mem(cx, cx.fcx.llobjfields.get(did));
}
case (ast.def_fn(?did)) {
check (cx.fcx.ccx.item_ids.contains_key(did));
ret lval_val(cx, cx.fcx.ccx.item_ids.get(did));
check (cx.fcx.ccx.fn_pairs.contains_key(did));
ret lval_val(cx, cx.fcx.ccx.fn_pairs.get(did));
}
case (ast.def_obj(?did)) {
check (cx.fcx.ccx.item_ids.contains_key(did));
ret lval_val(cx, cx.fcx.ccx.item_ids.get(did));
check (cx.fcx.ccx.fn_pairs.contains_key(did));
ret lval_val(cx, cx.fcx.ccx.fn_pairs.get(did));
}
case (ast.def_variant(?tid, ?vid)) {
check (cx.fcx.ccx.tags.contains_key(tid));
check (cx.fcx.ccx.item_ids.contains_key(vid));
ret lval_val(cx, cx.fcx.ccx.item_ids.get(vid));
if (cx.fcx.ccx.fn_pairs.contains_key(vid)) {
ret lval_val(cx, cx.fcx.ccx.fn_pairs.get(vid));
} else {
// Nullary variants are just scalar constants.
check (cx.fcx.ccx.item_ids.contains_key(vid));
ret lval_val(cx, cx.fcx.ccx.item_ids.get(vid));
}
}
case (_) {
cx.fcx.ccx.sess.unimpl("def variant in trans");
@ -1942,7 +1953,7 @@ impure fn trans_bind(@block_ctxt cx, @ast.expr f,
&ast.ann ann) -> result {
auto f_res = trans_lval(cx, f);
auto bcx = f_res.res.bcx;
auto pair_t = T_closure(node_type(cx.fcx.ccx, ann));
auto pair_t = node_type(cx.fcx.ccx, ann);
auto pair_v = bcx.build.Alloca(pair_t);
if (f_res.is_mem) {
cx.fcx.ccx.sess.unimpl("re-binding existing function");
@ -1959,19 +1970,18 @@ impure fn trans_call(@block_ctxt cx, @ast.expr f,
vec[@ast.expr] args, &ast.ann ann) -> result {
auto f_res = trans_lval(cx, f);
auto faddr = f_res.res.val;
if (f_res.is_mem) {
alt (f_res.llobj) {
case (some[ValueRef](_)) {
// It's a vtbl entry.
faddr = f_res.res.bcx.build.Load(faddr);
}
case (none[ValueRef]) {
// It's a closure.
auto bcx = f_res.res.bcx;
faddr = bcx.build.GEP(faddr, vec(C_int(0),
C_int(abi.fn_field_code)));
faddr = bcx.build.Load(faddr);
}
alt (f_res.llobj) {
case (some[ValueRef](_)) {
// It's a vtbl entry.
faddr = f_res.res.bcx.build.Load(faddr);
}
case (none[ValueRef]) {
// It's a closure.
auto bcx = f_res.res.bcx;
faddr = bcx.build.GEP(faddr, vec(C_int(0),
C_int(abi.fn_field_code)));
faddr = bcx.build.Load(faddr);
}
}
auto fn_ty = ty.expr_ty(f);
@ -2701,6 +2711,8 @@ impure fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty,
_str.buf("_rust_vtbl" + "." + cx.path));
llvm.LLVMSetInitializer(gvar, vtbl);
llvm.LLVMSetGlobalConstant(gvar, True);
llvm.LLVMSetLinkage(gvar, lib.llvm.LLVMPrivateLinkage
as llvm.Linkage);
ret gvar;
}
@ -2818,15 +2830,8 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
id=varg.id));
}
auto var_ty = ty.ann_to_type(variant.ann);
auto llfnty = type_of(cx, var_ty);
let str s = cx.names.next("_rust_tag") + "." + cx.path;
let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfnty);
cx.item_ids.insert(variant.id, llfn);
check (cx.item_ids.contains_key(variant.id));
let ValueRef llfndecl = cx.item_ids.get(variant.id);
cx.item_names.insert(cx.path, llfndecl);
auto fcx = new_fn_ctxt(cx, cx.path, llfndecl);
create_llargs_for_fn_args(fcx, none[TypeRef], ret_ty_of_fn(variant.ann),
@ -2907,25 +2912,59 @@ impure fn trans_mod(@crate_ctxt cx, &ast._mod m) {
}
}
fn decl_fn_and_pair(@crate_ctxt cx,
str kind,
str name,
&ast.ann ann,
ast.def_id id) {
// Bit of a kludge: pick the fn typeref out of the pair.
auto llpairty = node_type(cx, ann);
let vec[TypeRef] pair_tys = vec(T_nil(), T_nil());
llvm.LLVMGetStructElementTypes(llpairty,
_vec.buf[TypeRef](pair_tys));
auto llfty = llvm.LLVMGetElementType(pair_tys.(0));
// Declare the function itself.
let str s = cx.names.next("_rust_" + kind) + "." + name;
let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llfty);
// Declare the global constant pair that points to it.
let str ps = cx.names.next("_rust_" + kind + "_pair") + "." + name;
let ValueRef gvar = llvm.LLVMAddGlobal(cx.llmod, llpairty,
_str.buf(ps));
auto pair = C_struct(vec(llfn,
C_null(T_ptr(T_box(T_nil())))));
llvm.LLVMSetInitializer(gvar, pair);
llvm.LLVMSetGlobalConstant(gvar, True);
llvm.LLVMSetLinkage(gvar,
lib.llvm.LLVMPrivateLinkage
as llvm.Linkage);
cx.item_ids.insert(id, llfn);
cx.fn_pairs.insert(id, gvar);
}
fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
alt (i.node) {
case (ast.item_fn(?name, ?f, _, ?fid, ?ann)) {
// TODO: type-params
cx.items.insert(fid, i);
auto llty = node_type(cx, ann);
let str s = cx.names.next("_rust_fn") + "." + name;
let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llty);
cx.item_ids.insert(fid, llfn);
if (! cx.obj_methods.contains_key(fid)) {
decl_fn_and_pair(cx, "fn", name, ann, fid);
}
}
case (ast.item_obj(?name, ?ob, _, ?oid, ?ann)) {
// TODO: type-params
cx.items.insert(oid, i);
auto llty = node_type(cx, ann);
let str s = cx.names.next("_rust_obj_ctor") + "." + name;
let ValueRef llfn = decl_fastcall_fn(cx.llmod, s, llty);
cx.item_ids.insert(oid, llfn);
decl_fn_and_pair(cx, "obj_ctor", name, ann, oid);
for (@ast.method m in ob.methods) {
cx.obj_methods.insert(m.node.id, ());
}
}
case (ast.item_const(?name, _, _, ?cid, _)) {
@ -2963,6 +3002,36 @@ fn collect_items(@crate_ctxt cx, @ast.crate crate) {
fold.fold_crate[@crate_ctxt](cx, fld, crate);
}
fn collect_tag_ctor(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
alt (i.node) {
case (ast.item_tag(_, ?variants, _, _)) {
for (ast.variant variant in variants) {
if (_vec.len[ast.variant_arg](variant.args) != 0u) {
decl_fn_and_pair(cx, "tag", variant.name,
variant.ann, variant.id);
}
}
}
case (_) { /* fall through */ }
}
ret cx;
}
fn collect_tag_ctors(@crate_ctxt cx, @ast.crate crate) {
let fold.ast_fold[@crate_ctxt] fld =
fold.new_identity_fold[@crate_ctxt]();
fld = @rec( update_env_for_item = bind collect_tag_ctor(_,_)
with *fld );
fold.fold_crate[@crate_ctxt](cx, fld, crate);
}
// The tag type resolution pass, which determines all the LLVM types that
// correspond to each tag type in the crate.
@ -3048,6 +3117,9 @@ fn trans_constant(&@crate_ctxt cx, @ast.item it) -> @crate_ctxt {
_str.buf("tag"));
llvm.LLVMSetInitializer(gvar, val);
llvm.LLVMSetGlobalConstant(gvar, True);
llvm.LLVMSetLinkage(gvar,
lib.llvm.LLVMPrivateLinkage
as llvm.Linkage);
cx.item_ids.insert(variant_info._0, gvar);
}
case (n_ary) {
@ -3281,6 +3353,8 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
item_ids = new_def_hash[ValueRef](),
items = new_def_hash[@ast.item](),
tags = new_def_hash[@tag_info](),
fn_pairs = new_def_hash[ValueRef](),
obj_methods = new_def_hash[()](),
tydescs = tydescs,
obj_fields = obj_fields,
glues = glues,
@ -3291,6 +3365,7 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
collect_items(cx, crate);
resolve_tag_types(cx, crate);
collect_tag_ctors(cx, crate);
trans_constants(cx, crate);
trans_mod(cx, crate.node.module);