Hello, This patch changes a match.pd expression so that binary math expressions will not be done in the precision of it's widest type if -funsafe-math-optimizations is enabled.
This patch has been extracted from https://gcc.gnu.org/ml/gcc-patches/2019-09/msg00072.html based on upstream comments. For example take the function: float f (float x, float y) { double z = 1.0 / x; return z * y; } Without this patch this would generate the following (with -Ofast): _1 = (double) x_4(D); z_5 = 1.0e+0 / _1; _2 = (double) y_6(D); _3 = _2 * z_5; _7 = (float) _3; return _7; This contains 3 unnecessary casts - since all outputs of the expression are in single precision, the calculation itself can be done entirely in single precision - instead of converting the operands to double, doing the calculation and then converting the result back to single precision again. With this patch (and -Ofast) the following GIMPLE is generated: _5 = 1.0e+0 / x_1(D); _3 = y_2(D) * _5; return _3; The benefits can then be seen in the generated code: Without this patch f: fcvt d1, s1 fcvt d0, s0 fdiv d0, d1, d0 fcvt s0, d0 ret With this patch f: fdiv s0, s1, s0 ret Added tests to verify that no unnecessary casts are kept. Bootstrapped and regtested on aarch64 and x86_64 with no regressions. I don't have write access, so if OK for trunk then can someone commit on my behalf? Regards Barney gcc/ChangeLog: 2019-09-05 Barnaby Wilks <barnaby.wi...@arm.com> * match.pd: Add flag_unsafe_math_optimizations check before deciding on the widest type in a binary math operation. gcc/testsuite/ChangeLog: 2019-09-05 Barnaby Wilks <barnaby.wi...@arm.com> * gcc.dg/fold-binary-math-casts.c: New test.
diff --git a/gcc/match.pd b/gcc/match.pd index 1d13543a6159dc94ce1ff1112c0bfc6b0d588638..5b2d95dfa9d8feef7e7248c0364909fc061da3ab 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5040,10 +5040,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) && newtype == type && types_match (newtype, type)) (op (convert:newtype @1) (convert:newtype @2)) - (with { if (TYPE_PRECISION (ty1) > TYPE_PRECISION (newtype)) + (with + { + if (!flag_unsafe_math_optimizations) + { + if (TYPE_PRECISION (ty1) > TYPE_PRECISION (newtype)) newtype = ty1; + if (TYPE_PRECISION (ty2) > TYPE_PRECISION (newtype)) - newtype = ty2; } + newtype = ty2; + } + } + /* Sometimes this transformation is safe (cannot change results through affecting double rounding cases) and sometimes it is not. If NEWTYPE is diff --git a/gcc/testsuite/gcc.dg/fold-binary-math-casts.c b/gcc/testsuite/gcc.dg/fold-binary-math-casts.c new file mode 100644 index 0000000000000000000000000000000000000000..3005a1e6eefbd772756fb16df2ac94838e88e903 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-binary-math-casts.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -fdump-tree-optimized" } */ + +#include <math.h> + +float +f (float x, float y) +{ + double z = 1.0 / x; + return z * y; +} + +float +g (float x, float y) +{ + double a = 1.0 / x; + double b = 1.0 / y; + long double k = x*x*x*x*x*x; + + return a + b - k; +} + +float +h (float x) +{ + double a = x * 2.0; + double b = a / 3.5f; + return a + b; +} + +float +i (float y, float z) +{ + return pow (y, 2.0) / (double) (y + z); +} + +float +j (float x, float y) +{ + double t = 4.0 * x; + double z = t + y; + return z; +} + +float +k (float a) +{ + return 1.0 / sqrt (a); +} + +float +l (float a) +{ + return (double) a * (a / 2.0); +} + +/* { dg-final { scan-tree-dump-not "\\(double\\)" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "\\(float\\)" "optimized" } } */