The Zbb min/max pattern was not matching 32-bit sources when compiling for 64-bit. This patch separates the pattern into SImode and DImode, and use a define_expand to handle SImode on 64-bit. zbb-min-max-02.c generates different code as a result of the new expander. The resulting code is as efficient as the old code. Furthermore, the special sh1add pattern that appeared in zbb-min-max-02.c is tested by the zba-shNadd-* tests.
gcc/ChangeLog: * config/riscv/bitmanip.md (<bitmanip_optab><mode>3): Divide pattern into <bitmanip_optab>si3_insn and <bitmanip_optab>di3. (<bitmanip_optab>si3): Handle SImode sources on TARGET_64BIT. gcc/testsuite: * gcc.target/riscv/zbb-abs.c: New test. * gcc.target/riscv/zbb-min-max-02.c: Addapt the expected output. --- gcc/config/riscv/bitmanip.md | 38 ++++++++++++++++--- gcc/testsuite/gcc.target/riscv/zbb-abs.c | 18 +++++++++ .../gcc.target/riscv/zbb-min-max-02.c | 2 +- 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/zbb-abs.c diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index d17133d58c1..abf08a29e89 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -360,14 +360,42 @@ DONE; }) -(define_insn "<bitmanip_optab><mode>3" - [(set (match_operand:X 0 "register_operand" "=r") - (bitmanip_minmax:X (match_operand:X 1 "register_operand" "r") - (match_operand:X 2 "register_operand" "r")))] - "TARGET_ZBB" +(define_insn "<bitmanip_optab>si3_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (bitmanip_minmax:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "!TARGET_64BIT && TARGET_ZBB" "<bitmanip_insn>\t%0,%1,%2" [(set_attr "type" "bitmanip")]) +(define_insn "<bitmanip_optab>di3" + [(set (match_operand:DI 0 "register_operand" "=r") + (bitmanip_minmax:DI (match_operand:DI 1 "register_operand" "r") + (match_operand:DI 2 "register_operand" "r")))] + "TARGET_64BIT && TARGET_ZBB" + "<bitmanip_insn>\t%0,%1,%2" + [(set_attr "type" "bitmanip")]) + +(define_expand "<bitmanip_optab>si3" + [(set (match_operand:SI 0 "register_operand" "=r") + (bitmanip_minmax:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_ZBB" + " +{ + if (TARGET_64BIT) + { + rtx op1_x = gen_reg_rtx (DImode); + emit_move_insn (op1_x, gen_rtx_SIGN_EXTEND (DImode, operands[1])); + rtx op2_x = gen_reg_rtx (DImode); + emit_move_insn (op2_x, gen_rtx_SIGN_EXTEND (DImode, operands[2])); + rtx dst_x = gen_reg_rtx (DImode); + emit_insn (gen_<bitmanip_optab>di3 (dst_x, op1_x, op2_x)); + emit_move_insn (operands[0], gen_lowpart (SImode, dst_x)); + DONE; + } +}") + ;; Optimize the common case of a SImode min/max against a constant ;; that is safe both for sign- and zero-extension. (define_insn_and_split "*minmax" diff --git a/gcc/testsuite/gcc.target/riscv/zbb-abs.c b/gcc/testsuite/gcc.target/riscv/zbb-abs.c new file mode 100644 index 00000000000..6ef7efdbd49 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbb-abs.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbb" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +#define ABS(x) (((x) >= 0) ? (x) : -(x)) + +int +foo (int x) +{ + return ABS(x); +} + +/* { dg-final { scan-assembler-times "neg" 1 } } */ +/* { dg-final { scan-assembler-times "max" 1 } } */ +/* { dg-final { scan-assembler-not "sraiw" } } */ +/* { dg-final { scan-assembler-not "xor" } } */ +/* { dg-final { scan-assembler-not "subw" } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/zbb-min-max-02.c b/gcc/testsuite/gcc.target/riscv/zbb-min-max-02.c index b462859f10f..b9db655d55d 100644 --- a/gcc/testsuite/gcc.target/riscv/zbb-min-max-02.c +++ b/gcc/testsuite/gcc.target/riscv/zbb-min-max-02.c @@ -9,6 +9,6 @@ int f(unsigned int* a) } /* { dg-final { scan-assembler-times "minu" 1 } } */ -/* { dg-final { scan-assembler-times "sext.w" 1 } } */ +/* { dg-final { scan-assembler-times "sext.w|addw" 1 } } */ /* { dg-final { scan-assembler-not "zext.w" } } */ -- 2.38.1