aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorSandra Loosemore <sandra@codesourcery.com>2020-09-19 07:32:35 -0700
committerSandra Loosemore <sandra@codesourcery.com>2020-09-19 13:54:16 -0700
commitcba079f354a55363916759f6f186f92c5616b98a (patch)
treea797afe19b592943e8baf602824a39e261a94a5d /gcc/c-family
parentf7d2d4be7650acceb9d39327e21ee04f640c152f (diff)
downloadgcc-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.c24
-rw-r--r--gcc/c-family/c-common.def24
-rw-r--r--gcc/c-family/c-common.h53
-rw-r--r--gcc/c-family/c-dump.c38
-rw-r--r--gcc/c-family/c-gimplify.c408
-rw-r--r--gcc/c-family/c-pretty-print.c92
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);
+ }
}