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? 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; ! } ! ! /* 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) ! 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; + 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))