OSDN Git Service

2009-10-14 Daniel Gutson <dgutson@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / neon.md
index 06b9b3c..7d1ef11 100644 (file)
@@ -1,12 +1,12 @@
 ;; ARM NEON coprocessor Machine Description
-;; Copyright (C) 2006 Free Software Foundation, Inc.
+;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 ;; Written by CodeSourcery.
 ;;
 ;; This file is part of GCC.
 ;;
 ;; GCC is free software; you can redistribute it and/or modify it
 ;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 ;;
 ;; GCC is distributed in the hope that it will be useful, but
@@ -15,9 +15,8 @@
 ;; General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GCC; see the file COPYING.  If not, write to the Free
-;; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-;; 02110-1301, USA.
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
 
 ;; Constants for unspecs.
 (define_constants
    (UNSPEC_VZIP2               204)])
 
 ;; Double-width vector modes.
-(define_mode_macro VD [V8QI V4HI V2SI V2SF])
+(define_mode_iterator VD [V8QI V4HI V2SI V2SF])
 
 ;; Double-width vector modes plus 64-bit elements.
-(define_mode_macro VDX [V8QI V4HI V2SI V2SF DI])
+(define_mode_iterator VDX [V8QI V4HI V2SI V2SF DI])
 
 ;; Same, without floating-point elements.
-(define_mode_macro VDI [V8QI V4HI V2SI])
+(define_mode_iterator VDI [V8QI V4HI V2SI])
 
 ;; Quad-width vector modes.
-(define_mode_macro VQ [V16QI V8HI V4SI V4SF])
+(define_mode_iterator VQ [V16QI V8HI V4SI V4SF])
 
 ;; Quad-width vector modes plus 64-bit elements.
-(define_mode_macro VQX [V16QI V8HI V4SI V4SF V2DI])
+(define_mode_iterator VQX [V16QI V8HI V4SI V4SF V2DI])
 
 ;; Same, without floating-point elements.
-(define_mode_macro VQI [V16QI V8HI V4SI])
+(define_mode_iterator VQI [V16QI V8HI V4SI])
 
 ;; Same, with TImode added, for moves.
-(define_mode_macro VQXMOV [V16QI V8HI V4SI V4SF V2DI TI])
+(define_mode_iterator VQXMOV [V16QI V8HI V4SI V4SF V2DI TI])
 
 ;; Opaque structure types wider than TImode.
-(define_mode_macro VSTRUCT [EI OI CI XI])
+(define_mode_iterator VSTRUCT [EI OI CI XI])
 
 ;; Number of instructions needed to load/store struct elements. FIXME!
 (define_mode_attr V_slen [(EI "2") (OI "2") (CI "3") (XI "4")])
 
 ;; Opaque structure types used in table lookups (except vtbl1/vtbx1).
-(define_mode_macro VTAB [TI EI OI])
+(define_mode_iterator VTAB [TI EI OI])
 
 ;; vtbl<n> suffix for above modes.
 (define_mode_attr VTAB_n [(TI "2") (EI "3") (OI "4")])
 
 ;; Widenable modes.
-(define_mode_macro VW [V8QI V4HI V2SI])
+(define_mode_iterator VW [V8QI V4HI V2SI])
 
 ;; Narrowable modes.
-(define_mode_macro VN [V8HI V4SI V2DI])
+(define_mode_iterator VN [V8HI V4SI V2DI])
 
 ;; All supported vector modes (except singleton DImode).
-(define_mode_macro VDQ [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF V2DI])
+(define_mode_iterator VDQ [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF V2DI])
 
 ;; All supported vector modes (except those with 64-bit integer elements).
-(define_mode_macro VDQW [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF])
+(define_mode_iterator VDQW [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF])
 
 ;; Supported integer vector modes (not 64 bit elements).
-(define_mode_macro VDQIW [V8QI V16QI V4HI V8HI V2SI V4SI])
+(define_mode_iterator VDQIW [V8QI V16QI V4HI V8HI V2SI V4SI])
 
 ;; Supported integer vector modes (not singleton DI)
