arm.c (neon_immediate_valid_for_shift): New function.

2011-06-22  Dmitry Plotnikov  <dplotnikov@ispras.ru>
	Dmitry Melnik  <dm@ispras.ru>

	* config/arm/arm.c (neon_immediate_valid_for_shift): New function.
	(neon_output_shift_immediate): Ditto.
	* config/arm/arm-protos.h (neon_immediate_valid_for_shift): New
	prototype.
	(neon_output_shift_immediate): Ditto.
	* config/arm/neon.md (vashl<mode>3): Modified constraint.
	(vashr<mode>3_imm): New insn pattern.
	(vlshr<mode>3_imm): Ditto.
	(vashr<mode>3): Modified constraint.
	(vlshr<mode>3): Ditto.
	* config/arm/predicates.md (imm_for_neon_lshift_operand): New
	predicate.
	(imm_for_neon_rshift_operand): Ditto.
	(imm_lshift_or_reg_neon): Ditto.
	(imm_rshift_or_reg_neon): Ditto.

	* optabs.c (init_optabs): Init optab codes for vashl, vashr, vlshr.

testsuite:

	* gcc.target/arm/neon-vshr-imm-1.c: New testcase.
	* gcc.target/arm/neon-vshl-imm-1.c: New testcase.
	* gcc.target/arm/neon-vlshr-imm-1.c: New testcase.


Co-Authored-By: Dmitry Melnik <dm@ispras.ru>

From-SVN: r175293
This commit is contained in:
Dmitry Plotnikov 2011-06-22 11:57:52 +00:00 committed by Alexander Monakov
parent 1da9434b4b
commit 31a0c8251b
10 changed files with 232 additions and 14 deletions

View File

@ -1,3 +1,24 @@
2011-06-22 Dmitry Plotnikov <dplotnikov@ispras.ru>
Dmitry Melnik <dm@ispras.ru>
* config/arm/arm.c (neon_immediate_valid_for_shift): New function.
(neon_output_shift_immediate): Ditto.
* config/arm/arm-protos.h (neon_immediate_valid_for_shift): New
prototype.
(neon_output_shift_immediate): Ditto.
* config/arm/neon.md (vashl<mode>3): Modified constraint.
(vashr<mode>3_imm): New insn pattern.
(vlshr<mode>3_imm): Ditto.
(vashr<mode>3): Modified constraint.
(vlshr<mode>3): Ditto.
* config/arm/predicates.md (imm_for_neon_lshift_operand): New
predicate.
(imm_for_neon_rshift_operand): Ditto.
(imm_lshift_or_reg_neon): Ditto.
(imm_rshift_or_reg_neon): Ditto.
* optabs.c (init_optabs): Init optab codes for vashl, vashr, vlshr.
2011-06-22 Jakub Jelinek <jakub@redhat.com>
* tree-ssa-ccp.c (evaluate_stmt): Try bitwise tracking for

View File

@ -66,8 +66,12 @@ extern int vfp3_const_double_rtx (rtx);
extern int neon_immediate_valid_for_move (rtx, enum machine_mode, rtx *, int *);
extern int neon_immediate_valid_for_logic (rtx, enum machine_mode, int, rtx *,
int *);
extern int neon_immediate_valid_for_shift (rtx, enum machine_mode, rtx *,
int *, bool);
extern char *neon_output_logic_immediate (const char *, rtx *,
enum machine_mode, int, int);
extern char *neon_output_shift_immediate (const char *, char, rtx *,
enum machine_mode, int, bool);
extern void neon_pairwise_reduce (rtx, rtx, enum machine_mode,
rtx (*) (rtx, rtx, rtx));
extern rtx neon_make_constant (rtx);

View File

