From fb72be0a8990f530d20437bf9d11a31fcffc5a9d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 1 Jul 2011 12:36:49 +0200 Subject: [PATCH] Do not store a tag num for single-variant tags This is a preparation for tags-as-nominal-types. A tag that has only a single variant is now represented, at run-time, as simply a tuple of the variant's parameters, with the variant id left off. --- src/comp/middle/trans.rs | 265 +++++++++++++++++++++------------------ 1 file changed, 144 insertions(+), 121 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index f83ca389852..b1e87e0134b 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -809,14 +809,7 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { case (ty::ty_char) { llty = T_char(); } case (ty::ty_str) { llty = T_ptr(T_str()); } case (ty::ty_istr) { llty = T_ivec(T_i8()); } - case (ty::ty_tag(_, _)) { - if (ty::type_has_dynamic_size(cx.tcx, t)) { - llty = T_opaque_tag(cx.tn); - } else { - auto size = static_size_of_tag(cx, sp, t); - llty = T_tag(cx.tn, size); - } - } + case (ty::ty_tag(?did, _)) { llty = type_of_tag(cx, sp, did, t); } case (ty::ty_box(?mt)) { llty = T_ptr(T_box(type_of_inner(cx, sp, mt.ty))); } @@ -894,6 +887,22 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef { ret llty; } +fn type_of_tag(&@crate_ctxt cx, &span sp, &ast::def_id did, &ty::t t) + -> TypeRef { + auto degen = vec::len(ty::tag_variants(cx.tcx, did)) == 1u; + if (ty::type_has_dynamic_size(cx.tcx, t)) { + if (degen) { ret T_i8(); } + else { ret T_opaque_tag(cx.tn); } + } else { + auto size = static_size_of_tag(cx, sp, t); + if (!degen) { ret T_tag(cx.tn, size); } + // LLVM does not like 0-size arrays, apparently + if (size == 0u) { size = 1u; } + ret T_array(T_i8(), size); + } +} + + fn type_of_arg(@local_ctxt cx, &span sp, &ty::arg arg) -> TypeRef { alt (ty::struct(cx.ccx.tcx, arg.ty)) { case (ty::ty_param(_)) { @@ -1339,7 +1348,9 @@ fn dynamic_size_of(&@block_ctxt cx, ty::t t) -> result { bcx.build.Store(umax(bcx, this_size, old_max_size), max_size); } auto max_size_val = bcx.build.Load(max_size); - auto total_size = bcx.build.Add(max_size_val, llsize_of(T_int())); + auto total_size = if (vec::len(variants) != 1u) { + bcx.build.Add(max_size_val, llsize_of(T_int())) + } else { max_size_val }; ret rslt(bcx, total_size); } case (ty::ty_ivec(?mt)) { @@ -2535,6 +2546,7 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, r.bcx.build.Br(next_cx.llbb); ret rslt(next_cx, C_nil()); } + fn iter_ivec(@block_ctxt bcx, ValueRef av, ValueRef bv, ty::t unit_ty, &val_pair_and_ty_fn f) -> result { // FIXME: "unimplemented rebinding existing function" workaround @@ -2603,6 +2615,42 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, ret rslt(next_cx, C_nil()); } + + fn iter_variant(@block_ctxt cx, ValueRef a_tup, ValueRef b_tup, + &ty::variant_info variant, &vec[ty::t] tps, + &ast::def_id tid, &val_pair_and_ty_fn f) -> result { + if (vec::len[ty::t](variant.args) == 0u) { + ret rslt(cx, C_nil()); + } + auto fn_ty = variant.ctor_ty; + auto ccx = cx.fcx.lcx.ccx; + alt (ty::struct(ccx.tcx, fn_ty)) { + case (ty::ty_fn(_, ?args, _, _, _)) { + auto j = 0; + for (ty::arg a in args) { + auto rslt = GEP_tag(cx, a_tup, tid, + variant.id, tps, j); + auto llfldp_a = rslt.val; + cx = rslt.bcx; + rslt = GEP_tag(cx, b_tup, tid, + variant.id, tps, j); + auto llfldp_b = rslt.val; + cx = rslt.bcx; + auto ty_subst = + ty::substitute_type_params(ccx.tcx, tps, a.ty); + auto llfld_a = + load_if_immediate(cx, llfldp_a, ty_subst); + auto llfld_b = + load_if_immediate(cx, llfldp_b, ty_subst); + rslt = f(cx, llfld_a, llfld_b, ty_subst); + cx = rslt.bcx; + j += 1; + } + } + } + ret rslt(cx, C_nil()); + } + let result r = rslt(cx, C_nil()); alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) { case (ty::ty_tup(?args)) { @@ -2612,8 +2660,7 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, auto elt_a = r.val; r = GEP_tup_like(r.bcx, t, bv, [0, i]); auto elt_b = r.val; - r = - f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty), + r = f(r.bcx, load_if_immediate(r.bcx, elt_a, arg.ty), load_if_immediate(r.bcx, elt_b, arg.ty), arg.ty); i += 1; } @@ -2625,8 +2672,7 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, auto llfld_a = r.val; r = GEP_tup_like(r.bcx, t, bv, [0, i]); auto llfld_b = r.val; - r = - f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty), + r = f(r.bcx, load_if_immediate(r.bcx, llfld_a, fld.mt.ty), load_if_immediate(r.bcx, llfld_b, fld.mt.ty), fld.mt.ty); i += 1; @@ -2644,8 +2690,12 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, } case (ty::ty_tag(?tid, ?tps)) { auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid); - auto n_variants = vec::len[ty::variant_info](variants); + auto n_variants = vec::len(variants); + // Cast the tags to types we can GEP into. + if (n_variants == 1u) { + ret iter_variant(cx, av, bv, variants.(0), tps, tid, f); + } auto lltagty = T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn); auto av_tag = cx.build.PointerCast(av, lltagty); @@ -2656,9 +2706,9 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, auto lldiscrim_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(0)]); auto llunion_b_ptr = cx.build.GEP(bv_tag, [C_int(0), C_int(1)]); auto lldiscrim_b = cx.build.Load(lldiscrim_b_ptr); + // NB: we must hit the discriminant first so that structural // comparison know not to proceed when the discriminants differ. - auto bcx = cx; bcx = f(bcx, lldiscrim_a, lldiscrim_b, @@ -2675,47 +2725,10 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv, "tag-iter-variant-" + uint::to_str(i, 10u)); llvm::LLVMAddCase(llswitch, C_int(i as int), variant_cx.llbb); - if (vec::len[ty::t](variant.args) > 0u) { - // N-ary variant. - - auto fn_ty = variant.ctor_ty; - alt (ty::struct(bcx.fcx.lcx.ccx.tcx, fn_ty)) { - case (ty::ty_fn(_, ?args, _, _, _)) { - auto j = 0; - for (ty::arg a in args) { - auto rslt = - GEP_tag(variant_cx, llunion_a_ptr, tid, - variant.id, tps, j); - auto llfldp_a = rslt.val; - variant_cx = rslt.bcx; - rslt = - GEP_tag(variant_cx, llunion_b_ptr, tid, - variant.id, tps, j); - auto llfldp_b = rslt.val; - variant_cx = rslt.bcx; - auto tcx = cx.fcx.lcx.ccx.tcx; - auto ty_subst = - ty::substitute_type_params(tcx, tps, - a.ty); - auto llfld_a = - load_if_immediate(variant_cx, llfldp_a, - ty_subst); - auto llfld_b = - load_if_immediate(variant_cx, llfldp_b, - ty_subst); - rslt = - f(variant_cx, llfld_a, llfld_b, ty_subst); - variant_cx = rslt.bcx; - j += 1; - } - } - } - variant_cx.build.Br(next_cx.llbb); - } else { - // Nullary variant; nothing to do. - - variant_cx.build.Br(next_cx.llbb); - } + variant_cx = iter_variant + (variant_cx, llunion_a_ptr, llunion_b_ptr, variant, + tps, tid, f).bcx; + variant_cx.build.Br(next_cx.llbb); i += 1u; } ret rslt(next_cx, C_nil()); @@ -4614,34 +4627,43 @@ fn trans_pat_match(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, ret rslt(matched_cx, llval); } case (ast::pat_tag(?ident, ?subpats, ?id)) { - auto lltagptr = - cx.build.PointerCast(llval, - T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn)); - auto lldiscrimptr = cx.build.GEP(lltagptr, [C_int(0), C_int(0)]); - auto lldiscrim = cx.build.Load(lldiscrimptr); auto vdef = ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(id)); - auto variant_tag = 0; auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0); - auto i = 0; - for (ty::variant_info v in variants) { - auto this_variant_id = v.id; - if (vdef._1._0 == this_variant_id._0 && - vdef._1._1 == this_variant_id._1) { - variant_tag = i; - } - i += 1; - } auto matched_cx = new_sub_block_ctxt(cx, "matched_cx"); - auto lleq = - cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim, - C_int(variant_tag)); - cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb); + auto llblobptr = llval; + + if (vec::len(variants) == 1u) { + cx.build.Br(matched_cx.llbb); + } else { + auto lltagptr = + cx.build.PointerCast(llval, + T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn)); + auto lldiscrimptr = cx.build.GEP(lltagptr, + [C_int(0), C_int(0)]); + auto lldiscrim = cx.build.Load(lldiscrimptr); + auto variant_tag = 0; + auto i = 0; + for (ty::variant_info v in variants) { + auto this_variant_id = v.id; + if (vdef._1._0 == this_variant_id._0 && + vdef._1._1 == this_variant_id._1) { + variant_tag = i; + } + i += 1; + } + auto lleq = + cx.build.ICmp(lib::llvm::LLVMIntEQ, lldiscrim, + C_int(variant_tag)); + cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb); + if (vec::len(subpats) > 0u) { + llblobptr = + matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]); + } + } auto ty_params = ty::node_id_to_type_params (cx.fcx.lcx.ccx.tcx, id); - if (vec::len[@ast::pat](subpats) > 0u) { - auto llblobptr = - matched_cx.build.GEP(lltagptr, [C_int(0), C_int(1)]); + if (vec::len(subpats) > 0u) { auto i = 0; for (@ast::pat subpat in subpats) { auto rslt = @@ -4690,10 +4712,12 @@ fn trans_pat_binding(&@block_ctxt cx, &@ast::pat pat, ValueRef llval, auto vdef = ast::variant_def_ids(cx.fcx.lcx.ccx.tcx.def_map.get(id)); - auto lltagptr = - cx.build.PointerCast(llval, - T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn)); - auto llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]); + auto llblobptr = llval; + if (vec::len(ty::tag_variants(cx.fcx.lcx.ccx.tcx, vdef._0))!=1u) { + auto lltagptr = cx.build.PointerCast + (llval, T_opaque_tag_ptr(cx.fcx.lcx.ccx.tn)); + llblobptr = cx.build.GEP(lltagptr, [C_int(0), C_int(1)]); + } auto ty_param_substs = ty::node_id_to_type_params(cx.fcx.lcx.ccx.tcx, id); auto this_cx = cx; @@ -4828,6 +4852,7 @@ fn lookup_discriminant(&@local_ctxt lcx, &ast::def_id tid, &ast::def_id vid) } fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result { + auto ccx = cx.fcx.lcx.ccx; alt (cx.fcx.lcx.ccx.tcx.def_map.get(id)) { case (ast::def_arg(?did)) { alt (cx.fcx.llargs.find(did._1)) { @@ -4856,12 +4881,12 @@ fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result { ret lval_mem(cx, cx.fcx.llobjfields.get(did._1)); } case (ast::def_fn(?did, _)) { - auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did); + auto tyt = ty::lookup_item_type(ccx.tcx, did); ret lval_generic_fn(cx, tyt, did, id); } case (ast::def_variant(?tid, ?vid)) { - auto v_tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, vid); - alt (ty::struct(cx.fcx.lcx.ccx.tcx, v_tyt._1)) { + auto v_tyt = ty::lookup_item_type(ccx.tcx, vid); + alt (ty::struct(ccx.tcx, v_tyt._1)) { case (ty::ty_fn(_, _, _, _, _)) { // N-ary variant. @@ -4869,43 +4894,36 @@ fn trans_path(&@block_ctxt cx, &ast::path p, ast::node_id id) -> lval_result { } case (_) { // Nullary variant. - - auto tag_ty = node_id_type(cx.fcx.lcx.ccx, id); - auto lldiscrim_gv = - lookup_discriminant(cx.fcx.lcx, tid, vid); - auto lldiscrim = cx.build.Load(lldiscrim_gv); + auto tag_ty = node_id_type(ccx, id); auto alloc_result = alloc_ty(cx, tag_ty); auto lltagblob = alloc_result.val; - auto lltagty; - if (ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, tag_ty)) - { - lltagty = T_opaque_tag(cx.fcx.lcx.ccx.tn); - } else { - lltagty = type_of(cx.fcx.lcx.ccx, p.span, tag_ty); + auto lltagty = type_of_tag(ccx, p.span, tid, tag_ty); + auto bcx = alloc_result.bcx; + auto lltagptr = bcx.build.PointerCast + (lltagblob, T_ptr(lltagty)); + if (vec::len(ty::tag_variants(ccx.tcx, tid)) != 1u) { + auto lldiscrim_gv = + lookup_discriminant(bcx.fcx.lcx, tid, vid); + auto lldiscrim = bcx.build.Load(lldiscrim_gv); + auto lldiscrimptr = bcx.build.GEP + (lltagptr, [C_int(0), C_int(0)]); + bcx.build.Store(lldiscrim, lldiscrimptr); } - auto lltagptr = - alloc_result.bcx.build.PointerCast(lltagblob, - T_ptr(lltagty)); - auto lldiscrimptr = - alloc_result.bcx.build.GEP(lltagptr, - [C_int(0), C_int(0)]); - alloc_result.bcx.build.Store(lldiscrim, lldiscrimptr); - ret lval_val(alloc_result.bcx, lltagptr); + ret lval_val(bcx, lltagptr); } } } case (ast::def_const(?did)) { // TODO: externals - - assert (cx.fcx.lcx.ccx.consts.contains_key(did._1)); - ret lval_mem(cx, cx.fcx.lcx.ccx.consts.get(did._1)); + assert (ccx.consts.contains_key(did._1)); + ret lval_mem(cx, ccx.consts.get(did._1)); } case (ast::def_native_fn(?did)) { - auto tyt = ty::lookup_item_type(cx.fcx.lcx.ccx.tcx, did); + auto tyt = ty::lookup_item_type(ccx.tcx, did); ret lval_generic_fn(cx, tyt, did, id); } case (_) { - cx.fcx.lcx.ccx.sess.span_unimpl(cx.sp, "def variant in trans"); + ccx.sess.span_unimpl(cx.sp, "def variant in trans"); } } } @@ -5538,7 +5556,6 @@ fn trans_arg_expr(&@block_ctxt cx, &ty::arg arg, TypeRef lldestty0, // "undef" value, as such a value should never // be inspected. It's important for the value // to have type lldestty0 (the callee's expected type). - val = llvm::LLVMGetUndef(lldestty0); } else if (ty::type_contains_params(cx.fcx.lcx.ccx.tcx, arg.ty)) { auto lldestty = lldestty0; @@ -7920,7 +7937,7 @@ fn trans_res_ctor(@local_ctxt cx, &span sp, &ast::_fn dtor, fn trans_tag_variant(@local_ctxt cx, ast::node_id tag_id, - &ast::variant variant, int index, + &ast::variant variant, int index, bool is_degen, &vec[ast::ty_param] ty_params) { if (vec::len[ast::variant_arg](variant.node.args) == 0u) { ret; // nullary constructors are just constants @@ -7953,13 +7970,17 @@ fn trans_tag_variant(@local_ctxt cx, ast::node_id tag_id, copy_args_to_allocas(fcx, fn_args, arg_tys); auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; - // Cast the tag to a type we can GEP into. - auto lltagptr = - bcx.build.PointerCast(fcx.llretptr, T_opaque_tag_ptr(fcx.lcx.ccx.tn)); - auto lldiscrimptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(0)]); - bcx.build.Store(C_int(index), lldiscrimptr); - auto llblobptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]); + auto llblobptr = if (is_degen) { + fcx.llretptr + } else { + // Cast the tag to a type we can GEP into. + auto lltagptr = bcx.build.PointerCast + (fcx.llretptr, T_opaque_tag_ptr(fcx.lcx.ccx.tn)); + auto lldiscrimptr = bcx.build.GEP(lltagptr, [C_int(0), C_int(0)]); + bcx.build.Store(C_int(index), lldiscrimptr); + bcx.build.GEP(lltagptr, [C_int(0), C_int(1)]) + }; i = 0u; for (ast::variant_arg va in variant.node.args) { auto rslt = @@ -8040,9 +8061,10 @@ fn trans_item(@local_ctxt cx, &ast::item item) { } case (ast::item_tag(?variants, ?tps)) { auto sub_cx = extend_path(cx, item.ident); + auto degen = vec::len(variants) == 1u; auto i = 0; for (ast::variant variant in variants) { - trans_tag_variant(sub_cx, item.id, variant, i, tps); + trans_tag_variant(sub_cx, item.id, variant, i, degen, tps); i += 1; } } @@ -8427,13 +8449,14 @@ fn trans_constant(@crate_ctxt ccx, &@ast::item it, &vec[str] pt, auto n_variants = vec::len[ast::variant](variants); while (i < n_variants) { auto variant = variants.(i); - auto discrim_val = C_int(i as int); auto p = new_pt + [it.ident, variant.node.name, "discrim"]; auto s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); auto discrim_gvar = llvm::LLVMAddGlobal(ccx.llmod, T_int(), str::buf(s)); - llvm::LLVMSetInitializer(discrim_gvar, discrim_val); - llvm::LLVMSetGlobalConstant(discrim_gvar, True); + if (n_variants != 1u) { + llvm::LLVMSetInitializer(discrim_gvar, C_int(i as int)); + llvm::LLVMSetGlobalConstant(discrim_gvar, True); + } ccx.discrims.insert(variant.node.id, discrim_gvar); ccx.discrim_symbols.insert(variant.node.id, s); i += 1u;