https://gcc.gnu.org/g:cd211c9acc14124b28ccebc4f1028c97caa78af8

commit cd211c9acc14124b28ccebc4f1028c97caa78af8
Author: Michael Meissner <[email protected]>
Date:   Tue May 12 20:33:53 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.
    
    2026-05-12   Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/rs6000.md (gtu_geu): New code iterator.
            (subfus<mode>3_<code>): New insns.
    
    gcc/testsuite/
    
            * gcc.target/powerpc/saturate-subtract-1.c: New test.
            * gcc.target/powerpc/saturate-subtract-2.c: Likewise.
            * lib/target-supports.exp 
(check_effective_target_powerpc_future_ok):
            New target test.

Diff:
---
 gcc/config/rs6000/rs6000.md                        | 14 ++++++++
 .../gcc.target/powerpc/saturate-subtract-1.c       | 39 +++++++++++++++++++++
 .../gcc.target/powerpc/saturate-subtract-2.c       | 40 ++++++++++++++++++++++
 gcc/testsuite/lib/target-supports.exp              | 13 +++++++
 4 files changed, 106 insertions(+)

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 1a8212ca0b4e..dfe0402813ce 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 1 "gpc_reg_operand" "r")
+                                  (match_operand:GPR 2 "gpc_reg_operand" "r"))
+                         (minus:GPR (match_dup 1)
+                                    (match_dup 2))
+                         (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..c32a70a5e898
--- /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 {\msubwus\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..482d7384c172
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/saturate-subtract-2.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_future_ok } */
+/* { dg-require-effective-target lp64 } */
+/* { 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 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 01582621f841..9c0c98795195 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -8192,6 +8192,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 { } {

Reply via email to