Hi Mike, [I'm replying in this thread to the Objective-C patch you posted in the type-traits discussion, because both that post and this one are about reducing the number of tree codes]
On 3/13/07, Mike Stump <[EMAIL PROTECTED]> wrote:
I just converted the Objective-C front-end to free up enough tree codes so that Objective-C++ can compile again. I know it can be done. If you want a new tree code, you can convert some other tree code into a subcode. pick one one.
Thanks for doing this!
For ideas, please see the below patch. I glanced at the C++ front end, I see 8 tree codes (all the tcc_type codes) that you can reclaim using the technique below. For those that want to begin reviewing it, have at it, I'd be interested in, do we even want to go in this direction (we don't have hard numbers on the compile time costs yet, I don't think)? If so, any better way to do this in the short term?
Emboldened by your patch, I took a quick swing at introducing subcodes for the simplest tcc_type node in the C++ front end - TYPEOF_TYPE. The patch is attached. Here are some observations: - C++ already uses the LANG_TYPE tree code, although certainly not the way it was intended: UNKNOWN_TYPE is #define'd to LANG_TYPE. This is probably keeping Objective-C++ from working with your patch (I didn't try it). - C++ already uses TYPE_LANG_SPECIFIC, for class types and for pointers to member functions. Those are both based on RECORD_TYPE nodes (ugh). That's okay: it turns out that we can use TYPE_LANG_SPECIFIC for RECORD_TYPE nodes and LANG_TYPE nodes with no problems whatsoever. - If C++ uses LANG_TYPE, and Objective C uses LANG_TYPE, we're heading for a collision with Objective-C++. Either we'll need use different top-level codes (LANG_TYPE vs. OBJC_LANG_TYPE, for example), or we need to consolidate LANG_TYPE by making the subtype codes extensible by Objective-C++ (just like normal tree codes are). The latter seems like the right thing to do. - We're also heading toward collisions with lang_type_class, etc., but those are easy to fix. - It doesn't seem to happen in the Objective-C front end, but in the C++ front end we have a lot of large switches on the TREE_CODE of a type. With subcodes, these switches become very clunky. We go from something like this: switch (TREE_CODE (t)) { case TYPEOF_TYPE: /* Handle `typeof' */ break; default: /* Default case */ break; } to a two-level solution: switch (TREE_CODE (t)) { case LANG_TYPE: switch (LANG_TYPE_SUBCODE (t)) { case TYPEOF_TYPE_SUBCODE: /* Handle `typeof' */ break; default: /* Default case. */ break; } break; default: /* Default case */ break; } Notice how I had to duplicate the code in the default case? The situation gets worse when the TYPEOF_TYPE case was combined with other cases (more duplication) or there was a fall-through either into or out of the TYPEOF_TYPE case. The latter doesn't happen often with TYPEOF_TYPE, but it does with other C++ _TYPE nodes. While reviewing your Objective-C patch, the approach seemed very clean. The data structures were more explicit than they are today (I immediately started thinking, "hey, we could use this to shrink the size of the common bits for types!"), and the few comparisons against existing _TYPE nodes just because predicate checks. Unfortunately, it doesn't look like the approach transfers well to the C++ front end, where the two-level structure forced on us by subcodes becomes unwieldy pretty quickly. I fear that the code duplication in switch statements for default and fall-through cases is going to cause maintenance headaches for a long time to come. Still, please take a peek at the attached patch to decide for yourself... I may have missed something obvious. The patch itself doesn't actually save any nodes, because it introduces a real UNKNOWN_TYPE node while removing the TYPEOF_TYPE node. But, it makes TYPEOF_TYPE a subcode'd type, and the other tcc_type nodes (including UNKNOWN_TYPE) could then be subcode'd for an actual savings. Browse through the patch to see if the effort is well-spent. My conclusion from this is that, even if we don't store it in tree_base, we really, really want a TREE_CODE that is > 8 bits, or we want *gasp* separate codes for tcc_type vs. tcc_expression. If it doesn't work in a switch statement, it's not a viable solution for the C++ front end. Just FYI on your patch: +struct lang_type_header GTY(()) { + BOOL_BITFIELD subcode : 3; +}; That should be an ENUM_BITFIELD (subcode); Cheers, Doug
Index: cp-tree.def =================================================================== --- cp-tree.def (revision 122840) +++ cp-tree.def (working copy) @@ -166,7 +166,7 @@ DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "te /* The ordering of the following codes is optimized for the checking macros in tree.h. Changing the order will degrade the speed of the - compiler. TEMPLATE_TYPE_PARM, TYPENAME_TYPE, TYPEOF_TYPE, + compiler. TEMPLATE_TYPE_PARM, TYPENAME_TYPE, BOUND_TEMPLATE_TEMPLATE_PARM. */ /* Index into a template parameter list. This parameter must be a type. @@ -179,9 +179,9 @@ DEFTREECODE (TEMPLATE_ATE_TYPE_PARM, "templa TREE_TYPE is always NULL. */ DEFTREECODE (TYPENAME_TYPE, "typename_type", tcc_type, 0) -/* A type designated by `__typeof (expr)'. TYPEOF_TYPE_EXPR is the - expression in question. */ -DEFTREECODE (TYPEOF_TYPE, "typeof_type", tcc_type, 0) +/* An "unknown" type. Used when we cannot determine the type of an + entity, e.g., because it is overloaded. */ +DEFTREECODE (UNKNOWN_TYPE, "unknown_type", tcc_type, 0) /* Like TEMPLATE_TEMPLATE_PARM it is used with bound template arguments like TT<int>. Index: error.c =================================================================== --- error.c (revision 122840) +++ error.c (working copy) @@ -382,12 +382,20 @@ dump_type (tree t, int flags) dump_type (DECL_NAME (TYPE_NAME (t)), flags); break; - case TYPEOF_TYPE: - pp_cxx_identifier (cxx_pp, "__typeof__"); - pp_cxx_whitespace (cxx_pp); - pp_cxx_left_paren (cxx_pp); - dump_expr (TYPEOF_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS); - pp_cxx_right_paren (cxx_pp); + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) + { + case TYPEOF_TYPE_SUBCODE: + pp_cxx_identifier (cxx_pp, "__typeof__"); + pp_cxx_whitespace (cxx_pp); + pp_cxx_left_paren (cxx_pp); + dump_expr (TYPEOF_TYPE_EXPR (t), flags & ~TFF_EXPR_IN_PARENS); + pp_cxx_right_paren (cxx_pp); + break; + + default: + gcc_unreachable (); + } break; case TYPE_PACK_EXPANSION: @@ -589,11 +597,25 @@ dump_type_prefix (tree t, int flags) case TYPENAME_TYPE: case COMPLEX_TYPE: case VECTOR_TYPE: - case TYPEOF_TYPE: dump_type (t, flags); pp_base (cxx_pp)->padding = pp_before; break; + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) + { + case TYPEOF_TYPE_SUBCODE: + dump_type (t, flags); + pp_base (cxx_pp)->padding = pp_before; + break; + + default: + pp_unsupported_tree (cxx_pp, t); + pp_identifier (cxx_pp, "<typeprefixerror>"); + break; + } + break; + default: pp_unsupported_tree (cxx_pp, t); /* fall through. */ @@ -685,7 +707,18 @@ dump_type_suffix (tree t, int flags) case TYPENAME_TYPE: case COMPLEX_TYPE: case VECTOR_TYPE: - case TYPEOF_TYPE: + break; + + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) + { + case TYPEOF_TYPE_SUBCODE: + break; + + default: + pp_unsupported_tree (cxx_pp, t); + break; + } break; default: Index: tree.c =================================================================== --- tree.c (revision 122840) +++ tree.c (working copy) @@ -2232,7 +2232,6 @@ cp_walk_subtrees (tree *tp, int *walk_su case TEMPLATE_PARM_INDEX: case TEMPLATE_TYPE_PARM: case TYPENAME_TYPE: - case TYPEOF_TYPE: /* None of these have subtrees other than those already walked above. */ *walk_subtrees_p = 0; @@ -2300,6 +2299,19 @@ cp_walk_subtrees (tree *tp, int *walk_su *walk_subtrees_p = 0; break; + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (*tp)) + { + case TYPEOF_TYPE_SUBCODE: + *walk_subtrees_p = 0; + break; + + default: + input_location = save_locus; + return NULL_TREE; + } + break; + default: input_location = save_locus; return NULL_TREE; Index: cp-tree.h =================================================================== --- cp-tree.h (revision 122840) +++ cp-tree.h (working copy) @@ -921,10 +921,14 @@ enum languages { lang_c, lang_cplusplus, #define IS_AGGR_TYPE(T) \ (TREE_CODE (T) == TEMPLATE_TYPE_PARM \ || TREE_CODE (T) == TYPENAME_TYPE \ - || TREE_CODE (T) == TYPEOF_TYPE \ + || TYPEOF_TYPE_P (T) \ || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \ || TYPE_LANG_FLAG_5 (T)) +/* The subcode for LANG_TYPE nodes. */ +#define LANG_TYPE_SUBCODE(NODE) \ + (TYPE_LANG_SPECIFIC (LANG_TYPE_CHECK (NODE))->u.c.h.subcode) + /* Set IS_AGGR_TYPE for T to VAL. T must be a class, struct, or union type. */ #define SET_IS_AGGR_TYPE(T, VAL) \ @@ -1018,12 +1022,20 @@ typedef tree_pair_s *tree_pair_p; DEF_VEC_O (tree_pair_s); DEF_VEC_ALLOC_O (tree_pair_s,gc); +/* Enumeration containing all of the subcodes for C++ type nodes. */ +enum cp_lang_type_subcode +{ + CLASS_TYPE_SUBCODE, + PTRMEM_TYPE_SUBCODE, + TYPEOF_TYPE_SUBCODE +}; + /* This is a few header flags for 'struct lang_type'. Actually, all but the first are used only for lang_type_class; they are put in this structure to save space. */ struct lang_type_header GTY(()) { - BOOL_BITFIELD is_lang_type_class : 1; + ENUM_BITFIELD (cp_lang_type_subcode) subcode : 2; BOOL_BITFIELD has_type_conversion : 1; BOOL_BITFIELD has_init_ref : 1; @@ -1031,8 +1043,6 @@ struct lang_type_header GTY(()) BOOL_BITFIELD const_needs_init : 1; BOOL_BITFIELD ref_needs_init : 1; BOOL_BITFIELD has_const_assign_ref : 1; - - BOOL_BITFIELD spare : 1; }; /* This structure provides additional information above and beyond @@ -1128,34 +1138,56 @@ struct lang_type_ptrmem GTY(()) tree record; }; +/* Structure that stores information about the `typeof' type. */ +struct lang_type_typeof GTY(()) +{ + struct lang_type_header h; +}; + struct lang_type GTY(()) { union lang_type_u { struct lang_type_header GTY((skip (""))) h; - struct lang_type_class GTY((tag ("1"))) c; - struct lang_type_ptrmem GTY((tag ("0"))) ptrmem; - } GTY((desc ("%h.h.is_lang_type_class"))) u; + struct lang_type_class GTY((tag ("CLASS_TYPE_SUBCODE"))) c; + struct lang_type_ptrmem GTY((tag ("PTRMEM_TYPE_SUBCODE"))) ptrmem; + struct lang_type_typeof GTY((tag ("TYPEOF_TYPE_SUBCODE"))) type_of; + } GTY((desc ("%h.h.subcode"))) u; }; #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) #define LANG_TYPE_CLASS_CHECK(NODE) __extension__ \ ({ struct lang_type *lt = TYPE_LANG_SPECIFIC (NODE); \ - if (! lt->u.h.is_lang_type_class) \ + if (lt->u.h.subcode != CLASS_TYPE_SUBCODE) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ <->u.c; }) #define LANG_TYPE_PTRMEM_CHECK(NODE) __extension__ \ ({ struct lang_type *lt = TYPE_LANG_SPECIFIC (NODE); \ - if (lt->u.h.is_lang_type_class) \ + if (lt->u.h.subcode != PTRMEM_TYPE_SUBCODE) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ <->u.ptrmem; }) +#define LANG_TYPE_TYPEOF_CHECK(NODE) __extension__ \ +({ struct lang_type *lt = TYPE_LANG_SPECIFIC (NODE); \ + if (lt->u.h.subcode != TYPEOF_TYPE_SUBCODE) \ + lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ + <->u.type_of; }) + +#define TYPEOF_TYPE_CHECK(T) __extension__ \ +({ const tree __t = (T); \ + if (TREE_CODE (__t) != LANG_TYPE \ + || TYPE_LANG_SPECIFIC (T)->u.h.subcode != TYPEOF_TYPE_SUBCODE) \ + lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ + __t; }) + #else #define LANG_TYPE_CLASS_CHECK(NODE) (&TYPE_LANG_SPECIFIC (NODE)->u.c) #define LANG_TYPE_PTRMEM_CHECK(NODE) (&TYPE_LANG_SPECIFIC (NODE)->u.ptrmem) +#define LANG_TYPE_TYPEOF_CHECK(NODE) (&TYPE_LANG_SPECIFIC (NODE)->u.type_of) +#define TYPEOF_TYPE_CHECK(T) (T) #endif /* ENABLE_TREE_CHECKING */ @@ -2801,7 +2833,7 @@ more_aggr_init_expr_args_p (const aggr_i { \ TYPE_LANG_SPECIFIC (NODE) = GGC_CNEWVAR \ (struct lang_type, sizeof (struct lang_type_ptrmem)); \ - TYPE_LANG_SPECIFIC (NODE)->u.ptrmem.h.is_lang_type_class = 0; \ + TYPE_LANG_SPECIFIC (NODE)->u.h.subcode = PTRMEM_TYPE_SUBCODE; \ } \ TYPE_LANG_SPECIFIC (NODE)->u.ptrmem.record = (VALUE); \ } while (0) @@ -2831,7 +2863,12 @@ more_aggr_init_expr_args_p (const aggr_i `Y'. */ #define PTRMEM_CST_MEMBER(NODE) (((ptrmem_cst_t)PTRMEM_CST_CHECK (NODE))->member) -/* The expression in question for a TYPEOF_TYPE. */ +/* Whether NODE is a `typeof' type. */ +#define TYPEOF_TYPE_P(NODE) \ + (TREE_CODE (NODE) == LANG_TYPE \ + && LANG_TYPE_SUBCODE (NODE) == TYPEOF_TYPE_SUBCODE) + +/* The expression in question for a `typeof' type. */ #define TYPEOF_TYPE_EXPR(NODE) (TYPEOF_TYPE_CHECK (NODE))->type.values /* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was @@ -2863,8 +2900,6 @@ more_aggr_init_expr_args_p (const aggr_i #define ANON_UNION_TYPE_P(NODE) \ (TREE_CODE (NODE) == UNION_TYPE && ANON_AGGR_TYPE_P (NODE)) -#define UNKNOWN_TYPE LANG_TYPE - /* Define fields and accessors for nodes representing declared names. */ #define TYPE_WAS_ANONYMOUS(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->was_anonymous) @@ -4261,6 +4296,8 @@ extern tree copy_decl (tree); extern tree copy_type (tree); extern tree cxx_make_type (enum tree_code); extern tree make_aggr_type (enum tree_code); +extern void cp_set_type_subcode (tree, + enum cp_lang_type_subcode); extern void yyerror (const char *); extern void yyhook (int); extern bool cxx_init (void); Index: cxx-pretty-print.c =================================================================== --- cxx-pretty-print.c (revision 122840) +++ cxx-pretty-print.c (working copy) @@ -1574,7 +1574,6 @@ pp_cxx_type_id (cxx_pretty_printer *pp, case TEMPLATE_TYPE_PARM: case TEMPLATE_PARM_INDEX: case TEMPLATE_DECL: - case TYPEOF_TYPE: case TEMPLATE_ID_EXPR: pp_cxx_type_specifier_seq (pp, t); break; @@ -1584,6 +1583,18 @@ pp_cxx_type_id (cxx_pretty_printer *pp, pp_cxx_identifier (pp, "..."); break; + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) { + case TYPEOF_TYPE_SUBCODE: + pp_cxx_type_specifier_seq (pp, t); + break; + + default: + gcc_unreachable (); + break; + } + break; + default: pp_c_type_id (pp_c_base (pp), t); break; Index: pt.c =================================================================== --- pt.c (revision 122840) +++ pt.c (working copy) @@ -5616,10 +5616,18 @@ for_each_template_parm_r (tree *tp, int } break; - case TYPEOF_TYPE: - if (for_each_template_parm (TYPE_FIELDS (t), fn, data, - pfd->visited)) - return error_mark_node; + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) + { + case TYPEOF_TYPE_SUBCODE: + if (for_each_template_parm (TYPE_FIELDS (t), fn, data, + pfd->visited)) + return error_mark_node; + break; + + default: + break; + } break; case FUNCTION_DECL: @@ -8861,20 +8869,6 @@ tsubst (tree t, tree args, tsubst_flags_ e1, e2, QUALIFIED_NAME_IS_TEMPLATE (t)); } - case TYPEOF_TYPE: - { - tree type; - - type = finish_typeof (tsubst_expr - (TYPEOF_TYPE_EXPR (t), args, - complain, in_decl, - /*integral_constant_expression_p=*/false)); - return cp_build_qualified_type_real (type, - cp_type_quals (t) - | cp_type_quals (type), - complain); - } - case TYPE_ARGUMENT_PACK: case NONTYPE_ARGUMENT_PACK: { @@ -8895,6 +8889,28 @@ tsubst (tree t, tree args, tsubst_flags_ } break; + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) + { + case TYPEOF_TYPE_SUBCODE: + { + tree type; + + type = finish_typeof (tsubst_expr + (TYPEOF_TYPE_EXPR (t), args, + complain, in_decl, + /*integral_constant_expression_p=*/false)); + return cp_build_qualified_type_real (type, + cp_type_quals (t) + | cp_type_quals (type), + complain); + } + + default: + break; + } + /* Fall through. */ + default: sorry ("use of %qs in template", tree_code_name [(int) TREE_CODE (t)]); @@ -9437,7 +9453,6 @@ tsubst_copy (tree t, tree args, tsubst_f case ARRAY_TYPE: case TYPENAME_TYPE: case UNBOUND_CLASS_TEMPLATE: - case TYPEOF_TYPE: case TYPE_DECL: return tsubst (t, args, complain, in_decl); @@ -9477,6 +9492,17 @@ tsubst_copy (tree t, tree args, tsubst_f error ("use %<...%> to expand argument pack"); return error_mark_node; + case LANG_TYPE: + switch (LANG_TYPE_SUBCODE (t)) + { + case TYPEOF_TYPE_SUBCODE: + return tsubst (t, args, complain, in_decl); + + default: + break; + } + /* Fall through. */ + default: return t; } @@ -14627,7 +14653,7 @@ dependent_type_p_r (tree type) /* All TYPEOF_TYPEs are dependent; if the argument of the `typeof' expression is not type-dependent, then it should already been have resolved. */ - if (TREE_CODE (type) == TYPEOF_TYPE) + if (TYPEOF_TYPE_P (type)) return true; /* A template argument pack is dependent if any of its packed Index: semantics.c =================================================================== --- semantics.c (revision 122840) +++ semantics.c (working copy) @@ -2921,7 +2921,8 @@ finish_typeof (tree expr) if (type_dependent_expression_p (expr)) { - type = make_aggr_type (TYPEOF_TYPE); + type = make_node (LANG_TYPE); + cp_set_type_subcode (type, TYPEOF_TYPE_SUBCODE); TYPEOF_TYPE_EXPR (type) = expr; return type; Index: lex.c =================================================================== --- lex.c (revision 122840) +++ lex.c (working copy) @@ -763,10 +763,24 @@ copy_lang_type (tree node) if (! TYPE_LANG_SPECIFIC (node)) return; - if (TYPE_LANG_SPECIFIC (node)->u.h.is_lang_type_class) - size = sizeof (struct lang_type); - else - size = sizeof (struct lang_type_ptrmem); + switch (TYPE_LANG_SPECIFIC (node)->u.h.subcode) + { + case CLASS_TYPE_SUBCODE: + size = sizeof (struct lang_type_class); + break; + + case PTRMEM_TYPE_SUBCODE: + size = sizeof (struct lang_type_ptrmem); + break; + + case TYPEOF_TYPE_SUBCODE: + size = sizeof (struct lang_type_typeof); + break; + + default: + gcc_unreachable(); + } + lt = GGC_NEWVAR (struct lang_type, size); memcpy (lt, TYPE_LANG_SPECIFIC (node), size); TYPE_LANG_SPECIFIC (node) = lt; @@ -801,7 +815,7 @@ cxx_make_type (enum tree_code code) struct lang_type *pi = GGC_CNEW (struct lang_type); TYPE_LANG_SPECIFIC (t) = pi; - pi->u.c.h.is_lang_type_class = 1; + pi->u.c.h.subcode = CLASS_TYPE_SUBCODE; #ifdef GATHER_STATISTICS tree_node_counts[(int)lang_type] += 1; @@ -830,3 +844,31 @@ make_aggr_type (enum tree_code code) return t; } + +void +cp_set_type_subcode (tree t, enum cp_lang_type_subcode subcode) +{ + switch (subcode) + { + case CLASS_TYPE_SUBCODE: + TYPE_LANG_SPECIFIC (t) = + GGC_CNEWVAR (struct lang_type, sizeof (struct lang_type_class)); + break; + + case PTRMEM_TYPE_SUBCODE: + TYPE_LANG_SPECIFIC (t) = + GGC_CNEWVAR (struct lang_type, sizeof (struct lang_type_ptrmem)); + break; + + + case TYPEOF_TYPE_SUBCODE: + TYPE_LANG_SPECIFIC (t) = + GGC_CNEWVAR (struct lang_type, sizeof (struct lang_type_typeof)); + break; + + default: + gcc_unreachable (); + } + + LANG_TYPE_SUBCODE (t) = subcode; +}