aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorJames Greenhalgh <james.greenhalgh@arm.com>2013-11-20 09:19:25 +0000
committerJames Greenhalgh <jgreenhalgh@gcc.gnu.org>2013-11-20 09:19:25 +0000
commitb5828b4bf68ebdc3649853f7f0944a49ea71101d (patch)
tree7545d09d75eaaf3297b9f994f69b0d9630f28f35 /gcc/config
parentcc6ebdca92e3a84397ea1d0b38a729ab5cbf933c (diff)
downloadgcc-b5828b4bf68ebdc3649853f7f0944a49ea71101d.zip
gcc-b5828b4bf68ebdc3649853f7f0944a49ea71101d.tar.gz
gcc-b5828b4bf68ebdc3649853f7f0944a49ea71101d.tar.bz2
[AArch64] AArch64 SIMD Builtins Better Type Correctness.
gcc/ * gcc/config/aarch64/aarch64-builtins.c (aarch64_simd_itype): Remove. (aarch64_simd_builtin_datum): Remove itype, add qualifiers pointer. (VAR1): Use qualifiers. (aarch64_build_scalar_type): New. (aarch64_build_vector_type): Likewise. (aarch64_build_type): Likewise. (aarch64_init_simd_builtins): Refactor, remove special cases, consolidate main loop. (aarch64_simd_expand_args): Likewise. From-SVN: r205092
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/aarch64/aarch64-builtins.c1117
1 files changed, 393 insertions, 724 deletions
diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c
index 2dc7838..fec7b22 100644
--- a/gcc/config/aarch64/aarch64-builtins.c
+++ b/gcc/config/aarch64/aarch64-builtins.c
@@ -84,57 +84,101 @@ enum aarch64_simd_builtin_type_mode
#define UP(X) X##_UP
-typedef enum
+#define SIMD_MAX_BUILTIN_ARGS 5
+
+enum aarch64_type_qualifiers
{
- AARCH64_SIMD_BINOP,
- AARCH64_SIMD_TERNOP,
- AARCH64_SIMD_QUADOP,
- AARCH64_SIMD_UNOP,
- AARCH64_SIMD_GETLANE,
- AARCH64_SIMD_SETLANE,
- AARCH64_SIMD_CREATE,
- AARCH64_SIMD_DUP,
- AARCH64_SIMD_DUPLANE,
- AARCH64_SIMD_COMBINE,
- AARCH64_SIMD_SPLIT,
- AARCH64_SIMD_LANEMUL,
- AARCH64_SIMD_LANEMULL,
- AARCH64_SIMD_LANEMULH,
- AARCH64_SIMD_LANEMAC,
- AARCH64_SIMD_SCALARMUL,
- AARCH64_SIMD_SCALARMULL,
- AARCH64_SIMD_SCALARMULH,
- AARCH64_SIMD_SCALARMAC,
- AARCH64_SIMD_CONVERT,
- AARCH64_SIMD_FIXCONV,
- AARCH64_SIMD_SELECT,
- AARCH64_SIMD_RESULTPAIR,
- AARCH64_SIMD_REINTERP,
- AARCH64_SIMD_VTBL,
- AARCH64_SIMD_VTBX,
- AARCH64_SIMD_LOAD1,
- AARCH64_SIMD_LOAD1LANE,
- AARCH64_SIMD_STORE1,
- AARCH64_SIMD_STORE1LANE,
- AARCH64_SIMD_LOADSTRUCT,
- AARCH64_SIMD_LOADSTRUCTLANE,
- AARCH64_SIMD_STORESTRUCT,
- AARCH64_SIMD_STORESTRUCTLANE,
- AARCH64_SIMD_LOGICBINOP,
- AARCH64_SIMD_SHIFTINSERT,
- AARCH64_SIMD_SHIFTIMM,
- AARCH64_SIMD_SHIFTACC
-} aarch64_simd_itype;
+ /* T foo. */
+ qualifier_none = 0x0,
+ /* unsigned T foo. */
+ qualifier_unsigned = 0x1, /* 1 << 0 */
+ /* const T foo. */
+ qualifier_const = 0x2, /* 1 << 1 */
+ /* T *foo. */
+ qualifier_pointer = 0x4, /* 1 << 2 */
+ /* const T *foo. */
+ qualifier_const_pointer = 0x6, /* qualifier_const | qualifier_pointer */
+ /* Used when expanding arguments if an operand could
+ be an immediate. */
+ qualifier_immediate = 0x8, /* 1 << 3 */
+ qualifier_maybe_immediate = 0x10, /* 1 << 4 */
+ /* void foo (...). */
+ qualifier_void = 0x20, /* 1 << 5 */
+ /* Some patterns may have internal operands, this qualifier is an
+ instruction to the initialisation code to skip this operand. */
+ qualifier_internal = 0x40, /* 1 << 6 */
+ /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
+ rather than using the type of the operand. */
+ qualifier_map_mode = 0x80, /* 1 << 7 */
+ /* qualifier_pointer | qualifier_map_mode */
+ qualifier_pointer_map_mode = 0x84,
+ /* qualifier_const_pointer | qualifier_map_mode */
+ qualifier_const_pointer_map_mode = 0x86
+};
typedef struct
{
const char *name;
- const aarch64_simd_itype itype;
enum aarch64_simd_builtin_type_mode mode;
const enum insn_code code;
unsigned int fcode;
+ enum aarch64_type_qualifiers *qualifiers;
} aarch64_simd_builtin_datum;
+static enum aarch64_type_qualifiers
+aarch64_types_unop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none };
+#define TYPES_UNOP (aarch64_types_unop_qualifiers)
+#define TYPES_CREATE (aarch64_types_unop_qualifiers)
+#define TYPES_REINTERP (aarch64_types_unop_qualifiers)
+static enum aarch64_type_qualifiers
+aarch64_types_binop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none, qualifier_maybe_immediate };
+#define TYPES_BINOP (aarch64_types_binop_qualifiers)
+static enum aarch64_type_qualifiers
+aarch64_types_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
+#define TYPES_TERNOP (aarch64_types_ternop_qualifiers)
+static enum aarch64_type_qualifiers
+aarch64_types_quadop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none, qualifier_none,
+ qualifier_none, qualifier_none };
+#define TYPES_QUADOP (aarch64_types_quadop_qualifiers)
+
+static enum aarch64_type_qualifiers
+aarch64_types_getlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none, qualifier_immediate };
+#define TYPES_GETLANE (aarch64_types_getlane_qualifiers)
+#define TYPES_SHIFTIMM (aarch64_types_getlane_qualifiers)
+static enum aarch64_type_qualifiers
+aarch64_types_setlane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none, qualifier_none, qualifier_immediate };
+#define TYPES_SETLANE (aarch64_types_setlane_qualifiers)
+#define TYPES_SHIFTINSERT (aarch64_types_setlane_qualifiers)
+#define TYPES_SHIFTACC (aarch64_types_setlane_qualifiers)
+
+static enum aarch64_type_qualifiers
+aarch64_types_combine_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_none, qualifier_none };
+#define TYPES_COMBINE (aarch64_types_combine_qualifiers)
+
+static enum aarch64_type_qualifiers
+aarch64_types_load1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_none, qualifier_const_pointer_map_mode };
+#define TYPES_LOAD1 (aarch64_types_load1_qualifiers)
+#define TYPES_LOADSTRUCT (aarch64_types_load1_qualifiers)
+
+/* The first argument (return type) of a store should be void type,
+ which we represent with qualifier_void. Their first operand will be
+ a DImode pointer to the location to store to, so we must use
+ qualifier_map_mode | qualifier_pointer to build a pointer to the
+ element type of the vector. */
+static enum aarch64_type_qualifiers
+aarch64_types_store1_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_void, qualifier_pointer_map_mode, qualifier_none };
+#define TYPES_STORE1 (aarch64_types_store1_qualifiers)
+#define TYPES_STORESTRUCT (aarch64_types_store1_qualifiers)
+
#define CF0(N, X) CODE_FOR_aarch64_##N##X
#define CF1(N, X) CODE_FOR_##N##X##1
#define CF2(N, X) CODE_FOR_##N##X##2
@@ -143,7 +187,7 @@ typedef struct
#define CF10(N, X) CODE_FOR_##N##X
#define VAR1(T, N, MAP, A) \
- {#N, AARCH64_SIMD_##T, UP (A), CF##MAP (N, A), 0},
+ {#N, UP (A), CF##MAP (N, A), 0, TYPES_##T},
#define VAR2(T, N, MAP, A, B) \
VAR1 (T, N, MAP, A) \
VAR1 (T, N, MAP, B)
@@ -282,118 +326,175 @@ static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
#define NUM_DREG_TYPES 6
#define NUM_QREG_TYPES 6
+/* Return a tree for a signed or unsigned argument of either
+ the mode specified by MODE, or the inner mode of MODE. */
+tree
+aarch64_build_scalar_type (enum machine_mode mode, bool unsigned_p)
+{
+#undef INT_TYPES
+#define INT_TYPES \
+ AARCH64_TYPE_BUILDER (QI) \
+ AARCH64_TYPE_BUILDER (HI) \
+ AARCH64_TYPE_BUILDER (SI) \
+ AARCH64_TYPE_BUILDER (DI) \
+ AARCH64_TYPE_BUILDER (EI) \
+ AARCH64_TYPE_BUILDER (OI) \
+ AARCH64_TYPE_BUILDER (CI) \
+ AARCH64_TYPE_BUILDER (XI) \
+ AARCH64_TYPE_BUILDER (TI) \
+
+/* Statically declare all the possible types we might need. */
+#undef AARCH64_TYPE_BUILDER
+#define AARCH64_TYPE_BUILDER(X) \
+ static tree X##_aarch64_type_node_s = NULL; \
+ static tree X##_aarch64_type_node_u = NULL;
+
+ INT_TYPES
+
+ static tree float_aarch64_type_node = NULL;
+ static tree double_aarch64_type_node = NULL;
+
+ gcc_assert (!VECTOR_MODE_P (mode));
+
+/* If we've already initialised this type, don't initialise it again,
+ otherwise ask for a new type of the correct size. */
+#undef AARCH64_TYPE_BUILDER
+#define AARCH64_TYPE_BUILDER(X) \
+ case X##mode: \
+ if (unsigned_p) \
+ return (X##_aarch64_type_node_u \
+ ? X##_aarch64_type_node_u \
+ : X##_aarch64_type_node_u \
+ = make_unsigned_type (GET_MODE_PRECISION (mode))); \
+ else \
+ return (X##_aarch64_type_node_s \
+ ? X##_aarch64_type_node_s \
+ : X##_aarch64_type_node_s \
+ = make_signed_type (GET_MODE_PRECISION (mode))); \
+ break;
+
+ switch (mode)
+ {
+ INT_TYPES
+ case SFmode:
+ if (!float_aarch64_type_node)
+ {
+ float_aarch64_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (float_aarch64_type_node) = FLOAT_TYPE_SIZE;
+ layout_type (float_aarch64_type_node);
+ }
+ return float_aarch64_type_node;
+ break;
+ case DFmode:
+ if (!double_aarch64_type_node)
+ {
+ double_aarch64_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (double_aarch64_type_node) = DOUBLE_TYPE_SIZE;
+ layout_type (double_aarch64_type_node);
+ }
+ return double_aarch64_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+tree
+aarch64_build_vector_type (enum machine_mode mode, bool unsigned_p)
+{
+ tree eltype;
+
+#define VECTOR_TYPES \
+ AARCH64_TYPE_BUILDER (V16QI) \
+ AARCH64_TYPE_BUILDER (V8HI) \
+ AARCH64_TYPE_BUILDER (V4SI) \
+ AARCH64_TYPE_BUILDER (V2DI) \
+ AARCH64_TYPE_BUILDER (V8QI) \
+ AARCH64_TYPE_BUILDER (V4HI) \
+ AARCH64_TYPE_BUILDER (V2SI) \
+ \
+ AARCH64_TYPE_BUILDER (V4SF) \
+ AARCH64_TYPE_BUILDER (V2DF) \
+ AARCH64_TYPE_BUILDER (V2SF) \
+/* Declare our "cache" of values. */
+#undef AARCH64_TYPE_BUILDER
+#define AARCH64_TYPE_BUILDER(X) \
+ static tree X##_aarch64_type_node_s = NULL; \
+ static tree X##_aarch64_type_node_u = NULL;
+
+ VECTOR_TYPES
+
+ gcc_assert (VECTOR_MODE_P (mode));
+
+#undef AARCH64_TYPE_BUILDER
+#define AARCH64_TYPE_BUILDER(X) \
+ case X##mode: \
+ if (unsigned_p) \
+ return X##_aarch64_type_node_u \
+ ? X##_aarch64_type_node_u \
+ : X##_aarch64_type_node_u \
+ = build_vector_type_for_mode (aarch64_build_scalar_type \
+ (GET_MODE_INNER (mode), \
+ unsigned_p), mode); \
+ else \
+ return X##_aarch64_type_node_s \
+ ? X##_aarch64_type_node_s \
+ : X##_aarch64_type_node_s \
+ = build_vector_type_for_mode (aarch64_build_scalar_type \
+ (GET_MODE_INNER (mode), \
+ unsigned_p), mode); \
+ break;
+
+ switch (mode)
+ {
+ default:
+ eltype = aarch64_build_scalar_type (GET_MODE_INNER (mode), unsigned_p);
+ return build_vector_type_for_mode (eltype, mode);
+ break;
+ VECTOR_TYPES
+ }
+}
+
+tree
+aarch64_build_type (enum machine_mode mode, bool unsigned_p)
+{
+ if (VECTOR_MODE_P (mode))
+ return aarch64_build_vector_type (mode, unsigned_p);
+ else
+ return aarch64_build_scalar_type (mode, unsigned_p);
+}
+
static void
aarch64_init_simd_builtins (void)
{
unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1;
- /* Scalar type nodes. */
- tree aarch64_simd_intQI_type_node;
- tree aarch64_simd_intHI_type_node;
- tree aarch64_simd_polyQI_type_node;
- tree aarch64_simd_polyHI_type_node;
- tree aarch64_simd_intSI_type_node;
- tree aarch64_simd_intDI_type_node;
- tree aarch64_simd_float_type_node;
- tree aarch64_simd_double_type_node;
-
- /* Pointer to scalar type nodes. */
- tree intQI_pointer_node;
- tree intHI_pointer_node;
- tree intSI_pointer_node;
- tree intDI_pointer_node;
- tree float_pointer_node;
- tree double_pointer_node;
-
- /* Const scalar type nodes. */
- tree const_intQI_node;
- tree const_intHI_node;
- tree const_intSI_node;
- tree const_intDI_node;
- tree const_float_node;
- tree const_double_node;
-
- /* Pointer to const scalar type nodes. */
- tree const_intQI_pointer_node;
- tree const_intHI_pointer_node;
- tree const_intSI_pointer_node;
- tree const_intDI_pointer_node;
- tree const_float_pointer_node;
- tree const_double_pointer_node;
-
- /* Vector type nodes. */
- tree V8QI_type_node;
- tree V4HI_type_node;
- tree V2SI_type_node;
- tree V2SF_type_node;
- tree V16QI_type_node;
- tree V8HI_type_node;
- tree V4SI_type_node;
- tree V4SF_type_node;
- tree V2DI_type_node;
- tree V2DF_type_node;
-
- /* Scalar unsigned type nodes. */
- tree intUQI_type_node;
- tree intUHI_type_node;
- tree intUSI_type_node;
- tree intUDI_type_node;
-
- /* Opaque integer types for structures of vectors. */
- tree intEI_type_node;
- tree intOI_type_node;
- tree intCI_type_node;
- tree intXI_type_node;
-
- /* Pointer to vector type nodes. */
- tree V8QI_pointer_node;
- tree V4HI_pointer_node;
- tree V2SI_pointer_node;
- tree V2SF_pointer_node;
- tree V16QI_pointer_node;
- tree V8HI_pointer_node;
- tree V4SI_pointer_node;
- tree V4SF_pointer_node;
- tree V2DI_pointer_node;
- tree V2DF_pointer_node;
-
- /* Operations which return results as pairs. */
- tree void_ftype_pv8qi_v8qi_v8qi;
- tree void_ftype_pv4hi_v4hi_v4hi;
- tree void_ftype_pv2si_v2si_v2si;
- tree void_ftype_pv2sf_v2sf_v2sf;
- tree void_ftype_pdi_di_di;
- tree void_ftype_pv16qi_v16qi_v16qi;
- tree void_ftype_pv8hi_v8hi_v8hi;
- tree void_ftype_pv4si_v4si_v4si;
- tree void_ftype_pv4sf_v4sf_v4sf;
- tree void_ftype_pv2di_v2di_v2di;
- tree void_ftype_pv2df_v2df_v2df;
-
- tree reinterp_ftype_dreg[NUM_DREG_TYPES][NUM_DREG_TYPES];
- tree reinterp_ftype_qreg[NUM_QREG_TYPES][NUM_QREG_TYPES];
- tree dreg_types[NUM_DREG_TYPES], qreg_types[NUM_QREG_TYPES];
-
- /* Create distinguished type nodes for AARCH64_SIMD vector element types,
- and pointers to values of such types, so we can detect them later. */
- aarch64_simd_intQI_type_node =
- make_signed_type (GET_MODE_PRECISION (QImode));
- aarch64_simd_intHI_type_node =
- make_signed_type (GET_MODE_PRECISION (HImode));
- aarch64_simd_polyQI_type_node =
+ /* In order that 'poly' types mangle correctly they must not share
+ a base tree with the other scalar types, thus we must generate them
+ as a special case. */
+ tree aarch64_simd_polyQI_type_node =
make_signed_type (GET_MODE_PRECISION (QImode));
- aarch64_simd_polyHI_type_node =
+ tree aarch64_simd_polyHI_type_node =
make_signed_type (GET_MODE_PRECISION (HImode));
- aarch64_simd_intSI_type_node =
- make_signed_type (GET_MODE_PRECISION (SImode));
- aarch64_simd_intDI_type_node =
- make_signed_type (GET_MODE_PRECISION (DImode));
- aarch64_simd_float_type_node = make_node (REAL_TYPE);
- aarch64_simd_double_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (aarch64_simd_float_type_node) = FLOAT_TYPE_SIZE;
- TYPE_PRECISION (aarch64_simd_double_type_node) = DOUBLE_TYPE_SIZE;
- layout_type (aarch64_simd_float_type_node);
- layout_type (aarch64_simd_double_type_node);
+
+ /* Scalar type nodes. */
+ tree aarch64_simd_intQI_type_node = aarch64_build_type (QImode, false);
+ tree aarch64_simd_intHI_type_node = aarch64_build_type (HImode, false);
+ tree aarch64_simd_intSI_type_node = aarch64_build_type (SImode, false);
+ tree aarch64_simd_intDI_type_node = aarch64_build_type (DImode, false);
+ tree aarch64_simd_intTI_type_node = aarch64_build_type (TImode, false);
+ tree aarch64_simd_intEI_type_node = aarch64_build_type (EImode, false);
+ tree aarch64_simd_intOI_type_node = aarch64_build_type (OImode, false);
+ tree aarch64_simd_intCI_type_node = aarch64_build_type (CImode, false);
+ tree aarch64_simd_intXI_type_node = aarch64_build_type (XImode, false);
+ tree aarch64_simd_intUQI_type_node = aarch64_build_type (QImode, true);
+ tree aarch64_simd_intUHI_type_node = aarch64_build_type (HImode, true);
+ tree aarch64_simd_intUSI_type_node = aarch64_build_type (SImode, true);
+ tree aarch64_simd_intUDI_type_node = aarch64_build_type (DImode, true);
+
+ /* Float type nodes. */
+ tree aarch64_simd_float_type_node = aarch64_build_type (SFmode, false);
+ tree aarch64_simd_double_type_node = aarch64_build_type (DFmode, false);
/* Define typedefs which exactly correspond to the modes we are basing vector
types on. If you change these names you'll need to change
@@ -414,518 +515,129 @@ aarch64_init_simd_builtins (void)
"__builtin_aarch64_simd_poly8");
(*lang_hooks.types.register_builtin_type) (aarch64_simd_polyHI_type_node,
"__builtin_aarch64_simd_poly16");
-
- intQI_pointer_node = build_pointer_type (aarch64_simd_intQI_type_node);
- intHI_pointer_node = build_pointer_type (aarch64_simd_intHI_type_node);
- intSI_pointer_node = build_pointer_type (aarch64_simd_intSI_type_node);
- intDI_pointer_node = build_pointer_type (aarch64_simd_intDI_type_node);
- float_pointer_node = build_pointer_type (aarch64_simd_float_type_node);
- double_pointer_node = build_pointer_type (aarch64_simd_double_type_node);
-
- /* Next create constant-qualified versions of the above types. */
- const_intQI_node = build_qualified_type (aarch64_simd_intQI_type_node,
- TYPE_QUAL_CONST);
- const_intHI_node = build_qualified_type (aarch64_simd_intHI_type_node,
- TYPE_QUAL_CONST);
- const_intSI_node = build_qualified_type (aarch64_simd_intSI_type_node,
- TYPE_QUAL_CONST);
- const_intDI_node = build_qualified_type (aarch64_simd_intDI_type_node,
- TYPE_QUAL_CONST);
- const_float_node = build_qualified_type (aarch64_simd_float_type_node,
- TYPE_QUAL_CONST);
- const_double_node = build_qualified_type (aarch64_simd_double_type_node,
- TYPE_QUAL_CONST);
-
- const_intQI_pointer_node = build_pointer_type (const_intQI_node);
- const_intHI_pointer_node = build_pointer_type (const_intHI_node);
- const_intSI_pointer_node = build_pointer_type (const_intSI_node);
- const_intDI_pointer_node = build_pointer_type (const_intDI_node);
- const_float_pointer_node = build_pointer_type (const_float_node);
- const_double_pointer_node = build_pointer_type (const_double_node);
-
- /* Now create vector types based on our AARCH64 SIMD element types. */
- /* 64-bit vectors. */
- V8QI_type_node =
- build_vector_type_for_mode (aarch64_simd_intQI_type_node, V8QImode);
- V4HI_type_node =
- build_vector_type_for_mode (aarch64_simd_intHI_type_node, V4HImode);
- V2SI_type_node =
- build_vector_type_for_mode (aarch64_simd_intSI_type_node, V2SImode);
- V2SF_type_node =
- build_vector_type_for_mode (aarch64_simd_float_type_node, V2SFmode);
- /* 128-bit vectors. */
- V16QI_type_node =
- build_vector_type_for_mode (aarch64_simd_intQI_type_node, V16QImode);
- V8HI_type_node =
- build_vector_type_for_mode (aarch64_simd_intHI_type_node, V8HImode);
- V4SI_type_node =
- build_vector_type_for_mode (aarch64_simd_intSI_type_node, V4SImode);
- V4SF_type_node =
- build_vector_type_for_mode (aarch64_simd_float_type_node, V4SFmode);
- V2DI_type_node =
- build_vector_type_for_mode (aarch64_simd_intDI_type_node, V2DImode);
- V2DF_type_node =
- build_vector_type_for_mode (aarch64_simd_double_type_node, V2DFmode);
-
- /* Unsigned integer types for various mode sizes. */
- intUQI_type_node = make_unsigned_type (GET_MODE_PRECISION (QImode));
- intUHI_type_node = make_unsigned_type (GET_MODE_PRECISION (HImode));
- intUSI_type_node = make_unsigned_type (GET_MODE_PRECISION (SImode));
- intUDI_type_node = make_unsigned_type (GET_MODE_PRECISION (DImode));
-
- (*lang_hooks.types.register_builtin_type) (intUQI_type_node,
- "__builtin_aarch64_simd_uqi");
- (*lang_hooks.types.register_builtin_type) (intUHI_type_node,
- "__builtin_aarch64_simd_uhi");
- (*lang_hooks.types.register_builtin_type) (intUSI_type_node,
- "__builtin_aarch64_simd_usi");
- (*lang_hooks.types.register_builtin_type) (intUDI_type_node,
- "__builtin_aarch64_simd_udi");
-
- /* Opaque integer types for structures of vectors. */
- intEI_type_node = make_signed_type (GET_MODE_PRECISION (EImode));
- intOI_type_node = make_signed_type (GET_MODE_PRECISION (OImode));
- intCI_type_node = make_signed_type (GET_MODE_PRECISION (CImode));
- intXI_type_node = make_signed_type (GET_MODE_PRECISION (XImode));
-
- (*lang_hooks.types.register_builtin_type) (intTI_type_node,
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intTI_type_node,
"__builtin_aarch64_simd_ti");
- (*lang_hooks.types.register_builtin_type) (intEI_type_node,
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intEI_type_node,
"__builtin_aarch64_simd_ei");
- (*lang_hooks.types.register_builtin_type) (intOI_type_node,
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intOI_type_node,
"__builtin_aarch64_simd_oi");
- (*lang_hooks.types.register_builtin_type) (intCI_type_node,
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intCI_type_node,
"__builtin_aarch64_simd_ci");
- (*lang_hooks.types.register_builtin_type) (intXI_type_node,
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intXI_type_node,
"__builtin_aarch64_simd_xi");
- /* Pointers to vector types. */
- V8QI_pointer_node = build_pointer_type (V8QI_type_node);
- V4HI_pointer_node = build_pointer_type (V4HI_type_node);
- V2SI_pointer_node = build_pointer_type (V2SI_type_node);
- V2SF_pointer_node = build_pointer_type (V2SF_type_node);
- V16QI_pointer_node = build_pointer_type (V16QI_type_node);
- V8HI_pointer_node = build_pointer_type (V8HI_type_node);
- V4SI_pointer_node = build_pointer_type (V4SI_type_node);
- V4SF_pointer_node = build_pointer_type (V4SF_type_node);
- V2DI_pointer_node = build_pointer_type (V2DI_type_node);
- V2DF_pointer_node = build_pointer_type (V2DF_type_node);
-
- /* Operations which return results as pairs. */
- void_ftype_pv8qi_v8qi_v8qi =
- build_function_type_list (void_type_node, V8QI_pointer_node,
- V8QI_type_node, V8QI_type_node, NULL);
- void_ftype_pv4hi_v4hi_v4hi =
- build_function_type_list (void_type_node, V4HI_pointer_node,
- V4HI_type_node, V4HI_type_node, NULL);
- void_ftype_pv2si_v2si_v2si =
- build_function_type_list (void_type_node, V2SI_pointer_node,
- V2SI_type_node, V2SI_type_node, NULL);
- void_ftype_pv2sf_v2sf_v2sf =
- build_function_type_list (void_type_node, V2SF_pointer_node,
- V2SF_type_node, V2SF_type_node, NULL);
- void_ftype_pdi_di_di =
- build_function_type_list (void_type_node, intDI_pointer_node,
- aarch64_simd_intDI_type_node,
- aarch64_simd_intDI_type_node, NULL);
- void_ftype_pv16qi_v16qi_v16qi =
- build_function_type_list (void_type_node, V16QI_pointer_node,
- V16QI_type_node, V16QI_type_node, NULL);
- void_ftype_pv8hi_v8hi_v8hi =
- build_function_type_list (void_type_node, V8HI_pointer_node,
- V8HI_type_node, V8HI_type_node, NULL);
- void_ftype_pv4si_v4si_v4si =
- build_function_type_list (void_type_node, V4SI_pointer_node,
- V4SI_type_node, V4SI_type_node, NULL);
- void_ftype_pv4sf_v4sf_v4sf =
- build_function_type_list (void_type_node, V4SF_pointer_node,
- V4SF_type_node, V4SF_type_node, NULL);
- void_ftype_pv2di_v2di_v2di =
- build_function_type_list (void_type_node, V2DI_pointer_node,
- V2DI_type_node, V2DI_type_node, NULL);
- void_ftype_pv2df_v2df_v2df =
- build_function_type_list (void_type_node, V2DF_pointer_node,
- V2DF_type_node, V2DF_type_node, NULL);
-
- dreg_types[0] = V8QI_type_node;
- dreg_types[1] = V4HI_type_node;
- dreg_types[2] = V2SI_type_node;
- dreg_types[3] = V2SF_type_node;
- dreg_types[4] = aarch64_simd_intDI_type_node;
- dreg_types[5] = aarch64_simd_double_type_node;
-
- qreg_types[0] = V16QI_type_node;
- qreg_types[1] = V8HI_type_node;
- qreg_types[2] = V4SI_type_node;
- qreg_types[3] = V4SF_type_node;
- qreg_types[4] = V2DI_type_node;
- qreg_types[5] = V2DF_type_node;
-
- /* If NUM_DREG_TYPES != NUM_QREG_TYPES, we will need separate nested loops
- for qreg and dreg reinterp inits. */
- for (i = 0; i < NUM_DREG_TYPES; i++)
- {
- int j;
- for (j = 0; j < NUM_DREG_TYPES; j++)
- {
- reinterp_ftype_dreg[i][j]
- = build_function_type_list (dreg_types[i], dreg_types[j], NULL);
- reinterp_ftype_qreg[i][j]
- = build_function_type_list (qreg_types[i], qreg_types[j], NULL);
- }
- }
+ /* Unsigned integer types for various mode sizes. */
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUQI_type_node,
+ "__builtin_aarch64_simd_uqi");
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUHI_type_node,
+ "__builtin_aarch64_simd_uhi");
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUSI_type_node,
+ "__builtin_aarch64_simd_usi");
+ (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUDI_type_node,
+ "__builtin_aarch64_simd_udi");
for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++)
{
+ bool print_type_signature_p = false;
+ char type_signature[SIMD_MAX_BUILTIN_ARGS] = { 0 };
aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
const char *const modenames[] =
- {
- "v8qi", "v4hi", "v2si", "v2sf", "di", "df",
- "v16qi", "v8hi", "v4si", "v4sf", "v2di", "v2df",
- "ti", "ei", "oi", "xi", "si", "sf", "hi", "qi"
- };
+ {
+ "v8qi", "v4hi", "v2si", "v2sf", "di", "df",
+ "v16qi", "v8hi", "v4si", "v4sf", "v2di", "v2df",
+ "ti", "ei", "oi", "xi", "si", "sf", "hi", "qi"
+ };
+ const enum machine_mode modes[] =
+ {
+ V8QImode, V4HImode, V2SImode, V2SFmode, DImode, DFmode,
+ V16QImode, V8HImode, V4SImode, V4SFmode, V2DImode,
+ V2DFmode, TImode, EImode, OImode, XImode, SImode,
+ SFmode, HImode, QImode
+ };
char namebuf[60];
tree ftype = NULL;
tree fndecl = NULL;
- int is_load = 0;
- int is_store = 0;
gcc_assert (ARRAY_SIZE (modenames) == T_MAX);
d->fcode = fcode;
- switch (d->itype)
+ /* We must track two variables here. op_num is
+ the operand number as in the RTL pattern. This is
+ required to access the mode (e.g. V4SF mode) of the
+ argument, from which the base type can be derived.
+ arg_num is an index in to the qualifiers data, which
+ gives qualifiers to the type (e.g. const unsigned).
+ The reason these two variables may differ by one is the
+ void return type. While all return types take the 0th entry
+ in the qualifiers array, there is no operand for them in the
+ RTL pattern. */
+ int op_num = insn_data[d->code].n_operands - 1;
+ int arg_num = d->qualifiers[0] & qualifier_void
+ ? op_num + 1
+ : op_num;
+ tree return_type = void_type_node, args = void_list_node;
+ tree eltype;
+
+ /* Build a function type directly from the insn_data for this
+ builtin. The build_function_type () function takes care of
+ removing duplicates for us. */
+ for (; op_num >= 0; arg_num--, op_num--)
{
- case AARCH64_SIMD_LOAD1:
- case AARCH64_SIMD_LOAD1LANE:
- case AARCH64_SIMD_LOADSTRUCT:
- case AARCH64_SIMD_LOADSTRUCTLANE:
- is_load = 1;
- /* Fall through. */
- case AARCH64_SIMD_STORE1:
- case AARCH64_SIMD_STORE1LANE:
- case AARCH64_SIMD_STORESTRUCT:
- case AARCH64_SIMD_STORESTRUCTLANE:
- if (!is_load)
- is_store = 1;
- /* Fall through. */
- case AARCH64_SIMD_UNOP:
- case AARCH64_SIMD_BINOP:
- case AARCH64_SIMD_TERNOP:
- case AARCH64_SIMD_QUADOP:
- case AARCH64_SIMD_COMBINE:
- case AARCH64_SIMD_CONVERT:
- case AARCH64_SIMD_CREATE:
- case AARCH64_SIMD_DUP:
- case AARCH64_SIMD_DUPLANE:
- case AARCH64_SIMD_FIXCONV:
- case AARCH64_SIMD_GETLANE:
- case AARCH64_SIMD_LANEMAC:
- case AARCH64_SIMD_LANEMUL:
- case AARCH64_SIMD_LANEMULH:
- case AARCH64_SIMD_LANEMULL:
- case AARCH64_SIMD_LOGICBINOP:
- case AARCH64_SIMD_SCALARMAC:
- case AARCH64_SIMD_SCALARMUL:
- case AARCH64_SIMD_SCALARMULH:
- case AARCH64_SIMD_SCALARMULL:
- case AARCH64_SIMD_SELECT:
- case AARCH64_SIMD_SETLANE:
- case AARCH64_SIMD_SHIFTACC:
- case AARCH64_SIMD_SHIFTIMM:
- case AARCH64_SIMD_SHIFTINSERT:
- case AARCH64_SIMD_SPLIT:
- case AARCH64_SIMD_VTBL:
- case AARCH64_SIMD_VTBX:
- {
- int k;
- tree return_type = void_type_node, args = void_list_node;
- tree eltype;
- /* Build a function type directly from the insn_data for this
- builtin. The build_function_type () function takes care of
- removing duplicates for us. */
-
- for (k = insn_data[d->code].n_operands -1; k >= 0; k--)
- {
- /* Skip an internal operand for vget_{low, high}. */
- if (k == 2 && d->itype == AARCH64_SIMD_SPLIT)
- continue;
-
- if (is_load && k == 1)
- {
- /* AdvSIMD load patterns always have the memory operand
- (a DImode pointer) in the operand 1 position. We
- want a const pointer to the element type in that
- position. */
- gcc_assert (insn_data[d->code].operand[k].mode == DImode);
-
- switch (d->mode)
- {
- case T_V8QI:
- case T_V16QI:
- eltype = const_intQI_pointer_node;
- break;
-
- case T_V4HI:
- case T_V8HI:
- eltype = const_intHI_pointer_node;
- break;
-
- case T_V2SI:
- case T_V4SI:
- eltype = const_intSI_pointer_node;
- break;
-
- case T_V2SF:
- case T_V4SF:
- eltype = const_float_pointer_node;
- break;
-
- case T_DI:
- case T_V2DI:
- eltype = const_intDI_pointer_node;
- break;
-
- case T_DF:
- case T_V2DF:
- eltype = const_double_pointer_node;
- break;
-
- default:
- gcc_unreachable ();
- }
- }
- else if (is_store && k == 0)
- {
- /* Similarly, AdvSIMD store patterns use operand 0 as
- the memory location to store to (a DImode pointer).
- Use a pointer to the element type of the store in
- that position. */
- gcc_assert (insn_data[d->code].operand[k].mode == DImode);
-
- switch (d->mode)
- {
- case T_V8QI:
- case T_V16QI:
- eltype = intQI_pointer_node;
- break;
-
- case T_V4HI:
- case T_V8HI:
- eltype = intHI_pointer_node;
- break;
-
- case T_V2SI:
- case T_V4SI:
- eltype = intSI_pointer_node;
- break;
-
- case T_V2SF:
- case T_V4SF:
- eltype = float_pointer_node;
- break;
-
- case T_DI:
- case T_V2DI:
- eltype = intDI_pointer_node;
- break;
-
- case T_DF:
- case T_V2DF:
- eltype = double_pointer_node;
- break;
-
- default:
- gcc_unreachable ();
- }
- }
- else
- {
- switch (insn_data[d->code].operand[k].mode)
- {
- case VOIDmode:
- eltype = void_type_node;
- break;
- /* Scalars. */
- case QImode:
- eltype = aarch64_simd_intQI_type_node;
- break;
- case HImode:
- eltype = aarch64_simd_intHI_type_node;
- break;
- case SImode:
- eltype = aarch64_simd_intSI_type_node;
- break;
- case SFmode:
- eltype = aarch64_simd_float_type_node;
- break;
- case DFmode:
- eltype = aarch64_simd_double_type_node;
- break;
- case DImode:
- eltype = aarch64_simd_intDI_type_node;
- break;
- case TImode:
- eltype = intTI_type_node;
- break;
- case EImode:
- eltype = intEI_type_node;
- break;
- case OImode:
- eltype = intOI_type_node;
- break;
- case CImode:
- eltype = intCI_type_node;
- break;
- case XImode:
- eltype = intXI_type_node;
- break;
- /* 64-bit vectors. */
- case V8QImode:
- eltype = V8QI_type_node;
- break;
- case V4HImode:
- eltype = V4HI_type_node;
- break;
- case V2SImode:
- eltype = V2SI_type_node;
- break;
- case V2SFmode:
- eltype = V2SF_type_node;
- break;
- /* 128-bit vectors. */
- case V16QImode:
- eltype = V16QI_type_node;
- break;
- case V8HImode:
- eltype = V8HI_type_node;
- break;
- case V4SImode:
- eltype = V4SI_type_node;
- break;
- case V4SFmode:
- eltype = V4SF_type_node;
- break;
- case V2DImode:
- eltype = V2DI_type_node;
- break;
- case V2DFmode:
- eltype = V2DF_type_node;
- break;
- default:
- gcc_unreachable ();
- }
- }
-
- if (k == 0 && !is_store)
- return_type = eltype;
- else
- args = tree_cons (NULL_TREE, eltype, args);
- }
- ftype = build_function_type (return_type, args);
- }
- break;
+ enum machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
+ enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
- case AARCH64_SIMD_RESULTPAIR:
- {
- switch (insn_data[d->code].operand[1].mode)
- {
- case V8QImode:
- ftype = void_ftype_pv8qi_v8qi_v8qi;
- break;
- case V4HImode:
- ftype = void_ftype_pv4hi_v4hi_v4hi;
- break;
- case V2SImode:
- ftype = void_ftype_pv2si_v2si_v2si;
- break;
- case V2SFmode:
- ftype = void_ftype_pv2sf_v2sf_v2sf;
- break;
- case DImode:
- ftype = void_ftype_pdi_di_di;
- break;
- case V16QImode:
- ftype = void_ftype_pv16qi_v16qi_v16qi;
- break;
- case V8HImode:
- ftype = void_ftype_pv8hi_v8hi_v8hi;
- break;
- case V4SImode:
- ftype = void_ftype_pv4si_v4si_v4si;
- break;
- case V4SFmode:
- ftype = void_ftype_pv4sf_v4sf_v4sf;
- break;
- case V2DImode:
- ftype = void_ftype_pv2di_v2di_v2di;
- break;
- case V2DFmode:
- ftype = void_ftype_pv2df_v2df_v2df;
- break;
- default:
- gcc_unreachable ();
- }
- }
- break;
+ if (qualifiers & qualifier_unsigned)
+ {
+ type_signature[arg_num] = 'u';
+ print_type_signature_p = true;
+ }
+ else
+ type_signature[arg_num] = 's';
+
+ /* Skip an internal operand for vget_{low, high}. */
+ if (qualifiers & qualifier_internal)
+ continue;
+
+ /* Some builtins have different user-facing types
+ for certain arguments, encoded in d->mode. */
+ if (qualifiers & qualifier_map_mode)
+ op_mode = modes[d->mode];
+
+ /* For pointers, we want a pointer to the basic type
+ of the vector. */
+ if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
+ op_mode = GET_MODE_INNER (op_mode);
+
+ eltype = aarch64_build_type (op_mode,
+ qualifiers & qualifier_unsigned);
+
+ /* Add qualifiers. */
+ if (qualifiers & qualifier_const)
+ eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
+
+ if (qualifiers & qualifier_pointer)
+ eltype = build_pointer_type (eltype);
+
+ /* If we have reached arg_num == 0, we are at a non-void
+ return type. Otherwise, we are still processing
+ arguments. */
+ if (arg_num == 0)
+ return_type = eltype;
+ else
+ args = tree_cons (NULL_TREE, eltype, args);
+ }
- case AARCH64_SIMD_REINTERP:
- {
- /* We iterate over 6 doubleword types, then 6 quadword
- types. */
- int rhs_d = d->mode % NUM_DREG_TYPES;
- int rhs_q = (d->mode - NUM_DREG_TYPES) % NUM_QREG_TYPES;
- switch (insn_data[d->code].operand[0].mode)
- {
- case V8QImode:
- ftype = reinterp_ftype_dreg[0][rhs_d];
- break;
- case V4HImode:
- ftype = reinterp_ftype_dreg[1][rhs_d];
- break;
- case V2SImode:
- ftype = reinterp_ftype_dreg[2][rhs_d];
- break;
- case V2SFmode:
- ftype = reinterp_ftype_dreg[3][rhs_d];
- break;
- case DImode:
- ftype = reinterp_ftype_dreg[4][rhs_d];
- break;
- case DFmode:
- ftype = reinterp_ftype_dreg[5][rhs_d];
- break;
- case V16QImode:
- ftype = reinterp_ftype_qreg[0][rhs_q];
- break;
- case V8HImode:
- ftype = reinterp_ftype_qreg[1][rhs_q];
- break;
- case V4SImode:
- ftype = reinterp_ftype_qreg[2][rhs_q];
- break;
- case V4SFmode:
- ftype = reinterp_ftype_qreg[3][rhs_q];
- break;
- case V2DImode:
- ftype = reinterp_ftype_qreg[4][rhs_q];
- break;
- case V2DFmode:
- ftype = reinterp_ftype_qreg[5][rhs_q];
- break;
- default:
- gcc_unreachable ();
- }
- }
- break;
+ ftype = build_function_type (return_type, args);
- default:
- gcc_unreachable ();
- }
gcc_assert (ftype != NULL);
- snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s",
- d->name, modenames[d->mode]);
+ if (print_type_signature_p)
+ snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s_%s",
+ d->name, modenames[d->mode], type_signature);
+ else
+ snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s",
+ d->name, modenames[d->mode]);
fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
NULL, NULL_TREE);
@@ -956,8 +668,6 @@ typedef enum
SIMD_ARG_STOP
} builtin_simd_arg;
-#define SIMD_MAX_BUILTIN_ARGS 5
-
static rtx
aarch64_simd_expand_args (rtx target, int icode, int have_retval,
tree exp, ...)
@@ -1085,99 +795,58 @@ aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
{
aarch64_simd_builtin_datum *d =
&aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)];
- aarch64_simd_itype itype = d->itype;
enum insn_code icode = d->code;
+ builtin_simd_arg args[SIMD_MAX_BUILTIN_ARGS];
+ int num_args = insn_data[d->code].n_operands;
+ int is_void = 0;
+ int k;
- switch (itype)
- {
- case AARCH64_SIMD_UNOP:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_STOP);
+ is_void = !!(d->qualifiers[0] & qualifier_void);
- case AARCH64_SIMD_BINOP:
- {
- rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1));
- /* Handle constants only if the predicate allows it. */
- bool op1_const_int_p =
- (CONST_INT_P (arg2)
- && (*insn_data[icode].operand[2].predicate)
- (arg2, insn_data[icode].operand[2].mode));
- return aarch64_simd_expand_args
- (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- op1_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_STOP);
- }
+ num_args += is_void;
+
+ for (k = 1; k < num_args; k++)
+ {
+ /* We have four arrays of data, each indexed in a different fashion.
+ qualifiers - element 0 always describes the function return type.
+ operands - element 0 is either the operand for return value (if
+ the function has a non-void return type) or the operand for the
+ first argument.
+ expr_args - element 0 always holds the first argument.
+ args - element 0 is always used for the return type. */
+ int qualifiers_k = k;
+ int operands_k = k - is_void;
+ int expr_args_k = k - 1;
+
+ if (d->qualifiers[qualifiers_k] & qualifier_immediate)
+ args[k] = SIMD_ARG_CONSTANT;
+ else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
+ {
+ rtx arg
+ = expand_normal (CALL_EXPR_ARG (exp,
+ (expr_args_k)));
+ /* Handle constants only if the predicate allows it. */
+ bool op_const_int_p =
+ (CONST_INT_P (arg)
+ && (*insn_data[icode].operand[operands_k].predicate)
+ (arg, insn_data[icode].operand[operands_k].mode));
+ args[k] = op_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG;
+ }
+ else
+ args[k] = SIMD_ARG_COPY_TO_REG;
- case AARCH64_SIMD_TERNOP:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_STOP);
-
- case AARCH64_SIMD_QUADOP:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_STOP);
- case AARCH64_SIMD_LOAD1:
- case AARCH64_SIMD_LOADSTRUCT:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG, SIMD_ARG_STOP);
-
- case AARCH64_SIMD_STORE1:
- case AARCH64_SIMD_STORESTRUCT:
- return aarch64_simd_expand_args (target, icode, 0, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG, SIMD_ARG_STOP);
-
- case AARCH64_SIMD_REINTERP:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG, SIMD_ARG_STOP);
-
- case AARCH64_SIMD_CREATE:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG, SIMD_ARG_STOP);
-
- case AARCH64_SIMD_COMBINE:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG, SIMD_ARG_STOP);
-
- case AARCH64_SIMD_GETLANE:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_CONSTANT,
- SIMD_ARG_STOP);
-
- case AARCH64_SIMD_SETLANE:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_CONSTANT,
- SIMD_ARG_STOP);
-
- case AARCH64_SIMD_SHIFTIMM:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_CONSTANT,
- SIMD_ARG_STOP);
-
- case AARCH64_SIMD_SHIFTACC:
- case AARCH64_SIMD_SHIFTINSERT:
- return aarch64_simd_expand_args (target, icode, 1, exp,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_COPY_TO_REG,
- SIMD_ARG_CONSTANT,
- SIMD_ARG_STOP);
-
- default:
- gcc_unreachable ();
}
+ args[k] = SIMD_ARG_STOP;
+
+ /* The interface to aarch64_simd_expand_args expects a 0 if
+ the function is void, and a 1 if it is not. */
+ return aarch64_simd_expand_args
+ (target, icode, !is_void, exp,
+ args[1],
+ args[2],
+ args[3],
+ args[4],
+ SIMD_ARG_STOP);
}
/* Expand an expression EXP that calls a built-in function,