This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tuples] Adding switch support to the gimplifier
Changes made - and double spacing added near the functions I added :)
On 7/11/07, Andrew MacLeod <amacleod@redhat.com> wrote:
On Wed, 2007-07-11 at 16:15 -0400, Diego Novillo wrote:
> On 7/11/07 4:12 PM, Aldy Hernandez wrote:
>
> >> /* Return a hash value for a formal temporary table entry. */
> >
> > I see you've removed a few of the double vertical spaces after some
> > functions. I *think* Diego liked it that way. Diego?
>
> Yeah, I do like the double spacing between functions. But I'm in the
> minority, so I've sort of given up on that. I tend to add them back
> when I'm committing patches, then people remove them again, and so the
> cycle goes ;)
It is my preference as well. Anything I write is usually double spaced.
Andrew
Index: tree-pretty-print.c
===================================================================
--- tree-pretty-print.c (revision 126400)
+++ tree-pretty-print.c (working copy)
@@ -1644,7 +1644,7 @@ dump_generic_node (pretty_printer *buffe
dump_generic_node (buffer, CASE_LOW (node), spc, flags, false);
}
else
- pp_string (buffer, "default ");
+ pp_string (buffer, "default");
pp_character (buffer, ':');
break;
Index: tree.h
===================================================================
--- tree.h (revision 126527)
+++ tree.h (working copy)
@@ -4740,7 +4740,6 @@ extern tree create_artificial_label (voi
extern struct gs_sequence gimplify_function_tree (tree);
extern const char *get_name (tree);
extern tree unshare_expr (tree);
-extern void sort_case_labels (tree);
/* Interface of the DWARF2 unwind info support. */
Index: testsuite/gcc.dg/gimple/gs_switch.c
===================================================================
--- testsuite/gcc.dg/gimple/gs_switch.c (revision 0)
+++ testsuite/gcc.dg/gimple/gs_switch.c (revision 0)
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+
+/* Test GS_SWITCH. */
+
+int
+foo (int a)
+{
+ switch (a)
+ {
+ default:
+ return 2;
+ case 0:
+ return a;
+ case 1:
+ return 1;
+ }
+
+}
+/* { dg-final { scan-tree-dump-times "gimpleir: switch \\(a\\)" 1 "gimple"} } */
+/* { dg-final { scan-tree-dump-times "gimpleir: default:" 1 "gimple"} } */
+/* { dg-final { scan-tree-dump-times "gimpleir: case 0:" 1 "gimple"} } */
+/* { dg-final { scan-tree-dump-times "gimpleir: case 1:" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
Index: testsuite/gcc.dg/gimple/gs_switch2.c
===================================================================
--- testsuite/gcc.dg/gimple/gs_switch2.c (revision 0)
+++ testsuite/gcc.dg/gimple/gs_switch2.c (revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+/* Test the when the switch conditional has something complex in it. */
+int
+foo2 (int a, int b)
+{
+ switch (a+a)
+ {
+ case 0:
+ return a;
+ case 1:
+ return b;
+ default:
+ return 1;
+ }
+}
+/* { dg-final { scan-tree-dump-times "gimpleir: switch \\(D.*\\)" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
Index: testsuite/gcc.dg/gimple/gs_switch3.c
===================================================================
--- testsuite/gcc.dg/gimple/gs_switch3.c (revision 0)
+++ testsuite/gcc.dg/gimple/gs_switch3.c (revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* Test generation of default label. */
+int
+foo2 (int a)
+{
+ switch (a)
+ {
+ case 0:
+ return a;
+ case 1:
+ return a;
+ }
+}
+/* { dg-final { scan-tree-dump-times "gimpleir: default:" 1 "gimple"} } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
+
Index: tree-eh.c
===================================================================
--- tree-eh.c (revision 126400)
+++ tree-eh.c (working copy)
@@ -37,6 +37,7 @@ Boston, MA 02110-1301, USA. */
#include "langhooks.h"
#include "ggc.h"
#include "toplev.h"
+#include "gimple-ir.h"
/* Nonzero if we are using EH to handle cleanups. */
Index: gimple-pretty-print.c
===================================================================
--- gimple-pretty-print.c (revision 126400)
+++ gimple-pretty-print.c (working copy)
@@ -52,6 +52,7 @@ do_niy (pretty_printer *buffer, gimple g
gs_code_name[(int) GS_CODE (gs)]);
}
+
static void
maybe_init_pretty_print (FILE *file)
{
@@ -65,6 +66,7 @@ maybe_init_pretty_print (FILE *file)
buffer.buffer->stream = file;
}
+
static void
newline_and_indent (pretty_printer *buffer, int spc)
{
@@ -73,6 +75,7 @@ newline_and_indent (pretty_printer *buff
INDENT (spc);
}
+
void
debug_gimple_stmt (gimple gs)
{
@@ -80,6 +83,7 @@ debug_gimple_stmt (gimple gs)
fprintf (stderr, "\n");
}
+
void
debug_gimple_seq (gs_seq seq)
{
@@ -92,6 +96,7 @@ debug_gimple_seq (gs_seq seq)
}
}
+
/* Dump a sequence to a BUFFER. */
static void
@@ -107,6 +112,7 @@ dump_gs_seq (pretty_printer *buffer, gs_
}
}
+
/* Dump a sequence to a FILE *. */
void
@@ -122,6 +128,7 @@ dump_gimple_seq (FILE *file, gs_seq seq)
}
}
+
/* Same, but for gimple statements. */
void
@@ -214,6 +221,30 @@ dump_gs_call (pretty_printer *buffer, gi
}
+/* Dump the switch statement GS. BUFFER, SPC and FLAGS are as in
+ dump_gimple_stmt. */
+
+static void
+dump_gs_switch (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+ unsigned int i;
+ GS_CHECK (gs, GS_SWITCH);
+ pp_string (buffer, "switch (");
+ dump_generic_node (buffer, gs_switch_index (gs), spc, flags, true);
+ pp_string (buffer, ") <");
+ for (i = 0; i < gs_switch_nlabels (gs); i++)
+ {
+ dump_generic_node (buffer, gs_switch_label (gs, i), spc, flags, false);
+ if (i < gs_switch_nlabels (gs) - 1)
+ pp_string (buffer, ", ");
+ }
+ dump_generic_node (buffer, gs_switch_default_label (gs), spc, flags,
+ false);
+
+ pp_string (buffer, ">");
+}
+
+
/* Return the symbol associated with the GS_COND predicate PRED. */
static const char *
@@ -265,7 +296,23 @@ dump_gs_cond (pretty_printer *buffer, gi
}
-/* Dump a GS_BIND tuple. */
+/* Dump a GS_LABEL tuple on the pretty_printer BUFFER, SPC
+ spaces of indent. FLAGS specifies details to show in the dump (see
+ TDF_* in tree.h)*/
+
+static void
+dump_gs_label (pretty_printer *buffer, gimple gs, int spc, int flags)
+{
+ tree label = gs_label_label (gs);
+ dump_generic_node (buffer, label, spc, flags, false);
+ if (TREE_CODE (label) != CASE_LABEL_EXPR )
+ pp_string (buffer, ":");
+}
+
+
+/* Dump a GS_BIND tuple on the pretty_printer BUFFER, SPC
+ spaces of indent. FLAGS specifies details to show in the dump (see
+ TDF_* in tree.h) */
static void
dump_gs_bind (pretty_printer *buffer, gimple gs, int spc, int flags)
@@ -322,8 +369,7 @@ dump_gimple_stmt (pretty_printer *buffer
break;
case GS_LABEL:
- dump_generic_node (buffer, gs_label_label (gs), spc, flags, false);
- pp_character (buffer, ':');
+ dump_gs_label (buffer, gs, spc, flags);
break;
case GS_GOTO:
@@ -339,11 +385,13 @@ dump_gimple_stmt (pretty_printer *buffer
dump_gs_return (buffer, gs, spc, flags);
break;
+ case GS_SWITCH:
+ dump_gs_switch (buffer, gs, spc, flags);
+ break;
+
default:
GS_NIY;
}
-
- pp_character (buffer, ';');
newline_and_indent (buffer, spc);
pp_write_text_to_stream (buffer);
}
Index: ChangeLog.tuples
===================================================================
--- ChangeLog.tuples (revision 126400)
+++ ChangeLog.tuples (working copy)
@@ -1,3 +1,24 @@
+2007-07-11 Chris Matthews <chrismatthews@google.com>
+
+ * tree-pretty-print.c (dump_generic_node): Removed space before default
+ label colon.
+ * tree.h (sort_case_labels): Moved to gimple-ir.h.
+ * gimplify.c (sort_case_labels): Changed to a vector instead of tree
+ vector.
+ (gimplify_switch_expr): Initial implementation with tuples.
+ (gimplify_expr): Changed gimplify_case_label_expr parameter.
+ (gimplify_case_label_expr): Added a gs_seq parameter, and put cases in that.
+ (dump_gimple_stmt): Removed semicolon.
+ (dump_gs_label): Refactored from dump_gimple_expr.
+ (dump_gs_switch): Added.
+ (gs_build_switch_vec): Added.
+ * gimple-ir.c (gs_build_switch_1): Added.
+ (gs_build_switch): Refactored to use gs_build_switch_1.
+ (gs_build_switch_vec): Added.
+ * gs_switch.c: New test case.
+ * gs_switch1.c: New test case.
+ * gs_switch2.c: New test case.
+
2007-07-05 Aldy Hernandez <aldyh@redhat.com>
* gimple-pretty-print.c (dump_gimple_stmt): Alphabetize cases.
Index: gimple-ir.c
===================================================================
--- gimple-ir.c (revision 126400)
+++ gimple-ir.c (working copy)
@@ -426,18 +426,16 @@ gs_build_resx (int region)
return p;
}
-/* Construct a GS_SWITCH statement.
+/* The helper for constructing a gimple switch statement.
INDEX is the switch's index.
- NLABLES is the number of labels in the switch excluding the default.
- ... are the labels excluding the default. */
+ NLABELS is the number of labels in the switch excluding the default.
+ DEFAULT_LABEL is the default label for the switch statement. */
-gimple
-gs_build_switch (unsigned int nlabels, tree index, tree default_label, ...)
+static inline gimple
+gs_build_switch_1 (unsigned int nlabels, tree index, tree default_label)
{
gimple p;
- unsigned int i;
- va_list al;
/* nlables + 1 default - 1 extra from struct */
p = ggc_alloc_cleared ( sizeof (struct gimple_statement_switch)
@@ -447,13 +445,53 @@ gs_build_switch (unsigned int nlabels, t
gs_switch_set_nlabels (p, nlabels);
gs_switch_set_index (p, index);
gs_switch_set_default_label (p, default_label);
+
+ return p;
+}
+
+
+/* Construct a GS_SWITCH statement.
+
+ INDEX is the switch's index.
+ NLABELS is the number of labels in the switch excluding the DEFAULT_LABEL.
+ ... are the labels excluding the default. */
+
+gimple
+gs_build_switch (unsigned int nlabels, tree index, tree default_label, ...)
+{
+ va_list al;
+ unsigned int i;
+
+ gimple p = gs_build_switch_1 (nlabels, index, default_label);
va_start (al, default_label);
for (i = 0; i < nlabels; i++)
gs_switch_set_label (p, i, va_arg (al, tree));
va_end (al);
+
+ return p;
+}
+
+
+/* Construct a GS_SWITCH statement.
+
+ INDEX is the switch's index.
+ NLABLES is the number of labels in the switch excluding the default.
+ ARGS is a vector of labels excluding the default. */
+
+gimple
+gs_build_switch_vec (tree index, tree default_label, VEC(tree, heap) * args)
+{
+ size_t i;
+ size_t nlabels = VEC_length (tree, args);
+ gimple p = gs_build_switch_1 (nlabels, index, default_label);
+
+ for (i = 0; i < nlabels; i++)
+ gs_switch_set_label (p, i, VEC_index (tree, args, i));
+
return p;
}
+
/* Construct a GS_OMP_CRITICAL statement.
BODY is the sequence of statements for which only one thread can execute.
Index: gimple-ir.h
===================================================================
--- gimple-ir.h (revision 126400)
+++ gimple-ir.h (working copy)
@@ -384,6 +384,7 @@ extern gimple gs_build_try (gimple, gimp
extern gimple gs_build_phi (unsigned, unsigned, tree, ...);
extern gimple gs_build_resx (int);
extern gimple gs_build_switch (unsigned int, tree, tree, ...);
+extern gimple gs_build_switch_vec (tree, tree, VEC(tree,heap) *);
extern gimple gs_omp_build_parallel (struct gs_sequence, tree, tree, tree);
extern gimple gs_omp_build_for (struct gs_sequence, tree, tree, tree, tree,
tree, struct gs_sequence, enum gs_cond);
@@ -398,6 +399,7 @@ extern gimple gs_omp_build_single (struc
extern enum gimple_statement_structure_enum gimple_statement_structure (gimple);
extern void gs_add (gimple, gs_seq);
extern enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
+extern void sort_case_labels (VEC(tree,heap) *);
extern const char *const gs_code_name[];
Index: gimplify.c
===================================================================
--- gimplify.c (revision 126400)
+++ gimplify.c (working copy)
@@ -50,8 +50,8 @@ Software Foundation, 51 Franklin Street,
#include "optabs.h"
#include "pointer-set.h"
#include "splay-tree.h"
-#include "gimple-ir.h"
#include "vec.h"
+#include "gimple-ir.h"
enum gimplify_omp_var_data
@@ -69,6 +69,7 @@ enum gimplify_omp_var_data
| GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LOCAL)
};
+
struct gimplify_omp_ctx
{
struct gimplify_omp_ctx *outer_context;
@@ -103,7 +104,6 @@ static struct gimplify_ctx *gimplify_ctx
static struct gimplify_omp_ctx *gimplify_omp_ctxp;
-
/* Formal (expression) temporary table handling: Multiple occurrences of
the same scalar expression are evaluated into the same temporary. */
@@ -1317,6 +1317,36 @@ gimplify_loop_expr (tree *expr_p, gs_seq
return GS_ALL_DONE;
}
+/* Gimplifies a statement list onto a sequence. These may be created either
+ by an enlightened front-end, or by shortcut_cond_expr. */
+
+static enum gimplify_status
+gimplify_statement_list (tree *expr_p, gs_seq pre_p)
+{
+ tree temp = voidify_wrapper_expr (*expr_p, NULL);
+
+ tree_stmt_iterator i = tsi_start (*expr_p);
+
+ while (!tsi_end_p (i))
+ {
+ gimplify_stmt (tsi_stmt_ptr (i), pre_p);
+ /* FIXME tuples: We probably don't need to delink. GC will take care of
+ this. */
+ tsi_delink (&i); }
+
+ if (temp)
+ {
+ gimplify_expr (expr_p, pre_p, NULL, false,
+
+ /* FIXME tuples: I'm not sure of either of these. */
+ is_gimple_val, fb_rvalue);
+
+ *expr_p = temp;
+ }
+
+ return GS_ALL_DONE;
+}
+
/* Compare two case labels. Because the front end should already have
made sure that case ranges do not overlap, it is enough to only compare
the CASE_LOW values of each case label. */
@@ -1333,10 +1363,10 @@ compare_case_labels (const void *p1, con
/* Sort the case labels in LABEL_VEC in place in ascending order. */
void
-sort_case_labels (tree label_vec)
+sort_case_labels (VEC(tree,heap)* label_vec)
{
- size_t len = TREE_VEC_LENGTH (label_vec);
- tree default_case = TREE_VEC_ELT (label_vec, len - 1);
+ size_t len = VEC_length (tree, label_vec);
+ tree default_case = VEC_index (tree, label_vec, len - 1);
if (CASE_LOW (default_case))
{
@@ -1345,52 +1375,62 @@ sort_case_labels (tree label_vec)
/* The last label in the vector should be the default case
but it is not. */
for (i = 0; i < len; ++i)
- {
- tree t = TREE_VEC_ELT (label_vec, i);
- if (!CASE_LOW (t))
- {
- default_case = t;
- TREE_VEC_ELT (label_vec, i) = TREE_VEC_ELT (label_vec, len - 1);
- TREE_VEC_ELT (label_vec, len - 1) = default_case;
- break;
- }
- }
+ {
+ tree t = VEC_index (tree, label_vec, i);
+ if (!CASE_LOW (t))
+ {
+ default_case = t;
+ tree index = VEC_index (tree, label_vec, len - 1);
+ VEC_replace (tree, label_vec, i, index);
+ VEC_replace (tree, label_vec, len - 1, default_case);
+ break;
+ }
+ }
}
- qsort (&TREE_VEC_ELT (label_vec, 0), len - 1, sizeof (tree),
- compare_case_labels);
+ qsort (VEC_address (tree, label_vec), len - 1, sizeof (tree),
+ compare_case_labels);
}
+
/* Gimplify a SWITCH_EXPR, and collect a TREE_VEC of the labels it can
branch to. */
static enum gimplify_status
gimplify_switch_expr (tree *expr_p, gs_seq pre_p)
{
- tree switch_expr = *expr_p;
enum gimplify_status ret;
-
- ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, false,
- is_gimple_val, fb_rvalue);
-
+ gs_seq switch_body_seq;
+ tree switch_expr;
+ switch_expr = *expr_p;
+ struct gs_sequence switch_body_seq_;
+ switch_body_seq = &switch_body_seq_;
+
+ gs_seq_init (switch_body_seq);
+ gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, false, is_gimple_val,
+ fb_rvalue);
+
if (SWITCH_BODY (switch_expr))
{
- VEC(tree,heap) *labels, *saved_labels;
- tree label_vec, default_case = NULL_TREE;
+ VEC (tree,heap) *labels;
+ VEC (tree,heap) *saved_labels;
+ tree default_case = NULL_TREE;
size_t i, len;
-
+ gimple gs_switch;
+
/* If someone can be bothered to fill in the labels, they can
be bothered to null out the body too. */
gcc_assert (!SWITCH_LABELS (switch_expr));
+ /* save old labels, get new ones from body, then restore the old
+ labels. Save all the things from the switch body to append after. */
saved_labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
- gimplify_to_stmt_list (&SWITCH_BODY (switch_expr));
-
+ gimplify_statement_list (&SWITCH_BODY (switch_expr), switch_body_seq);
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
-
+
i = 0;
while (i < VEC_length (tree, labels))
{
@@ -1420,43 +1460,35 @@ gimplify_switch_expr (tree *expr_p, gs_s
}
len = i;
- label_vec = make_tree_vec (len + 1);
- SWITCH_LABELS (*expr_p) = label_vec;
- gimplify_and_add (switch_expr, pre_p);
-
if (! default_case)
{
/* If the switch has no default label, add one, so that we jump
around the switch body. */
- default_case = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE,
- NULL_TREE, create_artificial_label ());
- gimplify_and_add (SWITCH_BODY (switch_expr), pre_p);
- *expr_p = build1 (LABEL_EXPR, void_type_node,
- CASE_LABEL (default_case));
+ gimple new_default = gs_build_label (build3 (CASE_LABEL_EXPR,
+ void_type_node,
+ NULL_TREE,
+ NULL_TREE,
+ create_artificial_label ()));
+ gs_add (new_default, switch_body_seq);
+ default_case = gs_label_label (new_default);
}
- else
- *expr_p = SWITCH_BODY (switch_expr);
- for (i = 0; i < len; ++i)
- TREE_VEC_ELT (label_vec, i) = VEC_index (tree, labels, i);
- TREE_VEC_ELT (label_vec, len) = default_case;
-
- VEC_free (tree, heap, labels);
-
- sort_case_labels (label_vec);
-
- SWITCH_BODY (switch_expr) = NULL;
+ sort_case_labels (labels);
+ gs_switch = gs_build_switch_vec (SWITCH_COND (switch_expr), default_case,
+ labels);
+ gs_add (gs_switch, pre_p);
+ gs_seq_append (switch_body_seq, pre_p);
+ VEC_free(tree, heap, labels);
}
else
gcc_assert (SWITCH_LABELS (switch_expr));
-
return ret;
}
+
static enum gimplify_status
-gimplify_case_label_expr (tree *expr_p)
+gimplify_case_label_expr (tree *expr_p, gs_seq pre_p)
{
- tree expr = *expr_p;
struct gimplify_ctx *ctxp;
/* Invalid OpenMP programs can play Duff's Device type games with
@@ -1466,8 +1498,10 @@ gimplify_case_label_expr (tree *expr_p)
if (ctxp->case_labels)
break;
- VEC_safe_push (tree, heap, ctxp->case_labels, expr);
- *expr_p = build1 (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
+ gimple gs_label = gs_build_label (*expr_p);
+ VEC_safe_push (tree, heap, ctxp->case_labels, gs_label_label(gs_label));
+ gs_add (gs_label, pre_p);
+
return GS_ALL_DONE;
}
@@ -3843,36 +3877,6 @@ gimplify_compound_expr (tree *expr_p, gs
}
}
-/* Gimplifies a statement list onto a sequence. These may be created either
- by an enlightened front-end, or by shortcut_cond_expr. */
-
-static enum gimplify_status
-gimplify_statement_list (tree *expr_p, gs_seq pre_p)
-{
- tree temp = voidify_wrapper_expr (*expr_p, NULL);
-
- tree_stmt_iterator i = tsi_start (*expr_p);
-
- while (!tsi_end_p (i))
- {
- gimplify_stmt (tsi_stmt_ptr (i), pre_p);
- /* FIXME tuples: We probably don't need to delink. GC will take care of
- this. */
- tsi_delink (&i); }
-
- if (temp)
- {
- gimplify_expr (expr_p, pre_p, NULL, false,
-
- /* FIXME tuples: I'm not sure of either of these. */
- is_gimple_val, fb_rvalue);
-
- *expr_p = temp;
- }
-
- return GS_ALL_DONE;
-}
-
/* Gimplify a SAVE_EXPR node. EXPR_P points to the expression to
gimplify. After gimplification, EXPR_P will point to a new temporary
that holds the original value of the SAVE_EXPR node.
@@ -5763,7 +5767,7 @@ gimplify_expr (tree *expr_p, gs_seq pre_
break;
case CASE_LABEL_EXPR:
- ret = gimplify_case_label_expr (expr_p);
+ ret = gimplify_case_label_expr (expr_p, pre_p);
break;
case RETURN_EXPR: