fold-const.c (fold_binary_op_with_conditional_arg): New function, split out from ...
* fold-const.c (fold_binary_op_with_conditional_arg): New function, split out from ... (fold): ... here. * tree.def (COND_EXPR): Document the use of VOID_TYPE for conditional arms that throw exceptions. From-SVN: r39822
This commit is contained in:
parent
9c2c54dc94
commit
68626d4f0e
@ -1,5 +1,11 @@
|
||||
2001-02-17 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* fold-const.c (fold_binary_op_with_conditional_arg): New
|
||||
function, split out from ...
|
||||
(fold): ... here.
|
||||
* tree.def (COND_EXPR): Document the use of VOID_TYPE for
|
||||
conditional arms that throw exceptions.
|
||||
|
||||
* print-tree.c (print_node): Do not use BLOCK_CHAIN when we're not
|
||||
looking at a BLOCK.
|
||||
|
||||
|
252
gcc/fold-const.c
252
gcc/fold-const.c
@ -101,7 +101,9 @@ static tree strip_compound_expr PARAMS ((tree, tree));
|
||||
static int multiple_of_p PARAMS ((tree, tree, tree));
|
||||
static tree constant_boolean_node PARAMS ((int, tree));
|
||||
static int count_cond PARAMS ((tree, int));
|
||||
|
||||
static tree fold_binary_op_with_conditional_arg
|
||||
PARAMS ((enum tree_code, tree, tree, tree, int));
|
||||
|
||||
#ifndef BRANCH_COST
|
||||
#define BRANCH_COST 1
|
||||
#endif
|
||||
@ -4698,6 +4700,135 @@ count_cond (expr, lim)
|
||||
false = count_cond (TREE_OPERAND (expr, 2), lim - 1 - true);
|
||||
return MIN (lim, 1 + true + false);
|
||||
}
|
||||
|
||||
/* Transform `a + (b ? x : y)' into `x ? (a + b) : (a + y)'.
|
||||
Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'. Here
|
||||
CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)'
|
||||
expression, and ARG to `a'. If COND_FIRST_P is non-zero, then the
|
||||
COND is the first argument to CODE; otherwise (as in the example
|
||||
given here), it is the second argument. TYPE is the type of the
|
||||
original expression. */
|
||||
|
||||
static tree
|
||||
fold_binary_op_with_conditional_arg (code, type, cond, arg, cond_first_p)
|
||||
enum tree_code code;
|
||||
tree type;
|
||||
tree cond;
|
||||
tree arg;
|
||||
int cond_first_p;
|
||||
{
|
||||
tree test, true_value, false_value;
|
||||
tree lhs = NULL_TREE;
|
||||
tree rhs = NULL_TREE;
|
||||
/* In the end, we'll produce a COND_EXPR. Both arms of the
|
||||
conditional expression will be binary operations. The left-hand
|
||||
side of the expression to be executed if the condition is true
|
||||
will be pointed to by TRUE_LHS. Similarly, the right-hand side
|
||||
of the expression to be executed if the condition is true will be
|
||||
pointed to by TRUE_RHS. FALSE_LHS and FALSE_RHS are analagous --
|
||||
but apply to the expression to be executed if the conditional is
|
||||
false. */
|
||||
tree *true_lhs;
|
||||
tree *true_rhs;
|
||||
tree *false_lhs;
|
||||
tree *false_rhs;
|
||||
/* These are the codes to use for the left-hand side and right-hand
|
||||
side of the COND_EXPR. Normally, they are the same as CODE. */
|
||||
enum tree_code lhs_code = code;
|
||||
enum tree_code rhs_code = code;
|
||||
/* And these are the types of the expressions. */
|
||||
tree lhs_type = type;
|
||||
tree rhs_type = type;
|
||||
|
||||
if (cond_first_p)
|
||||
{
|
||||
true_rhs = false_rhs = &arg;
|
||||
true_lhs = &true_value;
|
||||
false_lhs = &false_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
true_lhs = false_lhs = &arg;
|
||||
true_rhs = &true_value;
|
||||
false_rhs = &false_value;
|
||||
}
|
||||
|
||||
if (TREE_CODE (cond) == COND_EXPR)
|
||||
{
|
||||
test = TREE_OPERAND (cond, 0);
|
||||
true_value = TREE_OPERAND (cond, 1);
|
||||
false_value = TREE_OPERAND (cond, 2);
|
||||
/* If this operand throws an expression, then it does not make
|
||||
sense to try to perform a logical or arithmetic operation
|
||||
involving it. Instead of building `a + throw 3' for example,
|
||||
we simply build `a, throw 3'. */
|
||||
if (VOID_TYPE_P (TREE_TYPE (true_value)))
|
||||
{
|
||||
lhs_code = COMPOUND_EXPR;
|
||||
if (!cond_first_p)
|
||||
lhs_type = void_type_node;
|
||||
}
|
||||
if (VOID_TYPE_P (TREE_TYPE (false_value)))
|
||||
{
|
||||
rhs_code = COMPOUND_EXPR;
|
||||
if (!cond_first_p)
|
||||
rhs_type = void_type_node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tree testtype = TREE_TYPE (cond);
|
||||
test = cond;
|
||||
true_value = convert (testtype, integer_one_node);
|
||||
false_value = convert (testtype, integer_zero_node);
|
||||
}
|
||||
|
||||
/* If ARG is complex we want to make sure we only evaluate
|
||||
it once. Though this is only required if it is volatile, it
|
||||
might be more efficient even if it is not. However, if we
|
||||
succeed in folding one part to a constant, we do not need
|
||||
to make this SAVE_EXPR. Since we do this optimization
|
||||
primarily to see if we do end up with constant and this
|
||||
SAVE_EXPR interferes with later optimizations, suppressing
|
||||
it when we can is important.
|
||||
|
||||
If we are not in a function, we can't make a SAVE_EXPR, so don't
|
||||
try to do so. Don't try to see if the result is a constant
|
||||
if an arm is a COND_EXPR since we get exponential behavior
|
||||
in that case. */
|
||||
|
||||
if (TREE_CODE (arg) != SAVE_EXPR && ! TREE_CONSTANT (arg)
|
||||
&& global_bindings_p () == 0
|
||||
&& ((TREE_CODE (arg) != VAR_DECL
|
||||
&& TREE_CODE (arg) != PARM_DECL)
|
||||
|| TREE_SIDE_EFFECTS (arg)))
|
||||
{
|
||||
if (TREE_CODE (true_value) != COND_EXPR)
|
||||
lhs = fold (build (lhs_code, lhs_type, *true_lhs, *true_rhs));
|
||||
|
||||
if (TREE_CODE (false_value) != COND_EXPR)
|
||||
rhs = fold (build (rhs_code, rhs_type, *false_lhs, *false_rhs));
|
||||
|
||||
if ((lhs == 0 || ! TREE_CONSTANT (lhs))
|
||||
&& (rhs == 0 || !TREE_CONSTANT (rhs)))
|
||||
arg = save_expr (arg), lhs = rhs = 0;
|
||||
}
|
||||
|
||||
if (lhs == 0)
|
||||
lhs = fold (build (lhs_code, lhs_type, *true_lhs, *true_rhs));
|
||||
if (rhs == 0)
|
||||
rhs = fold (build (rhs_code, rhs_type, *false_lhs, *false_rhs));
|
||||
|
||||
test = fold (build (COND_EXPR, type, test, lhs, rhs));
|
||||
|
||||
if (TREE_CODE (arg) == SAVE_EXPR)
|
||||
return build (COMPOUND_EXPR, type,
|
||||
convert (void_type_node, arg),
|
||||
strip_compound_expr (test, arg));
|
||||
else
|
||||
return convert (type, test);
|
||||
}
|
||||
|
||||
|
||||
/* Perform constant folding and related simplification of EXPR.
|
||||
The related simplifications include x*1 => x, x*0 => 0, etc.,
|
||||
@ -4919,70 +5050,9 @@ fold (expr)
|
||||
&& (! TREE_SIDE_EFFECTS (arg0)
|
||||
|| (global_bindings_p () == 0
|
||||
&& ! contains_placeholder_p (arg0))))
|
||||
{
|
||||
tree test, true_value, false_value;
|
||||
tree lhs = 0, rhs = 0;
|
||||
|
||||
if (TREE_CODE (arg1) == COND_EXPR)
|
||||
{
|
||||
test = TREE_OPERAND (arg1, 0);
|
||||
true_value = TREE_OPERAND (arg1, 1);
|
||||
false_value = TREE_OPERAND (arg1, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree testtype = TREE_TYPE (arg1);
|
||||
test = arg1;
|
||||
true_value = convert (testtype, integer_one_node);
|
||||
false_value = convert (testtype, integer_zero_node);
|
||||
}
|
||||
|
||||
/* If ARG0 is complex we want to make sure we only evaluate
|
||||
it once. Though this is only required if it is volatile, it
|
||||
might be more efficient even if it is not. However, if we
|
||||
succeed in folding one part to a constant, we do not need
|
||||
to make this SAVE_EXPR. Since we do this optimization
|
||||
primarily to see if we do end up with constant and this
|
||||
SAVE_EXPR interferes with later optimizations, suppressing
|
||||
it when we can is important.
|
||||
|
||||
If we are not in a function, we can't make a SAVE_EXPR, so don't
|
||||
try to do so. Don't try to see if the result is a constant
|
||||
if an arm is a COND_EXPR since we get exponential behavior
|
||||
in that case. */
|
||||
|
||||
if (TREE_CODE (arg0) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
|
||||
&& global_bindings_p () == 0
|
||||
&& ((TREE_CODE (arg0) != VAR_DECL
|
||||
&& TREE_CODE (arg0) != PARM_DECL)
|
||||
|| TREE_SIDE_EFFECTS (arg0)))
|
||||
{
|
||||
if (TREE_CODE (true_value) != COND_EXPR)
|
||||
lhs = fold (build (code, type, arg0, true_value));
|
||||
|
||||
if (TREE_CODE (false_value) != COND_EXPR)
|
||||
rhs = fold (build (code, type, arg0, false_value));
|
||||
|
||||
if ((lhs == 0 || ! TREE_CONSTANT (lhs))
|
||||
&& (rhs == 0 || !TREE_CONSTANT (rhs)))
|
||||
arg0 = save_expr (arg0), lhs = rhs = 0;
|
||||
}
|
||||
|
||||
if (lhs == 0)
|
||||
lhs = fold (build (code, type, arg0, true_value));
|
||||
if (rhs == 0)
|
||||
rhs = fold (build (code, type, arg0, false_value));
|
||||
|
||||
test = fold (build (COND_EXPR, type, test, lhs, rhs));
|
||||
|
||||
if (TREE_CODE (arg0) == SAVE_EXPR)
|
||||
return build (COMPOUND_EXPR, type,
|
||||
convert (void_type_node, arg0),
|
||||
strip_compound_expr (test, arg0));
|
||||
else
|
||||
return convert (type, test);
|
||||
}
|
||||
|
||||
return
|
||||
fold_binary_op_with_conditional_arg (code, type, arg1, arg0,
|
||||
/*cond_first_p=*/0);
|
||||
else if (TREE_CODE (arg0) == COMPOUND_EXPR)
|
||||
return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
|
||||
fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
|
||||
@ -4994,55 +5064,9 @@ fold (expr)
|
||||
&& (! TREE_SIDE_EFFECTS (arg1)
|
||||
|| (global_bindings_p () == 0
|
||||
&& ! contains_placeholder_p (arg1))))
|
||||
{
|
||||
tree test, true_value, false_value;
|
||||
tree lhs = 0, rhs = 0;
|
||||
|
||||
if (TREE_CODE (arg0) == COND_EXPR)
|
||||
{
|
||||
test = TREE_OPERAND (arg0, 0);
|
||||
true_value = TREE_OPERAND (arg0, 1);
|
||||
false_value = TREE_OPERAND (arg0, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree testtype = TREE_TYPE (arg0);
|
||||
test = arg0;
|
||||
true_value = convert (testtype, integer_one_node);
|
||||
false_value = convert (testtype, integer_zero_node);
|
||||
}
|
||||
|
||||
if (TREE_CODE (arg1) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
|
||||
&& global_bindings_p () == 0
|
||||
&& ((TREE_CODE (arg1) != VAR_DECL
|
||||
&& TREE_CODE (arg1) != PARM_DECL)
|
||||
|| TREE_SIDE_EFFECTS (arg1)))
|
||||
{
|
||||
if (TREE_CODE (true_value) != COND_EXPR)
|
||||
lhs = fold (build (code, type, true_value, arg1));
|
||||
|
||||
if (TREE_CODE (false_value) != COND_EXPR)
|
||||
rhs = fold (build (code, type, false_value, arg1));
|
||||
|
||||
if ((lhs == 0 || ! TREE_CONSTANT (lhs))
|
||||
&& (rhs == 0 || !TREE_CONSTANT (rhs)))
|
||||
arg1 = save_expr (arg1), lhs = rhs = 0;
|
||||
}
|
||||
|
||||
if (lhs == 0)
|
||||
lhs = fold (build (code, type, true_value, arg1));
|
||||
|
||||
if (rhs == 0)
|
||||
rhs = fold (build (code, type, false_value, arg1));
|
||||
|
||||
test = fold (build (COND_EXPR, type, test, lhs, rhs));
|
||||
if (TREE_CODE (arg1) == SAVE_EXPR)
|
||||
return build (COMPOUND_EXPR, type,
|
||||
convert (void_type_node, arg1),
|
||||
strip_compound_expr (test, arg1));
|
||||
else
|
||||
return convert (type, test);
|
||||
}
|
||||
return
|
||||
fold_binary_op_with_conditional_arg (code, type, arg0, arg1,
|
||||
/*cond_first_p=*/1);
|
||||
}
|
||||
else if (TREE_CODE_CLASS (code) == '<'
|
||||
&& TREE_CODE (arg0) == COMPOUND_EXPR)
|
||||
|
12
gcc/testsuite/g++.old-deja/g++.eh/crash5.C
Normal file
12
gcc/testsuite/g++.old-deja/g++.eh/crash5.C
Normal file
@ -0,0 +1,12 @@
|
||||
// Build don't link:
|
||||
// Origin: Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
void
|
||||
f ()
|
||||
{
|
||||
j = j + (i ? 7 : throw 1);
|
||||
}
|
||||
|
@ -425,8 +425,10 @@ DEFTREECODE (TARGET_EXPR, "target_expr", 'e', 4)
|
||||
Operand 0 is the condition.
|
||||
Operand 1 is the then-value.
|
||||
Operand 2 is the else-value.
|
||||
Operand 0 may be of any type, but the types of operands 1 and 2
|
||||
must be the same and the same as the type of this expression. */
|
||||
Operand 0 may be of any type.
|
||||
Operand 1 must have the same type as the entire expression, unless
|
||||
it unconditionally throws an exception, in which case it should
|
||||
have VOID_TYPE. The same constraints apply to operand 2. */
|
||||
DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3)
|
||||
|
||||
/* Declare local variables, including making RTL and allocating space.
|
||||
|
Loading…
Reference in New Issue
Block a user