From 31a0c8251b9fb551d9979988e5e63df8bcc1d65f Mon Sep 17 00:00:00 2001 From: Dmitry Plotnikov Date: Wed, 22 Jun 2011 11:57:52 +0000 Subject: arm.c (neon_immediate_valid_for_shift): New function. 2011-06-22 Dmitry Plotnikov Dmitry Melnik * 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 (vashl3): Modified constraint. (vashr3_imm): New insn pattern. (vlshr3_imm): Ditto. (vashr3): Modified constraint. (vlshr3): 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 From-SVN: r175293 --- gcc/ChangeLog | 21 +++++++ gcc/config/arm/arm-protos.h | 4 ++ gcc/config/arm/arm.c | 82 +++++++++++++++++++++++++ gcc/config/arm/neon.md | 74 ++++++++++++++++++---- gcc/config/arm/predicates.md | 20 ++++++ gcc/optabs.c | 3 + gcc/testsuite/ChangeLog | 7 +++ gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c | 11 ++++ gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c | 11 ++++ gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c | 11 ++++ 10 files changed, 231 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c create mode 100644 gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c create mode 100644 gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a8e03fd..9a07519 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2011-06-22 Dmitry Plotnikov + Dmitry Melnik + + * 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 (vashl3): Modified constraint. + (vashr3_imm): New insn pattern. + (vlshr3_imm): Ditto. + (vashr3): Modified constraint. + (vlshr3): 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 * tree-ssa-ccp.c (evaluate_stmt): Try bitwise tracking for diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 2fd75fb..3eb2177 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -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); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 88e3b62..efffcf8 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -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 -1. */ + if (last_elt >= maxshift) + return 0; + } + else + { + /* Right shift immediate value can be from 1 to . */ + 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 diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md index a8c1b87..2c109e0 100644 --- a/gcc/config/arm/neon.md +++ b/gcc/config/arm/neon.md @@ -969,17 +969,59 @@ ; SImode elements. (define_insn "vashl3" + [(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" + { + switch (which_alternative) + { + case 0: return "vshl.\t%0, %1, %2"; + case 1: return neon_output_shift_immediate ("vshl", 'i', &operands[2], + mode, + VALID_NEON_QREG_MODE (mode), + true); + default: gcc_unreachable (); + } + } + [(set (attr "neon_type") + (if_then_else (ne (symbol_ref "") (const_int 0)) + (const_string "neon_vshl_ddd") + (const_string "neon_shift_3")))] +) + +(define_insn "vashr3_imm" [(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")))] + (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w") + (match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))] "TARGET_NEON" - "vshl.\t%0, %1, %2" + { + return neon_output_shift_immediate ("vshr", 's', &operands[2], + mode, VALID_NEON_QREG_MODE (mode), + false); + } [(set (attr "neon_type") (if_then_else (ne (symbol_ref "") (const_int 0)) (const_string "neon_vshl_ddd") (const_string "neon_shift_3")))] ) +(define_insn "vlshr3_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, VALID_NEON_QREG_MODE (mode), + false); + } + [(set (attr "neon_type") + (if_then_else (ne (symbol_ref "") (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 ashl3 ; above, but using an unspec in case GCC tries anything tricky with negative @@ -1017,28 +1059,34 @@ (define_expand "vashr3" [(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); - - emit_insn (gen_neg2 (neg, operands[2])); - emit_insn (gen_ashl3_signed (operands[0], operands[1], neg)); - + if (REG_P (operands[2])) + { + emit_insn (gen_neg2 (neg, operands[2])); + emit_insn (gen_ashl3_signed (operands[0], operands[1], neg)); + } + else + emit_insn (gen_vashr3_imm (operands[0], operands[1], operands[2])); DONE; }) (define_expand "vlshr3" [(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); - - emit_insn (gen_neg2 (neg, operands[2])); - emit_insn (gen_ashl3_unsigned (operands[0], operands[1], neg)); - + if (REG_P (operands[2])) + { + emit_insn (gen_neg2 (neg, operands[2])); + emit_insn (gen_ashl3_unsigned (operands[0], operands[1], neg)); + } + else + emit_insn (gen_vlshr3_imm (operands[0], operands[1], operands[2])); DONE; }) diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 891a974..ec5de69 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -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") { diff --git a/gcc/optabs.c b/gcc/optabs.c index 969d5cf..bf15ab4 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a102060..7579620 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2011-06-22 Dmitry Plotnikov + Dmitry Melnik + + * 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 * gcc.dg/torture/tls/run-le.c: Skip for -pie on alpha*-*-linux*. diff --git a/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c b/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c new file mode 100644 index 0000000..e666371 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c b/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c new file mode 100644 index 0000000..913d595 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c new file mode 100644 index 0000000..82a3c5c --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c @@ -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; +} -- cgit v1.1