diff options
author | J"orn Rennecke <joern.rennecke@superh.com> | 2002-07-03 09:49:46 +0000 |
---|---|---|
committer | Joern Rennecke <amylaar@gcc.gnu.org> | 2002-07-03 10:49:46 +0100 |
commit | 34a80643d8c74d96786fa19eec8a39fc94ac10b4 (patch) | |
tree | 4e697d4885e1475c42eeedf76c38e9b4ccdff584 /gcc/simplify-rtx.c | |
parent | 032b2b29901082316175de7c7edb51c927ab06aa (diff) | |
download | gcc-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.c | 56 |
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. */ |