[RS6000] num_insns_constant ICE
This patch came about from investigating an ICE that appeared when I was retesting an old half-baked patch of mine to rs6000_rtx_costs. If a const_double is fed to rs6000_is_valid_and_mask and from there to rs6000_is_valid_mask where INTVAL is used, gcc will ICE. The num_insns_constant ICE was introduced with git commit f337168d97. However, the code was buggy before that. There was no point in testing for a mask since the mask predicates only handle const_int. In fact, I don't think the function ever handled floating point constants that might match a load of minus one and mask. It does now. I've added a few comments regarding splitters so the next person looking at this code can see how this works. The patch also extracts code out of num_insns_constant that needed to handle multiple gprs for DFmode constants in 32-bit mode, to a function that handles multiple gprs a little more generally. I don't think there is any need for anything but the 32-bit DFmode case currently, but this allows for possible future uses. The CONST_WIDE_INT case is also not used currently, and needed fixing. Adding CONST_WIDE_INT_NUNITS - 1 only makes sense if the elements of the array were being shifted into a register of size larger than the element size (which is 64-bits). * config/rs6000/rs6000.c (num_insns_constant_gpr): Renamed from num_insns_constant_wide. Make static. Revise comment. (num_insns_constant_multi): New function. (num_insns_constant): Formatting. Correct CONST_WIDE_INT calculation. Simplify and extract code common to both CONST_INT and CONST_DOUBLE. Add gcc_unreachable for unhandled const_double modes. * config/rs6000/rs6000-protos.h (num_insns_const_wide): Delete. From-SVN: r266662
This commit is contained in:
parent
f44697b78a
commit
ceb8c8c4ca
3 changed files with 84 additions and 50 deletions
|
@ -1,3 +1,14 @@
|
|||
2018-11-30 Alan Modra <amodra@gmail.com>
|
||||
|
||||
* config/rs6000/rs6000.c (num_insns_constant_gpr): Renamed from
|
||||
num_insns_constant_wide. Make static. Revise comment.
|
||||
(num_insns_constant_multi): New function.
|
||||
(num_insns_constant): Formatting. Correct CONST_WIDE_INT
|
||||
calculation. Simplify and extract code common to both
|
||||
CONST_INT and CONST_DOUBLE. Add gcc_unreachable for unhandled
|
||||
const_double modes.
|
||||
* config/rs6000/rs6000-protos.h (num_insns_const_wide): Delete.
|
||||
|
||||
2018-11-30 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/88274
|
||||
|
|
|
@ -36,7 +36,6 @@ extern int vspltis_shifted (rtx);
|
|||
extern HOST_WIDE_INT const_vector_elt_as_int (rtx, unsigned int);
|
||||
extern bool macho_lo_sum_memory_operand (rtx, machine_mode);
|
||||
extern int num_insns_constant (rtx, machine_mode);
|
||||
extern int num_insns_constant_wide (HOST_WIDE_INT);
|
||||
extern int small_data_operand (rtx, machine_mode);
|
||||
extern bool mem_operand_gpr (rtx, machine_mode);
|
||||
extern bool mem_operand_ds_form (rtx, machine_mode);
|
||||
|
|
|
@ -5821,11 +5821,12 @@ direct_return (void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return the number of instructions it takes to form a constant in an
|
||||
integer register. */
|
||||
/* Helper for num_insns_constant. Calculate number of instructions to
|
||||
load VALUE to a single gpr using combinations of addi, addis, ori,
|
||||
oris and sldi instructions. */
|
||||
|
||||
int
|
||||
num_insns_constant_wide (HOST_WIDE_INT value)
|
||||
static int
|
||||
num_insns_constant_gpr (HOST_WIDE_INT value)
|
||||
{
|
||||
/* signed constant loadable with addi */
|
||||
if (((unsigned HOST_WIDE_INT) value + 0x8000) < 0x10000)
|
||||
|
@ -5847,85 +5848,108 @@ num_insns_constant_wide (HOST_WIDE_INT value)
|
|||
high >>= 1;
|
||||
|
||||
if (low == 0)
|
||||
return num_insns_constant_wide (high) + 1;
|
||||
return num_insns_constant_gpr (high) + 1;
|
||||
else if (high == 0)
|
||||
return num_insns_constant_wide (low) + 1;
|
||||
return num_insns_constant_gpr (low) + 1;
|
||||
else
|
||||
return (num_insns_constant_wide (high)
|
||||
+ num_insns_constant_wide (low) + 1);
|
||||
return (num_insns_constant_gpr (high)
|
||||
+ num_insns_constant_gpr (low) + 1);
|
||||
}
|
||||
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Helper for num_insns_constant. Allow constants formed by the
|
||||
num_insns_constant_gpr sequences, plus li -1, rldicl/rldicr/rlwinm,
|
||||
and handle modes that require multiple gprs. */
|
||||
|
||||
static int
|
||||
num_insns_constant_multi (HOST_WIDE_INT value, machine_mode mode)
|
||||
{
|
||||
int nregs = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
|
||||
int total = 0;
|
||||
while (nregs-- > 0)
|
||||
{
|
||||
HOST_WIDE_INT low = sext_hwi (value, BITS_PER_WORD);
|
||||
int insns = num_insns_constant_gpr (low);
|
||||
if (insns > 2
|
||||
/* We won't get more than 2 from num_insns_constant_gpr
|
||||
except when TARGET_POWERPC64 and mode is DImode or
|
||||
wider, so the register mode must be DImode. */
|
||||
&& rs6000_is_valid_and_mask (GEN_INT (low), DImode))
|
||||
insns = 2;
|
||||
total += insns;
|
||||
value >>= BITS_PER_WORD;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Return the number of instructions it takes to form a constant in as
|
||||
many gprs are needed for MODE. */
|
||||
|
||||
int
|
||||
num_insns_constant (rtx op, machine_mode mode)
|
||||
{
|
||||
HOST_WIDE_INT low, high;
|
||||
HOST_WIDE_INT val;
|
||||
|
||||
switch (GET_CODE (op))
|
||||
{
|
||||
case CONST_INT:
|
||||
if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
|
||||
&& rs6000_is_valid_and_mask (op, mode))
|
||||
return 2;
|
||||
else
|
||||
return num_insns_constant_wide (INTVAL (op));
|
||||
val = INTVAL (op);
|
||||
break;
|
||||
|
||||
case CONST_WIDE_INT:
|
||||
{
|
||||
int i;
|
||||
int ins = CONST_WIDE_INT_NUNITS (op) - 1;
|
||||
for (i = 0; i < CONST_WIDE_INT_NUNITS (op); i++)
|
||||
ins += num_insns_constant_wide (CONST_WIDE_INT_ELT (op, i));
|
||||
return ins;
|
||||
int insns = 0;
|
||||
for (int i = 0; i < CONST_WIDE_INT_NUNITS (op); i++)
|
||||
insns += num_insns_constant_multi (CONST_WIDE_INT_ELT (op, i),
|
||||
DImode);
|
||||
return insns;
|
||||
}
|
||||
|
||||
case CONST_DOUBLE:
|
||||
case CONST_DOUBLE:
|
||||
{
|
||||
const struct real_value *rv = CONST_DOUBLE_REAL_VALUE (op);
|
||||
|
||||
if (mode == SFmode || mode == SDmode)
|
||||
{
|
||||
long l;
|
||||
|
||||
if (DECIMAL_FLOAT_MODE_P (mode))
|
||||
REAL_VALUE_TO_TARGET_DECIMAL32
|
||||
(*CONST_DOUBLE_REAL_VALUE (op), l);
|
||||
if (mode == SDmode)
|
||||
REAL_VALUE_TO_TARGET_DECIMAL32 (*rv, l);
|
||||
else
|
||||
REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op), l);
|
||||
return num_insns_constant_wide ((HOST_WIDE_INT) l);
|
||||
REAL_VALUE_TO_TARGET_SINGLE (*rv, l);
|
||||
/* See the first define_split in rs6000.md handling a
|
||||
const_double_operand. */
|
||||
val = l;
|
||||
mode = SImode;
|
||||
}
|
||||
|
||||
long l[2];
|
||||
if (DECIMAL_FLOAT_MODE_P (mode))
|
||||
REAL_VALUE_TO_TARGET_DECIMAL64 (*CONST_DOUBLE_REAL_VALUE (op), l);
|
||||
else
|
||||
REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), l);
|
||||
high = l[WORDS_BIG_ENDIAN == 0];
|
||||
low = l[WORDS_BIG_ENDIAN != 0];
|
||||
|
||||
if (TARGET_32BIT)
|
||||
return (num_insns_constant_wide (low)
|
||||
+ num_insns_constant_wide (high));
|
||||
else
|
||||
else if (mode == DFmode || mode == DDmode)
|
||||
{
|
||||
if ((high == 0 && low >= 0)
|
||||
|| (high == -1 && low < 0))
|
||||
return num_insns_constant_wide (low);
|
||||
|
||||
else if (rs6000_is_valid_and_mask (op, mode))
|
||||
return 2;
|
||||
|
||||
else if (low == 0)
|
||||
return num_insns_constant_wide (high) + 1;
|
||||
long l[2];
|
||||
|
||||
if (mode == DDmode)
|
||||
REAL_VALUE_TO_TARGET_DECIMAL64 (*rv, l);
|
||||
else
|
||||
return (num_insns_constant_wide (high)
|
||||
+ num_insns_constant_wide (low) + 1);
|
||||
REAL_VALUE_TO_TARGET_DOUBLE (*rv, l);
|
||||
|
||||
/* See the second (32-bit) and third (64-bit) define_split
|
||||
in rs6000.md handling a const_double_operand. */
|
||||
val = (unsigned HOST_WIDE_INT) l[WORDS_BIG_ENDIAN ? 0 : 1] << 32;
|
||||
val |= l[WORDS_BIG_ENDIAN ? 1 : 0] & 0xffffffffUL;
|
||||
mode = DImode;
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
return num_insns_constant_multi (val, mode);
|
||||
}
|
||||
|
||||
/* Interpret element ELT of the CONST_VECTOR OP as an integer value.
|
||||
|
|
Loading…
Add table
Reference in a new issue