-(define_mode_macro VDQI [V8QI V16QI V4HI V8HI V2SI V4SI V2DI])
+(define_mode_iterator VDQI [V8QI V16QI V4HI V8HI V2SI V4SI V2DI])
 
 ;; Vector modes, including 64-bit integer elements.
-(define_mode_macro VDQX [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF DI V2DI])
+(define_mode_iterator VDQX [V8QI V16QI V4HI V8HI V2SI V4SI V2SF V4SF DI V2DI])
 
 ;; Vector modes including 64-bit integer elements, but no floats.
-(define_mode_macro VDQIX [V8QI V16QI V4HI V8HI V2SI V4SI DI V2DI])
+(define_mode_iterator VDQIX [V8QI V16QI V4HI V8HI V2SI V4SI DI V2DI])
 
 ;; Vector modes for float->int conversions.
-(define_mode_macro VCVTF [V2SF V4SF])
+(define_mode_iterator VCVTF [V2SF V4SF])
 
 ;; Vector modes form int->float conversions.
-(define_mode_macro VCVTI [V2SI V4SI])
+(define_mode_iterator VCVTI [V2SI V4SI])
 
 ;; Vector modes for doubleword multiply-accumulate, etc. insns.
-(define_mode_macro VMD [V4HI V2SI V2SF])
+(define_mode_iterator VMD [V4HI V2SI V2SF])
 
 ;; Vector modes for quadword multiply-accumulate, etc. insns.
-(define_mode_macro VMQ [V8HI V4SI V4SF])
+(define_mode_iterator VMQ [V8HI V4SI V4SF])
 
 ;; Above modes combined.
-(define_mode_macro VMDQ [V4HI V2SI V2SF V8HI V4SI V4SF])
+(define_mode_iterator VMDQ [V4HI V2SI V2SF V8HI V4SI V4SF])
 
 ;; As VMD, but integer modes only.
-(define_mode_macro VMDI [V4HI V2SI])
+(define_mode_iterator VMDI [V4HI V2SI])
 
 ;; As VMQ, but integer modes only.
-(define_mode_macro VMQI [V8HI V4SI])
+(define_mode_iterator VMQI [V8HI V4SI])
 
 ;; Above modes combined.
-(define_mode_macro VMDQI [V4HI V2SI V8HI V4SI])
+(define_mode_iterator VMDQI [V4HI V2SI V8HI V4SI])
 
 ;; Modes with 8-bit and 16-bit elements.
-(define_mode_macro VX [V8QI V4HI V16QI V8HI])
+(define_mode_iterator VX [V8QI V4HI V16QI V8HI])
 
 ;; Modes with 8-bit elements.
-(define_mode_macro VE [V8QI V16QI])
+(define_mode_iterator VE [V8QI V16QI])
 
 ;; Modes with 64-bit elements only.
-(define_mode_macro V64 [DI V2DI])
+(define_mode_iterator V64 [DI V2DI])
 
 ;; Modes with 32-bit elements only.
-(define_mode_macro V32 [V2SI V2SF V4SI V4SF])
+(define_mode_iterator V32 [V2SI V2SF V4SI V4SF])
 
 ;; (Opposite) mode to convert to/from for above conversions.
 (define_mode_attr V_CVTTO [(V2SI "V2SF") (V2SF "V2SI")
                           (V2SF "SF") (V4SF "SF")
                           (DI "DI")   (V2DI "DI")])
 
+;; Element modes for vector extraction, padded up to register size.
+
+(define_mode_attr V_ext [(V8QI "SI") (V16QI "SI")
+                        (V4HI "SI") (V8HI "SI")
+                        (V2SI "SI") (V4SI "SI")
+                        (V2SF "SF") (V4SF "SF")
+                        (DI "DI") (V2DI "DI")])
+
 ;; Mode of pair of elements for each vector mode, to define transfer
 ;; size for structure lane/dup loads and stores.
 (define_mode_attr V_two_elem [(V8QI "HI") (V16QI "HI")
                           (DI   "ti") (V2DI  "oi")])
 
 ;; Operations on two halves of a quadword vector.
