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.
2018-01-02 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.
From-SVN: r256102
+2018-01-02 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * 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.
+
2018-01-02 Richard Sandiford <richard.sandiford@linaro.org>
* simplify-rtx.c (simplify_const_binary_operation): Use
rtlhash.o \
rtlanal.o \
rtlhooks.o \
+ rtx-vector-builder.o \
run-rtl-passes.o \
sched-deps.o \
sched-ebb.o \
#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"
}
}
-/* 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
{
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));
}
}
{
/* 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;
#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
}
}
-/* 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
{
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));
}
}
{
/* 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;
@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})
#include "stor-layout.h"
#include "opts.h"
#include "predict.h"
+#include "rtx-vector-builder.h"
struct target_rtl default_target_rtl;
#if SWITCHABLE_TARGET
|| 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.
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;
}
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
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
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. */
/* 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.
/* 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)
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));
}
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)
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;
/* 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, ... }
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)
{
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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