> On 7 May 2025, at 12:27, Karl Meakin <karl.mea...@arm.com> wrote: > > The rules for conditional branches were spread throughout `aarch64.md`. > Group them together so it is easier to understand how `cbranch<mode>4` > is lowered to RTL. > > gcc/ChangeLog: > > * config/aarch64/aarch64.md (condjump): move. > (*compare_condjump<GPI:mode>): likewise. > (aarch64_cb<optab><mode>1): likewise. > (*cb<optab><mode>1): likewise. > (tbranch_<code><mode>3): likewise. > (@aarch64_tb<optab><ALLI:mode><GPI:mode>): likewise.
Changelog entries should start with a capital letter. > --- > gcc/config/aarch64/aarch64.md | 387 ++++++++++++++++++---------------- > 1 file changed, 201 insertions(+), 186 deletions(-) > > diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md > index c678f7afb1a..4d556d886bc 100644 > --- a/gcc/config/aarch64/aarch64.md > +++ b/gcc/config/aarch64/aarch64.md > @@ -674,6 +674,10 @@ (define_insn "aarch64_write_sysregti" > "msrr\t%x0, %x1, %H1" > ) > > +;; ------------------------------------------------------------------- > +;; Unconditional jumps > +;; ------------------------------------------------------------------- > + > (define_insn "indirect_jump" > [(set (pc) (match_operand:DI 0 "register_operand" "r"))] > "" > @@ -692,6 +696,12 @@ (define_insn "jump" > [(set_attr "type" "branch")] > ) > > + > + > +;; ------------------------------------------------------------------- > +;; Conditional jumps > +;; ------------------------------------------------------------------- > + > (define_expand "cbranch<mode>4" > [(set (pc) (if_then_else (match_operator 0 "aarch64_comparison_operator" > [(match_operand:GPI 1 "register_operand") > @@ -731,6 +741,197 @@ (define_expand "cbranchcc4" > "" > "") > > +(define_insn "condjump" > + [(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))) > + (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))) > + (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 > +(define_insn_and_split "*compare_condjump<GPI:mode>" > + [(set (pc) (if_then_else (EQL > + (match_operand:GPI 0 "register_operand" "r") > + (match_operand:GPI 1 "aarch64_imm24" "n")) > + (label_ref:P (match_operand 2 "" "")) > + (pc)))] > + "!aarch64_move_imm (INTVAL (operands[1]), <GPI:MODE>mode) > + && !aarch64_plus_operand (operands[1], <GPI:MODE>mode) > + && !reload_completed" > + "#" > + "&& true" > + [(const_int 0)] > + { > + HOST_WIDE_INT lo_imm = UINTVAL (operands[1]) & 0xfff; > + HOST_WIDE_INT hi_imm = UINTVAL (operands[1]) & 0xfff000; > + rtx tmp = gen_reg_rtx (<GPI:MODE>mode); > + emit_insn (gen_add<GPI:mode>3 (tmp, operands[0], GEN_INT (-hi_imm))); > + emit_insn (gen_add<GPI:mode>3_compare0 (tmp, tmp, GEN_INT (-lo_imm))); > + rtx cc_reg = gen_rtx_REG (CC_NZmode, CC_REGNUM); > + rtx cmp_rtx = gen_rtx_fmt_ee (<EQL:CMP>, <GPI:MODE>mode, > + cc_reg, const0_rtx); > + emit_jump_insn (gen_condjump (cmp_rtx, cc_reg, operands[2])); > + DONE; > + } > +) This pattern isn’t really related to lowering jumps, it’s a splitting optimization. So I wouldn’t group it with other patterns moved here. Ok otherwise. Thanks, Kyrill > + > +(define_insn "aarch64_cb<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))) > + (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))) > + (const_int 0) > + (const_int 1)))] > +) > + > +(define_insn "*cb<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))) > + (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))) > + (const_int 0) > + (const_int 1)))] > +) > + > +;; ------------------------------------------------------------------- > +;; Test bit and branch > +;; ------------------------------------------------------------------- > + > +(define_expand "tbranch_<code><mode>3" > + [(set (pc) (if_then_else > + (EQL (match_operand:SHORT 0 "register_operand") > + (match_operand 1 "const0_operand")) > + (label_ref (match_operand 2 "")) > + (pc)))] > + "" > +{ > + rtx bitvalue = gen_reg_rtx (<ZEROM>mode); > + rtx reg = gen_lowpart (<ZEROM>mode, operands[0]); > + rtx val = gen_int_mode (HOST_WIDE_INT_1U << UINTVAL (operands[1]), > + <MODE>mode); > + emit_insn (gen_and<zerom>3 (bitvalue, reg, val)); > + operands[1] = const0_rtx; > + operands[0] = aarch64_gen_compare_reg (<CODE>, bitvalue, > + operands[1]); > +}) > + > +(define_insn "@aarch64_tb<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))) > + (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))) > + (const_int 0) > + (const_int 1)))] > + > +) > + > (define_insn "@ccmp<CC_ONLY:mode><GPI:mode>" > [(set (match_operand:CC_ONLY 1 "cc_register") > (if_then_else:CC_ONLY > @@ -861,71 +1062,6 @@ (define_expand "mod<mode>3" > } > ) > > -(define_insn "condjump" > - [(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))) > - (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))) > - (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 > -(define_insn_and_split "*compare_condjump<GPI:mode>" > - [(set (pc) (if_then_else (EQL > - (match_operand:GPI 0 "register_operand" "r") > - (match_operand:GPI 1 "aarch64_imm24" "n")) > - (label_ref:P (match_operand 2 "" "")) > - (pc)))] > - "!aarch64_move_imm (INTVAL (operands[1]), <GPI:MODE>mode) > - && !aarch64_plus_operand (operands[1], <GPI:MODE>mode) > - && !reload_completed" > - "#" > - "&& true" > - [(const_int 0)] > - { > - HOST_WIDE_INT lo_imm = UINTVAL (operands[1]) & 0xfff; > - HOST_WIDE_INT hi_imm = UINTVAL (operands[1]) & 0xfff000; > - rtx tmp = gen_reg_rtx (<GPI:MODE>mode); > - emit_insn (gen_add<GPI:mode>3 (tmp, operands[0], GEN_INT (-hi_imm))); > - emit_insn (gen_add<GPI:mode>3_compare0 (tmp, tmp, GEN_INT (-lo_imm))); > - rtx cc_reg = gen_rtx_REG (CC_NZmode, CC_REGNUM); > - rtx cmp_rtx = gen_rtx_fmt_ee (<EQL:CMP>, <GPI:MODE>mode, > - cc_reg, const0_rtx); > - emit_jump_insn (gen_condjump (cmp_rtx, cc_reg, operands[2])); > - DONE; > - } > -) > - > (define_expand "casesi" > [(match_operand:SI 0 "register_operand") ; Index > (match_operand:SI 1 "const_int_operand") ; Lower bound > @@ -1117,127 +1253,6 @@ (define_insn "simple_return" > (set_attr "sls_length" "retbr")] > ) > > -(define_insn "aarch64_cb<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))) > - (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))) > - (const_int 0) > - (const_int 1)))] > -) > - > -(define_expand "tbranch_<code><mode>3" > - [(set (pc) (if_then_else > - (EQL (match_operand:SHORT 0 "register_operand") > - (match_operand 1 "const0_operand")) > - (label_ref (match_operand 2 "")) > - (pc)))] > - "" > -{ > - rtx bitvalue = gen_reg_rtx (<ZEROM>mode); > - rtx reg = gen_lowpart (<ZEROM>mode, operands[0]); > - rtx val = gen_int_mode (HOST_WIDE_INT_1U << UINTVAL (operands[1]), > <MODE>mode); > - emit_insn (gen_and<zerom>3 (bitvalue, reg, val)); > - operands[1] = const0_rtx; > - operands[0] = aarch64_gen_compare_reg (<CODE>, bitvalue, > - operands[1]); > -}) > - > -(define_insn "@aarch64_tb<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))) > - (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))) > - (const_int 0) > - (const_int 1)))] > - > -) > - > -(define_insn "*cb<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))) > - (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))) > - (const_int 0) > - (const_int 1)))] > -) > - > (define_expand "save_stack_nonlocal" > [(set (match_operand 0 "memory_operand") > (match_operand 1 "register_operand"))] > -- > 2.45.2 >