-(define_code_macro vqh_ops [plus smin smax umin umax])
+(define_code_iterator vqh_ops [plus smin smax umin umax])
 
 ;; Same, without unsigned variants (for use with *SFmode pattern).
-(define_code_macro vqhs_ops [plus smin smax])
+(define_code_iterator vqhs_ops [plus smin smax])
 
 ;; Assembler mnemonics for above codes.
 (define_code_attr VQH_mnem [(plus "vadd") (smin "vmin") (smax "vmax")
 ;; neon_type attribute definitions.
 (define_attr "vqh_mnem" "vadd,vmin,vmax" (const_string "vadd"))
 
-;; Classification of NEON instructions for scheduling purposes.
-;; Do not set this attribute and the "type" attribute together in
-;; any one instruction pattern.
-(define_attr "neon_type"
-   "neon_int_1,\
-   neon_int_2,\
-   neon_int_3,\
-   neon_int_4,\
-   neon_int_5,\
-   neon_vqneg_vqabs,\
-   neon_vmov,\
-   neon_vaba,\
-   neon_vsma,\
-   neon_vaba_qqq,\
-   neon_mul_ddd_8_16_qdd_16_8_long_32_16_long,\
-   neon_mul_qqq_8_16_32_ddd_32,\
-   neon_mul_qdd_64_32_long_qqd_16_ddd_32_scalar_64_32_long_scalar,\
-   neon_mla_ddd_8_16_qdd_16_8_long_32_16_long,\
-   neon_mla_qqq_8_16,\
-   neon_mla_ddd_32_qqd_16_ddd_32_scalar_qdd_64_32_long_scalar_qdd_64_32_long,\
-   neon_mla_qqq_32_qqd_32_scalar,\
-   neon_mul_ddd_16_scalar_32_16_long_scalar,\
-   neon_mul_qqd_32_scalar,\
-   neon_mla_ddd_16_scalar_qdd_32_16_long_scalar,\
-   neon_shift_1,\
-   neon_shift_2,\
-   neon_shift_3,\
-   neon_vshl_ddd,\
-   neon_vqshl_vrshl_vqrshl_qqq,\
-   neon_vsra_vrsra,\
-   neon_fp_vadd_ddd_vabs_dd,\
-   neon_fp_vadd_qqq_vabs_qq,\
-   neon_fp_vsum,\
-   neon_fp_vmul_ddd,\
-   neon_fp_vmul_qqd,\
-   neon_fp_vmla_ddd,\
-   neon_fp_vmla_qqq,\
-   neon_fp_vmla_ddd_scalar,\
-   neon_fp_vmla_qqq_scalar,\
-   neon_fp_vrecps_vrsqrts_ddd,\
-   neon_fp_vrecps_vrsqrts_qqq,\
-   neon_bp_simple,\
-   neon_bp_2cycle,\
-   neon_bp_3cycle,\
-   neon_ldr,\
-   neon_str,\
-   neon_vld1_1_2_regs,\
-   neon_vld1_3_4_regs,\
-   neon_vld2_2_regs_vld1_vld2_all_lanes,\
-   neon_vld2_4_regs,\
-   neon_vld3_vld4,\
-   neon_vst1_1_2_regs_vst2_2_regs,\
-   neon_vst1_3_4_regs,\
-   neon_vst2_4_regs_vst3_vst4,\
-   neon_vst3_vst4,\
-   neon_vld1_vld2_lane,\
-   neon_vld3_vld4_lane,\
-   neon_vst1_vst2_lane,\
-   neon_vst3_vst4_lane,\
-   neon_vld3_vld4_all_lanes,\
-   neon_mcr,\
-   neon_mcr_2_mcrr,\
-   neon_mrc,\
-   neon_mrrc,\
-   neon_ldm_2,\
-   neon_stm_2,\
-   none"
- (const_string "none"))
-
-;; Predicates used for setting the above attribute.
+;; Predicates used for setting neon_type
 
 (define_mode_attr Is_float_mode [(V8QI "false") (V16QI "false")
                                 (V4HI "false") (V8HI "false")
 
   /* FIXME: If the memory layout is changed in big-endian mode, output_move_vfp
      below must be changed to output_move_neon (which will use the
-     element/structure loads/stores), and the constraint changed to 'Un' instead
+     element/structure loads/stores), and the constraint changed to 'Um' instead
      of 'Uv'.  */
 
   switch (which_alternative)
     default: gcc_unreachable ();
     }
 }
-  [(set_attr "length" "<V_slen>,<V_slen>,<V_slen>")])
+  [(set_attr "neon_type" "neon_int_1,neon_stm_2,neon_ldm_2")
+   (set_attr "length" "<V_slen>,<V_slen>,<V_slen>")])
 
 (define_split
   [(set (match_operand:EI 0 "s_register_operand" "")
   neon_disambiguate_copy (operands, dest, src, 4);
 })
 
-(define_insn "vec_set<mode>"
-  [(set (match_operand:VD 0 "s_register_operand" "+w")
+(define_insn "vec_set<mode>_internal"
+  [(set (match_operand:VD 0 "s_register_operand" "=w")
         (vec_merge:VD
-          (match_operand:VD 3 "s_register_operand" "0")
           (vec_duplicate:VD
             (match_operand:<V_elem> 1 "s_register_operand" "r"))
-          (ashift:SI (const_int 1)
-                     (match_operand:SI 2 "immediate_operand" "i"))))]
+          (match_operand:VD 3 "s_register_operand" "0")
+          (match_operand:SI 2 "immediate_operand" "i")))]
   "TARGET_NEON"
-  "vmov%?.<V_uf_sclr>\t%P0[%c2], %1"
+{
+  int elt = ffs ((int) INTVAL (operands[2]) - 1);
+  if (BYTES_BIG_ENDIAN)
+    elt = GET_MODE_NUNITS (<MODE>mode) - 1 - elt;
+  operands[2] = GEN_INT (elt);
+  
+  return "vmov%?.<V_uf_sclr>\t%P0[%c2], %1";
+}
   [(set_attr "predicable" "yes")
-   (set_attr "neon_type" "neon_mcr")]
-)
+   (set_attr "neon_type" "neon_mcr")])
 
