mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-10-04 16:08:34 +00:00
fold-const.c (fold_ternary): Unroll the "for" loop to extract operands.
* fold-const.c (fold_ternary): Unroll the "for" loop to extract operands. From-SVN: r95895
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
2005-03-04 Kazu Hirata <kazu@cs.umass.edu>
|
||||
|
||||
* fold-const.c (fold_ternary): Unroll the "for" loop to
|
||||
extract operands.
|
||||
|
||||
2005-03-04 Andrew Haley <aph@redhat.com>
|
||||
|
||||
* unwind-dw2-fde-glibc.c (struct
|
||||
|
||||
+48
-60
@@ -7024,41 +7024,38 @@ fold_ternary (tree expr)
|
||||
const tree t = expr;
|
||||
const tree type = TREE_TYPE (expr);
|
||||
tree tem;
|
||||
tree op0, op1, op2;
|
||||
tree arg0 = NULL_TREE, arg1 = NULL_TREE;
|
||||
enum tree_code code = TREE_CODE (t);
|
||||
enum tree_code_class kind = TREE_CODE_CLASS (code);
|
||||
int i;
|
||||
|
||||
gcc_assert (IS_EXPR_CODE_CLASS (kind)
|
||||
&& TREE_CODE_LENGTH (code) == 3);
|
||||
|
||||
/* For now, we iterate only twice even though we are handling
|
||||
ternary expressions. This is because we haven't defined arg2
|
||||
yet. */
|
||||
for (i = 0; i < 2; i++)
|
||||
op0 = TREE_OPERAND (t, 0);
|
||||
op1 = TREE_OPERAND (t, 1);
|
||||
op2 = TREE_OPERAND (t, 2);
|
||||
|
||||
/* Strip any conversions that don't change the mode. This is safe
|
||||
for every expression, except for a comparison expression because
|
||||
its signedness is derived from its operands. So, in the latter
|
||||
case, only strip conversions that don't change the signedness.
|
||||
|
||||
Note that this is done as an internal manipulation within the
|
||||
constant folder, in order to find the simplest representation of
|
||||
the arguments so that their form can be studied. In any cases,
|
||||
the appropriate type conversions should be put back in the tree
|
||||
that will get out of the constant folder. */
|
||||
if (op0)
|
||||
{
|
||||
tree op = TREE_OPERAND (t, i);
|
||||
arg0 = op0;
|
||||
STRIP_NOPS (arg0);
|
||||
}
|
||||
|
||||
if (op == 0)
|
||||
continue; /* Valid for CALL_EXPR, at least. */
|
||||
|
||||
/* Strip any conversions that don't change the mode. This is
|
||||
safe for every expression, except for a comparison expression
|
||||
because its signedness is derived from its operands. So, in
|
||||
the latter case, only strip conversions that don't change the
|
||||
signedness.
|
||||
|
||||
Note that this is done as an internal manipulation within the
|
||||
constant folder, in order to find the simplest representation
|
||||
of the arguments so that their form can be studied. In any
|
||||
cases, the appropriate type conversions should be put back in
|
||||
the tree that will get out of the constant folder. */
|
||||
STRIP_NOPS (op);
|
||||
|
||||
if (i == 0)
|
||||
arg0 = op;
|
||||
else if (i == 1)
|
||||
arg1 = op;
|
||||
if (op1)
|
||||
{
|
||||
arg1 = op1;
|
||||
STRIP_NOPS (arg1);
|
||||
}
|
||||
|
||||
switch (code)
|
||||
@@ -7078,7 +7075,7 @@ fold_ternary (tree expr)
|
||||
so all simple results must be passed through pedantic_non_lvalue. */
|
||||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||||
{
|
||||
tem = TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1));
|
||||
tem = integer_zerop (arg0) ? op2 : op1;
|
||||
/* Only optimize constant conditions when the selected branch
|
||||
has the same type as the COND_EXPR. This avoids optimizing
|
||||
away "c ? x : throw", where the throw has a void type. */
|
||||
@@ -7087,7 +7084,7 @@ fold_ternary (tree expr)
|
||||
return pedantic_non_lvalue (tem);
|
||||
return t;
|
||||
}
|
||||
if (operand_equal_p (arg1, TREE_OPERAND (t, 2), 0))
|
||||
if (operand_equal_p (arg1, op2, 0))
|
||||
return pedantic_omit_one_operand (type, arg1, arg0);
|
||||
|
||||
/* If we have A op B ? A : C, we may be able to convert this to a
|
||||
@@ -7101,25 +7098,21 @@ fold_ternary (tree expr)
|
||||
arg1, TREE_OPERAND (arg0, 1))
|
||||
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
|
||||
{
|
||||
tem = fold_cond_expr_with_comparison (type, arg0,
|
||||
TREE_OPERAND (t, 1),
|
||||
TREE_OPERAND (t, 2));
|
||||
tem = fold_cond_expr_with_comparison (type, arg0, op1, op2);
|
||||
if (tem)
|
||||
return tem;
|
||||
}
|
||||
|
||||
if (COMPARISON_CLASS_P (arg0)
|
||||
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
|
||||
TREE_OPERAND (t, 2),
|
||||
op2,
|
||||
TREE_OPERAND (arg0, 1))
|
||||
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 2)))))
|
||||
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
|
||||
{
|
||||
tem = invert_truthvalue (arg0);
|
||||
if (COMPARISON_CLASS_P (tem))
|
||||
{
|
||||
tem = fold_cond_expr_with_comparison (type, tem,
|
||||
TREE_OPERAND (t, 2),
|
||||
TREE_OPERAND (t, 1));
|
||||
tem = fold_cond_expr_with_comparison (type, tem, op2, op1);
|
||||
if (tem)
|
||||
return tem;
|
||||
}
|
||||
@@ -7127,8 +7120,7 @@ fold_ternary (tree expr)
|
||||
|
||||
/* If the second operand is simpler than the third, swap them
|
||||
since that produces better jump optimization results. */
|
||||
if (tree_swap_operands_p (TREE_OPERAND (t, 1),
|
||||
TREE_OPERAND (t, 2), false))
|
||||
if (tree_swap_operands_p (op1, op2, false))
|
||||
{
|
||||
/* See if this can be inverted. If it can't, possibly because
|
||||
it was a floating-point inequality comparison, don't do
|
||||
@@ -7136,14 +7128,13 @@ fold_ternary (tree expr)
|
||||
tem = invert_truthvalue (arg0);
|
||||
|
||||
if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
|
||||
return fold (build3 (code, type, tem,
|
||||
TREE_OPERAND (t, 2), TREE_OPERAND (t, 1)));
|
||||
return fold (build3 (code, type, tem, op2, op1));
|
||||
}
|
||||
|
||||
/* Convert A ? 1 : 0 to simply A. */
|
||||
if (integer_onep (TREE_OPERAND (t, 1))
|
||||
&& integer_zerop (TREE_OPERAND (t, 2))
|
||||
/* If we try to convert TREE_OPERAND (t, 0) to our type, the
|
||||
if (integer_onep (op1)
|
||||
&& integer_zerop (op2)
|
||||
/* If we try to convert OP0 to our type, the
|
||||
call to fold will try to move the conversion inside
|
||||
a COND, which will recurse. In that case, the COND_EXPR
|
||||
is probably the best choice, so leave it alone. */
|
||||
@@ -7152,8 +7143,8 @@ fold_ternary (tree expr)
|
||||
|
||||
/* Convert A ? 0 : 1 to !A. This prefers the use of NOT_EXPR
|
||||
over COND_EXPR in cases such as floating point comparisons. */
|
||||
if (integer_zerop (TREE_OPERAND (t, 1))
|
||||
&& integer_onep (TREE_OPERAND (t, 2))
|
||||
if (integer_zerop (op1)
|
||||
&& integer_onep (op2)
|
||||
&& truth_value_p (TREE_CODE (arg0)))
|
||||
return pedantic_non_lvalue (fold_convert (type,
|
||||
invert_truthvalue (arg0)));
|
||||
@@ -7161,7 +7152,7 @@ fold_ternary (tree expr)
|
||||
/* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>). */
|
||||
if (TREE_CODE (arg0) == LT_EXPR
|
||||
&& integer_zerop (TREE_OPERAND (arg0, 1))
|
||||
&& integer_zerop (TREE_OPERAND (t, 2))
|
||||
&& integer_zerop (op2)
|
||||
&& (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1)))
|
||||
return fold_convert (type, fold (build2 (BIT_AND_EXPR,
|
||||
TREE_TYPE (tem), tem, arg1)));
|
||||
@@ -7170,7 +7161,7 @@ fold_ternary (tree expr)
|
||||
already handled above. */
|
||||
if (TREE_CODE (arg0) == BIT_AND_EXPR
|
||||
&& integer_onep (TREE_OPERAND (arg0, 1))
|
||||
&& integer_zerop (TREE_OPERAND (t, 2))
|
||||
&& integer_zerop (op2)
|
||||
&& integer_pow2p (arg1))
|
||||
{
|
||||
tree tem = TREE_OPERAND (arg0, 0);
|
||||
@@ -7187,7 +7178,7 @@ fold_ternary (tree expr)
|
||||
is probably obsolete because the first operand should be a
|
||||
truth value (that's why we have the two cases above), but let's
|
||||
leave it in until we can confirm this for all front-ends. */
|
||||
if (integer_zerop (TREE_OPERAND (t, 2))
|
||||
if (integer_zerop (op2)
|
||||
&& TREE_CODE (arg0) == NE_EXPR
|
||||
&& integer_zerop (TREE_OPERAND (arg0, 1))
|
||||
&& integer_pow2p (arg1)
|
||||
@@ -7198,13 +7189,13 @@ fold_ternary (tree expr)
|
||||
TREE_OPERAND (arg0, 0)));
|
||||
|
||||
/* Convert A ? B : 0 into A && B if A and B are truth values. */
|
||||
if (integer_zerop (TREE_OPERAND (t, 2))
|
||||
if (integer_zerop (op2)
|
||||
&& truth_value_p (TREE_CODE (arg0))
|
||||
&& truth_value_p (TREE_CODE (arg1)))
|
||||
return fold (build2 (TRUTH_ANDIF_EXPR, type, arg0, arg1));
|
||||
|
||||
/* Convert A ? B : 1 into !A || B if A and B are truth values. */
|
||||
if (integer_onep (TREE_OPERAND (t, 2))
|
||||
if (integer_onep (op2)
|
||||
&& truth_value_p (TREE_CODE (arg0))
|
||||
&& truth_value_p (TREE_CODE (arg1)))
|
||||
{
|
||||
@@ -7217,30 +7208,27 @@ fold_ternary (tree expr)
|
||||
/* Convert A ? 0 : B into !A && B if A and B are truth values. */
|
||||
if (integer_zerop (arg1)
|
||||
&& truth_value_p (TREE_CODE (arg0))
|
||||
&& truth_value_p (TREE_CODE (TREE_OPERAND (t, 2))))
|
||||
&& truth_value_p (TREE_CODE (op2)))
|
||||
{
|
||||
/* Only perform transformation if ARG0 is easily inverted. */
|
||||
tem = invert_truthvalue (arg0);
|
||||
if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
|
||||
return fold (build2 (TRUTH_ANDIF_EXPR, type, tem,
|
||||
TREE_OPERAND (t, 2)));
|
||||
return fold (build2 (TRUTH_ANDIF_EXPR, type, tem, op2));
|
||||
}
|
||||
|
||||
/* Convert A ? 1 : B into A || B if A and B are truth values. */
|
||||
if (integer_onep (arg1)
|
||||
&& truth_value_p (TREE_CODE (arg0))
|
||||
&& truth_value_p (TREE_CODE (TREE_OPERAND (t, 2))))
|
||||
return fold (build2 (TRUTH_ORIF_EXPR, type, arg0,
|
||||
TREE_OPERAND (t, 2)));
|
||||
&& truth_value_p (TREE_CODE (op2)))
|
||||
return fold (build2 (TRUTH_ORIF_EXPR, type, arg0, op2));
|
||||
|
||||
return t;
|
||||
|
||||
case CALL_EXPR:
|
||||
/* Check for a built-in function. */
|
||||
if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
|
||||
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
|
||||
== FUNCTION_DECL)
|
||||
&& DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
|
||||
if (TREE_CODE (op0) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (op0, 0)) == FUNCTION_DECL
|
||||
&& DECL_BUILT_IN (TREE_OPERAND (op0, 0)))
|
||||
{
|
||||
tree tmp = fold_builtin (t, false);
|
||||
if (tmp)
|
||||
|
||||
Reference in New Issue
Block a user