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;