After r14-3110-g7fb65f10285, the canonical form for `a ? ~b : b` changed to be `-(a) ^ b` that means for aarch64 we need to add a few new insn patterns to be able to catch this and change it to be what is the canonical form for the aarch64 backend. A secondary pattern was needed to support a zero_extended form too; this adds a testcase for all 3 cases.
Bootstrapped and tested on aarch64-linux-gnu with no regressions. PR target/110986 gcc/ChangeLog: * config/aarch64/aarch64.md (*cmov<mode>_insn_insv): New pattern. (*cmov_uxtw_insn_insv): Likewise. gcc/testsuite/ChangeLog: * gcc.target/aarch64/cond_op-1.c: New test. --- gcc/config/aarch64/aarch64.md | 46 ++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/cond_op-1.c | 20 +++++++++ 2 files changed, 66 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/cond_op-1.c diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 32c7adc8928..59cd0415937 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -4413,6 +4413,52 @@ (define_insn "*csinv3_uxtw_insn3" [(set_attr "type" "csel")] ) +;; There are two canonical forms for `cmp ? ~a : a`. +;; This is the second form and is here to help combine. +;; Support `-(cmp) ^ a` into `cmp ? ~a : a` +;; The second pattern is to support the zero extend'ed version. + +(define_insn_and_split "*cmov<mode>_insn_insv" + [(set (match_operand:GPI 0 "register_operand" "=r") + (xor:GPI + (neg:GPI + (match_operator:GPI 1 "aarch64_comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])) + (match_operand:GPI 3 "general_operand" "r")))] + "can_create_pseudo_p ()" + "#" + "&& true" + [(set (match_dup 0) + (if_then_else:GPI (match_dup 1) + (not:GPI (match_dup 3)) + (match_dup 3)))] + { + operands[3] = force_reg (<MODE>mode, operands[3]); + } + [(set_attr "type" "csel")] +) + +(define_insn_and_split "*cmov_uxtw_insn_insv" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (xor:SI + (neg:SI + (match_operator:SI 1 "aarch64_comparison_operator" + [(match_operand 2 "cc_register" "") (const_int 0)])) + (match_operand:SI 3 "general_operand" "r"))))] + "can_create_pseudo_p ()" + "#" + "&& true" + [(set (match_dup 0) + (if_then_else:DI (match_dup 1) + (zero_extend:DI (not:SI (match_dup 3))) + (zero_extend:DI (match_dup 3))))] + { + operands[3] = force_reg (SImode, operands[3]); + } + [(set_attr "type" "csel")] +) + ;; If X can be loaded by a single CNT[BHWD] instruction, ;; ;; A = UMAX (B, X) diff --git a/gcc/testsuite/gcc.target/aarch64/cond_op-1.c b/gcc/testsuite/gcc.target/aarch64/cond_op-1.c new file mode 100644 index 00000000000..e6c7821127e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/cond_op-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* PR target/110986 */ + + +long long full(unsigned a, unsigned b) +{ + return a ? ~b : b; +} +unsigned fuu(unsigned a, unsigned b) +{ + return a ? ~b : b; +} +long long fllll(unsigned long long a, unsigned long long b) +{ + return a ? ~b : b; +} + +/* { dg-final { scan-assembler-times "csinv\tw\[0-9\]*" 2 } } */ +/* { dg-final { scan-assembler-times "csinv\tx\[0-9\]*" 1 } } */ -- 2.39.3