We already allow the target to change the size and alignment of a mode. This patch does the same thing for the number of units, which is needed to give command-line control of the SVE vector length.
Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64le-linux-gnu, on top of the poly_int series. I think I can approve this under the gen* maintainership, so if there are no comments in the menatime, I'll apply it if the prerequisites are approved. Thanks, Richard 2017-10-25 Richard Sandiford <richard.sandif...@linaro.org> Alan Hayward <alan.hayw...@arm.com> David Sherwood <david.sherw...@arm.com> gcc/ * machmode.h (mode_precision): Prefix with CONST_MODE_PRECISION. (mode_nunits): Likewise CONST_MODE_NUNITS. * machmode.def (ADJUST_NUNITS): Document. * genmodes.c (mode_data::need_nunits_adj): New field. (blank_mode): Update accordingly. (adj_nunits): New variable. (print_maybe_const_decl): Replace CATEGORY with a NEEDS_ADJ parameter. (emit_mode_size_inline): Set need_bytesize_adj for all modes listed in adj_nunits. (emit_mode_nunits_inline): Set need_nunits_adj for all modes listed in adj_nunits. Don't emit case statements for such modes. (emit_insn_modes_h): Emit definitions of CONST_MODE_NUNITS and CONST_MODE_PRECISION. Make CONST_MODE_SIZE expand to nothing if adj_nunits is nonnull. (emit_mode_precision, emit_mode_nunits): Use print_maybe_const_decl. (emit_mode_unit_size, emit_mode_base_align, emit_mode_ibit) (emit_mode_fbit): Update use of print_maybe_const_decl. (emit_move_size): Likewise. Treat the array as non-const if adj_nunits. (emit_mode_adjustments): Handle adj_nunits. Index: gcc/machmode.h =================================================================== --- gcc/machmode.h 2017-10-25 16:50:35.628184659 +0100 +++ gcc/machmode.h 2017-10-25 16:55:00.469175980 +0100 @@ -23,9 +23,9 @@ #define HAVE_MACHINE_MODES typedef opt_mode<machine_mode> opt_machine_mode; extern CONST_MODE_SIZE poly_uint16_pod mode_size[NUM_MACHINE_MODES]; -extern const poly_uint16_pod mode_precision[NUM_MACHINE_MODES]; +extern CONST_MODE_PRECISION poly_uint16_pod mode_precision[NUM_MACHINE_MODES]; extern const unsigned char mode_inner[NUM_MACHINE_MODES]; -extern const poly_uint16_pod mode_nunits[NUM_MACHINE_MODES]; +extern CONST_MODE_NUNITS poly_uint16_pod mode_nunits[NUM_MACHINE_MODES]; extern CONST_MODE_UNIT_SIZE unsigned char mode_unit_size[NUM_MACHINE_MODES]; extern const unsigned short mode_unit_precision[NUM_MACHINE_MODES]; extern const unsigned char mode_wider[NUM_MACHINE_MODES]; Index: gcc/machmode.def =================================================================== --- gcc/machmode.def 2017-10-25 16:50:35.628184659 +0100 +++ gcc/machmode.def 2017-10-25 16:55:00.468176022 +0100 @@ -169,6 +169,12 @@ along with GCC; see the file COPYING3. Unlike a FORMAT argument, if you are adjusting a float format you must put an & in front of the name of each format structure. + ADJUST_NUNITS (MODE, EXPR); + Like the above, but set the number of nunits of MODE to EXPR. + This changes the size and precision of the mode in proportion + to the change in the number of units; for example, doubling + the number of units doubles the size and precision as well. + Note: If a mode is ever made which is more than 255 bytes wide, machmode.h and genmodes.c will have to be changed to allocate more space for the mode_size and mode_alignment arrays. */ Index: gcc/genmodes.c =================================================================== --- gcc/genmodes.c 2017-10-25 16:50:35.627184698 +0100 +++ gcc/genmodes.c 2017-10-25 16:55:00.468176022 +0100 @@ -72,7 +72,9 @@ struct mode_data unsigned int counter; /* Rank ordering of modes */ unsigned int ibit; /* the number of integral bits */ unsigned int fbit; /* the number of fractional bits */ - bool need_bytesize_adj; /* true if this mode need dynamic size + bool need_nunits_adj; /* true if this mode needs dynamic nunits + adjustment */ + bool need_bytesize_adj; /* true if this mode needs dynamic size adjustment */ unsigned int int_n; /* If nonzero, then __int<INT_N> will be defined */ }; @@ -85,7 +87,7 @@ static const struct mode_data blank_mode 0, "<unknown>", MAX_MODE_CLASS, -1U, -1U, -1U, -1U, 0, 0, 0, 0, 0, 0, - "<unknown>", 0, 0, 0, 0, false, 0 + "<unknown>", 0, 0, 0, 0, false, false, 0 }; static htab_t modes_by_name; @@ -103,6 +105,7 @@ struct mode_adjust unsigned int line; }; +static struct mode_adjust *adj_nunits; static struct mode_adjust *adj_bytesize; static struct mode_adjust *adj_alignment; static struct mode_adjust *adj_format; @@ -786,6 +789,7 @@ make_vector_mode (enum mode_class bclass #define _ADD_ADJUST(A, M, X, C1, C2) \ new_adjust (#M, &adj_##A, #A, #X, MODE_##C1, MODE_##C2, __FILE__, __LINE__) +#define ADJUST_NUNITS(M, X) _ADD_ADJUST (nunits, M, X, RANDOM, RANDOM) #define ADJUST_BYTESIZE(M, X) _ADD_ADJUST (bytesize, M, X, RANDOM, RANDOM) #define ADJUST_ALIGNMENT(M, X) _ADD_ADJUST (alignment, M, X, RANDOM, RANDOM) #define ADJUST_FLOAT_FORMAT(M, X) _ADD_ADJUST (format, M, X, FLOAT, FLOAT) @@ -955,9 +959,9 @@ #define tagged_printf(FMT, ARG, TAG) do #define print_decl(TYPE, NAME, ASIZE) \ puts ("\nconst " TYPE " " NAME "[" ASIZE "] =\n{"); -#define print_maybe_const_decl(TYPE, NAME, ASIZE, CATEGORY) \ +#define print_maybe_const_decl(TYPE, NAME, ASIZE, NEEDS_ADJ) \ printf ("\n" TYPE " " NAME "[" ASIZE "] = \n{\n", \ - adj_##CATEGORY ? "" : "const ") + NEEDS_ADJ ? "" : "const ") #define print_closer() puts ("};") @@ -1015,6 +1019,11 @@ emit_mode_size_inline (void) m->need_bytesize_adj = true; } + /* Changing the number of units by a factor of X also changes the size + by a factor of X. */ + for (mode_adjust *a = adj_nunits; a; a = a->next) + a->mode->need_bytesize_adj = true; + printf ("\ #ifdef __cplusplus\n\ inline __attribute__((__always_inline__))\n\ @@ -1027,7 +1036,7 @@ mode_size_inline (machine_mode mode)\n\ extern %spoly_uint16_pod mode_size[NUM_MACHINE_MODES];\n\ gcc_assert (mode >= 0 && mode < NUM_MACHINE_MODES);\n\ switch (mode)\n\ - {\n", adj_bytesize ? "" : "const "); + {\n", adj_nunits || adj_bytesize ? "" : "const "); for_all_modes (c, m) if (!m->need_bytesize_adj) @@ -1046,7 +1055,10 @@ emit_mode_nunits_inline (void) int c; struct mode_data *m; - puts ("\ + for (mode_adjust *a = adj_nunits; a; a = a->next) + a->mode->need_nunits_adj = true; + + printf ("\ #ifdef __cplusplus\n\ inline __attribute__((__always_inline__))\n\ #else\n\ @@ -1055,12 +1067,13 @@ extern __inline__ __attribute__((__alway poly_uint16\n\ mode_nunits_inline (machine_mode mode)\n\ {\n\ - extern poly_uint16_pod mode_nunits[NUM_MACHINE_MODES];\n\ + extern %spoly_uint16_pod mode_nunits[NUM_MACHINE_MODES];\n\ switch (mode)\n\ - {"); + {\n", adj_nunits ? "" : "const "); for_all_modes (c, m) - printf (" case E_%smode: return %u;\n", m->name, m->ncomponents); + if (!m->need_nunits_adj) + printf (" case E_%smode: return %u;\n", m->name, m->ncomponents); puts ("\ default: return mode_nunits[mode];\n\ @@ -1277,7 +1290,10 @@ enum machine_mode\n{"); };\n"); /* I can't think of a better idea, can you? */ - printf ("#define CONST_MODE_SIZE%s\n", adj_bytesize ? "" : " const"); + printf ("#define CONST_MODE_NUNITS%s\n", adj_nunits ? "" : " const"); + printf ("#define CONST_MODE_PRECISION%s\n", adj_nunits ? "" : " const"); + printf ("#define CONST_MODE_SIZE%s\n", + adj_bytesize || adj_nunits ? "" : " const"); printf ("#define CONST_MODE_UNIT_SIZE%s\n", adj_bytesize ? "" : " const"); printf ("#define CONST_MODE_BASE_ALIGN%s\n", adj_alignment ? "" : " const"); #if 0 /* disabled for backward compatibility, temporary */ @@ -1392,7 +1408,8 @@ emit_mode_precision (void) int c; struct mode_data *m; - print_decl ("poly_uint16_pod", "mode_precision", "NUM_MACHINE_MODES"); + print_maybe_const_decl ("%spoly_uint16_pod", "mode_precision", + "NUM_MACHINE_MODES", adj_nunits); for_all_modes (c, m) if (m->precision != (unsigned int)-1) @@ -1411,7 +1428,7 @@ emit_mode_size (void) struct mode_data *m; print_maybe_const_decl ("%spoly_uint16_pod", "mode_size", - "NUM_MACHINE_MODES", bytesize); + "NUM_MACHINE_MODES", adj_nunits || adj_bytesize); for_all_modes (c, m) tagged_printf ("{ %u" ZERO_COEFFS " }", m->bytesize, m->name); @@ -1425,7 +1442,8 @@ emit_mode_nunits (void) int c; struct mode_data *m; - print_decl ("poly_uint16_pod", "mode_nunits", "NUM_MACHINE_MODES"); + print_maybe_const_decl ("%spoly_uint16_pod", "mode_nunits", + "NUM_MACHINE_MODES", adj_nunits); for_all_modes (c, m) tagged_printf ("{ %u" ZERO_COEFFS " }", m->ncomponents, m->name); @@ -1563,7 +1581,7 @@ emit_mode_unit_size (void) struct mode_data *m; print_maybe_const_decl ("%sunsigned char", "mode_unit_size", - "NUM_MACHINE_MODES", bytesize); + "NUM_MACHINE_MODES", adj_bytesize); for_all_modes (c, m) tagged_printf ("%u", @@ -1604,7 +1622,7 @@ emit_mode_base_align (void) print_maybe_const_decl ("%sunsigned short", "mode_base_align", "NUM_MACHINE_MODES", - alignment); + adj_alignment); for_all_modes (c, m) tagged_printf ("%u", m->alignment, m->name); @@ -1685,6 +1703,23 @@ emit_mode_adjustments (void) \n poly_uint16 ps ATTRIBUTE_UNUSED;\n\ size_t s ATTRIBUTE_UNUSED;"); + for (a = adj_nunits; a; a = a->next) + { + m = a->mode; + printf ("\n" + " {\n" + " /* %s:%d */\n ps = %s;\n", + a->file, a->line, a->adjustment); + printf (" int old_factor = vector_element_size" + " (mode_precision[E_%smode], mode_nunits[E_%smode]);\n", + m->name, m->name); + printf (" mode_precision[E_%smode] = ps * old_factor;\n", m->name); + printf (" mode_size[E_%smode] = exact_div (mode_precision[E_%smode]," + " BITS_PER_UNIT);\n", m->name, m->name); + printf (" mode_nunits[E_%smode] = ps;\n", m->name); + printf (" }\n"); + } + /* Size adjustments must be propagated to all containing modes. A size adjustment forces us to recalculate the alignment too. */ for (a = adj_bytesize; a; a = a->next) @@ -1825,7 +1860,7 @@ emit_mode_ibit (void) print_maybe_const_decl ("%sunsigned char", "mode_ibit", "NUM_MACHINE_MODES", - ibit); + adj_ibit); for_all_modes (c, m) tagged_printf ("%u", m->ibit, m->name); @@ -1843,7 +1878,7 @@ emit_mode_fbit (void) print_maybe_const_decl ("%sunsigned char", "mode_fbit", "NUM_MACHINE_MODES", - fbit); + adj_fbit); for_all_modes (c, m) tagged_printf ("%u", m->fbit, m->name);