Previously, a function like
```c
void foo(float32x2_t a, float32x2_t b) {
  vadd_f32(a, b);
}
```

would be optimised to a no-op, since the result of `vadd_f32` is unused.
This is undesirable if `-ftrapping-math` is enabled, because the `FADD`
instruction could produce a floating-point exception if the result is a
signalling-nan.

Fix by inserting an `asm volatile` statement (which creates a dependency
on the result) during expansion if `-ftrapping-math` is enabled.

gcc/ChangeLog:

        * config/aarch64/aarch64-neon-builtins-base.cc
        (build_optimization_barrier): New function.
        (gimple_arith::call_properties): Return the correct flags when
        inputs are floating-point and `-ftrapping-math` is enabled.
        (gimple_arith::fold): Insert an optimization barrier when
        necessary.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/neon/no_trapping_math.c: New test.
        * gcc.target/aarch64/neon/trapping_math.c: New test.
        * gcc.target/aarch64/simd/pr99195_1.c: Add `-fno-trapping-math`
        to `dg-options` to prevent unnecessary `fmov`s being generated.
        * gcc.target/aarch64/simd/pr99195_2.c: Likewise.
---
 .../aarch64/aarch64-neon-builtins-base.cc     | 36 ++++++++-
 .../aarch64/neon/no_trapping_math.c           | 68 +++++++++++++++++
 .../gcc.target/aarch64/neon/trapping_math.c   | 74 +++++++++++++++++++
 .../gcc.target/aarch64/simd/pr99195_1.c       |  2 +-
 .../gcc.target/aarch64/simd/pr99195_2.c       |  2 +-
 5 files changed, 179 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/neon/no_trapping_math.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/neon/trapping_math.c

diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.cc 
b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
index 9bceb271874..d4af7d4223f 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
@@ -45,6 +45,23 @@
 #include "gimple-fold.h"
 
 namespace aarch64_acle {
+/* Build an asm volatile statement that prevents VALUE from being optimized
+   away, even if it is not used.
+   Equivalent to the following C code:
+   asm volatile ("" : : "w" (VALUE));  */
+gimple *
+build_optimization_barrier (tree value)
+{
+  vec<tree, va_gc> *inputs = nullptr;
+  vec_safe_push (inputs,
+                build_tree_list (build_tree_list (NULL_TREE,
+                                                  build_string (1, "w")),
+                                 value));
+  auto stmt = gimple_build_asm_vec ("", inputs, nullptr, nullptr, nullptr);
+  gimple_asm_set_volatile (stmt, true);
+  return stmt;
+}
+
 /* Build a cast expression, `(TYPE)EXPR`, if necessary to make an expression
    with type TYPE.  */
 tree
@@ -222,6 +239,13 @@ public:
     : m_int_code (int_code), m_float_code (float_code), m_poly_code (poly_code)
   {}
 
+  unsigned call_properties (const function_instance &fi) const override
+  {
+    return (flag_trapping_math && fi.type_suffix (0).tclass == TYPE_float)
+            ? CP_READ_FPCR | CP_RAISE_FP_EXCEPTIONS
+            : 0;
+  }
+
   gimple *fold (gimple_folder &f) const override
   {
     auto nargs = gimple_call_num_args (f.call);
@@ -267,7 +291,17 @@ public:
        gcc_unreachable ();
       }
 
-    return gimple_build_assign (f.lhs, ret);
+    /* If the expression can raise an FP exception, use an optimization barrier
+       to prevent it being removed even if the resulting value is not used.
+       FIXME (Karl Meakin): This shouldn't be necessary, but not all
+       optimizations obey `-ftrapping-math` at the moment.  */
+    if (this->call_properties (f) & CP_RAISE_FP_EXCEPTIONS)
+      {
+       f.assign (f.lhs, ret);
+       return build_optimization_barrier (f.lhs);
+      }
+    else
+      return gimple_build_assign (f.lhs, ret);
   }
 };
 
