From: Kyrylo Tkachov <[email protected]>
A conditional comparison can skip its comparison operand. This is not valid
when the source evaluates both comparisons and the skipped comparison can
trap. For example:
int
f (double a, double b, double c, double d)
{
return (a < b) & (c < d);
}
At -O2, AArch64 emitted:
fcmpe d0, d1
fccmpe d2, d3, 0, mi
cset w0, mi
If a < b is false, FCCMPE does not compare c and d. A quiet NaN in c or d
therefore does not raise Invalid, although bitwise AND evaluates both
operands. After this patch GCC emits:
fcmpe d0, d1
cset w1, mi
fcmpe d2, d3
cset w0, mi
and w0, w1, w0
Reject a potentially trapping comparison from every conditional position.
A trapping comparison can still lead the sequence because the first
comparison always executes.
The runtime test clears FPSR with the AArch64 builtins and verifies that an
ordered comparison with a quiet NaN raises Invalid. The compile test covers
signalling NaNs.
Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill
gcc/
* ccmp.cc (expand_ccmp_next): Reject a comparison that can trap.
gcc/testsuite/
* gcc.target/aarch64/fccmp-trap-1.c: New test.
* gcc.target/aarch64/fccmp-trap-2.c: Likewise.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/ccmp.cc | 6 +++++
.../gcc.target/aarch64/fccmp-trap-1.c | 25 +++++++++++++++++++
.../gcc.target/aarch64/fccmp-trap-2.c | 12 +++++++++
3 files changed, 43 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c
diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc
index 0564ccf34bf..f63e44dcc84 100644
--- a/gcc/ccmp.cc
+++ b/gcc/ccmp.cc
@@ -168,6 +168,12 @@ expand_ccmp_next (tree op, tree_code code, rtx prev,
rtx_code rcode;
tree rhs1, rhs2;
+ /* A conditional comparison can skip OP. Only the first comparison can
+ therefore have observable traps. */
+ gimple *g = get_gimple_for_ssa_name (op);
+ if (g && gimple_assign_rhs_could_trap_p (g))
+ return NULL_RTX;
+
get_compare_parts (op, &rcode, &rhs1, &rhs2);
return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode,
rhs1, rhs2, get_rtx_code (code, 0));
diff --git a/gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c
new file mode 100644
index 00000000000..1d151f2f056
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+enum { FPSR_IOC = 1 << 0 };
+
+__attribute__ ((noipa))
+static int
+and_lt (double a, double b, double c, double d)
+{
+ return (a < b) & (c < d);
+}
+
+int
+main (void)
+{
+ double qnan = __builtin_nan ("");
+
+ __builtin_aarch64_set_fpsr (0);
+ if (and_lt (1.0, 0.0, qnan, 0.0) != 0)
+ __builtin_abort ();
+ if ((__builtin_aarch64_get_fpsr () & FPSR_IOC) == 0)
+ __builtin_abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c
new file mode 100644
index 00000000000..4b48fe5b6aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fsignaling-nans" } */
+
+int
+and_eq (double a, double b, double c, double d)
+{
+ return (a == b) & (c == d);
+}
+
+/* Both comparisons can raise an exception for a signaling NaN. */
+/* { dg-final { scan-assembler-not {\tfccmp} } } */
+/* { dg-final { scan-assembler-times {\tfcmp\td[0-9]+, d[0-9]+} 2 } } */
--
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.