Message ID | YYStWC018qK1Ta33@toto.the-meissners.org |
---|---|
State | New |
Headers | show |
Series | Add Power10 XXSPLTI* and LXVKQ instructions | expand |
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
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) + +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 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. */ + +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"