On 9/10/19 10:29 AM, Richard Sandiford wrote:
> On targets that use reload, call_fixed_reg_set is structurally:
> 
>   fixed_reg_set                           -- reginfo.c
>   | (call_used_reg_set & ~have_save_mode) -- first loop in init_caller_save
>   | ~have_save_insn                       -- final loop in init_caller_save
> 
> (where "have_save_mode" and "have_save_insn" are just my names).
> But the final loop in init_caller_save does:
> 
>   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
>     for (j = 1; j <= MOVE_MAX_WORDS; j++)
>       if (reg_save_code (i,regno_save_mode[i][j]) == -1)
> 
> This last condition ought to be true whenever:
> 
>   regno_save_mode[i][j] == VOIDmode
> 
> since either targetm.hard_regno_mode_ok (i, VOIDmode) should be
> false or the VOIDmode save & restore shouldn't match any move insn.
> And after the first loop, regno_save_mode[i][j] == VOIDmode whenever
> !call_used_regs[i].  So the above is actually:
> 
>   fixed_reg_set
>   | (call_used_reg_set & ~have_save_mode)
>   | (~call_used_reg_set | ~have_save_insn)
> 
> which simplifies to:
> 
>   fixed_reg_set                        -- reginfo.c
>   | ~have_save_mode                    -- first loop in init_caller_save
>   | ~have_save_insn                    -- final loop in init_caller_save
>   | ~call_used_reg_set                 -- final loop in init_caller_save
> 
> So:
> 
>   ~call_fixed_reg_set == (~fixed_reg_set
>                         & have_save_mode
>                         & have_save_insn
>                         & call_used_reg_set)  [A]
> 
> All users have the form:
> 
>   (call_used_reg_set or some subset) & ~(call_fixed_reg_set | ...)
> 
> i.e.:
> 
>   (call_used_reg_set or some subset) & ~call_fixed_reg_set & ~(...)
> 
> We can therefore drop the "& call_used_reg_set" from [A], leaving:
> 
>   ~fixed_reg_set & have_save_mode & have_save_insn
> 
> This patch combines have_save_mode & have_save_insn into a single
> condition "a save is possible", represented as savable_regs.
> We can then substitute:
> 
>   ~call_fixed_reg_set --> ~fixed_reg_set & savable_regs
>                           (registers we can actually save around calls)
> 
> The patch also sets regno_save_mode[i][j] for all registers,
> in case non-default ABIs require a save when the default ABI
> doesn't.  This ensures that savable_regs (like fixed_reg_set but
> unlike call_fixed_reg_set) isn't affected by the ABI.  This only
> becomes significant with later patches and at this point is just
> a simplification.
> 
> Since init_caller_save is only called for reload targets,
> the default assumption for LRA is that all registers are savable,
> just like the default assumption before the patch was that
> (~)call_fixed_reg_set == (~)fixed_reg_set.
> 
> 
> 2019-09-10  Richard Sandiford  <richard.sandif...@arm.com>
> 
> gcc/
>       * hard-reg-set.h (target_hard_regs::x_call_fixed_reg_set): Delete.
>       (target_hard_regs::x_savable_regs): New field.
>       (call_fixed_reg_set): Delete.
>       (savable_regs): New macro,
>       * reginfo.c (globalize_reg): Don't set call_fixed_reg_set.
>       (init_reg_sets_1): Likewise.  Initialize savable_regs.
>       * caller-save.c (init_caller_save): Invoke HARD_REGNO_CALLER_SAVE_MODE
>       for all registers.  Set savable_regs instead of call_fixed_reg_set.
>       (setup_save_areas, save_call_clobbered_regs): Replace uses of
>       ~call_fixed_reg_set with ~fixed_reg_set & savable_regs.
>       * config/sh/sh.c (output_stack_adjust): Likewise.
OK.

Given that the major targets at this point are LRA and caller-saves is
strictly for reload and of marginal value unless the target has heavily
used register classes with no callee saved regs, one could make an
argument that we should just drop caller-save.  That's clearly an
independent change, but one that I'd seriously consider.

jeff

Reply via email to