about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-03-04 15:08:33 -0800
committerPatrick Walton <pcwalton@mimiga.net>2011-03-04 15:10:22 -0800
commit76ec67063e3b310aca4d4164577d167862d1bf73 (patch)
treebf81a9700015f8433f9b3de42b909f0bb370fe48 /src
parent596face2745ccc11a959a530807ea3e36e9d1354 (diff)
downloadrust-76ec67063e3b310aca4d4164577d167862d1bf73.tar.gz
rust-76ec67063e3b310aca4d4164577d167862d1bf73.zip
rustc: Don't use recursive types for tags; remove tag_info; introduce GEP_tag()
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/trans.rs262
1 files changed, 154 insertions, 108 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 2f45691adf2..66539ab2a1f 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -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_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_ptr(T_struct(vec(T_int(), T_i8())));
+    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);