aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2004-01-01 15:13:44 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2004-01-01 14:13:44 +0000
commit997404de62431a850da6b05e228614a004549705 (patch)
tree366fcb1b6390ba0ac365092bc3e6aee1326879fc /gcc
parentb684a3df8e33898816611f1cefbd0068ca22beca (diff)
downloadgcc-997404de62431a850da6b05e228614a004549705.zip
gcc-997404de62431a850da6b05e228614a004549705.tar.gz
gcc-997404de62431a850da6b05e228614a004549705.tar.bz2
expmed.c (store_bit_field, [...]): Use new named patterns
* expmed.c (store_bit_field, extract_bit_field): Use new named patterns * expr.c (store_constructor): Use vec_init pattern. * genopinit.c (optabs): Initailize vec_set/vec_extract/vec_init. * optabs.h (optab_index): ADD OTI_vec_set/OTI_vec_extract/OTI_vec_init (vec_set_optab, vec_extract_optab, vec_init_optab): New. * i386.md (vec_setv2df, vec_extractv2df, vec_setv4sf, vec_extractv4sf): New patterns. (sse2_unpc?pd): Fix pattern. (sse2_movlpd): Kill. (sse2_movsd): Deal with movlpd too. * i386.c (ix86_expand_builtin): Use sse2_movsd instead of sse2_movlpd. (ix86_expand_vector_init): New. * emmintrin.h (__mm_set_pd, __mm_set_ps): Use vector extensions. * md.texi (vec_set, vec_extract): Document From-SVN: r75304
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/config/i386/emmintrin.h10
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.c92
-rw-r--r--gcc/config/i386/i386.md198
-rw-r--r--gcc/config/i386/xmmintrin.h15
-rw-r--r--gcc/expmed.c103
-rw-r--r--gcc/expr.c51
-rw-r--r--gcc/genopinit.c5
-rw-r--r--gcc/optabs.c3
-rw-r--r--gcc/optabs.h11
11 files changed, 455 insertions, 51 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9db27a7..2271495 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2004-01-01 Jan Hubicka <jh@suse.cz>
+
+ * expmed.c (store_bit_field, extract_bit_field): Use new named patterns
+ * expr.c (store_constructor): Use vec_init pattern.
+ * genopinit.c (optabs): Initailize vec_set/vec_extract/vec_init.
+ * optabs.h (optab_index): ADD OTI_vec_set/OTI_vec_extract/OTI_vec_init
+ (vec_set_optab, vec_extract_optab, vec_init_optab): New.
+ * i386.md (vec_setv2df, vec_extractv2df, vec_setv4sf, vec_extractv4sf):
+ New patterns.
+ (sse2_unpc?pd): Fix pattern.
+ (sse2_movlpd): Kill.
+ (sse2_movsd): Deal with movlpd too.
+ * i386.c (ix86_expand_builtin): Use sse2_movsd instead of sse2_movlpd.
+ (ix86_expand_vector_init): New.
+ * emmintrin.h (__mm_set_pd, __mm_set_ps): Use vector extensions.
+ * md.texi (vec_set, vec_extract): Document
+
2003-12-31 Jan Hubicka <jh@suse.cz>
PR opt/13473
diff --git a/gcc/config/i386/emmintrin.h b/gcc/config/i386/emmintrin.h
index 3618c2b..a7dbc67 100644
--- a/gcc/config/i386/emmintrin.h
+++ b/gcc/config/i386/emmintrin.h
@@ -115,15 +115,7 @@ _mm_set_pd1 (double __F)
static __inline __m128d
_mm_set_pd (double __Z, double __Y)
{
- union {
- double __a[2];
- __m128d __v;
- } __u;
-
- __u.__a[0] = __Y;
- __u.__a[1] = __Z;
-
- return __u.__v;
+ return (__v2df) {__Y, __Z};
}
/* Create the vector [Y Z]. */
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 66817c8..cc04a68 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -217,6 +217,7 @@ extern int x86_field_alignment (tree, int);
extern rtx ix86_tls_get_addr (void);
extern bool ix86_must_pass_in_stack (enum machine_mode mode, tree);
+extern void ix86_expand_vector_init (rtx, rtx);
/* In winnt.c */
extern int i386_pe_dllexport_name_p (const char *);
extern int i386_pe_dllimport_name_p (const char *);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 2762f63..0b904b1 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -14075,7 +14075,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
icode = (fcode == IX86_BUILTIN_LOADHPS ? CODE_FOR_sse_movhps
: fcode == IX86_BUILTIN_LOADLPS ? CODE_FOR_sse_movlps
: fcode == IX86_BUILTIN_LOADHPD ? CODE_FOR_sse2_movhpd
- : CODE_FOR_sse2_movlpd);
+ : CODE_FOR_sse2_movsd);
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
@@ -14104,7 +14104,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
icode = (fcode == IX86_BUILTIN_STOREHPS ? CODE_FOR_sse_movhps
: fcode == IX86_BUILTIN_STORELPS ? CODE_FOR_sse_movlps
: fcode == IX86_BUILTIN_STOREHPD ? CODE_FOR_sse2_movhpd
- : CODE_FOR_sse2_movlpd);
+ : CODE_FOR_sse2_movsd);
arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist));
op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
@@ -15784,4 +15784,92 @@ ix86_must_pass_in_stack (enum machine_mode mode, tree type)
return (!TARGET_64BIT && type && mode == TImode);
}
+/* Initialize vector TARGET via VALS. */
+void
+ix86_expand_vector_init (rtx target, rtx vals)
+{
+ enum machine_mode mode = GET_MODE (target);
+ int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
+ int n_elts = (GET_MODE_SIZE (mode) / elt_size);
+ int i;
+
+ for (i = n_elts - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (vals, 0, i)) != CONST_INT
+ && GET_CODE (XVECEXP (vals, 0, i)) != CONST_DOUBLE)
+ break;
+
+ /* Few special cases first...
+ ... constants are best loaded from constant pool. */
+ if (i < 0)
+ {
+ emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+ return;
+ }
+
+ /* ... values where only first field is non-constant are best loaded
+ from the pool and overwriten via move later. */
+ if (!i)
+ {
+ rtx op = simplify_gen_subreg (mode, XVECEXP (vals, 0, 0),
+ GET_MODE_INNER (mode), 0);
+
+ op = force_reg (mode, op);
+ XVECEXP (vals, 0, 0) = CONST0_RTX (GET_MODE_INNER (mode));
+ emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+ switch (GET_MODE (target))
+ {
+ case V2DFmode:
+ emit_insn (gen_sse2_movsd (target, target, op));
+ break;
+ case V4SFmode:
+ emit_insn (gen_sse_movss (target, target, op));
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+ /* And the busy sequence doing rotations. */
+ switch (GET_MODE (target))
+ {
+ case V2DFmode:
+ {
+ rtx vecop0 =
+ simplify_gen_subreg (V2DFmode, XVECEXP (vals, 0, 0), DFmode, 0);
+ rtx vecop1 =
+ simplify_gen_subreg (V2DFmode, XVECEXP (vals, 0, 1), DFmode, 0);
+
+ vecop0 = force_reg (V2DFmode, vecop0);
+ vecop1 = force_reg (V2DFmode, vecop1);
+ emit_insn (gen_sse2_unpcklpd (target, vecop0, vecop1));
+ }
+ break;
+ case V4SFmode:
+ {
+ rtx vecop0 =
+ simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 0), SFmode, 0);
+ rtx vecop1 =
+ simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 1), SFmode, 0);
+ rtx vecop2 =
+ simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 2), SFmode, 0);
+ rtx vecop3 =
+ simplify_gen_subreg (V4SFmode, XVECEXP (vals, 0, 3), SFmode, 0);
+ rtx tmp1 = gen_reg_rtx (V4SFmode);
+ rtx tmp2 = gen_reg_rtx (V4SFmode);
+
+ vecop0 = force_reg (V4SFmode, vecop0);
+ vecop1 = force_reg (V4SFmode, vecop1);
+ vecop2 = force_reg (V4SFmode, vecop2);
+ vecop3 = force_reg (V4SFmode, vecop3);
+ emit_insn (gen_sse_unpcklps (tmp1, vecop1, vecop3));
+ emit_insn (gen_sse_unpcklps (tmp2, vecop0, vecop2));
+ emit_insn (gen_sse_unpcklps (target, tmp2, tmp1));
+ }
+ break;
+ default:
+ abort ();
+ }
+}
+
#include "gt-i386.h"
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 06e3895..a004c32 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -4728,6 +4728,171 @@
"TARGET_SSE2 && TARGET_SSE_MATH && TARGET_64BIT"
"x86_emit_floatuns (operands); DONE;")
+;; SSE extract/set expanders
+
+(define_expand "vec_setv2df"
+ [(match_operand:V2DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" "")
+ (match_operand 2 "const_int_operand" "")]
+ "TARGET_SSE2"
+{
+ switch (INTVAL (operands[2]))
+ {
+ case 0:
+ emit_insn (gen_sse2_movsd (operands[0], operands[0],
+ simplify_gen_subreg (V2DFmode, operands[1],
+ DFmode, 0)));
+ break;
+ case 1:
+ {
+ rtx op1 = simplify_gen_subreg (V2DFmode, operands[1], DFmode, 0);
+
+ emit_insn (gen_sse2_unpcklpd (operands[0], operands[0], op1));
+ }
+ break;
+ default:
+ abort ();
+ }
+ DONE;
+})
+
+(define_expand "vec_extractv2df"
+ [(match_operand:DF 0 "register_operand" "")
+ (match_operand:V2DF 1 "register_operand" "")
+ (match_operand 2 "const_int_operand" "")]
+ "TARGET_SSE2"
+{
+ switch (INTVAL (operands[2]))
+ {
+ case 0:
+ emit_move_insn (operands[0], gen_lowpart (DFmode, operands[1]));
+ break;
+ case 1:
+ {
+ rtx dest = simplify_gen_subreg (V2DFmode, operands[0], DFmode, 0);
+
+ emit_insn (gen_sse2_unpckhpd (dest, operands[1], operands[1]));
+ }
+ break;
+ default:
+ abort ();
+ }
+ DONE;
+})
+
+(define_expand "vec_initv2df"
+ [(match_operand:V2DF 0 "register_operand" "")
+ (match_operand 1 "" "")]
+ "TARGET_SSE2"
+{
+ ix86_expand_vector_init (operands[0], operands[1]);
+ DONE;
+})
+
+(define_expand "vec_setv4sf"
+ [(match_operand:V4SF 0 "register_operand" "")
+ (match_operand:SF 1 "register_operand" "")
+ (match_operand 2 "const_int_operand" "")]
+ "TARGET_SSE"
+{
+ switch (INTVAL (operands[2]))
+ {
+ case 0:
+ emit_insn (gen_sse_movss (operands[0], operands[0],
+ simplify_gen_subreg (V4SFmode, operands[1],
+ SFmode, 0)));
+ break;
+ case 1:
+ {
+ rtx op1 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0);
+ rtx tmp = gen_reg_rtx (V4SFmode);
+
+ emit_move_insn (tmp, operands[0]);
+ emit_insn (gen_sse_unpcklps (operands[0], operands[0], operands[0]));
+ emit_insn (gen_sse_movss (operands[0], operands[0], op1));
+ emit_insn (gen_sse_shufps (operands[0], operands[0], tmp,
+ GEN_INT (1 + (0<<2) + (2<<4) + (3<<6))));
+ }
+ case 2:
+ {
+ rtx op1 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0);
+ rtx tmp = gen_reg_rtx (V4SFmode);
+
+ emit_move_insn (tmp, operands[0]);
+ emit_insn (gen_sse_movss (tmp, tmp, op1));
+ emit_insn (gen_sse_shufps (operands[0], operands[0], tmp,
+ GEN_INT (0 + (1<<2) + (0<<4) + (3<<6))));
+ }
+ break;
+ case 3:
+ {
+ rtx op1 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0);
+ rtx tmp = gen_reg_rtx (V4SFmode);
+
+ emit_move_insn (tmp, operands[0]);
+ emit_insn (gen_sse_movss (tmp, tmp, op1));
+ emit_insn (gen_sse_shufps (operands[0], operands[0], tmp,
+ GEN_INT (0 + (1<<2) + (2<<4) + (0<<6))));
+ }
+ break;
+ default:
+ abort ();
+ }
+ DONE;
+})
+
+(define_expand "vec_extractv4sf"
+ [(match_operand:SF 0 "register_operand" "")
+ (match_operand:V4SF 1 "register_operand" "")
+ (match_operand 2 "const_int_operand" "")]
+ "TARGET_SSE"
+{
+ switch (INTVAL (operands[2]))
+ {
+ case 0:
+ emit_move_insn (operands[0], gen_lowpart (SFmode, operands[1]));
+ break;
+ case 1:
+ {
+ rtx op0 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0);
+ rtx tmp = gen_reg_rtx (V4SFmode);
+
+ emit_move_insn (tmp, operands[1]);
+ emit_insn (gen_sse_shufps (op0, tmp, tmp,
+ GEN_INT (1)));
+ }
+ case 2:
+ {
+ rtx op0 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0);
+ rtx tmp = gen_reg_rtx (V4SFmode);
+
+ emit_move_insn (tmp, operands[1]);
+ emit_insn (gen_sse_unpckhps (op0, tmp, tmp));
+ }
+ case 3:
+ {
+ rtx op0 = simplify_gen_subreg (V4SFmode, operands[1], SFmode, 0);
+ rtx tmp = gen_reg_rtx (V4SFmode);
+
+ emit_move_insn (tmp, operands[1]);
+ emit_insn (gen_sse_shufps (op0, tmp, tmp,
+ GEN_INT (3)));
+ }
+ default:
+ abort ();
+ }
+ DONE;
+})
+
+(define_expand "vec_initv4sf"
+ [(match_operand:V4SF 0 "register_operand" "")
+ (match_operand 1 "" "")]
+ "TARGET_SSE"
+{
+ ix86_expand_vector_init (operands[0], operands[1]);
+ DONE;
+})
+
;; Add instructions
;; %%% splits for addsidi3
@@ -22386,11 +22551,11 @@
(vec_select:DF (match_operand:V2DF 1 "register_operand" "0")
(parallel [(const_int 1)]))
(vec_select:DF (match_operand:V2DF 2 "register_operand" "x")
- (parallel [(const_int 0)]))))]
+ (parallel [(const_int 1)]))))]
"TARGET_SSE2"
"unpckhpd\t{%2, %0|%0, %2}"
[(set_attr "type" "ssecvt")
- (set_attr "mode" "TI")])
+ (set_attr "mode" "V2DF")])
(define_insn "sse2_unpcklpd"
[(set (match_operand:V2DF 0 "register_operand" "=x")
@@ -22398,11 +22563,11 @@
(vec_select:DF (match_operand:V2DF 1 "register_operand" "0")
(parallel [(const_int 0)]))
(vec_select:DF (match_operand:V2DF 2 "register_operand" "x")
- (parallel [(const_int 1)]))))]
+ (parallel [(const_int 0)]))))]
"TARGET_SSE2"
"unpcklpd\t{%2, %0|%0, %2}"
[(set_attr "type" "ssecvt")
- (set_attr "mode" "TI")])
+ (set_attr "mode" "V2DF")])
;; MMX pack/unpack insns.
@@ -22718,17 +22883,6 @@
[(set_attr "type" "ssecvt")
(set_attr "mode" "V2DF")])
-(define_insn "sse2_movlpd"
- [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,m")
- (vec_merge:V2DF
- (match_operand:V2DF 1 "nonimmediate_operand" "0,0")
- (match_operand:V2DF 2 "nonimmediate_operand" "m,x")
- (const_int 1)))]
- "TARGET_SSE2 && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM)"
- "movlpd\t{%2, %0|%0, %2}"
- [(set_attr "type" "ssecvt")
- (set_attr "mode" "V2DF")])
-
(define_expand "sse2_loadsd"
[(match_operand:V2DF 0 "register_operand" "")
(match_operand:DF 1 "memory_operand" "")]
@@ -22751,15 +22905,17 @@
(set_attr "mode" "DF")])
(define_insn "sse2_movsd"
- [(set (match_operand:V2DF 0 "register_operand" "=x")
+ [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,x,m")
(vec_merge:V2DF
- (match_operand:V2DF 1 "register_operand" "0")
- (match_operand:V2DF 2 "register_operand" "x")
+ (match_operand:V2DF 1 "nonimmediate_operand" "0,0,0")
+ (match_operand:V2DF 2 "nonimmediate_operand" "x,m,x")
(const_int 1)))]
- "TARGET_SSE2"
- "movsd\t{%2, %0|%0, %2}"
+ "TARGET_SSE2 && ix86_binary_operator_ok (UNKNOWN, V2DFmode, operands)"
+ "@movsd\t{%2, %0|%0, %2}
+ movlpd\t{%2, %0|%0, %2}
+ movlpd\t{%2, %0|%0, %2}"
[(set_attr "type" "ssecvt")
- (set_attr "mode" "DF")])
+ (set_attr "mode" "DF,V2DF,V2DF")])
(define_insn "sse2_storesd"
[(set (match_operand:DF 0 "memory_operand" "=m")
diff --git a/gcc/config/i386/xmmintrin.h b/gcc/config/i386/xmmintrin.h
index f1275bd..dc54251 100644
--- a/gcc/config/i386/xmmintrin.h
+++ b/gcc/config/i386/xmmintrin.h
@@ -42,7 +42,6 @@ typedef int __m128 __attribute__ ((__mode__(__V4SF__)));
/* Internal data types for implementing the intrinsics. */
typedef int __v4sf __attribute__ ((__mode__(__V4SF__)));
-typedef int __v4si __attribute__ ((__mode__(__V4SI__)));
/* Create a selector for use with the SHUFPS instruction. */
#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) \
@@ -890,19 +889,9 @@ _mm_set_ps1 (float __F)
/* Create the vector [Z Y X W]. */
static __inline __m128
-_mm_set_ps (float __Z, float __Y, float __X, float __W)
+_mm_set_ps (const float __Z, const float __Y, const float __X, const float __W)
{
- union {
- float __a[4];
- __m128 __v;
- } __u;
-
- __u.__a[0] = __W;
- __u.__a[1] = __X;
- __u.__a[2] = __Y;
- __u.__a[3] = __Z;
-
- return __u.__v;
+ return (__v4sf) {__W, __X, __Y, __Z};
}
/* Create the vector [W X Y Z]. */
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 98a26a1..8ebfb48 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -313,6 +313,53 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
value = protect_from_queue (value, 0);
+ /* Use vec_extract patterns for extracting parts of vectors whenever
+ available. */
+ if (VECTOR_MODE_P (GET_MODE (op0))
+ && GET_CODE (op0) != MEM
+ && (vec_set_optab->handlers[(int)GET_MODE (op0)].insn_code
+ != CODE_FOR_nothing)
+ && fieldmode == GET_MODE_INNER (GET_MODE (op0))
+ && bitsize == GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
+ && !(bitnum % GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
+ {
+ enum machine_mode outermode = GET_MODE (op0);
+ enum machine_mode innermode = GET_MODE_INNER (outermode);
+ int icode = (int) vec_set_optab->handlers[(int) outermode].insn_code;
+ int pos = bitnum / GET_MODE_BITSIZE (innermode);
+ rtx rtxpos = GEN_INT (pos);
+ rtx src = value;
+ rtx dest = op0;
+ rtx pat, seq;
+ enum machine_mode mode0 = insn_data[icode].operand[0].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode2 = insn_data[icode].operand[2].mode;
+
+ start_sequence ();
+
+ if (! (*insn_data[icode].operand[1].predicate) (src, mode1))
+ src = copy_to_mode_reg (mode1, src);
+
+ if (! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
+ rtxpos = copy_to_mode_reg (mode1, rtxpos);
+
+ /* We could handle this, but we should always be called with a pseudo
+ for our targets and all insns should take them as outputs. */
+ if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)
+ || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
+ || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
+ abort ();
+ pat = GEN_FCN (icode) (dest, src, rtxpos);
+ seq = get_insns ();
+ end_sequence ();
+ if (pat)
+ {
+ emit_insn (seq);
+ emit_insn (pat);
+ return dest;
+ }
+ }
+
if (flag_force_mem)
{
int old_generating_concat_p = generating_concat_p;
@@ -1035,6 +1082,62 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
return op0;
}
+ /* Use vec_extract patterns for extracting parts of vectors whenever
+ available. */
+ if (VECTOR_MODE_P (GET_MODE (op0))
+ && GET_CODE (op0) != MEM
+ && (vec_extract_optab->handlers[(int)GET_MODE (op0)].insn_code
+ != CODE_FOR_nothing)
+ && ((bitsize + bitnum) / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
+ == bitsize / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
+ {
+ enum machine_mode outermode = GET_MODE (op0);
+ enum machine_mode innermode = GET_MODE_INNER (outermode);
+ int icode = (int) vec_extract_optab->handlers[(int) outermode].insn_code;
+ int pos = bitnum / GET_MODE_BITSIZE (innermode);
+ rtx rtxpos = GEN_INT (pos);
+ rtx src = op0;
+ rtx dest = NULL, pat, seq;
+ enum machine_mode mode0 = insn_data[icode].operand[0].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode2 = insn_data[icode].operand[2].mode;
+
+ if (innermode == tmode || innermode == mode)
+ dest = target;
+
+ if (!dest)
+ dest = gen_reg_rtx (innermode);
+
+ start_sequence ();
+
+ if (! (*insn_data[icode].operand[0].predicate) (dest, mode0))
+ dest = copy_to_mode_reg (mode0, dest);
+
+ if (! (*insn_data[icode].operand[1].predicate) (src, mode1))
+ src = copy_to_mode_reg (mode1, src);
+
+ if (! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
+ rtxpos = copy_to_mode_reg (mode1, rtxpos);
+
+ /* We could handle this, but we should always be called with a pseudo
+ for our targets and all insns should take them as outputs. */
+ if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)
+ || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
+ || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
+ abort ();
+ pat = GEN_FCN (icode) (dest, src, rtxpos);
+ seq = get_insns ();
+ end_sequence ();
+ if (pat)
+ {
+ emit_insn (seq);
+ emit_insn (pat);
+ return extract_bit_field (dest, bitsize,
+ bitnum - pos * GET_MODE_BITSIZE (innermode),
+ unsignedp, target, mode, tmode, total_size);
+ }
+ }
+
/* Make sure we are playing with integral modes. Pun with subregs
if we aren't. */
{
diff --git a/gcc/expr.c b/gcc/expr.c
index a38dee1..b0608fa 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -4710,6 +4710,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
int const_bounds_p;
HOST_WIDE_INT minelt = 0;
HOST_WIDE_INT maxelt = 0;
+ int icode = 0;
+ rtx *vector = NULL;
+ int elt_size = 0;
+ unsigned n_elts = 0;
/* Vectors are like arrays, but the domain is stored via an array
type indirectly. */
@@ -4720,6 +4724,22 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
it always will. */
domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
+ if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
+ {
+ enum machine_mode mode = GET_MODE (target);
+
+ icode = (int) vec_init_optab->handlers[mode].insn_code;
+ if (icode != CODE_FOR_nothing)
+ {
+ unsigned int i;
+
+ elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
+ n_elts = (GET_MODE_SIZE (mode) / elt_size);
+ vector = alloca (n_elts);
+ for (i = 0; i < n_elts; i++)
+ vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+ }
+ }
}
const_bounds_p = (TYPE_MIN_VALUE (domain)
@@ -4784,7 +4804,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
need_to_clear = 1;
}
- if (need_to_clear && size > 0)
+ if (need_to_clear && size > 0 && !vector)
{
if (! cleared)
{
@@ -4835,6 +4855,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
HOST_WIDE_INT lo, hi, count;
tree position;
+ if (vector)
+ abort ();
+
/* If the range is constant and "small", unroll the loop. */
if (const_bounds_p
&& host_integerp (lo_index, 0)
@@ -4926,6 +4949,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
{
tree position;
+ if (vector)
+ abort ();
+
if (index == 0)
index = ssize_int (1);
@@ -4943,6 +4969,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
xtarget = adjust_address (xtarget, mode, 0);
store_expr (value, xtarget, 0);
}
+ else if (vector)
+ {
+ int pos;
+
+ if (index != 0)
+ pos = tree_low_cst (index, 0) - minelt;
+ else
+ pos = i;
+ vector[pos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+ }
else
{
if (index != 0)
@@ -4958,12 +4994,17 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
target = copy_rtx (target);
MEM_KEEP_ALIAS_SET_P (target) = 1;
}
-
- store_constructor_field (target, bitsize, bitpos, mode, value,
- type, cleared, get_alias_set (elttype));
-
+ else
+ store_constructor_field (target, bitsize, bitpos, mode, value,
+ type, cleared, get_alias_set (elttype));
}
}
+ if (vector)
+ {
+ emit_insn (GEN_FCN (icode) (target,
+ gen_rtx_PARALLEL (GET_MODE (target),
+ gen_rtvec_v (n_elts, vector))));
+ }
}
/* Set constructor assignments. */
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 2dc59f5..8f309f4 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -152,7 +152,10 @@ static const char * const optabs[] =
"movstr_optab[$A] = CODE_FOR_$(movstr$a$)",
"clrstr_optab[$A] = CODE_FOR_$(clrstr$a$)",
"cmpstr_optab[$A] = CODE_FOR_$(cmpstr$a$)",
- "cmpmem_optab[$A] = CODE_FOR_$(cmpmem$a$)" };
+ "cmpmem_optab[$A] = CODE_FOR_$(cmpmem$a$)",
+ "vec_set_optab->handlers[$A].insn_code = CODE_FOR_$(vec_set$a$)",
+ "vec_extract_optab->handlers[$A].insn_code = CODE_FOR_$(vec_extract$a$)",
+ "vec_init_optab->handlers[$A].insn_code = CODE_FOR_$(vec_init$a$)" };
static void gen_insn (rtx);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 3a5705f..44d4b83 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -5271,6 +5271,9 @@ init_optabs (void)
cstore_optab = init_optab (UNKNOWN);
push_optab = init_optab (UNKNOWN);
+ vec_extract_optab = init_optab (UNKNOWN);
+ vec_set_optab = init_optab (UNKNOWN);
+ vec_init_optab = init_optab (UNKNOWN);
/* Conversions. */
sext_optab = init_convert_optab (SIGN_EXTEND);
zext_optab = init_convert_optab (ZERO_EXTEND);
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 20d5df6..a85ce30 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -197,6 +197,13 @@ enum optab_index
/* Conditional add instruction. */
OTI_addcc,
+ /* Set specified field of vector operand. */
+ OTI_vec_set,
+ /* Extract specified field of vector operand. */
+ OTI_vec_extract,
+ /* Initialize vector operand. */
+ OTI_vec_init,
+
OTI_MAX
};
@@ -281,6 +288,10 @@ extern GTY(()) optab optab_table[OTI_MAX];
#define push_optab (optab_table[OTI_push])
#define addcc_optab (optab_table[OTI_addcc])
+#define vec_set_optab (optab_table[OTI_vec_set])
+#define vec_extract_optab (optab_table[OTI_vec_extract])
+#define vec_init_optab (optab_table[OTI_vec_init])
+
/* Conversion optabs have their own table and indexes. */
enum convert_optab_index
{