From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1005) id C7BAB3858D39; Thu, 21 Oct 2021 02:28:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C7BAB3858D39 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Michael Meissner To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/meissner/heads/work071)] Add new constant data structure. X-Act-Checkin: gcc X-Git-Author: Michael Meissner X-Git-Refname: refs/users/meissner/heads/work071 X-Git-Oldrev: c0e1470ccd169cdc4781f46f621a7c8535f4fbb2 X-Git-Newrev: 95df247a7aa149df3c9e1d7421818383005bb322 Message-Id: <20211021022813.C7BAB3858D39@sourceware.org> Date: Thu, 21 Oct 2021 02:28:13 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Oct 2021 02:28:13 -0000 https://gcc.gnu.org/g:95df247a7aa149df3c9e1d7421818383005bb322 commit 95df247a7aa149df3c9e1d7421818383005bb322 Author: Michael Meissner Date: Wed Oct 20 22:27:44 2021 -0400 Add new constant data structure. This patch provides the data structure to convert an arbitrary RTL constant (CONST_INT, CONST_DOUBLE, CONST_VECTOR, or VEC_DUPLICATE of a constant) in arry of bytes, half-words, words, and double words. The next 3 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. While the PowerPC currently is limited to 128-bit vectors, I have tried to make this code work if we ever grow the vector size. 2021-10-20 Michael Meissner gcc/ * config/rs6000/rs6000-protos.h (RS6000_CONST_*): New macros. (rs6000_const_splat): New enum type. (rs6000_const): New structure type. (constant_to_bytes): New declaration. * config/rs6000/rs6000.c (constant_integer_to_bytes): New helper function. (constant_floating_point_to_bytes): New helper function. (constant_to_bytes): New function. Diff: --- gcc/config/rs6000/rs6000-protos.h | 35 +++++ gcc/config/rs6000/rs6000.c | 266 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+) diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 14f6b313105..a3fecbb7812 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -222,6 +222,41 @@ address_is_prefixed (rtx addr, return (iform == INSN_FORM_PREFIXED_NUMERIC || iform == INSN_FORM_PCREL_LOCAL); } + +/* Functions and data structures relating to constants that are converted to + byte, half-word, word, and double-word values. All fields are kept in big + endian order. */ +#define RS6000_CONST_MAX_BITS 128 /* Largest constant size. */ +#define RS6000_CONST_MAX_BYTES (RS6000_CONST_MAX_BITS / 8) +#define RS6000_CONST_MAX_HALF_WORDS (RS6000_CONST_MAX_BITS / 16) +#define RS6000_CONST_MAX_WORDS (RS6000_CONST_MAX_BITS / 32) +#define RS6000_CONST_MAX_DOUBLE_WORDS (RS6000_CONST_MAX_BITS / 64) + +/* If the constant is small, whether we will splat the constant to fill a + vector. */ +typedef enum { + RS6000_CONST_NO_SPLAT, /* Do not splat the constant. */ + RS6000_CONST_SPLAT_16_BYTES /* Splat to fill 16-bytes. */ +} rs6000_const_splat; + +typedef struct { + /* Constant as various sized items. */ + unsigned HOST_WIDE_INT double_words[RS6000_CONST_MAX_DOUBLE_WORDS]; + unsigned int words[RS6000_CONST_MAX_WORDS]; + unsigned short half_words[RS6000_CONST_MAX_HALF_WORDS]; + unsigned char bytes[RS6000_CONST_MAX_BYTES]; + + unsigned total_size; /* Size in bytes of the constant. */ + unsigned original_size; /* Size before a possible 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? */ +} rs6000_const; + +extern bool constant_to_bytes (rtx, machine_mode, rs6000_const *, + rs6000_const_splat); #endif /* RTX_CODE */ #ifdef TREE_CODE diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index acba4d9f26c..e2f48f5a1e2 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -28587,6 +28587,272 @@ rs6000_output_addr_vec_elt (FILE *file, int value) fprintf (file, "\n"); } + +/* Copy an integer constant to the constant structure. */ + +static void +constant_integer_to_bytes (rtx op, + machine_mode mode, + size_t byte_num, + rs6000_const *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 rs6000 constant structure. */ + +static void +constant_floating_point_to_bytes (rtx op, + machine_mode mode, + size_t byte_num, + rs6000_const *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[RS6000_CONST_MAX_WORDS]; + + /* Make sure we don't overflow the real_words array and that it is + filled completely. */ + gcc_assert (bitsize <= RS6000_CONST_MAX_BITS && (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 involes floating point. */ + info->fp_constant_p = true; +} + +/* Convert an RTL constant OP with mode MODE to an internal structure INFO. + Possibly splat the constant to a larger size (SPLAT). + + 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. */ + +bool +constant_to_bytes (rtx op, + machine_mode mode, + rs6000_const *info, + rs6000_const_splat splat) +{ + /* Initialize the constant structure. */ + memset ((void *)info, 0, sizeof (rs6000_const)); + + /* Assume plain integer constants 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); + + if (size > RS6000_CONST_MAX_BYTES) + return false; + + /* Set up the bits. */ + switch (GET_CODE (op)) + { + /* Integer constants, default to double word. */ + case CONST_INT: + { + constant_integer_to_bytes (op, mode, 0, info); + 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_floating_point_to_bytes (op, mode, 0, info); + 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. */ + if (GET_MODE (op) != mode) + 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_integer_to_bytes (ele, ele_mode, byte_num, info); + else if (CONST_DOUBLE_P (ele)) + constant_floating_point_to_bytes (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. */ + if (GET_MODE (op) != mode) + 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_integer_to_bytes (ele, ele_mode, byte_num, info); + else + constant_floating_point_to_bytes (ele, ele_mode, byte_num, info); + } + + break; + } + + /* Any thing else, just return failure. */ + default: + return false; + } + + unsigned total_size = size; + + /* Possibly splat the constant to fill a vector size. */ + if (splat == RS6000_CONST_SPLAT_16_BYTES) + { + if (size < 16) + { + total_size = 16; + if ((total_size % size) != 0) + return false; + + for (size_t offset = size; offset < total_size; offset += size) + memcpy ((void *) &info->bytes[offset], + (void *) &info->bytes[0], + size); + } + } + + else if (splat != RS6000_CONST_NO_SPLAT) + return false; + + /* Remember total/original sizes. */ + info->total_size = total_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 < total_size; 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 < total_size; i += 2) + info->half_words[i / 2] = ((info->bytes[i] << 8) + | info->bytes[i + 1]); + + unsigned short first_hword = info->half_words[0]; + info->all_half_words_same = true; + for (size_t i = 1; i < total_size / 2; 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 < total_size; i += 4) + info->words[i / 4] = ((info->bytes[i] << 24) + | (info->bytes[i + 1] << 16) + | (info->bytes[i + 2] << 8) + | info->bytes[i + 3]); + + unsigned int first_word = info->words[0]; + info->all_words_same = true; + for (size_t i = 1; i < total_size / 4; i++) + if (first_word != info->words[i]) + { + info->all_words_same = false; + break; + } + + /* Pack double words together & determine if all of the double words are the + same. */ + for (size_t i = 0; i < total_size; i += 8) + { + unsigned HOST_WIDE_INT d_word = 0; + for (size_t j = 0; j < 8; j++) + d_word = (d_word << 8) | info->bytes[i + j]; + + info->double_words[i / 8] = d_word; + } + + unsigned HOST_WIDE_INT first_dword = info->double_words[0]; + info->all_double_words_same = true; + for (size_t i = 1; i < total_size / 8; i++) + if (first_dword != info->double_words[i]) + { + info->all_double_words_same = false; + break; + } + + return true; +} + + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-rs6000.h"