Hi!
On Sun, 2026-09-06 at 16:04 -0500, Jack O'Donohue wrote:
> Hello,
>
> Attempting to use __builtin_sh_{get,set}_fpscr with sh-elf-gcc on targets
> without
> TARGET_FPU_ANY results in an ICE because the built-ins are enabled when
> TARGET_SH1
> is set, but their RTL expansions require TARGET_FPU_ANY.
> I noticed this while playing around with rounding modes in the SH-4 backend.
> I am waiting on a Bugzilla account, so I can't post it there yet or get a PR,
> but the error looks like this:
Thanks for looking into this. The patch generally makes sense, except that
there's no need to touch target-supports.exp. There are already various
such functions in gcc/testsuite/gcc.target/sh/sh.exp. Also, it's not a
question of SH4 vs. SH1 but whether the target has an FPU or not.
I've committed & pushed the attached version as
3adc17073b38eb5a29e228c05f4b35dfc4d87fee
Best regards,
Oleg Endo
From 3adc17073b38eb5a29e228c05f4b35dfc4d87fee Mon Sep 17 00:00:00 2001
From: Jack O'Donohue <[email protected]>
Date: Tue, 8 Sep 2026 13:10:28 +0900
Subject: [PATCH] SH: Fix __builtin_sh_{get,set}_fpscr ICE on targets without FPU
Attempting to use __builtin_sh_{get,set}_fpscr with sh-elf-gcc on targets
without TARGET_FPU_ANY results in an ICE because the built-ins are enabled when
TARGET_SH1 is set, but their RTL expansions require TARGET_FPU_ANY.
Fixed by adjusting the TARGET_xxx check to enable/not enable the builtins.
gcc/ChangeLog:
* config/sh/sh.cc (sh1_builtin_p): Rename to sh_fpu_p.
(sh_fpu_p): Check TARGET_FPU_ANY instead of TARGET_SH1.
(bdesc): Update sh1_builtin_p to sh_fpu_p.
gcc/testsuite/ChangeLog:
* gcc.target/sh/getset-fpscr-1.c: New test.
* gcc.target/sh/getset-fpscr-2.c: New test.
* gcc.target/sh/getset-fpscr-3.c: New test.
Signed-off-by: Jack O'Donohue <[email protected]>
---
gcc/config/sh/sh.cc | 16 ++++++++++------
gcc/testsuite/gcc.target/sh/getset-fpscr-1.c | 11 +++++++++++
gcc/testsuite/gcc.target/sh/getset-fpscr-2.c | 9 +++++++++
gcc/testsuite/gcc.target/sh/getset-fpscr-3.c | 12 ++++++++++++
4 files changed, 42 insertions(+), 6 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/sh/getset-fpscr-1.c
create mode 100644 gcc/testsuite/gcc.target/sh/getset-fpscr-2.c
create mode 100644 gcc/testsuite/gcc.target/sh/getset-fpscr-3.c
diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc
index 05b0060..880b0b9 100644
--- a/gcc/config/sh/sh.cc
+++ b/gcc/config/sh/sh.cc
@@ -10096,21 +10096,25 @@ sh_expand_sym_label2reg (rtx reg, rtx sym, rtx lab, bool sibcall_p)
/* Machine specific built-in functions. */
struct builtin_description
{
+ /* Tells whether the built-in can be used.
+ A built-in that is not enabled is not declared. This allows using
+ '__has_builtin' on it to check its presence. However, if not present, it
+ will ultimately result in a function call to an undeclared function.
+ The alternative would be to always declare it and throw a compiler error
+ during builtin expansion, as it's done on i386. */
bool (* const is_enabled) (void);
const enum insn_code icode;
const char *const name;
int signature;
tree fndecl;
};
-/* This function can be used if there are any built-ins that are not for
- SHmedia. It's commented out to avoid the defined-but-unused warning. */
static bool
-sh1_builtin_p (void)
+sh_fpu_p (void)
{
- return TARGET_SH1;
+ return TARGET_FPU_ANY;
}
/* describe number and signedness of arguments; arg[0] == result
(1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */
@@ -10183,11 +10187,11 @@ static const char signature_args[][4] =
/* mshards_q: returns signed short. */
/* nsb: takes long long arg, returns unsigned char. */
static struct builtin_description bdesc[] =
{
- { sh1_builtin_p,
+ { sh_fpu_p,
CODE_FOR_sts_fpscr, "__builtin_sh_get_fpscr", SH_BLTIN_UV, 0 },
- { sh1_builtin_p,
+ { sh_fpu_p,
CODE_FOR_set_fpscr, "__builtin_sh_set_fpscr", SH_BLTIN_VU, 0 },
};
static tree sh_builtin_get_fpscr;
diff --git a/gcc/testsuite/gcc.target/sh/getset-fpscr-1.c b/gcc/testsuite/gcc.target/sh/getset-fpscr-1.c
new file mode 100644
index 0000000..39d55e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/getset-fpscr-1.c
@@ -0,0 +1,11 @@
+/* Verify that no ICE occurs if target doesn't have an FPU. */
+/* { dg-do compile { target { no_fpu } } } */
+/* The default -ansi makes an implicit declaration legal and silent. */
+/* { dg-options "-Werror=implicit-function-declaration" } */
+
+void
+error (void)
+{
+ __builtin_sh_get_fpscr (); /* { dg-error "implicit declaration of function" } */
+ __builtin_sh_set_fpscr (0); /* { dg-error "implicit declaration of function" } */
+}
diff --git a/gcc/testsuite/gcc.target/sh/getset-fpscr-2.c b/gcc/testsuite/gcc.target/sh/getset-fpscr-2.c
new file mode 100644
index 0000000..b96fed8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/getset-fpscr-2.c
@@ -0,0 +1,9 @@
+/* Verify that built-ins compile correctly if floating-point is supported. */
+/* { dg-do compile { target { any_fpu } } } */
+
+void
+test (void)
+{
+ __builtin_sh_get_fpscr ();
+ __builtin_sh_set_fpscr (0);
+}
diff --git a/gcc/testsuite/gcc.target/sh/getset-fpscr-3.c b/gcc/testsuite/gcc.target/sh/getset-fpscr-3.c
new file mode 100644
index 0000000..850ca96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/getset-fpscr-3.c
@@ -0,0 +1,12 @@
+/* Verify that __has_builtin reports whether the built-ins are available. */
+/* { dg-do compile } */
+/* The default -ansi predates static_assert. */
+/* { dg-options "-std=c23" } */
+
+#ifdef __SH_FPU_ANY__
+static_assert (__has_builtin (__builtin_sh_get_fpscr));
+static_assert (__has_builtin (__builtin_sh_set_fpscr));
+#else
+static_assert (!__has_builtin (__builtin_sh_get_fpscr));
+static_assert (!__has_builtin (__builtin_sh_set_fpscr));
+#endif
--
libgit2 1.9.1