summaryrefslogtreecommitdiff
path: root/gcc/config/arm/arm.c
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2012-09-05 08:56:12 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2012-09-05 08:56:12 +0000
commit6a802d8242d059d55f3cdd558199403c3b8fbb05 (patch)
treed128c5095aaa3608ec7c87a3c747396d6d736929 /gcc/config/arm/arm.c
parentbf4993e7e79a3b597ba502231bf74f5676b08c19 (diff)
downloadgcc-6a802d8242d059d55f3cdd558199403c3b8fbb05.tar.gz
2012-09-05 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 190965 using svnmerge. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@190968 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/arm/arm.c')
-rw-r--r--gcc/config/arm/arm.c97
1 files changed, 84 insertions, 13 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9ce3c0f068a..4001f350f2f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -20959,7 +20959,7 @@ arm_expand_builtin (tree exp,
else if (icode == CODE_FOR_iwmmxt_tinsrw && (selector < 0 ||selector > 1))
error ("the range of selector should be in 0 to 1");
mask <<= selector;
- op2 = gen_rtx_CONST_INT (SImode, mask);
+ op2 = GEN_INT (mask);
}
if (target == 0
|| GET_MODE (target) != tmode
@@ -21862,7 +21862,7 @@ thumb1_extra_regs_pushed (arm_stack_offsets *offsets, bool for_prologue)
unsigned long l_mask = live_regs_mask & (for_prologue ? 0x40ff : 0xff);
/* Then count how many other high registers will need to be pushed. */
unsigned long high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
- int n_free, reg_base;
+ int n_free, reg_base, size;
if (!for_prologue && frame_pointer_needed)
amount = offsets->locals_base - offsets->saved_regs;
@@ -21901,7 +21901,8 @@ thumb1_extra_regs_pushed (arm_stack_offsets *offsets, bool for_prologue)
n_free = 0;
if (!for_prologue)
{
- reg_base = arm_size_return_regs () / UNITS_PER_WORD;
+ size = arm_size_return_regs ();
+ reg_base = ARM_NUM_INTS (size);
live_regs_mask >>= reg_base;
}
@@ -21955,8 +21956,7 @@ thumb1_unexpanded_epilogue (void)
if (extra_pop > 0)
{
unsigned long extra_mask = (1 << extra_pop) - 1;
- live_regs_mask |= extra_mask << ((size + UNITS_PER_WORD - 1)
- / UNITS_PER_WORD);
+ live_regs_mask |= extra_mask << ARM_NUM_INTS (size);
}
/* The prolog may have pushed some high registers to use as
@@ -25937,6 +25937,72 @@ arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
return true;
}
+/* Recognize patterns for the VEXT insns. */
+
+static bool
+arm_evpc_neon_vext (struct expand_vec_perm_d *d)
+{
+ unsigned int i, nelt = d->nelt;
+ rtx (*gen) (rtx, rtx, rtx, rtx);
+ rtx offset;
+
+ unsigned int location;
+
+ unsigned int next = d->perm[0] + 1;
+
+ /* TODO: Handle GCC's numbering of elements for big-endian. */
+ if (BYTES_BIG_ENDIAN)
+ return false;
+
+ /* Check if the extracted indexes are increasing by one. */
+ for (i = 1; i < nelt; next++, i++)
+ {
+ /* If we hit the most significant element of the 2nd vector in
+ the previous iteration, no need to test further. */
+ if (next == 2 * nelt)
+ return false;
+
+ /* If we are operating on only one vector: it could be a
+ rotation. If there are only two elements of size < 64, let
+ arm_evpc_neon_vrev catch it. */
+ if (d->one_vector_p && (next == nelt))
+ {
+ if ((nelt == 2) && (d->vmode != V2DImode))
+ return false;
+ else
+ next = 0;
+ }
+
+ if (d->perm[i] != next)
+ return false;
+ }
+
+ location = d->perm[0];
+
+ switch (d->vmode)
+ {
+ case V16QImode: gen = gen_neon_vextv16qi; break;
+ case V8QImode: gen = gen_neon_vextv8qi; break;
+ case V4HImode: gen = gen_neon_vextv4hi; break;
+ case V8HImode: gen = gen_neon_vextv8hi; break;
+ case V2SImode: gen = gen_neon_vextv2si; break;
+ case V4SImode: gen = gen_neon_vextv4si; break;
+ case V2SFmode: gen = gen_neon_vextv2sf; break;
+ case V4SFmode: gen = gen_neon_vextv4sf; break;
+ case V2DImode: gen = gen_neon_vextv2di; break;
+ default:
+ return false;
+ }
+
+ /* Success! */
+ if (d->testing_p)
+ return true;
+
+ offset = GEN_INT (location);
+ emit_insn (gen (d->target, d->op0, d->op1, offset));
+ return true;
+}
+
/* The NEON VTBL instruction is a fully variable permuation that's even
stronger than what we expose via VEC_PERM_EXPR. What it doesn't do
is mask the index operand as VEC_PERM_EXPR requires. Therefore we
@@ -25976,6 +26042,12 @@ arm_evpc_neon_vtbl (struct expand_vec_perm_d *d)
static bool
arm_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
{
+ /* Check if the input mask matches vext before reordering the
+ operands. */
+ if (TARGET_NEON)
+ if (arm_evpc_neon_vext (d))
+ return true;
+
/* The pattern matching functions above are written to look for a small
number to begin the sequence (0, 1, N/2). If we begin with an index
from the second operand, we can swap the operands. */
@@ -26218,12 +26290,12 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in,
/* Macros to make following code more readable. */
#define SUB_32(DEST,SRC) \
- gen_addsi3 ((DEST), (SRC), gen_rtx_CONST_INT (VOIDmode, -32))
+ gen_addsi3 ((DEST), (SRC), GEN_INT (-32))
#define RSB_32(DEST,SRC) \
- gen_subsi3 ((DEST), gen_rtx_CONST_INT (VOIDmode, 32), (SRC))
+ gen_subsi3 ((DEST), GEN_INT (32), (SRC))
#define SUB_S_32(DEST,SRC) \
gen_addsi3_compare0 ((DEST), (SRC), \
- gen_rtx_CONST_INT (VOIDmode, -32))
+ GEN_INT (-32))
#define SET(DEST,SRC) \
gen_rtx_SET (SImode, (DEST), (SRC))
#define SHIFT(CODE,SRC,AMOUNT) \
@@ -26259,7 +26331,7 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in,
{
if (code == ASHIFTRT)
{
- rtx const31_rtx = gen_rtx_CONST_INT (VOIDmode, 31);
+ rtx const31_rtx = GEN_INT (31);
emit_insn (SET (out_down, SHIFT (code, in_up, const31_rtx)));
emit_insn (SET (out_up, SHIFT (code, in_up, const31_rtx)));
}
@@ -26271,8 +26343,7 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in,
else if (INTVAL (amount) < 32)
{
/* Shifts by a constant less than 32. */
- rtx reverse_amount = gen_rtx_CONST_INT (VOIDmode,
- 32 - INTVAL (amount));
+ rtx reverse_amount = GEN_INT (32 - INTVAL (amount));
emit_insn (SET (out_down, LSHIFT (code, in_down, amount)));
emit_insn (SET (out_down,
@@ -26283,12 +26354,12 @@ arm_emit_coreregs_64bit_shift (enum rtx_code code, rtx out, rtx in,
else
{
/* Shifts by a constant greater than 31. */
- rtx adj_amount = gen_rtx_CONST_INT (VOIDmode, INTVAL (amount) - 32);
+ rtx adj_amount = GEN_INT (INTVAL (amount) - 32);
emit_insn (SET (out_down, SHIFT (code, in_up, adj_amount)));
if (code == ASHIFTRT)
emit_insn (gen_ashrsi3 (out_up, in_up,
- gen_rtx_CONST_INT (VOIDmode, 31)));
+ GEN_INT (31)));
else
emit_insn (SET (out_up, const0_rtx));
}