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