1*38fd1498Szrj /* A class for building vector constant patterns.
2*38fd1498Szrj    Copyright (C) 2017-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj #ifndef GCC_VECTOR_BUILDER_H
21*38fd1498Szrj #define GCC_VECTOR_BUILDER_H
22*38fd1498Szrj 
23*38fd1498Szrj /* This class is a wrapper around auto_vec<T> for building vectors of T.
24*38fd1498Szrj    It aims to encode each vector as npatterns interleaved patterns,
25*38fd1498Szrj    where each pattern represents a sequence:
26*38fd1498Szrj 
27*38fd1498Szrj      { BASE0, BASE1, BASE1 + STEP, BASE1 + STEP*2, BASE1 + STEP*3, ... }
28*38fd1498Szrj 
29*38fd1498Szrj    The first three elements in each pattern provide enough information
30*38fd1498Szrj    to derive the other elements.  If all patterns have a STEP of zero,
31*38fd1498Szrj    we only need to encode the first two elements in each pattern.
32*38fd1498Szrj    If BASE1 is also equal to BASE0 for all patterns, we only need to
33*38fd1498Szrj    encode the first element in each pattern.  The number of encoded
34*38fd1498Szrj    elements per pattern is given by nelts_per_pattern.
35*38fd1498Szrj 
36*38fd1498Szrj    The class can be used in two ways:
37*38fd1498Szrj 
38*38fd1498Szrj    1. It can be used to build a full image of the vector, which is then
39*38fd1498Szrj       canonicalized by finalize ().  In this case npatterns is initially
40*38fd1498Szrj       the number of elements in the vector and nelts_per_pattern is
41*38fd1498Szrj       initially 1.
42*38fd1498Szrj 
43*38fd1498Szrj    2. It can be used to build a vector that already has a known encoding.
44*38fd1498Szrj       This is preferred since it is more efficient and copes with
45*38fd1498Szrj       variable-length vectors.  finalize () then canonicalizes the encoding
46*38fd1498Szrj       to a simpler form if possible.
47*38fd1498Szrj 
48*38fd1498Szrj    The derived class Derived provides this functionality for specific Ts.
49*38fd1498Szrj    Derived needs to provide the following interface:
50*38fd1498Szrj 
51*38fd1498Szrj       bool equal_p (T elt1, T elt2) const;
52*38fd1498Szrj 
53*38fd1498Szrj 	  Return true if elements ELT1 and ELT2 are equal.
54*38fd1498Szrj 
55*38fd1498Szrj       bool allow_steps_p () const;
56*38fd1498Szrj 
57*38fd1498Szrj 	  Return true if a stepped representation is OK.  We don't allow
58*38fd1498Szrj 	  linear series for anything other than integers, to avoid problems
59*38fd1498Szrj 	  with rounding.
60*38fd1498Szrj 
61*38fd1498Szrj       bool integral_p (T elt) const;
62*38fd1498Szrj 
63*38fd1498Szrj 	  Return true if element ELT can be interpreted as an integer.
64*38fd1498Szrj 
65*38fd1498Szrj       StepType step (T elt1, T elt2) const;
66*38fd1498Szrj 
67*38fd1498Szrj 	  Return the value of element ELT2 minus the value of element ELT1,
68*38fd1498Szrj 	  given integral_p (ELT1) && integral_p (ELT2).  There is no fixed
69*38fd1498Szrj 	  choice of StepType.
70*38fd1498Szrj 
71*38fd1498Szrj       T apply_step (T base, unsigned int factor, StepType step) const;
72*38fd1498Szrj 
73*38fd1498Szrj 	  Return a vector element with the value BASE + FACTOR * STEP.
74*38fd1498Szrj 
75*38fd1498Szrj       bool can_elide_p (T elt) const;
76*38fd1498Szrj 
77*38fd1498Szrj 	  Return true if we can drop element ELT, even if the retained
78*38fd1498Szrj 	  elements are different.  This is provided for TREE_OVERFLOW
79*38fd1498Szrj 	  handling.
80*38fd1498Szrj 
81*38fd1498Szrj       void note_representative (T *elt1_ptr, T elt2);
82*38fd1498Szrj 
83*38fd1498Szrj 	  Record that ELT2 is being elided, given that ELT1_PTR points to
84*38fd1498Szrj 	  the last encoded element for the containing pattern.  This is
85*38fd1498Szrj 	  again provided for TREE_OVERFLOW handling.  */
86*38fd1498Szrj 
87*38fd1498Szrj template<typename T, typename Derived>
88*38fd1498Szrj class vector_builder : public auto_vec<T, 32>
89*38fd1498Szrj {
90*38fd1498Szrj public:
91*38fd1498Szrj   vector_builder ();
92*38fd1498Szrj 
full_nelts()93*38fd1498Szrj   poly_uint64 full_nelts () const { return m_full_nelts; }
npatterns()94*38fd1498Szrj   unsigned int npatterns () const { return m_npatterns; }
nelts_per_pattern()95*38fd1498Szrj   unsigned int nelts_per_pattern () const { return m_nelts_per_pattern; }
96*38fd1498Szrj   unsigned int encoded_nelts () const;
97*38fd1498Szrj   bool encoded_full_vector_p () const;
98*38fd1498Szrj   T elt (unsigned int) const;
99*38fd1498Szrj 
100*38fd1498Szrj   bool operator == (const Derived &) const;
101*38fd1498Szrj   bool operator != (const Derived &x) const { return !operator == (x); }
102*38fd1498Szrj 
103*38fd1498Szrj   void finalize ();
104*38fd1498Szrj 
105*38fd1498Szrj protected:
106*38fd1498Szrj   void new_vector (poly_uint64, unsigned int, unsigned int);
107*38fd1498Szrj   void reshape (unsigned int, unsigned int);
108*38fd1498Szrj   bool repeating_sequence_p (unsigned int, unsigned int, unsigned int);
109*38fd1498Szrj   bool stepped_sequence_p (unsigned int, unsigned int, unsigned int);
110*38fd1498Szrj   bool try_npatterns (unsigned int);
111*38fd1498Szrj 
112*38fd1498Szrj private:
113*38fd1498Szrj   vector_builder (const vector_builder &);
114*38fd1498Szrj   vector_builder &operator= (const vector_builder &);
derived()115*38fd1498Szrj   Derived *derived () { return static_cast<Derived *> (this); }
116*38fd1498Szrj   const Derived *derived () const;
117*38fd1498Szrj 
118*38fd1498Szrj   poly_uint64 m_full_nelts;
119*38fd1498Szrj   unsigned int m_npatterns;
120*38fd1498Szrj   unsigned int m_nelts_per_pattern;
121*38fd1498Szrj };
122*38fd1498Szrj 
123*38fd1498Szrj template<typename T, typename Derived>
124*38fd1498Szrj inline const Derived *
derived()125*38fd1498Szrj vector_builder<T, Derived>::derived () const
126*38fd1498Szrj {
127*38fd1498Szrj   return static_cast<const Derived *> (this);
128*38fd1498Szrj }
129*38fd1498Szrj 
130*38fd1498Szrj template<typename T, typename Derived>
131*38fd1498Szrj inline
vector_builder()132*38fd1498Szrj vector_builder<T, Derived>::vector_builder ()
133*38fd1498Szrj   : m_full_nelts (0),
134*38fd1498Szrj     m_npatterns (0),
135*38fd1498Szrj     m_nelts_per_pattern (0)
136*38fd1498Szrj {}
137*38fd1498Szrj 
138*38fd1498Szrj /* Return the number of elements that are explicitly encoded.  The vec
139*38fd1498Szrj    starts with these explicitly-encoded elements and may contain additional
140*38fd1498Szrj    elided elements.  */
141*38fd1498Szrj 
142*38fd1498Szrj template<typename T, typename Derived>
143*38fd1498Szrj inline unsigned int
encoded_nelts()144*38fd1498Szrj vector_builder<T, Derived>::encoded_nelts () const
145*38fd1498Szrj {
146*38fd1498Szrj   return m_npatterns * m_nelts_per_pattern;
147*38fd1498Szrj }
148*38fd1498Szrj 
149*38fd1498Szrj /* Return true if every element of the vector is explicitly encoded.  */
150*38fd1498Szrj 
151*38fd1498Szrj template<typename T, typename Derived>
152*38fd1498Szrj inline bool
encoded_full_vector_p()153*38fd1498Szrj vector_builder<T, Derived>::encoded_full_vector_p () const
154*38fd1498Szrj {
155*38fd1498Szrj   return known_eq (m_npatterns * m_nelts_per_pattern, m_full_nelts);
156*38fd1498Szrj }
157*38fd1498Szrj 
158*38fd1498Szrj /* Start building a vector that has FULL_NELTS elements.  Initially
159*38fd1498Szrj    encode it using NPATTERNS patterns with NELTS_PER_PATTERN each.  */
160*38fd1498Szrj 
161*38fd1498Szrj template<typename T, typename Derived>
162*38fd1498Szrj void
new_vector(poly_uint64 full_nelts,unsigned int npatterns,unsigned int nelts_per_pattern)163*38fd1498Szrj vector_builder<T, Derived>::new_vector (poly_uint64 full_nelts,
164*38fd1498Szrj 					unsigned int npatterns,
165*38fd1498Szrj 					unsigned int nelts_per_pattern)
166*38fd1498Szrj {
167*38fd1498Szrj   m_full_nelts = full_nelts;
168*38fd1498Szrj   m_npatterns = npatterns;
169*38fd1498Szrj   m_nelts_per_pattern = nelts_per_pattern;
170*38fd1498Szrj   this->reserve (encoded_nelts ());
171*38fd1498Szrj   this->truncate (0);
172*38fd1498Szrj }
173*38fd1498Szrj 
174*38fd1498Szrj /* Return true if this vector and OTHER have the same elements and
175*38fd1498Szrj    are encoded in the same way.  */
176*38fd1498Szrj 
177*38fd1498Szrj template<typename T, typename Derived>
178*38fd1498Szrj bool
179*38fd1498Szrj vector_builder<T, Derived>::operator == (const Derived &other) const
180*38fd1498Szrj {
181*38fd1498Szrj   if (maybe_ne (m_full_nelts, other.m_full_nelts)
182*38fd1498Szrj       || m_npatterns != other.m_npatterns
183*38fd1498Szrj       || m_nelts_per_pattern != other.m_nelts_per_pattern)
184*38fd1498Szrj     return false;
185*38fd1498Szrj 
186*38fd1498Szrj   unsigned int nelts = encoded_nelts ();
187*38fd1498Szrj   for (unsigned int i = 0; i < nelts; ++i)
188*38fd1498Szrj     if (!derived ()->equal_p ((*this)[i], other[i]))
189*38fd1498Szrj       return false;
190*38fd1498Szrj 
191*38fd1498Szrj   return true;
192*38fd1498Szrj }
193*38fd1498Szrj 
194*38fd1498Szrj /* Return the value of vector element I, which might or might not be
195*38fd1498Szrj    encoded explicitly.  */
196*38fd1498Szrj 
197*38fd1498Szrj template<typename T, typename Derived>
198*38fd1498Szrj T
elt(unsigned int i)199*38fd1498Szrj vector_builder<T, Derived>::elt (unsigned int i) const
200*38fd1498Szrj {
201*38fd1498Szrj   /* This only makes sense if the encoding has been fully populated.  */
202*38fd1498Szrj   gcc_checking_assert (encoded_nelts () <= this->length ());
203*38fd1498Szrj 
204*38fd1498Szrj   /* First handle elements that are already present in the underlying
205*38fd1498Szrj      vector, regardless of whether they're part of the encoding or not.  */
206*38fd1498Szrj   if (i < this->length ())
207*38fd1498Szrj     return (*this)[i];
208*38fd1498Szrj 
209*38fd1498Szrj   /* Identify the pattern that contains element I and work out the index of
210*38fd1498Szrj      the last encoded element for that pattern.  */
211*38fd1498Szrj   unsigned int pattern = i % m_npatterns;
212*38fd1498Szrj   unsigned int count = i / m_npatterns;
213*38fd1498Szrj   unsigned int final_i = encoded_nelts () - m_npatterns + pattern;
214*38fd1498Szrj   T final = (*this)[final_i];
215*38fd1498Szrj 
216*38fd1498Szrj   /* If there are no steps, the final encoded value is the right one.  */
217*38fd1498Szrj   if (m_nelts_per_pattern <= 2)
218*38fd1498Szrj     return final;
219*38fd1498Szrj 
220*38fd1498Szrj   /* Otherwise work out the value from the last two encoded elements.  */
221*38fd1498Szrj   T prev = (*this)[final_i - m_npatterns];
222*38fd1498Szrj   return derived ()->apply_step (final, count - 2,
223*38fd1498Szrj 				 derived ()->step (prev, final));
224*38fd1498Szrj }
225*38fd1498Szrj 
226*38fd1498Szrj /* Change the encoding to NPATTERNS patterns of NELTS_PER_PATTERN each,
227*38fd1498Szrj    but without changing the underlying vector.  */
228*38fd1498Szrj 
229*38fd1498Szrj template<typename T, typename Derived>
230*38fd1498Szrj void
reshape(unsigned int npatterns,unsigned int nelts_per_pattern)231*38fd1498Szrj vector_builder<T, Derived>::reshape (unsigned int npatterns,
232*38fd1498Szrj 				     unsigned int nelts_per_pattern)
233*38fd1498Szrj {
234*38fd1498Szrj   unsigned int old_encoded_nelts = encoded_nelts ();
235*38fd1498Szrj   unsigned int new_encoded_nelts = npatterns * nelts_per_pattern;
236*38fd1498Szrj   gcc_checking_assert (new_encoded_nelts <= old_encoded_nelts);
237*38fd1498Szrj   unsigned int next = new_encoded_nelts - npatterns;
238*38fd1498Szrj   for (unsigned int i = new_encoded_nelts; i < old_encoded_nelts; ++i)
239*38fd1498Szrj     {
240*38fd1498Szrj       derived ()->note_representative (&(*this)[next], (*this)[i]);
241*38fd1498Szrj       next += 1;
242*38fd1498Szrj       if (next == new_encoded_nelts)
243*38fd1498Szrj 	next -= npatterns;
244*38fd1498Szrj     }
245*38fd1498Szrj   m_npatterns = npatterns;
246*38fd1498Szrj   m_nelts_per_pattern = nelts_per_pattern;
247*38fd1498Szrj }
248*38fd1498Szrj 
249*38fd1498Szrj /* Return true if elements [START, END) contain a repeating sequence of
250*38fd1498Szrj    STEP elements.  */
251*38fd1498Szrj 
252*38fd1498Szrj template<typename T, typename Derived>
253*38fd1498Szrj bool
repeating_sequence_p(unsigned int start,unsigned int end,unsigned int step)254*38fd1498Szrj vector_builder<T, Derived>::repeating_sequence_p (unsigned int start,
255*38fd1498Szrj 						  unsigned int end,
256*38fd1498Szrj 						  unsigned int step)
257*38fd1498Szrj {
258*38fd1498Szrj   for (unsigned int i = start; i < end - step; ++i)
259*38fd1498Szrj     if (!derived ()->equal_p ((*this)[i], (*this)[i + step]))
260*38fd1498Szrj       return false;
261*38fd1498Szrj   return true;
262*38fd1498Szrj }
263*38fd1498Szrj 
264*38fd1498Szrj /* Return true if elements [START, END) contain STEP interleaved linear
265*38fd1498Szrj    series.  */
266*38fd1498Szrj 
267*38fd1498Szrj template<typename T, typename Derived>
268*38fd1498Szrj bool
stepped_sequence_p(unsigned int start,unsigned int end,unsigned int step)269*38fd1498Szrj vector_builder<T, Derived>::stepped_sequence_p (unsigned int start,
270*38fd1498Szrj 						unsigned int end,
271*38fd1498Szrj 						unsigned int step)
272*38fd1498Szrj {
273*38fd1498Szrj   if (!derived ()->allow_steps_p ())
274*38fd1498Szrj     return false;
275*38fd1498Szrj 
276*38fd1498Szrj   for (unsigned int i = start + step * 2; i < end; ++i)
277*38fd1498Szrj     {
278*38fd1498Szrj       T elt1 = (*this)[i - step * 2];
279*38fd1498Szrj       T elt2 = (*this)[i - step];
280*38fd1498Szrj       T elt3 = (*this)[i];
281*38fd1498Szrj 
282*38fd1498Szrj       if (!derived ()->integral_p (elt1)
283*38fd1498Szrj 	  || !derived ()->integral_p (elt2)
284*38fd1498Szrj 	  || !derived ()->integral_p (elt3))
285*38fd1498Szrj 	return false;
286*38fd1498Szrj 
287*38fd1498Szrj       if (maybe_ne (derived ()->step (elt1, elt2),
288*38fd1498Szrj 		    derived ()->step (elt2, elt3)))
289*38fd1498Szrj 	return false;
290*38fd1498Szrj 
291*38fd1498Szrj       if (!derived ()->can_elide_p (elt3))
292*38fd1498Szrj 	return false;
293*38fd1498Szrj     }
294*38fd1498Szrj   return true;
295*38fd1498Szrj }
296*38fd1498Szrj 
297*38fd1498Szrj /* Try to change the number of encoded patterns to NPATTERNS, returning
298*38fd1498Szrj    true on success.  */
299*38fd1498Szrj 
300*38fd1498Szrj template<typename T, typename Derived>
301*38fd1498Szrj bool
try_npatterns(unsigned int npatterns)302*38fd1498Szrj vector_builder<T, Derived>::try_npatterns (unsigned int npatterns)
303*38fd1498Szrj {
304*38fd1498Szrj   if (m_nelts_per_pattern == 1)
305*38fd1498Szrj     {
306*38fd1498Szrj       /* See whether NPATTERNS is valid with the current 1-element-per-pattern
307*38fd1498Szrj 	 encoding.  */
308*38fd1498Szrj       if (repeating_sequence_p (0, encoded_nelts (), npatterns))
309*38fd1498Szrj 	{
310*38fd1498Szrj 	  reshape (npatterns, 1);
311*38fd1498Szrj 	  return true;
312*38fd1498Szrj 	}
313*38fd1498Szrj 
314*38fd1498Szrj       /* We can only increase the number of elements per pattern if all
315*38fd1498Szrj 	 elements are still encoded explicitly.  */
316*38fd1498Szrj       if (!encoded_full_vector_p ())
317*38fd1498Szrj 	return false;
318*38fd1498Szrj     }
319*38fd1498Szrj 
320*38fd1498Szrj   if (m_nelts_per_pattern <= 2)
321*38fd1498Szrj     {
322*38fd1498Szrj       /* See whether NPATTERNS is valid with a 2-element-per-pattern
323*38fd1498Szrj 	 encoding.  */
324*38fd1498Szrj       if (repeating_sequence_p (npatterns, encoded_nelts (), npatterns))
325*38fd1498Szrj 	{
326*38fd1498Szrj 	  reshape (npatterns, 2);
327*38fd1498Szrj 	  return true;
328*38fd1498Szrj 	}
329*38fd1498Szrj 
330*38fd1498Szrj       /* We can only increase the number of elements per pattern if all
331*38fd1498Szrj 	 elements are still encoded explicitly.  */
332*38fd1498Szrj       if (!encoded_full_vector_p ())
333*38fd1498Szrj 	return false;
334*38fd1498Szrj     }
335*38fd1498Szrj 
336*38fd1498Szrj   if (m_nelts_per_pattern <= 3)
337*38fd1498Szrj     {
338*38fd1498Szrj       /* See whether we have NPATTERNS interleaved linear series,
339*38fd1498Szrj 	 giving a 3-element-per-pattern encoding.  */
340*38fd1498Szrj       if (stepped_sequence_p (npatterns, encoded_nelts (), npatterns))
341*38fd1498Szrj 	{
342*38fd1498Szrj 	  reshape (npatterns, 3);
343*38fd1498Szrj 	  return true;
344*38fd1498Szrj 	}
345*38fd1498Szrj       return false;
346*38fd1498Szrj     }
347*38fd1498Szrj 
348*38fd1498Szrj   gcc_unreachable ();
349*38fd1498Szrj }
350*38fd1498Szrj 
351*38fd1498Szrj /* Replace the current encoding with the canonical form.  */
352*38fd1498Szrj 
353*38fd1498Szrj template<typename T, typename Derived>
354*38fd1498Szrj void
finalize()355*38fd1498Szrj vector_builder<T, Derived>::finalize ()
356*38fd1498Szrj {
357*38fd1498Szrj   /* The encoding requires the same number of elements to come from each
358*38fd1498Szrj      pattern.  */
359*38fd1498Szrj   gcc_assert (multiple_p (m_full_nelts, m_npatterns));
360*38fd1498Szrj 
361*38fd1498Szrj   /* Allow the caller to build more elements than necessary.  For example,
362*38fd1498Szrj      it's often convenient to build a stepped vector from the natural
363*38fd1498Szrj      encoding of three elements even if the vector itself only has two.  */
364*38fd1498Szrj   unsigned HOST_WIDE_INT const_full_nelts;
365*38fd1498Szrj   if (m_full_nelts.is_constant (&const_full_nelts)
366*38fd1498Szrj       && const_full_nelts <= encoded_nelts ())
367*38fd1498Szrj     {
368*38fd1498Szrj       m_npatterns = const_full_nelts;
369*38fd1498Szrj       m_nelts_per_pattern = 1;
370*38fd1498Szrj     }
371*38fd1498Szrj 
372*38fd1498Szrj   /* Try to whittle down the number of elements per pattern.  That is:
373*38fd1498Szrj 
374*38fd1498Szrj      1. If we have stepped patterns whose steps are all 0, reduce the
375*38fd1498Szrj         number of elements per pattern from 3 to 2.
376*38fd1498Szrj 
377*38fd1498Szrj      2. If we have background fill values that are the same as the
378*38fd1498Szrj         foreground values, reduce the number of elements per pattern
379*38fd1498Szrj         from 2 to 1.  */
380*38fd1498Szrj   while (m_nelts_per_pattern > 1
381*38fd1498Szrj 	 && repeating_sequence_p (encoded_nelts () - m_npatterns * 2,
382*38fd1498Szrj 				  encoded_nelts (), m_npatterns))
383*38fd1498Szrj     /* The last two sequences of M_NPATTERNS elements are equal,
384*38fd1498Szrj        so remove the last one.  */
385*38fd1498Szrj     reshape (m_npatterns, m_nelts_per_pattern - 1);
386*38fd1498Szrj 
387*38fd1498Szrj   if (pow2p_hwi (m_npatterns))
388*38fd1498Szrj     {
389*38fd1498Szrj       /* Try to halve the number of patterns while doing so gives a
390*38fd1498Szrj 	 valid pattern.  This approach is linear in the number of
391*38fd1498Szrj 	 elements, whereas searcing from 1 up would be O(n*log(n)).
392*38fd1498Szrj 
393*38fd1498Szrj 	 Each halving step tries to keep the number of elements per pattern
394*38fd1498Szrj 	 the same.  If that isn't possible, and if all elements are still
395*38fd1498Szrj 	 explicitly encoded, the halving step can instead increase the number
396*38fd1498Szrj 	 of elements per pattern.
397*38fd1498Szrj 
398*38fd1498Szrj 	 E.g. for:
399*38fd1498Szrj 
400*38fd1498Szrj 	     { 0, 2, 3, 4, 5, 6, 7, 8 }  npatterns == 8  full_nelts == 8
401*38fd1498Szrj 
402*38fd1498Szrj 	 we first realize that the second half of the sequence is not
403*38fd1498Szrj 	 equal to the first, so we cannot maintain 1 element per pattern
404*38fd1498Szrj 	 for npatterns == 4.  Instead we halve the number of patterns
405*38fd1498Szrj 	 and double the number of elements per pattern, treating this
406*38fd1498Szrj 	 as a "foreground" { 0, 2, 3, 4 } against a "background" of
407*38fd1498Szrj 	 { 5, 6, 7, 8 | 5, 6, 7, 8 ... }:
408*38fd1498Szrj 
409*38fd1498Szrj 	     { 0, 2, 3, 4 | 5, 6, 7, 8 }  npatterns == 4
410*38fd1498Szrj 
411*38fd1498Szrj 	 Next we realize that this is *not* a foreround of { 0, 2 }
412*38fd1498Szrj 	 against a background of { 3, 4 | 3, 4 ... }, so the only
413*38fd1498Szrj 	 remaining option for reducing the number of patterns is
414*38fd1498Szrj 	 to use a foreground of { 0, 2 } against a stepped background
415*38fd1498Szrj 	 of { 1, 2 | 3, 4 | 5, 6 ... }.  This is valid because we still
416*38fd1498Szrj 	 haven't elided any elements:
417*38fd1498Szrj 
418*38fd1498Szrj 	     { 0, 2 | 3, 4 | 5, 6 }  npatterns == 2
419*38fd1498Szrj 
420*38fd1498Szrj 	 This in turn can be reduced to a foreground of { 0 } against a
421*38fd1498Szrj 	 stepped background of { 1 | 2 | 3 ... }:
422*38fd1498Szrj 
423*38fd1498Szrj 	     { 0 | 2 | 3 }  npatterns == 1
424*38fd1498Szrj 
425*38fd1498Szrj 	 This last step would not have been possible for:
426*38fd1498Szrj 
427*38fd1498Szrj 	     { 0, 0 | 3, 4 | 5, 6 }  npatterns == 2.  */
428*38fd1498Szrj       while ((m_npatterns & 1) == 0 && try_npatterns (m_npatterns / 2))
429*38fd1498Szrj 	continue;
430*38fd1498Szrj 
431*38fd1498Szrj       /* Builders of arbitrary fixed-length vectors can use:
432*38fd1498Szrj 
433*38fd1498Szrj 	     new_vector (x, x, 1)
434*38fd1498Szrj 
435*38fd1498Szrj 	 so that every element is specified explicitly.  Handle cases
436*38fd1498Szrj 	 that are actually wrapping series, like { 0, 1, 2, 3, 0, 1, 2, 3 }
437*38fd1498Szrj 	 would be for 2-bit elements.  We'll have treated them as
438*38fd1498Szrj 	 duplicates in the loop above.  */
439*38fd1498Szrj       if (m_nelts_per_pattern == 1
440*38fd1498Szrj 	  && m_full_nelts.is_constant (&const_full_nelts)
441*38fd1498Szrj 	  && this->length () >= const_full_nelts
442*38fd1498Szrj 	  && (m_npatterns & 3) == 0
443*38fd1498Szrj 	  && stepped_sequence_p (m_npatterns / 4, const_full_nelts,
444*38fd1498Szrj 				 m_npatterns / 4))
445*38fd1498Szrj 	{
446*38fd1498Szrj 	  reshape (m_npatterns / 4, 3);
447*38fd1498Szrj 	  while ((m_npatterns & 1) == 0 && try_npatterns (m_npatterns / 2))
448*38fd1498Szrj 	    continue;
449*38fd1498Szrj 	}
450*38fd1498Szrj     }
451*38fd1498Szrj   else
452*38fd1498Szrj     /* For the non-power-of-2 case, do a simple search up from 1.  */
453*38fd1498Szrj     for (unsigned int i = 1; i <= m_npatterns / 2; ++i)
454*38fd1498Szrj       if (m_npatterns % i == 0 && try_npatterns (i))
455*38fd1498Szrj 	break;
456*38fd1498Szrj }
457*38fd1498Szrj 
458*38fd1498Szrj #endif
459