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 reorganize condition gimplification


This patch reorganizes gimplification of COND_EXPRs so that we can retain
explicit flow information for short-circuit conditions.  Currently some of
the code is disabled, as it confuses the optimizers.  I plan to change it
to remove the COND_EXPR in cases where we need to add gotos.  Applying this
now may be a bit premature, but it doesn't hurt, and the new code is
clearer even if it has the same effect as the old code.

Tested i686-pc-linux-gnu, applied to tree-ssa.

2003-05-13  Jason Merrill  <jason@redhat.com>

        * gimplify.c (simplify_cond_expr): Reorganize.
        (shortcut_cond_expr, shortcut_cond_r): New fns.
        (build_and_jump): New fn.
        (gimplify_exit_expr): Use it.

*** gimplify.c.~1~	2003-05-12 05:09:05.000000000 -0400
--- gimplify.c	2003-05-09 17:57:28.000000000 -0400
*************** gimple_add_case_label (tree expr)
*** 958,963 ****
--- 988,1010 ----
      VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, CASE_LABEL (expr));
  }
  
+ /* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first
+    if necessary.  */
+ 
+ static tree
+ build_and_jump (tree *label_p)
+ {
+   if (*label_p == NULL_TREE)
+     {
+       tree label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+       DECL_ARTIFICIAL (label) = 1;
+       DECL_CONTEXT (label) = current_function_decl;
+       *label_p = label;
+     }
+ 
+   return build1 (GOTO_EXPR, void_type_node, *label_p);
+ }
+ 
  /* Simplify an EXIT_EXPR by converting to a GOTO_EXPR inside a COND_EXPR.
     This also involves building a label to jump to and communicating it to
     gimplify_loop_expr through gimplify_ctxp->exit_label.  */
*************** gimplify_exit_expr (expr_p, pre_p)
*** 968,988 ****
       tree *pre_p;
  {
    tree cond = TREE_OPERAND (*expr_p, 0);
-   tree label = gimplify_ctxp->exit_label;
    tree expr;
  
-   if (label == NULL_TREE)
-     {
-       label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-       DECL_ARTIFICIAL (label) = 1;
-       TREE_USED (label) = 1;
-       DECL_CONTEXT (label) = current_function_decl;
-       gimplify_ctxp->exit_label = label;
-     }
- 
    simplify_expr (&cond, pre_p, NULL, is_simple_condexpr, fb_rvalue);
  
!   expr = build1 (GOTO_EXPR, void_type_node, label);
    expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
    *expr_p = expr;
  }
--- 1015,1025 ----
       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;
  }
*************** simplify_tree_list (expr_p, pre_p, post_
*** 1401,1406 ****
--- 1438,1537 ----
  		   fb_rvalue);
  }
  
+ /* 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
+ 	 into
+ 	   if (a); else if (b); else d.  */
+       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;
+ }
+ 
  
  /*  Convert the conditional expression pointed by EXPR_P '(p) ? a : b;'
      into
*************** simplify_cond_expr (expr_p, pre_p, targe
*** 1422,1474 ****
       tree *pre_p;
       tree target;
  {
-   tree tmp = NULL_TREE;
    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)))
!       {
! 	if (target)
! 	  tmp = target;
! 	else
! 	  tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
! 
! 	/* Build the then clause, 't1 = a;'.  But don't build an assignment
! 	   if this branch is void; in C++ it can be, if it's a throw.  */
! 	if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
! 	  TREE_OPERAND (expr, 1)
! 	    = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
! 
! 	/* Build the else clause, 't1 = b;'.  */
! 	if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
! 	  TREE_OPERAND (expr, 2)
! 	    = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
! 
! 	TREE_TYPE (expr) = void_type_node;
! 	recalculate_side_effects (expr);
!       }
  
    /* Turn if (a && b) into if (a) if (b).  This only works if there is no
       'else'.  */
!   if (! TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2))
!       && TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR)
      {
!       do
  	{
! 	  tree pred = TREE_OPERAND (expr, 0);
! 	  TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
! 	  expr = build (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
! 			expr, build_empty_stmt ());
  	}
-       while (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR);
- 
-       if (!tmp)
- 	/* Don't simplify our children now; simplify_expr will re-simplify
- 	   us, since we've changed *expr_p.  */
- 	goto skip;
      }
-       
  
    /* Now do the normal simplification.  */
    simplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
--- 1553,1608 ----
       tree *pre_p;
       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
! 	tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
! 
!       /* Build the then clause, 't1 = a;'.  But don't build an assignment
! 	 if this branch is void; in C++ it can be, if it's a throw.  */
!       if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
! 	TREE_OPERAND (expr, 1)
! 	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
! 
!       /* Build the else clause, 't1 = b;'.  */
!       if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
! 	TREE_OPERAND (expr, 2)
! 	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
! 
!       TREE_TYPE (expr) = void_type_node;
!       recalculate_side_effects (expr);
! 
!       /* Move the COND_EXPR to the prequeue and use the temp in its place.  */
!       simplify_stmt (&expr);
!       add_tree (expr, pre_p);
!       *expr_p = tmp;
! 
!       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)
      {
!       expr = shortcut_cond_expr (expr);
! 
!       if (expr != *expr_p)
  	{
! 	  /* Don't simplify our children now; simplify_expr will re-simplify
! 	     us, since we've changed *expr_p.  */
! 	  *expr_p = expr;
! 	  return;
  	}
      }
  
    /* Now do the normal simplification.  */
    simplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
*************** simplify_cond_expr (expr_p, pre_p, targe
*** 1481,1499 ****
  
    gimple_pop_condition (pre_p);
  
!  skip:
!   /* If we had a value, move the COND_EXPR to the prequeue and use the temp
!      in its place.  */
!   if (tmp)
!     {
!       add_tree (expr, pre_p);
!       *expr_p = tmp;
!     }
!   else
!     *expr_p = expr;
  }
  
- 
  /*  Simplify the MODIFY_EXPR node pointed by EXPR_P.
  
      PRE_P points to the list where side effects that must happen before
--- 1615,1623 ----
  
    gimple_pop_condition (pre_p);
  
!   *expr_p = expr;
  }
  
  /*  Simplify the MODIFY_EXPR node pointed by EXPR_P.
  
      PRE_P points to the list where side effects that must happen before

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