-(define_insn "vec_set<mode>"
-  [(set (match_operand:VQ 0 "s_register_operand" "+w")
+(define_insn "vec_set<mode>_internal"
+  [(set (match_operand:VQ 0 "s_register_operand" "=w")
         (vec_merge:VQ
-          (match_operand:VQ 3 "s_register_operand" "0")
           (vec_duplicate:VQ
             (match_operand:<V_elem> 1 "s_register_operand" "r"))
-          (ashift:SI (const_int 1)
-                    (match_operand:SI 2 "immediate_operand" "i"))))]
+          (match_operand:VQ 3 "s_register_operand" "0")
+          (match_operand:SI 2 "immediate_operand" "i")))]
   "TARGET_NEON"
 {
+  HOST_WIDE_INT elem = ffs ((int) INTVAL (operands[2])) - 1;
   int half_elts = GET_MODE_NUNITS (<MODE>mode) / 2;
-  int elt = INTVAL (operands[2]) % half_elts;
-  int hi = (INTVAL (operands[2]) / half_elts) * 2;
+  int elt = elem % half_elts;
+  int hi = (elem / half_elts) * 2;
   int regno = REGNO (operands[0]);
 
+  if (BYTES_BIG_ENDIAN)
+    elt = half_elts - 1 - elt;
+
   operands[0] = gen_rtx_REG (<V_HALF>mode, regno + hi);
   operands[2] = GEN_INT (elt);
 
    (set_attr "neon_type" "neon_mcr")]
 )
 
