Middle distance branches between 1KiB and 1MiB may be
implemented with cmp+branch instead of branch+branch.

gcc:
        * config/aarch64/aarch64.cc (*aarch64_cb<INT_CMP><GPI>):
        Fall back to cmp/cmn + bcond if !far_branch.
        Adjust far_branch to 1MiB.
        (*aarch64_cb<INT_CMP><SHORT): Fall back to tst+bcond for
        EQ/NE if !far_branch.  Adjust far_branch to 1MiB.
---
 gcc/config/aarch64/aarch64.md | 37 +++++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index b947da977c3..4c9c1f43af2 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -876,10 +876,16 @@
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_CMPBR && aarch64_cb_rhs (<INT_CMP:CODE>, operands[1])"
   {
-    return (get_attr_far_branch (insn) == FAR_BRANCH_NO)
-      ? "cb<INT_CMP:cmp_op>\\t%<w>0, %<w>1, %l2"
-      : aarch64_gen_far_branch (operands, 2,
-          "cb<INT_CMP:inv_cmp_op>\\t%<w>0, %<w>1, ");
+    if (get_attr_length (insn) == 4)
+      return "cb<INT_CMP:cmp_op>\t%<w>0, %<w>1, %l2";
+    if (get_attr_far_branch (insn) == FAR_BRANCH_YES)
+      return aarch64_gen_far_branch (operands, 2,
+               "cb<INT_CMP:inv_cmp_op>\t%<w>0, %<w>1, ");
+    if (REG_P (operands[1]) || INTVAL (operands[1]) >= 0)
+      output_asm_insn ("cmp\t%<w>0, %<w>1", operands);
+    else
+      output_asm_insn ("cmn\t%<w>0, %<w>1", operands);
+    return "b<INT_CMP:cmp_op>\t%l2";
   }
   [(set_attr "type" "branch")
    (set (attr "length")
@@ -891,9 +897,9 @@
                      (const_int 8)))
    (set (attr "far_branch")
        (if_then_else (and (ge (minus (match_dup 2) (pc))
-                              (const_int BRANCH_LEN_N_1KiB))
+                              (const_int BRANCH_LEN_N_1MiB))
                           (lt (minus (match_dup 2) (pc))
-                              (const_int BRANCH_LEN_P_1KiB)))
+                              (const_int BRANCH_LEN_P_1MiB)))
                      (const_string "no")
                      (const_string "yes")))]
 )
@@ -908,10 +914,17 @@
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_CMPBR"
   {
-    return (get_attr_far_branch (insn) == FAR_BRANCH_NO)
-      ? "cb<SHORT:cmpbr_suffix><INT_CMP:cmp_op>\\t%<w>0, %<w>1, %l2"
-      : aarch64_gen_far_branch (operands, 2,
-          "cb<SHORT:cmpbr_suffix><INT_CMP:inv_cmp_op>\\t%<w>0, %<w>1, ");
+    if (get_attr_length (insn) == 4)
+      return "cb<SHORT:cmpbr_suffix><INT_CMP:cmp_op>\t%<w>0, %<w>1, %l2";
+    if ((<INT_CMP:CODE> == EQ || <INT_CMP:CODE> == NE)
+        && operands[1] == const0_rtx
+        && get_attr_far_branch (insn) == FAR_BRANCH_NO)
+      {
+        operands[1] = GEN_INT (GET_MODE_MASK (<SHORT:MODE>mode));
+        return "tst\t%w0, %1\;b<INT_CMP:cmp_op>\t%l2";
+      }
+    return aarch64_gen_far_branch (operands, 2,
+               "cb<SHORT:cmpbr_suffix><INT_CMP:inv_cmp_op>\t%<w>0, %<w>1, ");
   }
   [(set_attr "type" "branch")
    (set (attr "length")
@@ -923,9 +936,9 @@
                      (const_int 8)))
    (set (attr "far_branch")
        (if_then_else (and (ge (minus (match_dup 2) (pc))
-                              (const_int BRANCH_LEN_N_1KiB))
+                              (const_int BRANCH_LEN_N_1MiB))
                           (lt (minus (match_dup 2) (pc))
-                              (const_int BRANCH_LEN_P_1KiB)))
+                              (const_int BRANCH_LEN_P_1MiB)))
                      (const_string "no")
                      (const_string "yes")))]
 )
-- 
2.43.0

Reply via email to