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