Alexandre Oliva via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> When the mode of regno_reg_rtx is not hard_regno_mode_ok for the
> target, try grouping the register with subsequent ones.  This enables
> s16 to s31 and their hidden pairs to be zeroed with the default logic
> on some arm variants.
>
> Regstrapped on x86_64-linux-gnu, also tested on an affected arm
> configuration.  Ok to install?
>
>
> for  gcc/ChangeLog
>
>       * targhooks.c (default_zero_call_used_regs): Attempt to group
>       regs that the target refuses to use in their natural modes.

Thanks for doing this.  Some comments below…

> ---
>  gcc/targhooks.cc |   79 
> ++++++++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 70 insertions(+), 9 deletions(-)
>
> diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
> index fc49235eb38ee..bdaab9c63c7ee 100644
> --- a/gcc/targhooks.cc
> +++ b/gcc/targhooks.cc
> @@ -1035,16 +1035,45 @@ default_zero_call_used_regs (HARD_REG_SET 
> need_zeroed_hardregs)
>      if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno))
>        {
>       rtx_insn *last_insn = get_last_insn ();
> -     machine_mode mode = GET_MODE (regno_reg_rtx[regno]);
> +     rtx regno_rtx = regno_reg_rtx[regno];
> +     machine_mode mode = GET_MODE (regno_rtx);
> +
> +     /* If the natural mode doesn't work, try some wider mode.  */
> +     if (!targetm.hard_regno_mode_ok (regno, mode))
> +       {
> +         for (int nregs = 2;
> +              regno + nregs <= FIRST_PSEUDO_REGISTER
> +                && TEST_HARD_REG_BIT (need_zeroed_hardregs,
> +                                      regno + nregs - 1);
> +              nregs++)
> +           {
> +             mode = choose_hard_reg_mode (regno, nregs, 0);

I like the idea, but it would be good to avoid the large:

  FIRST_PSEUDO_REGISTER * FIRST_PSEUDO_REGISTER * NUM_MACHINE_MODES

constant factor.  How about if init_reg_modes_target recorded the
maximum value of x_hard_regno_nregs?

> +             if (mode == E_VOIDmode)
> +               continue;
> +             gcc_checking_assert (targetm.hard_regno_mode_ok (regno, mode));
> +             regno_rtx = gen_rtx_REG (mode, regno);
> +             break;
> +           }
> +         if (mode != GET_MODE (regno_rtx)
> +             || regno_rtx == regno_reg_rtx[regno])
> +           {
> +             SET_HARD_REG_BIT (failed, regno);
> +             continue;
> +           }
> +       }
> +
>       rtx zero = CONST0_RTX (mode);
> -     rtx_insn *insn = emit_move_insn (regno_reg_rtx[regno], zero);
> +     rtx_insn *insn = emit_move_insn (regno_rtx, zero);
>       if (!valid_insn_p (insn))
>         {
>           SET_HARD_REG_BIT (failed, regno);
>           delete_insns_since (last_insn);
>         }
>       else
> -       progress = true;
> +       {
> +         progress = true;
> +         regno += hard_regno_nregs (regno, mode) - 1;
> +       }
>        }
>  
>    /* Now retry with copies from zeroed registers, as long as we've
> @@ -1060,7 +1089,34 @@ default_zero_call_used_regs (HARD_REG_SET 
> need_zeroed_hardregs)
>        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]);
> +         rtx regno_rtx = regno_reg_rtx[regno];
> +         machine_mode mode = GET_MODE (regno_rtx);
> +
> +         /* If the natural mode doesn't work, try some wider mode.  */
> +         if (!targetm.hard_regno_mode_ok (regno, mode))
> +           {
> +             for (int nregs = 2;
> +                  regno + nregs <= FIRST_PSEUDO_REGISTER
> +                    && TEST_HARD_REG_BIT (need_zeroed_hardregs,
> +                                          regno + nregs - 1);
> +                  nregs++)
> +               {
> +                 mode = choose_hard_reg_mode (regno, nregs, 0);
> +                 if (mode == E_VOIDmode)
> +                   continue;
> +                 gcc_checking_assert (targetm.hard_regno_mode_ok (regno,
> +                                                                  mode));
> +                 regno_rtx = gen_rtx_REG (mode, regno);
> +                 break;
> +               }
> +             if (mode != GET_MODE (regno_rtx)
> +                 || regno_rtx == regno_reg_rtx[regno])
> +               {
> +                 SET_HARD_REG_BIT (failed, regno);
> +                 continue;
> +               }
> +           }
> +         

This seems big enough to be worth splitting out into a helper, rather
than repeating.  That should also simplify the failure detection:
the helper can return nonnull on success and null on failure.

>           bool success = false;
>           /* Look for a source.  */
>           for (unsigned int src = 0; src < FIRST_PSEUDO_REGISTER; src++)
> @@ -1086,8 +1142,10 @@ default_zero_call_used_regs (HARD_REG_SET 
> need_zeroed_hardregs)
>  
>               /* 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);
> +             rtx src_rtx = (mode == GET_MODE (regno_reg_rtx[src])
> +                            ? regno_reg_rtx[src]
> +                            : gen_rtx_REG (mode, src));

Is this needed?  The original gen_rtx_REG (mode, src) seems OK.

Thanks,
Richard

> +             rtx_insn *insn = emit_move_insn (regno_rtx, src_rtx);
>               if (!valid_insn_p (insn))
>                 /* It didn't work, remove any inserts.  We'll look
>                    for another SRC.  */
> @@ -1100,13 +1158,16 @@ default_zero_call_used_regs (HARD_REG_SET 
> need_zeroed_hardregs)
>                 }
>             }
>  
> -         /* If nothing worked for REGNO this round, marked it to be
> +         /* If nothing worked for REGNO this round, mark 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;
> +           {
> +             /* Take note so as to enable another round if needed.  */
> +             progress = true;
> +             regno += hard_regno_nregs (regno, mode) - 1;
> +           }
>         }
>      }

Reply via email to