@@ -77,7 +77,11 @@ enum arm_type_qualifiers
/* qualifier_const_pointer | qualifier_map_mode */
qualifier_const_pointer_map_mode = 0x86,
/* Polynomial types. */
- qualifier_poly = 0x100
+ qualifier_poly = 0x100,
+ /* Lane indices - must be in range, and flipped for bigendian. */
+ qualifier_lane_index = 0x200,
+ /* Lane indices for single lane structure loads and stores. */
+ qualifier_struct_load_store_lane_index = 0x400
};
/* The qualifier_internal allows generation of a unary builtin from
@@ -1927,6 +1931,8 @@ arm_expand_unop_builtin (enum insn_code icode,
typedef enum {
NEON_ARG_COPY_TO_REG,
NEON_ARG_CONSTANT,
+ NEON_ARG_LANE_INDEX,
+ NEON_ARG_STRUCT_LOAD_STORE_LANE_INDEX,
NEON_ARG_MEMORY,
NEON_ARG_STOP
} builtin_arg;
@@ -1984,9 +1990,9 @@ neon_dereference_pointer (tree exp, tree type, machine_mode mem_mode,
/* Expand a Neon builtin. */
static rtx
arm_expand_neon_args (rtx target, machine_mode map_mode, int fcode,
- int icode, int have_retval, tree exp, ...)
+ int icode, int have_retval, tree exp,
+ builtin_arg *args)
{
- va_list ap;
rtx pat;
tree arg[SIMD_MAX_BUILTIN_ARGS];
rtx op[SIMD_MAX_BUILTIN_ARGS];
@@ -2001,13 +2007,11 @@ arm_expand_neon_args (rtx target, machine_mode map_mode, int fcode,
|| !(*insn_data[icode].operand[0].predicate) (target, tmode)))
target = gen_reg_rtx (tmode);
- va_start (ap, exp);
-
formals = TYPE_ARG_TYPES (TREE_TYPE (arm_builtin_decls[fcode]));
for (;;)
{
- builtin_arg thisarg = (builtin_arg) va_arg (ap, int);
+ builtin_arg thisarg = args[argc];
if (thisarg == NEON_ARG_STOP)
break;
@@ -2043,17 +2047,46 @@ arm_expand_neon_args (rtx target, machine_mode map_mode, int fcode,
op[argc] = copy_to_mode_reg (mode[argc], op[argc]);
break;
+ case NEON_ARG_STRUCT_LOAD_STORE_LANE_INDEX:
+ gcc_assert (argc > 1);
+ if (CONST_INT_P (op[argc]))
+ {
+ arm_neon_lane_bounds (op[argc], 0,
+ GET_MODE_NUNITS (map_mode), exp);
+ /* Keep to GCC-vector-extension lane indices in the RTL. */
+ op[argc] =
+ GEN_INT (ENDIAN_LANE_N (map_mode, INTVAL (op[argc])));
+ }
+ goto constant_arg;
+
+ case NEON_ARG_LANE_INDEX:
+ /* Must be a previous operand into which this is an index. */
+ gcc_assert (argc > 0);
+ if (CONST_INT_P (op[argc]))
+ {
+ machine_mode vmode = insn_data[icode].operand[argc - 1].mode;
+ arm_neon_lane_bounds (op[argc],
+ 0, GET_MODE_NUNITS (vmode), exp);
+ /* Keep to GCC-vector-extension lane indices in the RTL. */
+ op[argc] = GEN_INT (ENDIAN_LANE_N (vmode, INTVAL (op[argc])));
+ }
+ /* Fall through - if the lane index isn't a constant then
+ the next case will error. */
case NEON_ARG_CONSTANT:
+constant_arg:
if (!(*insn_data[icode].operand[opno].predicate)
(op[argc], mode[argc]))
- error_at (EXPR_LOCATION (exp), "incompatible type for argument %d, "
- "expected %<const int%>", argc + 1);
+ {
+ error ("%Kargument %d must be a constant immediate",
+ exp, argc + 1);
+ return const0_rtx;
+ }
break;
+
case NEON_ARG_MEMORY:
/* Check if expand failed. */
if (op[argc] == const0_rtx)
{
- va_end (ap);
return 0;
}
gcc_assert (MEM_P (op[argc]));
@@ -2076,8 +2109,6 @@ arm_expand_neon_args (rtx target, machine_mode map_mode, int fcode,
}
}
- va_end (ap);
-
if (have_retval)
switch (argc)
{
@@ -2170,7 +2201,11 @@ arm_expand_neon_builtin (int fcode, tree exp, rtx target)
int operands_k = k - is_void;
int expr_args_k = k - 1;
- if (d->qualifiers[qualifiers_k] & qualifier_immediate)
+ if (d->qualifiers[qualifiers_k] & qualifier_lane_index)
+ args[k] = NEON_ARG_LANE_INDEX;
+ else if (d->qualifiers[qualifiers_k] & qualifier_struct_load_store_lane_index)
+ args[k] = NEON_ARG_STRUCT_LOAD_STORE_LANE_INDEX;
+ else if (d->qualifiers[qualifiers_k] & qualifier_immediate)
args[k] = NEON_ARG_CONSTANT;
else if (d->qualifiers[qualifiers_k] & qualifier_maybe_immediate)
{
@@ -2195,11 +2230,7 @@ arm_expand_neon_builtin (int fcode, tree exp, rtx target)
the function is void, and a 1 if it is not. */
return arm_expand_neon_args
(target, d->mode, fcode, icode, !is_void, exp,
- args[1],
- args[2],
- args[3],
- args[4],
- NEON_ARG_STOP);
+ &args[1]);
}
/* Expand an expression EXP that calls a built-in function,
@@ -343,6 +343,10 @@ extern void arm_cpu_builtins (struct cpp_reader *, int);
extern bool arm_is_constant_pool_ref (rtx);
+void arm_neon_lane_bounds (rtx operand, HOST_WIDE_INT low, HOST_WIDE_INT high,
+ const_tree exp);
+
+
/* Flags used to identify the presence of processor capabilities. */
/* Bit values used to identify processor capabilities. */
@@ -29652,4 +29652,24 @@ arm_sched_fusion_priority (rtx_insn *insn, int max_pri,
*pri = tmp;
return;
}
+
+/* Bounds-check lanes. Ensure OPERAND lies between LOW (inclusive) and
+ HIGH (exclusive). */
+void
+arm_neon_lane_bounds (rtx operand, HOST_WIDE_INT low, HOST_WIDE_INT high,
+ const_tree exp)
+{
+ HOST_WIDE_INT lane;
+ gcc_assert (CONST_INT_P (operand));
+ lane = INTVAL (operand);
+
+ if (lane < low || lane >= high)
+ {
+ if (exp)
+ error ("%Klane %ld out of range %ld - %ld", exp, lane, low, high - 1);
+ else
+ error ("lane %ld out of range %ld - %ld", lane, low, high - 1);
+ }
+}
+
#include "gt-arm.h"
@@ -298,6 +298,9 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
#define TARGET_BPABI false
#endif
+#define ENDIAN_LANE_N(mode, n) \
+ (BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 - n : n)
+
/* Support for a compile-time default CPU, et cetera. The rules are:
--with-arch is ignored if -march or -mcpu are specified.
--with-cpu is ignored if -march or -mcpu are specified, and is overridden