Extract the hardcoded values for the minimum PC-relative displacements into named constants and document them.
gcc/ChangeLog: * config/aarch64/aarch64.md (BRANCH_LEN_P_128MiB): New constant. (BRANCH_LEN_N_128MiB): Likewise. (BRANCH_LEN_P_1MiB): Likewise. (BRANCH_LEN_N_1MiB): Likewise. (BRANCH_LEN_P_32KiB): Likewise. (BRANCH_LEN_N_32KiB): Likewise. --- gcc/config/aarch64/aarch64.md | 64 ++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 1b1e982d466..bba3d1c505d 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -692,12 +692,28 @@ (define_insn "indirect_jump" (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "b\\t%l0" [(set_attr "type" "branch")] ) +;; Maximum PC-relative positive/negative displacements for various branching +;; instructions. +(define_constants + [ + ;; +/- 128MiB. Used by B, BL. + (BRANCH_LEN_P_128MiB 134217724) + (BRANCH_LEN_N_128MiB -134217728) + + ;; +/- 1MiB. Used by B.<cond>, CBZ, CBNZ. + (BRANCH_LEN_P_1MiB 1048572) + (BRANCH_LEN_N_1MiB -1048576) + ;; +/- 32KiB. Used by TBZ, TBNZ. + (BRANCH_LEN_P_32KiB 32764) + (BRANCH_LEN_N_32KiB -32768) + ] +) ;; ------------------------------------------------------------------- ;; Conditional jumps ;; ------------------------------------------------------------------- @@ -743,41 +759,45 @@ (define_expand "cbranchcc4" ;; Emit `B<cond>`, assuming that the condition is already in the CC register. (define_insn "aarch64_bcond" [(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator" [(match_operand 1 "cc_register") (const_int 0)]) (label_ref (match_operand 2)) (pc)))] "" { /* GCC's traditional style has been to use "beq" instead of "b.eq", etc., but the "." is required for SVE conditions. */ bool use_dot_p = GET_MODE (operands[1]) == CC_NZCmode; if (get_attr_length (insn) == 8) return aarch64_gen_far_branch (operands, 2, "Lbcond", use_dot_p ? "b.%M0\\t" : "b%M0\\t"); else return use_dot_p ? "b.%m0\\t%l2" : "b%m0\\t%l2"; } [(set_attr "type" "branch") (set (attr "length") - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -1048576)) - (lt (minus (match_dup 2) (pc)) (const_int 1048572))) + (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_int 4) (const_int 8))) (set (attr "far_branch") - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -1048576)) - (lt (minus (match_dup 2) (pc)) (const_int 1048572))) + (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_int 0) (const_int 1)))] ) ;; For a 24-bit immediate CST we can optimize the compare for equality ;; and branch sequence from: ;; mov x0, #imm1 ;; movk x0, #imm2, lsl 16 /* x0 contains CST. */ ;; cmp x1, x0 ;; b<ne,eq> .Label ;; into the shorter: ;; sub x0, x1, #(CST & 0xfff000) ;; subs x0, x0, #(CST & 0x000fff) ;; b<ne,eq> .Label @@ -809,69 +829,77 @@ (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 -1048576)) - (lt (minus (match_dup 1) (pc)) (const_int 1048572))) + (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 -1048576)) - (lt (minus (match_dup 2) (pc)) (const_int 1048572))) + (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_int 0) (const_int 1)))] ) ;; 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) == 1) 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 -32768)) - (lt (minus (match_dup 1) (pc)) (const_int 32764))) + (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 -1048576)) - (lt (minus (match_dup 1) (pc)) (const_int 1048572))) + (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 0) (const_int 1)))] ) ;; ------------------------------------------------------------------- ;; Test bit and branch ;; ------------------------------------------------------------------- @@ -897,39 +925,43 @@ (define_expand "tbranch_<code><mode>3" (define_insn "@aarch64_tbz<optab><ALLI:mode><GPI:mode>" [(set (pc) (if_then_else (EQL (zero_extract:GPI (match_operand:ALLI 0 "register_operand" "r") (const_int 1) (match_operand 1 "aarch64_simd_shift_imm_<ALLI:mode>" "n")) (const_int 0)) (label_ref (match_operand 2)) (pc))) (clobber (reg:CC CC_REGNUM))] "!aarch64_track_speculation" { if (get_attr_length (insn) == 8) { if (get_attr_far_branch (insn) == 1) return aarch64_gen_far_branch (operands, 2, "Ltb", "<inv_tb>\\t%<ALLI:w>0, %1, "); else { operands[1] = GEN_INT (HOST_WIDE_INT_1U << UINTVAL (operands[1])); return "tst\t%<ALLI:w>0, %1\;<bcond>\t%l2"; } } else return "<tbz>\t%<ALLI:w>0, %1, %l2"; } [(set_attr "type" "branch") (set (attr "length") - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -32768)) - (lt (minus (match_dup 2) (pc)) (const_int 32764))) + (if_then_else (and (ge (minus (match_dup 2) (pc)) + (const_int BRANCH_LEN_N_32KiB)) + (lt (minus (match_dup 2) (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 2) (pc)) (const_int -1048576)) - (lt (minus (match_dup 2) (pc)) (const_int 1048572))) + (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_int 0) (const_int 1)))] ) -- 2.45.2