aboutsummaryrefslogtreecommitdiff
path: root/gcc/simplify-rtx.c
diff options
context:
space:
mode:
authorJ"orn Rennecke <joern.rennecke@superh.com>2002-07-03 09:49:46 +0000
committerJoern Rennecke <amylaar@gcc.gnu.org>2002-07-03 10:49:46 +0100
commit34a80643d8c74d96786fa19eec8a39fc94ac10b4 (patch)
tree4e697d4885e1475c42eeedf76c38e9b4ccdff584 /gcc/simplify-rtx.c
parent032b2b29901082316175de7c7edb51c927ab06aa (diff)
downloadgcc-34a80643d8c74d96786fa19eec8a39fc94ac10b4.zip
gcc-34a80643d8c74d96786fa19eec8a39fc94ac10b4.tar.gz
gcc-34a80643d8c74d96786fa19eec8a39fc94ac10b4.tar.bz2
optabs.c (expand_vector_binop): Don't store using a SUBREG smaller than UNITS_PER_WORD...
gcc: * optabs.c (expand_vector_binop): Don't store using a SUBREG smaller than UNITS_PER_WORD, unless this is little endian and the first unit in this word. Let extract_bit_field decide how to load an element. Force arguments to matching mode. (expand_vector_unop): Likewise. * simplify-rtx.c (simplify_subreg): Don't assume that all vectors consist of word_mode elements. * c-typeck.c (build_binary_op): Allow vector types for BIT_AND_EXPR, BIT_ANDTC_EXPR, BIT_IOR_EXPR and BIT_XOR_EXPR. (build_unary_op): Allow vector types for BIT_NOT_EPR. * emit-rtl.c (gen_lowpart_common): Use simplify_gen_subreg for CONST_VECTOR. * optabs.c (expand_vector_binop): Try to perform operation in smaller vector modes with same inner size. Add handling of AND, IOR and XOR. Reject expansion to inner-mode sized scalars when using OPTAB_DIRECT. Use simplify_gen_subreg on constants. (expand_vector_unop): Try to perform operation in smaller vector modes with same inner size. Add handling of one's complement. When there is no vector negate operation, try a vector subtract operation. Use simplify_gen_subreg on constants. * simplify-rtx.c (simplify_subreg): Add capability to convert vector constants into smaller vectors with same inner mode, and to integer CONST_DOUBLEs. gcc/testsuite: * gcc.c-torture/execute/simd-1.c (main): Also test &, |, ^, ~. * gcc.c-torture/execute/simd-2.c (main): Likewise. From-SVN: r55209
Diffstat (limited to 'gcc/simplify-rtx.c')
-rw-r--r--gcc/simplify-rtx.c56
1 files changed, 47 insertions, 9 deletions
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index cdc6043..63961dd 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -2271,19 +2271,57 @@ simplify_subreg (outermode, op, innermode, byte)
/* Simplify subregs of vector constants. */
if (GET_CODE (op) == CONST_VECTOR)
{
- int offset = byte / UNITS_PER_WORD;
+ int elt_size = GET_MODE_SIZE (GET_MODE_INNER (innermode));
+ int offset = byte / elt_size;
rtx elt;
- /* This shouldn't happen, but let's not do anything stupid. */
- if (GET_MODE_INNER (innermode) != outermode)
- return NULL_RTX;
-
- elt = CONST_VECTOR_ELT (op, offset);
+ if (GET_MODE_INNER (innermode) == outermode)
+ {
+ elt = CONST_VECTOR_ELT (op, offset);
- /* ?? We probably don't need this copy_rtx because constants
- can be shared. ?? */
+ /* ?? We probably don't need this copy_rtx because constants
+ can be shared. ?? */
- return copy_rtx (elt);
+ return copy_rtx (elt);
+ }
+ else if (GET_MODE_INNER (innermode) == GET_MODE_INNER (outermode)
+ && GET_MODE_SIZE (innermode) > GET_MODE_SIZE (outermode))
+ {
+ return (gen_rtx_CONST_VECTOR
+ (outermode,
+ gen_rtvec_v (GET_MODE_NUNITS (outermode),
+ &CONST_VECTOR_ELT (op, offset))));
+ }
+ else if (GET_MODE_CLASS (outermode) == MODE_INT
+ && (GET_MODE_SIZE (outermode) % elt_size == 0))
+ {
+ /* This happens when the target register size is smaller then
+ the vector mode, and we synthesize operations with vectors
+ of elements that are smaller than the register size. */
+ HOST_WIDE_INT sum = 0, high = 0;
+ unsigned n_elts = (GET_MODE_SIZE (outermode) / elt_size);
+ unsigned i = BYTES_BIG_ENDIAN ? offset : offset + n_elts - 1;
+ unsigned step = BYTES_BIG_ENDIAN ? 1 : -1;
+ int shift = BITS_PER_UNIT * elt_size;
+
+ for (; n_elts--; i += step)
+ {
+ elt = CONST_VECTOR_ELT (op, i);
+ if (GET_CODE (elt) != CONST_INT)
+ return NULL_RTX;
+ high = high << shift | sum >> (HOST_BITS_PER_WIDE_INT - shift);
+ sum = (sum << shift) + INTVAL (elt);
+ }
+ if (GET_MODE_BITSIZE (outermode) <= HOST_BITS_PER_WIDE_INT)
+ return GEN_INT (trunc_int_for_mode (sum, outermode));
+ else if (GET_MODE_BITSIZE (outermode) == 2* HOST_BITS_PER_WIDE_INT)
+ return immed_double_const (high, sum, outermode);
+ else
+ return NULL_RTX;
+ }
+ else
+ /* This shouldn't happen, but let's not do anything stupid. */
+ return NULL_RTX;
}
/* Attempt to simplify constant to non-SUBREG expression. */