From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19628 invoked by alias); 11 Mar 2011 04:24:23 -0000 Received: (qmail 19215 invoked by uid 22791); 11 Mar 2011 04:24:17 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL,BAYES_00,TW_TM,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 11 Mar 2011 04:24:08 +0000 Received: (qmail 1804 invoked from network); 11 Mar 2011 04:24:04 -0000 Received: from unknown (HELO codesourcery.com) (froydnj@127.0.0.2) by mail.codesourcery.com with ESMTPA; 11 Mar 2011 04:24:04 -0000 From: Nathan Froyd To: gcc-patches@gcc.gnu.org Cc: Nathan Froyd , jason@redhat.com Subject: [PATCH 14/18] move TS_STATEMENT_LIST to be a substructure of TS_TYPED Date: Fri, 11 Mar 2011 04:24:00 -0000 Message-Id: <1299817406-16745-15-git-send-email-froydnj@codesourcery.com> In-Reply-To: <1299817406-16745-1-git-send-email-froydnj@codesourcery.com> References: <1299817406-16745-1-git-send-email-froydnj@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-03/txt/msg00560.txt.bz2 STATEMENT_LISTs use TREE_CHAIN for approximately nothing, so let's try to shrink them. This patch involves quite a bit of refactoring in the C and C++ FEs, as they used TREE_CHAIN to hold a stack of STATEMENT_LISTs being built. Most of the noise comes from unifying the checking macro name between the C FE and the C++ FE. The new checks in add_stmt are required to make sure that cur_stmt_list can always point at something when calling append_to_statement_list_force. I would have liked to remove TREE_TYPE, too; I tried, but doing so was leading to lots of ugly hacks, so I postponed that for a different day. -Nathan gcc/ * c-decl.c (c_push_function_context): Copy the current statement list stack. (add_stmt): Check building_stmt_list_p and push_stmt if necessary. (finish_struct): Call building_stmt_list_p instead of checking cur_stmt_list. * c-parser.c (c_parser_postfix_expression): Likewise. * c-typeck.c (c_end_compound_stmt): Likewise. * print-tree.c (print_node) [STATEMENT_LIST]: Don't print TREE_CHAIN. * tree-iterator.c (stmt_list_cache): Change to a VEC. (alloc_stmt_list): Adjust for stmt_list_cache's new type. (free_stmt_list): Likewise. * tree.h (struct tree_statement_list): Include typed_tree instead of tree_common. * tree.c (initialize_tree_contains_struct): Mark TS_STATEMENT_LIST as TS_TYPED instead of TS_COMMON. gcc/c-family/ * c-common.h (struct stmt_tree_s) [x_cur_stmt_list]: Change to a VEC. (stmt_list_stack): Define. (cur_stmt_list): Adjust for new type of x_cur_stmt_list. * c-semantics.c (push_stmt_list, pop_stmt_list): Likewise. gcc/cp/ * cp-tree.h (building_stmt_tree): Delete. * decl.c (save_function_data): Tweak initializer for x_cur_stmt_list. (build_aggr_init_full_exprs): Call building_stmt_list_p instead of building_stmt_tree. (initialize_local_var): Likewise. (finish_function): Likewise. * decl2.c (finish_anon_union): Likewise. * init.c (begin_init_stmts): Likewise. (finish_init_stmts): Likewise. (expand_aggr_init_1): Likewise. * name-lookup.c (do_local_using_decl): Likewise. (do_namespace_alias): Likewise. (do_using_directive): Likewise. (cp_emit_debug_info_for_using): Likewise. * semantics.c (add_stmt): Check building_stmt_list_p and push_stmt if necessary. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 14aef5f..9b87608 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -556,6 +556,8 @@ add_stmt (tree t) /* Add T to the statement-tree. Non-side-effect statements need to be recorded during statement expressions. */ + if (!building_stmt_list_p ()) + push_stmt_list (); append_to_statement_list_force (t, &cur_stmt_list); return t; @@ -7213,7 +7215,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, /* If we're inside a function proper, i.e. not file-scope and not still parsing parameters, then arrange for the size of a variable sized type to be bound now. */ - if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE)) + if (building_stmt_list_p () && variably_modified_type_p (t, NULL_TREE)) add_stmt (build_stmt (loc, DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); @@ -8461,6 +8463,8 @@ c_push_function_context (void) cfun->language = p; p->base.x_stmt_tree = c_stmt_tree; + c_stmt_tree.x_cur_stmt_list + = VEC_copy (tree, gc, c_stmt_tree.x_cur_stmt_list); p->x_break_label = c_break_label; p->x_cont_label = c_cont_label; p->x_switch_stack = c_switch_stack; diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 382d535..e7fe209 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -451,8 +451,8 @@ typedef enum ref_operator { /* Information about a statement tree. */ struct GTY(()) stmt_tree_s { - /* The current statement list being collected. */ - tree x_cur_stmt_list; + /* A stack of statement lists being collected. */ + VEC(tree,gc) *x_cur_stmt_list; /* In C++, Nonzero if we should treat statements as full expressions. In particular, this variable is no-zero if at the @@ -482,11 +482,17 @@ struct GTY(()) c_language_function { struct stmt_tree_s x_stmt_tree; }; +#define stmt_list_stack (current_stmt_tree ()->x_cur_stmt_list) + /* When building a statement-tree, this is the current statement list - being collected. It's TREE_CHAIN is a back-pointer to the previous - statement list. */ + being collected. We define it in this convoluted way, rather than + using VEC_last, because it must be an lvalue. */ + +#define cur_stmt_list \ + (*(VEC_address (tree, stmt_list_stack) \ + + VEC_length (tree, stmt_list_stack) - 1)) -#define cur_stmt_list (current_stmt_tree ()->x_cur_stmt_list) +#define building_stmt_list_p() (!VEC_empty (tree, stmt_list_stack)) /* Language-specific hooks. */ diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c index a5bd9ba..cb0f2be 100644 --- a/gcc/c-family/c-semantics.c +++ b/gcc/c-family/c-semantics.c @@ -38,8 +38,7 @@ push_stmt_list (void) { tree t; t = alloc_stmt_list (); - TREE_CHAIN (t) = cur_stmt_list; - cur_stmt_list = t; + VEC_safe_push (tree, gc, stmt_list_stack, t); return t; } @@ -48,21 +47,23 @@ push_stmt_list (void) tree pop_stmt_list (tree t) { - tree u = cur_stmt_list, chain; + tree u = NULL_TREE; /* Pop statement lists until we reach the target level. The extra nestings will be due to outstanding cleanups. */ while (1) { - chain = TREE_CHAIN (u); - TREE_CHAIN (u) = NULL_TREE; - if (chain) - STATEMENT_LIST_HAS_LABEL (chain) |= STATEMENT_LIST_HAS_LABEL (u); + u = VEC_pop (tree, stmt_list_stack); + if (!VEC_empty (tree, stmt_list_stack)) + { + tree x = VEC_last (tree, stmt_list_stack); + STATEMENT_LIST_HAS_LABEL (x) |= STATEMENT_LIST_HAS_LABEL (u); + } if (t == u) break; - u = chain; } - cur_stmt_list = chain; + + gcc_assert (u != NULL_TREE); /* If the statement list is completely empty, just return it. This is just as good small as build_empty_stmt, with the advantage that diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 69ce2e5..7580441 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -6107,7 +6107,7 @@ c_parser_postfix_expression (c_parser *parser) c_parser_consume_token (parser); brace_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - if (cur_stmt_list == NULL) + if (!building_stmt_list_p ()) { error_at (loc, "braced-group within expression allowed " "only inside a function"); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index a22bb73..c42f118 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -9284,7 +9284,7 @@ c_end_compound_stmt (location_t loc, tree stmt, bool do_scope) do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular, STATEMENT_LISTs merge, and thus we can lose track of what statement was really last. */ - if (cur_stmt_list + if (building_stmt_list_p () && STATEMENT_LIST_STMT_EXPR (cur_stmt_list) && TREE_CODE (stmt) != BIND_EXPR) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7bdf9e0..fd28593 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -292,10 +292,6 @@ typedef struct ptrmem_cst * ptrmem_cst_t; #define same_type_p(TYPE1, TYPE2) \ comptypes ((TYPE1), (TYPE2), COMPARE_STRICT) -/* Nonzero if we are presently building a statement tree, rather - than expanding each statement as we encounter it. */ -#define building_stmt_tree() (cur_stmt_list != NULL_TREE) - /* Returns nonzero iff NODE is a declaration for the global function `main'. */ #define DECL_MAIN_P(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6ff6974..e1e6fe2 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5245,13 +5245,13 @@ build_aggr_init_full_exprs (tree decl, tree init, int flags) { int saved_stmts_are_full_exprs_p = 0; - if (building_stmt_tree ()) + if (building_stmt_list_p ()) { saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); current_stmt_tree ()->stmts_are_full_exprs_p = 1; } init = build_aggr_init (decl, init, flags, tf_warning_or_error); - if (building_stmt_tree ()) + if (building_stmt_list_p ()) current_stmt_tree ()->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p; return init; @@ -5633,7 +5633,7 @@ initialize_local_var (tree decl, tree init) if (cleanup && TREE_CODE (type) != ARRAY_TYPE) wrap_temporary_cleanups (init, cleanup); - gcc_assert (building_stmt_tree ()); + gcc_assert (building_stmt_list_p ()); saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); current_stmt_tree ()->stmts_are_full_exprs_p = 1; finish_expr_stmt (init); @@ -12609,7 +12609,7 @@ save_function_data (tree decl) DECL_SAVED_FUNCTION_DATA (decl) = f; /* Clear out the bits we don't need. */ - f->base.x_stmt_tree.x_cur_stmt_list = NULL_TREE; + f->base.x_stmt_tree.x_cur_stmt_list = NULL; f->bindings = NULL; f->x_local_names = NULL; } @@ -12854,7 +12854,7 @@ finish_function (int flags) This caused &foo to be of type ptr-to-const-function which then got a warning when stored in a ptr-to-function variable. */ - gcc_assert (building_stmt_tree ()); + gcc_assert (building_stmt_list_p ()); /* The current function is being defined, so its DECL_INITIAL should be set, and unless there's a multiple definition, it should be error_mark_node. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 93d44a4..fa114ba 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1415,7 +1415,7 @@ finish_anon_union (tree anon_union_decl) } pushdecl (anon_union_decl); - if (building_stmt_tree () + if (building_stmt_list_p () && at_function_scope_p ()) add_decl_expr (anon_union_decl); else if (!processing_template_decl) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index e590118..f2173a4 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -64,7 +64,7 @@ static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool); static bool begin_init_stmts (tree *stmt_expr_p, tree *compound_stmt_p) { - bool is_global = !building_stmt_tree (); + bool is_global = !building_stmt_list_p (); *stmt_expr_p = begin_stmt_expr (); *compound_stmt_p = begin_compound_stmt (BCS_NO_SCOPE); @@ -82,7 +82,7 @@ finish_init_stmts (bool is_global, tree stmt_expr, tree compound_stmt) stmt_expr = finish_stmt_expr (stmt_expr, true); - gcc_assert (!building_stmt_tree () == is_global); + gcc_assert (!building_stmt_list_p () == is_global); return stmt_expr; } @@ -1491,7 +1491,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, tree type = TREE_TYPE (exp); gcc_assert (init != error_mark_node && type != error_mark_node); - gcc_assert (building_stmt_tree ()); + gcc_assert (building_stmt_list_p ()); /* Use a function returning the desired type to initialize EXP for us. If the function is a constructor, and its first argument is diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index e2e5450..b5472de 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2392,7 +2392,7 @@ do_local_using_decl (tree decl, tree scope, tree name) if (decl == NULL_TREE) return; - if (building_stmt_tree () + if (building_stmt_list_p () && at_function_scope_p ()) add_decl_expr (decl); @@ -3439,7 +3439,7 @@ do_namespace_alias (tree alias, tree name_space) pushdecl (alias); /* Emit debug info for namespace alias. */ - if (!building_stmt_tree ()) + if (!building_stmt_list_p ()) (*debug_hooks->global_decl) (alias); } @@ -3581,7 +3581,7 @@ do_using_directive (tree name_space) gcc_assert (TREE_CODE (name_space) == NAMESPACE_DECL); - if (building_stmt_tree ()) + if (building_stmt_list_p ()) add_stmt (build_stmt (input_location, USING_STMT, name_space)); name_space = ORIGINAL_NAMESPACE (name_space); @@ -5647,7 +5647,7 @@ cp_emit_debug_info_for_using (tree t, tree context) for (t = OVL_CURRENT (t); t; t = OVL_NEXT (t)) if (TREE_CODE (t) != TEMPLATE_DECL) { - if (building_stmt_tree ()) + if (building_stmt_list_p ()) add_stmt (build_stmt (input_location, USING_STMT, t)); else (*debug_hooks->imported_module_or_decl) (t, NULL_TREE, context, false); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 689ad00..6c8dfd7 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -393,6 +393,8 @@ add_stmt (tree t) /* Add T to the statement-tree. Non-side-effect statements need to be recorded during statement expressions. */ + if (!building_stmt_list_p ()) + push_stmt_list (); append_to_statement_list_force (t, &cur_stmt_list); return t; diff --git a/gcc/print-tree.c b/gcc/print-tree.c index 3b5edeb..d8acd1b 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -911,7 +911,6 @@ print_node (FILE *file, const char *prefix, tree node, int indent) print_node (file, "stmt", tsi_stmt (i), indent + 4); } } - print_node (file, "chain", TREE_CHAIN (node), indent + 4); break; case BLOCK: diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c index 05764da..44b6bed 100644 --- a/gcc/tree-iterator.c +++ b/gcc/tree-iterator.c @@ -31,17 +31,16 @@ along with GCC; see the file COPYING3. If not see /* This is a cache of STATEMENT_LIST nodes. We create and destroy them fairly often during gimplification. */ -static GTY ((deletable (""))) tree stmt_list_cache; +static GTY ((deletable (""))) VEC(tree,gc) *stmt_list_cache; tree alloc_stmt_list (void) { - tree list = stmt_list_cache; - if (list) + tree list; + if (!VEC_empty (tree, stmt_list_cache)) { - stmt_list_cache = TREE_CHAIN (list); - gcc_assert (stmt_list_cache != list); - memset (list, 0, sizeof(struct tree_common)); + list = VEC_pop (tree, stmt_list_cache); + memset (list, 0, sizeof(struct tree_base)); TREE_SET_CODE (list, STATEMENT_LIST); } else @@ -55,11 +54,7 @@ free_stmt_list (tree t) { gcc_assert (!STATEMENT_LIST_HEAD (t)); gcc_assert (!STATEMENT_LIST_TAIL (t)); - /* If this triggers, it's a sign that the same list is being freed - twice. */ - gcc_assert (t != stmt_list_cache || stmt_list_cache == NULL); - TREE_CHAIN (t) = stmt_list_cache; - stmt_list_cache = t; + VEC_safe_push (tree, gc, stmt_list_cache, t); } /* A subroutine of append_to_statement_list{,_force}. T is not NULL. */ diff --git a/gcc/tree.c b/gcc/tree.c index 16100a6..81ee05e 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -379,6 +379,7 @@ initialize_tree_contains_struct (void) case TS_SSA_NAME: case TS_CONSTRUCTOR: case TS_EXP: + case TS_STATEMENT_LIST: MARK_TS_TYPED (code); break; @@ -389,7 +390,6 @@ initialize_tree_contains_struct (void) case TS_VEC: case TS_BLOCK: case TS_BINFO: - case TS_STATEMENT_LIST: case TS_OMP_CLAUSE: case TS_OPTIMIZATION: case TS_TARGET_OPTION: diff --git a/gcc/tree.h b/gcc/tree.h index 461674c..4e3eebd 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3514,7 +3514,7 @@ struct GTY ((chain_next ("%h.next"), chain_prev ("%h.prev"))) tree_statement_lis struct GTY(()) tree_statement_list { - struct tree_common common; + struct typed_tree typed; struct tree_statement_list_node *head; struct tree_statement_list_node *tail; };