[RFC] MIPS: Use SLL+BGEZ for one bit test on pre-R2

Message ID 20240618080331.87938-1-syq@gcc.gnu.org
State New
Headers
Series [RFC] MIPS: Use SLL+BGEZ for one bit test on pre-R2 |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

YunQiang Su June 18, 2024, 8:03 a.m. UTC
  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
  

Patch

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();
+}