Commit c779bea5 by Yury Gribov Committed by Yury Gribov

Remove useless floating point casts in comparisons.

2017-08-04  Yury Gribov  <tetra2005@gmail.com>

	PR tree-optimization/57371

gcc/
	* match.pd: New pattern.

gcc/testsuite/
	* c-c++-common/pr57371-1.c: New test.
	* c-c++-common/pr57371-2.c: New test.
	* c-c++-common/pr57371-3.c: New test.
	* c-c++-common/pr57371-4.c: New test.
	* gcc.dg/pr57371-5.c: New test.

From-SVN: r250877
parent e52341f1
2017-08-04 Yury Gribov <tetra2005@gmail.com>
PR tree-optimization/57371
* match.pd: New pattern.
2017-08-04 Marek Polacek <polacek@redhat.com>
PR middle-end/81695
......
......@@ -2899,6 +2899,80 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (! HONOR_NANS (@0))
(cmp @0 @1))))))
/* Optimize various special cases of (FTYPE) N CMP CST. */
(for cmp (lt le eq ne ge gt)
icmp (le le eq ne ge ge)
(simplify
(cmp (float @0) REAL_CST@1)
(if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (@1))
&& ! DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@1)))
(with
{
tree itype = TREE_TYPE (@0);
signop isign = TYPE_SIGN (itype);
format_helper fmt (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@1))));
const REAL_VALUE_TYPE *cst = TREE_REAL_CST_PTR (@1);
/* Be careful to preserve any potential exceptions due to
NaNs. qNaNs are ok in == or != context.
TODO: relax under -fno-trapping-math or
-fno-signaling-nans. */
bool exception_p
= real_isnan (cst) && (cst->signalling
|| (cmp != EQ_EXPR || cmp != NE_EXPR));
/* INT?_MIN is power-of-two so it takes
only one mantissa bit. */
bool signed_p = isign == SIGNED;
bool itype_fits_ftype_p
= TYPE_PRECISION (itype) - signed_p <= significand_size (fmt);
}
/* TODO: allow non-fitting itype and SNaNs when
-fno-trapping-math. */
(if (itype_fits_ftype_p && ! exception_p)
(with
{
REAL_VALUE_TYPE imin, imax;
real_from_integer (&imin, fmt, wi::min_value (itype), isign);
real_from_integer (&imax, fmt, wi::max_value (itype), isign);
REAL_VALUE_TYPE icst;
if (cmp == GT_EXPR || cmp == GE_EXPR)
real_ceil (&icst, fmt, cst);
else if (cmp == LT_EXPR || cmp == LE_EXPR)
real_floor (&icst, fmt, cst);
else
real_trunc (&icst, fmt, cst);
bool cst_int_p = real_identical (&icst, cst);
bool overflow_p = false;
wide_int icst_val
= real_to_integer (&icst, &overflow_p, TYPE_PRECISION (itype));
}
(switch
/* Optimize cases when CST is outside of ITYPE's range. */
(if (real_compare (LT_EXPR, cst, &imin))
{ constant_boolean_node (cmp == GT_EXPR || cmp == GE_EXPR || cmp == NE_EXPR,
type); })
(if (real_compare (GT_EXPR, cst, &imax))
{ constant_boolean_node (cmp == LT_EXPR || cmp == LE_EXPR || cmp == NE_EXPR,
type); })
/* Remove cast if CST is an integer representable by ITYPE. */
(if (cst_int_p)
(cmp @0 { gcc_assert (!overflow_p);
wide_int_to_tree (itype, icst_val); })
)
/* When CST is fractional, optimize
(FTYPE) N == CST -> 0
(FTYPE) N != CST -> 1. */
(if (cmp == EQ_EXPR || cmp == NE_EXPR)
{ constant_boolean_node (cmp == NE_EXPR, type); })
/* Otherwise replace with sensible integer constant. */
(with
{
gcc_checking_assert (!overflow_p);
}
(icmp @0 { wide_int_to_tree (itype, icst_val); })))))))))
/* Fold A /[ex] B CMP C to A CMP B * C. */
(for cmp (eq ne)
(simplify
......
2017-08-04 Yury Gribov <tetra2005@gmail.com>
PR tree-optimization/57371
* c-c++-common/pr57371-1.c: New test.
* c-c++-common/pr57371-2.c: New test.
* c-c++-common/pr57371-3.c: New test.
* c-c++-common/pr57371-4.c: New test.
* gcc.dg/pr57371-5.c: New test.
2017-08-04 Carl Love <cel@us.ibm.com>
* gcc.target/powerpc/builtins-3.c: Remove ISA 3.0 word variant
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-original" } */
#include <limits.h>
/* Original testcase from PR. */
int foo1 (short x) {
return (double) x != 0;
/* { dg-final { scan-tree-dump "return (<retval> = )?x != 0" "original" } } */
}
int foo2 (short x) {
return (float) x != 0;
/* { dg-final { scan-tree-dump "return (<retval> = )?x != 0" "original" } } */
}
int foo3 (int x) {
return (double) x != 0;
/* { dg-final { scan-tree-dump "return (<retval> = )?x != 0" "original" } } */
}
/* Tests when RHS is within range of integer type. */
void in_range (unsigned short x)
{
{
volatile int in_range_1;
in_range_1 = (float) x > 100.0f;
/* { dg-final { scan-tree-dump "in_range_1 = x > 100" "original" } } */
}
{
volatile int in_range_2;
in_range_2 = (float) x < 100.0f;
/* { dg-final { scan-tree-dump "in_range_2 = x <= 99" "original" } } */
}
{
volatile int in_range_3;
in_range_3 = (float) x > 100.5f;
/* { dg-final { scan-tree-dump "in_range_3 = x (>= 101|> 100)" "original" } } */
}
{
volatile int in_range_4;
in_range_4 = (float) x < 100.5f;
/* { dg-final { scan-tree-dump "in_range_4 = x <= 100" "original" } } */
}
{
volatile int in_range_5;
in_range_5 = (float) x == 100.0f;
/* { dg-final { scan-tree-dump "in_range_5 = x == 100" "original" } } */
}
{
volatile int in_range_6;
in_range_6 = (float) x != 100.0f;
/* { dg-final { scan-tree-dump "in_range_6 = x != 100" "original" } } */
}
{
volatile int in_range_7;
in_range_7 = (float) x == 100.5f;
/* { dg-final { scan-tree-dump "in_range_7 = 0" "original" } } */
}
{
volatile int in_range_8;
in_range_8 = (float) x != 100.5f;
/* { dg-final { scan-tree-dump "in_range_8 = 1" "original" } } */
}
}
/* Tests for cases where RHS is out of range of integer type. */
void out_range (unsigned short x)
{
{
volatile int out_range_1;
out_range_1 = (float) x > -100.5f;
/* { dg-final { scan-tree-dump "out_range_1 = 1" "original" } } */
}
{
volatile int out_range_2;
out_range_2 = (float) x >= -100.5f;
/* { dg-final { scan-tree-dump "out_range_2 = 1" "original" } } */
}
{
volatile int out_range_3;
out_range_3 = (float) x < -100.5f;
/* { dg-final { scan-tree-dump "out_range_3 = 0" "original" } } */
}
{
volatile int out_range_4;
out_range_4 = (float) x <= -100.5f;
/* { dg-final { scan-tree-dump "out_range_4 = 0" "original" } } */
}
{
volatile int out_range_5;
out_range_5 = (float) x == -100.5f;
/* { dg-final { scan-tree-dump "out_range_5 = 0" "original" } } */
}
{
volatile int out_range_6;
out_range_6 = (float) x != -100.5f;
/* { dg-final { scan-tree-dump "out_range_6 = 1" "original" } } */
}
}
/* Tests when RHS is at boundary of integer type. */
void lo_bounds (unsigned short x)
{
{
volatile int lo_bounds_1;
lo_bounds_1 = (float) x > 0x0;
/* { dg-final { scan-tree-dump "lo_bounds_1 = x (>|!=) 0" "original" } } */
}
{
volatile int lo_bounds_2;
lo_bounds_2 = (float) x >= 0x0;
/* { dg-final { scan-tree-dump "lo_bounds_2 = 1" "original" } } */
}
{
volatile int lo_bounds_3;
lo_bounds_3 = (float) x < 0x0;
/* { dg-final { scan-tree-dump "lo_bounds_3 = 0" "original" } } */
}
{
volatile int lo_bounds_4;
lo_bounds_4 = (float) x <= 0x0;
/* { dg-final { scan-tree-dump "lo_bounds_4 = x (<=|==) 0" "original" } } */
}
{
volatile int lo_bounds_5;
lo_bounds_5 = (float) x > 0x0 - 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_5 = 1" "original" } } */
}
{
volatile int lo_bounds_6;
lo_bounds_6 = (float) x >= 0x0 - 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_6 = 1" "original" } } */
}
{
volatile int lo_bounds_7;
lo_bounds_7 = (float) x < 0x0 - 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_7 = 0" "original" } } */
}
{
volatile int lo_bounds_8;
lo_bounds_8 = (float) x <= 0x0 - 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_8 = 0" "original" } } */
}
{
volatile int lo_bounds_9;
lo_bounds_9 = (float) x > 0x0 + 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_9 = x (>= 1|!= 0)" "original" } } */
}
{
volatile int lo_bounds_10;
lo_bounds_10 = (float) x >= 0x0 + 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_10 = x (>= 1|!= 0)" "original" } } */
}
{
volatile int lo_bounds_11;
lo_bounds_11 = (float) x < 0x0 + 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_11 = x (<=|==) 0" "original" } } */
}
{
volatile int lo_bounds_12;
lo_bounds_12 = (float) x <= 0x0 + 0.5f;
/* { dg-final { scan-tree-dump "lo_bounds_12 = x (<=|==) 0" "original" } } */
}
}
void hi_bounds (unsigned short x)
{
{
volatile int hi_bounds_1;
hi_bounds_1 = (float) x > USHRT_MAX;
/* { dg-final { scan-tree-dump "hi_bounds_1 = 0" "original" } } */
}
{
volatile int hi_bounds_2;
hi_bounds_2 = (float) x >= USHRT_MAX;
/* { dg-final { scan-tree-dump "hi_bounds_2 = x (>=|==) 65535" "original" } } */
}
{
volatile int hi_bounds_3;
hi_bounds_3 = (float) x < USHRT_MAX;
/* { dg-final { scan-tree-dump "hi_bounds_3 = x (<|!=) 65535" "original" } } */
}
{
volatile int hi_bounds_4;
hi_bounds_4 = (float) x <= USHRT_MAX;
/* { dg-final { scan-tree-dump "hi_bounds_4 = 1" "original" } } */
}
{
volatile int hi_bounds_5;
hi_bounds_5 = (float) x > USHRT_MAX - 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_5 = x (>=|==) 65535" "original" } } */
}
{
volatile int hi_bounds_6;
hi_bounds_6 = (float) x >= USHRT_MAX - 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_6 = x (>=|==) 65535" "original" } } */
}
{
volatile int hi_bounds_7;
hi_bounds_7 = (float) x < USHRT_MAX - 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_7 = x (<= 65534|!= 65535)" "original" } } */
}
{
volatile int hi_bounds_8;
hi_bounds_8 = (float) x <= USHRT_MAX - 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_8 = x (<= 65534|!= 65535)" "original" } } */
}
{
volatile int hi_bounds_9;
hi_bounds_9 = (float) x > USHRT_MAX + 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_9 = 0" "original" } } */
}
{
volatile int hi_bounds_10;
hi_bounds_10 = (float) x >= USHRT_MAX + 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_10 = 0" "original" } } */
}
{
volatile int hi_bounds_11;
hi_bounds_11 = (float) x < USHRT_MAX + 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_11 = 1" "original" } } */
}
{
volatile int hi_bounds_12;
hi_bounds_12 = (float) x <= USHRT_MAX + 0.5f;
/* { dg-final { scan-tree-dump "hi_bounds_12 = 1" "original" } } */
}
}
/* Tests with non-finite float consts. */
void nonfinite (unsigned short x)
{
#define INFINITY __builtin_inff ()
{
volatile int nonfinite_1;
nonfinite_1 = (float) x > INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_1 = 0" "original" } } */
}
{
volatile int nonfinite_2;
nonfinite_2 = (float) x >= INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_2 = 0" "original" } } */
}
{
volatile int nonfinite_3;
nonfinite_3 = (float) x < INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_3 = 1" "original" } } */
}
{
volatile int nonfinite_4;
nonfinite_4 = (float) x <= INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_4 = 1" "original" } } */
}
{
volatile int nonfinite_5;
nonfinite_5 = (float) x > -INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_5 = 1" "original" } } */
}
{
volatile int nonfinite_6;
nonfinite_6 = (float) x >= -INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_6 = 1" "original" } } */
}
{
volatile int nonfinite_7;
nonfinite_7 = (float) x < -INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_7 = 0" "original" } } */
}
{
volatile int nonfinite_8;
nonfinite_8 = (float) x <= -INFINITY;
/* { dg-final { scan-tree-dump "nonfinite_8 = 0" "original" } } */
}
#define QNAN __builtin_nanf ("0")
/* Even for qNaNs, only == and != are quiet. */
{
volatile int nonfinite_9;
nonfinite_9 = (float) x == QNAN;
/* { dg-final { scan-tree-dump "nonfinite_9 = 0" "original" } } */
}
{
volatile int nonfinite_10;
nonfinite_10 = (float) x != QNAN;
/* { dg-final { scan-tree-dump "nonfinite_10 = 1" "original" } } */
}
}
/* { dg-final { scan-tree-dump-not "\\(float\\)" "original" } } */
/* { dg-final { scan-tree-dump-not "\\(double\\)" "original" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized" } */
/* We can not get rid of comparison in tests below because of
potential inexact exception.
TODO: enable when -fno-trapping-math. */
int foo1(int x) {
return (float) x != 0;
/* { dg-final { scan-tree-dump "\\(float\\)" "optimized" } } */
}
int foo2(long long x) {
/* { dg-final { scan-tree-dump "\\(double\\)" "optimized" } } */
return (double) x != 0;
}
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized" } */
/* { dg-require-effective-target int128 } */
/* We can not get rid of comparison in tests below because of
potential overflow exception.
TODO: enable when -fno-trapping-math. */
int foo(__int128_t x) {
/* { dg-final { scan-tree-dump "\\(float\\)" "optimized" } } */
return (float) x != 0;
}
/* { dg-do compile } */
/* { dg-options "-O -fsignaling-nans -fdump-tree-original" } */
/* We can not get rid of comparison in tests below because of
pending NaN exceptions.
TODO: avoid under -fno-trapping-math. */
#define QNAN __builtin_nanf ("0")
#define SNAN __builtin_nansf ("0")
void nonfinite(unsigned short x) {
{
volatile int nonfinite_1;
nonfinite_1 = (float) x > QNAN;
/* { dg-final { scan-tree-dump "nonfinite_1 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_2;
nonfinite_2 = (float) x >= QNAN;
/* { dg-final { scan-tree-dump "nonfinite_2 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_3;
nonfinite_3 = (float) x < QNAN;
/* { dg-final { scan-tree-dump "nonfinite_3 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_4;
nonfinite_4 = (float) x <= QNAN;
/* { dg-final { scan-tree-dump "nonfinite_4 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_5;
nonfinite_5 = (float) x > SNAN;
/* { dg-final { scan-tree-dump "nonfinite_5 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_6;
nonfinite_6 = (float) x >= SNAN;
/* { dg-final { scan-tree-dump "nonfinite_6 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_7;
nonfinite_7 = (float) x < SNAN;
/* { dg-final { scan-tree-dump "nonfinite_7 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_8;
nonfinite_8 = (float) x <= SNAN;
/* { dg-final { scan-tree-dump "nonfinite_8 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_9;
nonfinite_9 = (float) x == SNAN;
/* { dg-final { scan-tree-dump "nonfinite_9 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_10;
nonfinite_10 = (float) x != SNAN;
/* { dg-final { scan-tree-dump "nonfinite_10 = \\(float\\)" "original" } } */
}
}
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized" } */
/* { dg-require-effective-target dfp } */
/* We do not support DFPs. */
int foo(short x) {
/* { dg-final { scan-tree-dump "\\(_Decimal32\\)" "optimized" } } */
return (_Decimal32) x != 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment