Commit b5828b4b by James Greenhalgh Committed by James Greenhalgh

[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
parent cc6ebdca
2013-11-20 James Greenhalgh <james.greenhalgh@arm.com>
* 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.
2013-11-19 Joshua J Cogliati <jrincayc@yahoo.com> 2013-11-19 Joshua J Cogliati <jrincayc@yahoo.com>
PR c/53001 PR c/53001
...@@ -84,57 +84,101 @@ enum aarch64_simd_builtin_type_mode ...@@ -84,57 +84,101 @@ enum aarch64_simd_builtin_type_mode
#define UP(X) X##_UP #define UP(X) X##_UP
typedef enum #define SIMD_MAX_BUILTIN_ARGS 5
enum aarch64_type_qualifiers
{ {
AARCH64_SIMD_BINOP, /* T foo. */
AARCH64_SIMD_TERNOP, qualifier_none = 0x0,
AARCH64_SIMD_QUADOP, /* unsigned T foo. */
AARCH64_SIMD_UNOP, qualifier_unsigned = 0x1, /* 1 << 0 */
AARCH64_SIMD_GETLANE, /* const T foo. */
AARCH64_SIMD_SETLANE, qualifier_const = 0x2, /* 1 << 1 */
AARCH64_SIMD_CREATE, /* T *foo. */
AARCH64_SIMD_DUP, qualifier_pointer = 0x4, /* 1 << 2 */
AARCH64_SIMD_DUPLANE, /* const T *foo. */
AARCH64_SIMD_COMBINE, qualifier_const_pointer = 0x6, /* qualifier_const | qualifier_pointer */
AARCH64_SIMD_SPLIT, /* Used when expanding arguments if an operand could
AARCH64_SIMD_LANEMUL, be an immediate. */
AARCH64_SIMD_LANEMULL, qualifier_immediate = 0x8, /* 1 << 3 */
AARCH64_SIMD_LANEMULH, qualifier_maybe_immediate = 0x10, /* 1 << 4 */
AARCH64_SIMD_LANEMAC, /* void foo (...). */
AARCH64_SIMD_SCALARMUL, qualifier_void = 0x20, /* 1 << 5 */
AARCH64_SIMD_SCALARMULL, /* Some patterns may have internal operands, this qualifier is an
AARCH64_SIMD_SCALARMULH, instruction to the initialisation code to skip this operand. */
AARCH64_SIMD_SCALARMAC, qualifier_internal = 0x40, /* 1 << 6 */
AARCH64_SIMD_CONVERT, /* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
AARCH64_SIMD_FIXCONV, rather than using the type of the operand. */
AARCH64_SIMD_SELECT, qualifier_map_mode = 0x80, /* 1 << 7 */
AARCH64_SIMD_RESULTPAIR, /* qualifier_pointer | qualifier_map_mode */
AARCH64_SIMD_REINTERP, qualifier_pointer_map_mode = 0x84,
AARCH64_SIMD_VTBL, /* qualifier_const_pointer | qualifier_map_mode */
AARCH64_SIMD_VTBX, qualifier_const_pointer_map_mode = 0x86
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;
typedef struct typedef struct
{ {
const char *name; const char *name;
const aarch64_simd_itype itype;
enum aarch64_simd_builtin_type_mode mode; enum aarch64_simd_builtin_type_mode mode;
const enum insn_code code; const enum insn_code code;
unsigned int fcode; unsigned int fcode;
enum aarch64_type_qualifiers *qualifiers;
} aarch64_simd_builtin_datum; } 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 CF0(N, X) CODE_FOR_aarch64_##N##X
#define CF1(N, X) CODE_FOR_##N##X##1 #define CF1(N, X) CODE_FOR_##N##X##1
#define CF2(N, X) CODE_FOR_##N##X##2 #define CF2(N, X) CODE_FOR_##N##X##2
...@@ -143,7 +187,7 @@ typedef struct ...@@ -143,7 +187,7 @@ typedef struct
#define CF10(N, X) CODE_FOR_##N##X #define CF10(N, X) CODE_FOR_##N##X
#define VAR1(T, N, MAP, A) \ #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) \ #define VAR2(T, N, MAP, A, B) \
VAR1 (T, N, MAP, A) \ VAR1 (T, N, MAP, A) \
VAR1 (T, N, MAP, B) VAR1 (T, N, MAP, B)
...@@ -282,118 +326,175 @@ static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX]; ...@@ -282,118 +326,175 @@ static GTY(()) tree aarch64_builtin_decls[AARCH64_BUILTIN_MAX];
#define NUM_DREG_TYPES 6 #define NUM_DREG_TYPES 6
#define NUM_QREG_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 static void
aarch64_init_simd_builtins (void) aarch64_init_simd_builtins (void)
{ {
unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1; unsigned int i, fcode = AARCH64_SIMD_BUILTIN_BASE + 1;
/* Scalar type nodes. */ /* In order that 'poly' types mangle correctly they must not share
tree aarch64_simd_intQI_type_node; a base tree with the other scalar types, thus we must generate them
tree aarch64_simd_intHI_type_node; as a special case. */
tree aarch64_simd_polyQI_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 =
make_signed_type (GET_MODE_PRECISION (QImode)); 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)); make_signed_type (GET_MODE_PRECISION (HImode));
aarch64_simd_intSI_type_node =
make_signed_type (GET_MODE_PRECISION (SImode)); /* Scalar type nodes. */
aarch64_simd_intDI_type_node = tree aarch64_simd_intQI_type_node = aarch64_build_type (QImode, false);
make_signed_type (GET_MODE_PRECISION (DImode)); tree aarch64_simd_intHI_type_node = aarch64_build_type (HImode, false);
aarch64_simd_float_type_node = make_node (REAL_TYPE); tree aarch64_simd_intSI_type_node = aarch64_build_type (SImode, false);
aarch64_simd_double_type_node = make_node (REAL_TYPE); tree aarch64_simd_intDI_type_node = aarch64_build_type (DImode, false);
TYPE_PRECISION (aarch64_simd_float_type_node) = FLOAT_TYPE_SIZE; tree aarch64_simd_intTI_type_node = aarch64_build_type (TImode, false);
TYPE_PRECISION (aarch64_simd_double_type_node) = DOUBLE_TYPE_SIZE; tree aarch64_simd_intEI_type_node = aarch64_build_type (EImode, false);
layout_type (aarch64_simd_float_type_node); tree aarch64_simd_intOI_type_node = aarch64_build_type (OImode, false);
layout_type (aarch64_simd_double_type_node); 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 /* Define typedefs which exactly correspond to the modes we are basing vector
types on. If you change these names you'll need to change types on. If you change these names you'll need to change
...@@ -414,518 +515,129 @@ aarch64_init_simd_builtins (void) ...@@ -414,518 +515,129 @@ aarch64_init_simd_builtins (void)
"__builtin_aarch64_simd_poly8"); "__builtin_aarch64_simd_poly8");
(*lang_hooks.types.register_builtin_type) (aarch64_simd_polyHI_type_node, (*lang_hooks.types.register_builtin_type) (aarch64_simd_polyHI_type_node,
"__builtin_aarch64_simd_poly16"); "__builtin_aarch64_simd_poly16");
(*lang_hooks.types.register_builtin_type) (aarch64_simd_intTI_type_node,
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,
"__builtin_aarch64_simd_ti"); "__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"); "__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"); "__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"); "__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"); "__builtin_aarch64_simd_xi");
/* Pointers to vector types. */ /* Unsigned integer types for various mode sizes. */
V8QI_pointer_node = build_pointer_type (V8QI_type_node); (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUQI_type_node,
V4HI_pointer_node = build_pointer_type (V4HI_type_node); "__builtin_aarch64_simd_uqi");
V2SI_pointer_node = build_pointer_type (V2SI_type_node); (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUHI_type_node,
V2SF_pointer_node = build_pointer_type (V2SF_type_node); "__builtin_aarch64_simd_uhi");
V16QI_pointer_node = build_pointer_type (V16QI_type_node); (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUSI_type_node,
V8HI_pointer_node = build_pointer_type (V8HI_type_node); "__builtin_aarch64_simd_usi");
V4SI_pointer_node = build_pointer_type (V4SI_type_node); (*lang_hooks.types.register_builtin_type) (aarch64_simd_intUDI_type_node,
V4SF_pointer_node = build_pointer_type (V4SF_type_node); "__builtin_aarch64_simd_udi");
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);
}
}
for (i = 0; i < ARRAY_SIZE (aarch64_simd_builtin_data); i++, fcode++) 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]; aarch64_simd_builtin_datum *d = &aarch64_simd_builtin_data[i];
const char *const modenames[] = const char *const modenames[] =
{ {
"v8qi", "v4hi", "v2si", "v2sf", "di", "df", "v8qi", "v4hi", "v2si", "v2sf", "di", "df",
"v16qi", "v8hi", "v4si", "v4sf", "v2di", "v2df", "v16qi", "v8hi", "v4si", "v4sf", "v2di", "v2df",
"ti", "ei", "oi", "xi", "si", "sf", "hi", "qi" "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]; char namebuf[60];
tree ftype = NULL; tree ftype = NULL;
tree fndecl = NULL; tree fndecl = NULL;
int is_load = 0;
int is_store = 0;
gcc_assert (ARRAY_SIZE (modenames) == T_MAX); gcc_assert (ARRAY_SIZE (modenames) == T_MAX);
d->fcode = fcode; 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: enum machine_mode op_mode = insn_data[d->code].operand[op_num].mode;
case AARCH64_SIMD_LOAD1LANE: enum aarch64_type_qualifiers qualifiers = d->qualifiers[arg_num];
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;
case AARCH64_SIMD_RESULTPAIR: if (qualifiers & qualifier_unsigned)
{ {
switch (insn_data[d->code].operand[1].mode) type_signature[arg_num] = 'u';
{ print_type_signature_p = true;
case V8QImode: }
ftype = void_ftype_pv8qi_v8qi_v8qi; else
break; type_signature[arg_num] = 's';
case V4HImode:
ftype = void_ftype_pv4hi_v4hi_v4hi; /* Skip an internal operand for vget_{low, high}. */
break; if (qualifiers & qualifier_internal)
case V2SImode: continue;
ftype = void_ftype_pv2si_v2si_v2si;
break; /* Some builtins have different user-facing types
case V2SFmode: for certain arguments, encoded in d->mode. */
ftype = void_ftype_pv2sf_v2sf_v2sf; if (qualifiers & qualifier_map_mode)
break; op_mode = modes[d->mode];
case DImode:
ftype = void_ftype_pdi_di_di; /* For pointers, we want a pointer to the basic type
break; of the vector. */
case V16QImode: if (qualifiers & qualifier_pointer && VECTOR_MODE_P (op_mode))
ftype = void_ftype_pv16qi_v16qi_v16qi; op_mode = GET_MODE_INNER (op_mode);
break;
case V8HImode: eltype = aarch64_build_type (op_mode,
ftype = void_ftype_pv8hi_v8hi_v8hi; qualifiers & qualifier_unsigned);
break;
case V4SImode: /* Add qualifiers. */
ftype = void_ftype_pv4si_v4si_v4si; if (qualifiers & qualifier_const)
break; eltype = build_qualified_type (eltype, TYPE_QUAL_CONST);
case V4SFmode:
ftype = void_ftype_pv4sf_v4sf_v4sf; if (qualifiers & qualifier_pointer)
break; eltype = build_pointer_type (eltype);
case V2DImode:
ftype = void_ftype_pv2di_v2di_v2di; /* If we have reached arg_num == 0, we are at a non-void
break; return type. Otherwise, we are still processing
case V2DFmode: arguments. */
ftype = void_ftype_pv2df_v2df_v2df; if (arg_num == 0)
break; return_type = eltype;
default: else
gcc_unreachable (); args = tree_cons (NULL_TREE, eltype, args);
} }
}
break;
case AARCH64_SIMD_REINTERP: ftype = build_function_type (return_type, args);
{
/* 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;
default:
gcc_unreachable ();
}
gcc_assert (ftype != NULL); gcc_assert (ftype != NULL);
snprintf (namebuf, sizeof (namebuf), "__builtin_aarch64_%s%s", if (print_type_signature_p)
d->name, modenames[d->mode]); 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, fndecl = add_builtin_function (namebuf, ftype, fcode, BUILT_IN_MD,
NULL, NULL_TREE); NULL, NULL_TREE);
...@@ -956,8 +668,6 @@ typedef enum ...@@ -956,8 +668,6 @@ typedef enum
SIMD_ARG_STOP SIMD_ARG_STOP
} builtin_simd_arg; } builtin_simd_arg;
#define SIMD_MAX_BUILTIN_ARGS 5
static rtx static rtx
aarch64_simd_expand_args (rtx target, int icode, int have_retval, aarch64_simd_expand_args (rtx target, int icode, int have_retval,
tree exp, ...) tree exp, ...)
...@@ -1085,99 +795,58 @@ aarch64_simd_expand_builtin (int fcode, tree exp, rtx target) ...@@ -1085,99 +795,58 @@ aarch64_simd_expand_builtin (int fcode, tree exp, rtx target)
{ {
aarch64_simd_builtin_datum *d = aarch64_simd_builtin_datum *d =
&aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)]; &aarch64_simd_builtin_data[fcode - (AARCH64_SIMD_BUILTIN_BASE + 1)];
aarch64_simd_itype itype = d->itype;
enum insn_code icode = d->code; 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) is_void = !!(d->qualifiers[0] & qualifier_void);
{
case AARCH64_SIMD_UNOP:
return aarch64_simd_expand_args (target, icode, 1, exp,
SIMD_ARG_COPY_TO_REG,
SIMD_ARG_STOP);
case AARCH64_SIMD_BINOP: num_args += is_void;
{
rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); for (k = 1; k < num_args; k++)
/* Handle constants only if the predicate allows it. */ {
bool op1_const_int_p = /* We have four arrays of data, each indexed in a different fashion.
(CONST_INT_P (arg2) qualifiers - element 0 always describes the function return type.
&& (*insn_data[icode].operand[2].predicate) operands - element 0 is either the operand for return value (if
(arg2, insn_data[icode].operand[2].mode)); the function has a non-void return type) or the operand for the
return aarch64_simd_expand_args first argument.
(target, icode, 1, exp, expr_args - element 0 always holds the first argument.
SIMD_ARG_COPY_TO_REG, args - element 0 is always used for the return type. */
op1_const_int_p ? SIMD_ARG_CONSTANT : SIMD_ARG_COPY_TO_REG, int qualifiers_k = k;
SIMD_ARG_STOP); 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, /* Expand an expression EXP that calls a built-in function,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment