[gcc(refs/users/meissner/heads/work238-dmf)] Add saturate subtract support
Michael Meissner
meissner@gcc.gnu.org
Wed Mar 11 22:25:39 GMT 2026
https://gcc.gnu.org/g:f952b8ee5d860c2306c82ac0ee40b4dd26e012fd
commit f952b8ee5d860c2306c82ac0ee40b4dd26e012fd
Author: Michael Meissner <meissner@linux.ibm.com>
Date: Wed Mar 11 18:15:37 2026 -0400
Add saturate subtract support
This patch adds support for saturating subtract instructions that might be added
to a future PowerPC. I think I had originally submitted patches that added a
new built-in function to generate the subfus and subdus instructions. Segher
suggested that instead of generating a built-in function, that I should just
having GCC automatically recognize cases where a saturating subtract could be
generated. This patch generates the saturating subtract instructions in the
appropriate context.
gcc/
2026-03-11 Michael Meissner <meissner@linux.ibm.com>
* config/rs6000/rs6000.md (gtu_geu): New code iterator.
(subfus<mode>3_<code>): New insns.
gcc/testsuite/
2026-03-11 Michael Meissner <meissner@linux.ibm.com>
* gcc.target/powerpc/saturate-subtract-1.c: New test.
* gcc.target/powerpc/saturate-subtract-2.c: Likewise.
Diff:
---
gcc/config/rs6000/rs6000.md | 14 ++++++++
.../gcc.target/powerpc/saturate-subtract-1.c | 39 ++++++++++++++++++++++
.../gcc.target/powerpc/saturate-subtract-2.c | 38 +++++++++++++++++++++
gcc/testsuite/lib/target-supports.exp | 13 ++++++++
4 files changed, 104 insertions(+)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 57a239791ee3..909c817cbe7e 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -2397,6 +2397,20 @@
""
)
+;; Saturating subtract
+(define_code_iterator gtu_geu [gtu geu])
+
+(define_insn "*subfus<mode>3_<code>"
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+ (if_then_else:GPR (gtu_geu (match_operand:GPR 2 "gpc_reg_operand" "r")
+ (match_operand:GPR 1 "gpc_reg_operand" "r"))
+ (minus:GPR (match_dup 2)
+ (match_dup 1))
+ (const_int 0)))]
+ "TARGET_FUTURE"
+ "sub<wd>us %0,%1,%2"
+ [(set_attr "type" "add")])
+
(define_insn "@neg<mode>2"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
diff --git a/gcc/testsuite/gcc.target/powerpc/saturate-subtract-1.c b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-1.c
new file mode 100644
index 000000000000..336285fa0f81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+/* { dg-require-effective-target powerpc_future_ok } */
+
+/* Check that saturating subtract (subfus) is generated. Check that all
+ combinations of >, >=, <, and <= are optimized. */
+
+#ifndef TYPE
+#define TYPE unsigned int
+#endif
+
+void
+saturated_subtract_gt (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a > b) ? a - b : 0;
+}
+
+void
+saturated_subtract_ge (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a >= b) ? a - b : 0;
+}
+
+void
+saturated_subtract_lt (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a < b) ? 0 : a - b;
+}
+
+void
+saturated_subtract_le (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a <= b) ? 0 : a - b;
+}
+
+/* { dg-final { scan-assembler-times {\msubfus\M} 4 } } */
+/* { dg-final { scan-assembler-not {\mcmplw\M} } } */
+/* { dg-final { scan-assembler-not {\misel\M} } } */
+/* { dg-final { scan-assembler-not {\msubf\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c
new file mode 100644
index 000000000000..fa8fba2a6339
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+
+/* Check that saturating subtract (subfus) is generated. Check that all
+ combinations of >, >=, <, and <= are optimized. */
+
+#ifndef TYPE
+#define TYPE unsigned long
+#endif
+
+void
+saturated_subtract_gt (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a > b) ? a - b : 0;
+}
+
+void
+saturated_subtract_ge (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a >= b) ? a - b : 0;
+}
+
+void
+saturated_subtract_lt (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a < b) ? 0 : a - b;
+}
+
+void
+saturated_subtract_le (TYPE a, TYPE b, TYPE *p)
+{
+ *p = (a <= b) ? 0 : a - b;
+}
+
+/* { dg-final { scan-assembler-times {\msubdus\M} 4 } } */
+/* { dg-final { scan-assembler-not {\mcmpld\M} } } */
+/* { dg-final { scan-assembler-not {\misel\M} } } */
+/* { dg-final { scan-assembler-not {\msubf\M} } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 59c7a3f22b49..6c1d6d81e2c9 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -8155,6 +8155,19 @@ proc check_htm_hw_available { } {
}
}]
}
+
+# Return 1 if this is a PowerPC target supporting -mcpu=future
+
+proc check_effective_target_powerpc_future_ok { } {
+ return [check_no_compiler_messages powerpc_future_ok object {
+ unsigned long a, b, c;
+ int main (void) {
+ asm ("subdus %0,%1,%2" : "=r" (a) : "r" (b), "r" (c));
+ return 0;
+ }
+ } "-mcpu=future"]
+}
+
# Return 1 if this is a PowerPC target supporting -mcpu=cell.
proc check_effective_target_powerpc_ppu_ok { } {
More information about the Gcc-cvs
mailing list