aboutsummaryrefslogtreecommitdiff
path: root/gcc/simplify-rtx.c
diff options
context:
space:
mode:
authorUros Bizjak <uros@gcc.gnu.org>2007-08-28 11:52:06 +0200
committerUros Bizjak <uros@gcc.gnu.org>2007-08-28 11:52:06 +0200
commit7f97f938a70df00a44ad2cadc2bc5381e7ea27fa (patch)
tree9fabd68cfa56fff4c597b8d11980be9b00eeff43 /gcc/simplify-rtx.c
parent0b738568dad569012c12839d57721939ac8ef3f5 (diff)
downloadgcc-7f97f938a70df00a44ad2cadc2bc5381e7ea27fa.zip
gcc-7f97f938a70df00a44ad2cadc2bc5381e7ea27fa.tar.gz
gcc-7f97f938a70df00a44ad2cadc2bc5381e7ea27fa.tar.bz2
re PR target/32661 (__builtin_ia32_vec_ext suboptimal for pointer/ref args)
PR target/32661 * simplify-rtx.c (simplify_binary_operation_1) [VEC_SELECT]: Simplify nested VEC_SELECT (with optional VEC_CONCAT operator as operand) when top VEC_SELECT extracts scalar element. * config/i386/sse.md (*vec_extract_v4si_mem): New. (*vec_extract_v4sf_mem): Ditto. testsuite/ChangeLog: PR target/32661 * gcc.target/i386/pr32661.c: New test. From-SVN: r127857
Diffstat (limited to 'gcc/simplify-rtx.c')
-rw-r--r--gcc/simplify-rtx.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 97c4d93..3271a86 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -2659,6 +2659,85 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
if (GET_CODE (trueop0) == CONST_VECTOR)
return CONST_VECTOR_ELT (trueop0, INTVAL (XVECEXP
(trueop1, 0, 0)));
+
+ /* Extract a scalar element from a nested VEC_SELECT expression
+ (with optional nested VEC_CONCAT expression). Some targets
+ (i386) extract scalar element from a vector using chain of
+ nested VEC_SELECT expressions. When input operand is a memory
+ operand, this operation can be simplified to a simple scalar
+ load from an offseted memory address. */
+ if (GET_CODE (trueop0) == VEC_SELECT)
+ {
+ rtx op0 = XEXP (trueop0, 0);
+ rtx op1 = XEXP (trueop0, 1);
+
+ enum machine_mode opmode = GET_MODE (op0);
+ int elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
+ int n_elts = GET_MODE_SIZE (opmode) / elt_size;
+
+ int i = INTVAL (XVECEXP (trueop1, 0, 0));
+ int elem;
+
+ rtvec vec;
+ rtx tmp_op, tmp;
+
+ gcc_assert (GET_CODE (op1) == PARALLEL);
+ gcc_assert (i < n_elts);
+
+ /* Select element, pointed by nested selector. */
+ elem = INTVAL (CONST_VECTOR_ELT (op1, i));
+
+ /* Handle the case when nested VEC_SELECT wraps VEC_CONCAT. */
+ if (GET_CODE (op0) == VEC_CONCAT)
+ {
+ rtx op00 = XEXP (op0, 0);
+ rtx op01 = XEXP (op0, 1);
+
+ enum machine_mode mode00, mode01;
+ int n_elts00, n_elts01;
+
+ mode00 = GET_MODE (op00);
+ mode01 = GET_MODE (op01);
+
+ /* Find out number of elements of each operand. */
+ if (VECTOR_MODE_P (mode00))
+ {
+ elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode00));
+ n_elts00 = GET_MODE_SIZE (mode00) / elt_size;
+ }
+ else
+ n_elts00 = 1;
+
+ if (VECTOR_MODE_P (mode01))
+ {
+ elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode01));
+ n_elts01 = GET_MODE_SIZE (mode01) / elt_size;
+ }
+ else
+ n_elts01 = 1;
+
+ gcc_assert (n_elts == n_elts00 + n_elts01);
+
+ /* Select correct operand of VEC_CONCAT
+ and adjust selector. */
+ if (elem < n_elts01)
+ tmp_op = op00;
+ else
+ {
+ tmp_op = op01;
+ elem -= n_elts00;
+ }
+ }
+ else
+ tmp_op = op0;
+
+ vec = rtvec_alloc (1);
+ RTVEC_ELT (vec, 0) = GEN_INT (elem);
+
+ tmp = gen_rtx_fmt_ee (code, mode,
+ tmp_op, gen_rtx_PARALLEL (VOIDmode, vec));
+ return tmp;
+ }
}
else
{