-(define_insn "vec_setv2di"
-  [(set (match_operand:V2DI 0 "s_register_operand" "+w")
+(define_insn "vec_setv2di_internal"
+  [(set (match_operand:V2DI 0 "s_register_operand" "=w")
         (vec_merge:V2DI
-          (match_operand:V2DI 3 "s_register_operand" "0")
           (vec_duplicate:V2DI
             (match_operand:DI 1 "s_register_operand" "r"))
-          (ashift:SI (const_int 1)
-                    (match_operand:SI 2 "immediate_operand" "i"))))]
+          (match_operand:V2DI 3 "s_register_operand" "0")
+          (match_operand:SI 2 "immediate_operand" "i")))]
   "TARGET_NEON"
 {
-  int regno = REGNO (operands[0]) + INTVAL (operands[2]);
+  HOST_WIDE_INT elem = ffs ((int) INTVAL (operands[2])) - 1;
+  int regno = REGNO (operands[0]) + 2 * elem;
 
   operands[0] = gen_rtx_REG (DImode, regno);
 
    (set_attr "neon_type" "neon_mcr_2_mcrr")]
 )
 
+(define_expand "vec_set<mode>"
+  [(match_operand:VDQ 0 "s_register_operand" "")
+   (match_operand:<V_elem> 1 "s_register_operand" "")
+   (match_operand:SI 2 "immediate_operand" "")]
+  "TARGET_NEON"
+{
+  HOST_WIDE_INT elem = (HOST_WIDE_INT) 1 << INTVAL (operands[2]);
+  emit_insn (gen_vec_set<mode>_internal (operands[0], operands[1],
+                                        GEN_INT (elem), operands[0]));
+  DONE;
+})
+
 (define_insn "vec_extract<mode>"
   [(set (match_operand:<V_elem> 0 "s_register_operand" "=r")
         (vec_select:<V_elem>
           (match_operand:VD 1 "s_register_operand" "w")
           (parallel [(match_operand:SI 2 "immediate_operand" "i")])))]
   "TARGET_NEON"
-  "vmov%?.<V_uf_sclr>\t%0, %P1[%c2]"
+{
+  if (BYTES_BIG_ENDIAN)
+    {
+      int elt = INTVAL (operands[2]);
+      elt = GET_MODE_NUNITS (<MODE>mode) - 1 - elt;
+      operands[2] = GEN_INT (elt);
+    }
+  return "vmov%?.<V_uf_sclr>\t%0, %P1[%c2]";
+}
   [(set_attr "predicable" "yes")
    (set_attr "neon_type" "neon_bp_simple")]
 )
   int hi = (INTVAL (operands[2]) / half_elts) * 2;
   int regno = REGNO (operands[1]);
 
+  if (BYTES_BIG_ENDIAN)
+    elt = half_elts - 1 - elt;
+
   operands[1] = gen_rtx_REG (<V_HALF>mode, regno + hi);
   operands[2] = GEN_INT (elt);
 
                                     (const_string "neon_mul_qqq_8_16_32_ddd_32")))))]
 )
 
