> Am 12.11.2026 um 06:38 schrieb Surya Kumari Jangala <[email protected]>:
> 
> rs6000: De-prioritize r2 register allocation on PowerPC with pcrel
> 
> On PowerPC with PC-relative addressing (pcrel), r2 is not fixed and
> becomes available for general register allocation.
> 
> This patch introduces a new target hook TARGET_ALLOCNO_HARD_REG_COST
> that allows targets to add cost penalties to specific registers, causing
> register allocator to deprioritize them without making them completely
> unavailable (as fixed_regs would).
> 
> For PowerPC, this hook adds a penalty to r2 that exceeds callee-save
> costs, ensuring r2 is chosen only after all other general-purpose
> registers (both caller-saved and callee-saved) have been exhausted.

Isn’t that what reg-alloc-order is for?

> The penalty is only applied when r2 is not fixed (i.e., in pcrel mode).
> 
> gcc/
>    * target.def (allocno_hard_reg_cost): New target hook.
>    * doc/tm.texi: Regenerate.
>    * doc/tm.texi.in: Add TARGET_ALLOCNO_HARD_REG_COST reference.
>    * targhooks.cc (default_allocno_hard_reg_cost): New function.
>    * targhooks.h (default_allocno_hard_reg_cost): Declare.
>    * ira-color.cc (assign_hard_reg): Call targetm.allocno_hard_reg_cost to
>    add register-specific cost penalties.
>    (improve_allocation): Likewise.
>    * config/rs6000/rs6000.cc (rs6000_allocno_hard_reg_cost): New function.
>    (TARGET_ALLOCNO_HARD_REG_COST): Define.
> 
> gcc/testsuite/
>    * gcc.target/powerpc/pr110320-1.c: Update dg-options. Update comment.
> ---
> gcc/config/rs6000/rs6000.cc                   | 24 +++++++++++++++++++
> gcc/doc/tm.texi                               | 18 ++++++++++++++
> gcc/doc/tm.texi.in                            |  2 ++
> gcc/ira-color.cc                              | 22 +++++++++++++++++
> gcc/target.def                                | 20 ++++++++++++++++
> gcc/targhooks.cc                              |  6 +++++
> gcc/targhooks.h                               |  1 +
> gcc/testsuite/gcc.target/powerpc/pr110320-1.c |  8 +++----
> 8 files changed, 97 insertions(+), 4 deletions(-)
> 
> diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
> index 9581d122a9d..c8025cba97b 100644
> --- a/gcc/config/rs6000/rs6000.cc
> +++ b/gcc/config/rs6000/rs6000.cc
> @@ -1122,6 +1122,7 @@ static tree rs6000_handle_struct_attribute (tree *, 
> tree, tree, int, bool *);
> static tree rs6000_builtin_vectorized_libmass (combined_fn, tree, tree);
> static void rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, int * = nullptr);
> static int rs6000_memory_move_cost (machine_mode, reg_class_t, bool);
> +static int rs6000_allocno_hard_reg_cost (int, machine_mode, int);
> static bool rs6000_debug_rtx_costs (rtx, machine_mode, int, int, int *, bool);
> static int rs6000_debug_address_cost (rtx, machine_mode, addr_space_t,
>                      bool);
> @@ -1495,6 +1496,8 @@ static const scoped_attribute_specs *const 
> rs6000_attribute_table[] =
> #define TARGET_REGISTER_MOVE_COST rs6000_register_move_cost
> #undef TARGET_MEMORY_MOVE_COST
> #define TARGET_MEMORY_MOVE_COST rs6000_memory_move_cost
> +#undef TARGET_ALLOCNO_HARD_REG_COST
> +#define TARGET_ALLOCNO_HARD_REG_COST rs6000_allocno_hard_reg_cost
> #undef TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS
> #define TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS \
>   rs6000_ira_change_pseudo_allocno_class
> @@ -23105,6 +23108,27 @@ rs6000_memory_move_cost (machine_mode mode, 
> reg_class_t rclass,
>   return ret;
> }
> 
> +/* Implement TARGET_ALLOCNO_HARD_REG_COST.
> +
> +   Penalise r2 (TOC register) so the IRA cost-based allocator chooses
> +   it last among all GPRs, after both caller-saved and callee-saved
> +   registers.  The penalty uses the same memory-move cost basis as the
> +   callee-save cost computation in assign_hard_reg, multiplied by 2 to
> +   guarantee it strictly exceeds any callee-save cost even when the
> +   allocno's usage frequency equals the function entry/exit frequency.  */
> +
> +static int
> +rs6000_allocno_hard_reg_cost (int hard_regno, machine_mode mode, int freq)
> +{
> +  if (fixed_regs[2] || hard_regno != 2)
> +    return 0;
> +
> +  reg_class_t rclass = REGNO_REG_CLASS (hard_regno);
> +  return ((ira_memory_move_cost[mode][rclass][0]
> +       + ira_memory_move_cost[mode][rclass][1])
> +      * freq * 2);
> +}
> +
> /* Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS.
> 
>    The register allocator chooses GEN_OR_VSX_REGS for the allocno
> diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
> index 65cf4c640e7..b5b7d79278b 100644
> --- a/gcc/doc/tm.texi
> +++ b/gcc/doc/tm.texi
> @@ -7169,6 +7169,24 @@ allocator has not yet committed to using both 
> strategies.
> The default implementation returns 0.
> @end deftypefn
> 
> +@deftypefn {Target Hook} int TARGET_ALLOCNO_HARD_REG_COST (int 
> @var{hard_regno}, machine_mode @var{mode}, int @var{freq})
> +Return an additional cost penalty for the IRA register allocator to apply
> +to hard register @var{hard_regno} when costing an allocno.  This hook allows
> +targets to deprioritize specific registers in the allocation order without
> +making them unavailable (as @code{fixed_regs} would).
> +@var{mode} is the mode of the allocno and @var{freq} is its usage
> +frequency (@code{ALLOCNO_FREQ}).
> +
> +Use this hook when a register should remain available for allocation but
> +be chosen only as a last resort.
> +
> +The cost value should be chosen to achieve the desired prioritization 
> relative
> +to other allocation costs in the target.  For instance, to deprioritize a
> +register below all other general-purpose registers including callee-saved
> +registers, the penalty should exceed typical callee-save costs.
> +Return 0 (the default) to apply no penalty.
> +@end deftypefn
> +
> @defmac BRANCH_COST (@var{speed_p}, @var{predictable_p})
> A C expression for the cost of a branch instruction.  A value of 1 is
> the default; other values are interpreted relative to that. Parameter
> diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
> index 6b8203c5bed..039b5909d5f 100644
> --- a/gcc/doc/tm.texi.in
> +++ b/gcc/doc/tm.texi.in
> @@ -4634,6 +4634,8 @@ These macros are obsolete, new ports should use the 
> target hook
> 
> @hook TARGET_FRAME_ALLOCATION_COST
> 
> +@hook TARGET_ALLOCNO_HARD_REG_COST
> +
> @defmac BRANCH_COST (@var{speed_p}, @var{predictable_p})
> A C expression for the cost of a branch instruction.  A value of 1 is
> the default; other values are interpreted relative to that. Parameter
> diff --git a/gcc/ira-color.cc b/gcc/ira-color.cc
> index 866d5b6bec3..807bc19f1cf 100644
> --- a/gcc/ira-color.cc
> +++ b/gcc/ira-color.cc
> @@ -2292,6 +2292,19 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
>      cost += spill_cost;
>      full_cost += spill_cost;
>    }
> +
> +      /* Allow the target to add an unconditional cost penalty to
> +     specific hard registers.  */
> +      {
> +    int add_cost = targetm.allocno_hard_reg_cost (hard_regno, mode,
> +                              ALLOCNO_FREQ (a));
> +    if (add_cost != 0)
> +      {
> +        cost += add_cost;
> +        full_cost += add_cost;
> +      }
> +      }
> +
>       if (min_cost > cost)
>    min_cost = cost;
>       if (min_full_cost > full_cost)
> @@ -3345,6 +3358,15 @@ improve_allocation (void)
>        costs[hregno] += add_cost;
>      }
> 
> +      /* Allow the target to add an unconditional cost penalty to
> +         specific hard registers.  */
> +      {
> +        int add_cost = targetm.allocno_hard_reg_cost (hregno, mode,
> +                              ALLOCNO_FREQ (a));
> +        if (add_cost != 0)
> +          costs[hregno] += add_cost;
> +      }
> +
>      costs[hregno] -= base_cost;
>      if (costs[hregno] < 0)
>        try_p = true;
> diff --git a/gcc/target.def b/gcc/target.def
> index 877bd166b23..ac5053fb6dd 100644
> --- a/gcc/target.def
> +++ b/gcc/target.def
> @@ -4004,6 +4004,26 @@ The default implementation returns 0.",
>  int, (frame_cost_type cost_type, const HARD_REG_SET &allocated_callee_regs),
>  default_frame_allocation_cost)
> 
> +DEFHOOK
> +(allocno_hard_reg_cost,
> + "Return an additional cost penalty for the IRA register allocator to 
> apply\n\
> +to hard register @var{hard_regno} when costing an allocno.  This hook 
> allows\n\
> +targets to deprioritize specific registers in the allocation order without\n\
> +making them unavailable (as @code{fixed_regs} would).\n\
> +@var{mode} is the mode of the allocno and @var{freq} is its usage\n\
> +frequency (@code{ALLOCNO_FREQ}).\n\
> +\n\
> +Use this hook when a register should remain available for allocation but\n\
> +be chosen only as a last resort.\n\
> +\n\
> +The cost value should be chosen to achieve the desired prioritization 
> relative\n\
> +to other allocation costs in the target.  For instance, to deprioritize a\n\
> +register below all other general-purpose registers including callee-saved\n\
> +registers, the penalty should exceed typical callee-save costs.\n\
> +Return 0 (the default) to apply no penalty.",
> + int, (int hard_regno, machine_mode mode, int freq),
> + default_allocno_hard_reg_cost)
> +
> DEFHOOK
> (use_by_pieces_infrastructure_p,
>  "GCC will attempt several strategies when asked to copy between\n\
> diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
> index 727a0f2ba32..f7f53a942ea 100644
> --- a/gcc/targhooks.cc
> +++ b/gcc/targhooks.cc
> @@ -2167,6 +2167,12 @@ default_frame_allocation_cost (frame_cost_type, const 
> HARD_REG_SET &)
>   return 0;
> }
> 
> +int
> +default_allocno_hard_reg_cost (int, machine_mode, int)
> +{
> +  return 0;
> +}
> +
> /* The default implementation of TARGET_SLOW_UNALIGNED_ACCESS.  */
> 
> bool
> diff --git a/gcc/targhooks.h b/gcc/targhooks.h
> index d5f4548fc7c..b6ccf8bc248 100644
> --- a/gcc/targhooks.h
> +++ b/gcc/targhooks.h
> @@ -245,6 +245,7 @@ extern int default_callee_save_cost (spill_cost_type, 
> unsigned int,
>                     const HARD_REG_SET &, bool);
> extern int default_frame_allocation_cost (frame_cost_type,
>                      const HARD_REG_SET &);
> +extern int default_allocno_hard_reg_cost (int, machine_mode, int);
> extern bool default_slow_unaligned_access (machine_mode, unsigned int);
> extern HOST_WIDE_INT default_estimated_poly_value (poly_int64,
>                           poly_value_estimate_kind);
> diff --git a/gcc/testsuite/gcc.target/powerpc/pr110320-1.c 
> b/gcc/testsuite/gcc.target/powerpc/pr110320-1.c
> index a87b37c52be..34ea8c2de26 100644
> --- a/gcc/testsuite/gcc.target/powerpc/pr110320-1.c
> +++ b/gcc/testsuite/gcc.target/powerpc/pr110320-1.c
> @@ -1,15 +1,15 @@
> /* PR target/110320 */
> /* { dg-require-effective-target powerpc_elfv2 } */
> /* { dg-require-effective-target powerpc_pcrel } */
> -/* { dg-options "-O2 -mdejagnu-cpu=power10 -ffixed-r0 -ffixed-r11 
> -ffixed-r12" } */
> +/* { dg-options "-O2 -mdejagnu-cpu=power10 -ffixed-r0 -ffixed-r11 
> -ffixed-r12 -ffixed-r13 -ffixed-r14 -ffixed-r15 -ffixed-r16 -ffixed-r17 
> -ffixed-r18 -ffixed-r19 -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 
> -ffixed-r24 -ffixed-r25 -ffixed-r26 -ffixed-r27 -ffixed-r28 -ffixed-r29 
> -ffixed-r30 -ffixed-r31" } */
> 
> /* Ensure we use r2 as a normal volatile register for the code below.
>    The test case ensures all of the parameter registers r3 - r10 are used
>    and needed after we compute the expression "x + y" which requires a
>    temporary.  The -ffixed-r* options disallow using the other volatile
> -   registers r0, r11 and r12.  That leaves RA to choose from r2 and the more
> -   expensive non-volatile registers for the temporary to be assigned to, and
> -   RA will always chooses the cheaper volatile r2 register.  */
> +   registers r0, r11 and r12, as well as all callee-saved registers r13-r31. 
>                                                                   │
> +   That leaves RA to choose r2, demonstrating that r2 is available for       
>                                                                   │
> +   allocation when not fixed (as in pcrel mode).  */
> 
> extern long bar (long, long, long, long, long, long, long, long *);
> 
> --
> 2.52.0
> 

Reply via email to