fold-const.c (fold_cond_expr_with_comparison): New function, extracted from fold.
2004-06-21 Paolo Bonzini <bonzini@gnu.org> * fold-const.c (fold_cond_expr_with_comparison): New function, extracted from fold. (fold): Extract code to fold A op B ? A : C, use it to fold A op B ? C : A. Really optimize A & N ? N : 0 where N is a power of two. Avoid relying on canonicalization and recursion for foldings of COND_EXPR to happen. From-SVN: r83428
This commit is contained in:
parent
992d907d5c
commit
2c486ea78c
@ -1,3 +1,13 @@
|
|||||||
|
2004-06-21 Paolo Bonzini <bonzini@gnu.org>
|
||||||
|
|
||||||
|
* fold-const.c (fold_cond_expr_with_comparison):
|
||||||
|
New function, extracted from fold.
|
||||||
|
(fold): Extract code to fold A op B ? A : C, use
|
||||||
|
it to fold A op B ? C : A. Really optimize
|
||||||
|
A & N ? N : 0 where N is a power of two. Avoid
|
||||||
|
relying on canonicalization and recursion for
|
||||||
|
foldings of COND_EXPR to happen.
|
||||||
|
|
||||||
2004-06-20 David Ayers <d.ayers@inode.at>
|
2004-06-20 David Ayers <d.ayers@inode.at>
|
||||||
|
|
||||||
* objc/objc-act.h (get_object_reference): Rename to
|
* objc/objc-act.h (get_object_reference): Rename to
|
||||||
|
513
gcc/fold-const.c
513
gcc/fold-const.c
@ -116,6 +116,7 @@ static tree build_range_check (tree, tree, int, tree, tree);
|
|||||||
static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree,
|
static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree,
|
||||||
tree);
|
tree);
|
||||||
static tree fold_range_test (tree);
|
static tree fold_range_test (tree);
|
||||||
|
static tree fold_cond_expr_with_comparison (tree, tree, tree);
|
||||||
static tree unextend (tree, int, int, tree);
|
static tree unextend (tree, int, int, tree);
|
||||||
static tree fold_truthop (enum tree_code, tree, tree, tree);
|
static tree fold_truthop (enum tree_code, tree, tree, tree);
|
||||||
static tree optimize_minmax_comparison (tree);
|
static tree optimize_minmax_comparison (tree);
|
||||||
@ -4088,6 +4089,234 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
|
|||||||
*pin_p = in_p, *plow = low, *phigh = high;
|
*pin_p = in_p, *plow = low, *phigh = high;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Subroutine of fold, looking inside expressions of the form
|
||||||
|
A op B ? A : C, where ARG0 is A op B and ARG2 is C. This
|
||||||
|
function is being used also to optimize A op B ? C : A, by
|
||||||
|
reversing the comparison first.
|
||||||
|
|
||||||
|
Return a folded expression whose code is not a COND_EXPR
|
||||||
|
anymore, or NULL_TREE if no folding opportunity is found. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
fold_cond_expr_with_comparison (tree type, tree arg0, tree arg2)
|
||||||
|
{
|
||||||
|
enum tree_code comp_code = TREE_CODE (arg0);
|
||||||
|
tree arg00 = TREE_OPERAND (arg0, 0);
|
||||||
|
tree arg01 = TREE_OPERAND (arg0, 1);
|
||||||
|
tree tem;
|
||||||
|
STRIP_NOPS (arg2);
|
||||||
|
|
||||||
|
/* If we have A op 0 ? A : -A, consider applying the following
|
||||||
|
transformations:
|
||||||
|
|
||||||
|
A == 0? A : -A same as -A
|
||||||
|
A != 0? A : -A same as A
|
||||||
|
A >= 0? A : -A same as abs (A)
|
||||||
|
A > 0? A : -A same as abs (A)
|
||||||
|
A <= 0? A : -A same as -abs (A)
|
||||||
|
A < 0? A : -A same as -abs (A)
|
||||||
|
|
||||||
|
None of these transformations work for modes with signed
|
||||||
|
zeros. If A is +/-0, the first two transformations will
|
||||||
|
change the sign of the result (from +0 to -0, or vice
|
||||||
|
versa). The last four will fix the sign of the result,
|
||||||
|
even though the original expressions could be positive or
|
||||||
|
negative, depending on the sign of A.
|
||||||
|
|
||||||
|
Note that all these transformations are correct if A is
|
||||||
|
NaN, since the two alternatives (A and -A) are also NaNs. */
|
||||||
|
if ((FLOAT_TYPE_P (TREE_TYPE (arg01))
|
||||||
|
? real_zerop (arg01)
|
||||||
|
: integer_zerop (arg01))
|
||||||
|
&& TREE_CODE (arg2) == NEGATE_EXPR
|
||||||
|
&& operand_equal_p (TREE_OPERAND (arg2, 0), arg00, 0))
|
||||||
|
switch (comp_code)
|
||||||
|
{
|
||||||
|
case EQ_EXPR:
|
||||||
|
return fold_convert (type, negate_expr (arg00));
|
||||||
|
case NE_EXPR:
|
||||||
|
return pedantic_non_lvalue (fold_convert (type, arg00));
|
||||||
|
case GE_EXPR:
|
||||||
|
case GT_EXPR:
|
||||||
|
if (TYPE_UNSIGNED (TREE_TYPE (arg00)))
|
||||||
|
arg00 = fold_convert (lang_hooks.types.signed_type
|
||||||
|
(TREE_TYPE (arg00)), arg00);
|
||||||
|
tem = fold (build1 (ABS_EXPR, TREE_TYPE (arg00), arg00));
|
||||||
|
return pedantic_non_lvalue (fold_convert (type, tem));
|
||||||
|
case LE_EXPR:
|
||||||
|
case LT_EXPR:
|
||||||
|
if (TYPE_UNSIGNED (TREE_TYPE (arg00)))
|
||||||
|
arg00 = fold_convert (lang_hooks.types.signed_type
|
||||||
|
(TREE_TYPE (arg00)), arg00);
|
||||||
|
tem = fold (build1 (ABS_EXPR, TREE_TYPE (arg00), arg00));
|
||||||
|
return negate_expr (fold_convert (type, tem));
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A != 0 ? A : 0 is simply A, unless A is -0. Likewise
|
||||||
|
A == 0 ? A : 0 is always 0 unless A is -0. Note that
|
||||||
|
both transformations are correct when A is NaN: A != 0
|
||||||
|
is then true, and A == 0 is false. */
|
||||||
|
|
||||||
|
if (integer_zerop (arg01) && integer_zerop (arg2))
|
||||||
|
{
|
||||||
|
if (comp_code == NE_EXPR)
|
||||||
|
return pedantic_non_lvalue (fold_convert (type, arg00));
|
||||||
|
else if (comp_code == EQ_EXPR)
|
||||||
|
return pedantic_non_lvalue (fold_convert (type, integer_zero_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try some transformations of A op B ? A : B.
|
||||||
|
|
||||||
|
A == B? A : B same as B
|
||||||
|
A != B? A : B same as A
|
||||||
|
A >= B? A : B same as max (A, B)
|
||||||
|
A > B? A : B same as max (B, A)
|
||||||
|
A <= B? A : B same as min (A, B)
|
||||||
|
A < B? A : B same as min (B, A)
|
||||||
|
|
||||||
|
As above, these transformations don't work in the presence
|
||||||
|
of signed zeros. For example, if A and B are zeros of
|
||||||
|
opposite sign, the first two transformations will change
|
||||||
|
the sign of the result. In the last four, the original
|
||||||
|
expressions give different results for (A=+0, B=-0) and
|
||||||
|
(A=-0, B=+0), but the transformed expressions do not.
|
||||||
|
|
||||||
|
The first two transformations are correct if either A or B
|
||||||
|
is a NaN. In the first transformation, the condition will
|
||||||
|
be false, and B will indeed be chosen. In the case of the
|
||||||
|
second transformation, the condition A != B will be true,
|
||||||
|
and A will be chosen.
|
||||||
|
|
||||||
|
The conversions to max() and min() are not correct if B is
|
||||||
|
a number and A is not. The conditions in the original
|
||||||
|
expressions will be false, so all four give B. The min()
|
||||||
|
and max() versions would give a NaN instead. */
|
||||||
|
if (operand_equal_for_comparison_p (arg01, arg2, arg00))
|
||||||
|
{
|
||||||
|
tree comp_op0 = arg00;
|
||||||
|
tree comp_op1 = arg01;
|
||||||
|
tree comp_type = TREE_TYPE (comp_op0);
|
||||||
|
|
||||||
|
/* Avoid adding NOP_EXPRs in case this is an lvalue. */
|
||||||
|
if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
|
||||||
|
{
|
||||||
|
comp_type = type;
|
||||||
|
comp_op0 = arg00;
|
||||||
|
comp_op1 = arg2;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (comp_code)
|
||||||
|
{
|
||||||
|
case EQ_EXPR:
|
||||||
|
return pedantic_non_lvalue (fold_convert (type, arg2));
|
||||||
|
case NE_EXPR:
|
||||||
|
return pedantic_non_lvalue (fold_convert (type, arg00));
|
||||||
|
case LE_EXPR:
|
||||||
|
case LT_EXPR:
|
||||||
|
/* In C++ a ?: expression can be an lvalue, so put the
|
||||||
|
operand which will be used if they are equal first
|
||||||
|
so that we can convert this back to the
|
||||||
|
corresponding COND_EXPR. */
|
||||||
|
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00))))
|
||||||
|
return pedantic_non_lvalue (
|
||||||
|
fold_convert (type, fold (build2 (MIN_EXPR, comp_type,
|
||||||
|
(comp_code == LE_EXPR
|
||||||
|
? comp_op0 : comp_op1),
|
||||||
|
(comp_code == LE_EXPR
|
||||||
|
? comp_op1 : comp_op0)))));
|
||||||
|
break;
|
||||||
|
case GE_EXPR:
|
||||||
|
case GT_EXPR:
|
||||||
|
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00))))
|
||||||
|
return pedantic_non_lvalue (
|
||||||
|
fold_convert (type, fold (build2 (MAX_EXPR, comp_type,
|
||||||
|
(comp_code == GE_EXPR
|
||||||
|
? comp_op0 : comp_op1),
|
||||||
|
(comp_code == GE_EXPR
|
||||||
|
? comp_op1 : comp_op0)))));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is A op C1 ? A : C2 with C1 and C2 constant integers,
|
||||||
|
we might still be able to simplify this. For example,
|
||||||
|
if C1 is one less or one more than C2, this might have started
|
||||||
|
out as a MIN or MAX and been transformed by this function.
|
||||||
|
Only good for INTEGER_TYPEs, because we need TYPE_MAX_VALUE. */
|
||||||
|
|
||||||
|
if (INTEGRAL_TYPE_P (type)
|
||||||
|
&& TREE_CODE (arg01) == INTEGER_CST
|
||||||
|
&& TREE_CODE (arg2) == INTEGER_CST)
|
||||||
|
switch (comp_code)
|
||||||
|
{
|
||||||
|
case EQ_EXPR:
|
||||||
|
/* We can replace A with C1 in this case. */
|
||||||
|
arg00 = fold_convert (type, arg01);
|
||||||
|
return fold (build3 (COND_EXPR, type, arg0, arg00, arg2));
|
||||||
|
|
||||||
|
case LT_EXPR:
|
||||||
|
/* If C1 is C2 + 1, this is min(A, C2). */
|
||||||
|
if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
|
||||||
|
OEP_ONLY_CONST)
|
||||||
|
&& operand_equal_p (arg01,
|
||||||
|
const_binop (PLUS_EXPR, arg2,
|
||||||
|
integer_one_node, 0),
|
||||||
|
OEP_ONLY_CONST))
|
||||||
|
return pedantic_non_lvalue (fold (build2 (MIN_EXPR,
|
||||||
|
type, arg00, arg2)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LE_EXPR:
|
||||||
|
/* If C1 is C2 - 1, this is min(A, C2). */
|
||||||
|
if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
|
||||||
|
OEP_ONLY_CONST)
|
||||||
|
&& operand_equal_p (arg01,
|
||||||
|
const_binop (MINUS_EXPR, arg2,
|
||||||
|
integer_one_node, 0),
|
||||||
|
OEP_ONLY_CONST))
|
||||||
|
return pedantic_non_lvalue (fold (build2 (MIN_EXPR,
|
||||||
|
type, arg00, arg2)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GT_EXPR:
|
||||||
|
/* If C1 is C2 - 1, this is max(A, C2). */
|
||||||
|
if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
|
||||||
|
OEP_ONLY_CONST)
|
||||||
|
&& operand_equal_p (arg01,
|
||||||
|
const_binop (MINUS_EXPR, arg2,
|
||||||
|
integer_one_node, 0),
|
||||||
|
OEP_ONLY_CONST))
|
||||||
|
return pedantic_non_lvalue (fold (build2 (MAX_EXPR,
|
||||||
|
type, arg00, arg2)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GE_EXPR:
|
||||||
|
/* If C1 is C2 + 1, this is max(A, C2). */
|
||||||
|
if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
|
||||||
|
OEP_ONLY_CONST)
|
||||||
|
&& operand_equal_p (arg01,
|
||||||
|
const_binop (PLUS_EXPR, arg2,
|
||||||
|
integer_one_node, 0),
|
||||||
|
OEP_ONLY_CONST))
|
||||||
|
return pedantic_non_lvalue (fold (build2 (MAX_EXPR,
|
||||||
|
type, arg00, arg2)));
|
||||||
|
break;
|
||||||
|
case NE_EXPR:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef RANGE_TEST_NON_SHORT_CIRCUIT
|
#ifndef RANGE_TEST_NON_SHORT_CIRCUIT
|
||||||
#define RANGE_TEST_NON_SHORT_CIRCUIT (BRANCH_COST >= 2)
|
#define RANGE_TEST_NON_SHORT_CIRCUIT (BRANCH_COST >= 2)
|
||||||
@ -8325,227 +8554,33 @@ fold (tree expr)
|
|||||||
/* If we have A op B ? A : C, we may be able to convert this to a
|
/* If we have A op B ? A : C, we may be able to convert this to a
|
||||||
simpler expression, depending on the operation and the values
|
simpler expression, depending on the operation and the values
|
||||||
of B and C. Signed zeros prevent all of these transformations,
|
of B and C. Signed zeros prevent all of these transformations,
|
||||||
for reasons given above each one. */
|
for reasons given above each one.
|
||||||
|
|
||||||
|
Also try swapping the arguments and inverting the conditional. */
|
||||||
if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
|
if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
|
||||||
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
|
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
|
||||||
arg1, TREE_OPERAND (arg0, 1))
|
arg1, TREE_OPERAND (arg0, 1))
|
||||||
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
|
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
|
||||||
{
|
{
|
||||||
tree arg2 = TREE_OPERAND (t, 2);
|
tem = fold_cond_expr_with_comparison (type, arg0,
|
||||||
enum tree_code comp_code = TREE_CODE (arg0);
|
TREE_OPERAND (t, 2));
|
||||||
|
if (tem)
|
||||||
|
return tem;
|
||||||
|
}
|
||||||
|
|
||||||
STRIP_NOPS (arg2);
|
if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
|
||||||
|
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
|
||||||
/* If we have A op 0 ? A : -A, consider applying the following
|
TREE_OPERAND (t, 2),
|
||||||
transformations:
|
TREE_OPERAND (arg0, 1))
|
||||||
|
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 2)))))
|
||||||
A == 0? A : -A same as -A
|
{
|
||||||
A != 0? A : -A same as A
|
tem = invert_truthvalue (arg0);
|
||||||
A >= 0? A : -A same as abs (A)
|
if (TREE_CODE_CLASS (TREE_CODE (tem)) == '<')
|
||||||
A > 0? A : -A same as abs (A)
|
|
||||||
A <= 0? A : -A same as -abs (A)
|
|
||||||
A < 0? A : -A same as -abs (A)
|
|
||||||
|
|
||||||
None of these transformations work for modes with signed
|
|
||||||
zeros. If A is +/-0, the first two transformations will
|
|
||||||
change the sign of the result (from +0 to -0, or vice
|
|
||||||
versa). The last four will fix the sign of the result,
|
|
||||||
even though the original expressions could be positive or
|
|
||||||
negative, depending on the sign of A.
|
|
||||||
|
|
||||||
Note that all these transformations are correct if A is
|
|
||||||
NaN, since the two alternatives (A and -A) are also NaNs. */
|
|
||||||
if ((FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 1)))
|
|
||||||
? real_zerop (TREE_OPERAND (arg0, 1))
|
|
||||||
: integer_zerop (TREE_OPERAND (arg0, 1)))
|
|
||||||
&& TREE_CODE (arg2) == NEGATE_EXPR
|
|
||||||
&& operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0))
|
|
||||||
switch (comp_code)
|
|
||||||
{
|
|
||||||
case EQ_EXPR:
|
|
||||||
tem = fold_convert (TREE_TYPE (TREE_OPERAND (t, 1)), arg1);
|
|
||||||
tem = fold_convert (type, negate_expr (tem));
|
|
||||||
return pedantic_non_lvalue (tem);
|
|
||||||
case NE_EXPR:
|
|
||||||
return pedantic_non_lvalue (fold_convert (type, arg1));
|
|
||||||
case GE_EXPR:
|
|
||||||
case GT_EXPR:
|
|
||||||
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
|
|
||||||
arg1 = fold_convert (lang_hooks.types.signed_type
|
|
||||||
(TREE_TYPE (arg1)), arg1);
|
|
||||||
arg1 = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
|
|
||||||
return pedantic_non_lvalue (fold_convert (type, arg1));
|
|
||||||
case LE_EXPR:
|
|
||||||
case LT_EXPR:
|
|
||||||
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
|
|
||||||
arg1 = fold_convert (lang_hooks.types.signed_type
|
|
||||||
(TREE_TYPE (arg1)), arg1);
|
|
||||||
arg1 = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
|
|
||||||
arg1 = negate_expr (fold_convert (type, arg1));
|
|
||||||
return pedantic_non_lvalue (arg1);
|
|
||||||
default:
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A != 0 ? A : 0 is simply A, unless A is -0. Likewise
|
|
||||||
A == 0 ? A : 0 is always 0 unless A is -0. Note that
|
|
||||||
both transformations are correct when A is NaN: A != 0
|
|
||||||
is then true, and A == 0 is false. */
|
|
||||||
|
|
||||||
if (integer_zerop (TREE_OPERAND (arg0, 1)) && integer_zerop (arg2))
|
|
||||||
{
|
{
|
||||||
if (comp_code == NE_EXPR)
|
tem = fold_cond_expr_with_comparison (type, tem, arg1);
|
||||||
return pedantic_non_lvalue (fold_convert (type, arg1));
|
if (tem)
|
||||||
else if (comp_code == EQ_EXPR)
|
return tem;
|
||||||
return pedantic_non_lvalue (fold_convert (type, integer_zero_node));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try some transformations of A op B ? A : B.
|
|
||||||
|
|
||||||
A == B? A : B same as B
|
|
||||||
A != B? A : B same as A
|
|
||||||
A >= B? A : B same as max (A, B)
|
|
||||||
A > B? A : B same as max (B, A)
|
|
||||||
A <= B? A : B same as min (A, B)
|
|
||||||
A < B? A : B same as min (B, A)
|
|
||||||
|
|
||||||
As above, these transformations don't work in the presence
|
|
||||||
of signed zeros. For example, if A and B are zeros of
|
|
||||||
opposite sign, the first two transformations will change
|
|
||||||
the sign of the result. In the last four, the original
|
|
||||||
expressions give different results for (A=+0, B=-0) and
|
|
||||||
(A=-0, B=+0), but the transformed expressions do not.
|
|
||||||
|
|
||||||
The first two transformations are correct if either A or B
|
|
||||||
is a NaN. In the first transformation, the condition will
|
|
||||||
be false, and B will indeed be chosen. In the case of the
|
|
||||||
second transformation, the condition A != B will be true,
|
|
||||||
and A will be chosen.
|
|
||||||
|
|
||||||
The conversions to max() and min() are not correct if B is
|
|
||||||
a number and A is not. The conditions in the original
|
|
||||||
expressions will be false, so all four give B. The min()
|
|
||||||
and max() versions would give a NaN instead. */
|
|
||||||
if (operand_equal_for_comparison_p (TREE_OPERAND (arg0, 1),
|
|
||||||
arg2, TREE_OPERAND (arg0, 0)))
|
|
||||||
{
|
|
||||||
tree comp_op0 = TREE_OPERAND (arg0, 0);
|
|
||||||
tree comp_op1 = TREE_OPERAND (arg0, 1);
|
|
||||||
tree comp_type = TREE_TYPE (comp_op0);
|
|
||||||
|
|
||||||
/* Avoid adding NOP_EXPRs in case this is an lvalue. */
|
|
||||||
if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
|
|
||||||
{
|
|
||||||
comp_type = type;
|
|
||||||
comp_op0 = arg1;
|
|
||||||
comp_op1 = arg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (comp_code)
|
|
||||||
{
|
|
||||||
case EQ_EXPR:
|
|
||||||
return pedantic_non_lvalue (fold_convert (type, arg2));
|
|
||||||
case NE_EXPR:
|
|
||||||
return pedantic_non_lvalue (fold_convert (type, arg1));
|
|
||||||
case LE_EXPR:
|
|
||||||
case LT_EXPR:
|
|
||||||
/* In C++ a ?: expression can be an lvalue, so put the
|
|
||||||
operand which will be used if they are equal first
|
|
||||||
so that we can convert this back to the
|
|
||||||
corresponding COND_EXPR. */
|
|
||||||
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
|
|
||||||
return pedantic_non_lvalue (fold_convert
|
|
||||||
(type, fold (build2 (MIN_EXPR, comp_type,
|
|
||||||
(comp_code == LE_EXPR
|
|
||||||
? comp_op0 : comp_op1),
|
|
||||||
(comp_code == LE_EXPR
|
|
||||||
? comp_op1 : comp_op0)))));
|
|
||||||
break;
|
|
||||||
case GE_EXPR:
|
|
||||||
case GT_EXPR:
|
|
||||||
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
|
|
||||||
return pedantic_non_lvalue (fold_convert
|
|
||||||
(type, fold (build2 (MAX_EXPR, comp_type,
|
|
||||||
(comp_code == GE_EXPR
|
|
||||||
? comp_op0 : comp_op1),
|
|
||||||
(comp_code == GE_EXPR
|
|
||||||
? comp_op1 : comp_op0)))));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If this is A op C1 ? A : C2 with C1 and C2 constant integers,
|
|
||||||
we might still be able to simplify this. For example,
|
|
||||||
if C1 is one less or one more than C2, this might have started
|
|
||||||
out as a MIN or MAX and been transformed by this function.
|
|
||||||
Only good for INTEGER_TYPEs, because we need TYPE_MAX_VALUE. */
|
|
||||||
|
|
||||||
if (INTEGRAL_TYPE_P (type)
|
|
||||||
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
|
|
||||||
&& TREE_CODE (arg2) == INTEGER_CST)
|
|
||||||
switch (comp_code)
|
|
||||||
{
|
|
||||||
case EQ_EXPR:
|
|
||||||
/* We can replace A with C1 in this case. */
|
|
||||||
arg1 = fold_convert (type, TREE_OPERAND (arg0, 1));
|
|
||||||
return fold (build3 (code, type, TREE_OPERAND (t, 0), arg1,
|
|
||||||
TREE_OPERAND (t, 2)));
|
|
||||||
|
|
||||||
case LT_EXPR:
|
|
||||||
/* If C1 is C2 + 1, this is min(A, C2). */
|
|
||||||
if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
|
|
||||||
OEP_ONLY_CONST)
|
|
||||||
&& operand_equal_p (TREE_OPERAND (arg0, 1),
|
|
||||||
const_binop (PLUS_EXPR, arg2,
|
|
||||||
integer_one_node, 0),
|
|
||||||
OEP_ONLY_CONST))
|
|
||||||
return pedantic_non_lvalue
|
|
||||||
(fold (build2 (MIN_EXPR, type, arg1, arg2)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LE_EXPR:
|
|
||||||
/* If C1 is C2 - 1, this is min(A, C2). */
|
|
||||||
if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
|
|
||||||
OEP_ONLY_CONST)
|
|
||||||
&& operand_equal_p (TREE_OPERAND (arg0, 1),
|
|
||||||
const_binop (MINUS_EXPR, arg2,
|
|
||||||
integer_one_node, 0),
|
|
||||||
OEP_ONLY_CONST))
|
|
||||||
return pedantic_non_lvalue
|
|
||||||
(fold (build2 (MIN_EXPR, type, arg1, arg2)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GT_EXPR:
|
|
||||||
/* If C1 is C2 - 1, this is max(A, C2). */
|
|
||||||
if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
|
|
||||||
OEP_ONLY_CONST)
|
|
||||||
&& operand_equal_p (TREE_OPERAND (arg0, 1),
|
|
||||||
const_binop (MINUS_EXPR, arg2,
|
|
||||||
integer_one_node, 0),
|
|
||||||
OEP_ONLY_CONST))
|
|
||||||
return pedantic_non_lvalue
|
|
||||||
(fold (build2 (MAX_EXPR, type, arg1, arg2)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GE_EXPR:
|
|
||||||
/* If C1 is C2 + 1, this is max(A, C2). */
|
|
||||||
if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
|
|
||||||
OEP_ONLY_CONST)
|
|
||||||
&& operand_equal_p (TREE_OPERAND (arg0, 1),
|
|
||||||
const_binop (PLUS_EXPR, arg2,
|
|
||||||
integer_one_node, 0),
|
|
||||||
OEP_ONLY_CONST))
|
|
||||||
return pedantic_non_lvalue
|
|
||||||
(fold (build2 (MAX_EXPR, type, arg1, arg2)));
|
|
||||||
break;
|
|
||||||
case NE_EXPR:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
abort ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the second operand is simpler than the third, swap them
|
/* If the second operand is simpler than the third, swap them
|
||||||
@ -8581,9 +8616,34 @@ fold (tree expr)
|
|||||||
return pedantic_non_lvalue (fold_convert (type,
|
return pedantic_non_lvalue (fold_convert (type,
|
||||||
invert_truthvalue (arg0)));
|
invert_truthvalue (arg0)));
|
||||||
|
|
||||||
/* Look for expressions of the form A & 2 ? 2 : 0. The result of this
|
/* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>). */
|
||||||
operation is simply A & 2. */
|
if (TREE_CODE (arg0) == LT_EXPR
|
||||||
|
&& integer_zerop (TREE_OPERAND (arg0, 1))
|
||||||
|
&& integer_zerop (TREE_OPERAND (t, 2))
|
||||||
|
&& (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1)))
|
||||||
|
return fold_convert (type, fold (build2 (BIT_AND_EXPR,
|
||||||
|
TREE_TYPE (tem), tem, arg1)));
|
||||||
|
|
||||||
|
/* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N). A & 1 was
|
||||||
|
already handled above. */
|
||||||
|
if (TREE_CODE (arg0) == BIT_AND_EXPR
|
||||||
|
&& integer_onep (TREE_OPERAND (arg0, 1))
|
||||||
|
&& integer_zerop (TREE_OPERAND (t, 2))
|
||||||
|
&& integer_pow2p (arg1))
|
||||||
|
{
|
||||||
|
tree tem = TREE_OPERAND (arg0, 0);
|
||||||
|
STRIP_NOPS (tem);
|
||||||
|
if (TREE_CODE (tem) == RSHIFT_EXPR
|
||||||
|
&& (unsigned HOST_WIDE_INT) tree_log2 (arg1) ==
|
||||||
|
TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)))
|
||||||
|
return fold (build2 (BIT_AND_EXPR, type,
|
||||||
|
TREE_OPERAND (tem, 0), arg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A & N ? N : 0 is simply A & N if N is a power of two. This
|
||||||
|
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 (TREE_OPERAND (t, 2))
|
||||||
&& TREE_CODE (arg0) == NE_EXPR
|
&& TREE_CODE (arg0) == NE_EXPR
|
||||||
&& integer_zerop (TREE_OPERAND (arg0, 1))
|
&& integer_zerop (TREE_OPERAND (arg0, 1))
|
||||||
@ -8598,8 +8658,7 @@ fold (tree expr)
|
|||||||
if (integer_zerop (TREE_OPERAND (t, 2))
|
if (integer_zerop (TREE_OPERAND (t, 2))
|
||||||
&& truth_value_p (TREE_CODE (arg0))
|
&& truth_value_p (TREE_CODE (arg0))
|
||||||
&& truth_value_p (TREE_CODE (arg1)))
|
&& truth_value_p (TREE_CODE (arg1)))
|
||||||
return pedantic_non_lvalue (fold (build2 (TRUTH_ANDIF_EXPR, type,
|
return fold (build2 (TRUTH_ANDIF_EXPR, type, arg0, arg1));
|
||||||
arg0, arg1)));
|
|
||||||
|
|
||||||
/* Convert A ? B : 1 into !A || B if A and B are truth values. */
|
/* Convert A ? B : 1 into !A || B if A and B are truth values. */
|
||||||
if (integer_onep (TREE_OPERAND (t, 2))
|
if (integer_onep (TREE_OPERAND (t, 2))
|
||||||
@ -8609,10 +8668,28 @@ fold (tree expr)
|
|||||||
/* Only perform transformation if ARG0 is easily inverted. */
|
/* Only perform transformation if ARG0 is easily inverted. */
|
||||||
tem = invert_truthvalue (arg0);
|
tem = invert_truthvalue (arg0);
|
||||||
if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
|
if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
|
||||||
return pedantic_non_lvalue (fold (build2 (TRUTH_ORIF_EXPR, type,
|
return fold (build2 (TRUTH_ORIF_EXPR, type, tem, arg1));
|
||||||
tem, arg1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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))))
|
||||||
|
{
|
||||||
|
/* 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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)));
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
case COMPOUND_EXPR:
|
case COMPOUND_EXPR:
|
||||||
|
Loading…
Reference in New Issue
Block a user