https://gcc.gnu.org/g:02018d606e8ae483cdf2f5ea3f222fc582ce3090
commit r17-5785-g02018d606e8ae483cdf2f5ea3f222fc582ce3090 Author: Jeff Law <[email protected]> Date: Sun Nov 1 10:01:00 2026 -0700 [RISC-V][PR target/127908] Properly recognize additional UNSPECs that may trap for RISC-v As noted in the BZ the RISC-V port has several UNSPECs with integer modes, but which can trigger FE_INVALID or other similar exceptions. Because the UNSPECs have an integer mode, the standard may-trap hooks return false and that allows the scheduler to move things around too aggressively speculate a trapping insn up past its controlling condition. This patch introduces a suitable target override which will detect the potentially trapping UNSPECs with integer modes which in turn avoids the invalid speculation. Tested on riscv32-elf and riscv64-elf. Bootstrap on the K3 and c920 is in flight. K1 is queued. Pushing to the trunk. PR target/127908 gcc/ * config/riscv/riscv.cc (riscv_unspec_may_trap_p): New function. (TARGET_UNSPEC_MAY_TRAP_P): Define. gcc/testsuite * gcc.target/riscv/pr127908.c: New test. Diff: --- gcc/config/riscv/riscv.cc | 35 ++++++++++++++++++++++ gcc/testsuite/gcc.target/riscv/pr127908.c | 48 +++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index bed695ccae4b..ab9354162fab 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -16984,6 +16984,38 @@ riscv_can_tag_addresses () return TARGET_64BIT && target_has_pointer_masking_p; } +/* Implement TARGET_UNSPEC_MAY_TRAP_P. */ + +static int +riscv_unspec_may_trap_p (const_rtx x, unsigned flags) +{ + /* The default implementation catches things with an FP mode on the UNSPEC. + Thus we don't need to list all those. We can focus on cases where the + UNSPEC has no mode or an integer/vector mode. */ + switch (XINT (x, 1)) + { + case UNSPEC_LRINT: + case UNSPEC_ROUND: + case UNSPEC_FLOOR: + case UNSPEC_CEIL: + case UNSPEC_BTRUNC: + case UNSPEC_ROUNDEVEN: + case UNSPEC_NEARBYINT: + case UNSPEC_FLT_QUIET: + case UNSPEC_FLE_QUIET: + case UNSPEC_VFCVT: + case UNSPEC_UNSIGNED_VFCVT: + /* If FLAG_TRAPPING_MATH is active, then these potentially trap, otherwise + fall into the default case. */ + if (flag_trapping_math) + return 1; + default: + break; + } + + return default_unspec_may_trap_p (x, flags); +} + /* libsanitizer expects 8 tag bits. */ @@ -17437,6 +17469,9 @@ riscv_memtag_tag_bitsize () #undef TARGET_MEMTAG_TAG_BITSIZE #define TARGET_MEMTAG_TAG_BITSIZE riscv_memtag_tag_bitsize +#undef TARGET_UNSPEC_MAY_TRAP_P +#define TARGET_UNSPEC_MAY_TRAP_P riscv_unspec_may_trap_p + #undef TARGET_DOCUMENTATION_NAME #define TARGET_DOCUMENTATION_NAME "RISC-V" diff --git a/gcc/testsuite/gcc.target/riscv/pr127908.c b/gcc/testsuite/gcc.target/riscv/pr127908.c new file mode 100644 index 000000000000..a67d276d7cbe --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr127908.c @@ -0,0 +1,48 @@ +/* { dg-do run } */ +/* { dg-additional-options "-std=c11" } */ + +#include <fenv.h> +#include <math.h> + +#define DEF(NAME, FN, T) \ + __attribute__((noipa)) void \ + NAME (const T *s, T *d, long n) \ + { \ + for (; n > 0; --n, ++s, ++d) \ + *d = FN (*s); \ + } + +DEF (ceil_d, ceil, double) +DEF (floor_d, floor, double) +DEF (trunc_d, trunc, double) +DEF (ceil_f, ceilf, float) +DEF (floor_f, floorf, float) +DEF (trunc_f, truncf, float) + +#define CHECK(NAME, T, IN) \ + do \ + for (int i = 0; i < 4; i++) \ + { \ + T out; \ + feclearexcept (FE_ALL_EXCEPT); \ + NAME (&(IN)[i], &out, 1); \ + if (fetestexcept (FE_INVALID)) \ + __builtin_abort (); \ + } \ + while (0) + +int +main (void) +{ + const double in_d[] = { INFINITY, -INFINITY, 1e300, 2.5 }; + const float in_f[] = { INFINITY, -INFINITY, 1e30f, 2.5f }; + + CHECK (ceil_d, double, in_d); + CHECK (floor_d, double, in_d); + CHECK (trunc_d, double, in_d); + CHECK (ceil_f, float, in_f); + CHECK (floor_f, float, in_f); + CHECK (trunc_f, float, in_f); + + __builtin_exit (0); +}