+(define_insn "*mul<mode>3add<mode>_neon"
+  [(set (match_operand:VDQ 0 "s_register_operand" "=w")
+        (plus:VDQ (mult:VDQ (match_operand:VDQ 2 "s_register_operand" "w")
+                            (match_operand:VDQ 3 "s_register_operand" "w"))
+                 (match_operand:VDQ 1 "s_register_operand" "0")))]
+  "TARGET_NEON"
+  "vmla.<V_if_elem>\t%<V_reg>0, %<V_reg>2, %<V_reg>3"
+  [(set (attr "neon_type")
+      (if_then_else (ne (symbol_ref "<Is_float_mode>") (const_int 0))
+                    (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+                                  (const_string "neon_fp_vmla_ddd")
+                                  (const_string "neon_fp_vmla_qqq"))
+                    (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+                                  (if_then_else
+                                    (ne (symbol_ref "<Scalar_mul_8_16>") (const_int 0))
+                                    (const_string "neon_mla_ddd_8_16_qdd_16_8_long_32_16_long")
+                                    (const_string "neon_mla_ddd_32_qqd_16_ddd_32_scalar_qdd_64_32_long_scalar_qdd_64_32_long"))
+                                  (if_then_else (ne (symbol_ref "<Scalar_mul_8_16>") (const_int 0))
+                                    (const_string "neon_mla_qqq_8_16")
+                                    (const_string "neon_mla_qqq_32_qqd_32_scalar")))))]
+)
+
+(define_insn "*mul<mode>3neg<mode>add<mode>_neon"
+  [(set (match_operand:VDQ 0 "s_register_operand" "=w")
+        (minus:VDQ (match_operand:VDQ 1 "s_register_operand" "0")
+                   (mult:VDQ (match_operand:VDQ 2 "s_register_operand" "w")
+                             (match_operand:VDQ 3 "s_register_operand" "w"))))]
+  "TARGET_NEON"
+  "vmls.<V_if_elem>\t%<V_reg>0, %<V_reg>2, %<V_reg>3"
+  [(set (attr "neon_type")
+      (if_then_else (ne (symbol_ref "<Is_float_mode>") (const_int 0))
+                    (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+                                  (const_string "neon_fp_vmla_ddd")
+                                  (const_string "neon_fp_vmla_qqq"))
+                    (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+                                  (if_then_else
+                                    (ne (symbol_ref "<Scalar_mul_8_16>") (const_int 0))
+                                    (const_string "neon_mla_ddd_8_16_qdd_16_8_long_32_16_long")
+                                    (const_string "neon_mla_ddd_32_qqd_16_ddd_32_scalar_qdd_64_32_long_scalar_qdd_64_32_long"))
+                                  (if_then_else (ne (symbol_ref "<Scalar_mul_8_16>") (const_int 0))
+                                    (const_string "neon_mla_qqq_8_16")
+                                    (const_string "neon_mla_qqq_32_qqd_32_scalar")))))]
+)
+
 (define_insn "ior<mode>3"
   [(set (match_operand:VDQ 0 "s_register_operand" "=w,w")
        (ior:VDQ (match_operand:VDQ 1 "s_register_operand" "w,0")
 ; generic vectorizer code.  It ends up creating a V2DI constructor with
 ; SImode elements.
 
-(define_insn "ashl<mode>3"
+(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")))]
                     (const_string "neon_shift_3")))]
 )
 
-(define_expand "ashr<mode>3"
+(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" "")))]
   DONE;
 })
 
-(define_expand "lshr<mode>3"
+(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" "")))]
   DONE;
 })
 
-;; FIXME: 32-bit element sizes are a bit funky (should be output as .32 not
-;; .u32), but the assembler should cope with that.
-
-(define_insn "neon_vget_lane<mode>"
-  [(set (match_operand:<V_elem> 0 "s_register_operand" "=r")
-       (unspec:<V_elem> [(match_operand:VD 1 "s_register_operand" "w")
-                         (match_operand:SI 2 "immediate_operand" "i")
-                          (match_operand:SI 3 "immediate_operand" "i")]
-                         UNSPEC_VGET_LANE))]
+(define_insn "neon_vget_lane<mode>_sext_internal"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (sign_extend:SI
+         (vec_select:<V_elem>
+           (match_operand:VD 1 "s_register_operand" "w")
+           (parallel [(match_operand:SI 2 "immediate_operand" "i")]))))]
   "TARGET_NEON"
 {
-  neon_lane_bounds (operands[2], 0, GET_MODE_NUNITS (<MODE>mode));
-  return "vmov%?.%t3%#<V_sz_elem>\t%0, %P1[%c2]";
+  if (BYTES_BIG_ENDIAN)
+    {
+      int elt = INTVAL (operands[2]);
+      elt = GET_MODE_NUNITS (<MODE>mode) - 1 - elt;
+      operands[2] = GEN_INT (elt);
+    }
+  return "vmov%?.s<V_sz_elem>\t%0, %P1[%c2]";
 }
   [(set_attr "predicable" "yes")
    (set_attr "neon_type" "neon_bp_simple")]
 )
 
-; Operand 2 (lane number) is ignored because we can only extract the zeroth lane
-; with this insn. Operand 3 (info word) is ignored because it does nothing
-; useful with 64-bit elements.
+(define_insn "neon_vget_lane<mode>_zext_internal"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (zero_extend:SI
+         (vec_select:<V_elem>
+           (match_operand:VD 1 "s_register_operand" "w")
+           (parallel [(match_operand:SI 2 "immediate_operand" "i")]))))]
+  "TARGET_NEON"
+{
+  if (BYTES_BIG_ENDIAN)
+    {
+      int elt = INTVAL (operands[2]);
+      elt = GET_MODE_NUNITS (<MODE>mode) - 1 - elt;
+      operands[2] = GEN_INT (elt);
+    }
+  return "vmov%?.u<V_sz_elem>\t%0, %P1[%c2]";
+}
+  [(set_attr "predicable" "yes")
+   (set_attr "neon_type" "neon_bp_simple")]
+)
 
