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

Reply via email to