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);