-(define_insn "neon_vget_lanedi"
-  [(set (match_operand:DI 0 "s_register_operand" "=r")
-       (unspec:DI [(match_operand:DI 1 "s_register_operand" "w")
-                   (match_operand:SI 2 "immediate_operand" "i")
-                   (match_operand:SI 3 "immediate_operand" "i")]
-                  UNSPEC_VGET_LANE))]
+(define_insn "neon_vget_lane<mode>_sext_internal"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (sign_extend:SI
+         (vec_select:<V_elem>
+           (match_operand:VQ 1 "s_register_operand" "w")
+           (parallel [(match_operand:SI 2 "immediate_operand" "i")]))))]
   "TARGET_NEON"
 {
-  neon_lane_bounds (operands[2], 0, 1);
-  return "vmov%?\t%Q0, %R0, %P1  @ di";
+  rtx ops[3];
+  int regno = REGNO (operands[1]);
+  unsigned int halfelts = GET_MODE_NUNITS (<MODE>mode) / 2;
+  unsigned int elt = INTVAL (operands[2]);
+  unsigned int elt_adj = elt % halfelts;
+
+  if (BYTES_BIG_ENDIAN)
+    elt_adj = halfelts - 1 - elt_adj;
+
+  ops[0] = operands[0];
+  ops[1] = gen_rtx_REG (<V_HALF>mode, regno + 2 * (elt / halfelts));
+  ops[2] = GEN_INT (elt_adj);
+  output_asm_insn ("vmov%?.s<V_sz_elem>\t%0, %P1[%c2]", ops);
+
+  return "";
 }
   [(set_attr "predicable" "yes")
    (set_attr "neon_type" "neon_bp_simple")]
 )
 
-(define_insn "neon_vget_lane<mode>"
-  [(set (match_operand:<V_elem> 0 "s_register_operand" "=r")
-       (unspec:<V_elem> [(match_operand:VQ 1 "s_register_operand" "w")
-                         (match_operand:SI 2 "immediate_operand" "i")
-                         (match_operand:SI 3 "immediate_operand" "i")]
-                        UNSPEC_VGET_LANE))]
+(define_insn "neon_vget_lane<mode>_zext_internal"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (zero_extend:SI
+         (vec_select:<V_elem>
+           (match_operand:VQ 1 "s_register_operand" "w")
+           (parallel [(match_operand:SI 2 "immediate_operand" "i")]))))]
   "TARGET_NEON"
 {
-  rtx ops[4];
+  rtx ops[3];
   int regno = REGNO (operands[1]);
   unsigned int halfelts = GET_MODE_NUNITS (<MODE>mode) / 2;
   unsigned int elt = INTVAL (operands[2]);
+  unsigned int elt_adj = elt % halfelts;
 
-  neon_lane_bounds (operands[2], 0, halfelts * 2);
+  if (BYTES_BIG_ENDIAN)
+    elt_adj = halfelts - 1 - elt_adj;
 
   ops[0] = operands[0];
   ops[1] = gen_rtx_REG (<V_HALF>mode, regno + 2 * (elt / halfelts));
-  ops[2] = GEN_INT (elt % halfelts);
-  ops[3] = operands[3];
-  output_asm_insn ("vmov%?.%t3%#<V_sz_elem>\t%0, %P1[%c2]", ops);
+  ops[2] = GEN_INT (elt_adj);
+  output_asm_insn ("vmov%?.u<V_sz_elem>\t%0, %P1[%c2]", ops);
 
   return "";
 }
    (set_attr "neon_type" "neon_bp_simple")]
 )
 
