Richard Henderson <richard.hender...@linaro.org> writes: > 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);
It looks like this should be "cmn\t%<w>0, #%n1", since GAS "helpfully" converts cmn w0, #-1 to cmp w0, #1. Alternatively, we could use the cmp string unconditionally and rely on the assembler alias for negative immediates. I don't see anything in the ISA documentation that mandates the negative immediate aliases though, so keeping cmn is probably safer. Richard > + 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")))] > )