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.
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; + + 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); -- 2.25.1