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);

Reply via email to