From e41ec71bd97a1a8eaef40695c7ae9b7f4b1fc819 Mon Sep 17 00:00:00 2001 From: Yury Gribov Date: Fri, 12 Oct 2018 20:35:20 +0000 Subject: [PATCH] Add pattern to remove useless float casts in comparisons. PR middle-end/81376 gcc/ * real.c (format_helper::can_represent_integral_type_p): New function * real.h (format_helper::can_represent_integral_type_p): Ditto. * match.pd: New pattern. gcc/testsuite/ * c-c++-common/pr81376.c: New test. * gcc.target/i386/387-ficom-2.c: Update test. * gcc.target/i386/387-ficom-2.c: Ditto. From-SVN: r265131 --- gcc/ChangeLog | 7 +++ gcc/match.pd | 35 ++++++++++++--- gcc/real.c | 13 ++++++ gcc/real.h | 1 + gcc/testsuite/ChangeLog | 7 +++ gcc/testsuite/c-c++-common/pr81376.c | 48 +++++++++++++++++++++ gcc/testsuite/gcc.target/i386/387-ficom-1.c | 5 ++- gcc/testsuite/gcc.target/i386/387-ficom-2.c | 5 ++- 8 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/pr81376.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1cc85d8f23e..465de40d61e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2018-10-12 Yury Gribov + + PR middle-end/81376 + * real.c (format_helper::can_represent_integral_type_p): New function + * real.h (format_helper::can_represent_integral_type_p): Ditto. + * match.pd: New pattern. + 2018-10-12 Alexandre Oliva * configure.ac: Introduce --enable-large-address-aware diff --git a/gcc/match.pd b/gcc/match.pd index 94fbab841f5..b36d7ccb5dc 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -3400,6 +3400,32 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (! HONOR_NANS (@0)) (cmp @0 @1)))))) +/* Optimize various special cases of (FTYPE) N CMP (FTYPE) M. */ +(for cmp (tcc_comparison) + (simplify + (cmp (float@0 @1) (float @2)) + (if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (@0)) + && ! DECIMAL_FLOAT_TYPE_P (TREE_TYPE (@0))) + (with + { + format_helper fmt (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (@0)))); + tree type1 = TREE_TYPE (@1); + bool type1_signed_p = TYPE_SIGN (type1) == SIGNED; + tree type2 = TREE_TYPE (@2); + bool type2_signed_p = TYPE_SIGN (type2) == SIGNED; + } + (if (fmt.can_represent_integral_type_p (type1) + && fmt.can_represent_integral_type_p (type2)) + (if (TYPE_PRECISION (type1) > TYPE_PRECISION (type2) + && type1_signed_p >= type2_signed_p) + (cmp @1 (convert @2)) + (if (TYPE_PRECISION (type1) < TYPE_PRECISION (type2) + && type1_signed_p <= type2_signed_p) + (cmp (convert:type2 @1) @2) + (if (TYPE_PRECISION (type1) == TYPE_PRECISION (type2) + && type1_signed_p == type2_signed_p) + (cmp @1 @2))))))))) + /* Optimize various special cases of (FTYPE) N CMP CST. */ (for cmp (lt le eq ne ge gt) icmp (le le eq ne ge ge) @@ -3410,7 +3436,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (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 @@ -3420,17 +3445,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) 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) + (if (fmt.can_represent_integral_type_p (itype) && ! exception_p) (with { + signop isign = TYPE_SIGN (itype); 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); diff --git a/gcc/real.c b/gcc/real.c index 51f8fd5b3ae..0e2da25c2d1 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -5176,6 +5176,19 @@ get_max_float (const struct real_format *fmt, char *buf, size_t len) gcc_assert (strlen (buf) < len); } +/* True if all values of integral type can be represented + by this floating-point type exactly. */ + +bool format_helper::can_represent_integral_type_p (tree type) const +{ + gcc_assert (! decimal_p () && INTEGRAL_TYPE_P (type)); + + /* INT?_MIN is power-of-two so it takes + only one mantissa bit. */ + bool signed_p = TYPE_SIGN (type) == SIGNED; + return TYPE_PRECISION (type) - signed_p <= significand_size (*this); +} + /* True if mode M has a NaN representation and the treatment of NaN operands is important. */ diff --git a/gcc/real.h b/gcc/real.h index 561d0fda129..cd557b31c23 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -216,6 +216,7 @@ public: operator const real_format *() const { return m_format; } bool decimal_p () const { return m_format && m_format->b == 10; } + bool can_represent_integral_type_p (tree type) const; private: const real_format *m_format; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3604fe63137..d5bdf787a38 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2018-10-12 Yury Gribov + + PR middle-end/81376 + * c-c++-common/pr81376.c: New test. + * gcc.target/i386/387-ficom-2.c: Update test. + * gcc.target/i386/387-ficom-2.c: Ditto. + 2018-10-12 Tobias Burnus PR fortran/87597 diff --git a/gcc/testsuite/c-c++-common/pr81376.c b/gcc/testsuite/c-c++-common/pr81376.c new file mode 100644 index 00000000000..e67f41e7356 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr81376.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-original" } */ + +typedef double c_t; +typedef int a_t; +int f(a_t a1, a_t a2) { + return (c_t) a1 < (c_t) a2; + /* { dg-final { scan-tree-dump "return ( = )?a1 < a2" "original" } } */ +} + +void f1(short a, short b) +{ + volatile int s_s; + s_s = (float) a < (float) b; + /* { dg-final { scan-tree-dump "s_s = a < b" "original" } } */ +} + +void f2(unsigned short a, unsigned short b) +{ + volatile int us_us; + us_us = (float) a < (float) b; + /* { dg-final { scan-tree-dump "us_us = a < b" "original" } } */ +} + +/* We don't optimize here because neither of integral types is + subset of the other. */ +void f3(unsigned short a, short b) +{ + volatile int us_s; + us_s = (float) a < (float) b; + /* { dg-final { scan-tree-dump "us_s = \\(float\\) a < \\(float\\) b" "original" } } */ +} + +void f4(unsigned short a, int b) +{ + volatile int us_i; + us_i = (double) a < (double) b; + /* { dg-final { scan-tree-dump "us_i = \\(int\\) a < b" "original" } } */ +} + +/* We don't optimize here because neither of integral types is + subset of the other. */ +void f5(short a, unsigned int b) +{ + volatile int s_ui; + s_ui = (double) a < (double) b; + /* { dg-final { scan-tree-dump "s_ui = \\(double\\) a < \\(double\\) b" "original" } } */ +} diff --git a/gcc/testsuite/gcc.target/i386/387-ficom-1.c b/gcc/testsuite/gcc.target/i386/387-ficom-1.c index 325698854a9..8cef82df6a0 100644 --- a/gcc/testsuite/gcc.target/i386/387-ficom-1.c +++ b/gcc/testsuite/gcc.target/i386/387-ficom-1.c @@ -37,5 +37,6 @@ int test_ld_i (int x) return (long double)i != x; } -/* { dg-final { scan-assembler-times "ficomp\[s\t\]" 3 } } */ -/* { dg-final { scan-assembler-times "ficompl" 3 } } */ +/* { dg-final { scan-assembler-times "cmpw\[s\t\]" 3 } } */ +/* { dg-final { scan-assembler-times "ficompl" 1 } } */ +/* { dg-final { scan-assembler-times "cmpl" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/387-ficom-2.c b/gcc/testsuite/gcc.target/i386/387-ficom-2.c index d5283684f8e..46c4b558d8c 100644 --- a/gcc/testsuite/gcc.target/i386/387-ficom-2.c +++ b/gcc/testsuite/gcc.target/i386/387-ficom-2.c @@ -5,5 +5,6 @@ #include "387-ficom-1.c" -/* { dg-final { scan-assembler-times "ficomp\[s\t\]" 3 } } */ -/* { dg-final { scan-assembler-times "ficompl" 3 } } */ +/* { dg-final { scan-assembler-times "cmpw\[s\t\]" 3 } } */ +/* { dg-final { scan-assembler-times "ficompl" 1 } } */ +/* { dg-final { scan-assembler-times "cmpl" 2 } } */ -- 2.30.2