This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] PATCH to &&/|| gimplification
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 20 May 2003 16:17:41 -0400
- Subject: [tree-ssa] PATCH to &&/|| gimplification
This patch improves our handling of complex &&/|| conditionals. Previously
we would only break them up if we could do so without introducing any
gotos; any others we would evaluate into a temporary and use that for the
condition. Now we break them up like do_jump does for RTL.
This patch avoids many of the spurious uninitialized warnings during
bootstrap by making shortcut control flow explicit. I started to remove
some of the -Wno-error lines from the Makefile, but discovered that there
were a bunch of new ones that I wasn't sure why they were there, so I'm
holding off on that for the moment.
The remaining spurious warnings are the va_start warning mentioned in the
Makefile (which I will fix shortly) and another uninitialized warning due
to loop flow analysis failure: Given a testcase like
int main()
{
int i = 0;
int j;
while (1)
{
if (i>2)
break;
j = i;
++i;
}
return j;
}
The RTL loop optimizer isn't clever enough to know that we will always
execute the loop at least once, so j will always be initialized before use.
It does handle explicit 'for' loops with the same semantics, but the
gimplifier breaks them down into the above. I think this bug needs to be
fixed in the loop optimizer.
Booted and tested i686-pc-linux-gnu, applied to tree-ssa.
2003-05-20 Jason Merrill <jason@redhat.com>
* gimplify.c (shortcut_cond_expr, shortcut_cond_r): Rewrite.
(simplify_cond_expr): Also invert ifs with no 'then'.
(build_and_jump): New fn, split out from...
(gimplify_exit_expr): ...here. Don't bother gimplifying the
condition.
*** gimplify.c.~1~ Tue May 13 15:44:24 2003
--- gimplify.c Tue May 20 15:45:58 2003
*************** static void gimple_push_condition PARAMS
*** 76,82 ****
static void gimple_pop_condition PARAMS ((tree *));
static void gimple_push_cleanup PARAMS ((tree, tree *));
static void gimplify_loop_expr PARAMS ((tree *));
! static void gimplify_exit_expr PARAMS ((tree *, tree *));
static void gimplify_switch_expr (tree *, tree *);
static void gimple_add_case_label (tree);
static hashval_t gimple_tree_hash (const void *);
--- 76,82 ----
static void gimple_pop_condition PARAMS ((tree *));
static void gimple_push_cleanup PARAMS ((tree, tree *));
static void gimplify_loop_expr PARAMS ((tree *));
! static void gimplify_exit_expr PARAMS ((tree *));
static void gimplify_switch_expr (tree *, tree *);
static void gimple_add_case_label (tree);
static hashval_t gimple_tree_hash (const void *);
*************** static int gimple_tree_eq (const void *,
*** 84,89 ****
--- 84,90 ----
static tree lookup_tmp_var (tree, bool);
static tree internal_get_tmp_var (tree, tree *, bool);
static tree build_and_jump (tree *);
+ static tree shortcut_cond_expr (tree);
static struct gimplify_ctx
{
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 521,527 ****
break;
case EXIT_EXPR:
! gimplify_exit_expr (expr_p, pre_p);
break;
case GOTO_EXPR:
--- 522,528 ----
break;
case EXIT_EXPR:
! gimplify_exit_expr (expr_p);
break;
case GOTO_EXPR:
*************** gimple_add_case_label (tree expr)
*** 1000,1005 ****
--- 1001,1010 ----
static tree
build_and_jump (tree *label_p)
{
+ if (label_p == NULL)
+ /* If there's nowhere to jump, just fall through. */
+ return build_empty_stmt ();
+
if (*label_p == NULL_TREE)
{
tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
*************** build_and_jump (tree *label_p)
*** 1016,1030 ****
gimplify_loop_expr through gimplify_ctxp->exit_label. */
static void
! gimplify_exit_expr (expr_p, pre_p)
tree *expr_p;
- tree *pre_p;
{
tree cond = TREE_OPERAND (*expr_p, 0);
tree expr;
- simplify_expr (&cond, pre_p, NULL, is_simple_condexpr, fb_rvalue);
-
expr = build_and_jump (&gimplify_ctxp->exit_label);
expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
*expr_p = expr;
--- 1021,1032 ----
gimplify_loop_expr through gimplify_ctxp->exit_label. */
static void
! gimplify_exit_expr (expr_p)
tree *expr_p;
{
tree cond = TREE_OPERAND (*expr_p, 0);
tree expr;
expr = build_and_jump (&gimplify_ctxp->exit_label);
expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
*expr_p = expr;
*************** simplify_tree_list (expr_p, pre_p, post_
*** 1445,1471 ****
}
/* Handle shortcut semantics in the predicate operand of a COND_EXPR by
! rewriting it into multiple COND_EXPRs, and possibly GOTO_EXPRs. */
static tree
! shortcut_cond_r (tree expr, tree *false_label_p)
{
tree pred = TREE_OPERAND (expr, 0);
! tree t;
! if (!TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
{
/* If there is no 'else', turn (a && b) into if (a) if (b). */
while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
! expr = shortcut_cond_r (expr, false_label_p);
pred = TREE_OPERAND (pred, 0);
! expr = build (COND_EXPR, void_type_node, pred, expr,
build_empty_stmt ());
}
}
! if (!TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
{
/* If there is no 'then', turn
if (a || b); else d
--- 1447,1553 ----
}
/* Handle shortcut semantics in the predicate operand of a COND_EXPR by
! rewriting it into multiple COND_EXPRs, and possibly GOTO_EXPRs.
!
! TRUE_LABEL_P and FALSE_LABEL_P point to the labels to jump to if the
! condition is true or false, respectively. If null, we should generate
! our own to skip over the evaluation of this specific expression.
!
! This function is the tree equivalent of do_jump.
!
! shortcut_cond_r should only be called by shortcut_cond_expr. */
static tree
! shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p)
! {
! tree local_label = NULL_TREE;
! tree one, two, expr;
!
! /* OK, it's not a simple case; we need to pull apart the COND_EXPR to
! retain the shortcut semantics. Just insert the gotos here;
! shortcut_cond_expr will append the real blocks later. */
! if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
! {
! /* Turn if (a && b) into
!
! if (a); else goto no;
! if (b) goto yes; else goto no;
! (no:) */
!
! if (false_label_p == NULL)
! false_label_p = &local_label;
!
! one = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p);
! two = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
! false_label_p);
! expr = add_stmt_to_compound (one, two);
! }
! else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
! {
! /* Turn if (a || b) into
!
! if (a) goto yes;
! if (b) goto yes; else goto no;
! (yes:) */
!
! if (true_label_p == NULL)
! true_label_p = &local_label;
!
! one = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL);
! two = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
! false_label_p);
! expr = add_stmt_to_compound (one, two);
! }
! else if (TREE_CODE (pred) == COND_EXPR)
! {
! /* As long as we're messing with gotos, turn if (a ? b : c) into
! if (a)
! if (b) goto yes; else goto no;
! else
! if (c) goto yes; else goto no; */
! one = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
! false_label_p);
! two = shortcut_cond_r (TREE_OPERAND (pred, 2), true_label_p,
! false_label_p);
! expr = build (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
! one, two);
! }
! else
! {
! expr = build (COND_EXPR, void_type_node, pred,
! build_and_jump (true_label_p),
! build_and_jump (false_label_p));
! }
!
! if (local_label)
! add_tree (build1 (LABEL_EXPR, void_type_node, local_label), &expr);
!
! return expr;
! }
!
! static tree
! shortcut_cond_expr (tree expr)
{
tree pred = TREE_OPERAND (expr, 0);
! tree then_ = TREE_OPERAND (expr, 1);
! tree else_ = TREE_OPERAND (expr, 2);
! tree false_label, end_label;
! bool emit_end;
! /* First do simple transformations. */
! if (!TREE_SIDE_EFFECTS (else_))
{
/* If there is no 'else', turn (a && b) into if (a) if (b). */
while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
! then_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
! expr = build (COND_EXPR, void_type_node, pred, then_,
build_empty_stmt ());
}
}
! if (!TREE_SIDE_EFFECTS (then_))
{
/* If there is no 'then', turn
if (a || b); else d
*************** shortcut_cond_r (tree expr, tree *false_
*** 1474,1539 ****
while (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
! expr = shortcut_cond_r (expr, false_label_p);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred,
! build_empty_stmt (), expr);
}
}
! /* Don't do these other transformations yet. */
! return expr;
!
! if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
! {
! /* Turn if (a && b) c; else d; into
!
! if (a); else goto no;
! if (b) c; else { no: d; } */
!
! TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
! expr = shortcut_cond_r (expr, false_label_p);
!
! t = build (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
! build_empty_stmt (), build_and_jump (false_label_p));
! t = shortcut_cond_r (t, false_label_p);
!
! expr = add_stmt_to_compound (t, expr);
! }
! else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
{
! /* Turn if (a || b) c; else d; into
!
! if (a || b); else goto no;
! if (1) c; else { no: d; } */
! TREE_OPERAND (expr, 0) = integer_one_node;
!
! t = build (COND_EXPR, void_type_node, pred,
! build_empty_stmt (), build_and_jump (false_label_p));
! t = shortcut_cond_r (t, false_label_p);
!
! expr = add_stmt_to_compound (t, expr);
}
! return expr;
! }
! static tree
! shortcut_cond_expr (tree expr)
! {
! tree false_label = NULL_TREE;
! tree *false_branch_p = &TREE_OPERAND (expr, 2);
!
! expr = shortcut_cond_r (expr, &false_label);
!
! if (false_label)
{
! false_label = build1 (LABEL_EXPR, void_type_node, false_label);
! if (TREE_SIDE_EFFECTS (*false_branch_p))
! *false_branch_p = add_stmt_to_compound (false_label, *false_branch_p);
! else
! expr = add_stmt_to_compound (expr, false_label);
}
return expr;
}
--- 1556,1611 ----
while (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
! else_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred,
! build_empty_stmt (), else_);
}
}
! /* If we're done, great. */
! if (TREE_CODE (pred) != TRUTH_ANDIF_EXPR
! && TREE_CODE (pred) != TRUTH_ORIF_EXPR)
! return expr;
!
! /* Otherwise we need to mess with gotos. Change
! if (a) c; else d;
! to
! if (a); else goto no;
! c; goto end;
! no: d; end:
! and recursively simplify the condition. */
!
! false_label = end_label = NULL_TREE;
! emit_end = true;
!
! /* If our subexpression already has a terminal label, reuse it. */
! if (TREE_SIDE_EFFECTS (else_))
! expr = expr_last (else_);
! else
! expr = expr_last (then_);
! if (TREE_CODE (expr) == LABEL_EXPR)
{
! emit_end = false;
! end_label = LABEL_EXPR_LABEL (expr);
! if (!TREE_SIDE_EFFECTS (else_))
! false_label = end_label;
}
! expr = shortcut_cond_r (pred, NULL, &false_label);
! add_tree (then_, &expr);
! if (TREE_SIDE_EFFECTS (else_))
{
! add_tree (build_and_jump (&end_label), &expr);
! add_tree (build1 (LABEL_EXPR, void_type_node, false_label), &expr);
! add_tree (else_, &expr);
}
+ else
+ end_label = false_label;
+
+ if (emit_end)
+ add_tree (build1 (LABEL_EXPR, void_type_node, end_label), &expr);
return expr;
}
*************** simplify_cond_expr (expr_p, pre_p, targe
*** 1560,1572 ****
tree target;
{
tree expr = *expr_p;
/* If this COND_EXPR has a value, copy the values into a temporary within
the arms. */
if (! VOID_TYPE_P (TREE_TYPE (expr)))
{
- tree tmp;
-
if (target)
tmp = target;
else
--- 1632,1643 ----
tree target;
{
tree expr = *expr_p;
+ tree tmp;
/* If this COND_EXPR has a value, copy the values into a temporary within
the arms. */
if (! VOID_TYPE_P (TREE_TYPE (expr)))
{
if (target)
tmp = target;
else
*************** simplify_cond_expr (expr_p, pre_p, targe
*** 1594,1601 ****
return;
}
! /* Turn if (a && b) into if (a) if (b). This only works if there is no
! 'else'. */
if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
|| TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
{
--- 1665,1680 ----
return;
}
! /* Rewrite "if (a); else b" to "if (!a) b" */
! if (!TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
! {
! TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
! tmp = TREE_OPERAND (expr, 1);
! TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
! TREE_OPERAND (expr, 2) = tmp;
! }
!
! /* Break apart && and || conditions. */
if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
|| TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
{