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-12-15 Michael Meissner <meissner@the-meissners.org> gcc/ * config/rs6000/rs6000-protos.h (VECTOR_128BIT_BITS): New macro. (VECTOR_128BIT_BYTES): Likewise. (VECTOR_128BIT_HALF_WORDS): Likewise. (VECTOR_128BIT_WORDS): Likewise. (VECTOR_128BIT_DOUBLE_WORDS): Likewise. (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.
This commit is contained in:
parent
71cc9b8c39
commit
c6756b3bc1
2 changed files with 281 additions and 0 deletions
|
@ -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 half 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
|
||||
|
|
|
@ -28334,6 +28334,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 a 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 target endian fashion. We need
|
||||
to arrange the order so that the bytes 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 converted the 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;
|
||||
}
|
||||
|
||||
/* Splat the constant to fill 128 bits if desired. */
|
||||
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"
|
||||
|
|
Loading…
Add table
Reference in a new issue