diff --git a/gcc/testsuite/gcc.target/aarch64/neon/no_trapping_math.c 
b/gcc/testsuite/gcc.target/aarch64/neon/no_trapping_math.c
new file mode 100644
index 00000000000..e4cd471d0e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/neon/no_trapping_math.c
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-additional-options "-fno-trapping-math" } */
+
+/* These tests assert that floating point instructions are removed if the 
result
+   is unused and `-ftrapping-math` is disabled. */
+
+#include "arm_neon_test.h"
+
+/*
+** test_vadd_f16:
+** ret
+*/
+void
+test_vadd_f16 (float16x4_t a, float16x4_t b)
+{
+  vadd_f16 (a, b);
+}
+
+/*
+** test_vadd_f32:
+** ret
+*/
+void
+test_vadd_f32 (float32x2_t a, float32x2_t b)
+{
+  vadd_f32 (a, b);
+}
+
+/*
+** test_vadd_f64:
+** ret
+*/
+void
+test_vadd_f64 (float64x1_t a, float64x1_t b)
+{
+  vadd_f64 (a, b);
+}
+
+/*
+** test_vaddq_f16:
+** ret
+*/
+void
+test_vaddq_f16 (float16x8_t a, float16x8_t b)
+{
+  vaddq_f16 (a, b);
+}
+
+/*
+** test_vaddq_f32:
+** ret
+*/
+void
+test_vaddq_f32 (float32x4_t a, float32x4_t b)
+{
+  vaddq_f32 (a, b);
+}
+
+/*
+** test_vaddq_f64:
+** ret
+*/
+void
+test_vaddq_f64 (float64x2_t a, float64x2_t b)
+{
+  vaddq_f64 (a, b);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/neon/trapping_math.c 
b/gcc/testsuite/gcc.target/aarch64/neon/trapping_math.c
new file mode 100644
index 00000000000..0f56da59c12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/neon/trapping_math.c
@@ -0,0 +1,74 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" } } */
+/* { dg-additional-options "-ftrapping-math" } */
+
+/* These tests assert that floating point expressions are not removed, even if
+   the result is unused, when `-ftrapping-math` is enabled. */
+
+#include "arm_neon_test.h"
+
+/*
+** test_vadd_f16:
+** fadd        v[0-9]+\.4h, (v0\.4h, v1\.4h|v1\.4h, v0\.4h)
+** ret
+*/
+void
+test_vadd_f16 (float16x4_t a, float16x4_t b)
+{
+  vadd_f16 (a, b);
+}
+
+/*
+** test_vadd_f32:
+** fadd        v[0-9]+\.2s, (v0\.2s, v1\.2s|v1\.2s, v0\.2s)
+** ret
+*/
+void
+test_vadd_f32 (float32x2_t a, float32x2_t b)
+{
+  vadd_f32 (a, b);
+}
+
+/*
+** test_vadd_f64:
+** fadd        d[0-9]+, (d0, d1|d1, d0)
+** ret
+*/
+void
+test_vadd_f64 (float64x1_t a, float64x1_t b)
+{
+  vadd_f64 (a, b);
+}
+
+/*
+** test_vaddq_f16:
+** fadd        v[0-9]+\.8h, (v0\.8h, v1\.8h|v1\.8h, v0\.8h)
+** ret
+*/
+void
+test_vaddq_f16 (float16x8_t a, float16x8_t b)
+{
+  vaddq_f16 (a, b);
+}
+
+/*
+** test_vaddq_f32:
+** fadd        v[0-9]+\.4s, (v0\.4s, v1\.4s|v1\.4s, v0\.4s)
+** ret
+*/
+void
+test_vaddq_f32 (float32x4_t a, float32x4_t b)
+{
+  vaddq_f32 (a, b);
+}
+
+/*
+** test_vaddq_f64:
+** fadd        v[0-9]+\.2d, (v0\.2d, v1\.2d|v1\.2d, v0\.2d)
+** ret
+*/
+void
+test_vaddq_f64 (float64x2_t a, float64x2_t b)
+{
+  vaddq_f64 (a, b);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/simd/pr99195_1.c 
b/gcc/testsuite/gcc.target/aarch64/simd/pr99195_1.c
index 765cb270b4c..6600fdbb704 100644
--- a/gcc/testsuite/gcc.target/aarch64/simd/pr99195_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/simd/pr99195_1.c
@@ -3,7 +3,7 @@
     the top half of the vector register and no explicit zeroing instructions
     are emitted.  */
 /* { dg-do compile } */
-/* { dg-options "-O" } */
+/* { dg-options "-O -fno-trapping-math" } */
 
 #include <arm_neon.h>
 
diff --git a/gcc/testsuite/gcc.target/aarch64/simd/pr99195_2.c 
b/gcc/testsuite/gcc.target/aarch64/simd/pr99195_2.c
index f11f49e0087..6a96a617d78 100644
--- a/gcc/testsuite/gcc.target/aarch64/simd/pr99195_2.c
+++ b/gcc/testsuite/gcc.target/aarch64/simd/pr99195_2.c
@@ -3,7 +3,7 @@
     the top half of the vector register and no explicit zeroing instructions
     are emitted.  */
 /* { dg-do compile } */
-/* { dg-options "-O -march=armv8.2-a+fp16" } */
+/* { dg-options "-O -march=armv8.2-a+fp16 -fno-trapping-math" } */
 
 #include <arm_neon.h>
 
-- 
2.51.0

Reply via email to