summaryrefslogtreecommitdiffstats
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2004-01-01 14:13:44 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2004-01-01 14:13:44 +0000
commitb8d2bcdd743853cfef58c1c0d7ee7f518c098416 (patch)
tree366fcb1b6390ba0ac365092bc3e6aee1326879fc /gcc/expmed.c
parent99cf25d08b422ccf718a05f484e1be90f533ab63 (diff)
downloadppe42-gcc-b8d2bcdd743853cfef58c1c0d7ee7f518c098416.tar.gz
ppe42-gcc-b8d2bcdd743853cfef58c1c0d7ee7f518c098416.zip
* 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 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@75304 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 98a26a14c1e..8ebfb487552 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. */
{
OpenPOWER on IntegriCloud