/* Machine description for AArch64 architecture.
   Copyright (C) 2012-2013 Free Software Foundation, Inc.
   Contributed by ARM Ltd.

   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 3, or (at your option)
   any later version.

   GCC is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GCC; see the file COPYING3.  If not see
   <http://www.gnu.org/licenses/>.  */

/* In the list below, the BUILTIN_<ITERATOR> macros expand to create
   builtins for each of the modes described by <ITERATOR>.  When adding
   new builtins to this list, a helpful idiom to follow is to add
   a line for each pattern in the md file.  Thus, ADDP, which has one
   pattern defined for the VD_BHSI iterator, and one for DImode, has two
   entries below.

   Parameter 1 is the 'type' of the intrinsic.  This is used to
   describe the type modifiers (for example; unsigned) applied to
   each of the parameters to the intrinsic function.

   Parameter 2 is the name of the intrinsic.  This is appended
   to `__builtin_aarch64_<name><mode>` to give the intrinsic name
   as exported to the front-ends.

   Parameter 3 describes how to map from the name to the CODE_FOR_
   macro holding the RTL pattern for the intrinsic.  This mapping is:
   0 - CODE_FOR_aarch64_<name><mode>
   1-9 - CODE_FOR_<name><mode><1-9>
   10 - CODE_FOR_<name><mode>.  */

  BUILTIN_VD_RE (CREATE, create, 0)
  BUILTIN_VQ_S (GETLANE, get_lane_signed, 0)
  BUILTIN_VDQ (GETLANE, get_lane_unsigned, 0)
  BUILTIN_VDQF (GETLANE, get_lane, 0)
  VAR1 (GETLANE, get_lane, 0, di)
  BUILTIN_VDC (COMBINE, combine, 0)
  BUILTIN_VB (BINOP, pmul, 0)
  BUILTIN_VDQF (UNOP, sqrt, 2)
  BUILTIN_VD_BHSI (BINOP, addp, 0)
  VAR1 (UNOP, addp, 0, di)
  VAR1 (UNOP, clz, 2, v4si)

  BUILTIN_VD_RE (REINTERP, reinterpretdi, 0)
  BUILTIN_VDC (REINTERP, reinterpretv8qi, 0)
  BUILTIN_VDC (REINTERP, reinterpretv4hi, 0)
  BUILTIN_VDC (REINTERP, reinterpretv2si, 0)
  BUILTIN_VDC (REINTERP, reinterpretv2sf, 0)
  BUILTIN_VQ (REINTERP, reinterpretv16qi, 0)
  BUILTIN_VQ (REINTERP, reinterpretv8hi, 0)
  BUILTIN_VQ (REINTERP, reinterpretv4si, 0)
  BUILTIN_VQ (REINTERP, reinterpretv4sf, 0)
  BUILTIN_VQ (REINTERP, reinterpretv2di, 0)
  BUILTIN_VQ (REINTERP, reinterpretv2df, 0)

  BUILTIN_VDQ_I (BINOP, dup_lane, 0)
  BUILTIN_SDQ_I (BINOP, dup_lane, 0)
  /* Implemented by aarch64_<sur>q<r>shl<mode>.  */
  BUILTIN_VSDQ_I (BINOP, sqshl, 0)
  BUILTIN_VSDQ_I (BINOP, uqshl, 0)
  BUILTIN_VSDQ_I (BINOP, sqrshl, 0)
  BUILTIN_VSDQ_I (BINOP, uqrshl, 0)
  /* Implemented by aarch64_<su_optab><optab><mode>.  */
  BUILTIN_VSDQ_I (BINOP, sqadd, 0)
  BUILTIN_VSDQ_I (BINOP, uqadd, 0)
  BUILTIN_VSDQ_I (BINOP, sqsub, 0)
  BUILTIN_VSDQ_I (BINOP, uqsub, 0)
  /* Implemented by aarch64_<sur>qadd<mode>.  */
  BUILTIN_VSDQ_I (BINOP, suqadd, 0)
  BUILTIN_VSDQ_I (BINOP, usqadd, 0)

  /* Implemented by aarch64_get_dreg<VSTRUCT:mode><VDC:mode>.  */
  BUILTIN_VDC (GETLANE, get_dregoi, 0)
  BUILTIN_VDC (GETLANE, get_dregci, 0)
  BUILTIN_VDC (GETLANE, get_dregxi, 0)
  /* Implemented by aarch64_get_qreg<VSTRUCT:mode><VQ:mode>.  */
  BUILTIN_VQ (GETLANE, get_qregoi, 0)
  BUILTIN_VQ (GETLANE, get_qregci, 0)
  BUILTIN_VQ (GETLANE, get_qregxi, 0)
  /* Implemented by aarch64_set_qreg<VSTRUCT:mode><VQ:mode>.  */
  BUILTIN_VQ (SETLANE, set_qregoi, 0)
  BUILTIN_VQ (SETLANE, set_qregci, 0)
  BUILTIN_VQ (SETLANE, set_qregxi, 0)
  /* Implemented by aarch64_ld<VSTRUCT:nregs><VDC:mode>.  */
  BUILTIN_VDC (LOADSTRUCT, ld2, 0)
  BUILTIN_VDC (LOADSTRUCT, ld3, 0)
  BUILTIN_VDC (LOADSTRUCT, ld4, 0)
  /* Implemented by aarch64_ld<VSTRUCT:nregs><VQ:mode>.  */
  BUILTIN_VQ (LOADSTRUCT, ld2, 0)
  BUILTIN_VQ (LOADSTRUCT, ld3, 0)
  BUILTIN_VQ (LOADSTRUCT, ld4, 0)
  /* Implemented by aarch64_st<VSTRUCT:nregs><VDC:mode>.  */
  BUILTIN_VDC (STORESTRUCT, st2, 0)
  BUILTIN_VDC (STORESTRUCT, st3, 0)
  BUILTIN_VDC (STORESTRUCT, st4, 0)
  /* Implemented by aarch64_st<VSTRUCT:nregs><VQ:mode>.  */
  BUILTIN_VQ (STORESTRUCT, st2, 0)
  BUILTIN_VQ (STORESTRUCT, st3, 0)
  BUILTIN_VQ (STORESTRUCT, st4, 0)

  BUILTIN_VQW (BINOP, saddl2, 0)
  BUILTIN_VQW (BINOP, uaddl2, 0)
  BUILTIN_VQW (BINOP, ssubl2, 0)
  BUILTIN_VQW (BINOP, usubl2, 0)
  BUILTIN_VQW (BINOP, saddw2, 0)
  BUILTIN_VQW (BINOP, uaddw2, 0)
  BUILTIN_VQW (BINOP, ssubw2, 0)
  BUILTIN_VQW (BINOP, usubw2, 0)
  /* Implemented by aarch64_<ANY_EXTEND:su><ADDSUB:optab>l<mode>.  */
  BUILTIN_VDW (BINOP, saddl, 0)
  BUILTIN_VDW (BINOP, uaddl, 0)
  BUILTIN_VDW (BINOP, ssubl, 0)
  BUILTIN_VDW (BINOP, usubl, 0)
  /* Implemented by aarch64_<ANY_EXTEND:su><ADDSUB:optab>w<mode>.  */
  BUILTIN_VDW (BINOP, saddw, 0)
  BUILTIN_VDW (BINOP, uaddw, 0)
  BUILTIN_VDW (BINOP, ssubw, 0)
  BUILTIN_VDW (BINOP, usubw, 0)
  /* Implemented by aarch64_<sur>h<addsub><mode>.  */
  BUILTIN_VQ_S (BINOP, shadd, 0)
  BUILTIN_VQ_S (BINOP, uhadd, 0)
  BUILTIN_VQ_S (BINOP, srhadd, 0)
  BUILTIN_VQ_S (BINOP, urhadd, 0)
  /* Implemented by aarch64_<sur><addsub>hn<mode>.  */
  BUILTIN_VQN (BINOP, addhn, 0)
  BUILTIN_VQN (BINOP, raddhn, 0)
  /* Implemented by aarch64_<sur><addsub>hn2<mode>.  */
  BUILTIN_VQN (TERNOP, addhn2, 0)
  BUILTIN_VQN (TERNOP, raddhn2, 0)

  BUILTIN_VSQN_HSDI (UNOP, sqmovun, 0)
  /* Implemented by aarch64_<sur>qmovn<mode>.  */
  BUILTIN_VSQN_HSDI (UNOP, sqmovn, 0)
  BUILTIN_VSQN_HSDI (UNOP, uqmovn, 0)
  /* Implemented by aarch64_s<optab><mode>.  */
  BUILTIN_VSDQ_I_BHSI (UNOP, sqabs, 0)
  BUILTIN_VSDQ_I_BHSI (UNOP, sqneg, 0)

  BUILTIN_VSD_HSI (QUADOP, sqdmlal_lane, 0)
  BUILTIN_VSD_HSI (QUADOP, sqdmlsl_lane, 0)
  BUILTIN_VSD_HSI (QUADOP, sqdmlal_laneq, 0)
  BUILTIN_VSD_HSI (QUADOP, sqdmlsl_laneq, 0)
  BUILTIN_VQ_HSI (TERNOP, sqdmlal2, 0)
  BUILTIN_VQ_HSI (TERNOP, sqdmlsl2, 0)
  BUILTIN_VQ_HSI (QUADOP, sqdmlal2_lane, 0)
  BUILTIN_VQ_HSI (QUADOP, sqdmlsl2_lane, 0)
  BUILTIN_VQ_HSI (QUADOP, sqdmlal2_laneq, 0)
  BUILTIN_VQ_HSI (QUADOP, sqdmlsl2_laneq, 0)
  BUILTIN_VQ_HSI (TERNOP, sqdmlal2_n, 0)
  BUILTIN_VQ_HSI (TERNOP, sqdmlsl2_n, 0)
  /* Implemented by aarch64_sqdml<SBINQOPS:as>l<mode>.  */
  BUILTIN_VSD_HSI (TERNOP, sqdmlal, 0)
  BUILTIN_VSD_HSI (TERNOP, sqdmlsl, 0)
  /* Implemented by aarch64_sqdml<SBINQOPS:as>l_n<mode>.  */
  BUILTIN_VD_HSI (TERNOP, sqdmlal_n, 0)
  BUILTIN_VD_HSI (TERNOP, sqdmlsl_n, 0)

  BUILTIN_VSD_HSI (BINOP, sqdmull, 0)
  BUILTIN_VSD_HSI (TERNOP, sqdmull_lane, 0)
  BUILTIN_VD_HSI (TERNOP, sqdmull_laneq, 0)
  BUILTIN_VD_HSI (BINOP, sqdmull_n, 0)
  BUILTIN_VQ_HSI (BINOP, sqdmull2, 0)
  BUILTIN_VQ_HSI (TERNOP, sqdmull2_lane, 0)
  BUILTIN_VQ_HSI (TERNOP, sqdmull2_laneq, 0)
  BUILTIN_VQ_HSI (BINOP, sqdmull2_n, 0)
  /* Implemented by aarch64_sq<r>dmulh<mode>.  */
  BUILTIN_VSDQ_HSI (BINOP, sqdmulh, 0)
  BUILTIN_VSDQ_HSI (BINOP, sqrdmulh, 0)
  /* Implemented by aarch64_sq<r>dmulh_lane<q><mode>.  */
  BUILTIN_VDQHS (TERNOP, sqdmulh_lane, 0)
  BUILTIN_VDQHS (TERNOP, sqdmulh_laneq, 0)
  BUILTIN_VDQHS (TERNOP, sqrdmulh_lane, 0)
  BUILTIN_VDQHS (TERNOP, sqrdmulh_laneq, 0)
  BUILTIN_SD_HSI (TERNOP, sqdmulh_lane, 0)
  BUILTIN_SD_HSI (TERNOP, sqrdmulh_lane, 0)

  BUILTIN_VSDQ_I_DI (BINOP, ashl, 3)
  /* Implemented by aarch64_<sur>shl<mode>.  */
  BUILTIN_VSDQ_I_DI (BINOP, sshl, 0)
  BUILTIN_VSDQ_I_DI (BINOP, ushl, 0)
  BUILTIN_VSDQ_I_DI (BINOP, srshl, 0)
  BUILTIN_VSDQ_I_DI (BINOP, urshl, 0)

  BUILTIN_VSDQ_I_DI (SHIFTIMM, ashr, 3)
  BUILTIN_VSDQ_I_DI (SHIFTIMM, lshr, 3)
  /* Implemented by aarch64_<sur>shr_n<mode>.  */
  BUILTIN_VSDQ_I_DI (SHIFTIMM, srshr_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTIMM, urshr_n, 0)
  /* Implemented by aarch64_<sur>sra_n<mode>.  */
  BUILTIN_VSDQ_I_DI (SHIFTACC, ssra_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTACC, usra_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTACC, srsra_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTACC, ursra_n, 0)
  /* Implemented by aarch64_<sur>shll_n<mode>.  */
  BUILTIN_VDW (SHIFTIMM, sshll_n, 0)
  BUILTIN_VDW (SHIFTIMM, ushll_n, 0)
  /* Implemented by aarch64_<sur>shll2_n<mode>.  */
  BUILTIN_VQW (SHIFTIMM, sshll2_n, 0)
  BUILTIN_VQW (SHIFTIMM, ushll2_n, 0)
  /* Implemented by aarch64_<sur>q<r>shr<u>n_n<mode>.  */
  BUILTIN_VSQN_HSDI (SHIFTIMM, sqshrun_n, 0)
  BUILTIN_VSQN_HSDI (SHIFTIMM, sqrshrun_n, 0)
  BUILTIN_VSQN_HSDI (SHIFTIMM, sqshrn_n, 0)
  BUILTIN_VSQN_HSDI (SHIFTIMM, uqshrn_n, 0)
  BUILTIN_VSQN_HSDI (SHIFTIMM, sqrshrn_n, 0)
  BUILTIN_VSQN_HSDI (SHIFTIMM, uqrshrn_n, 0)
  /* Implemented by aarch64_<sur>s<lr>i_n<mode>.  */
  BUILTIN_VSDQ_I_DI (SHIFTINSERT, ssri_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTINSERT, usri_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTINSERT, ssli_n, 0)
  BUILTIN_VSDQ_I_DI (SHIFTINSERT, usli_n, 0)
  /* Implemented by aarch64_<sur>qshl<u>_n<mode>.  */
  BUILTIN_VSDQ_I (SHIFTIMM, sqshlu_n, 0)
  BUILTIN_VSDQ_I (SHIFTIMM, sqshl_n, 0)
  BUILTIN_VSDQ_I (SHIFTIMM, uqshl_n, 0)

  /* Implemented by aarch64_cm<cmp><mode>.  */
  BUILTIN_VALLDI (BINOP, cmeq, 0)
  BUILTIN_VALLDI (BINOP, cmge, 0)
  BUILTIN_VALLDI (BINOP, cmgt, 0)
  BUILTIN_VALLDI (BINOP, cmle, 0)
  BUILTIN_VALLDI (BINOP, cmlt, 0)
  /* Implemented by aarch64_cm<cmp><mode>.  */
  BUILTIN_VSDQ_I_DI (BINOP, cmgeu, 0)
  BUILTIN_VSDQ_I_DI (BINOP, cmgtu, 0)
  BUILTIN_VSDQ_I_DI (BINOP, cmtst, 0)

  /* Implemented by reduc_<sur>plus_<mode>.  */
  BUILTIN_VALL (UNOP, reduc_splus_, 10)
  BUILTIN_VDQ (UNOP, reduc_uplus_, 10)

  /* Implemented by reduc_<maxmin_uns>_<mode>.  */
  BUILTIN_VDQIF (UNOP, reduc_smax_, 10)
  BUILTIN_VDQIF (UNOP, reduc_smin_, 10)
  BUILTIN_VDQ_BHSI (UNOP, reduc_umax_, 10)
  BUILTIN_VDQ_BHSI (UNOP, reduc_umin_, 10)
  BUILTIN_VDQF (UNOP, reduc_smax_nan_, 10)
  BUILTIN_VDQF (UNOP, reduc_smin_nan_, 10)

  /* Implemented by <maxmin><mode>3.
     smax variants map to fmaxnm,
     smax_nan variants map to fmax.  */
  BUILTIN_VDQIF (BINOP, smax, 3)
  BUILTIN_VDQIF (BINOP, smin, 3)
  BUILTIN_VDQ_BHSI (BINOP, umax, 3)
  BUILTIN_VDQ_BHSI (BINOP, umin, 3)
  BUILTIN_VDQF (BINOP, smax_nan, 3)
  BUILTIN_VDQF (BINOP, smin_nan, 3)

  /* Implemented by <frint_pattern><mode>2.  */
  BUILTIN_VDQF (UNOP, btrunc, 2)
  BUILTIN_VDQF (UNOP, ceil, 2)
  BUILTIN_VDQF (UNOP, floor, 2)
  BUILTIN_VDQF (UNOP, nearbyint, 2)
  BUILTIN_VDQF (UNOP, rint, 2)
  BUILTIN_VDQF (UNOP, round, 2)
  BUILTIN_VDQF (UNOP, frintn, 2)

  /* Implemented by l<fcvt_pattern><su_optab><VQDF:mode><vcvt_target>2.  */
  VAR1 (UNOP, lbtruncv2sf, 2, v2si)
  VAR1 (UNOP, lbtruncv4sf, 2, v4si)
  VAR1 (UNOP, lbtruncv2df, 2, v2di)

  VAR1 (UNOP, lbtruncuv2sf, 2, v2si)
  VAR1 (UNOP, lbtruncuv4sf, 2, v4si)
  VAR1 (UNOP, lbtruncuv2df, 2, v2di)

  VAR1 (UNOP, lroundv2sf, 2, v2si)
  VAR1 (UNOP, lroundv4sf, 2, v4si)
  VAR1 (UNOP, lroundv2df, 2, v2di)
  /* Implemented by l<fcvt_pattern><su_optab><GPF:mode><GPI:mode>2.  */
  VAR1 (UNOP, lroundsf, 2, si)
  VAR1 (UNOP, lrounddf, 2, di)

  VAR1 (UNOP, lrounduv2sf, 2, v2si)
  VAR1 (UNOP, lrounduv4sf, 2, v4si)
  VAR1 (UNOP, lrounduv2df, 2, v2di)
  VAR1 (UNOP, lroundusf, 2, si)
  VAR1 (UNOP, lroundudf, 2, di)

  VAR1 (UNOP, lceilv2sf, 2, v2si)
  VAR1 (UNOP, lceilv4sf, 2, v4si)
  VAR1 (UNOP, lceilv2df, 2, v2di)

  VAR1 (UNOP, lceiluv2sf, 2, v2si)
  VAR1 (UNOP, lceiluv4sf, 2, v4si)
  VAR1 (UNOP, lceiluv2df, 2, v2di)
  VAR1 (UNOP, lceilusf, 2, si)
  VAR1 (UNOP, lceiludf, 2, di)

  VAR1 (UNOP, lfloorv2sf, 2, v2si)
  VAR1 (UNOP, lfloorv4sf, 2, v4si)
  VAR1 (UNOP, lfloorv2df, 2, v2di)

  VAR1 (UNOP, lflooruv2sf, 2, v2si)
  VAR1 (UNOP, lflooruv4sf, 2, v4si)
  VAR1 (UNOP, lflooruv2df, 2, v2di)
  VAR1 (UNOP, lfloorusf, 2, si)
  VAR1 (UNOP, lfloorudf, 2, di)

  VAR1 (UNOP, lfrintnv2sf, 2, v2si)
  VAR1 (UNOP, lfrintnv4sf, 2, v4si)
  VAR1 (UNOP, lfrintnv2df, 2, v2di)
  VAR1 (UNOP, lfrintnsf, 2, si)
  VAR1 (UNOP, lfrintndf, 2, di)

  VAR1 (UNOP, lfrintnuv2sf, 2, v2si)
  VAR1 (UNOP, lfrintnuv4sf, 2, v4si)
  VAR1 (UNOP, lfrintnuv2df, 2, v2di)
  VAR1 (UNOP, lfrintnusf, 2, si)
  VAR1 (UNOP, lfrintnudf, 2, di)

  /* Implemented by <optab><fcvt_target><VDQF:mode>2.  */
  VAR1 (UNOP, floatv2si, 2, v2sf)
  VAR1 (UNOP, floatv4si, 2, v4sf)
  VAR1 (UNOP, floatv2di, 2, v2df)

  VAR1 (UNOP, floatunsv2si, 2, v2sf)
  VAR1 (UNOP, floatunsv4si, 2, v4sf)
  VAR1 (UNOP, floatunsv2di, 2, v2df)

  /* Implemented by
     aarch64_<PERMUTE:perm_insn><PERMUTE:perm_hilo><mode>.  */
  BUILTIN_VALL (BINOP, zip1, 0)
  BUILTIN_VALL (BINOP, zip2, 0)
  BUILTIN_VALL (BINOP, uzp1, 0)
  BUILTIN_VALL (BINOP, uzp2, 0)
  BUILTIN_VALL (BINOP, trn1, 0)
  BUILTIN_VALL (BINOP, trn2, 0)

  /* Implemented by
     aarch64_frecp<FRECP:frecp_suffix><mode>.  */
  BUILTIN_GPF (UNOP, frecpe, 0)
  BUILTIN_GPF (BINOP, frecps, 0)
  BUILTIN_GPF (UNOP, frecpx, 0)

  BUILTIN_VDQF (UNOP, frecpe, 0)
  BUILTIN_VDQF (BINOP, frecps, 0)

  BUILTIN_VDQF (UNOP, abs, 2)

  VAR1 (UNOP, vec_unpacks_hi_, 10, v4sf)
  VAR1 (BINOP, float_truncate_hi_, 0, v4sf)

  VAR1 (UNOP, float_extend_lo_, 0, v2df)
  VAR1 (UNOP, float_truncate_lo_, 0, v2sf)
