diff mbox series

[2/4] New CONST_VECTOR layout

Message ID 87shbuh8y9.fsf@linaro.org
State New
Headers show
Series Use new vector constant encoding for CONST_VECTOR | expand

Commit Message

Richard Sandiford Dec. 28, 2017, 8:51 p.m. UTC
This patch makes CONST_VECTOR use the same encoding as VECTOR_CST.

One problem that occurs in RTL but not at the tree level is that a fair
amount of code uses XVEC and XVECEXP directly on CONST_VECTORs (which is
valid, just with looser checking).  This is complicated by the fact that
vectors are also represented as PARALLELs in some target interfaces,
so using XVECEXP is a good polymorphic way of handling both forms.

Rather than try to untangle all that, the best approach seemed to be to
continue to encode every element in a fixed-length vector.  That way only
target-independent and AArch64 code need to be precise about using
CONST_VECTOR_ELT over XVECEXP.

After this change is no longer valid to modify CONST_VECTORs in-place.
This needed some fix-up in the powerpc backends.


2017-12-28  Richard Sandiford  <richard.sandiford@linaro.org>

gcc/
	* doc/rtl.texi (const_vector): Describe new encoding scheme.
	* Makefile.in (OBJS): Add rtx-vector-builder.o.
	* rtx-vector-builder.h: New file.
	* rtx-vector-builder.c: Likewise.
	* rtl.h (rtx_def::u2): Add a const_vector field.
	(CONST_VECTOR_NPATTERNS): New macro.
	(CONST_VECTOR_NELTS_PER_PATTERN): Likewise.
	(CONST_VECTOR_DUPLICATE_P): Likewise.
	(CONST_VECTOR_STEPPED_P): Likewise.
	(CONST_VECTOR_ENCODED_ELT): Likewise.
	(const_vec_duplicate_p): Check for a duplicated vector encoding.
	(unwrap_const_vec_duplicate): Likewise.
	(const_vec_series_p): Check for a non-duplicated vector encoding.
	Say that the function only returns true for integer vectors.
	* emit-rtl.c: Include rtx-vector-builder.h.
	(gen_const_vec_duplicate_1): Delete.
	(gen_const_vector): Call gen_const_vec_duplicate instead of
	gen_const_vec_duplicate_1.
	(const_vec_series_p_1): Operate directly on the CONST_VECTOR encoding.
	(gen_const_vec_duplicate): Use rtx_vector_builder.
	(gen_const_vec_series): Likewise.
	(gen_rtx_CONST_VECTOR): Likewise.
	* config/powerpcspe/powerpcspe.c: Include rtx-vector-builder.h.
	(swap_const_vector_halves): Take an rtx pointer rather than rtx.
	Build a new vector rather than modifying a CONST_VECTOR in-place.
	(handle_special_swappables): Update call accordingly.
	* config/rs6000/rs6000-p8swap.c: Include rtx-vector-builder.h.
	(swap_const_vector_halves): Take an rtx pointer rather than rtx.
	Build a new vector rather than modifying a CONST_VECTOR in-place.
	(handle_special_swappables): Update call accordingly.

Comments

Richard Biener Jan. 2, 2018, 2:02 p.m. UTC | #1
On Thu, Dec 28, 2017 at 9:51 PM, Richard Sandiford
<richard.sandiford@linaro.org> wrote:
> This patch makes CONST_VECTOR use the same encoding as VECTOR_CST.

>

> One problem that occurs in RTL but not at the tree level is that a fair

> amount of code uses XVEC and XVECEXP directly on CONST_VECTORs (which is

> valid, just with looser checking).  This is complicated by the fact that

> vectors are also represented as PARALLELs in some target interfaces,

> so using XVECEXP is a good polymorphic way of handling both forms.

>

> Rather than try to untangle all that, the best approach seemed to be to

> continue to encode every element in a fixed-length vector.  That way only

> target-independent and AArch64 code need to be precise about using

> CONST_VECTOR_ELT over XVECEXP.

>

> After this change is no longer valid to modify CONST_VECTORs in-place.

> This needed some fix-up in the powerpc backends.


Ok.

Richard.

> 2017-12-28  Richard Sandiford  <richard.sandiford@linaro.org>

>

> gcc/

>         * doc/rtl.texi (const_vector): Describe new encoding scheme.

>         * Makefile.in (OBJS): Add rtx-vector-builder.o.

>         * rtx-vector-builder.h: New file.

>         * rtx-vector-builder.c: Likewise.

>         * rtl.h (rtx_def::u2): Add a const_vector field.

>         (CONST_VECTOR_NPATTERNS): New macro.

>         (CONST_VECTOR_NELTS_PER_PATTERN): Likewise.

>         (CONST_VECTOR_DUPLICATE_P): Likewise.

>         (CONST_VECTOR_STEPPED_P): Likewise.

>         (CONST_VECTOR_ENCODED_ELT): Likewise.

>         (const_vec_duplicate_p): Check for a duplicated vector encoding.

>         (unwrap_const_vec_duplicate): Likewise.

>         (const_vec_series_p): Check for a non-duplicated vector encoding.

>         Say that the function only returns true for integer vectors.

>         * emit-rtl.c: Include rtx-vector-builder.h.

>         (gen_const_vec_duplicate_1): Delete.

>         (gen_const_vector): Call gen_const_vec_duplicate instead of

>         gen_const_vec_duplicate_1.

>         (const_vec_series_p_1): Operate directly on the CONST_VECTOR encoding.

>         (gen_const_vec_duplicate): Use rtx_vector_builder.

>         (gen_const_vec_series): Likewise.

>         (gen_rtx_CONST_VECTOR): Likewise.

>         * config/powerpcspe/powerpcspe.c: Include rtx-vector-builder.h.

>         (swap_const_vector_halves): Take an rtx pointer rather than rtx.

>         Build a new vector rather than modifying a CONST_VECTOR in-place.

>         (handle_special_swappables): Update call accordingly.

>         * config/rs6000/rs6000-p8swap.c: Include rtx-vector-builder.h.

>         (swap_const_vector_halves): Take an rtx pointer rather than rtx.

>         Build a new vector rather than modifying a CONST_VECTOR in-place.

>         (handle_special_swappables): Update call accordingly.

>

> Index: gcc/doc/rtl.texi

> ===================================================================

> --- gcc/doc/rtl.texi    2017-12-22 16:54:11.793940998 +0000

> +++ gcc/doc/rtl.texi    2017-12-28 16:58:43.018987597 +0000

