match.pd: Add new pattern: (cond (cmp (convert?
* match.pd: Add new pattern: (cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2). gcc/testsuite * gcc.dg/fold-bopcond-1.c: New test. * gcc.dg/fold-bopcond-2.c: New test. From-SVN: r243180
This commit is contained in:
parent
d313d52cd5
commit
714445ae04
@ -1,3 +1,8 @@
|
||||
2016-12-02 Bin Cheng <bin.cheng@arm.com>
|
||||
|
||||
* match.pd: Add new pattern:
|
||||
(cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2).
|
||||
|
||||
2016-12-02 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
* diagnostic.c (diagnostic_report_diagnostic): Remove extraneous
|
||||
|
100
gcc/match.pd
100
gcc/match.pd
@ -2038,6 +2038,106 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
|
||||
(convert (cond (eq @1 (convert @3))
|
||||
(convert:from_type @3) (convert:from_type @2)))))))))
|
||||
|
||||
/* (cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2) if:
|
||||
|
||||
1) OP is PLUS or MINUS.
|
||||
2) CMP is LT, LE, GT or GE.
|
||||
3) C3 == (C1 op C2), and computation doesn't have undefined behavior.
|
||||
|
||||
This pattern also handles special cases like:
|
||||
|
||||
A) Operand x is a unsigned to signed type conversion and c1 is
|
||||
integer zero. In this case,
|
||||
(signed type)x < 0 <=> x > MAX_VAL(signed type)
|
||||
(signed type)x >= 0 <=> x <= MAX_VAL(signed type)
|
||||
B) Const c1 may not equal to (C3 op' C2). In this case we also
|
||||
check equality for (c1+1) and (c1-1) by adjusting comparison
|
||||
code.
|
||||
|
||||
TODO: Though signed type is handled by this pattern, it cannot be
|
||||
simplified at the moment because C standard requires additional
|
||||
type promotion. In order to match&simplify it here, the IR needs
|
||||
to be cleaned up by other optimizers, i.e, VRP. */
|
||||
(for op (plus minus)
|
||||
(for cmp (lt le gt ge)
|
||||
(simplify
|
||||
(cond (cmp (convert? @X) INTEGER_CST@1) (op @X INTEGER_CST@2) INTEGER_CST@3)
|
||||
(with { tree from_type = TREE_TYPE (@X), to_type = TREE_TYPE (@1); }
|
||||
(if (types_match (from_type, to_type)
|
||||
/* Check if it is special case A). */
|
||||
|| (TYPE_UNSIGNED (from_type)
|
||||
&& !TYPE_UNSIGNED (to_type)
|
||||
&& TYPE_PRECISION (from_type) == TYPE_PRECISION (to_type)
|
||||
&& integer_zerop (@1)
|
||||
&& (cmp == LT_EXPR || cmp == GE_EXPR)))
|
||||
(with
|
||||
{
|
||||
bool overflow = false;
|
||||
enum tree_code code, cmp_code = cmp;
|
||||
wide_int real_c1, c1 = @1, c2 = @2, c3 = @3;
|
||||
signop sgn = TYPE_SIGN (from_type);
|
||||
|
||||
/* Handle special case A), given x of unsigned type:
|
||||
((signed type)x < 0) <=> (x > MAX_VAL(signed type))
|
||||
((signed type)x >= 0) <=> (x <= MAX_VAL(signed type)) */
|
||||
if (!types_match (from_type, to_type))
|
||||
{
|
||||
if (cmp_code == LT_EXPR)
|
||||
cmp_code = GT_EXPR;
|
||||
if (cmp_code == GE_EXPR)
|
||||
cmp_code = LE_EXPR;
|
||||
c1 = wi::max_value (to_type);
|
||||
}
|
||||
/* To simplify this pattern, we require c3 = (c1 op c2). Here we
|
||||
compute (c3 op' c2) and check if it equals to c1 with op' being
|
||||
the inverted operator of op. Make sure overflow doesn't happen
|
||||
if it is undefined. */
|
||||
if (op == PLUS_EXPR)
|
||||
real_c1 = wi::sub (c3, c2, sgn, &overflow);
|
||||
else
|
||||
real_c1 = wi::add (c3, c2, sgn, &overflow);
|
||||
|
||||
code = cmp_code;
|
||||
if (!overflow || !TYPE_OVERFLOW_UNDEFINED (from_type))
|
||||
{
|
||||
/* Check if c1 equals to real_c1. Boundary condition is handled
|
||||
by adjusting comparison operation if necessary. */
|
||||
if (!wi::cmp (wi::sub (real_c1, 1, sgn, &overflow), c1, sgn)
|
||||
&& !overflow)
|
||||
{
|
||||
/* X <= Y - 1 equals to X < Y. */
|
||||
if (cmp_code == LE_EXPR)
|
||||
code = LT_EXPR;
|
||||
/* X > Y - 1 equals to X >= Y. */
|
||||
if (cmp_code == GT_EXPR)
|
||||
code = GE_EXPR;
|
||||
}
|
||||
if (!wi::cmp (wi::add (real_c1, 1, sgn, &overflow), c1, sgn)
|
||||
&& !overflow)
|
||||
{
|
||||
/* X < Y + 1 equals to X <= Y. */
|
||||
if (cmp_code == LT_EXPR)
|
||||
code = LE_EXPR;
|
||||
/* X >= Y + 1 equals to X > Y. */
|
||||
if (cmp_code == GE_EXPR)
|
||||
code = GT_EXPR;
|
||||
}
|
||||
if (code != cmp_code || !wi::cmp (real_c1, c1, sgn))
|
||||
{
|
||||
if (cmp_code == LT_EXPR || cmp_code == LE_EXPR)
|
||||
code = MIN_EXPR;
|
||||
if (cmp_code == GT_EXPR || cmp_code == GE_EXPR)
|
||||
code = MAX_EXPR;
|
||||
}
|
||||
}
|
||||
}
|
||||
(if (code == MAX_EXPR)
|
||||
(op (max @X { wide_int_to_tree (from_type, real_c1); })
|
||||
{ wide_int_to_tree (from_type, c2); })
|
||||
(if (code == MIN_EXPR)
|
||||
(op (min @X { wide_int_to_tree (from_type, real_c1); })
|
||||
{ wide_int_to_tree (from_type, c2); })))))))))
|
||||
|
||||
(for cnd (cond vec_cond)
|
||||
/* A ? B : (A ? X : C) -> A ? B : C. */
|
||||
(simplify
|
||||
|
@ -1,3 +1,8 @@
|
||||
2016-12-02 Bin Cheng <bin.cheng@arm.com>
|
||||
|
||||
* gcc.dg/fold-bopcond-1.c: New test.
|
||||
* gcc.dg/fold-bopcond-2.c: New test.
|
||||
|
||||
2016-12-02 Dominik Vogt <vogt@linux.vnet.ibm.com>
|
||||
|
||||
* gcc.target/s390/md/setmem_long-1.c: Fix test.
|
||||
|
48
gcc/testsuite/gcc.dg/fold-bopcond-1.c
Normal file
48
gcc/testsuite/gcc.dg/fold-bopcond-1.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -fdump-tree-ifcvt" } */
|
||||
|
||||
int foo1 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x <= 32768 ? x + 32768 : 0);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int foo2 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x < 32768 ? x + 32768 : 0);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int foo3 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x < 1000 ? x - 1000 : 0);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int foo4 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x <= 2 ? x + 999 : 1001);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "MIN_EXPR " 4 "ifcvt" } } */
|
48
gcc/testsuite/gcc.dg/fold-bopcond-2.c
Normal file
48
gcc/testsuite/gcc.dg/fold-bopcond-2.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -fdump-tree-ifcvt" } */
|
||||
|
||||
int foo1 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x >= 32768 ? x - 32768 : 0);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int foo2 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x > 32768 ? x - 32768 : 0);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int foo3 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x > 1000 ? x - 1000 : 0);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int foo4 (unsigned short a[], unsigned int x)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
x = a[i];
|
||||
a[i] = (unsigned short)(x >= 2 ? x - 32768 : 32770);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "MAX_EXPR " 4 "ifcvt" } } */
|
Loading…
Reference in New Issue
Block a user