[1/5] Add XXSPLTI* and LXVKQ instructions (new data structure and function)
Commit Message
Add new constant data structure.
This patch provides the data structure and function to convert a
CONST_INT, CONST_DOUBLE, CONST_VECTOR, or VEC_DUPLICATE of a constant) to
an array of bytes, half-words, words, and double words that can be loaded
into a 128-bit vector register.
The next patches will use this data structure to generate code that
generates load of the vector/floating point registers using the XXSPLTIDP,
XXSPLTIW, and LXVKQ instructions that were added in power10.
2021-11-05 Michael Meissner <meissner@the-meissners.org>
gcc/
* config/rs6000/rs6000-protos.h (VECTOR_128BIT_*): New macros.
(vec_const_128bit_type): New structure type.
(vec_const_128bit_to_bytes): New declaration.
* config/rs6000/rs6000.c (constant_int_to_128bit_vector): New
helper function.
(constant_fp_to_128bit_vector): New helper function.
(vec_const_128bit_to_bytes): New function.
---
gcc/config/rs6000/rs6000-protos.h | 28 ++++
gcc/config/rs6000/rs6000.c | 253 ++++++++++++++++++++++++++++++
2 files changed, 281 insertions(+)
Comments
On Fri, 2021-11-05 at 00:04 -0400, Michael Meissner wrote:
> Add new constant data structure.
>
> This patch provides the data structure and function to convert a
> CONST_INT, CONST_DOUBLE, CONST_VECTOR, or VEC_DUPLICATE of a constant) to
> an array of bytes, half-words, words, and double words that can be loaded
> into a 128-bit vector register.
>
> The next patches will use this data structure to generate code that
> generates load of the vector/floating point registers using the XXSPLTIDP,
> XXSPLTIW, and LXVKQ instructions that were added in power10.
>
> 2021-11-05 Michael Meissner <meissner@the-meissners.org>
>
Email here is different than the from:. No big deal either way.
> gcc/
>
> * config/rs6000/rs6000-protos.h (VECTOR_128BIT_*): New macros.
I defer to maintainers. I like to explicitly include the full macro names here so a grep later on can easily find it.
> (vec_const_128bit_type): New structure type.
> (vec_const_128bit_to_bytes): New declaration.
> * config/rs6000/rs6000.c (constant_int_to_128bit_vector): New
> helper function.
> (constant_fp_to_128bit_vector): New helper function.
> (vec_const_128bit_to_bytes): New function.
ok
> ---
> gcc/config/rs6000/rs6000-protos.h | 28 ++++
> gcc/config/rs6000/rs6000.c | 253 ++++++++++++++++++++++++++++++
> 2 files changed, 281 insertions(+)
>
> diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
> index 14f6b313105..490d6e33736 100644
> --- a/gcc/config/rs6000/rs6000-protos.h
> +++ b/gcc/config/rs6000/rs6000-protos.h
> @@ -222,6 +222,34 @@ address_is_prefixed (rtx addr,
> return (iform == INSN_FORM_PREFIXED_NUMERIC
> || iform == INSN_FORM_PCREL_LOCAL);
> }
> +
> +/* Functions and data structures relating to 128-bit constants that are
> + converted to byte, half-word, word, and double-word values. All fields are
> + kept in big endian order. We also convert scalar values to 128-bits if they
> + are going to be loaded into vector registers. */
> +#define VECTOR_128BIT_BITS 128
> +#define VECTOR_128BIT_BYTES (128 / 8)
> +#define VECTOR_128BIT_HALF_WORDS (128 / 16)
> +#define VECTOR_128BIT_WORDS (128 / 32)
> +#define VECTOR_128BIT_DOUBLE_WORDS (128 / 64)
ok
> +
> +typedef struct {
> + /* Constant as various sized items. */
> + unsigned HOST_WIDE_INT double_words[VECTOR_128BIT_DOUBLE_WORDS];
> + unsigned int words[VECTOR_128BIT_WORDS];
> + unsigned short half_words[VECTOR_128BIT_HALF_WORDS];
> + unsigned char bytes[VECTOR_128BIT_BYTES];
> +
> + unsigned original_size; /* Constant size before splat. */
> + bool fp_constant_p; /* Is the constant floating point? */
> + bool all_double_words_same; /* Are the double words all equal? */
> + bool all_words_same; /* Are the words all equal? */
> + bool all_half_words_same; /* Are the halft words all equal? */
half
> + bool all_bytes_same; /* Are the bytes all equal? */
> +} vec_const_128bit_type;
> +
ok.
> +extern bool vec_const_128bit_to_bytes (rtx, machine_mode,
> + vec_const_128bit_type *);
> #endif /* RTX_CODE */
>
> #ifdef TREE_CODE
> diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
> index 01affc7a47c..f285022294a 100644
> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -28619,6 +28619,259 @@ rs6000_output_addr_vec_elt (FILE *file, int value)
> fprintf (file, "\n");
> }
>
> +
> +/* Copy an integer constant to the vector constant structure. */
> +
Here and subsequent comments, I'd debate on whether to enhance the
comment to be explicit on the structure name being copied to/from.
(vec_const_128bit_type is easy to search for, vector or constant or
structure are not as unique)
> +static void
> +constant_int_to_128bit_vector (rtx op,
> + machine_mode mode,
> + size_t byte_num,
> + vec_const_128bit_type *info)
> +{
> + unsigned HOST_WIDE_INT uvalue = UINTVAL (op);
> + unsigned bitsize = GET_MODE_BITSIZE (mode);
> +
> + for (int shift = bitsize - 8; shift >= 0; shift -= 8)
> + info->bytes[byte_num++] = (uvalue >> shift) & 0xff;
> +}
I didn't confirm the maths, but looks OK at a glance.
> +
> +/* Copy an floating point constant to the vector constant structure. */
> +
s/an/a/
> +static void
> +constant_fp_to_128bit_vector (rtx op,
> + machine_mode mode,
> + size_t byte_num,
> + vec_const_128bit_type *info)
> +{
> + unsigned bitsize = GET_MODE_BITSIZE (mode);
> + unsigned num_words = bitsize / 32;
> + const REAL_VALUE_TYPE *rtype = CONST_DOUBLE_REAL_VALUE (op);
> + long real_words[VECTOR_128BIT_WORDS];
> +
> + /* Make sure we don't overflow the real_words array and that it is
> + filled completely. */
> + gcc_assert (num_words <= VECTOR_128BIT_WORDS && (bitsize % 32) == 0);
Not clear to me on the potential to partially fill the real_words
array.
> +
> + real_to_target (real_words, rtype, mode);
> +
> + /* Iterate over each 32-bit word in the floating point constant. The
> + real_to_target function puts out words in endian fashion. We need
Meaning host-endian fashion, or is that meant to be big-endian ?
Perhaps also rephrase or move the comment up to indicate that
real_to_target will have placed or has already placed the words in
<whatever> endian fashion.
As stated I was expecting to see a call to real_to_target() below the
comment.
The description of how real_to_target() works may be better placed
on that function over in real.c . :-)
> + to arrange so the words are written in big endian order. */
> + for (unsigned num = 0; num < num_words; num++)
> + {
> + unsigned endian_num = (BYTES_BIG_ENDIAN
> + ? num
> + : num_words - 1 - num);
> +
> + unsigned uvalue = real_words[endian_num];
> + for (int shift = 32 - 8; shift >= 0; shift -= 8)
> + info->bytes[byte_num++] = (uvalue >> shift) & 0xff;
> + }
> +
> + /* Mark that this constant involves floating point. */
> + info->fp_constant_p = true;
> +}
> +
> +/* Convert a vector constant OP with mode MODE to a vector 128-bit constant
> + structure INFO.
> +
> + Break out the constant out to bytes, half words, words, and double words.
> + Return true if we have successfully broken out a constant.
Too many outs.
> +
> + We handle CONST_INT, CONST_DOUBLE, CONST_VECTOR, and VEC_DUPLICATE of
> + constants. Integer and floating point scalar constants are splatted to fill
> + out the vector. */
> +
> +bool
> +vec_const_128bit_to_bytes (rtx op,
> + machine_mode mode,
> + vec_const_128bit_type *info)
> +{
> + /* Initialize the constant structure. */
> + memset ((void *)info, 0, sizeof (vec_const_128bit_type));
> +
> + /* Assume CONST_INTs are DImode. */
> + if (mode == VOIDmode)
> + mode = CONST_INT_P (op) ? DImode : GET_MODE (op);
> +
> + if (mode == VOIDmode)
> + return false;
> +
> + unsigned size = GET_MODE_SIZE (mode);
> + bool splat_p = false;
> +
> + if (size > VECTOR_128BIT_BYTES)
> + return false;
> +
> + /* Set up the bits. */
> + switch (GET_CODE (op))
> + {
> + /* Integer constants, default to double word. */
> + case CONST_INT:
> + {
> + constant_int_to_128bit_vector (op, mode, 0, info);
> + splat_p = true;
> + break;
> + }
> +
> + /* Floating point constants. */
> + case CONST_DOUBLE:
> + {
> + /* Fail if the floating point constant is the wrong mode. */
> + if (GET_MODE (op) != mode)
> + return false;
> +
> + /* SFmode stored as scalars are stored in DFmode format. */
> + if (mode == SFmode)
> + {
> + mode = DFmode;
> + size = GET_MODE_SIZE (DFmode);
> + }
> +
> + constant_fp_to_128bit_vector (op, mode, 0, info);
> + splat_p = true;
> + break;
> + }
> +
> + /* Vector constants, iterate over each element. On little endian
> + systems, we have to reverse the element numbers. */
> + case CONST_VECTOR:
> + {
> + /* Fail if the vector constant is the wrong mode or size. */
> + if (GET_MODE (op) != mode
> + || GET_MODE_SIZE (mode) != VECTOR_128BIT_BYTES)
> + return false;
> +
> + machine_mode ele_mode = GET_MODE_INNER (mode);
> + size_t ele_size = GET_MODE_SIZE (ele_mode);
> + size_t nunits = GET_MODE_NUNITS (mode);
> +
> + for (size_t num = 0; num < nunits; num++)
> + {
> + rtx ele = CONST_VECTOR_ELT (op, num);
> + size_t byte_num = (BYTES_BIG_ENDIAN
> + ? num
> + : nunits - 1 - num) * ele_size;
> +
> + if (CONST_INT_P (ele))
> + constant_int_to_128bit_vector (ele, ele_mode, byte_num, info);
> + else if (CONST_DOUBLE_P (ele))
> + constant_fp_to_128bit_vector (ele, ele_mode, byte_num, info);
> + else
> + return false;
> + }
> +
> + break;
> + }
> +
> + /* Treat VEC_DUPLICATE of a constant just like a vector constant.
> + Since we are duplicating the element, we don't have to worry about
> + endian issues. */
> + case VEC_DUPLICATE:
> + {
> + /* Fail if the vector duplicate is the wrong mode or size. */
> + if (GET_MODE (op) != mode
> + || GET_MODE_SIZE (mode) != VECTOR_128BIT_BYTES)
> + return false;
> +
> + machine_mode ele_mode = GET_MODE_INNER (mode);
> + size_t ele_size = GET_MODE_SIZE (ele_mode);
> + rtx ele = XEXP (op, 0);
> + size_t nunits = GET_MODE_NUNITS (mode);
> +
> + if (!CONST_INT_P (ele) && !CONST_DOUBLE_P (ele))
> + return false;
> +
> + for (size_t num = 0; num < nunits; num++)
> + {
> + size_t byte_num = num * ele_size;
> +
> + if (CONST_INT_P (ele))
> + constant_int_to_128bit_vector (ele, ele_mode, byte_num, info);
> + else
> + constant_fp_to_128bit_vector (ele, ele_mode, byte_num, info);
> + }
> +
> + break;
> + }
> +
> + /* Any thing else, just return failure. */
> + default:
> + return false;
> + }
Seems OK.
> +
> + /* Possibly splat the constant to fill a vector size. */
Suggest "Splat the constant to fill a vector size if ..."
> + if (splat_p && size < VECTOR_128BIT_BYTES)
> + {
> + if ((VECTOR_128BIT_BYTES % size) != 0)
> + return false;
> +
> + for (size_t offset = size;
> + offset < VECTOR_128BIT_BYTES;
> + offset += size)
> + memcpy ((void *) &info->bytes[offset],
> + (void *) &info->bytes[0],
> + size);
> + }
> +
> + /* Remember original size. */
> + info->original_size = size;
> +
> + /* Determine if the bytes are all the same. */
> + unsigned char first_byte = info->bytes[0];
> + info->all_bytes_same = true;
> + for (size_t i = 1; i < VECTOR_128BIT_BYTES; i++)
> + if (first_byte != info->bytes[i])
> + {
> + info->all_bytes_same = false;
> + break;
> + }
> +
> + /* Pack half words together & determine if all of the half words are the
> + same. */
> + for (size_t i = 0; i < VECTOR_128BIT_HALF_WORDS; i++)
> + info->half_words[i] = ((info->bytes[i * 2] << 8)
> + | info->bytes[(i * 2) + 1]);
> +
> + unsigned short first_hword = info->half_words[0];
> + info->all_half_words_same = true;
> + for (size_t i = 1; i < VECTOR_128BIT_HALF_WORDS; i++)
> + if (first_hword != info->half_words[i])
> + {
> + info->all_half_words_same = false;
> + break;
> + }
ok
> +
> + /* Pack words together & determine if all of the words are the same. */
> + for (size_t i = 0; i < VECTOR_128BIT_WORDS; i++)
> + info->words[i] = ((info->bytes[i * 4] << 24)
> + | (info->bytes[(i * 4) + 1] << 16)
> + | (info->bytes[(i * 4) + 2] << 8)
> + | info->bytes[(i * 4) + 3]);
> +
> + info->all_words_same
> + = (info->words[0] == info->words[1]
> + && info->words[0] == info->words[1]
> + && info->words[0] == info->words[2]
> + && info->words[0] == info->words[3]);
> +
> + /* Pack double words together & determine if all of the double words are the
> + same. */
> + for (size_t i = 0; i < VECTOR_128BIT_DOUBLE_WORDS; i++)
> + {
> + unsigned HOST_WIDE_INT d_word = 0;
> + for (size_t j = 0; j < 8; j++)
> + d_word = (d_word << 8) | info->bytes[(i * 8) + j];
> +
> + info->double_words[i] = d_word;
> + }
> +
> + info->all_double_words_same
> + = (info->double_words[0] == info->double_words[1]);
> +
> + return true;
> +}
> +
ok.
> struct gcc_target targetm = TARGET_INITIALIZER;
>
> #include "gt-rs6000.h"
> --
> 2.31.1
>
>
On Fri, Nov 05, 2021 at 12:01:43PM -0500, will schmidt wrote:
> On Fri, 2021-11-05 at 00:04 -0400, Michael Meissner wrote:
> > Add new constant data structure.
> >
> > This patch provides the data structure and function to convert a
> > CONST_INT, CONST_DOUBLE, CONST_VECTOR, or VEC_DUPLICATE of a constant) to
> > an array of bytes, half-words, words, and double words that can be loaded
> > into a 128-bit vector register.
> >
> > The next patches will use this data structure to generate code that
> > generates load of the vector/floating point registers using the XXSPLTIDP,
> > XXSPLTIW, and LXVKQ instructions that were added in power10.
> >
> > 2021-11-05 Michael Meissner <meissner@the-meissners.org>
> >
Whoops, it should be meissner@linux.ibm.com.
> comment to be explicit on the structure name being copied to/from.
> (vec_const_128bit_type is easy to search for, vector or constant or
> structure are not as unique)
Yes, the original name was more generic (rs6000_const). Originally it could
potentially handle vector constants that were greater than 128-bits if we ever
have support for larger vectors. But I thought that extra generallity hindered
the code (since you had to check whether the size was exactly 128-bits, etc.).
So I made the data structure tailored to the problem at hand.
> > +
> > +/* Copy an floating point constant to the vector constant structure. */
> > +
>
> s/an/a/
Ok.
> > +static void
> > +constant_fp_to_128bit_vector (rtx op,
> > + machine_mode mode,
> > + size_t byte_num,
> > + vec_const_128bit_type *info)
> > +{
> > + unsigned bitsize = GET_MODE_BITSIZE (mode);
> > + unsigned num_words = bitsize / 32;
> > + const REAL_VALUE_TYPE *rtype = CONST_DOUBLE_REAL_VALUE (op);
> > + long real_words[VECTOR_128BIT_WORDS];
> > +
> > + /* Make sure we don't overflow the real_words array and that it is
> > + filled completely. */
> > + gcc_assert (num_words <= VECTOR_128BIT_WORDS && (bitsize % 32) == 0);
>
> Not clear to me on the potential to partially fill the real_words
> array.
At the moment we don't support a 16-bit floating point type in the compiler
(the Power10 has limited 16-bit floating point support, but we don't make a
special type for it). If/when we add the 16-bit floating point, we will
possibly need to revisit this.
> > +
> > + real_to_target (real_words, rtype, mode);
> > +
> > + /* Iterate over each 32-bit word in the floating point constant. The
> > + real_to_target function puts out words in endian fashion. We need
>
> Meaning host-endian fashion, or is that meant to be big-endian ?
Real_to_target puts out the 32-bit values in endian fashion. This data
structure wants to hold everything in big endian fashion to make checking
things simpler.
> Perhaps also rephrase or move the comment up to indicate that
> real_to_target will have placed or has already placed the words in
> <whatever> endian fashion.
> As stated I was expecting to see a call to real_to_target() below the
> comment.
Yes, I probably should move the real_to_target call after the comment.
> > +
> > + /* Possibly splat the constant to fill a vector size. */
>
>
> Suggest "Splat the constant to fill a vector size if ..."
Ok.
Ping patch.
| Date: Fri, 5 Nov 2021 00:04:40 -0400
| Subject: [PATCH 1/5] Add XXSPLTI* and LXVKQ instructions (new data structure and function)
| Message-ID: <YYStWC018qK1Ta33@toto.the-meissners.org>
Ping patch.
| Date: Fri, 5 Nov 2021 00:04:40 -0400
| From: Michael Meissner <meissner@linux.ibm.com>
| Subject: [PATCH 1/5] Add XXSPLTI* and LXVKQ instructions (new data structure and function)
| Message-ID: <YYStWC018qK1Ta33@toto.the-meissners.org>
Note, I will on-line until December 20th, and then I won't be on-line until January.
On Fri, Nov 5, 2021 at 2:13 PM Michael Meissner <meissner@linux.ibm.com> wrote:
>
> On Fri, Nov 05, 2021 at 12:01:43PM -0500, will schmidt wrote:
> > On Fri, 2021-11-05 at 00:04 -0400, Michael Meissner wrote:
> > > Add new constant data structure.
> > >
> > > This patch provides the data structure and function to convert a
> > > CONST_INT, CONST_DOUBLE, CONST_VECTOR, or VEC_DUPLICATE of a constant) to
> > > an array of bytes, half-words, words, and double words that can be loaded
> > > into a 128-bit vector register.
> > >
> > > The next patches will use this data structure to generate code that
> > > generates load of the vector/floating point registers using the XXSPLTIDP,
> > > XXSPLTIW, and LXVKQ instructions that were added in power10.
> > >
> > > 2021-11-05 Michael Meissner <meissner@the-meissners.org>
> > >
>
> Whoops, it should be meissner@linux.ibm.com.
>
> > comment to be explicit on the structure name being copied to/from.
> > (vec_const_128bit_type is easy to search for, vector or constant or
> > structure are not as unique)
>
> Yes, the original name was more generic (rs6000_const). Originally it could
> potentially handle vector constants that were greater than 128-bits if we ever
> have support for larger vectors. But I thought that extra generallity hindered
> the code (since you had to check whether the size was exactly 128-bits, etc.).
> So I made the data structure tailored to the problem at hand.
>
> > > +
> > > +/* Copy an floating point constant to the vector constant structure. */
> > > +
> >
> > s/an/a/
>
> Ok.
>
> > > +static void
> > > +constant_fp_to_128bit_vector (rtx op,
> > > + machine_mode mode,
> > > + size_t byte_num,
> > > + vec_const_128bit_type *info)
> > > +{
> > > + unsigned bitsize = GET_MODE_BITSIZE (mode);
> > > + unsigned num_words = bitsize / 32;
> > > + const REAL_VALUE_TYPE *rtype = CONST_DOUBLE_REAL_VALUE (op);
> > > + long real_words[VECTOR_128BIT_WORDS];
> > > +
> > > + /* Make sure we don't overflow the real_words array and that it is
> > > + filled completely. */
> > > + gcc_assert (num_words <= VECTOR_128BIT_WORDS && (bitsize % 32) == 0);
> >
> > Not clear to me on the potential to partially fill the real_words
> > array.
>
> At the moment we don't support a 16-bit floating point type in the compiler
> (the Power10 has limited 16-bit floating point support, but we don't make a
> special type for it). If/when we add the 16-bit floating point, we will
> possibly need to revisit this.
>
> > > +
> > > + real_to_target (real_words, rtype, mode);
> > > +
> > > + /* Iterate over each 32-bit word in the floating point constant. The
> > > + real_to_target function puts out words in endian fashion. We need
> >
> > Meaning host-endian fashion, or is that meant to be big-endian ?
>
> Real_to_target puts out the 32-bit values in endian fashion. This data
> structure wants to hold everything in big endian fashion to make checking
> things simpler.
>
> > Perhaps also rephrase or move the comment up to indicate that
> > real_to_target will have placed or has already placed the words in
> > <whatever> endian fashion.
> > As stated I was expecting to see a call to real_to_target() below the
> > comment.
>
> Yes, I probably should move the real_to_target call after the comment.
>
> > > +
> > > + /* Possibly splat the constant to fill a vector size. */
> >
> >
> > Suggest "Splat the constant to fill a vector size if ..."
>
> Ok.
Okay.
Thanks, David
@@ -222,6 +222,34 @@ address_is_prefixed (rtx addr,
return (iform == INSN_FORM_PREFIXED_NUMERIC
|| iform == INSN_FORM_PCREL_LOCAL);
}
+
+/* Functions and data structures relating to 128-bit constants that are
+ converted to byte, half-word, word, and double-word values. All fields are
+ kept in big endian order. We also convert scalar values to 128-bits if they
+ are going to be loaded into vector registers. */
+#define VECTOR_128BIT_BITS 128
+#define VECTOR_128BIT_BYTES (128 / 8)
+#define VECTOR_128BIT_HALF_WORDS (128 / 16)
+#define VECTOR_128BIT_WORDS (128 / 32)
+#define VECTOR_128BIT_DOUBLE_WORDS (128 / 64)
+
+typedef struct {
+ /* Constant as various sized items. */
+ unsigned HOST_WIDE_INT double_words[VECTOR_128BIT_DOUBLE_WORDS];
+ unsigned int words[VECTOR_128BIT_WORDS];
+ unsigned short half_words[VECTOR_128BIT_HALF_WORDS];
+ unsigned char bytes[VECTOR_128BIT_BYTES];
+
+ unsigned original_size; /* Constant size before splat. */
+ bool fp_constant_p; /* Is the constant floating point? */
+ bool all_double_words_same; /* Are the double words all equal? */
+ bool all_words_same; /* Are the words all equal? */
+ bool all_half_words_same; /* Are the halft words all equal? */
+ bool all_bytes_same; /* Are the bytes all equal? */
+} vec_const_128bit_type;
+
+extern bool vec_const_128bit_to_bytes (rtx, machine_mode,
+ vec_const_128bit_type *);
#endif /* RTX_CODE */
#ifdef TREE_CODE
@@ -28619,6 +28619,259 @@ rs6000_output_addr_vec_elt (FILE *file, int value)
fprintf (file, "\n");
}
+
+/* Copy an integer constant to the vector constant structure. */
+
+static void
+constant_int_to_128bit_vector (rtx op,
+ machine_mode mode,
+ size_t byte_num,
+ vec_const_128bit_type *info)
+{
+ unsigned HOST_WIDE_INT uvalue = UINTVAL (op);
+ unsigned bitsize = GET_MODE_BITSIZE (mode);
+
+ for (int shift = bitsize - 8; shift >= 0; shift -= 8)
+ info->bytes[byte_num++] = (uvalue >> shift) & 0xff;
+}
+
+/* Copy an floating point constant to the vector constant structure. */
+
+static void
+constant_fp_to_128bit_vector (rtx op,
+ machine_mode mode,
+ size_t byte_num,
+ vec_const_128bit_type *info)
+{
+ unsigned bitsize = GET_MODE_BITSIZE (mode);
+ unsigned num_words = bitsize / 32;
+ const REAL_VALUE_TYPE *rtype = CONST_DOUBLE_REAL_VALUE (op);
+ long real_words[VECTOR_128BIT_WORDS];
+
+ /* Make sure we don't overflow the real_words array and that it is
+ filled completely. */
+ gcc_assert (num_words <= VECTOR_128BIT_WORDS && (bitsize % 32) == 0);
+
+ real_to_target (real_words, rtype, mode);
+
+ /* Iterate over each 32-bit word in the floating point constant. The
+ real_to_target function puts out words in endian fashion. We need
+ to arrange so the words are written in big endian order. */
+ for (unsigned num = 0; num < num_words; num++)
+ {
+ unsigned endian_num = (BYTES_BIG_ENDIAN
+ ? num
+ : num_words - 1 - num);
+
+ unsigned uvalue = real_words[endian_num];
+ for (int shift = 32 - 8; shift >= 0; shift -= 8)
+ info->bytes[byte_num++] = (uvalue >> shift) & 0xff;
+ }
+
+ /* Mark that this constant involves floating point. */
+ info->fp_constant_p = true;
+}
+
+/* Convert a vector constant OP with mode MODE to a vector 128-bit constant
+ structure INFO.
+
+ Break out the constant out to bytes, half words, words, and double words.
+ Return true if we have successfully broken out a constant.
+
+ We handle CONST_INT, CONST_DOUBLE, CONST_VECTOR, and VEC_DUPLICATE of
+ constants. Integer and floating point scalar constants are splatted to fill
+ out the vector. */
+
+bool
+vec_const_128bit_to_bytes (rtx op,
+ machine_mode mode,
+ vec_const_128bit_type *info)
+{
+ /* Initialize the constant structure. */
+ memset ((void *)info, 0, sizeof (vec_const_128bit_type));
+
+ /* Assume CONST_INTs are DImode. */
+ if (mode == VOIDmode)
+ mode = CONST_INT_P (op) ? DImode : GET_MODE (op);
+
+ if (mode == VOIDmode)
+ return false;
+
+ unsigned size = GET_MODE_SIZE (mode);
+ bool splat_p = false;
+
+ if (size > VECTOR_128BIT_BYTES)
+ return false;
+
+ /* Set up the bits. */
+ switch (GET_CODE (op))
+ {
+ /* Integer constants, default to double word. */
+ case CONST_INT:
+ {
+ constant_int_to_128bit_vector (op, mode, 0, info);
+ splat_p = true;
+ break;
+ }
+
+ /* Floating point constants. */
+ case CONST_DOUBLE:
+ {
+ /* Fail if the floating point constant is the wrong mode. */
+ if (GET_MODE (op) != mode)
+ return false;
+
+ /* SFmode stored as scalars are stored in DFmode format. */
+ if (mode == SFmode)
+ {
+ mode = DFmode;
+ size = GET_MODE_SIZE (DFmode);
+ }
+
+ constant_fp_to_128bit_vector (op, mode, 0, info);
+ splat_p = true;
+ break;
+ }
+
+ /* Vector constants, iterate over each element. On little endian
+ systems, we have to reverse the element numbers. */
+ case CONST_VECTOR:
+ {
+ /* Fail if the vector constant is the wrong mode or size. */
+ if (GET_MODE (op) != mode
+ || GET_MODE_SIZE (mode) != VECTOR_128BIT_BYTES)
+ return false;
+
+ machine_mode ele_mode = GET_MODE_INNER (mode);
+ size_t ele_size = GET_MODE_SIZE (ele_mode);
+ size_t nunits = GET_MODE_NUNITS (mode);
+
+ for (size_t num = 0; num < nunits; num++)
+ {
+ rtx ele = CONST_VECTOR_ELT (op, num);
+ size_t byte_num = (BYTES_BIG_ENDIAN
+ ? num
+ : nunits - 1 - num) * ele_size;
+
+ if (CONST_INT_P (ele))
+ constant_int_to_128bit_vector (ele, ele_mode, byte_num, info);
+ else if (CONST_DOUBLE_P (ele))
+ constant_fp_to_128bit_vector (ele, ele_mode, byte_num, info);
+ else
+ return false;
+ }
+
+ break;
+ }
+
+ /* Treat VEC_DUPLICATE of a constant just like a vector constant.
+ Since we are duplicating the element, we don't have to worry about
+ endian issues. */
+ case VEC_DUPLICATE:
+ {
+ /* Fail if the vector duplicate is the wrong mode or size. */
+ if (GET_MODE (op) != mode
+ || GET_MODE_SIZE (mode) != VECTOR_128BIT_BYTES)
+ return false;
+
+ machine_mode ele_mode = GET_MODE_INNER (mode);
+ size_t ele_size = GET_MODE_SIZE (ele_mode);
+ rtx ele = XEXP (op, 0);
+ size_t nunits = GET_MODE_NUNITS (mode);
+
+ if (!CONST_INT_P (ele) && !CONST_DOUBLE_P (ele))
+ return false;
+
+ for (size_t num = 0; num < nunits; num++)
+ {
+ size_t byte_num = num * ele_size;
+
+ if (CONST_INT_P (ele))
+ constant_int_to_128bit_vector (ele, ele_mode, byte_num, info);
+ else
+ constant_fp_to_128bit_vector (ele, ele_mode, byte_num, info);
+ }
+
+ break;
+ }
+
+ /* Any thing else, just return failure. */
+ default:
+ return false;
+ }
+
+ /* Possibly splat the constant to fill a vector size. */
+ if (splat_p && size < VECTOR_128BIT_BYTES)
+ {
+ if ((VECTOR_128BIT_BYTES % size) != 0)
+ return false;
+
+ for (size_t offset = size;
+ offset < VECTOR_128BIT_BYTES;
+ offset += size)
+ memcpy ((void *) &info->bytes[offset],
+ (void *) &info->bytes[0],
+ size);
+ }
+
+ /* Remember original size. */
+ info->original_size = size;
+
+ /* Determine if the bytes are all the same. */
+ unsigned char first_byte = info->bytes[0];
+ info->all_bytes_same = true;
+ for (size_t i = 1; i < VECTOR_128BIT_BYTES; i++)
+ if (first_byte != info->bytes[i])
+ {
+ info->all_bytes_same = false;
+ break;
+ }
+
+ /* Pack half words together & determine if all of the half words are the
+ same. */
+ for (size_t i = 0; i < VECTOR_128BIT_HALF_WORDS; i++)
+ info->half_words[i] = ((info->bytes[i * 2] << 8)
+ | info->bytes[(i * 2) + 1]);
+
+ unsigned short first_hword = info->half_words[0];
+ info->all_half_words_same = true;
+ for (size_t i = 1; i < VECTOR_128BIT_HALF_WORDS; i++)
+ if (first_hword != info->half_words[i])
+ {
+ info->all_half_words_same = false;
+ break;
+ }
+
+ /* Pack words together & determine if all of the words are the same. */
+ for (size_t i = 0; i < VECTOR_128BIT_WORDS; i++)
+ info->words[i] = ((info->bytes[i * 4] << 24)
+ | (info->bytes[(i * 4) + 1] << 16)
+ | (info->bytes[(i * 4) + 2] << 8)
+ | info->bytes[(i * 4) + 3]);
+
+ info->all_words_same
+ = (info->words[0] == info->words[1]
+ && info->words[0] == info->words[1]
+ && info->words[0] == info->words[2]
+ && info->words[0] == info->words[3]);
+
+ /* Pack double words together & determine if all of the double words are the
+ same. */
+ for (size_t i = 0; i < VECTOR_128BIT_DOUBLE_WORDS; i++)
+ {
+ unsigned HOST_WIDE_INT d_word = 0;
+ for (size_t j = 0; j < 8; j++)
+ d_word = (d_word << 8) | info->bytes[(i * 8) + j];
+
+ info->double_words[i] = d_word;
+ }
+
+ info->all_double_words_same
+ = (info->double_words[0] == info->double_words[1]);
+
+ return true;
+}
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-rs6000.h"