Message ID | oreeec7nkp.fsf@lxoliva.fsfla.org |
---|---|
State | New |
Headers | show |
Series | retry zero-call-used-regs from zeroed regs | expand |
On Wed, May 12, 2021 at 3:44 AM Alexandre Oliva <oliva@adacore.com> wrote: > > > default_zero_call_used_regs currently requires all potentially zeroed > registers to offer a move opcode that accepts zero as an operand. > > This is not the case e.g. for ARM's r12/ip in Thumb mode, and it was > not the case of FP registers on AArch64 as of GCC 10. > > This patch introduces a fallback strategy to zero out registers, > copying from registers that have already been zeroed. Adjacent > sources to make up wider modes are also supported. > > This does not guarantee that there will be some zeroed-out register to > use as the source, but it expands the cases in which the default > implementation works out of the box. > > This patch was regstrapped on x86_64-linux-gnu, where it is not supposed > to make any difference. It was also tested with an older to which the > feature was backported, with flag_zero_call_used_regs defaulting to ALL > and to USED on x86_64-linux-gnu (bootstrap), arm-eabi, aarch64-elf, and > a few other targets that didn't hit problems before or after the patch. > ARM and AArch64 failed to build target libs in that tree without this > patch, and succeeded with it. AArch64 wouldn't have required the patch > in mainline, because of improvements to movti. Ok to install? OK. Thanks, Richard. > > for gcc/ChangeLog > > * targhooks.c (default_zero_call_used_regs): Retry using > successfully-zeroed registers as sources. > --- > gcc/targhooks.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 86 insertions(+), 7 deletions(-) > > diff --git a/gcc/targhooks.c b/gcc/targhooks.c > index 2e0fdb797e093..1947ef26fd644 100644 > --- a/gcc/targhooks.c > +++ b/gcc/targhooks.c > @@ -1001,6 +1001,13 @@ default_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs) > { > gcc_assert (!hard_reg_set_empty_p (need_zeroed_hardregs)); > > + HARD_REG_SET failed; > + CLEAR_HARD_REG_SET (failed); > + bool progress = false; > + > + /* First, try to zero each register in need_zeroed_hardregs by > + loading a zero into it, taking note of any failures in > + FAILED. */ > for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) > if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno)) > { > @@ -1010,16 +1017,88 @@ default_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs) > rtx_insn *insn = emit_move_insn (regno_reg_rtx[regno], zero); > if (!valid_insn_p (insn)) > { > - static bool issued_error; > - if (!issued_error) > - { > - issued_error = true; > - sorry ("%qs not supported on this target", > - "-fzero-call-used-regs"); > - } > + SET_HARD_REG_BIT (failed, regno); > delete_insns_since (last_insn); > } > + else > + progress = true; > } > + > + /* Now retry with copies from zeroed registers, as long as we've > + made some PROGRESS, and registers remain to be zeroed in > + FAILED. */ > + while (progress && !hard_reg_set_empty_p (failed)) > + { > + HARD_REG_SET retrying = failed; > + > + CLEAR_HARD_REG_SET (failed); > + progress = false; > + > + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) > + if (TEST_HARD_REG_BIT (retrying, regno)) > + { > + machine_mode mode = GET_MODE (regno_reg_rtx[regno]); > + bool success = false; > + /* Look for a source. */ > + for (unsigned int src = 0; src < FIRST_PSEUDO_REGISTER; src++) > + { > + /* If SRC hasn't been zeroed (yet?), skip it. */ > + if (! TEST_HARD_REG_BIT (need_zeroed_hardregs, src)) > + continue; > + if (TEST_HARD_REG_BIT (retrying, src)) > + continue; > + > + /* Check that SRC can hold MODE, and that any other > + registers needed to hold MODE in SRC have also been > + zeroed. */ > + if (!targetm.hard_regno_mode_ok (src, mode)) > + continue; > + unsigned n = targetm.hard_regno_nregs (src, mode); > + bool ok = true; > + for (unsigned i = 1; ok && i < n; i++) > + ok = (TEST_HARD_REG_BIT (need_zeroed_hardregs, src + i) > + && !TEST_HARD_REG_BIT (retrying, src + i)); > + if (!ok) > + continue; > + > + /* SRC is usable, try to copy from it. */ > + rtx_insn *last_insn = get_last_insn (); > + rtx zsrc = gen_rtx_REG (mode, src); > + rtx_insn *insn = emit_move_insn (regno_reg_rtx[regno], zsrc); > + if (!valid_insn_p (insn)) > + /* It didn't work, remove any inserts. We'll look > + for another SRC. */ > + delete_insns_since (last_insn); > + else > + { > + /* We're done for REGNO. */ > + success = true; > + break; > + } > + } > + > + /* If nothing worked for REGNO this round, marked it to be > + retried if we get another round. */ > + if (!success) > + SET_HARD_REG_BIT (failed, regno); > + else > + /* Take note so as to enable another round if needed. */ > + progress = true; > + } > + } > + > + /* If any register remained, report it. */ > + if (!progress) > + { > + static bool issued_error; > + if (!issued_error) > + { > + issued_error = true; > + sorry ("%qs not supported on this target", > + "-fzero-call-used-regs"); > + } > + } > + > return need_zeroed_hardregs; > } > > > -- > Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ > Free Software Activist GNU Toolchain Engineer > Disinformation flourishes because many people care deeply about injustice > but very few check the facts. Ask me about <https://stallmansupport.org>
diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 2e0fdb797e093..1947ef26fd644 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1001,6 +1001,13 @@ default_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs) { gcc_assert (!hard_reg_set_empty_p (need_zeroed_hardregs)); + HARD_REG_SET failed; + CLEAR_HARD_REG_SET (failed); + bool progress = false; + + /* First, try to zero each register in need_zeroed_hardregs by + loading a zero into it, taking note of any failures in + FAILED. */ for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno)) { @@ -1010,16 +1017,88 @@ default_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs) rtx_insn *insn = emit_move_insn (regno_reg_rtx[regno], zero); if (!valid_insn_p (insn)) { - static bool issued_error; - if (!issued_error) - { - issued_error = true; - sorry ("%qs not supported on this target", - "-fzero-call-used-regs"); - } + SET_HARD_REG_BIT (failed, regno); delete_insns_since (last_insn); } + else + progress = true; } + + /* Now retry with copies from zeroed registers, as long as we've + made some PROGRESS, and registers remain to be zeroed in + FAILED. */ + while (progress && !hard_reg_set_empty_p (failed)) + { + HARD_REG_SET retrying = failed; + + CLEAR_HARD_REG_SET (failed); + progress = false; + + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (retrying, regno)) + { + machine_mode mode = GET_MODE (regno_reg_rtx[regno]); + bool success = false; + /* Look for a source. */ + for (unsigned int src = 0; src < FIRST_PSEUDO_REGISTER; src++) + { + /* If SRC hasn't been zeroed (yet?), skip it. */ + if (! TEST_HARD_REG_BIT (need_zeroed_hardregs, src)) + continue; + if (TEST_HARD_REG_BIT (retrying, src)) + continue; + + /* Check that SRC can hold MODE, and that any other + registers needed to hold MODE in SRC have also been + zeroed. */ + if (!targetm.hard_regno_mode_ok (src, mode)) + continue; + unsigned n = targetm.hard_regno_nregs (src, mode); + bool ok = true; + for (unsigned i = 1; ok && i < n; i++) + ok = (TEST_HARD_REG_BIT (need_zeroed_hardregs, src + i) + && !TEST_HARD_REG_BIT (retrying, src + i)); + if (!ok) + continue; + + /* SRC is usable, try to copy from it. */ + rtx_insn *last_insn = get_last_insn (); + rtx zsrc = gen_rtx_REG (mode, src); + rtx_insn *insn = emit_move_insn (regno_reg_rtx[regno], zsrc); + if (!valid_insn_p (insn)) + /* It didn't work, remove any inserts. We'll look + for another SRC. */ + delete_insns_since (last_insn); + else + { + /* We're done for REGNO. */ + success = true; + break; + } + } + + /* If nothing worked for REGNO this round, marked it to be + retried if we get another round. */ + if (!success) + SET_HARD_REG_BIT (failed, regno); + else + /* Take note so as to enable another round if needed. */ + progress = true; + } + } + + /* If any register remained, report it. */ + if (!progress) + { + static bool issued_error; + if (!issued_error) + { + issued_error = true; + sorry ("%qs not supported on this target", + "-fzero-call-used-regs"); + } + } + return need_zeroed_hardregs; }