On Wed, Nov 29, 2017 at 12:57 PM, Richard Sandiford <richard.sandif...@linaro.org> wrote: > It was clear from the SVE reviews that people were unhappy with how > "special" the variable-length case was. One particular concern was > the use of VEC_DUPLICATE_CST and VEC_SERIES_CST, and the way that > that would in turn lead to different representations of VEC_PERM_EXPRs > with constant permute vectors, and difficulties in invoking > vec_perm_const_ok. > > This is an RFC for a VECTOR_CST representation that treats each > specific constant as one instance of an arbitrary-length sequence. > The reprensentation then extends to variable-length vectors in a > natural way. > > As discussed on IRC, if a vector contains X*N elements for some > constant N and integer X>0, the main features we need are: > > 1) the ability to represent a sequence that duplicates N values > > This is useful for SLP invariants. > > 2) the ability to represent a sequence that starts with N values and > is followed by zeros > > This is useful for the initial value in a double or SLP reduction > > 3) the ability to represent N interleaved series > > This is useful for SLP inductions and for VEC_PERM_EXPRs. > > For (2), zero isn't necessarily special, since vectors used in an AND > reduction might need to fill with ones. Also, we might need up to N > different fill values with mixed SLP operations; it isn't necessarily > safe to assume that a single fill value will always be enough. > > The same goes for (3): there's no reason in principle why the > steps in an SLP induction should all be the same (although they > do need to be at the moment). E.g. once we support SLP on: > > for (unsigned int i = 0; i < n; i += 2) > { > x[i] += 4 + i; > x[i + 1] += 11 + i * 3; > } > > we'll need {[4, 14], +, [2, 6]}. > > So the idea is to represent vectors as P interleaved patterns of the form: > > [BASE0, BASE1, BASE1 + STEP, BASE1 + STEP*2, ...] > > where the STEP is always zero (actually null) for non-integer vectors. > This is effectively projecting a "foreground" value of P elements > onto an arbitrary-length "background" sequenece, where the background > sequence contains P parallel linear series. > > E.g. to pick an extreme and unlikely example, > > [42, 99, 2, 20, 3, 30, 4, 40, ...] > > has 2 patterns: > > BASE0 = 42, BASE1 = 2, STEP = 1 > BASE0 = 99, BASE1 = 20, STEP = 10 > > The more useful cases are degenerate versions of this general case. > > As far as memory consumption goes: the number of patterns needed for a > fixed-length vector with 2*N elements is always at most N; in the worst > case, we simply interleave the first N elements with the second N elements. > The worst-case increase in footprint is therefore N trees for the steps. > In practice the footprint is usually smaller than it was before, since > most constants do have a pattern. > > The patch below implements this for trees. I have patches to use the > same style of encoding for CONST_VECTOR and vec_perm_indices, but the > tree one is probably easiest to read. > > The patch only adds the representation. Follow-on patches make more > use of it (and usually make things simpler; e.g. integer_zerop is no > longer a looping operation). > > Does this look better?
Yes, the overall design looks good. I wonder why you chose to have the number of patterns being a power of two? I suppose this is to have the same number of elements from all patterns in the final vector (which is power-of-two sized)? I wonder if there exists a vector where say a three-pattern interleaving would be smaller than a four-pattern one? Given you add flags for various purposes would it make sense to overload 'step' with a regular element to avoid the storage increase in case step is unnecessary? This makes it have three elements which is of course awkward :/ Few more comments below. Otherwise looks good to go! Thanks for doing this. > Thanks, > Richard > > > 2017-11-29 Richard Sandiford <richard.sandif...@arm.com> > > gcc/ > * doc/generic.texi (VECTOR_CST): Describe new representation of > vector constants. > * tree.def (VECTOR_CST): Update comment to refer to generic.texi. > * tree-core.h (tree_base): Add a vector_cst field to the u union. > (tree_vector_pattern): New struct. > (tree_vector): Replace elts array with a patterns array. > * tree.h (VECTOR_CST_NELTS): Redefine using TYPE_VECTOR_SUBPARTS. > (VECTOR_CST_ELTS): Delete. > (VECTOR_CST_ELT): Redefine using vector_cst_elt. > (VECTOR_CST_LOG2_NPATTERNS, VECTOR_CST_NPATTERNS): New macros. > (VECTOR_CST_DUPLICATE_P, VECTOR_CST_SERIES_P, VECTOR_CST_BASE) > (VECTOR_CST_STEP): Likewise. > (make_vector): Take the values of VECTOR_CST_LOG2_NPATTERNS, > VECTOR_CST_DUPLICATE_P and VECTOR_CST_SERIES_P as arguments. > (build_vector): Declare an overload that takes a vector of > tree_vector_patterns. > (vector_cst_int_elt, vector_cst_elt): Declare. > * tree.c (tree_code_size): Abort if passed VECTOR_CST. > (tree_size): Update for new VECTOR_CST layout. > (make_vector): Take the values of VECTOR_CST_LOG2_NPATTERNS, > VECTOR_CST_DUPLICATE_P and VECTOR_CST_SERIES_P as arguments. > (combine_patterns, compress_vector_patterns, vector_overflow_p) > (vector_duplicate_p, vector_series_p): New functions. > (build_vector): Add an overload that takes a vector of > tree_vector_patterns. Use it for the overload that takes > a vector of elements. > (vector_cst_int_elt, vector_cst_elt): New functions. > (drop_tree_overflow): For VECTOR_CST, drop the overflow flags > from the VECTOR_CST_BASEs. > (check_vector_cst, test_vector_cst_patterns): New functions. > (tree_c_tests): Call it. > * lto-streamer-out.c (DFS::DFS_write_tree_body): Handle the new > VECTOR_CST fields. > (hash_tree): Likewise. > * tree-streamer-out.c (write_ts_vector_tree_pointers): Likewise. > (streamer_write_tree_header): Likewise. > * tree-streamer-in.c (lto_input_ts_vector_tree_pointers): Likewise. > (streamer_alloc_tree): Likewise. Update call to make_vector. > * fold-const.c (fold_ternary_loc): Avoid using VECTOR_CST_ELTS. > > gcc/lto/ > * lto.c (compare_tree_sccs_1): Compare the new VECTOR_CST flags. > > Index: gcc/doc/generic.texi > =================================================================== > *** gcc/doc/generic.texi 2017-11-29 11:07:59.961993930 +0000 > --- gcc/doc/generic.texi 2017-11-29 11:08:00.183993912 +0000 > *************** These nodes are used to represent comple > *** 1084,1093 **** > imaginary parts respectively. > > @item VECTOR_CST > ! These nodes are used to represent vector constants, whose parts are > ! constant nodes. Each individual constant node is either an integer or a > ! double constant node. The first operand is a @code{TREE_LIST} of the > ! constant nodes and is accessed through @code{TREE_VECTOR_CST_ELTS}. > > @item STRING_CST > These nodes represent string-constants. The @code{TREE_STRING_LENGTH} > --- 1084,1147 ---- > imaginary parts respectively. > > @item VECTOR_CST > ! These nodes are used to represent vector constants. Each vector > ! constant @var{v} is treated as a specific instance of an arbitrary-length > ! sequence that itself contains @samp{VECTOR_CST_NPATTERNS (@var{v})} > ! interleaved patterns. Each pattern @var{i} has three parts: > ! > ! @itemize @samp > ! @item VECTOR_CST_BASE (@var{v}, @var{i}, 0) > ! The vector element value for the first instance of the pattern. > ! > ! @item VECTOR_CST_BASE (@var{v}, @var{i}, 1) > ! The vector element value for the second instance of the pattern. > ! > ! @item VECTOR_CST_STEP (@var{v}, @var{i}) > ! If the first and second instances of the pattern are @code{INTEGER_CST}s, > ! this is the difference between each subsequent instance of the pattern > ! and the previous instance. In other cases it is null, which indicates > ! that subsequent instances of the pattern have the same value as the > ! second instance. > ! > ! If @var{v} only needs two instances of a pattern, and if both instances > ! are @code{INTEGER_CST}s, the step is the difference between them. > ! > ! The addition of the step to get third and subsequent elements is always > ! a wrapping operation: there is no undefined behavior or overflow. > ! @end itemize > ! > ! For example, the constant: > ! @smallexample > ! @{ 1, 5, 2, 6, 3, 7, 4, 8 @} > ! @end smallexample > ! is encoded using the interleaved patterns: > ! @smallexample > ! @{ 1, 2, 3, @dots{} @} > ! @{ 5, 6, 7, @dots{} @} > ! @end smallexample > ! where: > ! @smallexample > ! wi::to_wide (VECTOR_CST_BASE (@var{v}, 0, 0)) == 1 > ! wi::to_wide (VECTOR_CST_BASE (@var{v}, 0, 1)) == 2 > ! wi::to_wide (VECTOR_CST_STEP (@var{v}, 0)) == 1 > ! wi::to_wide (VECTOR_CST_BASE (@var{v}, 1, 0)) == 5 > ! wi::to_wide (VECTOR_CST_BASE (@var{v}, 1, 1)) == 6 > ! wi::to_wide (VECTOR_CST_STEP (@var{v}, 1)) == 1 > ! @end smallexample > ! > ! @samp{VECTOR_CST_DUPLICATE_P (@var{v})} is true if @var{v} simply > ! contains repeated instances of @samp{VECTOR_CST_NPATTERNS (@var{v})} > ! values. In this case the two bases in each pattern are equal and > ! the steps for integer vectors are zero. > ! > ! @samp{VECTOR_CST_SERIES_P (@var{v})} is true if each pattern can > ! be seen as a linear series, with @samp{VECTOR_CST_BASE (@var{v}, @var{i}, > 0)} > ! giving the start value and @samp{VECTOR_CST_STEP (@var{v}, @var{i}))} > ! giving the step. > ! > ! The utility function @code{vector_cst_elt} gives the value of an > ! arbitrary index as a @code{tree}. @code{vector_cst_int_elt} gives > ! the same value as a @code{wide_int}. > > @item STRING_CST > These nodes represent string-constants. The @code{TREE_STRING_LENGTH} > Index: gcc/tree.def > =================================================================== > *** gcc/tree.def 2017-11-29 11:07:59.961993930 +0000 > --- gcc/tree.def 2017-11-29 11:08:00.187993912 +0000 > *************** DEFTREECODE (FIXED_CST, "fixed_cst", tcc > *** 301,307 **** > whose contents are other constant nodes. */ > DEFTREECODE (COMPLEX_CST, "complex_cst", tcc_constant, 0) > > ! /* Contents are in VECTOR_CST_ELTS field. */ > DEFTREECODE (VECTOR_CST, "vector_cst", tcc_constant, 0) > > /* Contents are TREE_STRING_LENGTH and the actual contents of the string. > */ > --- 301,307 ---- > whose contents are other constant nodes. */ > DEFTREECODE (COMPLEX_CST, "complex_cst", tcc_constant, 0) > > ! /* See generic.texi for details. */ > DEFTREECODE (VECTOR_CST, "vector_cst", tcc_constant, 0) > > /* Contents are TREE_STRING_LENGTH and the actual contents of the string. > */ > Index: gcc/tree-core.h > =================================================================== > *** gcc/tree-core.h 2017-11-29 11:07:59.961993930 +0000 > --- gcc/tree-core.h 2017-11-29 11:08:00.185993912 +0000 > *************** struct GTY(()) tree_base { > *** 976,983 **** > /* VEC length. This field is only used with TREE_VEC. */ > int length; > > ! /* Number of elements. This field is only used with VECTOR_CST. */ > ! unsigned int nelts; > > /* SSA version number. This field is only used with SSA_NAME. */ > unsigned int version; > --- 976,995 ---- > /* VEC length. This field is only used with TREE_VEC. */ > int length; > > ! /* This field is only used with VECTOR_CST. */ > ! struct { > ! /* The value of VECTOR_CST_LOG2_NPATTERNS. */ > ! unsigned int log2_npatterns : 16; > ! > ! /* The value of VECTOR_CST_DUPLICATE_P. */ > ! unsigned int duplicate_p : 1; > ! > ! /* The value of VECTOR_CST_SERIES_P. */ > ! unsigned int series_p : 1; > ! > ! /* For future expansion. */ > ! unsigned int unused : 14; > ! } vector_cst; > > /* SSA version number. This field is only used with SSA_NAME. */ > unsigned int version; > *************** struct GTY(()) tree_complex { > *** 1331,1339 **** > tree imag; > }; > > struct GTY(()) tree_vector { > struct tree_typed typed; > ! tree GTY ((length ("VECTOR_CST_NELTS ((tree) &%h)"))) elts[1]; > }; > > struct GTY(()) tree_identifier { > --- 1343,1363 ---- > tree imag; > }; > > + /* One pattern in a VECTOR_CST. Instance I of the pattern has the value: > + > + I == 0 ? BASE[0] : BASE[1] + (I - 1) * STEP > + > + The STEP is nonnull iff BASE[0] and BASE[1] are INTEGER_CSTs; > + in other cases the step is implicitly 0. */ > + struct GTY(()) tree_vector_pattern { > + tree base[2]; > + tree step; > + }; > + > struct GTY(()) tree_vector { > struct tree_typed typed; > ! tree_vector_pattern > ! GTY ((length ("VECTOR_CST_NPATTERNS ((tree) &%h)"))) patterns[1]; > }; > > struct GTY(()) tree_identifier { > Index: gcc/tree.h > =================================================================== > *** gcc/tree.h 2017-11-29 11:07:59.961993930 +0000 > --- gcc/tree.h 2017-11-29 11:08:00.188993912 +0000 > *************** #define TREE_STRING_POINTER(NODE) \ > *** 1012,1021 **** > #define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real) > #define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag) > > ! /* In a VECTOR_CST node. */ > ! #define VECTOR_CST_NELTS(NODE) (VECTOR_CST_CHECK (NODE)->base.u.nelts) > ! #define VECTOR_CST_ELTS(NODE) (VECTOR_CST_CHECK (NODE)->vector.elts) > ! #define VECTOR_CST_ELT(NODE,IDX) (VECTOR_CST_CHECK (NODE)->vector.elts[IDX]) > > /* Define fields and accessors for some special-purpose tree nodes. */ > > --- 1012,1033 ---- > #define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real) > #define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag) > > ! /* In a VECTOR_CST node. See generic.texi for details. */ > ! #define VECTOR_CST_NELTS(NODE) (TYPE_VECTOR_SUBPARTS (TREE_TYPE (NODE))) > ! #define VECTOR_CST_ELT(NODE,IDX) vector_cst_elt (NODE, IDX) > ! > ! #define VECTOR_CST_LOG2_NPATTERNS(NODE) \ > ! (VECTOR_CST_CHECK (NODE)->base.u.vector_cst.log2_npatterns) > ! #define VECTOR_CST_NPATTERNS(NODE) \ > ! (1U << VECTOR_CST_LOG2_NPATTERNS (NODE)) > ! #define VECTOR_CST_DUPLICATE_P(NODE) \ > ! (VECTOR_CST_CHECK (NODE)->base.u.vector_cst.duplicate_p) > ! #define VECTOR_CST_SERIES_P(NODE) \ > ! (VECTOR_CST_CHECK (NODE)->base.u.vector_cst.series_p) > ! #define VECTOR_CST_BASE(NODE, ELT, SUBELT) \ > ! (VECTOR_CST_CHECK (NODE)->vector.patterns[ELT].base[SUBELT]) > ! #define VECTOR_CST_STEP(NODE, ELT) \ > ! (VECTOR_CST_CHECK (NODE)->vector.patterns[ELT].step) > > /* Define fields and accessors for some special-purpose tree nodes. */ > > *************** extern tree force_fit_type (tree, const > *** 4024,4030 **** > extern tree build_int_cst (tree, HOST_WIDE_INT); > extern tree build_int_cstu (tree type, unsigned HOST_WIDE_INT cst); > extern tree build_int_cst_type (tree, HOST_WIDE_INT); > ! extern tree make_vector (unsigned CXX_MEM_STAT_INFO); > extern tree build_vector (tree, vec<tree> CXX_MEM_STAT_INFO); > extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *); > extern tree build_vector_from_val (tree, tree); > --- 4036,4043 ---- > extern tree build_int_cst (tree, HOST_WIDE_INT); > extern tree build_int_cstu (tree type, unsigned HOST_WIDE_INT cst); > extern tree build_int_cst_type (tree, HOST_WIDE_INT); > ! extern tree make_vector (unsigned, bool, bool CXX_MEM_STAT_INFO); > ! extern tree build_vector (tree, vec<tree_vector_pattern> CXX_MEM_STAT_INFO); > extern tree build_vector (tree, vec<tree> CXX_MEM_STAT_INFO); > extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *); > extern tree build_vector_from_val (tree, tree); > *************** extern tree first_field (const_tree); > *** 4271,4276 **** > --- 4284,4292 ---- > > extern bool initializer_zerop (const_tree); > > + extern wide_int vector_cst_int_elt (const_tree, unsigned int); > + extern tree vector_cst_elt (const_tree, unsigned int); > + > /* Given a vector VEC, return its first element if all elements are > the same. Otherwise return NULL_TREE. */ > > Index: gcc/tree.c > =================================================================== > *** gcc/tree.c 2017-11-29 11:07:59.961993930 +0000 > --- gcc/tree.c 2017-11-29 11:08:00.187993912 +0000 > *************** tree_code_size (enum tree_code code) > *** 839,845 **** > case REAL_CST: return sizeof (tree_real_cst); > case FIXED_CST: return sizeof (tree_fixed_cst); > case COMPLEX_CST: return sizeof (tree_complex); > ! case VECTOR_CST: return sizeof (tree_vector); > case STRING_CST: gcc_unreachable (); > default: > gcc_checking_assert (code >= NUM_TREE_CODES); > --- 839,845 ---- > case REAL_CST: return sizeof (tree_real_cst); > case FIXED_CST: return sizeof (tree_fixed_cst); > case COMPLEX_CST: return sizeof (tree_complex); > ! case VECTOR_CST: gcc_unreachable (); > case STRING_CST: gcc_unreachable (); > default: > gcc_checking_assert (code >= NUM_TREE_CODES); > *************** tree_size (const_tree node) > *** 899,905 **** > > case VECTOR_CST: > return (sizeof (struct tree_vector) > ! + (VECTOR_CST_NELTS (node) - 1) * sizeof (tree)); > > case STRING_CST: > return TREE_STRING_LENGTH (node) + offsetof (struct tree_string, str) > + 1; > --- 899,906 ---- > > case VECTOR_CST: > return (sizeof (struct tree_vector) > ! + ((VECTOR_CST_NPATTERNS (node) - 1) > ! * sizeof (tree_vector_pattern))); > > case STRING_CST: > return TREE_STRING_LENGTH (node) + offsetof (struct tree_string, str) > + 1; > *************** cst_and_fits_in_hwi (const_tree x) > *** 1708,1720 **** > && (tree_fits_shwi_p (x) || tree_fits_uhwi_p (x))); > } > > ! /* Build a newly constructed VECTOR_CST node of length LEN. */ > > tree > ! make_vector (unsigned len MEM_STAT_DECL) > { > tree t; > ! unsigned length = (len - 1) * sizeof (tree) + sizeof (struct tree_vector); > > record_node_allocation_statistics (VECTOR_CST, length); > > --- 1709,1726 ---- > && (tree_fits_shwi_p (x) || tree_fits_uhwi_p (x))); > } > > ! /* Build a newly constructed VECTOR_CST with the given values of > ! (VECTOR_CST_)LOG2_NPATTERNS, (VECTOR_CST_)DUPLICATE_P amd > ! (VECTOR_CST_)SERIES_P. */ > > tree > ! make_vector (unsigned log2_npatterns, bool duplicate_p, > ! bool series_p MEM_STAT_DECL) > { > tree t; > ! unsigned npatterns = 1 << log2_npatterns; > ! unsigned length = (sizeof (struct tree_vector) > ! + (npatterns - 1) * sizeof (tree_vector_pattern)); > > record_node_allocation_statistics (VECTOR_CST, length); > > *************** make_vector (unsigned len MEM_STAT_DECL) > *** 1722,1764 **** > > TREE_SET_CODE (t, VECTOR_CST); > TREE_CONSTANT (t) = 1; > ! VECTOR_CST_NELTS (t) = len; > > return t; > } > > ! /* Return a new VECTOR_CST node whose type is TYPE and whose values > ! are given by VALS. */ > > ! tree > ! build_vector (tree type, vec<tree> vals MEM_STAT_DECL) > { > ! unsigned int nelts = vals.length (); > ! gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (type)); > ! int over = 0; > ! unsigned cnt = 0; > ! tree v = make_vector (nelts); > ! TREE_TYPE (v) = type; > > ! /* Iterate through elements and check for overflow. */ > ! for (cnt = 0; cnt < nelts; ++cnt) > { > ! tree value = vals[cnt]; > > ! VECTOR_CST_ELT (v, cnt) = value; > > ! /* Don't crash if we get an address constant. */ > ! if (!CONSTANT_CLASS_P (value)) > ! continue; > > ! over |= TREE_OVERFLOW (value); > } > > ! TREE_OVERFLOW (v) = over; > return v; > } > > /* Return a new VECTOR_CST node whose type is TYPE and whose values > are extracted from V, a vector of CONSTRUCTOR_ELT. */ > > tree > --- 1728,1949 ---- > > TREE_SET_CODE (t, VECTOR_CST); > TREE_CONSTANT (t) = 1; > ! VECTOR_CST_LOG2_NPATTERNS (t) = log2_npatterns; > ! VECTOR_CST_DUPLICATE_P (t) = duplicate_p; > ! VECTOR_CST_SERIES_P (t) = series_p; > > return t; > } > > ! /* Try to represent the interleaving of SRC1 and SRC2 as a single > ! pattern. Return true on success, adding the pattern to DEST. > ! FIRST_P is true if all elements are represented by the bases, > ! with no values determined by the steps. */ > > ! static bool > ! combine_patterns (vec<tree_vector_pattern> *dest, > ! const tree_vector_pattern *src1, > ! const tree_vector_pattern *src2, > ! bool first_p) > { > ! /* Any new pattern would represent: > ! > ! { src1->base[0], vals[0], vals[1], vals[2], ... } > ! > ! where ... exists only if !FIRST_P. */ > ! tree vals[3] = { src2->base[0], src1->base[1], src2->base[1] }; > ! > ! /* See whether any values overflowed. */ > ! tree overflowed = NULL_TREE; > ! for (unsigned int i = 0; i < 3; ++i) > ! if (CONSTANT_CLASS_P (vals[i]) && TREE_OVERFLOW (vals[i])) > ! { > ! overflowed = vals[i]; > ! break; > ! } > ! > ! bool zero_step1_p = (!src1->step || wi::to_wide (src1->step) == 0); > ! bool zero_step2_p = (!src2->step || wi::to_wide (src1->step) == 0); > > ! /* Option 1: use VALS[0] as the second base without a step. */ > ! if ((first_p || (zero_step1_p && zero_step2_p)) > ! && operand_equal_p (vals[0], vals[1], 0) > ! && operand_equal_p (vals[1], vals[2], 0)) > ! { > ! tree_vector_pattern pattern (*src1); > ! /* Set TREE_OVERFLOW on the result if it was set for any of > ! the values being merged. */ > ! if (overflowed) > ! pattern.base[1] = overflowed; > ! if (!zero_step1_p) > ! pattern.step = build_zero_cst (TREE_TYPE (pattern.step)); > ! dest->quick_push (pattern); > ! return true; > ! } > ! > ! /* Option 2: use VALS[0] as the second base and handle the rest > ! via a step. In this case we must have nonnull steps (which > ! indicates that using a step is valid). */ > ! if (!src1->step || !src2->step) > ! return false; > ! > ! /* Check that VALS has a consistent step. */ > ! wide_int step = wi::to_wide (vals[1]) - wi::to_wide (vals[0]); > ! if (step != wi::to_wide (vals[2]) - wi::to_wide (vals[1])) > ! return false; > ! > ! /* Check that that step is in turn consistent with any existing one. */ > ! if (!first_p) > { > ! wide_int double_step = wi::lshift (step, 1); > ! if (double_step != wi::to_wide (src1->step) > ! || double_step != wi::to_wide (src2->step)) > ! return false; > ! } > > ! /* The combination is valid. */ > ! tree_vector_pattern pattern (*src1); > ! /* Set TREE_OVERFLOW on the result if it was set for any of > ! the values being merged. */ > ! if (!overflowed || overflowed == vals[0]) > ! pattern.base[1] = vals[0]; > ! else > ! pattern.base[1] = force_fit_type (TREE_TYPE (vals[0]), > ! wi::to_wide (vals[0]), 0, true); > ! pattern.step = wide_int_to_tree (TREE_TYPE (vals[0]), step); > ! dest->quick_push (pattern); > ! return true; > ! } > > ! /* PATTERNS represents a constant of type TYPE. Compress it into the > ! canonical form, returning the new vector of patterns. Use CUR and NEXT > ! as temporary workspace. */ > ! > ! static vec<tree_vector_pattern> > ! compress_vector_patterns (vec<tree_vector_pattern> *cur, > ! vec<tree_vector_pattern> *next, > ! tree type, vec<tree_vector_pattern> patterns) > ! { > ! while (patterns.length () > 1) > ! { > ! unsigned int npatterns = patterns.length (); > ! gcc_assert ((npatterns & 1) == 0); > ! unsigned int step = npatterns / 2; > ! cur->truncate (0); > ! cur->reserve (step); > ! bool first_p = npatterns * 2 == TYPE_VECTOR_SUBPARTS (type); > ! for (unsigned int i = 0; i < step; ++i) > ! if (!combine_patterns (cur, &patterns[i], &patterns[i + step], > ! first_p)) > ! return patterns; > ! patterns = *cur; > ! std::swap (cur, next); > ! } > ! return patterns; > ! } Wow, that looks complicated ;) Which means it needs some more comments. I wonder if avoiding all this for the special cases we like to handle by providing vector_cst constructors for one and two pattern cases would be best. Or even more specialized, not exposing "patterns". > ! /* Return true if PATTERNS has an overflow bit set. */ > ! > ! static bool > ! vector_overflow_p (vec<tree_vector_pattern> patterns) > ! { > ! unsigned int i; > ! tree_vector_pattern *pattern; > ! FOR_EACH_VEC_ELT (patterns, i, pattern) > ! for (unsigned int j = 0; j < 2; ++j) > ! if (CONSTANT_CLASS_P (pattern->base[j]) > ! && TREE_OVERFLOW (pattern->base[j])) > ! return true; > ! return false; > ! } > ! > ! /* Return true if PATTERNS represents a duplicate operation. */ > > ! static bool > ! vector_duplicate_p (vec<tree_vector_pattern> patterns) > ! { > ! unsigned int i; > ! tree_vector_pattern *pattern; > ! FOR_EACH_VEC_ELT (patterns, i, pattern) > ! { > ! if (pattern->step && wi::to_wide (pattern->step) != 0) I wonder if step == 0 should be canonicalized to NULL_TREE? > ! return false; > ! if (!operand_equal_p (pattern->base[0], pattern->base[1], 0)) > ! return false; > } > + return true; > + } > + > + /* Return true if PATTERNS represents a vector series. */ > + > + static bool > + vector_series_p (vec<tree_vector_pattern> patterns) > + { > + unsigned int i; > + tree_vector_pattern *pattern; > + FOR_EACH_VEC_ELT (patterns, i, pattern) > + if (!pattern->step > + || (wi::to_wide (pattern->base[1]) - wi::to_wide (pattern->base[0]) > + != wi::to_wide (pattern->step))) > + return false; > + return true; > + } > + > + /* Build a VECTOR_CST of type TYPE using the patterns in PATTERNS, > + canonicalizing it first if necessary. */ > + > + tree > + build_vector (tree type, vec<tree_vector_pattern> patterns MEM_STAT_DECL) > + { > + auto_vec<tree_vector_pattern, 16> tmp1, tmp2; > + patterns = compress_vector_patterns (&tmp1, &tmp2, type, patterns); > + unsigned int npatterns = patterns.length (); > + > + gcc_assert (pow2p_hwi (npatterns)); > + bool overflow_p = vector_overflow_p (patterns); > + bool duplicate_p = vector_duplicate_p (patterns); > + bool series_p = vector_series_p (patterns); > + tree v = make_vector (exact_log2 (npatterns), duplicate_p, series_p); > + TREE_TYPE (v) = type; > + TREE_OVERFLOW (v) = overflow_p; > > ! memcpy (v->vector.patterns, patterns.address (), > ! npatterns * sizeof (tree_vector_pattern)); > return v; > } > > /* Return a new VECTOR_CST node whose type is TYPE and whose values > + are given by ELTS. */ > + > + tree > + build_vector (tree type, vec<tree> elts MEM_STAT_DECL) > + { > + unsigned int nelts = elts.length (); > + gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (type)); > + > + gcc_assert (pow2p_hwi (nelts)); > + bool single_p = nelts == 1; > + unsigned int npatterns = single_p ? 1 : nelts / 2; > + auto_vec<tree_vector_pattern, 16> patterns (npatterns); > + for (unsigned int i = 0; i < npatterns; ++i) > + { > + tree_vector_pattern pattern; > + pattern.base[0] = elts[i]; > + pattern.base[1] = elts[single_p ? i : i + npatterns]; > + if (INTEGRAL_TYPE_P (TREE_TYPE (type)) > + && TREE_CODE (pattern.base[0]) == INTEGER_CST > + && TREE_CODE (pattern.base[1]) == INTEGER_CST) > + pattern.step = wide_int_to_tree (TREE_TYPE (type), > + wi::to_wide (pattern.base[1]) > + - wi::to_wide (pattern.base[0])); > + else > + pattern.step = NULL_TREE; I wonder why given the simple representation with n/2 patterns you don't use step == NULL_TREE unconditionally here. Is there a target macro specifying the maximum target supported vector length? It might be nice to use that in the auto_vec <> size. OTOH sometimes I really like tree_vector_pattern *p = XALLOCAVEC (npatterns); more... (ok, __attribute__((vector_size(1048576))) might blow the stack...) > + patterns.quick_push (pattern); > + } > + return build_vector (type, patterns); > + } > + > + /* Return a new VECTOR_CST node whose type is TYPE and whose values > are extracted from V, a vector of CONSTRUCTOR_ELT. */ > > tree > *************** build_opaque_vector_type (tree innertype > *** 10353,10358 **** > --- 10538,10581 ---- > return cand; > } > > + /* Return the value of element I of VECTOR_CST T as a wide_int. */ > + > + wide_int > + vector_cst_int_elt (const_tree t, unsigned int i) > + { > + unsigned int npatterns = VECTOR_CST_NPATTERNS (t); > + if (i < npatterns) > + return wi::to_wide (VECTOR_CST_BASE (t, i, 0)); > + > + unsigned int pattern = i & (npatterns - 1); > + tree base = VECTOR_CST_BASE (t, pattern, 1); > + tree step = VECTOR_CST_STEP (t, pattern); > + if (i < npatterns * 2 || !step || wi::to_wide (step) == 0) > + return wi::to_wide (base); > + > + unsigned int factor = (i >> VECTOR_CST_LOG2_NPATTERNS (t)) - 1; > + return wi::to_wide (base) + factor * wi::to_wide (step); > + } > + > + /* Return the value of element I of VECTOR_CST T. */ > + > + tree > + vector_cst_elt (const_tree t, unsigned int i) > + { > + unsigned int npatterns = VECTOR_CST_NPATTERNS (t); > + if (i < npatterns) > + return VECTOR_CST_BASE (t, i, 0); > + > + unsigned int pattern = i & (npatterns - 1); > + tree base = VECTOR_CST_BASE (t, pattern, 1); > + tree step = VECTOR_CST_STEP (t, pattern); > + if (i < npatterns * 2 || !step || wi::to_wide (step) == 0) > + return base; > + > + unsigned int factor = (i >> VECTOR_CST_LOG2_NPATTERNS (t)) - 1; > + return wide_int_to_tree (TREE_TYPE (TREE_TYPE (t)), > + wi::to_wide (base) + factor * wi::to_wide (step)); > + } > > /* Given an initializer INIT, return TRUE if INIT is zero or some > aggregate of zeros. Otherwise return FALSE. */ > *************** drop_tree_overflow (tree t) > *** 12447,12461 **** > if (TREE_OVERFLOW (TREE_IMAGPART (t))) > TREE_IMAGPART (t) = drop_tree_overflow (TREE_IMAGPART (t)); > } > if (TREE_CODE (t) == VECTOR_CST) > ! { > ! for (unsigned i = 0; i < VECTOR_CST_NELTS (t); ++i) > ! { > ! tree& elt = VECTOR_CST_ELT (t, i); > ! if (TREE_OVERFLOW (elt)) > ! elt = drop_tree_overflow (elt); > } > ! } > return t; > } > > --- 12670,12686 ---- > if (TREE_OVERFLOW (TREE_IMAGPART (t))) > TREE_IMAGPART (t) = drop_tree_overflow (TREE_IMAGPART (t)); > } > + > if (TREE_CODE (t) == VECTOR_CST) > ! /* Only the base values can have an overflow bit set. */ > ! for (unsigned i = 0; i < VECTOR_CST_NPATTERNS (t); ++i) > ! for (unsigned int j = 0; j < 2; ++j) > ! { > ! tree *elt = &VECTOR_CST_BASE (t, i, j); > ! if (TREE_OVERFLOW (*elt)) > ! *elt = drop_tree_overflow (*elt); > } > ! > return t; > } > > *************** test_labels () > *** 13954,13959 **** > --- 14179,14350 ---- > ASSERT_FALSE (FORCED_LABEL (label_decl)); > } > > + /* Check that VECTOR_CST Y contains the elements in X. */ > + > + static void > + check_vector_cst (vec<tree> x, tree y) > + { > + for (unsigned int i = 0; i < x.length (); ++i) > + ASSERT_EQ (wi::to_wide (x[i]), wi::to_wide (vector_cst_elt (y, i))); > + } > + > + /* Test the creation of VECTOR_CSTs. */ > + > + static void > + test_vector_cst_patterns () > + { > + auto_vec<tree, 8> elements (8); > + elements.quick_grow (8); > + tree element_type = build_nonstandard_integer_type (16, true); > + tree vector_type = build_vector_type (element_type, 8); > + > + /* Test a simple linear series with a base of 0 and a step of 1: > + { 0, 1, 2, 3, 4, 5, 6, 7 }. */ > + for (unsigned int i = 0; i < 8; ++i) > + elements[i] = build_int_cst (element_type, i); > + tree series_0_1 = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (series_0_1), 1); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_BASE (series_0_1, 0, 0))); > + ASSERT_TRUE (integer_onep (VECTOR_CST_BASE (series_0_1, 0, 1))); > + ASSERT_TRUE (integer_onep (VECTOR_CST_STEP (series_0_1, 0))); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (series_0_1)); > + ASSERT_TRUE (VECTOR_CST_SERIES_P (series_0_1)); > + check_vector_cst (elements, series_0_1); > + > + /* Try the same with the first element replaced by 100: > + { 100, 1, 2, 3, 4, 5, 6, 7 }. */ > + elements[0] = build_int_cst (element_type, 100); > + tree jump_series = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (jump_series), 1); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (jump_series, 0, 0)), 100); > + ASSERT_TRUE (integer_onep (VECTOR_CST_BASE (jump_series, 0, 1))); > + ASSERT_TRUE (integer_onep (VECTOR_CST_STEP (jump_series, 0))); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (jump_series)); > + ASSERT_FALSE (VECTOR_CST_SERIES_P (jump_series)); > + check_vector_cst (elements, jump_series); > + > + /* Try a series that wraps around. > + { 100, 65531, 65532, 65533, 65534, 65535, 0, 1 }. */ > + for (unsigned int i = 1; i < 8; ++i) > + elements[i] = build_int_cst (element_type, (65530 + i) & 0xffff); > + tree wrap_series = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (wrap_series), 1); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (wrap_series, 0, 0)), 100); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (wrap_series, 0, 1)), 65531); > + ASSERT_TRUE (integer_onep (VECTOR_CST_STEP (wrap_series, 0))); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (wrap_series)); > + ASSERT_FALSE (VECTOR_CST_SERIES_P (wrap_series)); > + check_vector_cst (elements, wrap_series); > + > + /* Try a downward series: > + { 100, 79, 78, 77, 76, 75, 75, 73 }. */ > + for (unsigned int i = 1; i < 8; ++i) > + elements[i] = build_int_cst (element_type, 80 - i); > + tree down_series = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (down_series), 1); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (down_series, 0, 0)), 100); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (down_series, 0, 1)), 79); > + ASSERT_TRUE (integer_minus_onep (VECTOR_CST_STEP (down_series, 0))); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (down_series)); > + ASSERT_FALSE (VECTOR_CST_SERIES_P (down_series)); > + check_vector_cst (elements, down_series); > + > + /* Try two interleaved series with different bases and steps: > + { 100, 53, 66, 206, 62, 212, 58, 218 }. */ > + elements[1] = build_int_cst (element_type, 53); > + for (unsigned int i = 2; i < 8; i += 2) > + { > + elements[i] = build_int_cst (element_type, 70 - i * 2); > + elements[i + 1] = build_int_cst (element_type, 200 + i * 3); > + } > + tree mixed_series = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (mixed_series), 2); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed_series, 0, 0)), 100); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed_series, 0, 1)), 66); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (mixed_series, 0)), -4); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed_series, 1, 0)), 53); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed_series, 1, 1)), 206); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (mixed_series, 1)), 6); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (mixed_series)); > + ASSERT_FALSE (VECTOR_CST_SERIES_P (mixed_series)); > + check_vector_cst (elements, mixed_series); > + > + /* Try a duplicated value: > + { 100, 100, 100, 100, 100, 100, 100, 100 }. */ > + for (unsigned int i = 1; i < 8; ++i) > + elements[i] = elements[0]; > + tree dup1 = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (dup1), 1); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (dup1, 0, 0)), 100); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (dup1, 0, 1)), 100); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_STEP (dup1, 0))); > + ASSERT_TRUE (VECTOR_CST_DUPLICATE_P (dup1)); > + ASSERT_TRUE (VECTOR_CST_SERIES_P (dup1)); > + check_vector_cst (elements, dup1); > + > + /* Try an interleaved duplicated value: > + { 100, 55, 100, 55, 100, 55, 100, 55 }. */ > + elements[1] = build_int_cst (element_type, 55); > + for (unsigned int i = 2; i < 8; ++i) > + elements[i] = elements[i - 2]; > + tree dup2 = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (dup2), 2); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (dup2, 0, 0)), 100); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (dup2, 0, 1)), 100); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_STEP (dup2, 0))); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (dup2, 1, 0)), 55); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (dup2, 1, 1)), 55); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_STEP (dup2, 1))); > + ASSERT_TRUE (VECTOR_CST_DUPLICATE_P (dup2)); > + ASSERT_TRUE (VECTOR_CST_SERIES_P (dup2)); > + check_vector_cst (elements, dup2); > + > + /* Try a duplicated value with 2 exceptions > + { 41, 97, 100, 55, 100, 55, 100, 55 }. */ > + elements[0] = build_int_cst (element_type, 41); > + elements[1] = build_int_cst (element_type, 97); > + tree jump_dup2 = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (jump_dup2), 2); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (jump_dup2, 0, 0)), 41); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (jump_dup2, 0, 1)), 100); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_STEP (jump_dup2, 0))); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (jump_dup2, 1, 0)), 97); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (jump_dup2, 1, 1)), 55); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_STEP (jump_dup2, 1))); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (jump_dup2)); > + ASSERT_FALSE (VECTOR_CST_SERIES_P (jump_dup2)); > + check_vector_cst (elements, jump_dup2); > + > + /* Try with and without a step > + { 41, 97, 100, 21, 100, 35, 100, 49 }. */ > + for (unsigned int i = 3; i < 8; i += 2) > + elements[i] = build_int_cst (element_type, i * 7); > + tree mixed2 = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (mixed2), 2); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed2, 0, 0)), 41); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed2, 0, 1)), 100); > + ASSERT_TRUE (integer_zerop (VECTOR_CST_STEP (mixed2, 0))); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed2, 1, 0)), 97); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_BASE (mixed2, 1, 1)), 21); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (mixed2, 1)), 14); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (mixed2)); > + ASSERT_FALSE (VECTOR_CST_SERIES_P (mixed2)); > + check_vector_cst (elements, mixed2); > + > + /* Try a fully-general constant: > + { 41, 97, 100, 21, 100, 9990, 100, 49 }. */ > + elements[5] = build_int_cst (element_type, 9990); > + tree general = build_vector (vector_type, elements); > + ASSERT_EQ (VECTOR_CST_NPATTERNS (general), 4); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (general, 0)), 59); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (general, 1)), 9893); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (general, 2)), 0); > + ASSERT_EQ (wi::to_wide (VECTOR_CST_STEP (general, 3)), 28); > + ASSERT_FALSE (VECTOR_CST_DUPLICATE_P (general)); > + ASSERT_TRUE (VECTOR_CST_SERIES_P (general)); > + check_vector_cst (elements, general); > + } > + > /* Run all of the selftests within this file. */ > > void > *************** tree_c_tests () > *** 13962,13967 **** > --- 14353,14359 ---- > test_integer_constants (); > test_identifiers (); > test_labels (); > + test_vector_cst_patterns (); > } > > } // namespace selftest > Index: gcc/lto-streamer-out.c > =================================================================== > *** gcc/lto-streamer-out.c 2017-11-29 11:07:59.961993930 +0000 > --- gcc/lto-streamer-out.c 2017-11-29 11:08:00.185993912 +0000 > *************** #define DFS_follow_tree_edge(DEST) \ > *** 747,754 **** > > if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > { > ! for (unsigned i = 0; i < VECTOR_CST_NELTS (expr); ++i) > ! DFS_follow_tree_edge (VECTOR_CST_ELT (expr, i)); > } > > if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) > --- 747,758 ---- > > if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > { > ! for (unsigned i = 0; i < VECTOR_CST_NPATTERNS (expr); ++i) > ! { > ! for (unsigned int j = 0; j < 2; ++j) > ! DFS_follow_tree_edge (VECTOR_CST_BASE (expr, i, j)); > ! DFS_follow_tree_edge (VECTOR_CST_STEP (expr, i)); > ! } > } > > if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) > *************** #define visit(SIBLING) \ > *** 1195,1202 **** > } > > if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > ! for (unsigned i = 0; i < VECTOR_CST_NELTS (t); ++i) > ! visit (VECTOR_CST_ELT (t, i)); > > if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) > { > --- 1199,1210 ---- > } > > if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > ! for (unsigned i = 0; i < VECTOR_CST_NPATTERNS (t); ++i) > ! { > ! for (unsigned int j = 0; j < 2; ++j) > ! visit (VECTOR_CST_BASE (t, i, j)); > ! visit (VECTOR_CST_STEP (t, i)); > ! } > > if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) > { > Index: gcc/tree-streamer-out.c > =================================================================== > *** gcc/tree-streamer-out.c 2017-11-29 11:07:59.961993930 +0000 > --- gcc/tree-streamer-out.c 2017-11-29 11:08:00.186993912 +0000 > *************** write_ts_common_tree_pointers (struct ou > *** 533,543 **** > static void > write_ts_vector_tree_pointers (struct output_block *ob, tree expr, bool > ref_p) > { > - unsigned i; > /* Note that the number of elements for EXPR has already been emitted > in EXPR's header (see streamer_write_tree_header). */ > ! for (i = 0; i < VECTOR_CST_NELTS (expr); ++i) > ! stream_write_tree (ob, VECTOR_CST_ELT (expr, i), ref_p); > } > > > --- 533,546 ---- > static void > write_ts_vector_tree_pointers (struct output_block *ob, tree expr, bool > ref_p) > { > /* Note that the number of elements for EXPR has already been emitted > in EXPR's header (see streamer_write_tree_header). */ > ! for (unsigned int i = 0; i < VECTOR_CST_NPATTERNS (expr); ++i) > ! { > ! for (unsigned int j = 0; j < 2; ++j) > ! stream_write_tree (ob, VECTOR_CST_BASE (expr, i, j), ref_p); > ! stream_write_tree (ob, VECTOR_CST_STEP (expr, i), ref_p); > ! } > } > > > *************** streamer_write_tree_header (struct outpu > *** 960,966 **** > else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER)) > write_identifier (ob, ob->main_stream, expr); > else if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > ! streamer_write_hwi (ob, VECTOR_CST_NELTS (expr)); > else if (CODE_CONTAINS_STRUCT (code, TS_VEC)) > streamer_write_hwi (ob, TREE_VEC_LENGTH (expr)); > else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) > --- 963,975 ---- > else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER)) > write_identifier (ob, ob->main_stream, expr); > else if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > ! { > ! bitpack_d bp = bitpack_create (ob->main_stream); > ! bp_pack_value (&bp, VECTOR_CST_LOG2_NPATTERNS (expr), 16); > ! bp_pack_value (&bp, VECTOR_CST_DUPLICATE_P (expr), 1); > ! bp_pack_value (&bp, VECTOR_CST_SERIES_P (expr), 1); > ! streamer_write_bitpack (&bp); > ! } > else if (CODE_CONTAINS_STRUCT (code, TS_VEC)) > streamer_write_hwi (ob, TREE_VEC_LENGTH (expr)); > else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) > Index: gcc/tree-streamer-in.c > =================================================================== > *** gcc/tree-streamer-in.c 2017-11-29 11:07:59.961993930 +0000 > --- gcc/tree-streamer-in.c 2017-11-29 11:08:00.186993912 +0000 > *************** streamer_alloc_tree (struct lto_input_bl > *** 592,599 **** > } > else if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > { > ! HOST_WIDE_INT len = streamer_read_hwi (ib); > ! result = make_vector (len); > } > else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) > { > --- 592,602 ---- > } > else if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > { > ! bitpack_d bp = streamer_read_bitpack (ib); > ! unsigned int log2_npatterns = bp_unpack_value (&bp, 16); > ! unsigned int duplicate_p = bp_unpack_value (&bp, 1); > ! unsigned int series_p = bp_unpack_value (&bp, 1); > ! result = make_vector (log2_npatterns, duplicate_p, series_p); > } > else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) > { > *************** lto_input_ts_common_tree_pointers (struc > *** 650,658 **** > lto_input_ts_vector_tree_pointers (struct lto_input_block *ib, > struct data_in *data_in, tree expr) > { > ! unsigned i; > ! for (i = 0; i < VECTOR_CST_NELTS (expr); ++i) > ! VECTOR_CST_ELT (expr, i) = stream_read_tree (ib, data_in); > } > > > --- 653,664 ---- > lto_input_ts_vector_tree_pointers (struct lto_input_block *ib, > struct data_in *data_in, tree expr) > { > ! for (unsigned int i = 0; i < VECTOR_CST_NPATTERNS (expr); ++i) > ! { > ! for (unsigned int j = 0; j < 2; ++j) > ! VECTOR_CST_BASE (expr, i, j) = stream_read_tree (ib, data_in); > ! VECTOR_CST_STEP (expr, i) = stream_read_tree (ib, data_in); > ! } > } > > > Index: gcc/fold-const.c > =================================================================== > *** gcc/fold-const.c 2017-11-29 11:07:59.961993930 +0000 > --- gcc/fold-const.c 2017-11-29 11:08:00.184993912 +0000 > *************** fold_ternary_loc (location_t loc, enum t > *** 11610,11618 **** > unsigned int nelts = VECTOR_CST_NELTS (arg0); > auto_vec<tree, 32> elts (nelts); > elts.quick_grow (nelts); > ! memcpy (&elts[0], VECTOR_CST_ELTS (arg0), > ! sizeof (tree) * nelts); > ! elts[k] = arg1; > return build_vector (type, elts); > } > } > --- 11610,11617 ---- > unsigned int nelts = VECTOR_CST_NELTS (arg0); > auto_vec<tree, 32> elts (nelts); > elts.quick_grow (nelts); > ! for (unsigned int i = 0; i < VECTOR_CST_NELTS (arg0); ++i) > ! elts[i] = (i == k ? arg1 : VECTOR_CST_ELT (arg0, i)); > return build_vector (type, elts); > } > } > Index: gcc/lto/lto.c > =================================================================== > *** gcc/lto/lto.c 2017-11-29 11:07:59.961993930 +0000 > --- gcc/lto/lto.c 2017-11-29 11:08:00.185993912 +0000 > *************** #define compare_values(X) \ > *** 1065,1070 **** > --- 1065,1077 ---- > TREE_FIXED_CST_PTR (t1), TREE_FIXED_CST_PTR (t2))) > return false; > > + if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > + { > + compare_values (VECTOR_CST_LOG2_NPATTERNS); > + compare_values (VECTOR_CST_DUPLICATE_P); > + compare_values (VECTOR_CST_SERIES_P); > + } > + > if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) > { > compare_values (DECL_MODE); > *************** #define compare_tree_edges(E1, E2) \ > *** 1281,1291 **** > > if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > { > - unsigned i; > /* Note that the number of elements for EXPR has already been emitted > in EXPR's header (see streamer_write_tree_header). */ > ! for (i = 0; i < VECTOR_CST_NELTS (t1); ++i) > ! compare_tree_edges (VECTOR_CST_ELT (t1, i), VECTOR_CST_ELT (t2, i)); > } > > if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) > --- 1288,1303 ---- > > if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) > { > /* Note that the number of elements for EXPR has already been emitted > in EXPR's header (see streamer_write_tree_header). */ > ! for (unsigned int i = 0; i < VECTOR_CST_NPATTERNS (t1); ++i) > ! { > ! for (unsigned int j = 0; j < 2; ++j) > ! compare_tree_edges (VECTOR_CST_BASE (t1, i, j), > ! VECTOR_CST_BASE (t2, i, j)); > ! compare_tree_edges (VECTOR_CST_STEP (t1, i), > ! VECTOR_CST_STEP (t2, i)); > ! } > } > > if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))