> @@ -1644,18 +1644,92 @@ low-level routines) and @code{const_poly

>

>  @findex const_vector

>  @item (const_vector:@var{m} [@var{x0} @var{x1} @dots{}])

> -Represents a vector constant.  The square brackets stand for the vector

> -containing the constant elements.  @var{x0}, @var{x1} and so on are

> -the @code{const_int}, @code{const_wide_int}, @code{const_double} or

> -@code{const_fixed} elements.

> -

> -The number of units in a @code{const_vector} is obtained with the macro

> -@code{CONST_VECTOR_NUNITS} as in @code{CONST_VECTOR_NUNITS (@var{v})}.

> -

> -Individual elements in a vector constant are accessed with the macro

> -@code{CONST_VECTOR_ELT} as in @code{CONST_VECTOR_ELT (@var{v}, @var{n})}

> -where @var{v} is the vector constant and @var{n} is the element

> -desired.

> +Represents a vector constant.  The values in square brackets are

> +elements of the vector, which are always @code{const_int},

> +@code{const_wide_int}, @code{const_double} or @code{const_fixed}

> +expressions.

> +

> +Each vector constant @var{v} is treated as a specific instance of an

> +arbitrary-length sequence that itself contains

> +@samp{CONST_VECTOR_NPATTERNS (@var{v})} interleaved patterns.  Each

> +pattern has the form:

> +

> +@smallexample

> +@{ @var{base0}, @var{base1}, @var{base1} + @var{step}, @var{base1} + @var{step} * 2, @dots{} @}

> +@end smallexample

> +

> +The first three elements in each pattern are enough to determine the

> +values of the other elements.  However, if all @var{step}s are zero,

> +only the first two elements are needed.  If in addition each @var{base1}

> +is equal to the corresponding @var{base0}, only the first element in

> +each pattern is needed.  The number of determining elements per pattern

> +is given by @samp{CONST_VECTOR_NELTS_PER_PATTERN (@var{v})}.

> +

> +For example, the constant:

> +

> +@smallexample

> +@{ 0, 1, 2, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18 @}

> +@end smallexample

> +

> +is interpreted as an interleaving of the sequences:

> +

> +@smallexample

> +@{ 0, 2, 3, 4, 5, 6, 7, 8 @}

> +@{ 1, 6, 8, 10, 12, 14, 16, 18 @}

> +@end smallexample

> +

> +where the sequences are represented by the following patterns:

> +

> +@smallexample

> +@var{base0} == 0, @var{base1} == 2, @var{step} == 1

> +@var{base0} == 1, @var{base1} == 6, @var{step} == 2

> +@end smallexample

> +

> +In this case:

> +

> +@smallexample

> +CONST_VECTOR_NPATTERNS (@var{v}) == 2

> +CONST_VECTOR_NELTS_PER_PATTERN (@var{v}) == 3

> +@end smallexample

> +

> +Thus the first 6 elements (@samp{@{ 0, 1, 2, 6, 3, 8 @}}) are enough

> +to determine the whole sequence; we refer to them as the ``encoded''

> +elements.  They are the only elements present in the square brackets

> +for variable-length @code{const_vector}s (i.e. for

> +@code{const_vector}s whose mode @var{m} has a variable number of

> +elements).  However, as a convenience to code that needs to handle

> +both @code{const_vector}s and @code{parallel}s, all elements are

> +present in the square brackets for fixed-length @code{const_vector}s;

> +the encoding scheme simply reduces the amount of work involved in

> +processing constants that follow a regular pattern.

> +

> +Sometimes this scheme can create two possible encodings of the same

> +vector.  For example @{ 0, 1 @} could be seen as two patterns with

> +one element each or one pattern with two elements (@var{base0} and

> +@var{base1}).  The canonical encoding is always the one with the

> +fewest patterns or (if both encodings have the same number of

> +petterns) the one with the fewest encoded elements.

> +

> +@samp{const_vector_encoding_nelts (@var{v})} gives the total number of

> +encoded elements in @var{v}, which is 6 in the example above.

> +@code{CONST_VECTOR_ENCODED_ELT (@var{v}, @var{i})} accesses the value

> +of encoded element @var{i}.

> +

> +@samp{CONST_VECTOR_DUPLICATE_P (@var{v})} is true if @var{v} simply contains

> +repeated instances of @samp{CONST_VECTOR_NPATTERNS (@var{v})} values.  This is

> +a shorthand for testing @samp{CONST_VECTOR_NELTS_PER_PATTERN (@var{v}) == 1}.

> +

> +@samp{CONST_VECTOR_STEPPED_P (@var{v})} is true if at least one

> +pattern in @var{v} has a nonzero step.  This is a shorthand for

> +testing @samp{CONST_VECTOR_NELTS_PER_PATTERN (@var{v}) == 3}.

> +

> +@code{CONST_VECTOR_NUNITS (@var{v})} gives the total number of elements

> +in @var{v}; it is a shorthand for getting the number of units in

> +@samp{GET_MODE (@var{v})}.

> +

> +The utility function @code{const_vector_elt} gives the value of an

> +arbitrary element as an @code{rtx}.  @code{const_vector_int_elt} gives

> +the same value as a @code{wide_int}.

>

>  @findex const_string

>  @item (const_string @var{str})

> Index: gcc/Makefile.in

> ===================================================================

> --- gcc/Makefile.in     2017-12-28 16:57:58.744157771 +0000

> +++ gcc/Makefile.in     2017-12-28 16:58:43.014988604 +0000

> @@ -1453,6 +1453,7 @@ OBJS = \

>         rtlhash.o \

>         rtlanal.o \

>         rtlhooks.o \

> +       rtx-vector-builder.o \

>         run-rtl-passes.o \

>         sched-deps.o \

>         sched-ebb.o \

> Index: gcc/rtx-vector-builder.h

> ===================================================================

> --- /dev/null   2017-12-28 10:25:58.775409153 +0000

> +++ gcc/rtx-vector-builder.h    2017-12-28 16:58:43.020987093 +0000

> @@ -0,0 +1,115 @@

> +/* A class for building vector rtx constants.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

> +

> +This file is part of GCC.

> +

> +GCC is free software; you can redistribute it and/or modify it under

> +the terms of the GNU General Public License as published by the Free

> +Software Foundation; either version 3, or (at your option) any later

> +version.

> +

> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY

> +WARRANTY; without even the implied warranty of MERCHANTABILITY or

> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License

> +for more details.

> +

> +You should have received a copy of the GNU General Public License

> +along with GCC; see the file COPYING3.  If not see

> +<http://www.gnu.org/licenses/>.  */

> +

> +#ifndef GCC_RTX_VECTOR_BUILDER_H

> +#define GCC_RTX_VECTOR_BUILDER_H

> +

> +#include "vector-builder.h"

> +

> +/* This class is used to build VECTOR_CSTs from a sequence of elements.

> +   See vector_builder for more details.  */

> +class rtx_vector_builder : public vector_builder<rtx, rtx_vector_builder>

> +{

> +  typedef vector_builder<rtx, rtx_vector_builder> parent;

> +  friend class vector_builder<rtx, rtx_vector_builder>;

> +

> +public:

> +  rtx_vector_builder () : m_mode (VOIDmode) {}

> +  rtx_vector_builder (machine_mode, unsigned int, unsigned int);

> +  rtx build (rtvec);

> +  rtx build ();

> +

> +  machine_mode mode () const { return m_mode; }

> +

> +  void new_vector (machine_mode, unsigned int, unsigned int);

> +

> +private:

> +  bool equal_p (rtx, rtx) const;

> +  bool allow_steps_p () const;

> +  bool integral_p (rtx) const;

> +  wide_int step (rtx, rtx) const;

> +  rtx apply_step (rtx, unsigned int, const wide_int &) const;

> +  bool can_elide_p (rtx) const { return true; }

> +  void note_representative (rtx *, rtx) {}

> +

> +  rtx find_cached_value ();

> +

> +  machine_mode m_mode;

> +};

> +

> +/* Create a new builder for a vector of mode MODE.  Initially encode the

> +   value as NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements

> +   each.  */

> +

> +inline

> +rtx_vector_builder::rtx_vector_builder (machine_mode mode,

> +                                       unsigned int npatterns,

> +                                       unsigned int nelts_per_pattern)

> +{

> +  new_vector (mode, npatterns, nelts_per_pattern);

> +}

> +

> +/* Start building a new vector of mode MODE.  Initially encode the value

> +   as NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements each.  */

> +

> +inline void

> +rtx_vector_builder::new_vector (machine_mode mode, unsigned int npatterns,

> +                               unsigned int nelts_per_pattern)

> +{

> +  m_mode = mode;

> +  parent::new_vector (GET_MODE_NUNITS (mode), npatterns, nelts_per_pattern);

> +}

> +

> +/* Return true if elements ELT1 and ELT2 are equal.  */

> +

> +inline bool

> +rtx_vector_builder::equal_p (rtx elt1, rtx elt2) const

> +{

> +  return rtx_equal_p (elt1, elt2);

> +}

> +

> +/* Return true if a stepped representation is OK.  We don't allow

> +   linear series for anything other than integers, to avoid problems

> +   with rounding.  */

> +

> +inline bool

> +rtx_vector_builder::allow_steps_p () const

> +{

> +  return is_a <scalar_int_mode> (GET_MODE_INNER (m_mode));

> +}

> +

> +/* Return true if element ELT can be interpreted as an integer.  */

> +

> +inline bool

> +rtx_vector_builder::integral_p (rtx elt) const

> +{

> +  return CONST_SCALAR_INT_P (elt);

> +}

> +

> +/* Return the value of element ELT2 minus the value of element ELT1.

> +   Both elements are known to be CONST_SCALAR_INT_Ps.  */

> +

> +inline wide_int

> +rtx_vector_builder::step (rtx elt1, rtx elt2) const

> +{

> +  return wi::sub (rtx_mode_t (elt2, GET_MODE_INNER (m_mode)),

> +                 rtx_mode_t (elt1, GET_MODE_INNER (m_mode)));

> +}

> +

> +#endif

> Index: gcc/rtx-vector-builder.c

> ===================================================================

> --- /dev/null   2017-12-28 10:25:58.775409153 +0000

> +++ gcc/rtx-vector-builder.c    2017-12-28 16:58:43.020987093 +0000

> @@ -0,0 +1,100 @@

> +/* A class for building vector rtx constants.

> +   Copyright (C) 2017 Free Software Foundation, Inc.

> +

> +This file is part of GCC.

> +

> +GCC is free software; you can redistribute it and/or modify it under

> +the terms of the GNU General Public License as published by the Free

> +Software Foundation; either version 3, or (at your option) any later

> +version.

> +

> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY

> +WARRANTY; without even the implied warranty of MERCHANTABILITY or

> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License

> +for more details.

> +

> +You should have received a copy of the GNU General Public License

> +along with GCC; see the file COPYING3.  If not see

> +<http://www.gnu.org/licenses/>.  */

> +

> +#include "config.h"

> +#include "system.h"

> +#include "coretypes.h"

> +#include "tm.h"

> +#include "rtl.h"

> +#include "rtx-vector-builder.h"

> +

> +/* Return a CONST_VECTOR for the current constant.  V is an existing

> +   rtvec that contains all the elements.  */

> +

> +rtx

> +rtx_vector_builder::build (rtvec v)

> +{

> +  finalize ();

> +

> +  rtx x = find_cached_value ();

> +  if (x)

> +    return x;

> +

> +  x = gen_rtx_raw_CONST_VECTOR (m_mode, v);

> +  CONST_VECTOR_NPATTERNS (x) = npatterns ();

> +  CONST_VECTOR_NELTS_PER_PATTERN (x) = nelts_per_pattern ();

> +  return x;

> +}

> +

> +/* Return a vector element with the value BASE + FACTOR * STEP.  */

> +

> +rtx

> +rtx_vector_builder::apply_step (rtx base, unsigned int factor,

> +                               const wide_int &step) const

> +{

> +  scalar_int_mode int_mode = as_a <scalar_int_mode> (GET_MODE_INNER (m_mode));

> +  return immed_wide_int_const (wi::add (rtx_mode_t (base, int_mode),

> +                                       factor * step),

> +                              int_mode);

> +}

> +

> +/* Return a CONST_VECTOR for the current constant.  */

> +

> +rtx

> +rtx_vector_builder::build ()

> +{

> +  finalize ();

> +

> +  rtx x = find_cached_value ();

> +  if (x)

> +    return x;

> +

> +  unsigned int nelts = GET_MODE_NUNITS (m_mode);

> +  rtvec v = rtvec_alloc (nelts);

> +  for (unsigned int i = 0; i < nelts; ++i)

> +    RTVEC_ELT (v, i) = elt (i);

> +  x = gen_rtx_raw_CONST_VECTOR (m_mode, v);

> +  CONST_VECTOR_NPATTERNS (x) = npatterns ();

> +  CONST_VECTOR_NELTS_PER_PATTERN (x) = nelts_per_pattern ();

> +  return x;

> +}

> +

> +/* Check whether there is a global cached value for the vector.

> +   Return it if so, otherwise return null.  */

> +

> +rtx

> +rtx_vector_builder::find_cached_value ()

> +{

> +  if (encoded_nelts () != 1)

> +    return NULL_RTX;

> +

> +  rtx elt = (*this)[0];

> +

> +  /* We can be called before the global vector constants are set up,

> +     but in that case we'll just return null.  */

> +  scalar_mode inner_mode = GET_MODE_INNER (m_mode);

> +  if (elt == CONST0_RTX (inner_mode))

> +    return CONST0_RTX (m_mode);

> +  else if (elt == CONST1_RTX (inner_mode))

> +    return CONST1_RTX (m_mode);

> +  else if (elt == CONSTM1_RTX (inner_mode))

> +    return CONSTM1_RTX (m_mode);

> +

> +  return NULL_RTX;

> +}

> Index: gcc/rtl.h

> ===================================================================

> --- gcc/rtl.h   2017-12-28 16:57:58.744157771 +0000

> +++ gcc/rtl.h   2017-12-28 16:58:43.020987093 +0000

> @@ -418,6 +418,19 @@ struct GTY((desc("0"), tag("0"),

>      /* In a CONST_WIDE_INT (aka hwivec_def), this is the number of

>         HOST_WIDE_INTs in the hwivec_def.  */

>      unsigned int num_elem;

> +

> +    /* Information about a CONST_VECTOR.  */

> +    struct

> +    {

> +      /* The value of CONST_VECTOR_NPATTERNS.  */

> +      unsigned int npatterns : 16;

> +

> +      /* The value of CONST_VECTOR_NELTS_PER_PATTERN.  */

> +      unsigned int nelts_per_pattern : 8;

> +

> +      /* For future expansion.  */

> +      unsigned int unused : 8;

> +    } const_vector;

>    } GTY ((skip)) u2;

>

>    /* The first element of the operands of this rtx.

> @@ -1958,6 +1971,23 @@ #define CONST_FIXED_VALUE_LOW(r) \

>  /* For a CONST_VECTOR, return element #n.  */

>  #define CONST_VECTOR_ELT(RTX, N) XCVECEXP (RTX, 0, N, CONST_VECTOR)

>

> +/* See rtl.texi for a description of these macros.  */

> +#define CONST_VECTOR_NPATTERNS(RTX) \

> + (RTL_FLAG_CHECK1 ("CONST_VECTOR_NPATTERNS", (RTX), CONST_VECTOR) \

> +  ->u2.const_vector.npatterns)

> +

> +#define CONST_VECTOR_NELTS_PER_PATTERN(RTX) \

> + (RTL_FLAG_CHECK1 ("CONST_VECTOR_NELTS_PER_PATTERN", (RTX), CONST_VECTOR) \

> +  ->u2.const_vector.nelts_per_pattern)

> +

> +#define CONST_VECTOR_DUPLICATE_P(RTX) \

> +  (CONST_VECTOR_NELTS_PER_PATTERN (RTX) == 1)

> +

> +#define CONST_VECTOR_STEPPED_P(RTX) \

> +  (CONST_VECTOR_NELTS_PER_PATTERN (RTX) == 3)

> +

> +#define CONST_VECTOR_ENCODED_ELT(RTX, N) XCVECEXP (RTX, 0, N, CONST_VECTOR)

> +

>  /* For a CONST_VECTOR, return the number of elements in a vector.  */

>  #define CONST_VECTOR_NUNITS(RTX) XCVECLEN (RTX, 0, CONST_VECTOR)

>

> @@ -2910,7 +2940,9 @@ const_vec_p (const_rtx x)

>  inline bool

>  const_vec_duplicate_p (const_rtx x)

>  {

> -  return ((GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0)))

> +  return ((GET_CODE (x) == CONST_VECTOR

> +          && CONST_VECTOR_NPATTERNS (x) == 1

> +          && CONST_VECTOR_DUPLICATE_P (x))

>           || (GET_CODE (x) == CONST

>               && GET_CODE (XEXP (x, 0)) == VEC_DUPLICATE));

>  }

> @@ -2922,9 +2954,11 @@ const_vec_duplicate_p (const_rtx x)

>  inline bool

>  const_vec_duplicate_p (T x, T *elt)

>  {

> -  if (GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0)))

