Hi,

on 2023/10/25 10:00, Jiufu Guo wrote:
> Hi,
> 
> Trunk gcc supports more constants to be built via two instructions: e.g.
> "li/lis; xori/xoris/rldicl/rldicr/rldic".
> And then num_insns_constant should also be updated.
> 

Thanks for updating this.

> Bootstrap & regtest pass ppc64{,le}.
> Is this ok for trunk?
> 
> BR,
> Jeff (Jiufu Guo)
> 
> gcc/ChangeLog:
> 
>       * config/rs6000/rs6000.cc (can_be_built_by_lilis_and_rldicX): New
>       function.
>       (num_insns_constant_gpr): Update to return 2 for more cases.
>       (rs6000_emit_set_long_const): Update to use
>       can_be_built_by_lilis_and_rldicX.
> 
> ---
>  gcc/config/rs6000/rs6000.cc | 64 ++++++++++++++++++++++++-------------
>  1 file changed, 41 insertions(+), 23 deletions(-)
> 
> diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
> index cc24dd5301e..b23ff3d7917 100644
> --- a/gcc/config/rs6000/rs6000.cc
> +++ b/gcc/config/rs6000/rs6000.cc
> @@ -6032,6 +6032,9 @@ direct_return (void)
>    return 0;
>  }
>  
> +static bool
> +can_be_built_by_lilis_and_rldicX (HOST_WIDE_INT, int *, HOST_WIDE_INT *);
> +
>  /* Helper for num_insns_constant.  Calculate number of instructions to
>     load VALUE to a single gpr using combinations of addi, addis, ori,
>     oris, sldi and rldimi instructions.  */
> @@ -6044,35 +6047,41 @@ num_insns_constant_gpr (HOST_WIDE_INT value)
>      return 1;
>  
>    /* constant loadable with addis */
> -  else if ((value & 0xffff) == 0
> -        && (value >> 31 == -1 || value >> 31 == 0))
> +  if ((value & 0xffff) == 0 && (value >> 31 == -1 || value >> 31 == 0))
>      return 1;
>  
>    /* PADDI can support up to 34 bit signed integers.  */
> -  else if (TARGET_PREFIXED && SIGNED_INTEGER_34BIT_P (value))
> +  if (TARGET_PREFIXED && SIGNED_INTEGER_34BIT_P (value))
>      return 1;
>  
> -  else if (TARGET_POWERPC64)
> -    {
> -      HOST_WIDE_INT low = sext_hwi (value, 32);
> -      HOST_WIDE_INT high = value >> 31;
> +  if (!TARGET_POWERPC64)
> +    return 2;
>  
> -      if (high == 0 || high == -1)
> -     return 2;
> +  HOST_WIDE_INT low = sext_hwi (value, 32);
> +  HOST_WIDE_INT high = value >> 31;
>  
> -      high >>= 1;
> +  if (high == 0 || high == -1)
> +    return 2;
>  
> -      if (low == 0 || low == high)
> -     return num_insns_constant_gpr (high) + 1;
> -      else if (high == 0)
> -     return num_insns_constant_gpr (low) + 1;
> -      else
> -     return (num_insns_constant_gpr (high)
> -             + num_insns_constant_gpr (low) + 1);
> -    }
> +  high >>= 1;
>  
> -  else
> +  HOST_WIDE_INT ud2 = (low >> 16) & 0xffff;
> +  HOST_WIDE_INT ud1 = low & 0xffff;
> +  if (high == -1 && ((!(ud2 & 0x8000) && ud1 == 0) || (ud1 & 0x8000)))
> +    return 2;
> +  if (high == 0 && (ud1 == 0 || (!(ud1 & 0x8000))))
>      return 2;

I was thinking that instead of enumerating all the cases in function
rs6000_emit_set_long_const, if we can add one optional argument like
"int* num_insns=nullptr" to function rs6000_emit_set_long_const, and
when it's not nullptr, not emitting anything but update the count in
rs6000_emit_set_long_const.  It helps people remember to update
num_insns when updating rs6000_emit_set_long_const in future, it's
also more clear on how the number comes from.

Does it sound good to you?

BR,
Kewen

> +
> +  int shift;
> +  HOST_WIDE_INT mask;
> +  if (can_be_built_by_lilis_and_rldicX (value, &shift, &mask))
> +    return 2;
> +
> +  if (low == 0 || low == high)
> +    return num_insns_constant_gpr (high) + 1;
> +  if (high == 0)
> +    return num_insns_constant_gpr (low) + 1;
> +  return (num_insns_constant_gpr (high) + num_insns_constant_gpr (low) + 1);
>  }
>  
>  /* Helper for num_insns_constant.  Allow constants formed by the
> @@ -10492,6 +10501,18 @@ can_be_built_by_li_and_rldic (HOST_WIDE_INT c, int 
> *shift, HOST_WIDE_INT *mask)
>    return false;
>  }
>  
> +/* Combine the above checking functions for  li/lis;rldicX. */
> +
> +static bool
> +can_be_built_by_lilis_and_rldicX (HOST_WIDE_INT c, int *shift,
> +                               HOST_WIDE_INT *mask)
> +{
> +  return (can_be_built_by_li_lis_and_rotldi (c, shift, mask)
> +       || can_be_built_by_li_lis_and_rldicl (c, shift, mask)
> +       || can_be_built_by_li_lis_and_rldicr (c, shift, mask)
> +       || can_be_built_by_li_and_rldic (c, shift, mask));
> +}
> +
>  /* Subroutine of rs6000_emit_set_const, handling PowerPC64 DImode.
>     Output insns to set DEST equal to the constant C as a series of
>     lis, ori and shl instructions.  */
> @@ -10538,10 +10559,7 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT 
> c)
>        emit_move_insn (dest, gen_rtx_XOR (DImode, temp,
>                                        GEN_INT ((ud2 ^ 0xffff) << 16)));
>      }
> -  else if (can_be_built_by_li_lis_and_rotldi (c, &shift, &mask)
> -        || can_be_built_by_li_lis_and_rldicl (c, &shift, &mask)
> -        || can_be_built_by_li_lis_and_rldicr (c, &shift, &mask)
> -        || can_be_built_by_li_and_rldic (c, &shift, &mask))
> +  else if (can_be_built_by_lilis_and_rldicX (c, &shift, &mask))
>      {
>        temp = !can_create_pseudo_p () ? dest : gen_reg_rtx (DImode);
>        unsigned HOST_WIDE_INT imm = (c | ~mask);

Reply via email to