On 10/23/2017 11:00 AM, Richard Sandiford wrote: > This patch adds an rtl representation of poly_int values. > There were three possible ways of doing this: > > (1) Add a new rtl code for the poly_ints themselves and store the > coefficients as trailing wide_ints. This would give constants like: > > (const_poly_int [c0 c1 ... cn]) > > The runtime value would be: > > c0 + c1 * x1 + ... + cn * xn > > (2) Like (1), but use rtxes for the coefficients. This would give > constants like: > > (const_poly_int [(const_int c0) > (const_int c1) > ... > (const_int cn)]) > > although the coefficients could be const_wide_ints instead > of const_ints where appropriate. > > (3) Add a new rtl code for the polynomial indeterminates, > then use them in const wrappers. A constant like c0 + c1 * x1 > would then look like: > > (const:M (plus:M (mult:M (const_param:M x1) > (const_int c1)) > (const_int c0))) > > There didn't seem to be that much to choose between them. The main > advantage of (1) is that it's a more efficient representation and > that we can refer to the cofficients directly as wide_int_storage. Well, and #1 feels more like how we handle CONST_INT :-) > > > 2017-10-23 Richard Sandiford <richard.sandif...@linaro.org> > Alan Hayward <alan.hayw...@arm.com> > David Sherwood <david.sherw...@arm.com> > > gcc/ > * doc/rtl.texi (const_poly_int): Document. > * gengenrtl.c (excluded_rtx): Return true for CONST_POLY_INT. > * rtl.h (const_poly_int_def): New struct. > (rtx_def::u): Add a cpi field. > (CASE_CONST_UNIQUE, CASE_CONST_ANY): Add CONST_POLY_INT. > (CONST_POLY_INT_P, CONST_POLY_INT_COEFFS): New macros. > (wi::rtx_to_poly_wide_ref): New typedef > (const_poly_int_value, wi::to_poly_wide, rtx_to_poly_int64) > (poly_int_rtx_p): New functions. > (trunc_int_for_mode): Declare a poly_int64 version. > (plus_constant): Take a poly_int64 instead of a HOST_WIDE_INT. > (immed_wide_int_const): Take a poly_wide_int_ref rather than > a wide_int_ref. > (strip_offset): Declare. > (strip_offset_and_add): New function. > * rtl.def (CONST_POLY_INT): New rtx code. > * rtl.c (rtx_size): Handle CONST_POLY_INT. > (shared_const_p): Use poly_int_rtx_p. > * emit-rtl.h (gen_int_mode): Take a poly_int64 instead of a > HOST_WIDE_INT. > (gen_int_shift_amount): Likewise. > * emit-rtl.c (const_poly_int_hasher): New class. > (const_poly_int_htab): New variable. > (init_emit_once): Initialize it when NUM_POLY_INT_COEFFS > 1. > (const_poly_int_hasher::hash): New function. > (const_poly_int_hasher::equal): Likewise. > (gen_int_mode): Take a poly_int64 instead of a HOST_WIDE_INT. > (immed_wide_int_const): Rename to... > (immed_wide_int_const_1): ...this and make static. > (immed_wide_int_const): New function, taking a poly_wide_int_ref > instead of a wide_int_ref. > (gen_int_shift_amount): Take a poly_int64 instead of a HOST_WIDE_INT. > (gen_lowpart_common): Handle CONST_POLY_INT. > * cse.c (hash_rtx_cb, equiv_constant): Likewise. > * cselib.c (cselib_hash_rtx): Likewise. > * dwarf2out.c (const_ok_for_output_1): Likewise. > * expr.c (convert_modes): Likewise. > * print-rtl.c (rtx_writer::print_rtx, print_value): Likewise. > * rtlhash.c (add_rtx): Likewise. > * explow.c (trunc_int_for_mode): Add a poly_int64 version. > (plus_constant): Take a poly_int64 instead of a HOST_WIDE_INT. > Handle existing CONST_POLY_INT rtxes. > * expmed.h (expand_shift): Take a poly_int64 instead of a > HOST_WIDE_INT. > * expmed.c (expand_shift): Likewise. > * rtlanal.c (strip_offset): New function. > (commutative_operand_precedence): Give CONST_POLY_INT the same > precedence as CONST_DOUBLE and put CONST_WIDE_INT between that > and CONST_INT. > * rtl-tests.c (const_poly_int_tests): New struct. > (rtl_tests_c_tests): Use it. > * simplify-rtx.c (simplify_const_unary_operation): Handle > CONST_POLY_INT. > (simplify_const_binary_operation): Likewise. > (simplify_binary_operation_1): Fold additions of symbolic constants > and CONST_POLY_INTs. > (simplify_subreg): Handle extensions and truncations of > CONST_POLY_INTs. > (simplify_const_poly_int_tests): New struct. > (simplify_rtx_c_tests): Use it. > * wide-int.h (storage_ref): Add default constructor. > (wide_int_ref_storage): Likewise. > (trailing_wide_ints): Use GTY((user)). > (trailing_wide_ints::operator[]): Add a const version. > (trailing_wide_ints::get_precision): New function. > (trailing_wide_ints::extra_size): Likewise. Do we need to define anything WRT structure sharing in rtl.texi for a CONST_POLY_INT?
> > Index: gcc/rtl.c > =================================================================== > --- gcc/rtl.c 2017-10-23 16:52:20.579835373 +0100 > +++ gcc/rtl.c 2017-10-23 17:00:54.443002147 +0100 > @@ -257,9 +261,10 @@ shared_const_p (const_rtx orig) > > /* CONST can be shared if it contains a SYMBOL_REF. If it contains > a LABEL_REF, it isn't sharable. */ > + poly_int64 offset; > return (GET_CODE (XEXP (orig, 0)) == PLUS > && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF > - && CONST_INT_P (XEXP (XEXP (orig, 0), 1))); > + && poly_int_rtx_p (XEXP (XEXP (orig, 0), 1), &offset)); Did this just change structure sharing for CONST_WIDE_INT? > + /* Create a new rtx. There's a choice to be made here between installing > + the actual mode of the rtx or leaving it as VOIDmode (for consistency > + with CONST_INT). In practice the handling of the codes is different > + enough that we get no benefit from using VOIDmode, and various places > + assume that VOIDmode implies CONST_INT. Using the real mode seems like > + the right long-term direction anyway. */ Certainly my preference is to get the mode in there. I see modeless CONST_INTs as a long standing wart and I'm not keen to repeat it. > Index: gcc/wide-int.h > =================================================================== > --- gcc/wide-int.h 2017-10-23 17:00:20.923835582 +0100 > +++ gcc/wide-int.h 2017-10-23 17:00:54.445999420 +0100 > @@ -613,6 +613,7 @@ #define SHIFT_FUNCTION \ > access. */ > struct storage_ref > { > + storage_ref () {} > storage_ref (const HOST_WIDE_INT *, unsigned int, unsigned int); > > const HOST_WIDE_INT *val; > @@ -944,6 +945,8 @@ struct wide_int_ref_storage : public wi: > HOST_WIDE_INT scratch[2]; > > public: > + wide_int_ref_storage () {} > + > wide_int_ref_storage (const wi::storage_ref &); > > template <typename T> So doesn't this play into the whole question about initialization of these objects. So I'll defer on this hunk until we settle that question, but the rest is OK. Jeff