Tested on current master (GCC 17) with

make -k check RUNTESTFLAGS="--target_board=sh-sim\{-m2/-ml,-m2/-mb,-m2a/-
mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}"

and committed to master.

Backported to open release branches GCC 13, 14, 15, 16 as obvious.
(only sanity checked sh-elf with "make all")


Best regards,
Oleg Endo

gcc/ChangeLog:

        PR target/67459
        PR target/122948
        * config/sh/sh.md (addc): Fix T bit set expression.
        (subc): Likewise.

gcc/testsuite/ChangeLog:

        PR target/67459
        PR target/122948
        * gcc.target/sh/pr122948.c: New test.
From 1a59bc13e2ca584b16059306d780d6f95156be93 Mon Sep 17 00:00:00 2001
From: Oleg Endo <[email protected]>
Date: Sat, 4 Jul 2026 01:22:41 +0900
Subject: [PATCH] SH: Fix T bit set expressions of addc and subc insns.

gcc/ChangeLog:

	PR target/67459
	PR target/122948
	* config/sh/sh.md (addc): Fix T bit set expression.
	(subc): Likewise.

gcc/testsuite/ChangeLog:

	PR target/67459
	PR target/122948
	* gcc.target/sh/pr122948.c: New test.
---
 gcc/config/sh/sh.md                    | 11 +++++++----
 gcc/testsuite/gcc.target/sh/pr122948.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/sh/pr122948.c

diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 2d08287..4a15af7 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -1563,7 +1563,10 @@
 			  (match_operand:SI 2 "arith_reg_operand" "r"))
 		 (reg:SI T_REG)))
    (set (reg:SI T_REG)
-	(ltu:SI (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1)))]
+	(gtu:SI (plus:DI (plus:DI (zero_extend:DI (match_dup 1))
+				  (zero_extend:DI (match_dup 2)))
+			 (zero_extend:DI (reg:SI T_REG)))
+		(const_int 4294967295)))]
   "TARGET_SH1"
   "addc	%2,%0"
   [(set_attr "type" "arith")])
@@ -1955,9 +1958,9 @@
 			    (match_operand:SI 2 "arith_reg_operand" "r"))
 		  (reg:SI T_REG)))
    (set (reg:SI T_REG)
-	(gtu:SI (minus:SI (minus:SI (match_dup 1) (match_dup 2))
-			  (reg:SI T_REG))
-		(match_dup 1)))]
+	(gtu:SI (plus:DI (zero_extend:DI (match_dup 2))
+			 (zero_extend:DI (reg:SI T_REG)))
+		(zero_extend:DI (match_dup 1))))]
   "TARGET_SH1"
   "subc	%2,%0"
   [(set_attr "type" "arith")])
diff --git a/gcc/testsuite/gcc.target/sh/pr122948.c b/gcc/testsuite/gcc.target/sh/pr122948.c
new file mode 100644
index 0000000..91732b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sh/pr122948.c
@@ -0,0 +1,67 @@
+/* Verify that the T bit (carry/borrow) set expression of the subc insn is
+   correct.  */
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+extern void abort (void);
+
+__attribute__ ((noipa)) unsigned int
+foo (unsigned int a, unsigned int b)
+{
+  if (b - a - 1 <= b)
+    a = 0;
+  return a;
+}
+
+__attribute__ ((noipa)) unsigned int
+bar (unsigned int a, unsigned int b)
+{
+  return (b - a - 1) > b;
+}
+
+__attribute__ ((noipa)) unsigned int
+baz (unsigned int a, unsigned int b)
+{
+  return (a + b + 1) <= a;
+}
+
+int
+main (void)
+{
+  if (foo (0xffffffff, 0x4e92c833) != 0)
+    abort ();
+
+  if (bar (0xffffffff, 0x4e92c833) != 0)
+    abort ();
+
+  /* b - a - 1 wraps (borrow) whenever a + 1 > b (unsigned).  */
+  if (bar (5, 3) != 1)
+    abort ();
+
+  if (bar (0, 0) != 1)
+    abort ();
+
+  if (bar (0, 5) != 0)
+    abort ();
+
+  /* addc carry-out: (a + b + 1) <= a.  */
+  /* 0xffffffff + 0 + 1 wraps to 0.  */
+  if (baz (0xffffffff, 0) != 1)
+    abort ();
+
+  if (baz (0xffffffff, 0xffffffff) != 1)
+    abort ();
+
+  /* wraps to 0.  */
+  if (baz (0xfffffffe, 1) != 1)
+    abort ();
+
+  /* 1 <= 0 is false.  */
+  if (baz (0, 0) != 0)
+    abort ();
+
+  if (baz (1, 2) != 0)
+    abort ();
+
+  return 0;
+}
--
libgit2 1.9.0

Reply via email to