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 { } {
