rustc: Don't use recursive types for tags; remove tag_info; introduce GEP_tag()

This commit is contained in:
Patrick Walton 2011-03-04 15:08:33 -08:00
parent 596face274
commit 76ec67063e

View file

@ -60,8 +60,6 @@ type glue_fns = rec(ValueRef activate_glue,
ValueRef bzero_glue,
ValueRef vec_append_glue);
type tag_info = rec(type_handle th);
state type crate_ctxt = rec(session.session sess,
ModuleRef llmod,
target_data td,
@ -74,7 +72,8 @@ state type crate_ctxt = rec(session.session sess,
hashmap[ast.def_id, @ast.item] items,
hashmap[ast.def_id,
@ast.native_item] native_items,
hashmap[@ty.t, @tag_info] tags,
// TODO: hashmap[tup(tag_id,subtys), @tag_info]
hashmap[@ty.t, uint] tag_sizes,
hashmap[ast.def_id, ValueRef] discrims,
hashmap[ast.def_id, ValueRef] fn_pairs,
hashmap[ast.def_id, ValueRef] consts,
@ -395,16 +394,30 @@ fn T_opaque_closure_ptr(type_names tn) -> TypeRef {
ret t;
}
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
auto s = "*tag";
fn T_tag(type_names tn, uint size) -> TypeRef {
auto s = "tag_" + _uint.to_str(size, 10u);
if (tn.name_has_type(s)) {
ret tn.get_type(s);
}
auto t = T_ptr(T_struct(vec(T_int(), T_i8())));
auto t = T_struct(vec(T_int(), T_array(T_i8(), size)));
tn.associate(s, t);
ret t;
}
fn T_opaque_tag(type_names tn) -> TypeRef {
auto s = "tag";
if (tn.name_has_type(s)) {
ret tn.get_type(s);
}
auto t = T_struct(vec(T_int(), T_i8()));
tn.associate(s, t);
ret t;
}
fn T_opaque_tag_ptr(type_names tn) -> TypeRef {
ret T_ptr(T_opaque_tag(tn));
}
fn T_captured_tydescs(type_names tn, uint n) -> TypeRef {
ret T_struct(_vec.init_elt[TypeRef](T_ptr(T_tydesc(tn)), n));
}
@ -436,7 +449,7 @@ fn type_of(@crate_ctxt cx, @ty.t t) -> TypeRef {
fail;
}
ret type_of_inner(cx, t);
ret type_of_inner(cx, t, false);
}
fn type_of_explicit_args(@crate_ctxt cx,
@ -447,12 +460,14 @@ fn type_of_explicit_args(@crate_ctxt cx,
check (arg.mode == ast.alias);
atys += T_typaram_ptr(cx.tn);
} else {
let TypeRef t = type_of_inner(cx, arg.ty);
let TypeRef t;
alt (arg.mode) {
case (ast.alias) {
t = T_ptr(t);
t = T_ptr(type_of_inner(cx, arg.ty, true));
}
case (_) {
t = type_of_inner(cx, arg.ty, false);
}
case (_) { /* fall through */ }
}
atys += t;
}
@ -478,7 +493,7 @@ fn type_of_fn_full(@crate_ctxt cx,
if (ty.type_has_dynamic_size(output)) {
atys += T_typaram_ptr(cx.tn);
} else {
atys += T_ptr(type_of_inner(cx, output));
atys += T_ptr(type_of_inner(cx, output, false));
}
// Arg 1: Task pointer.
@ -545,10 +560,10 @@ fn type_of_native_fn(@crate_ctxt cx, ast.native_abi abi,
}
}
atys += type_of_explicit_args(cx, inputs);
ret T_fn(atys, type_of_inner(cx, output));
ret T_fn(atys, type_of_inner(cx, output, false));
}
fn type_of_inner(@crate_ctxt cx, @ty.t t) -> TypeRef {
fn type_of_inner(@crate_ctxt cx, @ty.t t, bool boxed) -> TypeRef {
let TypeRef llty = 0 as TypeRef;
alt (t.struct) {
@ -573,26 +588,31 @@ fn type_of_inner(@crate_ctxt cx, @ty.t t) -> TypeRef {
}
case (ty.ty_char) { llty = T_char(); }
case (ty.ty_str) { llty = T_ptr(T_str()); }
case (ty.ty_tag(?tag_id, _)) {
llty = llvm.LLVMResolveTypeHandle(cx.tags.get(t).th.llth);
case (ty.ty_tag(_, _)) {
if (boxed) {
llty = T_opaque_tag(cx.tn);
} else {
auto size = static_size_of_tag(cx, t);
llty = T_tag(cx.tn, size);
}
}
case (ty.ty_box(?t)) {
llty = T_ptr(T_box(type_of_inner(cx, t)));
llty = T_ptr(T_box(type_of_inner(cx, t, true)));
}
case (ty.ty_vec(?t)) {
llty = T_ptr(T_vec(type_of_inner(cx, t)));
llty = T_ptr(T_vec(type_of_inner(cx, t, true)));
}
case (ty.ty_tup(?elts)) {
let vec[TypeRef] tys = vec();
for (@ty.t elt in elts) {
tys += type_of_inner(cx, elt);
tys += type_of_inner(cx, elt, boxed);
}
llty = T_struct(tys);
}
case (ty.ty_rec(?fields)) {
let vec[TypeRef] tys = vec();
for (ty.field f in fields) {
tys += type_of_inner(cx, f.ty);
tys += type_of_inner(cx, f.ty, boxed);
}
llty = T_struct(tys);
}
@ -650,9 +670,11 @@ fn type_of_arg(@crate_ctxt cx, &ty.arg arg) -> TypeRef {
}
}
auto typ = type_of_inner(cx, arg.ty);
auto typ;
if (arg.mode == ast.alias) {
typ = T_ptr(typ);
typ = T_ptr(type_of_inner(cx, arg.ty, true));
} else {
typ = type_of_inner(cx, arg.ty, false);
}
ret typ;
}
@ -856,6 +878,11 @@ fn align_to(@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
ret cx.build.And(bumped, cx.build.Not(mask));
}
// Returns the real size of the given type for the current target.
fn llsize_of_real(@crate_ctxt cx, TypeRef t) -> uint {
ret llvm.LLVMStoreSizeOfType(cx.td.lltd, t);
}
fn llsize_of(TypeRef t) -> ValueRef {
ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}
@ -878,6 +905,49 @@ fn align_of(@block_ctxt cx, @ty.t t) -> result {
ret dynamic_align_of(cx, t);
}
// Computes the size of the data part of a non-dynamically-sized tag.
fn static_size_of_tag(@crate_ctxt cx, @ty.t t) -> uint {
if (ty.type_has_dynamic_size(t)) {
log "dynamically sized type passed to static_size_of_tag()";
fail;
}
if (cx.tag_sizes.contains_key(t)) {
ret cx.tag_sizes.get(t);
}
auto tid = tup(0, 0); // FIXME (#250): typestate botch
let vec[@ty.t] subtys = vec(); // FIXME (#250): typestate botch
alt (t.struct) {
case (ty.ty_tag(?tid_, ?subtys_)) {
tid = tid_;
subtys = subtys_;
}
case (_) {
log "non-tag passed to static_size_of_tag()";
fail;
}
}
// Compute max(variant sizes).
auto max_size = 0u;
auto variants = tag_variants(cx, tid);
for (ast.variant variant in variants) {
let vec[@ty.t] tys = variant_types(cx, variant);
auto tup_ty = ty.plain_ty(ty.ty_tup(tys));
// Here we possibly do a recursive call.
auto this_size = llsize_of_real(cx, type_of(cx, tup_ty));
if (max_size < this_size) {
max_size = this_size;
}
}
cx.tag_sizes.insert(t, max_size);
ret max_size;
}
fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> result {
fn align_elements(@block_ctxt cx, vec[@ty.t] elts) -> result {
//
@ -974,10 +1044,10 @@ fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> result {
}
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
// tuple-like structure (tup, rec, tag) with a static index. This one is
// driven off ty.struct and knows what to do when it runs into a ty_param
// stuck in the middle of the thing it's GEP'ing into. Much like size_of and
// align_of, above.
// tuple-like structure (tup, rec) with a static index. This one is driven off
// ty.struct and knows what to do when it runs into a ty_param stuck in the
// middle of the thing it's GEP'ing into. Much like size_of and align_of,
// above.
fn GEP_tup_like(@block_ctxt cx, @ty.t t,
ValueRef base, vec[int] ixs) -> result {
@ -1076,6 +1146,53 @@ fn GEP_tup_like(@block_ctxt cx, @ty.t t,
ret res(bcx, bcx.build.PointerCast(bumped, typ));
}
// Replacement for the LLVM 'GEP' instruction when field indexing into a tag.
// This function uses GEP_tup_like() above and automatically performs casts as
// appropriate. @llblobptr is the data part of a tag value; its actual type is
// meaningless, as it will be cast away.
fn GEP_tag(@block_ctxt cx, ValueRef llblobptr, &ast.variant variant, int ix)
-> result {
// Synthesize a tuple type so that GEP_tup_like() can work its magic.
// Separately, store the type of the element we're interested in.
auto arg_tys = arg_tys_of_fn(variant.ann);
auto elem_ty = ty.plain_ty(ty.ty_nil); // typestate infelicity
auto i = 0;
let vec[@ty.t] true_arg_tys = vec();
for (ty.arg a in arg_tys) {
true_arg_tys += vec(a.ty);
if (i == ix) {
elem_ty = a.ty;
}
i += 1;
}
auto tup_ty = ty.plain_ty(ty.ty_tup(true_arg_tys));
// Cast the blob pointer to the appropriate type, if we need to (i.e. if
// the blob pointer isn't dynamically sized).
let ValueRef llunionptr;
if (!ty.type_has_dynamic_size(tup_ty)) {
auto llty = type_of(cx.fcx.ccx, tup_ty);
llunionptr = cx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
} else {
llunionptr = llblobptr;
}
// Do the GEP_tup_like().
auto rslt = GEP_tup_like(cx, tup_ty, llunionptr, vec(0, ix));
// Cast the result to the appropriate type, if necessary.
auto val;
if (!ty.type_has_dynamic_size(elem_ty)) {
auto llelemty = type_of(rslt.bcx.fcx.ccx, elem_ty);
val = rslt.bcx.build.PointerCast(rslt.val, T_ptr(llelemty));
} else {
val = rslt.val;
}
ret res(rslt.bcx, val);
}
fn trans_raw_malloc(@block_ctxt cx, TypeRef llptr_ty, ValueRef llsize)
-> result {
@ -1527,6 +1644,7 @@ fn variant_types(@crate_ctxt cx, &ast.variant v) -> vec[@ty.t] {
tys += vec(arg.ty);
}
}
case (ty.ty_tag(_, _)) { /* nothing */ }
case (_) { fail; }
}
ret tys;
@ -1647,8 +1765,6 @@ fn iter_structural_ty_full(@block_ctxt cx,
}
}
case (ty.ty_tag(?tid, ?tps)) {
auto info = cx.fcx.ccx.tags.get(mk_plain_tag(tid));
auto variants = tag_variants(cx.fcx.ccx, tid);
auto n_variants = _vec.len[ast.variant](variants);
@ -4653,14 +4769,6 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
auto arg_tys = arg_tys_of_fn(variant.ann);
copy_args_to_allocas(bcx, none[TypeRef], fn_args, arg_tys);
// Now synthesize a tuple type for the arguments, so that GEP_tup_like()
// will know what the data part of the variant looks like.
let vec[@ty.t] true_arg_tys = vec();
for (ty.arg a in arg_tys) {
true_arg_tys += vec(a.ty);
}
auto tup_ty = ty.plain_ty(ty.ty_tup(true_arg_tys));
// Cast the tag to a type we can GEP into.
auto lltagptr = bcx.build.PointerCast(fcx.llretptr,
T_opaque_tag_ptr(fcx.ccx.tn));
@ -4672,23 +4780,19 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id,
auto llblobptr = bcx.build.GEP(lltagptr,
vec(C_int(0), C_int(1)));
// Cast the blob pointer to the appropriate type, if we need to (i.e. if
// the blob pointer isn't dynamically sized).
let ValueRef llunionptr;
if (!ty.type_has_dynamic_size(tup_ty)) {
auto llty = type_of(cx, tup_ty);
llunionptr = bcx.build.TruncOrBitCast(llblobptr, T_ptr(llty));
} else {
llunionptr = llblobptr;
}
i = 0u;
for (ast.variant_arg va in variant.args) {
auto llargval = bcx.build.Load(fcx.llargs.get(va.id));
auto rslt = GEP_tup_like(bcx, tup_ty, llunionptr, vec(0, i as int));
auto rslt = GEP_tag(bcx, llblobptr, variant, i as int);
bcx = rslt.bcx;
auto lldestptr = rslt.val;
// If this argument to this function is a tag, it'll have come in to
// this function as an opaque blob due to the way that type_of()
// works. So we have to cast to the destination's view of the type.
auto llargptr = bcx.build.PointerCast(fcx.llargs.get(va.id),
val_ty(lldestptr));
auto llargval = bcx.build.Load(llargptr);
bcx.build.Store(llargval, lldestptr);
i += 1u;
}
@ -4747,6 +4851,7 @@ fn trans_item(@crate_ctxt cx, &ast.item item) {
case (ast.item_tag(?name, ?variants, ?tps, ?tag_id)) {
auto sub_cx = @rec(path=cx.path + sep() + name with *cx);
auto i = 0;
log "translating variants for " + name;
for (ast.variant variant in variants) {
trans_tag_variant(sub_cx, tag_id, variant, i, tps);
i += 1;
@ -4885,12 +4990,6 @@ fn collect_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
}
case (ast.item_tag(_, ?variants, ?tps, ?tag_id)) {
auto vi = new_def_hash[uint]();
auto navi = new_def_hash[uint]();
auto info = @rec(th=mk_type_handle());
cx.tags.insert(mk_plain_tag(tag_id), info);
cx.items.insert(tag_id, i);
}
@ -4942,58 +5041,6 @@ fn collect_tag_ctors(@crate_ctxt cx, @ast.crate crate) {
}
// The tag type resolution pass, which determines all the LLVM types that
// correspond to each tag type in the crate.
fn resolve_tag_types_for_item(&@crate_ctxt cx, @ast.item i) -> @crate_ctxt {
alt (i.node) {
case (ast.item_tag(_, ?variants, _, ?tag_id)) {
// FIXME: This is all wrong. Now sizes and alignments are computed
// dynamically instead of up front.
auto max_align = 0u;
auto max_size = 0u;
auto info = cx.tags.get(mk_plain_tag(tag_id));
for (ast.variant variant in variants) {
if (_vec.len[ast.variant_arg](variant.args) > 0u) {
auto llvariantty = type_of_variant(cx, variant);
auto align =
llvm.LLVMPreferredAlignmentOfType(cx.td.lltd,
llvariantty);
auto size =
llvm.LLVMStoreSizeOfType(cx.td.lltd,
llvariantty) as uint;
if (max_align < align) { max_align = align; }
if (max_size < size) { max_size = size; }
}
}
// FIXME: alignment is wrong here, manually insert padding I
// guess :(
auto tag_ty = T_struct(vec(T_int(), T_array(T_i8(), max_size)));
auto th = info.th.llth;
llvm.LLVMRefineType(llvm.LLVMResolveTypeHandle(th), tag_ty);
}
case (_) {
// fall through
}
}
ret cx;
}
fn resolve_tag_types(@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 resolve_tag_types_for_item(_,_)
with *fld );
fold.fold_crate[@crate_ctxt](cx, fld, crate);
}
// The constant translation pass.
fn trans_constant(&@crate_ctxt cx, @ast.item it) -> @crate_ctxt {
@ -5461,7 +5508,7 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
auto glues = make_glues(llmod, tn);
auto hasher = ty.hash_ty;
auto eqer = ty.eq_ty;
auto tags = map.mk_hashmap[@ty.t,@tag_info](hasher, eqer);
auto tag_sizes = map.mk_hashmap[@ty.t,uint](hasher, eqer);
auto tydescs = map.mk_hashmap[@ty.t,ValueRef](hasher, eqer);
let vec[ast.ty_param] obj_typarams = vec();
let vec[ast.obj_field] obj_fields = vec();
@ -5477,7 +5524,7 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
item_ids = new_def_hash[ValueRef](),
items = new_def_hash[@ast.item](),
native_items = new_def_hash[@ast.native_item](),
tags = tags,
tag_sizes = tag_sizes,
discrims = new_def_hash[ValueRef](),
fn_pairs = new_def_hash[ValueRef](),
consts = new_def_hash[ValueRef](),
@ -5492,7 +5539,6 @@ fn trans_crate(session.session sess, @ast.crate crate, str output,
create_typedefs(cx);
collect_items(cx, crate);
resolve_tag_types(cx, crate);
collect_tag_ctors(cx, crate);
trans_constants(cx, crate);