From ec4598f68ed7760ea47d3cae70ec9fb1eb2c70c8 Mon Sep 17 00:00:00 2001 From: rakdver Date: Mon, 6 Oct 2003 00:55:02 +0000 Subject: [PATCH] * gimple-low.c (struct lower_data): New field encl_switch_body. (lower_case_label_expr): New. (lower_stmt_body, lower_stmt, lower_switch_expr): Handle switch_expr lowering. * tree-cfg.c (CASE_END, CASE_NEXT_RAW): Removed. (CASE_GOTO, CASE_NEXT, CASE_DESTINATION, CASE_CASE, CASE_EDGE): Work over tree_stmt_iterators. (CASE_START): New. (make_switch_expr_edges, tree_redirect_edge_and_branch, find_taken_edge_switch_expr, tree_cleanup_block_edges, remove_superfluous_labels): Use tree_stmt_iterator for switch cases. (build_new_label): Moved ... * gimplify.c (build_new_label): ...here. (build_and_jump): Use it. * tree-flatten.c (tree_flatten_statement): Assume SWITCH_EXPRs are lowered. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/tree-ssa-cfg-branch@72127 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog.tree-ssa-cfg | 19 +++++++ gcc/gimple-low.c | 121 +++++++++++++++++++++++++++++++++++++++++++-- gcc/gimplify.c | 19 ++++--- gcc/tree-cfg.c | 83 ++++++++++++++++--------------- gcc/tree-flatten.c | 78 +---------------------------- 5 files changed, 195 insertions(+), 125 deletions(-) diff --git a/gcc/ChangeLog.tree-ssa-cfg b/gcc/ChangeLog.tree-ssa-cfg index 1c74e9a140a..54818732564 100644 --- a/gcc/ChangeLog.tree-ssa-cfg +++ b/gcc/ChangeLog.tree-ssa-cfg @@ -1,5 +1,24 @@ 2003-10-05 Zdenek Dvorak + * gimple-low.c (struct lower_data): New field encl_switch_body. + (lower_case_label_expr): New. + (lower_stmt_body, lower_stmt, lower_switch_expr): Handle switch_expr + lowering. + * tree-cfg.c (CASE_END, CASE_NEXT_RAW): Removed. + (CASE_GOTO, CASE_NEXT, CASE_DESTINATION, CASE_CASE, CASE_EDGE): Work + over tree_stmt_iterators. + (CASE_START): New. + (make_switch_expr_edges, tree_redirect_edge_and_branch, + find_taken_edge_switch_expr, tree_cleanup_block_edges, + remove_superfluous_labels): Use tree_stmt_iterator for switch cases. + (build_new_label): Moved ... + * gimplify.c (build_new_label): ...here. + (build_and_jump): Use it. + * tree-flatten.c (tree_flatten_statement): Assume SWITCH_EXPRs are + lowered. + +2003-10-05 Zdenek Dvorak + * gimple-low.c (simple_goto_p): New. (lower_cond_expr): Lower COND_EXPR form. * tree-cfg.c (tree_cleanup_block_edges): Cleanup edges that are both diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 7e3a57264f9..b80647c9f18 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -43,6 +43,10 @@ struct lower_data { /* Block the current statement belongs to. */ tree block; + + /* The end of chain of CASE_LABEL_EXPRs in the innermost SWITCH_EXPR it + belongs to. */ + tree_stmt_iterator encl_switch_body; }; static void lower_stmt_body (tree *, struct lower_data *); @@ -50,6 +54,7 @@ static void lower_stmt (tree_stmt_iterator *, struct lower_data *); static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); static void lower_switch_expr (tree_stmt_iterator *, struct lower_data *); +static void lower_case_label_expr (tree_stmt_iterator *, struct lower_data *); static bool simple_goto_p (tree); /* Lowers the BODY. */ @@ -82,7 +87,7 @@ lower_stmt_body (tree *expr, struct lower_data *data) { tree_stmt_iterator tsi; - for (tsi = tsi_start (expr); !tsi_end_p (tsi); tsi_next (&tsi)) + for (tsi = tsi_start (expr); !tsi_end_p (tsi); ) lower_stmt (&tsi, data); } @@ -111,7 +116,6 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) case CALL_EXPR: case GOTO_EXPR: case LABEL_EXPR: - case CASE_LABEL_EXPR: case VA_ARG_EXPR: case RESX_EXPR: break; @@ -124,10 +128,18 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) lower_switch_expr (tsi, data); break; + case CASE_LABEL_EXPR: + lower_case_label_expr (tsi, data); + /* Avoid moving the tsi -- it is moved by delinking the statement + already. */ + return; + default: print_node_brief (stderr, "", tsi_stmt (*tsi), 0); abort (); } + + tsi_next (tsi); } /* Lowers a bind_expr TSI. DATA is passed through the recursion. */ @@ -243,5 +255,108 @@ lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) static void lower_switch_expr (tree_stmt_iterator *tsi, struct lower_data *data) { - lower_stmt_body (&SWITCH_BODY (tsi_stmt (*tsi)), data); + tree stmt = tsi_stmt (*tsi); + tree body = SWITCH_BODY (stmt); + tree case_label = NULL_TREE; + tree label_end; + tree_stmt_iterator encl_switch_body = data->encl_switch_body; + tree_stmt_iterator tsi_tmp; + + /* The body of the switch serves as a list to that CASE_LABEL_EXPRs + add new GOTO_EXPR entries. Add a default alternative to the list + (if there is some in the switch body, it will replace it). */ + SWITCH_BODY (stmt) = NULL_TREE; + data->encl_switch_body = tsi_start (&SWITCH_BODY (stmt)); + tsi_link_after (&data->encl_switch_body, + build1 (GOTO_EXPR, void_type_node, NULL_TREE), + TSI_NEW_STMT); + tsi_link_before (&data->encl_switch_body, + build (CASE_LABEL_EXPR, void_type_node, + NULL_TREE, NULL_TREE, NULL_TREE), + TSI_NEW_STMT); + + lower_stmt_body (&body, data); + + /* Now we have a chain of CASE_LABEL_EXPR + GOTOs in SWITCH_BODY, and + body contains the chain of statements we want to add after the + SWITCH_EXPR. If there was not a default alternative, add a corresponding + goto. */ + + tsi_tmp = data->encl_switch_body; + tsi_next (&tsi_tmp); + if (!GOTO_DESTINATION (tsi_stmt (tsi_tmp))) + { + label_end = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + *tsi_stmt_ptr (tsi_tmp) = build_and_jump (&LABEL_EXPR_LABEL (label_end)); + case_label = build_new_label (); + CASE_LABEL (tsi_stmt (data->encl_switch_body)) = case_label; + + /* Add the new entry to SWITCH_LABELS (is it really needed???) */ + if (SWITCH_LABELS (stmt)) + { + tree switch_labels = SWITCH_LABELS (stmt); + tree new_switch_labels = + make_tree_vec (TREE_VEC_LENGTH (switch_labels) + 1); + int i; + + for (i = 0; i < TREE_VEC_LENGTH (switch_labels); i++) + TREE_VEC_ELT (new_switch_labels, i) = + TREE_VEC_ELT (switch_labels, i); + TREE_VEC_ELT (new_switch_labels, i) = case_label; + SWITCH_LABELS (stmt) = new_switch_labels; + } + } + else + label_end = NULL_TREE; + + tsi_link_chain_after (tsi, body, TSI_CONTINUE_LINKING); + if (label_end) + tsi_link_after (tsi, label_end, TSI_CONTINUE_LINKING); + + data->encl_switch_body = encl_switch_body; +} + +/* Replace the CASE_LABEL_EXPR at TSI with an ordinary label, and place the + goto to this label to the enclosing SWITCH_EXPR body; this position is + taken from DATA passed through recursion. */ + +static void +lower_case_label_expr (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt = tsi_stmt (*tsi); + tree_stmt_iterator tsi_tmp, tsi_nxt; + tree goto_expr, label; + + tsi_nxt = *tsi; + tsi_next (&tsi_nxt); + if (!tsi_end_p (tsi_nxt) && simple_goto_p (tsi_stmt (tsi_nxt))) + { + /* Reuse the label. */ + label = GOTO_DESTINATION (tsi_stmt (tsi_nxt)); + goto_expr = build1 (GOTO_EXPR, void_type_node, label); + } + else + { + /* Create a new goto, and add the label. */ + label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + tsi_link_after (tsi, label, TSI_SAME_STMT); + goto_expr = build_and_jump (&LABEL_EXPR_LABEL (label)); + } + + if (CASE_LOW (stmt) == NULL_TREE) + { + /* Replace the prepared default entry. */ + tsi_tmp = data->encl_switch_body; + *tsi_stmt_ptr (tsi_tmp) = stmt; + tsi_next (&tsi_tmp); + *tsi_stmt_ptr (tsi_tmp) = goto_expr; + } + else + { + /* Add a new entry. */ + tsi_link_before (&data->encl_switch_body, stmt, TSI_SAME_STMT); + tsi_link_before (&data->encl_switch_body, goto_expr, TSI_SAME_STMT); + } + + tsi_delink (tsi); } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 52c1af655eb..9de7b0f2f92 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1085,6 +1085,18 @@ gimplify_exit_block_expr (tree *expr_p) *expr_p = build1 (GOTO_EXPR, void_type_node, label); } +/* Creates a new anonymous label. */ + +tree +build_new_label () +{ + tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (label) = current_function_decl; + DECL_ARTIFICIAL (label) = 1; + + return label; +} + /* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first if necessary. */ @@ -1096,12 +1108,7 @@ build_and_jump (tree *label_p) return build_empty_stmt (); if (*label_p == NULL_TREE) - { - tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); - DECL_ARTIFICIAL (label) = 1; - DECL_CONTEXT (label) = current_function_decl; - *label_p = label; - } + *label_p = build_new_label (); return build1 (GOTO_EXPR, void_type_node, *label_p); } diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 26dc0ce167a..d8d015b4492 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -164,6 +164,7 @@ static void remove_superfluous_labels (void); static void thread_jumps (void); static bool tree_forwarder_block_p (basic_block); static void merge_seq_blocks (void); +static tree CASE_GOTO (tree_stmt_iterator); /* Location to track pending stmt for edge insertion. */ #define PENDING_STMT(e) ((tree)(e->insns)) @@ -172,16 +173,18 @@ static void merge_seq_blocks (void); #define SET_PENDING_STMT(e, t) ((e->insns) = (rtx)t) /* Accessors for switch statement case list. */ -#define CASE_END(STMT) (TREE_CODE (TREE_OPERAND (STMT, 1)) == GOTO_EXPR) -#define CASE_NEXT_RAW(STMT) (TREE_OPERAND (TREE_OPERAND (STMT, 1), 1)) -#define CASE_NEXT(STMT) (CASE_END (STMT) ? NULL_TREE : CASE_NEXT_RAW (STMT)) -#define CASE_GOTO(STMT) \ - (CASE_END (STMT) \ - ? TREE_OPERAND (STMT, 1) \ - : TREE_OPERAND (TREE_OPERAND (STMT, 1), 0)) -#define CASE_DESTINATION(STMT) (GOTO_DESTINATION (CASE_GOTO (STMT))) -#define CASE_CASE(STMT) (TREE_OPERAND (STMT, 0)) -#define CASE_EDGE(STMT) (get_stmt_ann (CASE_CASE (STMT))->case_edge) +#define CASE_START(STMT) tsi_start (&SWITCH_BODY (STMT)) +#define CASE_NEXT(TSI) tsi_next (&TSI), tsi_next (&TSI) +#define CASE_END_P(TSI) tsi_end_p (TSI) +static tree +CASE_GOTO (tree_stmt_iterator tsi) +{ + tsi_next (&tsi); + return tsi_stmt (tsi); +} +#define CASE_DESTINATION(TSI) (GOTO_DESTINATION (CASE_GOTO (TSI))) +#define CASE_CASE(TSI) (tsi_stmt(TSI)) +#define CASE_EDGE(TSI) (get_stmt_ann (CASE_CASE (TSI))->case_edge) /* FIXME These need to be filled in with appropriate pointers. But this implies an ABI change in some functions. */ @@ -679,7 +682,8 @@ make_switch_expr_edges (basic_block bb) { tree entry = last_stmt (bb); basic_block label_bb; - tree label, stmt; + tree label; + tree_stmt_iterator case_entry; edge e; #if defined ENABLE_CHECKING @@ -687,16 +691,18 @@ make_switch_expr_edges (basic_block bb) abort (); #endif - for (stmt = SWITCH_BODY (entry); stmt; stmt = CASE_NEXT (stmt)) + for (case_entry = CASE_START (entry); + !CASE_END_P (case_entry); + CASE_NEXT (case_entry)) { - label = CASE_DESTINATION (stmt); + label = CASE_DESTINATION (case_entry); label_bb = VARRAY_BB (label_to_block_map, LABEL_DECL_INDEX (label)); e = make_edge (bb, label_bb, 0); if (!e) e = find_edge (bb, label_bb); if (!e) abort (); - CASE_EDGE (stmt) = e; + CASE_EDGE (case_entry) = e; } } @@ -708,6 +714,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest) tree stmt, gto; basic_block bb = e->src; edge old; + tree_stmt_iterator case_entry; if (e->dest == dest) return true; @@ -747,12 +754,14 @@ tree_redirect_edge_and_branch (edge e, basic_block dest) { /* This is more complicated, since there may be more gotos corresponding to this edge. */ - for (gto = SWITCH_BODY (stmt); gto; gto = CASE_NEXT (gto)) - if (CASE_EDGE (gto) == e) + for (case_entry = CASE_START (stmt); + !CASE_END_P (case_entry); + CASE_NEXT (case_entry)) + if (CASE_EDGE (case_entry) == e) { - CASE_DESTINATION (gto) = tree_block_label (dest); + CASE_DESTINATION (case_entry) = tree_block_label (dest); if (old) - CASE_EDGE (gto) = old; + CASE_EDGE (case_entry) = old; } goto redirect; @@ -1279,14 +1288,17 @@ static edge find_taken_edge_switch_expr (basic_block bb, tree val) { edge e, default_edge; - tree case_label, stmt; + tree case_label; + tree_stmt_iterator case_entry; /* See if the switch() value matches one of the case labels. */ default_edge = NULL; - for (stmt = SWITCH_BODY (last_stmt (bb)); stmt; stmt = CASE_NEXT (stmt)) + for (case_entry = CASE_START (last_stmt (bb)); + !CASE_END_P (case_entry); + CASE_NEXT (case_entry)) { - e = CASE_EDGE (stmt); - case_label = CASE_CASE (stmt); + e = CASE_EDGE (case_entry); + case_label = CASE_CASE (case_entry); if (value_matches_label (e, val, case_label, &default_edge)) return e; @@ -2823,7 +2835,8 @@ tree_cleanup_block_edges (basic_block bb, int no_false_fallthru) { edge e, e_true, e_false, next; block_stmt_iterator bsi; - tree stmt, alt; + tree stmt; + tree_stmt_iterator alt; if (bb == ENTRY_BLOCK_PTR) return; @@ -2925,7 +2938,7 @@ redo: if (!bb->succ) break; - alt = SWITCH_BODY (stmt); + alt = CASE_START (stmt); if (bb->succ->succ_next) { /* If there are more edges, but only one matches, we may proceed @@ -2933,10 +2946,10 @@ redo: e_true = find_taken_edge (bb, SWITCH_COND (stmt)); if (!e_true) break; - for (alt = SWITCH_BODY (stmt); alt; alt = CASE_NEXT (alt)) + for (; !CASE_END_P (alt); CASE_NEXT (alt)) if (CASE_EDGE (alt) == e_true) break; - if (!alt) + if (CASE_END_P (alt)) abort (); for (e = bb->succ; e; e = next) @@ -3131,7 +3144,8 @@ remove_superfluous_labels () basic_block bb; edge e; block_stmt_iterator bsi; - tree stmt, label, alt; + tree stmt, label; + tree_stmt_iterator alt; int preserve; FOR_EACH_BB (bb) @@ -3166,7 +3180,9 @@ remove_superfluous_labels () stmt = last_stmt (e->src); if (TREE_CODE (stmt) == SWITCH_EXPR) { - for (alt = SWITCH_BODY (stmt); alt; alt = CASE_NEXT (alt)) + for (alt = CASE_START (stmt); + !CASE_END_P (alt); + CASE_NEXT (alt)) if (CASE_EDGE (alt) == e) CASE_DESTINATION (alt) = label; } @@ -3331,17 +3347,6 @@ thread_jumps () } } -/* Creates a new anonymous label. */ -tree -build_new_label () -{ - tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); - DECL_CONTEXT (label) = current_function_decl; - DECL_ARTIFICIAL (label) = 1; - - return label; -} - /* Returns a GOTO_EXPR for edge E found in STMT. */ static tree find_edge_goto (tree stmt, edge e) diff --git a/gcc/tree-flatten.c b/gcc/tree-flatten.c index c80a3757ae8..4215f1a1274 100644 --- a/gcc/tree-flatten.c +++ b/gcc/tree-flatten.c @@ -121,84 +121,8 @@ tree_flatten_statement (tree stmt, tree_cell *after, tree enclosing_switch) case VA_ARG_EXPR: case RESX_EXPR: case COND_EXPR: - append (after, stmt, TCN_STATEMENT); - break; - case SWITCH_EXPR: - { - tree body = SWITCH_BODY (stmt); - tree case_label, last_case_label; - tree label_end, dflt, dflt_goto; - - SWITCH_BODY (stmt) = NULL_TREE; - append (after, stmt, TCN_STATEMENT); - - tree_flatten_statement (body, after, stmt); - - /* Now we have a chain of CASE_LABEL_EXPR + GOTOs in - SWITCH_BODY. If there is not a default alternative, - add one. */ - last_case_label = SWITCH_BODY (stmt); - if (!last_case_label - || CASE_LOW (TREE_CHAIN (last_case_label)) != NULL_TREE) - { - case_label = build_new_label (); - label_end = build_new_label (); - - append (after, build1 (LABEL_EXPR, void_type_node, label_end), - TCN_STATEMENT); - - dflt = build (CASE_LABEL_EXPR, void_type_node, - NULL_TREE, NULL_TREE, case_label); - dflt_goto = build1 (GOTO_EXPR, void_type_node, label_end); - TREE_CHAIN (dflt_goto) = dflt; - TREE_CHAIN (dflt) = last_case_label; - last_case_label = dflt_goto; - - if (SWITCH_LABELS (stmt)) - { - tree switch_labels = SWITCH_LABELS (stmt); - tree new_switch_labels = - make_tree_vec (TREE_VEC_LENGTH (switch_labels) + 1); - int i; - - for (i = 0; i < TREE_VEC_LENGTH (switch_labels); i++) - TREE_VEC_ELT (new_switch_labels, i) = - TREE_VEC_ELT (switch_labels, i); - TREE_VEC_ELT (new_switch_labels, i) = case_label; - SWITCH_LABELS (stmt) = new_switch_labels; - } - } - - for (case_label = TREE_CHAIN (last_case_label); - case_label; - case_label = TREE_CHAIN (case_label)) - last_case_label = build (COMPOUND_EXPR, void_type_node, - case_label, last_case_label); - SWITCH_BODY (stmt) = last_case_label; - } - break; - - case CASE_LABEL_EXPR: - { - tree case_label = build_new_label (); - tree goto_stmt = build1 (GOTO_EXPR, void_type_node, case_label); - tree *where, chain = SWITCH_BODY (enclosing_switch); - - append (after, build1 (LABEL_EXPR, void_type_node, case_label), - TCN_STATEMENT); - - /* Keep the default alternative first. */ - if (!chain - || CASE_LOW (stmt) == NULL_TREE - || CASE_LOW (TREE_CHAIN (chain)) != NULL_TREE) - where = &SWITCH_BODY (enclosing_switch); - else - where = &TREE_CHAIN (TREE_CHAIN (SWITCH_BODY (enclosing_switch))); - TREE_CHAIN (goto_stmt) = stmt; - TREE_CHAIN (stmt) = *where; - *where = goto_stmt; - } + append (after, stmt, TCN_STATEMENT); break; default: -- 2.11.4.GIT