[PATCH v1 1/2] arm: handle neon vec_dup from select of 128-bit vector
Richard Earnshaw via Sourceware Forge <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <bmm.hkvpdth7hg.gcc.gcc.rearnsha.208.1.1@forge-stage.sourceware.org> |
From: Richard Earnshaw <[email protected]> The Neon instruction set lacks a direct vdup from a lane in a 128-bit vector; but one isn't needed because the lane is a constant and we can handle the appropriate half of a 128-bit register simply by selecting that during output. Additionally, we can also handle core registers as the source operand for both 64-bit and 128-bit sources without needing to copy the entire vector to VFP/SIMD regs; at most a simple shift is needed to extract the appropriate lane to the lower bits of a scratch core reg, but in some cases we can use the core reg directly (when no shift is needed) since the upper bits are ignored. gcc/ChangeLog: * config/arm/neon.md (neon_vdup_lane<mode>_internal): Handle core registers as the input vector operand by splitting. (neon_vdupq_lane<mode>_internal): New pattern gcc/testsuite/ChangeLog: * gcc.target/arm/crypto-vsha1cq_u32.c: Don't expect a vmov.32 in the generated code. * gcc.target/arm/crypto-vsha1h_u32.c: Likewise. * gcc.target/arm/crypto-vsha1mq_u32.c: Likewise. * gcc.target/arm/crypto-vsha1pq_u32.c: Likewise. --- gcc/config/arm/neon.md | 99 +++++++++++++++---- .../gcc.target/arm/crypto-vsha1cq_u32.c | 2 +- .../gcc.target/arm/crypto-vsha1h_u32.c | 1 - .../gcc.target/arm/crypto-vsha1mq_u32.c | 1 - .../gcc.target/arm/crypto-vsha1pq_u32.c | 1 - 5 files changed, 82 insertions(+), 22 deletions(-) diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md index 603bdc1ab828..131e361aead9 100644 --- a/gcc/config/arm/neon.md +++ b/gcc/config/arm/neon.md @@ -3526,26 +3526,89 @@ if (BYTES_BIG_ENDIAN) (set_attr "type" "multiple")] ) -(define_insn "neon_vdup_lane<mode>_internal" - [(set (match_operand:VDQW 0 "s_register_operand" "=w") - (vec_duplicate:VDQW - (vec_select:<V_elem> - (match_operand:<V_double_vector_mode> 1 "s_register_operand" "w") - (parallel [(match_operand:SI 2 "immediate_operand" "i")]))))] +(define_insn_and_split "neon_vdup_lane<mode>_internal" + [(set (match_operand:VDQW 0 "s_register_operand" "=w,w") + (vec_duplicate:VDQW + (vec_select:<V_elem> + (match_operand:<V_double_vector_mode> 1 "s_register_operand" "w,r") + (parallel [(match_operand:SI 2 "immediate_operand" "i,i")])))) + (clobber (match_scratch:<V_elem> 3 "=X,r"))] "TARGET_NEON" -{ - if (BYTES_BIG_ENDIAN) - { - int elt = INTVAL (operands[2]); + { + if (REGNO (operands[1]) <= LAST_ARM_REGNUM) + return "#"; + if (BYTES_BIG_ENDIAN) + { + int elt = INTVAL (operands[2]); + elt = GET_MODE_NUNITS (<V_double_vector_mode>mode) - 1 - elt; + operands[2] = GEN_INT (elt); + } + if (<Is_d_reg>) + return "vdup.<V_sz_elem>\t%P0, %P1[%c2]"; + else + return "vdup.<V_sz_elem>\t%q0, %P1[%c2]"; + } + "&& REGNO (operands[1]) <= LAST_ARM_REGNUM" + [(set (match_dup 0) + (vec_duplicate:VDQW (match_dup 3)))] + { + unsigned HOST_WIDE_INT elt = UINTVAL (operands[2]); + if (BYTES_BIG_ENDIAN) elt = GET_MODE_NUNITS (<V_double_vector_mode>mode) - 1 - elt; - operands[2] = GEN_INT (elt); - } - if (<Is_d_reg>) - return "vdup.<V_sz_elem>\t%P0, %P1[%c2]"; - else - return "vdup.<V_sz_elem>\t%q0, %P1[%c2]"; -} - [(set_attr "type" "neon_dup<q>")] + unsigned HOST_WIDE_INT size = GET_MODE_SIZE (<V_elem>mode); + int base_regno = REGNO (operands[1]); + int regno = (base_regno + + subreg_regno_offset (base_regno, <V_double_vector_mode>mode, + elt * size, SImode)); + unsigned HOST_WIDE_INT offset = (elt * size) % GET_MODE_SIZE (SImode); + if (offset != 0) + { + gcc_assert (offset < 4); + rtx reg = gen_rtx_REG (SImode, regno); + rtx shift = gen_rtx_LSHIFTRT (SImode, reg, + GEN_INT (offset * BITS_PER_UNIT)); + emit_move_insn (gen_rtx_SUBREG (SImode, operands[3], 0), + shift); + } + else + operands[3] = gen_rtx_REG (<V_elem>mode, regno); + } + [(set_attr "length" "4,8") + (set_attr "type" "neon_dup<q>")] +) + +; There isn't an intrinsic for this, but the compiler can generate it +; idomatically from other operations. +(define_insn_and_split "neon_vdupq_lane<mode>_internal" + [(set (match_operand:VQ2BF 0 "s_register_operand" "=w,w") + (vec_duplicate:VQ2BF + (vec_select:<V_elem> + (match_operand:VQ2BF 1 "s_register_operand" "w,r") + (parallel [(match_operand:SI 2 "immediate_operand" "i,i")])))) + (clobber (match_scratch:<V_elem> 3 "=X,r"))] + "TARGET_NEON" + "#" + "" ;; && reload_completed" + [(parallel + [(set (match_dup 0) + (vec_duplicate:VQ2BF + (vec_select:<V_elem> (match_dup 1) (parallel [(match_dup 2)])))) + (clobber (match_dup 3))])] + { + HOST_WIDE_INT elt = INTVAL (operands[2]); + if (elt >= GET_MODE_NUNITS (<MODE>mode) / 2) + { + elt -= GET_MODE_NUNITS (<MODE>mode) / 2; + operands[1] = simplify_gen_subreg (<V_HALF>mode, operands[1], + <MODE>mode, + GET_MODE_SIZE (<V_HALF>mode)); + operands[2] = GEN_INT (elt); + } + else + operands[1] = gen_lowpart (<V_HALF>mode, operands[1]); + } + [(set_attr "type" "neon_dup<q>") + (set_attr "length" "4,8")] ) (define_insn "neon_vdup_lane<mode>_internal" diff --git a/gcc/testsuite/gcc.target/arm/crypto-vsha1cq_u32.c b/gcc/testsuite/gcc.target/arm/crypto-vsha1cq_u32.c index e2835cf4122f..82eb2e3749a0 100644 --- a/gcc/testsuite/gcc.target/arm/crypto-vsha1cq_u32.c +++ b/gcc/testsuite/gcc.target/arm/crypto-vsha1cq_u32.c @@ -32,4 +32,4 @@ TEST_SHA1C_VEC_SELECT (GET_LANE) /* { dg-final { scan-assembler-times {sha1c.32\tq[0-9]+, q[0-9]+} 5 } } */ /* { dg-final { scan-assembler-times {vdup.32\tq[0-9]+, (?:r[0-9]+|d[0-9]+\[[0-9]+\])} 4 { xfail { arm_thumb2 && arm_hf_eabi } } } } */ -/* { dg-final { scan-assembler-times {vmov.32\tr[0-9]+, d[0-9]+\[[0-9]+\]} 3 } } */ + diff --git a/gcc/testsuite/gcc.target/arm/crypto-vsha1h_u32.c b/gcc/testsuite/gcc.target/arm/crypto-vsha1h_u32.c index c67048ab3633..a4e9a48698c3 100644 --- a/gcc/testsuite/gcc.target/arm/crypto-vsha1h_u32.c +++ b/gcc/testsuite/gcc.target/arm/crypto-vsha1h_u32.c @@ -28,4 +28,3 @@ TEST_SHA1H_VEC_SELECT (GET_LANE) /* { dg-final { scan-assembler-times {sha1h.32\tq[0-9]+, q[0-9]+} 5 } } */ /* { dg-final { scan-assembler-times {vdup.32\tq[0-9]+, (?:r[0-9]+|d[0-9]+\[[0-9]+\])} 4 { xfail { arm_thumb2 && arm_hf_eabi } } } } */ -/* { dg-final { scan-assembler-times {vmov.32\tr[0-9]+, d[0-9]+\[[0-9]+\]} 3 } } */ diff --git a/gcc/testsuite/gcc.target/arm/crypto-vsha1mq_u32.c b/gcc/testsuite/gcc.target/arm/crypto-vsha1mq_u32.c index 967b682de27f..d1f30d647e36 100644 --- a/gcc/testsuite/gcc.target/arm/crypto-vsha1mq_u32.c +++ b/gcc/testsuite/gcc.target/arm/crypto-vsha1mq_u32.c @@ -32,4 +32,3 @@ TEST_SHA1M_VEC_SELECT (GET_LANE) /* { dg-final { scan-assembler-times {sha1m.32\tq[0-9]+, q[0-9]+} 5 } } */ /* { dg-final { scan-assembler-times {vdup.32\tq[0-9]+, (?:r[0-9]+|d[0-9]+\[[0-9]+\])} 4 { xfail { arm_thumb2 && arm_hf_eabi } } } } */ -/* { dg-final { scan-assembler-times {vmov.32\tr[0-9]+, d[0-9]+\[[0-9]+\]} 3 } } */ diff --git a/gcc/testsuite/gcc.target/arm/crypto-vsha1pq_u32.c b/gcc/testsuite/gcc.target/arm/crypto-vsha1pq_u32.c index 09e763256961..43425f3d5ecf 100644 --- a/gcc/testsuite/gcc.target/arm/crypto-vsha1pq_u32.c +++ b/gcc/testsuite/gcc.target/arm/crypto-vsha1pq_u32.c @@ -32,4 +32,3 @@ TEST_SHA1P_VEC_SELECT (GET_LANE) /* { dg-final { scan-assembler-times {sha1p.32\tq[0-9]+, q[0-9]+} 5 } } */ /* { dg-final { scan-assembler-times {vdup.32\tq[0-9]+, (?:r[0-9]+|d[0-9]+\[[0-9]+\])} 4 { xfail { arm_thumb2 && arm_hf_eabi } } } } */ -/* { dg-final { scan-assembler-times {vmov.32\tr[0-9]+, d[0-9]+\[[0-9]+\]} 3 } } */ -- 2.54.0