From 28131dfe443772ac5e625914cc341f5be9f8bbc7 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Thu, 29 Nov 2012 17:51:40 +0000 Subject: [PATCH] re PR target/55073 (Wrong Neon code generation at -O2 caused by -fschedule-insns) PR target/55073 * arm/neon.md (neon_vtrn_internal): Split into expand and insn patterns. Re-order insn arguments to tie inputs to outputs. (neon_vzip_internal): Likewise. (neon_vuzp_internal): Likewise. * gcc.target/arm/pr55073.C: New test. From-SVN: r193943 --- gcc/ChangeLog | 9 ++++ gcc/config/arm/neon.md | 69 ++++++++++++++++++------ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/arm/pr55073.C | 74 ++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/pr55073.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8ca3588b3ee..7560e28eb87 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2012-11-29 Richard Earnshaw + + PR target/55073 + * arm/neon.md (neon_vtrn_internal): Split into expand + and insn patterns. Re-order insn arguments to tie inputs to + outputs. + (neon_vzip_internal): Likewise. + (neon_vuzp_internal): Likewise. + 2012-11-29 Marc Glisse PR c++/53094 diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md index 8f84795334b..0822049a3e9 100644 --- a/gcc/config/arm/neon.md +++ b/gcc/config/arm/neon.md @@ -4411,16 +4411,29 @@ [(set_attr "neon_type" "neon_bp_3cycle")] ) -(define_insn "neon_vtrn_internal" +(define_expand "neon_vtrn_internal" + [(parallel + [(set (match_operand:VDQW 0 "s_register_operand" "") + (unspec:VDQW [(match_operand:VDQW 1 "s_register_operand" "") + (match_operand:VDQW 2 "s_register_operand" "")] + UNSPEC_VTRN1)) + (set (match_operand:VDQW 3 "s_register_operand" "") + (unspec:VDQW [(match_dup 1) (match_dup 2)] UNSPEC_VTRN2))])] + "TARGET_NEON" + "" +) + +;; Note: Different operand numbering to handle tied registers correctly. +(define_insn "*neon_vtrn_insn" [(set (match_operand:VDQW 0 "s_register_operand" "=w") (unspec:VDQW [(match_operand:VDQW 1 "s_register_operand" "0") - (match_operand:VDQW 2 "s_register_operand" "w")] + (match_operand:VDQW 3 "s_register_operand" "2")] UNSPEC_VTRN1)) - (set (match_operand:VDQW 3 "s_register_operand" "=2") - (unspec:VDQW [(match_dup 1) (match_dup 2)] + (set (match_operand:VDQW 2 "s_register_operand" "=w") + (unspec:VDQW [(match_dup 1) (match_dup 3)] UNSPEC_VTRN2))] "TARGET_NEON" - "vtrn.\t%0, %3" + "vtrn.\t%0, %2" [(set (attr "neon_type") (if_then_else (match_test "") (const_string "neon_bp_simple") @@ -4438,16 +4451,29 @@ DONE; }) -(define_insn "neon_vzip_internal" +(define_expand "neon_vzip_internal" + [(parallel + [(set (match_operand:VDQW 0 "s_register_operand" "") + (unspec:VDQW [(match_operand:VDQW 1 "s_register_operand" "") + (match_operand:VDQW 2 "s_register_operand" "")] + UNSPEC_VZIP1)) + (set (match_operand:VDQW 3 "s_register_operand" "") + (unspec:VDQW [(match_dup 1) (match_dup 2)] UNSPEC_VZIP2))])] + "TARGET_NEON" + "" +) + +;; Note: Different operand numbering to handle tied registers correctly. +(define_insn "*neon_vzip_insn" [(set (match_operand:VDQW 0 "s_register_operand" "=w") (unspec:VDQW [(match_operand:VDQW 1 "s_register_operand" "0") - (match_operand:VDQW 2 "s_register_operand" "w")] + (match_operand:VDQW 3 "s_register_operand" "2")] UNSPEC_VZIP1)) - (set (match_operand:VDQW 3 "s_register_operand" "=2") - (unspec:VDQW [(match_dup 1) (match_dup 2)] + (set (match_operand:VDQW 2 "s_register_operand" "=w") + (unspec:VDQW [(match_dup 1) (match_dup 3)] UNSPEC_VZIP2))] "TARGET_NEON" - "vzip.\t%0, %3" + "vzip.\t%0, %2" [(set (attr "neon_type") (if_then_else (match_test "") (const_string "neon_bp_simple") @@ -4465,16 +4491,29 @@ DONE; }) -(define_insn "neon_vuzp_internal" +(define_expand "neon_vuzp_internal" + [(parallel + [(set (match_operand:VDQW 0 "s_register_operand" "") + (unspec:VDQW [(match_operand:VDQW 1 "s_register_operand" "") + (match_operand:VDQW 2 "s_register_operand" "")] + UNSPEC_VUZP1)) + (set (match_operand:VDQW 3 "s_register_operand" "") + (unspec:VDQW [(match_dup 1) (match_dup 2)] UNSPEC_VUZP2))])] + "TARGET_NEON" + "" +) + +;; Note: Different operand numbering to handle tied registers correctly. +(define_insn "*neon_vuzp_insn" [(set (match_operand:VDQW 0 "s_register_operand" "=w") (unspec:VDQW [(match_operand:VDQW 1 "s_register_operand" "0") - (match_operand:VDQW 2 "s_register_operand" "w")] + (match_operand:VDQW 3 "s_register_operand" "2")] UNSPEC_VUZP1)) - (set (match_operand:VDQW 3 "s_register_operand" "=2") - (unspec:VDQW [(match_dup 1) (match_dup 2)] + (set (match_operand:VDQW 2 "s_register_operand" "=w") + (unspec:VDQW [(match_dup 1) (match_dup 3)] UNSPEC_VUZP2))] "TARGET_NEON" - "vuzp.\t%0, %3" + "vuzp.\t%0, %2" [(set (attr "neon_type") (if_then_else (match_test "") (const_string "neon_bp_simple") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4e623fb7df2..996347b764f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-11-29 Richard Earnshaw + + PR target/55073 + * gcc.target/arm/pr55073.C: New test. + 2012-11-29 Marc Glisse PR c++/53094 diff --git a/gcc/testsuite/gcc.target/arm/pr55073.C b/gcc/testsuite/gcc.target/arm/pr55073.C new file mode 100644 index 00000000000..5575cf77911 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr55073.C @@ -0,0 +1,74 @@ +/* { dg-do run } */ +/* { dg-require-effective-target arm_neon } */ +/* { dg-options "-O2" } */ +/* { dg-add-options arm_neon } */ + +#include +#include + +struct __attribute__((aligned(16))) _v16u8_ { + uint8x16_t val; + _v16u8_() { } + + _v16u8_( const uint8x16_t &src) { val = src; } + _v16u8_( const int16x8_t &src) { val = vreinterpretq_u8_s16(src); } + _v16u8_( const uint32x4_t &src) { val = vreinterpretq_u8_u32(src); } + + operator uint8x16_t () const { return val; } + operator int8x16_t () const { return vreinterpretq_s8_u8 (val); } + operator int16x8_t () const { return vreinterpretq_s16_u8(val); } + operator uint32x4_t () const { return vreinterpretq_u32_u8(val); } + operator int32x4_t () const { return vreinterpretq_s32_u8(val); } +}; +typedef struct _v16u8_ v16u8; +typedef const v16u8 cv16u8; + +typedef v16u8 v16i8; +typedef v16u8 v8i16; +typedef v16u8 v4u32; + +inline v16u8 __attribute__((always_inline)) mergelo( const v16u8 & s, const v16u8 & t ) +{ + uint8x8x2_t r = vzip_u8( vget_low_u8(s), vget_low_u8(t) ); + return vcombine_u8( r.val[0], r.val[1] ); +} + +inline v8i16 __attribute__((always_inline)) unpacklo(const v16i8 & s) +{ + return vmovl_s8( vget_low_s8( s ) ); +} + +const uint32_t __attribute__((aligned(16))) _InA [4] = { 0xFF020001, 0xFF020001, 0xFF000101, 0xFF000101 } ; +const uint32_t __attribute__((aligned(16))) _InB [4] = { 0xFF050002, 0xFF050002, 0xFF000303, 0xFF000203 } ; + +__attribute__((noinline)) v16i8 test_func(void) +{ + v16u8 A = vld1q_u8( (uint8_t*) _InA ); + v16u8 B = vld1q_u8( (uint8_t*) _InB ); + v8i16 r = vdupq_n_s16(2); + + v16u8 _0 = mergelo( A, B ); + v16u8 _1 = mergelo( B, A ); + + v16u8 _2 = mergelo( _0, _1 ); + v16u8 _3 = mergelo( _1, _0 ); + + v8i16 _4 = vsubq_s16( unpacklo( _2 ), r ); + v8i16 _5 = vsubq_s16( unpacklo( _3 ), r ); + + v8i16 ret = vaddq_s16( _4, _5 ); + + return ( ret ); +} + +int main (int argc, char **argv) +{ + v16u8 val = test_func(); + + if (vgetq_lane_u32( val, 0 ) != 0xffffffff + || vgetq_lane_u32( val, 1 ) != 0xffffffff + || vgetq_lane_u32( val, 2 ) != 0xfffcfffc + || vgetq_lane_u32( val, 3 ) != 0xfffcfffc) + abort (); + exit (0); +} -- 2.30.2