+(define_expand "neon_vget_lane<mode>"
+  [(match_operand:<V_ext> 0 "s_register_operand" "")
+   (match_operand:VDQW 1 "s_register_operand" "")
+   (match_operand:SI 2 "immediate_operand" "")
+   (match_operand:SI 3 "immediate_operand" "")]
+  "TARGET_NEON"
+{
+  HOST_WIDE_INT magic = INTVAL (operands[3]);
+  rtx insn;
+
+  neon_lane_bounds (operands[2], 0, GET_MODE_NUNITS (<MODE>mode));
+
+  if (BYTES_BIG_ENDIAN)
+    {
+      /* The intrinsics are defined in terms of a model where the
+        element ordering in memory is vldm order, whereas the generic
+        RTL is defined in terms of a model where the element ordering
+        in memory is array order.  Convert the lane number to conform
+        to this model.  */
+      unsigned int elt = INTVAL (operands[2]);
+      unsigned int reg_nelts
+       = 64 / GET_MODE_BITSIZE (GET_MODE_INNER (<MODE>mode));
+      elt ^= reg_nelts - 1;
+      operands[2] = GEN_INT (elt);
+    }
+
+  if ((magic & 3) == 3 || GET_MODE_BITSIZE (GET_MODE_INNER (<MODE>mode)) == 32)
+    insn = gen_vec_extract<mode> (operands[0], operands[1], operands[2]);
+  else
+    {
+      if ((magic & 1) != 0)
+       insn = gen_neon_vget_lane<mode>_sext_internal (operands[0], operands[1],
+                                                      operands[2]);
+      else
+       insn = gen_neon_vget_lane<mode>_zext_internal (operands[0], operands[1],
+                                                      operands[2]);
+    }
+  emit_insn (insn);
+  DONE;
+})
+
+; Operand 3 (info word) is ignored because it does nothing useful with 64-bit
+; elements.
+
+(define_insn "neon_vget_lanedi"
+  [(set (match_operand:DI 0 "s_register_operand" "=r")
+       (unspec:DI [(match_operand:DI 1 "s_register_operand" "w")
+                   (match_operand:SI 2 "immediate_operand" "i")
+                   (match_operand:SI 3 "immediate_operand" "i")]
+                  UNSPEC_VGET_LANE))]
+  "TARGET_NEON"
+{
+  neon_lane_bounds (operands[2], 0, 1);
+  return "vmov%?\t%Q0, %R0, %P1  @ di";
+}
+  [(set_attr "predicable" "yes")
+   (set_attr "neon_type" "neon_bp_simple")]
+)
+
 (define_insn "neon_vget_lanev2di"
   [(set (match_operand:DI 0 "s_register_operand" "=r")
        (unspec:DI [(match_operand:V2DI 1 "s_register_operand" "w")
                          UNSPEC_VSHLL_N))]
   "TARGET_NEON"
 {
-  neon_const_bounds (operands[2], 0, neon_element_bits (<MODE>mode));
+  /* The boundaries are: 0 < imm <= size.  */
+  neon_const_bounds (operands[2], 0, neon_element_bits (<MODE>mode) + 1);
   return "vshll.%T3%#<V_sz_elem>\t%q0, %P1, %2";
 }
   [(set_attr "neon_type" "neon_shift_1")]