Paolo Bonzini wrote:

a) if anyone propagates a value anywhere, she should check whether the propagated value is part of a comparison in a COND_EXPR (and explicitly fold the comparison, if so). b) in case of a COND_EXPR, fold_ternary (...) in fold-const.c folds the comparison before doing anything else (currently, it doesn't do it at all).

I'd go for the second alternative.
It needs an amendment in your statement "fold and friends don't recurse on trees..." for the special case of the comparison of a COND_EXPR, but it avoids explicit checks and folding every time a pass propagates anything into a COND_EXPR.
I think this emphasizes a problem with COND_EXPRs in GIMPLE (and VEC_COND_EXPRs too for that matter; this poor aspect of the design has been there forever): that in this case you cannot assume anymore the RHS of a MODIFY_EXPR to be flat (the other case in which this does not hold is load and stores).

I'd go for the first alternative, writing a fold_gimple_cond_expr function that folds the comparison like this:

static tree
fold_gimple_cond_expr (tree temp)
{
 tree temp = fold (COND_EXPR_COND (cond_expr));
 if (temp == COND_EXPR_COND (cond_expr))
   return fold (cond_expr);
 else
   return fold_build3 (COND_EXPR, TREE_TYPE (cond_expr), temp,
         COND_EXPR_THEN (cond_expr), COND_EXPR_ELSE (cond_expr));
}

which can be used in fold_stmt. Roger will surely have more to say, however.

(Remember that fold and friends are not GIMPLE-only. They are used also by front-ends.)

Paolo

Hello,
I produced the following patch (attached), which I believe takes into account Roger's remark and Paolo's suggestion.
I tested it, I bootstrapped with no regressions on i686-pc-linux-gnu.
Please, tell me what do you think. I hope it is ready for approval, I'd really like to check these bits and pieces of work about COND_EXPRs before I forget about the all matter. :-)

Cheers,
Roberto


2006-11-14  Roberto Costa  <[EMAIL PROTECTED]>

        * tree-vrp.c (extract_range_from_cond_expr): New.
        (extract_range_from_expr): Handle COND_EXPR nodes used as expressions.
        * tree-ssa-ccp.c (get_maxval_strlen): Handle COND_EXPR nodes used
        as expressions.
        (fold_stmt): Bug fix, avoid infinite recursion when folding COND_EXPRs.
        * tree-ssa-forwprop.c (simplify_cond, forward_propagate_into_cond,
        tree_ssa_forward_propagate_single_use_vars): Handle COND_EXPR nodes
        used as expressions.
        * tree-object-size.c (cond_expr_object_size): New.
        (collect_object_sizes_for): Handle COND_EXPR nodes used as expressions.

Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c      (revision 118652)
+++ gcc/tree-vrp.c      (working copy)
@@ -43,6 +43,7 @@ static sbitmap found_in_subgraph;
 
 /* Local functions.  */
 static int compare_values (tree val1, tree val2);
+static void vrp_meet (value_range_t *, value_range_t *);
 
 /* Location information for ASSERT_EXPRs.  Each instance of this
    structure describes an ASSERT_EXPR for an SSA name.  Since a single
@@ -1862,6 +1863,40 @@ extract_range_from_unary_expr (value_ran
 }
 
 
+/* Extract range information from a conditional expression EXPR based on
+   the ranges of each of its operands and the expression code.  */
+
+static void
+extract_range_from_cond_expr (value_range_t *vr, tree expr)
+{
+  tree op0, op1;
+  value_range_t vr0 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+  value_range_t vr1 = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+
+  /* Get value ranges for each operand.  For constant operands, create
+     a new value range with the operand to simplify processing.  */
+  op0 = COND_EXPR_THEN (expr);
+  if (TREE_CODE (op0) == SSA_NAME)
+    vr0 = *(get_value_range (op0));
+  else if (is_gimple_min_invariant (op0))
+    set_value_range (&vr0, VR_RANGE, op0, op0, NULL);
+  else
+    set_value_range_to_varying (&vr0);
+
+  op1 = COND_EXPR_ELSE (expr);
+  if (TREE_CODE (op1) == SSA_NAME)
+    vr1 = *(get_value_range (op1));
+  else if (is_gimple_min_invariant (op1))
+    set_value_range (&vr1, VR_RANGE, op1, op1, NULL);
+  else
+    set_value_range_to_varying (&vr1);
+
+  /* The resulting value range is the union of the operand ranges */
+  vrp_meet (&vr0, &vr1);
+  copy_value_range (vr, &vr0);
+}
+
+
 /* Extract range information from a comparison expression EXPR based
    on the range of its operand and the expression code.  */
 
@@ -1903,6 +1938,8 @@ extract_range_from_expr (value_range_t *
     extract_range_from_binary_expr (vr, expr);
   else if (TREE_CODE_CLASS (code) == tcc_unary)
     extract_range_from_unary_expr (vr, expr);
+  else if (code == COND_EXPR)
+    extract_range_from_cond_expr (vr, expr);
   else if (TREE_CODE_CLASS (code) == tcc_comparison)
     extract_range_from_comparison (vr, expr);
   else if (is_gimple_min_invariant (expr))
Index: gcc/tree-ssa-ccp.c
===================================================================
--- gcc/tree-ssa-ccp.c  (revision 118652)
+++ gcc/tree-ssa-ccp.c  (working copy)
@@ -2030,6 +2030,10 @@ get_maxval_strlen (tree arg, tree *lengt
   
   if (TREE_CODE (arg) != SSA_NAME)
     {
+      if (TREE_CODE (arg) == COND_EXPR)
+        return get_maxval_strlen (COND_EXPR_THEN (arg), length, visited, type)
+               && get_maxval_strlen (COND_EXPR_ELSE (arg), length, visited, 
type);
+
       if (type == 2)
        {
          val = arg;
@@ -2359,6 +2363,13 @@ fold_stmt (tree *stmt_p)
            }
        }
     }
+  else if (TREE_CODE (rhs) == COND_EXPR)
+    {
+      tree temp = fold (COND_EXPR_COND (rhs));
+      if (temp != COND_EXPR_COND (rhs))
+        result = fold_build3 (COND_EXPR, TREE_TYPE (rhs), temp,
+                              COND_EXPR_THEN (rhs), COND_EXPR_ELSE (rhs));
+    }
 
   /* If we couldn't fold the RHS, hand over to the generic fold routines.  */
   if (result == NULL_TREE)
Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c     (revision 118652)
+++ gcc/tree-ssa-forwprop.c     (working copy)
@@ -490,15 +490,16 @@ find_equivalent_equality_comparison (tre
   return NULL;
 }
 
-/* STMT is a COND_EXPR
+/* EXPR is a COND_EXPR
+   STMT is the statement containing EXPR.
 
    This routine attempts to find equivalent forms of the condition
    which we may be able to optimize better.  */
 
 static void
-simplify_cond (tree stmt)
+simplify_cond (tree cond_expr, tree stmt)
 {
-  tree cond = COND_EXPR_COND (stmt);
+  tree cond = COND_EXPR_COND (cond_expr);
 
   if (COMPARISON_CLASS_P (cond))
     {
@@ -517,7 +518,7 @@ simplify_cond (tree stmt)
 
              if (new_cond)
                {
-                 COND_EXPR_COND (stmt) = new_cond;
+                 COND_EXPR_COND (cond_expr) = new_cond;
                  update_stmt (stmt);
                }
            }
@@ -529,7 +530,7 @@ simplify_cond (tree stmt)
    times as possible.  */
 
 static void
-forward_propagate_into_cond (tree cond_expr)
+forward_propagate_into_cond (tree cond_expr, tree stmt)
 {
   gcc_assert (TREE_CODE (cond_expr) == COND_EXPR);
 
@@ -554,7 +555,7 @@ forward_propagate_into_cond (tree cond_e
        }
 
       COND_EXPR_COND (cond_expr) = new_cond;
-      update_stmt (cond_expr);
+      update_stmt (stmt);
 
       if (has_zero_uses (test_var))
        {
@@ -569,7 +570,7 @@ forward_propagate_into_cond (tree cond_e
      against a constant where the SSA_NAME is the result of a
      conversion.  Perhaps this should be folded into the rest
      of the COND_EXPR simplification code.  */
-  simplify_cond (cond_expr);
+  simplify_cond (cond_expr, stmt);
 }
 
 /* We've just substituted an ADDR_EXPR into stmt.  Update all the 
@@ -1001,6 +1002,11 @@ tree_ssa_forward_propagate_single_use_va
                  simplify_not_neg_expr (stmt);
                  bsi_next (&bsi);
                }
+              else if (TREE_CODE (rhs) == COND_EXPR)
+                {
+                  forward_propagate_into_cond (rhs, stmt);
+                 bsi_next (&bsi);
+                }
              else
                bsi_next (&bsi);
            }
@@ -1011,7 +1017,7 @@ tree_ssa_forward_propagate_single_use_va
            }
          else if (TREE_CODE (stmt) == COND_EXPR)
            {
-             forward_propagate_into_cond (stmt);
+             forward_propagate_into_cond (stmt, stmt);
              bsi_next (&bsi);
            }
          else
Index: gcc/tree-object-size.c
===================================================================
--- gcc/tree-object-size.c      (revision 118652)
+++ gcc/tree-object-size.c      (working copy)
@@ -50,6 +50,7 @@ static void expr_object_size (struct obj
 static bool merge_object_sizes (struct object_size_info *, tree, tree,
                                unsigned HOST_WIDE_INT);
 static bool plus_expr_object_size (struct object_size_info *, tree, tree);
+static bool cond_expr_object_size (struct object_size_info *, tree, tree);
 static unsigned int compute_object_sizes (void);
 static void init_offset_limit (void);
 static void check_for_plus_in_loops (struct object_size_info *, tree);
@@ -621,6 +622,40 @@ plus_expr_object_size (struct object_siz
 }
 
 
+/* Compute object_sizes for PTR, defined to VALUE, which is
+   a COND_EXPR.  Return true if the object size might need reexamination
+   later.  */
+
+static bool
+cond_expr_object_size (struct object_size_info *osi, tree var, tree value)
+{
+  tree then_, else_;
+  int object_size_type = osi->object_size_type;
+  unsigned int varno = SSA_NAME_VERSION (var);
+  bool reexamine = false;
+
+  gcc_assert (TREE_CODE (value) == COND_EXPR);
+
+  if (object_sizes[object_size_type][varno] == unknown[object_size_type])
+    return false;
+
+  then_ = COND_EXPR_THEN (value);
+  else_ = COND_EXPR_ELSE (value);
+
+  if (TREE_CODE (then_) == SSA_NAME)
+    reexamine |= merge_object_sizes (osi, var, then_, 0);
+  else
+    expr_object_size (osi, var, then_);
+
+  if (TREE_CODE (else_) == SSA_NAME)
+    reexamine |= merge_object_sizes (osi, var, else_, 0);
+  else
+    expr_object_size (osi, var, else_);
+
+  return reexamine;
+}
+
+
 /* Compute object sizes for VAR.
    For ADDR_EXPR an object size is the number of remaining bytes
    to the end of the object (where what is considered an object depends on
@@ -711,6 +746,9 @@ collect_object_sizes_for (struct object_
        else if (TREE_CODE (rhs) == PLUS_EXPR)
          reexamine = plus_expr_object_size (osi, var, rhs);
 
+        else if (TREE_CODE (rhs) == COND_EXPR)
+         reexamine = cond_expr_object_size (osi, var, rhs);
+
        else
          expr_object_size (osi, var, rhs);
        break;

Reply via email to