PR target/111376. Currently, we are using LUI/ANDI/BEQZ for on-bit-test if the bitpos>=16, while in fact we can use SLL/BGEZ.
Note: 1) if bitpos<16, we can use ANDI/BEQZ. 2) For R2+, we have EXT. Known problems: 1. On some uarch, SLL has more delay, such as 74K: See the talk in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111376. 2. We haven't test it on any real pre-R2 hardware for performance. So, I request some test here. --- gcc/config/mips/mips.md | 33 +++++++++++ .../gcc.target/mips/mips3-one-bit-test.c | 55 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 gcc/testsuite/gcc.target/mips/mips3-one-bit-test.c diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 806fd29cf97..508fb1afa6c 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -6256,6 +6256,39 @@ (define_insn "*branch_bit<bbv><mode>_inverted" } [(set_attr "type" "branch") (set_attr "branch_likely" "no")]) + +(define_insn_and_split "*branch_on_bit<mode>" + [(set (pc) + (if_then_else + (match_operator 0 "equality_operator" + [(zero_extract:GPR (match_operand:GPR 2 "register_operand" "d") + (const_int 1) + (match_operand:GPR 3 "const_int_operand")) + (const_int 0)]) + (label_ref (match_operand 1)) + (pc)))] + "!ISA_HAS_BBIT && !ISA_HAS_EXT_INS && !TARGET_MIPS16 && UINTVAL (operands[3]) >= 16" + "#" + "&& !reload_completed" + [(set (match_dup 4) + (ashift:GPR (match_dup 2) (match_dup 3))) + (set (pc) + (if_then_else + (match_op_dup 0 [(match_dup 4) (const_int 0)]) + (label_ref (match_operand 1)) + (pc)))] +{ + int shift = GET_MODE_BITSIZE (<MODE>mode) - 1 - INTVAL (operands[3]); + operands[3] = GEN_INT (shift); + operands[4] = gen_reg_rtx (<MODE>mode); + + if (GET_CODE (operands[0]) == EQ) + operands[0] = gen_rtx_GE (<MODE>mode, operands[4], const0_rtx); + else + operands[0] = gen_rtx_LT (<MODE>mode, operands[4], const0_rtx); +} +[(set_attr "type" "branch")]) + ;; ;; .................... diff --git a/gcc/testsuite/gcc.target/mips/mips3-one-bit-test.c b/gcc/testsuite/gcc.target/mips/mips3-one-bit-test.c new file mode 100644 index 00000000000..50672e71d73 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/mips3-one-bit-test.c @@ -0,0 +1,55 @@ +/* { dg-options "-mips3 -mgp64" } */ +/* FIXME: -Os fails due to rtx_cost: PR115473. */ +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-Os" } { "" } } */ +/* { dg-final { scan-assembler "f32_15:.*andi\t\\\$4,\\\$4,0x8000" } } */ +/* { dg-final { scan-assembler "f32:.*sll\t\\\$4,\\\$4,15" } } */ +/* { dg-final { scan-assembler "f64_15:.*andi\t\\\$4,\\\$4,0x8000" } } */ +/* { dg-final { scan-assembler "f64:.*dsll\t\\\$4,\\\$4,47" } } */ + +/* Test to make sure we can use sll+bgtz to test one bit. + See PR111376. */ + +int f1(); +int f2(); + +/* If the bits is < 16, we can use andi+beqz. */ +NOMIPS16 int +f32_15(int a) +{ + int p = (a & (1<<15)); + if (p) + return f1(); + else + return f2(); +} + +/* If the bits >= 16, we can use sll+bgez. */ +NOMIPS16 int +f32(int a) +{ + int p = (a & (1<<16)); + if (p) + return f1(); + else + return f2(); +} + +NOMIPS16 int +f64_15(long long a) +{ + long long p = (a & (1LL<<15)); + if (p) + return f1(); + else + return f2(); +} + +NOMIPS16 int +f64(long long a) +{ + long long p = (a & (1LL<<16)); + if (p) + return f1(); + else + return f2(); +} -- 2.39.3 (Apple Git-146)