> +  if (GET_CODE (x) == CONST_VECTOR

> +      && CONST_VECTOR_NPATTERNS (x) == 1

> +      && CONST_VECTOR_DUPLICATE_P (x))

>      {

> -      *elt = CONST_VECTOR_ELT (x, 0);

> +      *elt = CONST_VECTOR_ENCODED_ELT (x, 0);

>        return true;

>      }

>    if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == VEC_DUPLICATE)

> @@ -2957,8 +2991,10 @@ vec_duplicate_p (T x, T *elt)

>  inline T

>  unwrap_const_vec_duplicate (T x)

>  {

> -  if (GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0)))

> -    return CONST_VECTOR_ELT (x, 0);

> +  if (GET_CODE (x) == CONST_VECTOR

> +      && CONST_VECTOR_NPATTERNS (x) == 1

> +      && CONST_VECTOR_DUPLICATE_P (x))

> +    return CONST_VECTOR_ENCODED_ELT (x, 0);

>    if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == VEC_DUPLICATE)

>      return XEXP (XEXP (x, 0), 0);

>    return x;

> @@ -2967,8 +3003,8 @@ unwrap_const_vec_duplicate (T x)

>  /* In emit-rtl.c.  */

>  extern bool const_vec_series_p_1 (const_rtx, rtx *, rtx *);

>

> -/* Return true if X is a constant vector that contains a linear series

> -   of the form:

> +/* Return true if X is an integer constant vector that contains a linear

> +   series of the form:

>

>     { B, B + S, B + 2 * S, B + 3 * S, ... }

>

> @@ -2978,7 +3014,8 @@ extern bool const_vec_series_p_1 (const_

>  const_vec_series_p (const_rtx x, rtx *base_out, rtx *step_out)

>  {

>    if (GET_CODE (x) == CONST_VECTOR

> -      && GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR_INT)

> +      && CONST_VECTOR_NPATTERNS (x) == 1

> +      && !CONST_VECTOR_DUPLICATE_P (x))

>      return const_vec_series_p_1 (x, base_out, step_out);

>    if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == VEC_SERIES)

>      {

> Index: gcc/emit-rtl.c

> ===================================================================

> --- gcc/emit-rtl.c      2017-12-28 16:57:58.744157771 +0000

> +++ gcc/emit-rtl.c      2017-12-28 16:58:43.018987597 +0000

> @@ -60,6 +60,7 @@ Software Foundation; either version 3, o

>  #include "stor-layout.h"

>  #include "opts.h"

>  #include "predict.h"

> +#include "rtx-vector-builder.h"

>

>  struct target_rtl default_target_rtl;

>  #if SWITCHABLE_TARGET

> @@ -5872,33 +5873,15 @@ valid_for_const_vector_p (machine_mode,

>           || CONST_FIXED_P (x));

>  }

>

> -/* Like gen_const_vec_duplicate, but ignore const_tiny_rtx.  */

> -

> -static rtx

> -gen_const_vec_duplicate_1 (machine_mode mode, rtx el)

> -{

> -  int nunits = GET_MODE_NUNITS (mode);

> -  rtvec v = rtvec_alloc (nunits);

> -  for (int i = 0; i < nunits; ++i)

> -    RTVEC_ELT (v, i) = el;

> -  return gen_rtx_raw_CONST_VECTOR (mode, v);

> -}

> -

>  /* Generate a vector constant of mode MODE in which every element has

>     value ELT.  */

>

>  rtx

>  gen_const_vec_duplicate (machine_mode mode, rtx elt)

>  {

> -  scalar_mode inner_mode = GET_MODE_INNER (mode);

> -  if (elt == CONST0_RTX (inner_mode))

> -    return CONST0_RTX (mode);

> -  else if (elt == CONST1_RTX (inner_mode))

> -    return CONST1_RTX (mode);

> -  else if (elt == CONSTM1_RTX (inner_mode))

> -    return CONSTM1_RTX (mode);

> -

> -  return gen_const_vec_duplicate_1 (mode, elt);

> +  rtx_vector_builder builder (mode, 1, 1);

> +  builder.quick_push (elt);

> +  return builder.build ();

>  }

>

>  /* Return a vector rtx of mode MODE in which every element has value X.

> @@ -5912,28 +5895,44 @@ gen_vec_duplicate (machine_mode mode, rt

>    return gen_rtx_VEC_DUPLICATE (mode, x);

>  }

>

> -/* A subroutine of const_vec_series_p that handles the case in which

> -   X is known to be an integer CONST_VECTOR.  */

> +/* A subroutine of const_vec_series_p that handles the case in which:

> +

> +     (GET_CODE (X) == CONST_VECTOR

> +      && CONST_VECTOR_NPATTERNS (X) == 1

> +      && !CONST_VECTOR_DUPLICATE_P (X))

> +

> +   is known to hold.  */

>

>  bool

>  const_vec_series_p_1 (const_rtx x, rtx *base_out, rtx *step_out)

>  {

> -  unsigned int nelts = CONST_VECTOR_NUNITS (x);

> -  if (nelts < 2)

> +  /* Stepped sequences are only defined for integers, to avoid specifying

> +     rounding behavior.  */

> +  if (GET_MODE_CLASS (GET_MODE (x)) != MODE_VECTOR_INT)

> +    return false;

> +

> +  /* A non-duplicated vector with two elements can always be seen as a

> +     series with a nonzero step.  Longer vectors must have a stepped

> +     encoding.  */

> +  if (CONST_VECTOR_NUNITS (x) != 2

> +      && !CONST_VECTOR_STEPPED_P (x))

>      return false;

>

> +  /* Calculate the step between the first and second elements.  */

>    scalar_mode inner = GET_MODE_INNER (GET_MODE (x));

>    rtx base = CONST_VECTOR_ELT (x, 0);

>    rtx step = simplify_binary_operation (MINUS, inner,

> -                                       CONST_VECTOR_ELT (x, 1), base);

> +                                       CONST_VECTOR_ENCODED_ELT (x, 1), base);

>    if (rtx_equal_p (step, CONST0_RTX (inner)))

>      return false;

>

> -  for (unsigned int i = 2; i < nelts; ++i)

> +  /* If we have a stepped encoding, check that the step between the

> +     second and third elements is the same as STEP.  */

> +  if (CONST_VECTOR_STEPPED_P (x))

>      {

>        rtx diff = simplify_binary_operation (MINUS, inner,

> -                                           CONST_VECTOR_ELT (x, i),

> -                                           CONST_VECTOR_ELT (x, i - 1));

> +                                           CONST_VECTOR_ENCODED_ELT (x, 2),

> +                                           CONST_VECTOR_ENCODED_ELT (x, 1));

>        if (!rtx_equal_p (step, diff))

>         return false;

>      }

> @@ -5952,14 +5951,12 @@ gen_const_vec_series (machine_mode mode,

>    gcc_assert (valid_for_const_vector_p (mode, base)

>               && valid_for_const_vector_p (mode, step));

>

> -  int nunits = GET_MODE_NUNITS (mode);

> -  rtvec v = rtvec_alloc (nunits);

> -  scalar_mode inner_mode = GET_MODE_INNER (mode);

> -  RTVEC_ELT (v, 0) = base;

> -  for (int i = 1; i < nunits; ++i)

> -    RTVEC_ELT (v, i) = simplify_gen_binary (PLUS, inner_mode,

> -                                           RTVEC_ELT (v, i - 1), step);

> -  return gen_rtx_raw_CONST_VECTOR (mode, v);

> +  rtx_vector_builder builder (mode, 1, 3);

> +  builder.quick_push (base);

> +  for (int i = 1; i < 3; ++i)

> +    builder.quick_push (simplify_gen_binary (PLUS, GET_MODE_INNER (mode),

> +                                            builder[i - 1], step));

> +  return builder.build ();

>  }

>

>  /* Generate a vector of mode MODE in which element I has the value

> @@ -5990,7 +5987,7 @@ gen_const_vector (machine_mode mode, int

>    rtx el = const_tiny_rtx[constant][(int) inner];

>    gcc_assert (el);

>

> -  return gen_const_vec_duplicate_1 (mode, el);

> +  return gen_const_vec_duplicate (mode, el);

>  }

>

>  /* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when

> @@ -6005,7 +6002,11 @@ gen_rtx_CONST_VECTOR (machine_mode mode,

>    if (rtvec_all_equal_p (v))

>      return gen_const_vec_duplicate (mode, RTVEC_ELT (v, 0));

>

> -  return gen_rtx_raw_CONST_VECTOR (mode, v);

> +  unsigned int nunits = GET_NUM_ELEM (v);

> +  rtx_vector_builder builder (mode, nunits, 1);

> +  for (unsigned int i = 0; i < nunits; ++i)

> +    builder.quick_push (RTVEC_ELT (v, i));

> +  return builder.build (v);

>  }

>

>  /* Initialise global register information required by all functions.  */

> Index: gcc/config/powerpcspe/powerpcspe.c

> ===================================================================

> --- gcc/config/powerpcspe/powerpcspe.c  2017-12-28 16:57:58.744157771 +0000

> +++ gcc/config/powerpcspe/powerpcspe.c  2017-12-28 16:58:43.017987848 +0000

> @@ -79,6 +79,7 @@ #define IN_TARGET_CODE 1

>  #endif

>  #include "case-cfn-macros.h"

>  #include "ppc-auxv.h"

> +#include "rtx-vector-builder.h"

>

>  /* This file should be included last.  */

>  #include "target-def.h"

> @@ -42581,23 +42582,24 @@ mark_swaps_for_removal (swap_web_entry *

>      }

>  }

>

> -/* OP is either a CONST_VECTOR or an expression containing one.

> +/* *OP_PTR is either a CONST_VECTOR or an expression containing one.

>     Swap the first half of the vector with the second in the first

>     case.  Recurse to find it in the second.  */

>  static void

> -swap_const_vector_halves (rtx op)

> +swap_const_vector_halves (rtx *op_ptr)

>  {

>    int i;

> +  rtx op = *op_ptr;

>    enum rtx_code code = GET_CODE (op);

>    if (GET_CODE (op) == CONST_VECTOR)

>      {

> -      int half_units = GET_MODE_NUNITS (GET_MODE (op)) / 2;

> -      for (i = 0; i < half_units; ++i)

> -       {

> -         rtx temp = CONST_VECTOR_ELT (op, i);

> -         CONST_VECTOR_ELT (op, i) = CONST_VECTOR_ELT (op, i + half_units);

> -         CONST_VECTOR_ELT (op, i + half_units) = temp;

> -       }

> +      int units = GET_MODE_NUNITS (GET_MODE (op));

> +      rtx_vector_builder builder (GET_MODE (op), units, 1);

> +      for (i = 0; i < units / 2; ++i)

> +       builder.quick_push (CONST_VECTOR_ELT (op, i + units / 2));

> +      for (i = 0; i < units / 2; ++i)

> +       builder.quick_push (CONST_VECTOR_ELT (op, i));

> +      *op_ptr = builder.build ();

>      }

>    else

>      {

> @@ -42605,10 +42607,10 @@ swap_const_vector_halves (rtx op)

>        const char *fmt = GET_RTX_FORMAT (code);

>        for (i = 0; i < GET_RTX_LENGTH (code); ++i)

>         if (fmt[i] == 'e' || fmt[i] == 'u')

> -         swap_const_vector_halves (XEXP (op, i));

> +         swap_const_vector_halves (&XEXP (op, i));

>         else if (fmt[i] == 'E')

>           for (j = 0; j < XVECLEN (op, i); ++j)

> -           swap_const_vector_halves (XVECEXP (op, i, j));

> +           swap_const_vector_halves (&XVECEXP (op, i, j));

>      }

>  }

>

> @@ -42900,8 +42902,7 @@ handle_special_swappables (swap_web_entr

>        {

>         /* A CONST_VECTOR will only show up somewhere in the RHS of a SET.  */

>         gcc_assert (GET_CODE (body) == SET);

> -       rtx rhs = SET_SRC (body);

> -       swap_const_vector_halves (rhs);

> +       swap_const_vector_halves (&SET_SRC (body));

>         if (dump_file)

>           fprintf (dump_file, "Swapping constant halves in insn %d\n", i);

>         break;

> Index: gcc/config/rs6000/rs6000-p8swap.c

> ===================================================================

> --- gcc/config/rs6000/rs6000-p8swap.c   2017-12-28 16:57:58.744157771 +0000

> +++ gcc/config/rs6000/rs6000-p8swap.c   2017-12-28 16:58:43.017987848 +0000

> @@ -36,6 +36,7 @@ #define IN_TARGET_CODE 1

>  #include "expr.h"

>  #include "output.h"

>  #include "tree-pass.h"

> +#include "rtx-vector-builder.h"

>

>  /* Analyze vector computations and remove unnecessary doubleword

>     swaps (xxswapdi instructions).  This pass is performed only

> @@ -931,23 +932,24 @@ mark_swaps_for_removal (swap_web_entry *

>      }

>  }

>

> -/* OP is either a CONST_VECTOR or an expression containing one.

> +/* *OP_PTR is either a CONST_VECTOR or an expression containing one.

>     Swap the first half of the vector with the second in the first

>     case.  Recurse to find it in the second.  */

>  static void

> -swap_const_vector_halves (rtx op)

> +swap_const_vector_halves (rtx *op_ptr)

>  {

>    int i;

> +  rtx op = *op_ptr;

>    enum rtx_code code = GET_CODE (op);

>    if (GET_CODE (op) == CONST_VECTOR)

>      {

> -      int half_units = GET_MODE_NUNITS (GET_MODE (op)) / 2;

> -      for (i = 0; i < half_units; ++i)

> -       {

> -         rtx temp = CONST_VECTOR_ELT (op, i);

> -         CONST_VECTOR_ELT (op, i) = CONST_VECTOR_ELT (op, i + half_units);

> -         CONST_VECTOR_ELT (op, i + half_units) = temp;

> -       }

> +      int units = GET_MODE_NUNITS (GET_MODE (op));

> +      rtx_vector_builder builder (GET_MODE (op), units, 1);

> +      for (i = 0; i < units / 2; ++i)

> +       builder.quick_push (CONST_VECTOR_ELT (op, i + units / 2));

> +      for (i = 0; i < units / 2; ++i)

> +       builder.quick_push (CONST_VECTOR_ELT (op, i));

> +      *op_ptr = builder.build ();

>      }

>    else

>      {

> @@ -955,10 +957,10 @@ swap_const_vector_halves (rtx op)

>        const char *fmt = GET_RTX_FORMAT (code);

>        for (i = 0; i < GET_RTX_LENGTH (code); ++i)

>         if (fmt[i] == 'e' || fmt[i] == 'u')

> -         swap_const_vector_halves (XEXP (op, i));

> +         swap_const_vector_halves (&XEXP (op, i));

>         else if (fmt[i] == 'E')

>           for (j = 0; j < XVECLEN (op, i); ++j)

> -           swap_const_vector_halves (XVECEXP (op, i, j));

> +           swap_const_vector_halves (&XVECEXP (op, i, j));

>      }

>  }

>

> @@ -1251,8 +1253,7 @@ handle_special_swappables (swap_web_entr

>        {

>         /* A CONST_VECTOR will only show up somewhere in the RHS of a SET.  */

>         gcc_assert (GET_CODE (body) == SET);

> -       rtx rhs = SET_SRC (body);

> -       swap_const_vector_halves (rhs);

> +       swap_const_vector_halves (&SET_SRC (body));

>         if (dump_file)

>           fprintf (dump_file, "Swapping constant halves in insn %d\n", i);

>         break;
diff mbox series

Patch

Index: gcc/doc/rtl.texi
===================================================================
--- gcc/doc/rtl.texi	2017-12-22 16:54:11.793940998 +0000
+++ gcc/doc/rtl.texi	2017-12-28 16:58:43.018987597 +0000
@@ -1644,18 +1644,92 @@  low-level routines) and @code{const_poly
 
 @findex const_vector
 @item (const_vector:@var{m} [@var{x0} @var{x1} @dots{}])
-Represents a vector constant.  The square brackets stand for the vector
-containing the constant elements.  @var{x0}, @var{x1} and so on are
-the @code{const_int}, @code{const_wide_int}, @code{const_double} or
-@code{const_fixed} elements.
-
-The number of units in a @code{const_vector} is obtained with the macro
-@code{CONST_VECTOR_NUNITS} as in @code{CONST_VECTOR_NUNITS (@var{v})}.
-
-Individual elements in a vector constant are accessed with the macro
-@code{CONST_VECTOR_ELT} as in @code{CONST_VECTOR_ELT (@var{v}, @var{n})}
-where @var{v} is the vector constant and @var{n} is the element
-desired.
+Represents a vector constant.  The values in square brackets are
+elements of the vector, which are always @code{const_int},
+@code{const_wide_int}, @code{const_double} or @code{const_fixed}
+expressions.
+
+Each vector constant @var{v} is treated as a specific instance of an
+arbitrary-length sequence that itself contains
+@samp{CONST_VECTOR_NPATTERNS (@var{v})} interleaved patterns.  Each
+pattern has the form:
+
+@smallexample
+@{ @var{base0}, @var{base1}, @var{base1} + @var{step}, @var{base1} + @var{step} * 2, @dots{} @}
+@end smallexample
+
+The first three elements in each pattern are enough to determine the
+values of the other elements.  However, if all @var{step}s are zero,
+only the first two elements are needed.  If in addition each @var{base1}
+is equal to the corresponding @var{base0}, only the first element in
+each pattern is needed.  The number of determining elements per pattern
+is given by @samp{CONST_VECTOR_NELTS_PER_PATTERN (@var{v})}.
+
+For example, the constant:
+
+@smallexample
+@{ 0, 1, 2, 6, 3, 8, 4, 10, 5, 12, 6, 14, 7, 16, 8, 18 @}
+@end smallexample
+
+is interpreted as an interleaving of the sequences:
+
+@smallexample
+@{ 0, 2, 3, 4, 5, 6, 7, 8 @}
+@{ 1, 6, 8, 10, 12, 14, 16, 18 @}
+@end smallexample
+
+where the sequences are represented by the following patterns:
+
+@smallexample
+@var{base0} == 0, @var{base1} == 2, @var{step} == 1
+@var{base0} == 1, @var{base1} == 6, @var{step} == 2
+@end smallexample
+
+In this case:
+
+@smallexample
+CONST_VECTOR_NPATTERNS (@var{v}) == 2
+CONST_VECTOR_NELTS_PER_PATTERN (@var{v}) == 3
+@end smallexample
+
+Thus the first 6 elements (@samp{@{ 0, 1, 2, 6, 3, 8 @}}) are enough
+to determine the whole sequence; we refer to them as the ``encoded''
+elements.  They are the only elements present in the square brackets
+for variable-length @code{const_vector}s (i.e. for
+@code{const_vector}s whose mode @var{m} has a variable number of
+elements).  However, as a convenience to code that needs to handle
+both @code{const_vector}s and @code{parallel}s, all elements are
+present in the square brackets for fixed-length @code{const_vector}s;
+the encoding scheme simply reduces the amount of work involved in
+processing constants that follow a regular pattern.
+
+Sometimes this scheme can create two possible encodings of the same
+vector.  For example @{ 0, 1 @} could be seen as two patterns with
+one element each or one pattern with two elements (@var{base0} and
+@var{base1}).  The canonical encoding is always the one with the
+fewest patterns or (if both encodings have the same number of
+petterns) the one with the fewest encoded elements.
+
+@samp{const_vector_encoding_nelts (@var{v})} gives the total number of
+encoded elements in @var{v}, which is 6 in the example above.
+@code{CONST_VECTOR_ENCODED_ELT (@var{v}, @var{i})} accesses the value
+of encoded element @var{i}.
+
+@samp{CONST_VECTOR_DUPLICATE_P (@var{v})} is true if @var{v} simply contains
+repeated instances of @samp{CONST_VECTOR_NPATTERNS (@var{v})} values.  This is
+a shorthand for testing @samp{CONST_VECTOR_NELTS_PER_PATTERN (@var{v}) == 1}.
+
+@samp{CONST_VECTOR_STEPPED_P (@var{v})} is true if at least one
+pattern in @var{v} has a nonzero step.  This is a shorthand for
+testing @samp{CONST_VECTOR_NELTS_PER_PATTERN (@var{v}) == 3}.
+
+@code{CONST_VECTOR_NUNITS (@var{v})} gives the total number of elements
+in @var{v}; it is a shorthand for getting the number of units in
+@samp{GET_MODE (@var{v})}.
+
+The utility function @code{const_vector_elt} gives the value of an
+arbitrary element as an @code{rtx}.  @code{const_vector_int_elt} gives
+the same value as a @code{wide_int}.
 
 @findex const_string
 @item (const_string @var{str})
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	2017-12-28 16:57:58.744157771 +0000
+++ gcc/Makefile.in	2017-12-28 16:58:43.014988604 +0000
@@ -1453,6 +1453,7 @@  OBJS = \
 	rtlhash.o \
 	rtlanal.o \
 	rtlhooks.o \
+	rtx-vector-builder.o \
 	run-rtl-passes.o \
 	sched-deps.o \
 	sched-ebb.o \
Index: gcc/rtx-vector-builder.h
===================================================================
--- /dev/null	2017-12-28 10:25:58.775409153 +0000
+++ gcc/rtx-vector-builder.h	2017-12-28 16:58:43.020987093 +0000
@@ -0,0 +1,115 @@ 
+/* A class for building vector rtx constants.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_RTX_VECTOR_BUILDER_H
+#define GCC_RTX_VECTOR_BUILDER_H
+
+#include "vector-builder.h"
+
+/* This class is used to build VECTOR_CSTs from a sequence of elements.
+   See vector_builder for more details.  */
+class rtx_vector_builder : public vector_builder<rtx, rtx_vector_builder>
+{
+  typedef vector_builder<rtx, rtx_vector_builder> parent;
+  friend class vector_builder<rtx, rtx_vector_builder>;
+
+public:
+  rtx_vector_builder () : m_mode (VOIDmode) {}
+  rtx_vector_builder (machine_mode, unsigned int, unsigned int);
+  rtx build (rtvec);
+  rtx build ();
+
+  machine_mode mode () const { return m_mode; }
+
+  void new_vector (machine_mode, unsigned int, unsigned int);
+
+private:
+  bool equal_p (rtx, rtx) const;
+  bool allow_steps_p () const;
+  bool integral_p (rtx) const;
+  wide_int step (rtx, rtx) const;
+  rtx apply_step (rtx, unsigned int, const wide_int &) const;
+  bool can_elide_p (rtx) const { return true; }
+  void note_representative (rtx *, rtx) {}
+
+  rtx find_cached_value ();
+
+  machine_mode m_mode;
+};
+
+/* Create a new builder for a vector of mode MODE.  Initially encode the
+   value as NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements
+   each.  */
+
+inline
+rtx_vector_builder::rtx_vector_builder (machine_mode mode,
+					unsigned int npatterns,
+					unsigned int nelts_per_pattern)
+{
+  new_vector (mode, npatterns, nelts_per_pattern);
+}
+
+/* Start building a new vector of mode MODE.  Initially encode the value
+   as NPATTERNS interleaved patterns with NELTS_PER_PATTERN elements each.  */
+
+inline void
+rtx_vector_builder::new_vector (machine_mode mode, unsigned int npatterns,
+				unsigned int nelts_per_pattern)
+{
+  m_mode = mode;
+  parent::new_vector (GET_MODE_NUNITS (mode), npatterns, nelts_per_pattern);
+}
+
+/* Return true if elements ELT1 and ELT2 are equal.  */
+
+inline bool
+rtx_vector_builder::equal_p (rtx elt1, rtx elt2) const
+{
+  return rtx_equal_p (elt1, elt2);
+}
+
+/* Return true if a stepped representation is OK.  We don't allow
+   linear series for anything other than integers, to avoid problems
+   with rounding.  */
+
+inline bool
+rtx_vector_builder::allow_steps_p () const
+{
+  return is_a <scalar_int_mode> (GET_MODE_INNER (m_mode));
+}
+
+/* Return true if element ELT can be interpreted as an integer.  */
+
+inline bool
+rtx_vector_builder::integral_p (rtx elt) const
+{
+  return CONST_SCALAR_INT_P (elt);
+}
+
+/* Return the value of element ELT2 minus the value of element ELT1.
+   Both elements are known to be CONST_SCALAR_INT_Ps.  */
+
+inline wide_int
+rtx_vector_builder::step (rtx elt1, rtx elt2) const
+{
+  return wi::sub (rtx_mode_t (elt2, GET_MODE_INNER (m_mode)),
+		  rtx_mode_t (elt1, GET_MODE_INNER (m_mode)));
+}
+
+#endif
Index: gcc/rtx-vector-builder.c
===================================================================
--- /dev/null	2017-12-28 10:25:58.775409153 +0000
+++ gcc/rtx-vector-builder.c	2017-12-28 16:58:43.020987093 +0000
@@ -0,0 +1,100 @@ 
+/* A class for building vector rtx constants.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "rtx-vector-builder.h"
+
+/* Return a CONST_VECTOR for the current constant.  V is an existing
+   rtvec that contains all the elements.  */
+
+rtx
+rtx_vector_builder::build (rtvec v)
+{
+  finalize ();
+
+  rtx x = find_cached_value ();
+  if (x)
+    return x;
+
+  x = gen_rtx_raw_CONST_VECTOR (m_mode, v);
+  CONST_VECTOR_NPATTERNS (x) = npatterns ();
+  CONST_VECTOR_NELTS_PER_PATTERN (x) = nelts_per_pattern ();
+  return x;
+}
+
+/* Return a vector element with the value BASE + FACTOR * STEP.  */
+
+rtx
+rtx_vector_builder::apply_step (rtx base, unsigned int factor,
+				const wide_int &step) const
+{
+  scalar_int_mode int_mode = as_a <scalar_int_mode> (GET_MODE_INNER (m_mode));
+  return immed_wide_int_const (wi::add (rtx_mode_t (base, int_mode),
+					factor * step),
+			       int_mode);
+}
+
+/* Return a CONST_VECTOR for the current constant.  */
+
+rtx
+rtx_vector_builder::build ()
+{
+  finalize ();
+
+  rtx x = find_cached_value ();
+  if (x)
+    return x;
+
+  unsigned int nelts = GET_MODE_NUNITS (m_mode);
+  rtvec v = rtvec_alloc (nelts);
+  for (unsigned int i = 0; i < nelts; ++i)
+    RTVEC_ELT (v, i) = elt (i);
+  x = gen_rtx_raw_CONST_VECTOR (m_mode, v);
+  CONST_VECTOR_NPATTERNS (x) = npatterns ();
+  CONST_VECTOR_NELTS_PER_PATTERN (x) = nelts_per_pattern ();
+  return x;
+}
+
+/* Check whether there is a global cached value for the vector.
+   Return it if so, otherwise return null.  */
+
+rtx
+rtx_vector_builder::find_cached_value ()
+{
+  if (encoded_nelts () != 1)
+    return NULL_RTX;
+
+  rtx elt = (*this)[0];
+
+  /* We can be called before the global vector constants are set up,
+     but in that case we'll just return null.  */
+  scalar_mode inner_mode = GET_MODE_INNER (m_mode);
+  if (elt == CONST0_RTX (inner_mode))
+    return CONST0_RTX (m_mode);
+  else if (elt == CONST1_RTX (inner_mode))
+    return CONST1_RTX (m_mode);
+  else if (elt == CONSTM1_RTX (inner_mode))
+    return CONSTM1_RTX (m_mode);
+
+  return NULL_RTX;
+}
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	2017-12-28 16:57:58.744157771 +0000
+++ gcc/rtl.h	2017-12-28 16:58:43.020987093 +0000
@@ -418,6 +418,19 @@  struct GTY((desc("0"), tag("0"),
     /* In a CONST_WIDE_INT (aka hwivec_def), this is the number of
        HOST_WIDE_INTs in the hwivec_def.  */
     unsigned int num_elem;
+
+    /* Information about a CONST_VECTOR.  */
+    struct
+    {
+      /* The value of CONST_VECTOR_NPATTERNS.  */
+      unsigned int npatterns : 16;
+
+      /* The value of CONST_VECTOR_NELTS_PER_PATTERN.  */
+      unsigned int nelts_per_pattern : 8;
+
+      /* For future expansion.  */
+      unsigned int unused : 8;
+    } const_vector;
   } GTY ((skip)) u2;
 
   /* The first element of the operands of this rtx.
@@ -1958,6 +1971,23 @@  #define CONST_FIXED_VALUE_LOW(r) \
 /* For a CONST_VECTOR, return element #n.  */
 #define CONST_VECTOR_ELT(RTX, N) XCVECEXP (RTX, 0, N, CONST_VECTOR)
 
+/* See rtl.texi for a description of these macros.  */
+#define CONST_VECTOR_NPATTERNS(RTX) \
+ (RTL_FLAG_CHECK1 ("CONST_VECTOR_NPATTERNS", (RTX), CONST_VECTOR) \
+  ->u2.const_vector.npatterns)
+
+#define CONST_VECTOR_NELTS_PER_PATTERN(RTX) \
+ (RTL_FLAG_CHECK1 ("CONST_VECTOR_NELTS_PER_PATTERN", (RTX), CONST_VECTOR) \
+  ->u2.const_vector.nelts_per_pattern)
+
+#define CONST_VECTOR_DUPLICATE_P(RTX) \
+  (CONST_VECTOR_NELTS_PER_PATTERN (RTX) == 1)
+
+#define CONST_VECTOR_STEPPED_P(RTX) \
+  (CONST_VECTOR_NELTS_PER_PATTERN (RTX) == 3)
+
+#define CONST_VECTOR_ENCODED_ELT(RTX, N) XCVECEXP (RTX, 0, N, CONST_VECTOR)
+
 /* For a CONST_VECTOR, return the number of elements in a vector.  */
 #define CONST_VECTOR_NUNITS(RTX) XCVECLEN (RTX, 0, CONST_VECTOR)
 
@@ -2910,7 +2940,9 @@  const_vec_p (const_rtx x)
 inline bool
 const_vec_duplicate_p (const_rtx x)
 {
-  return ((GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0)))
+  return ((GET_CODE (x) == CONST_VECTOR
+	   && CONST_VECTOR_NPATTERNS (x) == 1
+	   && CONST_VECTOR_DUPLICATE_P (x))
 	  || (GET_CODE (x) == CONST
 	      && GET_CODE (XEXP (x, 0)) == VEC_DUPLICATE));
 }
@@ -2922,9 +2954,11 @@  const_vec_duplicate_p (const_rtx x)
 inline bool
 const_vec_duplicate_p (T x, T *elt)
 {
-  if (GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0)))
+  if (GET_CODE (x) == CONST_VECTOR
+      && CONST_VECTOR_NPATTERNS (x) == 1
+      && CONST_VECTOR_DUPLICATE_P (x))
     {
-      *elt = CONST_VECTOR_ELT (x, 0);
+      *elt = CONST_VECTOR_ENCODED_ELT (x, 0);
       return true;
     }
   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == VEC_DUPLICATE)
@@ -2957,8 +2991,10 @@  vec_duplicate_p (T x, T *elt)
 inline T
 unwrap_const_vec_duplicate (T x)
 {
-  if (GET_CODE (x) == CONST_VECTOR && rtvec_all_equal_p (XVEC (x, 0)))
-    return CONST_VECTOR_ELT (x, 0);
+  if (GET_CODE (x) == CONST_VECTOR
+      && CONST_VECTOR_NPATTERNS (x) == 1
+      && CONST_VECTOR_DUPLICATE_P (x))
+    return CONST_VECTOR_ENCODED_ELT (x, 0);
   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == VEC_DUPLICATE)
     return XEXP (XEXP (x, 0), 0);
   return x;
@@ -2967,8 +3003,8 @@  unwrap_const_vec_duplicate (T x)
 /* In emit-rtl.c.  */
 extern bool const_vec_series_p_1 (const_rtx, rtx *, rtx *);
 
-/* Return true if X is a constant vector that contains a linear series
-   of the form:
+/* Return true if X is an integer constant vector that contains a linear
+   series of the form:
 
    { B, B + S, B + 2 * S, B + 3 * S, ... }
 
@@ -2978,7 +3014,8 @@  extern bool const_vec_series_p_1 (const_
 const_vec_series_p (const_rtx x, rtx *base_out, rtx *step_out)
 {
   if (GET_CODE (x) == CONST_VECTOR
-      && GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR_INT)
+      && CONST_VECTOR_NPATTERNS (x) == 1
+      && !CONST_VECTOR_DUPLICATE_P (x))
     return const_vec_series_p_1 (x, base_out, step_out);
   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == VEC_SERIES)
     {
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	2017-12-28 16:57:58.744157771 +0000
+++ gcc/emit-rtl.c	2017-12-28 16:58:43.018987597 +0000
@@ -60,6 +60,7 @@  Software Foundation; either version 3, o
 #include "stor-layout.h"
 #include "opts.h"
 #include "predict.h"
+#include "rtx-vector-builder.h"
 
 struct target_rtl default_target_rtl;
 #if SWITCHABLE_TARGET
@@ -5872,33 +5873,15 @@  valid_for_const_vector_p (machine_mode,
 	  || CONST_FIXED_P (x));
 }
 
-/* Like gen_const_vec_duplicate, but ignore const_tiny_rtx.  */
-
-static rtx
-gen_const_vec_duplicate_1 (machine_mode mode, rtx el)
-{
-  int nunits = GET_MODE_NUNITS (mode);
-  rtvec v = rtvec_alloc (nunits);
-  for (int i = 0; i < nunits; ++i)
-    RTVEC_ELT (v, i) = el;
-  return gen_rtx_raw_CONST_VECTOR (mode, v);
-}
-
 /* Generate a vector constant of mode MODE in which every element has
    value ELT.  */
 
 rtx
 gen_const_vec_duplicate (machine_mode mode, rtx elt)
 {
-  scalar_mode inner_mode = GET_MODE_INNER (mode);
-  if (elt == CONST0_RTX (inner_mode))
-    return CONST0_RTX (mode);
-  else if (elt == CONST1_RTX (inner_mode))
-    return CONST1_RTX (mode);
-  else if (elt == CONSTM1_RTX (inner_mode))
-    return CONSTM1_RTX (mode);
-
-  return gen_const_vec_duplicate_1 (mode, elt);
+  rtx_vector_builder builder (mode, 1, 1);
+  builder.quick_push (elt);
+  return builder.build ();
 }
 
 /* Return a vector rtx of mode MODE in which every element has value X.
@@ -5912,28 +5895,44 @@  gen_vec_duplicate (machine_mode mode, rt
   return gen_rtx_VEC_DUPLICATE (mode, x);
 }
 
-/* A subroutine of const_vec_series_p that handles the case in which
-   X is known to be an integer CONST_VECTOR.  */
+/* A subroutine of const_vec_series_p that handles the case in which:
+
+     (GET_CODE (X) == CONST_VECTOR
+      && CONST_VECTOR_NPATTERNS (X) == 1
+      && !CONST_VECTOR_DUPLICATE_P (X))
+
+   is known to hold.  */
 
 bool
 const_vec_series_p_1 (const_rtx x, rtx *base_out, rtx *step_out)
 {
-  unsigned int nelts = CONST_VECTOR_NUNITS (x);
-  if (nelts < 2)
+  /* Stepped sequences are only defined for integers, to avoid specifying
+     rounding behavior.  */
+  if (GET_MODE_CLASS (GET_MODE (x)) != MODE_VECTOR_INT)
+    return false;
+
+  /* A non-duplicated vector with two elements can always be seen as a
+     series with a nonzero step.  Longer vectors must have a stepped
+     encoding.  */
+  if (CONST_VECTOR_NUNITS (x) != 2
+      && !CONST_VECTOR_STEPPED_P (x))
     return false;
 
+  /* Calculate the step between the first and second elements.  */
   scalar_mode inner = GET_MODE_INNER (GET_MODE (x));
   rtx base = CONST_VECTOR_ELT (x, 0);
   rtx step = simplify_binary_operation (MINUS, inner,
-					CONST_VECTOR_ELT (x, 1), base);
+					CONST_VECTOR_ENCODED_ELT (x, 1), base);
   if (rtx_equal_p (step, CONST0_RTX (inner)))
     return false;
 
-  for (unsigned int i = 2; i < nelts; ++i)
+  /* If we have a stepped encoding, check that the step between the
+     second and third elements is the same as STEP.  */
+  if (CONST_VECTOR_STEPPED_P (x))
     {
       rtx diff = simplify_binary_operation (MINUS, inner,
-					    CONST_VECTOR_ELT (x, i),
-					    CONST_VECTOR_ELT (x, i - 1));
+					    CONST_VECTOR_ENCODED_ELT (x, 2),
+					    CONST_VECTOR_ENCODED_ELT (x, 1));
       if (!rtx_equal_p (step, diff))
 	return false;
     }
@@ -5952,14 +5951,12 @@  gen_const_vec_series (machine_mode mode,
   gcc_assert (valid_for_const_vector_p (mode, base)
 	      && valid_for_const_vector_p (mode, step));
 
-  int nunits = GET_MODE_NUNITS (mode);
-  rtvec v = rtvec_alloc (nunits);
-  scalar_mode inner_mode = GET_MODE_INNER (mode);
-  RTVEC_ELT (v, 0) = base;
-  for (int i = 1; i < nunits; ++i)
-    RTVEC_ELT (v, i) = simplify_gen_binary (PLUS, inner_mode,
-					    RTVEC_ELT (v, i - 1), step);
-  return gen_rtx_raw_CONST_VECTOR (mode, v);
+  rtx_vector_builder builder (mode, 1, 3);
+  builder.quick_push (base);
+  for (int i = 1; i < 3; ++i)
+    builder.quick_push (simplify_gen_binary (PLUS, GET_MODE_INNER (mode),
+					     builder[i - 1], step));
+  return builder.build ();
 }
 
 /* Generate a vector of mode MODE in which element I has the value
@@ -5990,7 +5987,7 @@  gen_const_vector (machine_mode mode, int
   rtx el = const_tiny_rtx[constant][(int) inner];
   gcc_assert (el);
 
-  return gen_const_vec_duplicate_1 (mode, el);
+  return gen_const_vec_duplicate (mode, el);
 }
 
 /* Generate a vector like gen_rtx_raw_CONST_VEC, but use the zero vector when
@@ -6005,7 +6002,11 @@  gen_rtx_CONST_VECTOR (machine_mode mode,
   if (rtvec_all_equal_p (v))
     return gen_const_vec_duplicate (mode, RTVEC_ELT (v, 0));
 
-  return gen_rtx_raw_CONST_VECTOR (mode, v);
+  unsigned int nunits = GET_NUM_ELEM (v);
+  rtx_vector_builder builder (mode, nunits, 1);
+  for (unsigned int i = 0; i < nunits; ++i)
+    builder.quick_push (RTVEC_ELT (v, i));
+  return builder.build (v);
 }
 
 /* Initialise global register information required by all functions.  */
Index: gcc/config/powerpcspe/powerpcspe.c
===================================================================
--- gcc/config/powerpcspe/powerpcspe.c	2017-12-28 16:57:58.744157771 +0000
+++ gcc/config/powerpcspe/powerpcspe.c	2017-12-28 16:58:43.017987848 +0000
@@ -79,6 +79,7 @@  #define IN_TARGET_CODE 1
 #endif
 #include "case-cfn-macros.h"
 #include "ppc-auxv.h"
+#include "rtx-vector-builder.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -42581,23 +42582,24 @@  mark_swaps_for_removal (swap_web_entry *
     }
 }
 
-/* OP is either a CONST_VECTOR or an expression containing one.
+/* *OP_PTR is either a CONST_VECTOR or an expression containing one.
    Swap the first half of the vector with the second in the first
    case.  Recurse to find it in the second.  */
 static void
-swap_const_vector_halves (rtx op)
+swap_const_vector_halves (rtx *op_ptr)
 {
   int i;
+  rtx op = *op_ptr;
   enum rtx_code code = GET_CODE (op);
   if (GET_CODE (op) == CONST_VECTOR)
     {
-      int half_units = GET_MODE_NUNITS (GET_MODE (op)) / 2;
-      for (i = 0; i < half_units; ++i)
-	{
-	  rtx temp = CONST_VECTOR_ELT (op, i);
-	  CONST_VECTOR_ELT (op, i) = CONST_VECTOR_ELT (op, i + half_units);
-	  CONST_VECTOR_ELT (op, i + half_units) = temp;
-	}
+      int units = GET_MODE_NUNITS (GET_MODE (op));
+      rtx_vector_builder builder (GET_MODE (op), units, 1);
+      for (i = 0; i < units / 2; ++i)
+	builder.quick_push (CONST_VECTOR_ELT (op, i + units / 2));
+      for (i = 0; i < units / 2; ++i)
+	builder.quick_push (CONST_VECTOR_ELT (op, i));
+      *op_ptr = builder.build ();
     }
   else
     {
@@ -42605,10 +42607,10 @@  swap_const_vector_halves (rtx op)
       const char *fmt = GET_RTX_FORMAT (code);
       for (i = 0; i < GET_RTX_LENGTH (code); ++i)
 	if (fmt[i] == 'e' || fmt[i] == 'u')
-	  swap_const_vector_halves (XEXP (op, i));
+	  swap_const_vector_halves (&XEXP (op, i));
 	else if (fmt[i] == 'E')
 	  for (j = 0; j < XVECLEN (op, i); ++j)
-	    swap_const_vector_halves (XVECEXP (op, i, j));
+	    swap_const_vector_halves (&XVECEXP (op, i, j));
     }
 }
 
@@ -42900,8 +42902,7 @@  handle_special_swappables (swap_web_entr
       {
 	/* A CONST_VECTOR will only show up somewhere in the RHS of a SET.  */
 	gcc_assert (GET_CODE (body) == SET);
-	rtx rhs = SET_SRC (body);
-	swap_const_vector_halves (rhs);
+	swap_const_vector_halves (&SET_SRC (body));
 	if (dump_file)
 	  fprintf (dump_file, "Swapping constant halves in insn %d\n", i);
 	break;
Index: gcc/config/rs6000/rs6000-p8swap.c
===================================================================
--- gcc/config/rs6000/rs6000-p8swap.c	2017-12-28 16:57:58.744157771 +0000
+++ gcc/config/rs6000/rs6000-p8swap.c	2017-12-28 16:58:43.017987848 +0000
@@ -36,6 +36,7 @@  #define IN_TARGET_CODE 1
 #include "expr.h"
 #include "output.h"
 #include "tree-pass.h"
+#include "rtx-vector-builder.h"
 
 /* Analyze vector computations and remove unnecessary doubleword
    swaps (xxswapdi instructions).  This pass is performed only
@@ -931,23 +932,24 @@  mark_swaps_for_removal (swap_web_entry *
     }
 }
 
-/* OP is either a CONST_VECTOR or an expression containing one.
+/* *OP_PTR is either a CONST_VECTOR or an expression containing one.
    Swap the first half of the vector with the second in the first
    case.  Recurse to find it in the second.  */
 static void
-swap_const_vector_halves (rtx op)
+swap_const_vector_halves (rtx *op_ptr)
 {
   int i;
+  rtx op = *op_ptr;
   enum rtx_code code = GET_CODE (op);
   if (GET_CODE (op) == CONST_VECTOR)
     {
-      int half_units = GET_MODE_NUNITS (GET_MODE (op)) / 2;
-      for (i = 0; i < half_units; ++i)
-	{
-	  rtx temp = CONST_VECTOR_ELT (op, i);
-	  CONST_VECTOR_ELT (op, i) = CONST_VECTOR_ELT (op, i + half_units);
-	  CONST_VECTOR_ELT (op, i + half_units) = temp;
-	}
+      int units = GET_MODE_NUNITS (GET_MODE (op));
+      rtx_vector_builder builder (GET_MODE (op), units, 1);
+      for (i = 0; i < units / 2; ++i)
+	builder.quick_push (CONST_VECTOR_ELT (op, i + units / 2));
+      for (i = 0; i < units / 2; ++i)
+	builder.quick_push (CONST_VECTOR_ELT (op, i));
+      *op_ptr = builder.build ();
     }
   else
     {
@@ -955,10 +957,10 @@  swap_const_vector_halves (rtx op)
       const char *fmt = GET_RTX_FORMAT (code);
       for (i = 0; i < GET_RTX_LENGTH (code); ++i)
 	if (fmt[i] == 'e' || fmt[i] == 'u')
-	  swap_const_vector_halves (XEXP (op, i));
+	  swap_const_vector_halves (&XEXP (op, i));
 	else if (fmt[i] == 'E')
 	  for (j = 0; j < XVECLEN (op, i); ++j)
-	    swap_const_vector_halves (XVECEXP (op, i, j));
+	    swap_const_vector_halves (&XVECEXP (op, i, j));
     }
 }
 
@@ -1251,8 +1253,7 @@  handle_special_swappables (swap_web_entr
       {
 	/* A CONST_VECTOR will only show up somewhere in the RHS of a SET.  */
 	gcc_assert (GET_CODE (body) == SET);
-	rtx rhs = SET_SRC (body);
-	swap_const_vector_halves (rhs);
+	swap_const_vector_halves (&SET_SRC (body));
 	if (dump_file)
 	  fprintf (dump_file, "Swapping constant halves in insn %d\n", i);
 	break;