diff options
author | Sandra Loosemore <sandra@codesourcery.com> | 2020-09-19 07:32:35 -0700 |
---|---|---|
committer | Sandra Loosemore <sandra@codesourcery.com> | 2020-09-19 13:54:16 -0700 |
commit | cba079f354a55363916759f6f186f92c5616b98a (patch) | |
tree | a797afe19b592943e8baf602824a39e261a94a5d /gcc/c-family | |
parent | f7d2d4be7650acceb9d39327e21ee04f640c152f (diff) | |
download | gcc-cba079f354a55363916759f6f186f92c5616b98a.zip gcc-cba079f354a55363916759f6f186f92c5616b98a.tar.gz gcc-cba079f354a55363916759f6f186f92c5616b98a.tar.bz2 |
Move loop and switch tree data structures from cp/ to c-family/.
This patch moves the definitions for DO_STMT, FOR_STMT, WHILE_STMT,
SWITCH_STMT, BREAK_STMT, and CONTINUE_STMT from the C++ front end to
c-family. This includes the genericizers, pretty-printers, and dump
support as well as the tree definitions and accessors. Some related
code for OMP_FOR and similar OMP constructs is also moved.
2020-08-12 Sandra Loosemore <sandra@codesourcery.com>
gcc/c-family/
* c-common.c (c_block_may_fallthrough): New, split from
cxx_block_may_fallthrough in the cp front end.
(c_common_init_ts): Move handling of loop and switch-related
statements here from the cp front end.
* c-common.def (FOR_STMT, WHILE_STMT, DO_STMT): Move here from
cp front end.
(BREAK_STMT, CONTINUE_STMT, SWITCH_STMT): Likewise.
* c-common.h (c_block_may_fallthru): Declare.
(bc_state_t): Move here from cp front end.
(save_bc_state, restore_bc_state): Declare.
(c_genericize_control_stmt): Declare.
(WHILE_COND, WHILE_BODY): Likewise.
(DO_COND, DO_BODY): Likewise.
(FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, FOR_SCOPE): Likewise.
(SWITCH_STMT_COND, SWITCH_STMT_BODY): Likewise.
(SWITCH_STMT_TYPE, SWITCH_STMT_SCOPE): Likewise.
(SWITCH_STMT_ALL_CASES_P, SWITCH_STMT_NO_BREAK_P): Likewise.
(LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): Likewise.
* c-dump.c (dump_stmt): Copy from cp front end.
(c_dump_tree): Move code to handle structured loop and switch
tree nodes here from cp front end.
* c-gimplify.c: Adjust includes.
(enum bc_t, bc_label, begin_bc_block, finish_bc_block): Move from
cp front end.
(save_bc_state, restore_bc_state): New functions using old code
from cp front end.
(get_bc_label, expr_loc_or_loc): Move from cp front end.
(genericize_c_loop): Move from cp front end.
(genericize_for_stmt, genericize_while_stmt): Likewise.
(genericize_do_stmt, genericize_switch_stmt): Likewise.
(genericize_continue_stmt, genericize_break_stmt): Likewise.
(genericize_omp_for_stmt): Likewise.
(c_genericize_control_stmt): New function using code split from
cp front end.
(c_genericize_control_r): New.
(c_genericize): Call walk_tree with c_genericize_control_r.
* c-pretty-print.c (c_pretty_printer::statement): Move code to handle
structured loop and switch tree nodes here from cp front end.
gcc/cp/
* cp-gimplify.c (enum bc_t, bc_label): Move to c-family.
(begin_bc_block, finish_bc_block, get_bc_label): Likewise.
(genericize_cp_loop): Likewise.
(genericize_for_stmt, genericize_while_stmt): Likewise.
(genericize_do_stmt, genericize_switch_stmt): Likewise.
(genericize_continue_stmt, genericize_break_stmt): Likewise.
(genericize_omp_for_stmt): Likewise.
(cp_genericize_r): Call c_genericize_control_stmt instead of
above functions directly.
(cp_genericize): Call save_bc_state and restore_bc_state instead
of manipulating bc_label directly.
* cp-objcp-common.c (cxx_block_may_fallthru): Defer to
c_block_may_fallthru instead of handling SWITCH_STMT here.
(cp_common_init_ts): Move handling of loop and switch-related
statements to c-family.
* cp-tree.def (FOR_STMT, WHILE_STMT, DO_STMT): Move to c-family.
(BREAK_STMT, CONTINUE_STMT, SWITCH_STMT): Likewise.
* cp-tree.h (LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): Likewise.
(WHILE_COND, WHILE_BODY): Likewise.
(DO_COND, DO_BODY): Likewise.
(FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, FOR_SCOPE): Likewise.
(SWITCH_STMT_COND, SWITCH_STMT_BODY): Likewise.
(SWITCH_STMT_TYPE, SWITCH_STMT_SCOPE): Likewise.
(SWITCH_STMT_ALL_CASES_P, SWITCH_STMT_NO_BREAK_P): Likewise.
* cxx-pretty-print.c (cxx_pretty_printer::statement): Move code
to handle structured loop and switch tree nodes to c-family.
* dump.c (cp_dump_tree): Likewise.
gcc/
* doc/generic.texi (Basic Statements): Document SWITCH_EXPR here,
not SWITCH_STMT.
(Statements for C and C++): Rename node to reflect what
the introduction already says about sharing between C and C++
front ends. Copy-edit and correct documentation for structured
loops and switch.
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/c-common.c | 24 | ||||
-rw-r--r-- | gcc/c-family/c-common.def | 24 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 53 | ||||
-rw-r--r-- | gcc/c-family/c-dump.c | 38 | ||||
-rw-r--r-- | gcc/c-family/c-gimplify.c | 408 | ||||
-rw-r--r-- | gcc/c-family/c-pretty-print.c | 92 |
6 files changed, 633 insertions, 6 deletions
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 873bea9..e16ca38 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5007,6 +5007,24 @@ c_switch_covers_all_cases_p (splay_tree cases, tree type) return true; } +/* Return true if stmt can fall through. Used by block_may_fallthru + default case. */ + +bool +c_block_may_fallthru (const_tree stmt) +{ + switch (TREE_CODE (stmt)) + { + case SWITCH_STMT: + return (!SWITCH_STMT_ALL_CASES_P (stmt) + || !SWITCH_STMT_NO_BREAK_P (stmt) + || block_may_fallthru (SWITCH_STMT_BODY (stmt))); + + default: + return true; + } +} + /* Finish an expression taking the address of LABEL (an IDENTIFIER_NODE). Returns an expression for the address. @@ -8126,6 +8144,12 @@ c_common_init_ts (void) MARK_TS_EXP (SIZEOF_EXPR); MARK_TS_EXP (C_MAYBE_CONST_EXPR); MARK_TS_EXP (EXCESS_PRECISION_EXPR); + MARK_TS_EXP (BREAK_STMT); + MARK_TS_EXP (CONTINUE_STMT); + MARK_TS_EXP (DO_STMT); + MARK_TS_EXP (FOR_STMT); + MARK_TS_EXP (SWITCH_STMT); + MARK_TS_EXP (WHILE_STMT); } /* Build a user-defined numeric literal out of an integer constant type VALUE diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def index 7ceb9a2..1954bfe 100644 --- a/gcc/c-family/c-common.def +++ b/gcc/c-family/c-common.def @@ -55,6 +55,30 @@ DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3) or for the purpose of -Wsizeof-pointer-memaccess warning. */ DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1) +/* Used to represent a `for' statement. The operands are + FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, and FOR_SCOPE, + respectively. */ +DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5) + +/* Used to represent a 'while' statement. The operands are WHILE_COND + and WHILE_BODY, respectively. */ +DEFTREECODE (WHILE_STMT, "while_stmt", tcc_statement, 2) + +/* Used to represent a 'do' statement. The operands are DO_COND and + DO_BODY, respectively. */ +DEFTREECODE (DO_STMT, "do_stmt", tcc_statement, 2) + +/* Used to represent a 'break' statement. */ +DEFTREECODE (BREAK_STMT, "break_stmt", tcc_statement, 0) + +/* Used to represent a 'continue' statement. */ +DEFTREECODE (CONTINUE_STMT, "continue_stmt", tcc_statement, 0) + +/* Used to represent a 'switch' statement. The operands are + SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE, and + SWITCH_STMT_SCOPE, respectively. */ +DEFTREECODE (SWITCH_STMT, "switch_stmt", tcc_statement, 4) + /* Local variables: mode:c diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 4fc64bc..6abfe4b 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1008,6 +1008,7 @@ extern int case_compare (splay_tree_key, splay_tree_key); extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree); extern bool c_switch_covers_all_cases_p (splay_tree, tree); +extern bool c_block_may_fallthru (const_tree); extern tree build_function_call (location_t, tree, tree); @@ -1115,7 +1116,15 @@ class substring_loc; extern const char *c_get_substring_location (const substring_loc &substr_loc, location_t *out_loc); -/* In c-gimplify.c */ +/* In c-gimplify.c. */ +typedef struct bc_state +{ + tree bc_label[2]; +} bc_state_t; +extern void save_bc_state (bc_state_t *); +extern void restore_bc_state (bc_state_t *); +extern tree c_genericize_control_stmt (tree *, int *, void *, + walk_tree_fn, walk_tree_lh); extern void c_genericize (tree); extern int c_gimplify_expr (tree *, gimple_seq *, gimple_seq *); extern tree c_build_bind_expr (location_t, tree, tree); @@ -1279,6 +1288,48 @@ extern tree build_userdef_literal (tree suffix_id, tree value, enum overflow_type overflow, tree num_string); + +/* WHILE_STMT accessors. These give access to the condition of the + while statement and the body of the while statement, respectively. */ +#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0) +#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1) + +/* DO_STMT accessors. These give access to the condition of the do + statement and the body of the do statement, respectively. */ +#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0) +#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1) + +/* FOR_STMT accessors. These give access to the init statement, + condition, update expression, and body of the for statement, + respectively. */ +#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0) +#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1) +#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2) +#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3) +#define FOR_SCOPE(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 4) + +#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) +#define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1) +#define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2) +#define SWITCH_STMT_SCOPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 3) +/* True if there are case labels for all possible values of switch cond, either + because there is a default: case label or because the case label ranges cover + all values. */ +#define SWITCH_STMT_ALL_CASES_P(NODE) \ + TREE_LANG_FLAG_0 (SWITCH_STMT_CHECK (NODE)) +/* True if the body of a switch stmt contains no BREAK_STMTs. */ +#define SWITCH_STMT_NO_BREAK_P(NODE) \ + TREE_LANG_FLAG_2 (SWITCH_STMT_CHECK (NODE)) + + +/* Nonzero if NODE is the target for genericization of 'break' stmts. */ +#define LABEL_DECL_BREAK(NODE) \ + DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE)) + +/* Nonzero if NODE is the target for genericization of 'continue' stmts. */ +#define LABEL_DECL_CONTINUE(NODE) \ + DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE)) + extern bool convert_vector_to_array_for_subscript (location_t, tree *, tree); /* Possibe cases of scalar_to_vector conversion. */ diff --git a/gcc/c-family/c-dump.c b/gcc/c-family/c-dump.c index ffc5808..d3caacc 100644 --- a/gcc/c-family/c-dump.c +++ b/gcc/c-family/c-dump.c @@ -26,6 +26,13 @@ along with GCC; see the file COPYING3. If not see /* Dump any C-specific tree codes and attributes of common codes. */ +static void +dump_stmt (dump_info_p di, const_tree t) +{ + if (EXPR_HAS_LOCATION (t)) + dump_int (di, "line", EXPR_LINENO (t)); +} + bool c_dump_tree (void *dump_info, tree t) { @@ -42,6 +49,37 @@ c_dump_tree (void *dump_info, tree t) dump_string (di, "bitfield"); break; + case BREAK_STMT: + case CONTINUE_STMT: + dump_stmt (di, t); + break; + + case DO_STMT: + dump_stmt (di, t); + dump_child ("body", DO_BODY (t)); + dump_child ("cond", DO_COND (t)); + break; + + case FOR_STMT: + dump_stmt (di, t); + dump_child ("init", FOR_INIT_STMT (t)); + dump_child ("cond", FOR_COND (t)); + dump_child ("expr", FOR_EXPR (t)); + dump_child ("body", FOR_BODY (t)); + break; + + case SWITCH_STMT: + dump_stmt (di, t); + dump_child ("cond", SWITCH_STMT_COND (t)); + dump_child ("body", SWITCH_STMT_BODY (t)); + break; + + case WHILE_STMT: + dump_stmt (di, t); + dump_child ("cond", WHILE_COND (t)); + dump_child ("body", WHILE_BODY (t)); + break; + default: break; } diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c index 5d357d0..db930fc 100644 --- a/gcc/c-family/c-gimplify.c +++ b/gcc/c-family/c-gimplify.c @@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see #include "function.h" #include "basic-block.h" #include "tree.h" +#include "tree-iterator.h" +#include "predict.h" #include "gimple.h" #include "cgraph.h" #include "c-pretty-print.h" @@ -107,6 +109,399 @@ ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data) /* Gimplification of statement trees. */ +/* Local declarations. */ + +enum bc_t { bc_break = 0, bc_continue = 1 }; + +/* Stack of labels which are targets for "break" or "continue", + linked through TREE_CHAIN. */ +static tree bc_label[2]; + +/* Begin a scope which can be exited by a break or continue statement. BC + indicates which. + + Just creates a label with location LOCATION and pushes it into the current + context. */ + +static tree +begin_bc_block (enum bc_t bc, location_t location) +{ + tree label = create_artificial_label (location); + DECL_CHAIN (label) = bc_label[bc]; + bc_label[bc] = label; + if (bc == bc_break) + LABEL_DECL_BREAK (label) = true; + else + LABEL_DECL_CONTINUE (label) = true; + return label; +} + +/* Finish a scope which can be exited by a break or continue statement. + LABEL was returned from the most recent call to begin_bc_block. BLOCK is + an expression for the contents of the scope. + + If we saw a break (or continue) in the scope, append a LABEL_EXPR to + BLOCK. Otherwise, just forget the label. */ + +static void +finish_bc_block (tree *block, enum bc_t bc, tree label) +{ + gcc_assert (label == bc_label[bc]); + + if (TREE_USED (label)) + append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label), + block); + + bc_label[bc] = DECL_CHAIN (label); + DECL_CHAIN (label) = NULL_TREE; +} + +/* Allow saving and restoring break/continue state. */ + +void +save_bc_state (bc_state_t *state) +{ + state->bc_label[bc_break] = bc_label[bc_break]; + state->bc_label[bc_continue] = bc_label[bc_continue]; + bc_label[bc_break] = NULL_TREE; + bc_label[bc_continue] = NULL_TREE; +} + +void +restore_bc_state (bc_state_t *state) +{ + gcc_assert (bc_label[bc_break] == NULL); + gcc_assert (bc_label[bc_continue] == NULL); + bc_label[bc_break] = state->bc_label[bc_break]; + bc_label[bc_continue] = state->bc_label[bc_continue]; +} + +/* Get the LABEL_EXPR to represent a break or continue statement + in the current block scope. BC indicates which. */ + +static tree +get_bc_label (enum bc_t bc) +{ + tree label = bc_label[bc]; + gcc_assert (label); + + /* Mark the label used for finish_bc_block. */ + TREE_USED (label) = 1; + return label; +} + +/* Return the location from EXPR, or OR_LOC if the former is unknown. */ + +location_t +expr_loc_or_loc (const_tree expr, location_t or_loc) +{ + tree t = CONST_CAST_TREE (expr); + location_t loc = UNKNOWN_LOCATION; + if (t) + loc = EXPR_LOCATION (t); + if (loc == UNKNOWN_LOCATION) + loc = or_loc; + return loc; +} + +/* Build a generic representation of one of the C loop forms. COND is the + loop condition or NULL_TREE. BODY is the (possibly compound) statement + controlled by the loop. INCR is the increment expression of a for-loop, + or NULL_TREE. COND_IS_FIRST indicates whether the condition is + evaluated before the loop body as in while and for loops, or after the + loop body as in do-while loops. */ + +static void +genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, + tree incr, bool cond_is_first, int *walk_subtrees, + void *data, walk_tree_fn func, walk_tree_lh lh) +{ + tree blab, clab; + tree exit = NULL; + tree stmt_list = NULL; + tree debug_begin = NULL; + + protected_set_expr_location_if_unset (incr, start_locus); + + walk_tree_1 (&cond, func, data, NULL, lh); + walk_tree_1 (&incr, func, data, NULL, lh); + + blab = begin_bc_block (bc_break, start_locus); + clab = begin_bc_block (bc_continue, start_locus); + + walk_tree_1 (&body, func, data, NULL, lh); + *walk_subtrees = 0; + + if (MAY_HAVE_DEBUG_MARKER_STMTS + && (!cond || !integer_zerop (cond))) + { + debug_begin = build0 (DEBUG_BEGIN_STMT, void_type_node); + SET_EXPR_LOCATION (debug_begin, expr_loc_or_loc (cond, start_locus)); + } + + if (cond && TREE_CODE (cond) != INTEGER_CST) + { + /* If COND is constant, don't bother building an exit. If it's false, + we won't build a loop. If it's true, any exits are in the body. */ + location_t cloc = expr_loc_or_loc (cond, start_locus); + exit = build1_loc (cloc, GOTO_EXPR, void_type_node, + get_bc_label (bc_break)); + exit = fold_build3_loc (cloc, COND_EXPR, void_type_node, cond, + build_empty_stmt (cloc), exit); + } + + if (exit && cond_is_first) + { + append_to_statement_list (debug_begin, &stmt_list); + debug_begin = NULL_TREE; + append_to_statement_list (exit, &stmt_list); + } + append_to_statement_list (body, &stmt_list); + finish_bc_block (&stmt_list, bc_continue, clab); + if (incr) + { + if (MAY_HAVE_DEBUG_MARKER_STMTS) + { + tree d = build0 (DEBUG_BEGIN_STMT, void_type_node); + SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus)); + append_to_statement_list (d, &stmt_list); + } + append_to_statement_list (incr, &stmt_list); + } + append_to_statement_list (debug_begin, &stmt_list); + if (exit && !cond_is_first) + append_to_statement_list (exit, &stmt_list); + + if (!stmt_list) + stmt_list = build_empty_stmt (start_locus); + + tree loop; + if (cond && integer_zerop (cond)) + { + if (cond_is_first) + loop = fold_build3_loc (start_locus, COND_EXPR, + void_type_node, cond, stmt_list, + build_empty_stmt (start_locus)); + else + loop = stmt_list; + } + else + { + location_t loc = start_locus; + if (!cond || integer_nonzerop (cond)) + loc = EXPR_LOCATION (expr_first (body)); + if (loc == UNKNOWN_LOCATION) + loc = start_locus; + loop = build1_loc (loc, LOOP_EXPR, void_type_node, stmt_list); + } + + stmt_list = NULL; + append_to_statement_list (loop, &stmt_list); + finish_bc_block (&stmt_list, bc_break, blab); + if (!stmt_list) + stmt_list = build_empty_stmt (start_locus); + + *stmt_p = stmt_list; +} + +/* Genericize a FOR_STMT node *STMT_P. */ + +static void +genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data, + walk_tree_fn func, walk_tree_lh lh) +{ + tree stmt = *stmt_p; + tree expr = NULL; + tree loop; + tree init = FOR_INIT_STMT (stmt); + + if (init) + { + walk_tree_1 (&init, func, data, NULL, lh); + append_to_statement_list (init, &expr); + } + + genericize_c_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt), + FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, + data, func, lh); + append_to_statement_list (loop, &expr); + if (expr == NULL_TREE) + expr = loop; + *stmt_p = expr; +} + +/* Genericize a WHILE_STMT node *STMT_P. */ + +static void +genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data, + walk_tree_fn func, walk_tree_lh lh) +{ + tree stmt = *stmt_p; + genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt), + WHILE_BODY (stmt), NULL_TREE, 1, walk_subtrees, + data, func, lh); +} + +/* Genericize a DO_STMT node *STMT_P. */ + +static void +genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data, + walk_tree_fn func, walk_tree_lh lh) +{ + tree stmt = *stmt_p; + genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt), + DO_BODY (stmt), NULL_TREE, 0, walk_subtrees, + data, func, lh); +} + +/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */ + +static void +genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data, + walk_tree_fn func, walk_tree_lh lh) +{ + tree stmt = *stmt_p; + tree break_block, body, cond, type; + location_t stmt_locus = EXPR_LOCATION (stmt); + + body = SWITCH_STMT_BODY (stmt); + if (!body) + body = build_empty_stmt (stmt_locus); + cond = SWITCH_STMT_COND (stmt); + type = SWITCH_STMT_TYPE (stmt); + + walk_tree_1 (&cond, func, data, NULL, lh); + + break_block = begin_bc_block (bc_break, stmt_locus); + + walk_tree_1 (&body, func, data, NULL, lh); + walk_tree_1 (&type, func, data, NULL, lh); + *walk_subtrees = 0; + + if (TREE_USED (break_block)) + SWITCH_BREAK_LABEL_P (break_block) = 1; + finish_bc_block (&body, bc_break, break_block); + *stmt_p = build2_loc (stmt_locus, SWITCH_EXPR, type, cond, body); + SWITCH_ALL_CASES_P (*stmt_p) = SWITCH_STMT_ALL_CASES_P (stmt); + gcc_checking_assert (!SWITCH_STMT_NO_BREAK_P (stmt) + || !TREE_USED (break_block)); +} + +/* Genericize a CONTINUE_STMT node *STMT_P. */ + +static void +genericize_continue_stmt (tree *stmt_p) +{ + tree stmt_list = NULL; + tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN); + tree label = get_bc_label (bc_continue); + location_t location = EXPR_LOCATION (*stmt_p); + tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label); + append_to_statement_list_force (pred, &stmt_list); + append_to_statement_list (jump, &stmt_list); + *stmt_p = stmt_list; +} + +/* Genericize a BREAK_STMT node *STMT_P. */ + +static void +genericize_break_stmt (tree *stmt_p) +{ + tree label = get_bc_label (bc_break); + location_t location = EXPR_LOCATION (*stmt_p); + *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label); +} + +/* Genericize a OMP_FOR node *STMT_P. */ + +static void +genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data, + walk_tree_fn func, walk_tree_lh lh) +{ + tree stmt = *stmt_p; + location_t locus = EXPR_LOCATION (stmt); + tree clab = begin_bc_block (bc_continue, locus); + + walk_tree_1 (&OMP_FOR_BODY (stmt), func, data, NULL, lh); + if (TREE_CODE (stmt) != OMP_TASKLOOP) + walk_tree_1 (&OMP_FOR_CLAUSES (stmt), func, data, NULL, lh); + walk_tree_1 (&OMP_FOR_INIT (stmt), func, data, NULL, lh); + walk_tree_1 (&OMP_FOR_COND (stmt), func, data, NULL, lh); + walk_tree_1 (&OMP_FOR_INCR (stmt), func, data, NULL, lh); + walk_tree_1 (&OMP_FOR_PRE_BODY (stmt), func, data, NULL, lh); + *walk_subtrees = 0; + + finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab); +} + + +/* Lower structured control flow tree nodes, such as loops. The + STMT_P, WALK_SUBTREES, and DATA arguments are as for the walk_tree_fn + type. FUNC and LH are language-specific functions passed to walk_tree_1 + for node visiting and traversal, respectively; they are used to do + subtree processing in a language-dependent way. */ + +tree +c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data, + walk_tree_fn func, walk_tree_lh lh) +{ + tree stmt = *stmt_p; + + switch (TREE_CODE (stmt)) + { + case FOR_STMT: + genericize_for_stmt (stmt_p, walk_subtrees, data, func, lh); + break; + + case WHILE_STMT: + genericize_while_stmt (stmt_p, walk_subtrees, data, func, lh); + break; + + case DO_STMT: + genericize_do_stmt (stmt_p, walk_subtrees, data, func, lh); + break; + + case SWITCH_STMT: + genericize_switch_stmt (stmt_p, walk_subtrees, data, func, lh); + break; + + case CONTINUE_STMT: + genericize_continue_stmt (stmt_p); + break; + + case BREAK_STMT: + genericize_break_stmt (stmt_p); + break; + + case OMP_FOR: + case OMP_SIMD: + case OMP_DISTRIBUTE: + case OMP_LOOP: + case OMP_TASKLOOP: + case OACC_LOOP: + genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh); + break; + + default: + break; + } + + return NULL; +} + + +/* Wrapper for c_genericize_control_stmt to allow it to be used as a walk_tree + callback. This is appropriate for C; C++ calls c_genericize_control_stmt + directly. */ + +static tree +c_genericize_control_r (tree *stmt_p, int *walk_subtrees, void *data) +{ + c_genericize_control_stmt (stmt_p, walk_subtrees, data, + c_genericize_control_r, NULL); + return NULL; +} + /* Convert the tree representation of FNDECL from C frontend trees to GENERIC. */ @@ -128,6 +523,19 @@ c_genericize (tree fndecl) walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), do_warn_duplicated_branches_r, NULL); + /* Genericize loops and other structured control constructs. The C++ + front end has already done this in lang-specific code. */ + if (!c_dialect_cxx ()) + { + bc_state_t save_state; + push_cfun (DECL_STRUCT_FUNCTION (fndecl)); + save_bc_state (&save_state); + walk_tree (&DECL_SAVED_TREE (fndecl), c_genericize_control_r, + NULL, NULL); + restore_bc_state (&save_state); + pop_cfun (); + } + /* Dump the C-specific tree IR. */ dump_orig = get_dump_info (TDI_original, &local_dump_flags); if (dump_orig) diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c index ec0bafe..c364e1c 100644 --- a/gcc/c-family/c-pretty-print.c +++ b/gcc/c-family/c-pretty-print.c @@ -2364,15 +2364,97 @@ c_pretty_printer::expression (tree e) /* Statements. */ void -c_pretty_printer::statement (tree stmt) +c_pretty_printer::statement (tree t) { - if (stmt == NULL) + if (t == NULL) return; - if (pp_needs_newline (this)) - pp_newline_and_indent (this, 0); + switch (TREE_CODE (t)) + { + + case SWITCH_STMT: + pp_c_ws_string (this, "switch"); + pp_space (this); + pp_c_left_paren (this); + expression (SWITCH_STMT_COND (t)); + pp_c_right_paren (this); + pp_indentation (this) += 3; + pp_needs_newline (this) = true; + statement (SWITCH_STMT_BODY (t)); + pp_newline_and_indent (this, -3); + break; + + /* iteration-statement: + while ( expression ) statement + do statement while ( expression ) ; + for ( expression(opt) ; expression(opt) ; expression(opt) ) statement + for ( declaration expression(opt) ; expression(opt) ) statement */ + case WHILE_STMT: + pp_c_ws_string (this, "while"); + pp_space (this); + pp_c_left_paren (this); + expression (WHILE_COND (t)); + pp_c_right_paren (this); + pp_newline_and_indent (this, 3); + statement (WHILE_BODY (t)); + pp_indentation (this) -= 3; + pp_needs_newline (this) = true; + break; + + case DO_STMT: + pp_c_ws_string (this, "do"); + pp_newline_and_indent (this, 3); + statement (DO_BODY (t)); + pp_newline_and_indent (this, -3); + pp_c_ws_string (this, "while"); + pp_space (this); + pp_c_left_paren (this); + expression (DO_COND (t)); + pp_c_right_paren (this); + pp_c_semicolon (this); + pp_needs_newline (this) = true; + break; - dump_generic_node (this, stmt, pp_indentation (this), TDF_NONE, true); + case FOR_STMT: + pp_c_ws_string (this, "for"); + pp_space (this); + pp_c_left_paren (this); + if (FOR_INIT_STMT (t)) + statement (FOR_INIT_STMT (t)); + else + pp_c_semicolon (this); + pp_needs_newline (this) = false; + pp_c_whitespace (this); + if (FOR_COND (t)) + expression (FOR_COND (t)); + pp_c_semicolon (this); + pp_needs_newline (this) = false; + pp_c_whitespace (this); + if (FOR_EXPR (t)) + expression (FOR_EXPR (t)); + pp_c_right_paren (this); + pp_newline_and_indent (this, 3); + statement (FOR_BODY (t)); + pp_indentation (this) -= 3; + pp_needs_newline (this) = true; + break; + + /* jump-statement: + goto identifier; + continue ; + return expression(opt) ; */ + case BREAK_STMT: + case CONTINUE_STMT: + pp_string (this, TREE_CODE (t) == BREAK_STMT ? "break" : "continue"); + pp_c_semicolon (this); + pp_needs_newline (this) = true; + break; + + default: + if (pp_needs_newline (this)) + pp_newline_and_indent (this, 0); + dump_generic_node (this, t, pp_indentation (this), TDF_NONE, true); + } } |