This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tuples] GS_COND, GS_GOTO, GS_LABEL
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: dnovillo at google dot com, amacleod at redhat dot com, gcc-patches at gcc dot gnu dot org
- Date: Thu, 28 Jun 2007 14:19:05 -0600
- Subject: [tuples] GS_COND, GS_GOTO, GS_LABEL
In the spirit of, let's get these patches in before Diego causes me
conflicts...
Here is a patch implementing gotos, labels, and cond_exprs.
One interesting bit... Previously we were checking for side effects to
determine if an arm of a COND_EXPR was present or not so we could
reverse its format. The simplest alternative I found was to have
gimplify_stmt() return true if we actually added any statements, and use
that instead.
However... since GS_COND is a lowered version of GS_COND_EXPR, I would
much rather not swap GS_COND labels, and rip this code out. Does this
really matter, or do we need to canonicalize GS_COND or something?
Anyways... no regressions. Committing to branch. I'll be optimizing
the GS_COND predicates, and getting the push/pop_context business
working.
Aldy
* testsuite/gcc.dg/gimple/gs_goto.c: New.
* testsuite/gcc.dg/gimple/gs_cond.c: New.
* tree-gimple.h (gimplify_stmt): Return bool.
* gimple-pretty-print.c (INDENT): New.
(newline_and_indent): New.
(op_gs_cond): New.
(dump_gs_cond): New.
(dump_gimple_stmt): New.
* gimple-ir.c (gs_cond_invert): New.
* gimple-ir.h (enum gs_cond): Add comment.
(gs_cond_invert): Protoize.
* gimplify.c (gimplify_cond_expr): Rewrite for tuples.
(gimplify_stmt): Return true if we added a statement to the queue.
(gimplify_expr): Enable gimplify_cond_expr.
Build tuples for GOTO_EXPRs and LABEL_EXPRs.
Index: testsuite/gcc.dg/gimple/gs_goto.c
===================================================================
--- testsuite/gcc.dg/gimple/gs_goto.c (revision 0)
+++ testsuite/gcc.dg/gimple/gs_goto.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Test GS_GOTO. */
+
+void yanory()
+{
+hotdog:
+ goto hotdog;
+}
+
+/* { dg-final { scan-tree-dump-times "gimpleir: goto hotdog" 1 "gimple"} } */
+/* { dg-final { scan-tree-dump-times "gimpleir: hotdog:" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
Index: testsuite/gcc.dg/gimple/gs_cond.c
===================================================================
--- testsuite/gcc.dg/gimple/gs_cond.c (revision 0)
+++ testsuite/gcc.dg/gimple/gs_cond.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Test GS_COND. */
+
+int res, a, b, c;
+
+void foo()
+{
+ res = a > 5 ? b : c;
+}
+
+/* { dg-final { scan-tree-dump-times "gimpleir: GS_COND tuple" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
Index: tree-gimple.h
===================================================================
--- tree-gimple.h (revision 126065)
+++ tree-gimple.h (working copy)
@@ -115,7 +115,7 @@ extern enum gimplify_status gimplify_exp
bool (*) (tree), fallback_t);
extern void gimplify_type_sizes (tree, gs_seq);
extern void gimplify_one_sizepos (tree *, gs_seq);
-extern void gimplify_stmt (tree *, gs_seq);
+extern bool gimplify_stmt (tree *, gs_seq);
extern void gimplify_to_stmt_list (tree *);
extern void gimplify_body (tree *, gs_seq, tree, bool);
extern void push_gimplify_context (void);
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c (revision 126065)
+++ gimple-pretty-print.c (working copy)
@@ -34,6 +34,8 @@ Software Foundation, 51 Franklin Street,
#include "tree-pass.h"
#include "gimple-ir.h"
+#define INDENT(SPACE) do { \
+ int i; for (i = 0; i<SPACE; i++) pp_space (buffer); } while (0)
static pretty_printer buffer;
static bool initialized = false;
@@ -63,6 +65,14 @@ maybe_init_pretty_print (FILE *file)
buffer.buffer->stream = file;
}
+static void
+newline_and_indent (pretty_printer *buffer, int spc)
+{
+ pp_newline (buffer);
+ pp_string (buffer, "gimpleir: ");
+ INDENT (spc);
+}
+
void
debug_gimple_stmt (gimple gs)
{
@@ -187,6 +197,57 @@ dump_gs_call (pretty_printer *buffer, gi
}
+/* Return the symbol associated with the GS_COND predicate PRED. */
+
+static const char *
+op_gs_cond (enum gs_cond pred)
+{
+ /* These must be in sync with enum gs_cond. */
+ static const char *table[] =
+ { "<", ">", "<=", ">=", "==", "!=" };
+
+ return table[(int) pred];
+}
+
+
+/* Dump the gimple conditional GS. BUFFER, SPC and FLAGS are as in
+ dump_gimple_stmt. */
+
+static void
+dump_gs_cond (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+ /* This stupid line is here so we can scan for it in the testsuite. */
+ pp_string (buffer, "GS_COND tuple");
+
+ newline_and_indent (buffer, spc);
+ pp_string (buffer, "if (");
+ dump_generic_node (buffer, gs_cond_lhs (gs), spc, flags, false);
+ pp_space (buffer);
+ pp_string (buffer, op_gs_cond (GS_SUBCODE_FLAGS (gs)));
+ pp_space (buffer);
+ dump_generic_node (buffer, gs_cond_rhs (gs), spc, flags, false);
+ pp_character (buffer, ')');
+ newline_and_indent (buffer, spc + 2);
+ pp_character (buffer, '{');
+ newline_and_indent (buffer, spc + 4);
+ pp_string (buffer, "goto ");
+ dump_generic_node (buffer, gs_cond_true_label (gs), spc, flags, false);
+ pp_character (buffer, ';');
+ newline_and_indent (buffer, spc + 2);
+ pp_character (buffer, '}');
+ newline_and_indent (buffer, spc);
+ pp_string (buffer, "else");
+ newline_and_indent (buffer, spc + 2);
+ pp_character (buffer, '{');
+ newline_and_indent (buffer, spc + 4);
+ pp_string (buffer, "goto ");
+ dump_generic_node (buffer, gs_cond_false_label (gs), spc, flags, false);
+ pp_character (buffer, ';');
+ newline_and_indent (buffer, spc + 2);
+ pp_character (buffer, '}');
+}
+
+
/* Dump the gimple statement GS on the pretty_printer BUFFER, SPC
spaces of indent. FLAGS specifies details to show in the dump (see
TDF_* in tree.h). */
@@ -211,6 +272,20 @@ dump_gimple_stmt (pretty_printer *buffer
dump_gs_call (buffer, gs, spc, flags);
break;
+ case GS_LABEL:
+ dump_generic_node (buffer, gs_label_label (gs), spc, flags, false);
+ pp_character (buffer, ':');
+ break;
+
+ case GS_GOTO:
+ pp_string (buffer, "goto ");
+ dump_generic_node (buffer, gs_goto_dest (gs), spc, flags, false);
+ break;
+
+ case GS_COND:
+ dump_gs_cond (buffer, gs, spc, flags);
+ break;
+
default:
GS_NIY;
}
Index: gimple-ir.c
===================================================================
--- gimple-ir.c (revision 126065)
+++ gimple-ir.c (working copy)
@@ -211,6 +211,18 @@ gs_build_cond (enum gs_cond pred, tree l
return p;
}
+/* Invert the condition of a GS_COND by swapping its labels. */
+
+void
+gs_cond_invert (gimple g)
+{
+ tree tmp;
+
+ tmp = gs_cond_true_label (g);
+ gs_cond_set_true_label (g, gs_cond_false_label (g));
+ gs_cond_set_false_label (g, tmp);
+}
+
/* Construct a GS_LABEL statement for LABEL. */
gimple
Index: gimple-ir.h
===================================================================
--- gimple-ir.h (revision 126065)
+++ gimple-ir.h (working copy)
@@ -287,6 +287,7 @@ struct gimple_statement_omp_for GTY(())
/* Predicate for conds. */
enum gs_cond {
+ /* These must be in sync with op_gs_cond(). */
GS_COND_LT, GS_COND_GT, GS_COND_LE, GS_COND_GE, GS_COND_EQ, GS_COND_NE
};
@@ -371,6 +372,7 @@ extern gimple gs_build_assign (tree, tre
extern gimple gs_build_call_vec (tree, VEC(tree, gc) *);
extern gimple gs_build_call (tree, size_t, ...);
extern gimple gs_build_cond (enum gs_cond, tree, tree, tree, tree);
+extern void gs_cond_invert (gimple);
extern gimple gs_build_label (tree label);
extern gimple gs_build_goto (tree dest);
extern gimple gs_build_nop (void);
Index: gimplify.c
===================================================================
--- gimplify.c (revision 126065)
+++ gimplify.c (working copy)
@@ -337,6 +337,7 @@ append_to_statement_list_force (tree t,
append_to_statement_list_1 (t, list_p);
}
+/* FIXME tuples: This function is obsolete. Use gimplify_stmt instead. */
/* Both gimplify the statement T and append it to SEQ. */
void
@@ -2462,19 +2463,18 @@ gimple_boolify (tree expr)
The second form is used when *EXPR_P is of type void.
- TARGET is the tree for T1 above.
-
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored. */
-#if 0
-/* FIXME tuples */
static enum gimplify_status
gimplify_cond_expr (tree *expr_p, gs_seq pre_p, fallback_t fallback)
{
tree expr = *expr_p;
- tree tmp, tmp2, type;
+ tree tmp, type;
enum gimplify_status ret;
+ tree label_true, label_false, label_cont;
+ bool have_then_clause_p, have_else_clause_p;
+ gimple gs_cond;
type = TREE_TYPE (expr);
@@ -2485,10 +2485,7 @@ gimplify_cond_expr (tree *expr_p, gs_seq
tree result;
if ((fallback & fb_lvalue) == 0)
- {
- result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
- ret = GS_ALL_DONE;
- }
+ result = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
else
{
tree type = build_pointer_type (TREE_TYPE (expr));
@@ -2501,13 +2498,12 @@ gimplify_cond_expr (tree *expr_p, gs_seq
TREE_OPERAND (expr, 2) =
build_fold_addr_expr (TREE_OPERAND (expr, 2));
- tmp2 = tmp = create_tmp_var (type, "iftmp");
+ tmp = create_tmp_var (type, "iftmp");
expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
result = build_fold_indirect_ref (tmp);
- ret = GS_ALL_DONE;
}
/* Build the then clause, 't1 = a;'. But don't build an assignment
@@ -2519,16 +2515,16 @@ gimplify_cond_expr (tree *expr_p, gs_seq
/* Build the else clause, 't1 = b;'. */
if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
TREE_OPERAND (expr, 2)
- = build_gimple_modify_stmt (tmp2, TREE_OPERAND (expr, 2));
+ = build_gimple_modify_stmt (tmp, TREE_OPERAND (expr, 2));
TREE_TYPE (expr) = void_type_node;
recalculate_side_effects (expr);
/* Move the COND_EXPR to the prequeue. */
- gimplify_and_add (expr, pre_p);
+ gimplify_stmt (expr_p, pre_p);
*expr_p = result;
- return ret;
+ return GS_ALL_DONE;
}
/* Make sure the condition has BOOLEAN_TYPE. */
@@ -2548,49 +2544,68 @@ gimplify_cond_expr (tree *expr_p, gs_seq
form properly, as cleanups might cause the target labels to be
wrapped in a TRY_FINALLY_EXPR. To prevent that, we need to
set up a conditional context. */
+ /* FIXME tuples
gimple_push_condition ();
- gimplify_stmt (expr_p);
+ */
+ gimplify_stmt (expr_p, pre_p);
+ /* FIXME tuples
gimple_pop_condition (pre_p);
+ */
return GS_ALL_DONE;
}
}
/* Now do the normal gimplification. */
- ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+
+ /* Gimplify condition. */
+ ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, false,
is_gimple_condexpr, fb_rvalue);
+ gcc_assert (TREE_OPERAND (expr, 0) != NULL_TREE);
+ /* FIXME tuples
gimple_push_condition ();
+ */
- gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
- gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
- recalculate_side_effects (expr);
+ label_true = create_artificial_label ();
+ label_false = create_artificial_label ();
+ /* FIXME tuples: We should add smarts to use the other GS_COND predicates
+ when appropriate. */
+ gs_cond = gs_build_cond (GS_COND_NE,
+ TREE_OPERAND (expr, 0), boolean_false_node,
+ label_true, label_false);
+ gs_add (gs_cond, pre_p);
+ gs_add (gs_build_label (label_true), pre_p);
+ have_then_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 1), pre_p);
+ label_cont = create_artificial_label ();
+ gs_add (gs_build_goto (label_cont), pre_p);
+ gs_add (gs_build_label (label_false), pre_p);
+ have_else_clause_p = gimplify_stmt (&TREE_OPERAND (expr, 2), pre_p);
+ gs_add (gs_build_label (label_cont), pre_p);
+ /* FIXME tuples
gimple_pop_condition (pre_p);
+ */
if (ret == GS_ERROR)
;
- else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+ else if (have_then_clause_p)
ret = GS_ALL_DONE;
- else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
- /* Rewrite "if (a); else b" to "if (!a) b" */
+ else if (have_else_clause_p)
{
- TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
- ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
- is_gimple_condexpr, fb_rvalue);
-
- tmp = TREE_OPERAND (expr, 1);
- TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
- TREE_OPERAND (expr, 2) = tmp;
+ /* Rewrite "if (a); else b" into "if (!a) b" */
+ gs_cond_invert (gs_cond);
}
else
- /* Both arms are empty; replace the COND_EXPR with its predicate. */
- expr = TREE_OPERAND (expr, 0);
+ {
+ /* Both arms are empty; replace the COND_EXPR with its predicate. */
+ expr = TREE_OPERAND (expr, 0);
+ gimplify_stmt (&expr, pre_p);
+ }
- *expr_p = expr;
+ *expr_p = NULL;
return ret;
}
-#endif
/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with
a call to __builtin_memcpy. */
@@ -4368,12 +4383,17 @@ gimplify_target_expr (tree *expr_p, gs_s
/* Gimplification of expression trees. */
-/* Gimplify an expression which appears at statement context into SEQ_P. */
+/* Gimplify an expression which appears at statement context into SEQ_P.
+ Return true if we actually added a statement to the queue. */
-void
+bool
gimplify_stmt (tree *stmt_p, gs_seq seq_p)
{
+ gimple last;
+
+ last = gs_seq_last (seq_p);
gimplify_expr (stmt_p, seq_p, NULL, true, is_gimple_stmt, fb_none);
+ return last != gs_seq_last (seq_p);
}
/* Similarly, but force the result to be a STATEMENT_LIST. */
@@ -5566,9 +5586,7 @@ gimplify_expr (tree *expr_p, gs_seq pre_
break;
case COND_EXPR:
-#if 0
-/* FIXME tuples */
- ret = gimplify_cond_expr (expr_p, seq_p, pre_p, fallback);
+ ret = gimplify_cond_expr (expr_p, pre_p, fallback);
/* C99 code may assign to an array in a structure value of a
conditional expression, and this has undefined behavior
only on execution, so create a temporary if an lvalue is
@@ -5578,8 +5596,6 @@ gimplify_expr (tree *expr_p, gs_seq pre_
*expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
lang_hooks.mark_addressable (*expr_p);
}
-#endif
- gcc_unreachable();
break;
case CALL_EXPR:
@@ -5725,12 +5741,14 @@ gimplify_expr (tree *expr_p, gs_seq pre_
if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL)
ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p,
NULL, false, is_gimple_val, fb_rvalue);
+ gs_add (gs_build_goto (GOTO_DESTINATION (*expr_p)), pre_p);
break;
case LABEL_EXPR:
ret = GS_ALL_DONE;
gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
== current_function_decl);
+ gs_add (gs_build_label (LABEL_EXPR_LABEL (*expr_p)), pre_p);
break;
case CASE_LABEL_EXPR: