Message ID | 87shbuh8y9.fsf@linaro.org |
---|---|
State | New |
Headers | show |
Series | Use new vector constant encoding for CONST_VECTOR | expand |
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;
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;