@ -8608,6 +8608,66 @@ neon_immediate_valid_for_logic (rtx op, enum machine_mode mode, int inverse,
return 1;
}
/* Return TRUE if rtx OP is legal for use in a VSHR or VSHL instruction. If
the immediate is valid, write a constant suitable for using as an operand
to VSHR/VSHL to *MODCONST and the corresponding element width to
*ELEMENTWIDTH. ISLEFTSHIFT is for determine left or right shift,
because they have different limitations. */
int
neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
rtx *modconst, int *elementwidth,
bool isleftshift)
{
unsigned int innersize = GET_MODE_SIZE (GET_MODE_INNER (mode));
unsigned int n_elts = CONST_VECTOR_NUNITS (op), i;
unsigned HOST_WIDE_INT last_elt = 0;
unsigned HOST_WIDE_INT maxshift;
/* Split vector constant out into a byte vector. */
for (i = 0; i < n_elts; i++)
{
rtx el = CONST_VECTOR_ELT (op, i);
unsigned HOST_WIDE_INT elpart;
if (GET_CODE (el) == CONST_INT)
elpart = INTVAL (el);
else if (GET_CODE (el) == CONST_DOUBLE)
return 0;
else
gcc_unreachable ();
if (i != 0 && elpart != last_elt)
return 0;
last_elt = elpart;
}
/* Shift less than element size. */
maxshift = innersize * 8;
if (isleftshift)
{
/* Left shift immediate value can be from 0 to <size>-1. */
if (last_elt >= maxshift)
return 0;
}
else
{
/* Right shift immediate value can be from 1 to <size>. */
if (last_elt == 0 || last_elt > maxshift)
return 0;
}
if (elementwidth)
*elementwidth = innersize * 8;
if (modconst)
*modconst = CONST_VECTOR_ELT (op, 0);
return 1;
}
/* Return a string suitable for output of Neon immediate logic operation
MNEM. */
@ -8630,6 +8690,28 @@ neon_output_logic_immediate (const char *mnem, rtx *op2, enum machine_mode mode,
return templ;
}
/* Return a string suitable for output of Neon immediate shift operation
(VSHR or VSHL) MNEM. */
char *
neon_output_shift_immediate (const char *mnem, char sign, rtx *op2,
enum machine_mode mode, int quad,
bool isleftshift)
{
int width, is_valid;
static char templ[40];
is_valid = neon_immediate_valid_for_shift (*op2, mode, op2, &width, isleftshift);
gcc_assert (is_valid != 0);
if (quad)
sprintf (templ, "%s.%c%d\t%%q0, %%q1, %%2", mnem, sign, width);
else
sprintf (templ, "%s.%c%d\t%%P0, %%P1, %%2", mnem, sign, width);
return templ;
}
/* Output a sequence of pairwise operations to implement a reduction.
NOTE: We do "too much work" here, because pairwise operations work on two
registers-worth of operands in one go. Unfortunately we can't exploit those

View File

@ -969,17 +969,59 @@
; SImode elements.
(define_insn "vashl<mode>3"
[(set (match_operand:VDQIW 0 "s_register_operand" "=w")
(ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
(match_operand:VDQIW 2 "s_register_operand" "w")))]
[(set (match_operand:VDQIW 0 "s_register_operand" "=w,w")
(ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w,w")
(match_operand:VDQIW 2 "imm_lshift_or_reg_neon" "w,Dn")))]
"TARGET_NEON"
"vshl.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
{
switch (which_alternative)
{
case 0: return "vshl.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2";
case 1: return neon_output_shift_immediate ("vshl", 'i', &operands[2],
<MODE>mode,
VALID_NEON_QREG_MODE (<MODE>mode),
true);
default: gcc_unreachable ();
}
}
[(set (attr "neon_type")
(if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
(const_string "neon_vshl_ddd")
(const_string "neon_shift_3")))]
)
(define_insn "vashr<mode>3_imm"
[(set (match_operand:VDQIW 0 "s_register_operand" "=w")
(ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
(match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))]
"TARGET_NEON"
{
return neon_output_shift_immediate ("vshr", 's', &operands[2],
<MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode),
false);
}
[(set (attr "neon_type")
(if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
(const_string "neon_vshl_ddd")
(const_string "neon_shift_3")))]
)
(define_insn "vlshr<mode>3_imm"
[(set (match_operand:VDQIW 0 "s_register_operand" "=w")
(lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
(match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))]
"TARGET_NEON"
{
return neon_output_shift_immediate ("vshr", 'u', &operands[2],
<MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode),
false);
}
[(set (attr "neon_type")
(if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
(const_string "neon_vshl_ddd")
(const_string "neon_shift_3")))]
)
; Used for implementing logical shift-right, which is a left-shift by a negative
; amount, with signed operands. This is essentially the same as ashl<mode>3
; above, but using an unspec in case GCC tries anything tricky with negative
@ -1017,28 +1059,34 @@
(define_expand "vashr<mode>3"
[(set (match_operand:VDQIW 0 "s_register_operand" "")
(ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
(match_operand:VDQIW 2 "s_register_operand" "")))]
(match_operand:VDQIW 2 "imm_rshift_or_reg_neon" "")))]
"TARGET_NEON"
{
rtx neg = gen_reg_rtx (<MODE>mode);
emit_insn (gen_neg<mode>2 (neg, operands[2]));
emit_insn (gen_ashl<mode>3_signed (operands[0], operands[1], neg));
if (REG_P (operands[2]))
{
emit_insn (gen_neg<mode>2 (neg, operands[2]));
emit_insn (gen_ashl<mode>3_signed (operands[0], operands[1], neg));
}
else
emit_insn (gen_vashr<mode>3_imm (operands[0], operands[1], operands[2]));
DONE;
})
(define_expand "vlshr<mode>3"
[(set (match_operand:VDQIW 0 "s_register_operand" "")
(lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
(match_operand:VDQIW 2 "s_register_operand" "")))]
(match_operand:VDQIW 2 "imm_rshift_or_reg_neon" "")))]
"TARGET_NEON"
{
rtx neg = gen_reg_rtx (<MODE>mode);
emit_insn (gen_neg<mode>2 (neg, operands[2]));
emit_insn (gen_ashl<mode>3_unsigned (operands[0], operands[1], neg));
if (REG_P (operands[2]))
{
emit_insn (gen_neg<mode>2 (neg, operands[2]));
emit_insn (gen_ashl<mode>3_unsigned (operands[0], operands[1], neg));
}
else
emit_insn (gen_vlshr<mode>3_imm (operands[0], operands[1], operands[2]));
DONE;
})

View File

@ -585,6 +585,26 @@
return neon_immediate_valid_for_move (op, mode, NULL, NULL);
})
(define_predicate "imm_for_neon_lshift_operand"
(match_code "const_vector")
{
return neon_immediate_valid_for_shift (op, mode, NULL, NULL, true);
})
(define_predicate "imm_for_neon_rshift_operand"
(match_code "const_vector")
{
return neon_immediate_valid_for_shift (op, mode, NULL, NULL, false);
})
(define_predicate "imm_lshift_or_reg_neon"
(ior (match_operand 0 "s_register_operand")
(match_operand 0 "imm_for_neon_lshift_operand")))
(define_predicate "imm_rshift_or_reg_neon"
(ior (match_operand 0 "s_register_operand")
(match_operand 0 "imm_for_neon_rshift_operand")))
(define_predicate "imm_for_neon_logic_operand"
(match_code "const_vector")
{

View File

@ -5925,6 +5925,9 @@ init_optabs (void)
init_optab (usashl_optab, US_ASHIFT);
init_optab (ashr_optab, ASHIFTRT);
init_optab (lshr_optab, LSHIFTRT);
init_optabv (vashl_optab, ASHIFT);
init_optabv (vashr_optab, ASHIFTRT);
init_optabv (vlshr_optab, LSHIFTRT);
init_optab (rotl_optab, ROTATE);
init_optab (rotr_optab, ROTATERT);
init_optab (smin_optab, SMIN);

View File

@ -1,3 +1,10 @@
2011-06-22 Dmitry Plotnikov <dplotnikov@ispras.ru>
Dmitry Melnik <dm@ispras.ru>
* gcc.target/arm/neon-vshr-imm-1.c: New testcase.
* gcc.target/arm/neon-vshl-imm-1.c: New testcase.
* gcc.target/arm/neon-vlshr-imm-1.c: New testcase.
2011-06-22 Uros Bizjak <ubizjak@gmail.com>
* gcc.dg/torture/tls/run-le.c: Skip for -pie on alpha*-*-linux*.

View File

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-require-effective-target arm_neon_ok } */
/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
/* { dg-final { scan-assembler "vshr\.u32.*#3" } } */
/* Verify that VSHR immediate is used. */
void f1(int n, unsigned int x[], unsigned int y[]) {
int i;
for (i = 0; i < n; ++i)
y[i] = x[i] >> 3;
}

View File

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-require-effective-target arm_neon_ok } */
/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
/* { dg-final { scan-assembler "vshl\.i32.*#3" } } */
/* Verify that VSHR immediate is used. */
void f1(int n, int x[], int y[]) {
int i;
for (i = 0; i < n; ++i)
y[i] = x[i] << 3;
}

View File

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-require-effective-target arm_neon_ok } */
/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
/* { dg-final { scan-assembler "vshr\.s32.*#3" } } */
/* Verify that VSHR immediate is used. */
void f1(int n, int x[], int y[]) {
int i;
for (i = 0; i < n; ++i)
y[i] = x[i] >> 3;
}