This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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)
      {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]