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