Richard Henderson <[email protected]> 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")))]
> )