Hi!
On Sun, Nov 25, 2018 at 10:49:12PM +1030, Alan Modra wrote:
> 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).
>
> Boostrapped etc. powerpc64le-linux and powerpc64-linux.
>
> * 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.
> +/* Helper for num_insn_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)
> + {
> + int ins = num_insns_constant_gpr (value);
You probably should mask "value" here so that it is only one GPR.
Alternatively, make num_insns_constant_gpr handle that. Consider what
happens for a 64-bit number with 32-bit registers here?
Also, s/ins/insns/ please.
> + if (ins > 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 (value), DImode))
> + ins = 2;
> + total += ins;
> + value >>= 32;
> + if (TARGET_POWERPC64)
> + value >>= 32;
That's just
value >>= BITS_PER_WORD;
> + long l[2];
> + val = l[WORDS_BIG_ENDIAN ? 0 : 1] << 32;
This doesn't work, as in the other patch: long can be 32 bit.
Looks good otherwise.
Segher