This patch allows the target to override MAX_FIXED_MODE_SIZE for specific kinds of array. We can then give a non-BLK mode to things like uint32x2x4_t, which in turn allows them to be stored in registers.
The patch is a backport of:
http://gcc.gnu.org/ml/gcc-patches/2011-03/msg02192.html
which Richard Guenther approved in principle, but which can't be applied yet because of 4/5. The only difference in the 4.5 version is that 4.5 still uses the old target hook definition scheme, rather than 4.7's target.def.
Richard
gcc/ * hooks.h (hook_bool_mode_uhwi_false): Declare. * hooks.c (hook_bool_mode_uhwi_false): New function. * doc/tm.texi (TARGET_ARRAY_MODE_SUPPORTED_P): Document. * target.h (array_mode_supported_p): New hook. * target-def.h (TARGET_ARRAY_MODE_SUPPORTED_P): Define if undefined. (TARGET_INITIALIZER): Include it. * stor-layout.c (mode_for_array): New function. (layout_type): Use it. * config/arm/arm.c (arm_array_mode_supported_p): New function. (TARGET_ARRAY_MODE_SUPPORTED_P): Define.
Index: gcc/hooks.h =================================================================== --- gcc/hooks.h 2011-04-19 14:14:01.000000000 +0000 +++ gcc/hooks.h 2011-04-19 16:19:06.000000000 +0000 @@ -32,6 +32,8 @@ extern bool hook_bool_const_int_const_in extern bool hook_bool_mode_false (enum machine_mode); extern bool hook_bool_mode_const_rtx_false (enum machine_mode, const_rtx); extern bool hook_bool_mode_const_rtx_true (enum machine_mode, const_rtx); +extern bool hook_bool_mode_uhwi_false (enum machine_mode, + unsigned HOST_WIDE_INT); extern bool hook_bool_tree_false (tree); extern bool hook_bool_const_tree_false (const_tree); extern bool hook_bool_tree_true (tree); Index: gcc/hooks.c =================================================================== --- gcc/hooks.c 2011-04-19 14:14:01.000000000 +0000 +++ gcc/hooks.c 2011-04-19 16:19:06.000000000 +0000 @@ -86,6 +86,15 @@ hook_bool_mode_const_rtx_true (enum mach return true; }
+/* Generic hook that takes (enum machine_mode, unsigned HOST_WIDE_INT) + and returns false. */ +bool +hook_bool_mode_uhwi_false (enum machine_mode mode ATTRIBUTE_UNUSED, + unsigned HOST_WIDE_INT value ATTRIBUTE_UNUSED) +{ + return false; +} + /* Generic hook that takes (FILE *, const char *) and does nothing. */ void hook_void_FILEptr_constcharptr (FILE *a ATTRIBUTE_UNUSED, const char *b ATTRIBUTE_UNUSED) Index: gcc/doc/tm.texi =================================================================== --- gcc/doc/tm.texi 2011-04-19 14:14:01.000000000 +0000 +++ gcc/doc/tm.texi 2011-04-19 16:38:08.000000000 +0000 @@ -4367,6 +4367,34 @@ insns involving vector mode @var{mode}. must have move patterns for this mode. @end deftypefn
+@deftypefn {Target Hook} bool TARGET_ARRAY_MODE_SUPPORTED_P (enum machine_mode @var{mode}, unsigned HOST_WIDE_INT @var{nelems}) +Return true if GCC should try to use a scalar mode to store an array +of @var{nelems} elements, given that each element has mode @var{mode}. +Returning true here overrides the usual @code{MAX_FIXED_MODE} limit +and allows GCC to use any defined integer mode. + +One use of this hook is to support vector load and store operations +that operate on several homogeneous vectors. For example, ARM Neon +has operations like: + +@smallexample +int8x8x3_t vld3_s8 (const int8_t *) +@end smallexample + +where the return type is defined as: + +@smallexample +typedef struct int8x8x3_t +@{ + int8x8_t val[3]; +@} int8x8x3_t; +@end smallexample + +If this hook allows @code{val} to have a scalar mode, then +@code{int8x8x3_t} can have the same mode. GCC can then store +@code{int8x8x3_t}s in registers rather than forcing them onto the stack. +@end deftypefn + @node Scalar Return @subsection How Scalar Function Values Are Returned @cindex return values in registers Index: gcc/target.h =================================================================== --- gcc/target.h 2011-04-19 14:14:01.000000000 +0000 +++ gcc/target.h 2011-04-19 16:38:08.000000000 +0000 @@ -764,6 +764,9 @@ struct gcc_target for further details. */ bool (* vector_mode_supported_p) (enum machine_mode mode);
+ /* See tm.texi. */ + bool (* array_mode_supported_p) (enum machine_mode, unsigned HOST_WIDE_INT); + /* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */ Index: gcc/target-def.h =================================================================== --- gcc/target-def.h 2011-04-19 14:14:01.000000000 +0000 +++ gcc/target-def.h 2011-04-19 16:38:08.000000000 +0000 @@ -553,6 +553,10 @@ #define TARGET_FIXED_POINT_SUPPORTED_P d #define TARGET_VECTOR_MODE_SUPPORTED_P hook_bool_mode_false #endif
+#ifndef TARGET_ARRAY_MODE_SUPPORTED_P +#define TARGET_ARRAY_MODE_SUPPORTED_P hook_bool_mode_uhwi_false +#endif + /* In hooks.c. */ #define TARGET_CANNOT_MODIFY_JUMPS_P hook_bool_void_false #define TARGET_BRANCH_TARGET_REGISTER_CLASS \ @@ -985,6 +989,7 @@ #define TARGET_INITIALIZER \ TARGET_ADDR_SPACE_HOOKS, \ TARGET_SCALAR_MODE_SUPPORTED_P, \ TARGET_VECTOR_MODE_SUPPORTED_P, \ + TARGET_ARRAY_MODE_SUPPORTED_P, \ TARGET_RTX_COSTS, \ TARGET_ADDRESS_COST, \ TARGET_ALLOCATE_INITIAL_VALUE, \ Index: gcc/stor-layout.c =================================================================== --- gcc/stor-layout.c 2011-04-19 14:14:01.000000000 +0000 +++ gcc/stor-layout.c 2011-04-19 14:14:03.000000000 +0000 @@ -507,6 +507,34 @@ get_mode_alignment (enum machine_mode mo return MIN (BIGGEST_ALIGNMENT, MAX (1, mode_base_align[mode]*BITS_PER_UNIT)); }
+/* Return the natural mode of an array, given that it is SIZE bytes in + total and has elements of type ELEM_TYPE. */ + +static enum machine_mode +mode_for_array (tree elem_type, tree size) +{ + tree elem_size; + unsigned HOST_WIDE_INT int_size, int_elem_size; + bool limit_p; + + /* One-element arrays get the component type's mode. */ + elem_size = TYPE_SIZE (elem_type); + if (simple_cst_equal (size, elem_size)) + return TYPE_MODE (elem_type); + + limit_p = true; + if (host_integerp (size, 1) && host_integerp (elem_size, 1)) + { + int_size = tree_low_cst (size, 1); + int_elem_size = tree_low_cst (elem_size, 1); + if (int_elem_size > 0 + && int_size % int_elem_size == 0 + && targetm.array_mode_supported_p (TYPE_MODE (elem_type), + int_size / int_elem_size)) + limit_p = false; + } + return mode_for_size_tree (size, MODE_INT, limit_p); +} /* Subroutine of layout_decl: Force alignment required for the data type. But if the decl itself wants greater alignment, don't override that. */ @@ -2044,14 +2072,8 @@ layout_type (tree type) && (TYPE_MODE (TREE_TYPE (type)) != BLKmode || TYPE_NO_FORCE_BLK (TREE_TYPE (type)))) { - /* One-element arrays get the component type's mode. */ - if (simple_cst_equal (TYPE_SIZE (type), - TYPE_SIZE (TREE_TYPE (type)))) - SET_TYPE_MODE (type, TYPE_MODE (TREE_TYPE (type))); - else - SET_TYPE_MODE (type, mode_for_size_tree (TYPE_SIZE (type), - MODE_INT, 1)); - + SET_TYPE_MODE (type, mode_for_array (TREE_TYPE (type), + TYPE_SIZE (type))); if (TYPE_MODE (type) != BLKmode && STRICT_ALIGNMENT && TYPE_ALIGN (type) < BIGGEST_ALIGNMENT && TYPE_ALIGN (type) < GET_MODE_ALIGNMENT (TYPE_MODE (type))) Index: gcc/config/arm/arm.c =================================================================== --- gcc/config/arm/arm.c 2011-04-19 14:14:01.000000000 +0000 +++ gcc/config/arm/arm.c 2011-04-19 16:38:08.000000000 +0000 @@ -222,6 +222,8 @@ static const char *arm_invalid_return_ty static tree arm_promoted_type (const_tree t); static tree arm_convert_to_type (tree type, tree expr); static bool arm_scalar_mode_supported_p (enum machine_mode); +static bool arm_array_mode_supported_p (enum machine_mode, + unsigned HOST_WIDE_INT); static bool arm_frame_pointer_required (void); static bool arm_can_eliminate (const int, const int); static void arm_asm_trampoline_template (FILE *); @@ -355,6 +357,8 @@ #define TARGET_ADDRESS_COST arm_address_ #define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask #undef TARGET_VECTOR_MODE_SUPPORTED_P #define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p +#undef TARGET_ARRAY_MODE_SUPPORTED_P +#define TARGET_ARRAY_MODE_SUPPORTED_P arm_array_mode_supported_p
#undef TARGET_MACHINE_DEPENDENT_REORG #define TARGET_MACHINE_DEPENDENT_REORG arm_reorg @@ -22435,6 +22439,20 @@ arm_vector_mode_supported_p (enum machin return true;
return false; +} + +/* Implements target hook array_mode_supported_p. */ + +static bool +arm_array_mode_supported_p (enum machine_mode mode, + unsigned HOST_WIDE_INT nelems) +{ + if (TARGET_NEON + && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode)) + && (nelems >= 2 && nelems <= 4)) + return true; + + return false; }
/* Implement TARGET_SHIFT_TRUNCATION_MASK. SImode shifts use normal