Move the rules for CBZ/TBZ to be above the rules for
CBB<cond>/CBH<cond>/CB<cond>. We want them to have higher priority
because they can express larger displacements.

gcc/ChangeLog:

        * config/aarch64/aarch64.md (aarch64_cbz<optab><mode>1): Move
        above rules for CBB<cond>/CBH<cond>/CB<cond>.
        (*aarch64_tbz<optab><mode>1): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/cmpbr.c: Update tests.
---
 gcc/config/aarch64/aarch64.md            | 161 ++++++++++++-----------
 gcc/testsuite/gcc.target/aarch64/cmpbr.c |  36 ++---
 2 files changed, 105 insertions(+), 92 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index c50c41753a7..509ef4c0f2f 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -724,6 +724,19 @@ (define_constants
 ;; Conditional jumps
 ;; -------------------------------------------------------------------
 
+;; The order of the rules below is important.
+;; Higher priority rules are preferred because they can express larger
+;; displacements.
+;; 1) EQ/NE comparisons against zero are handled by CBZ/CBNZ.
+;; 2) LT/GE comparisons against zero are handled by TBZ/TBNZ.
+;; 3) When the CMPBR extension is enabled:
+;;   a) Comparisons between two registers are handled by
+;;      CBB<cond>/CBH<cond>/CB<cond>.
+;;   b) Comparisons between a GP register and an in range immediate are
+;;      handled by CB<cond> (immediate).
+;; 4) Otherwise, emit a CMP+B<cond> sequence.
+;; -------------------------------------------------------------------
+
 (define_expand "cbranch<GPI:mode>4"
   [(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator"
                            [(match_operand:GPI 1 "register_operand")
@@ -780,6 +793,80 @@ (define_expand "cbranchcc4"
   ""
 )
 
+;; For an EQ/NE comparison against zero, emit `CBZ`/`CBNZ`
+(define_insn "aarch64_cbz<optab><mode>1"
+  [(set (pc) (if_then_else (EQL (match_operand:GPI 0 "register_operand" "r")
+                               (const_int 0))
+                          (label_ref (match_operand 1))
+                          (pc)))]
+  "!aarch64_track_speculation"
+  {
+    if (get_attr_length (insn) == 8)
+      return aarch64_gen_far_branch (operands, 1, "Lcb", "<inv_cb>\\t%<w>0, ");
+    else
+      return "<cbz>\\t%<w>0, %l1";
+  }
+  [(set_attr "type" "branch")
+   (set (attr "length")
+       (if_then_else (and (ge (minus (match_dup 1) (pc))
+                              (const_int BRANCH_LEN_N_1MiB))
+                          (lt (minus (match_dup 1) (pc))
+                              (const_int BRANCH_LEN_P_1MiB)))
+                     (const_int 4)
+                     (const_int 8)))
+   (set (attr "far_branch")
+       (if_then_else (and (ge (minus (match_dup 2) (pc))
+                              (const_int BRANCH_LEN_N_1MiB))
+                          (lt (minus (match_dup 2) (pc))
+                              (const_int BRANCH_LEN_P_1MiB)))
+                     (const_string "no")
+                     (const_string "yes")))]
+)
+
+;; For an LT/GE comparison against zero, emit `TBZ`/`TBNZ`
+(define_insn "*aarch64_tbz<optab><mode>1"
+  [(set (pc) (if_then_else (LTGE (match_operand:ALLI 0 "register_operand" "r")
+                                (const_int 0))
+                          (label_ref (match_operand 1))
+                          (pc)))
+   (clobber (reg:CC CC_REGNUM))]
+  "!aarch64_track_speculation"
+  {
+    if (get_attr_length (insn) == 8)
+      {
+       if (get_attr_far_branch (insn) == FAR_BRANCH_YES)
+         return aarch64_gen_far_branch (operands, 1, "Ltb",
+                                        "<inv_tb>\\t%<w>0, <sizem1>, ");
+       else
+         {
+           char buf[64];
+           uint64_t val = ((uint64_t) 1)
+               << (GET_MODE_SIZE (<MODE>mode) * BITS_PER_UNIT - 1);
+           sprintf (buf, "tst\t%%<w>0, %" PRId64, val);
+           output_asm_insn (buf, operands);
+           return "<bcond>\t%l1";
+         }
+      }
+    else
+      return "<tbz>\t%<w>0, <sizem1>, %l1";
+  }
+  [(set_attr "type" "branch")
+   (set (attr "length")
+       (if_then_else (and (ge (minus (match_dup 1) (pc))
+                              (const_int BRANCH_LEN_N_32KiB))
+                          (lt (minus (match_dup 1) (pc))
+                              (const_int BRANCH_LEN_P_32KiB)))
+                     (const_int 4)
+                     (const_int 8)))
+   (set (attr "far_branch")
+       (if_then_else (and (ge (minus (match_dup 1) (pc))
+                              (const_int BRANCH_LEN_N_1MiB))
+                          (lt (minus (match_dup 1) (pc))
+                              (const_int BRANCH_LEN_P_1MiB)))
+                     (const_string "no")
+                     (const_string "yes")))]
+)
+
 ;; Emit a `CB<cond> (register)` or `CB<cond> (immediate)` instruction.
 ;; The immediate range depends on the comparison code.
 ;; Comparisons against immediates outside this range fall back to
@@ -916,80 +1003,6 @@ (define_insn_and_split "*aarch64_bcond_wide_imm<GPI:mode>"
   }
 )
 
-;; For an EQ/NE comparison against zero, emit `CBZ`/`CBNZ`
-(define_insn "aarch64_cbz<optab><mode>1"
-  [(set (pc) (if_then_else (EQL (match_operand:GPI 0 "register_operand" "r")
-                               (const_int 0))
-                          (label_ref (match_operand 1))
-                          (pc)))]
-  "!aarch64_track_speculation"
-  {
-    if (get_attr_length (insn) == 8)
-      return aarch64_gen_far_branch (operands, 1, "Lcb", "<inv_cb>\\t%<w>0, ");
-    else
-      return "<cbz>\\t%<w>0, %l1";
-  }
-  [(set_attr "type" "branch")
-   (set (attr "length")
-       (if_then_else (and (ge (minus (match_dup 1) (pc))
-                              (const_int BRANCH_LEN_N_1MiB))
-                          (lt (minus (match_dup 1) (pc))
-                              (const_int BRANCH_LEN_P_1MiB)))
-                     (const_int 4)
-                     (const_int 8)))
-   (set (attr "far_branch")
-       (if_then_else (and (ge (minus (match_dup 2) (pc))
-                              (const_int BRANCH_LEN_N_1MiB))
-                          (lt (minus (match_dup 2) (pc))
-                              (const_int BRANCH_LEN_P_1MiB)))
-                     (const_string "no")
-                     (const_string "yes")))]
-)
-
-;; For an LT/GE comparison against zero, emit `TBZ`/`TBNZ`
-(define_insn "*aarch64_tbz<optab><mode>1"
-  [(set (pc) (if_then_else (LTGE (match_operand:ALLI 0 "register_operand" "r")
-                                (const_int 0))
-                          (label_ref (match_operand 1))
-                          (pc)))
-   (clobber (reg:CC CC_REGNUM))]
-  "!aarch64_track_speculation"
-  {
-    if (get_attr_length (insn) == 8)
-      {
-       if (get_attr_far_branch (insn) == FAR_BRANCH_YES)
-         return aarch64_gen_far_branch (operands, 1, "Ltb",
-                                        "<inv_tb>\\t%<w>0, <sizem1>, ");
-       else
-         {
-           char buf[64];
-           uint64_t val = ((uint64_t) 1)
-               << (GET_MODE_SIZE (<MODE>mode) * BITS_PER_UNIT - 1);
-           sprintf (buf, "tst\t%%<w>0, %" PRId64, val);
-           output_asm_insn (buf, operands);
-           return "<bcond>\t%l1";
-         }
-      }
-    else
-      return "<tbz>\t%<w>0, <sizem1>, %l1";
-  }
-  [(set_attr "type" "branch")
-   (set (attr "length")
-       (if_then_else (and (ge (minus (match_dup 1) (pc))
-                              (const_int BRANCH_LEN_N_32KiB))
-                          (lt (minus (match_dup 1) (pc))
-                              (const_int BRANCH_LEN_P_32KiB)))
-                     (const_int 4)
-                     (const_int 8)))
-   (set (attr "far_branch")
-       (if_then_else (and (ge (minus (match_dup 1) (pc))
-                              (const_int BRANCH_LEN_N_1MiB))
-                          (lt (minus (match_dup 1) (pc))
-                              (const_int BRANCH_LEN_P_1MiB)))
-                     (const_string "no")
-                     (const_string "yes")))]
-)
-
 ;; -------------------------------------------------------------------
 ;; Test bit and branch
 ;; -------------------------------------------------------------------
diff --git a/gcc/testsuite/gcc.target/aarch64/cmpbr.c 
b/gcc/testsuite/gcc.target/aarch64/cmpbr.c
index 4b72647de53..a86af9dce8e 100644
--- a/gcc/testsuite/gcc.target/aarch64/cmpbr.c
+++ b/gcc/testsuite/gcc.target/aarch64/cmpbr.c
@@ -643,7 +643,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** i8_x0_slt_0:
-**     cbblt   w0, wzr, .L([0-9]+)
+**     tbnz    w0, #7, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -667,7 +667,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** i8_x0_sge_0:
-**     cbbge   w0, wzr, .L([0-9]+)
+**     tbz     w0, #7, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -717,7 +717,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** i16_x0_slt_0:
-**     cbhlt   w0, wzr, .L([0-9]+)
+**     tbnz    w0, #15, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -741,7 +741,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** i16_x0_sge_0:
-**     cbhge   w0, wzr, .L([0-9]+)
+**     tbz     w0, #15, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -749,7 +749,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u32_x0_eq_0:
-**     cbeq    w0, wzr, .L([0-9]+)
+**     cbz     w0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -757,7 +757,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u32_x0_ne_0:
-**     cbne    w0, wzr, .L([0-9]+)
+**     cbnz    w0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -770,7 +770,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u32_x0_ule_0:
-**     cbeq    w0, wzr, .L([0-9]+)
+**     cbz     w0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -778,7 +778,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u32_x0_ugt_0:
-**     cbne    w0, wzr, .L([0-9]+)
+**     cbnz    w0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -815,15 +815,15 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** i32_x0_sge_0:
-**     cblt    w0, wzr, .L([0-9]+)
-**     b       taken
-** .L\1:
+**     tbz     w0, #31, .L([0-9]+)
 **     b       not_taken
+** .L\1:
+**     b       taken
 */
 
 /*
 ** u64_x0_eq_0:
-**     cbeq    x0, xzr, .L([0-9]+)
+**     cbz     x0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -831,7 +831,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u64_x0_ne_0:
-**     cbne    x0, xzr, .L([0-9]+)
+**     cbnz    x0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -844,7 +844,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u64_x0_ule_0:
-**     cbeq    x0, xzr, .L([0-9]+)
+**     cbz     x0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -852,7 +852,7 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** u64_x0_ugt_0:
-**     cbne    x0, xzr, .L([0-9]+)
+**     cbnz    x0, .L([0-9]+)
 **     b       not_taken
 ** .L\1:
 **     b       taken
@@ -889,10 +889,10 @@ FAR_BRANCH(u64, 42);
 
 /*
 ** i64_x0_sge_0:
-**     cblt    x0, xzr, .L([0-9]+)
-**     b       taken
-** .L\1:
+**     tbz     x0, #63, .L([0-9]+)
 **     b       not_taken
+** .L\1:
+**     b       taken
 */
 
 /*
-- 
2.48.1

Reply via email to