The previous patch gives the middle end a way to pass named output
modifiers to targets.  This patch teaches AArch64 to use that mechanism
without changing the meaning of the existing one-letter modifiers.

AArch64 used to dispatch print operands directly from the raw character in
a large switch.  That made sense when the modifier could only be a single
letter, but it does not give us a natural place to say that a named
modifier is internal-only or to attach small pieces of data to a modifier.

This patch moves the AArch64 print operand selection into a small lookup
table.  The existing public modifiers, such as %w0, %x0 and %c0, are
registered under their current names and continue to work for user asm and
machine descriptions.  The table also records whether a modifier is
available to user asm, and has an extra field that later patches use for
small constants such as a lane count.

So for the old form:

  %w0

the hook still ends up selecting the existing W-register printing
behaviour.  For the new form:

  %[SOME_TARGET_NAME]0

the hook asks the middle end for the bracketed name and performs the same
table lookup.  Unknown names, or internal-only names used from user asm,
are rejected with the normal output operand diagnostic.

There should be no intended assembly output change from this patch by
itself.  It is the AArch64 plumbing needed by the following cleanups.

Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.

OK for master?

Thanks,
Tamar

gcc/ChangeLog:

        * config/aarch64/aarch64.cc (aarch64_print_operands): New enum.
        (aarch64_print_operand_info): New structure.
        (operands_cache): New hash map.
        (operands_cache_initializer): New helper.
        (aarch64_lookup_operand): New overloads.
        (aarch64_print_operand): Dispatch via aarch64_print_operands.

---
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 
13a63a936d5956c1ef38d2314f0e618d31e918e9..438c109596e9a2c8483edd5cf98a57358f2fae22
 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -13178,67 +13178,217 @@ sizetochar (int size)
     }
 }
 
+/* Print operands supported by AArch64.  */
+typedef enum aarch64_print_operands {
+  /* An integer or symbol address without a preceding # sign.  */
+  A64_PRINT_constants,
+  /* Print the sign/zero-extend size as a character 8->b, 16->h, 32->w.  Can
+     also be used for masks: 0xff->b, 0xffff->h, 0xffffffff->w.  */
+  A64_PRINT_extended,
+  /* Prints N such that 2^N == X (X must be power of 2 and const int). */
+  A64_PRINT_power2n,
+  /* Print the number of non-zero bits in X (a const_int).  */
+  A64_PRINT_num_nonzero,
+  /* Print the higher numbered register of a pair (TImode) of regs.  */
+  A64_PRINT_hi_regpair,
+  /* If the operand is a duplicated vector constant, replace it with the
+     duplicated scalar.  If the operand is then a floating-point constant,
+     replace it with the integer bit representation.  Print the transformed
+     constant as a signed decimal number.  */
+  A64_PRINT_dup_or_int,
+  /* Print a condition (eq, ne, etc).  */
+  A64_PRINT_cc_code,
+  /* Same as 'm', but invert condition.  */
+  A64_PRINT_inv_cc_code,
+  /* Take the duplicated element in a vector constant and print the negative
+     of it in decimal.  */
+  A64_PRINT_neg_dup_const,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_b_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_h_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_s_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_d_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_simd_q_reg,
+  /* Same for SVE registers.  ('z' was already taken.) Note that it is not
+     necessary to use %Z for operands that have SVE modes.  The convention is 
to
+     use %Z only for non-SVE (or potentially non-SVE) modes.  */
+  A64_PRINT_sve_reg,
+  /* Print a FP/SIMD register name for a register list.  The register printed 
is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_0,
+  /* Print a FP/SIMD register name for a register list.  The register printed 
is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_1,
+  /* Print a FP/SIMD register name for a register list.  The register printed 
is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_2,
+  /* Print a FP/SIMD register name for a register list.  The register printed 
is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_3,
+  /* Print a scalar Integer/FP/SIMD register name + 1.  */
+  A64_PRINT_scalar_intreg_plus_1,
+  /* Print bottom 16 bits of integer constant in hex.  */
+  A64_PRINT_bottom_16bits,
+  /* Take the duplicated element in a vector constant and print it in hex.  */
+  A64_PRINT_dup_as_hex,
+  /* Take the duplicated element in a vector constant and print it as an
+     unsigned integer, in decimal.  */
+  A64_PRINT_dup_as_unsigned_dec,
+  /* Print a general register name or the zero register (32-bit or 64-bit).  */
+  A64_PRINT_gpr_w,
+  /* Print a general register name or the zero register (32-bit or 64-bit).  */
+  A64_PRINT_gpr_x,
+  /* Print a normal operand, if it's a general register, then we assume
+     DImode.  */
+  A64_PRINT_operand,
+  /* Output address constant representing the first argument of X, specifying a
+     relocation offset if appropriate.  */
+  A64_PRINT_output_addr,
+  /* Output constant address specified by X with a relocation offset if
+     appropriate.  */
+  A64_PRINT_output_const_addr,
+  /* Prints address of X, specifying a PC relative relocation mode if
+     appropriate.  */
+  A64_PRINT_output_addr_or_reloc,
+  /* Print NZCV for conditional compare instructions.  */
+  A64_PRINT_cond_cc_code,
+  /* Print a predicate register as pn<N> rather than p<N>.  */
+  A64_PRINT_pred_reg,
+  /* Output address of LDP or STP - this is used for some LDP/STPs which don't
+     use a PARALLEL in their pattern (so the mode needs to be adjusted).  */
+  A64_PRINT_addr_ldp_stp_np,
+  /* Output address of a typical LDP or STP.  */
+  A64_PRINT_addr_ldp_stp,
+  /* Unknown print operand.  */
+  A64_PRINT_UNKNOWN
+} aarch64_print_operands_t;
+
+struct aarch64_print_operand_info
+{
+  aarch64_print_operands_t code;
+  bool user_p;
+  void *extra;
+};
+
+static hash_map<nofree_string_hash, aarch64_print_operand_info> operands_cache;
+
+struct operands_cache_initializer
+{
+  void add (const char *token, aarch64_print_operands_t code,
+           bool user_p = true, void *extra = nullptr)
+  {
+    operands_cache.put (token, { code, user_p, extra });
+  }
+
+  operands_cache_initializer ()
+  {
+#define DEF_PUBLIC_OPERAND(NAME, CODE) add (#NAME, CODE)
+#define DEF_PRIVATE_OPERAND(NAME, CODE) add (#NAME, CODE, false)
+#define DEF_PUBLIC_OPERAND_EXT(NAME, CODE, EXTRA) \
+  add (#NAME, CODE, true, (void *) (uintptr_t) (EXTRA))
+#define DEF_PRIVATE_OPERAND_EXT(NAME, CODE, EXTRA) \
+  add (#NAME, CODE, false, (void *) (uintptr_t) (EXTRA))
+
+    DEF_PUBLIC_OPERAND (A, A64_PRINT_output_addr);
+    DEF_PUBLIC_OPERAND (b, A64_PRINT_scalar_b_reg);
+    DEF_PUBLIC_OPERAND (c, A64_PRINT_constants);
+    DEF_PUBLIC_OPERAND (C, A64_PRINT_dup_as_hex);
+    DEF_PUBLIC_OPERAND (d, A64_PRINT_scalar_d_reg);
+    DEF_PUBLIC_OPERAND (D, A64_PRINT_dup_as_unsigned_dec);
+    DEF_PUBLIC_OPERAND (e, A64_PRINT_extended);
+    DEF_PUBLIC_OPERAND (p, A64_PRINT_power2n);
+    DEF_PUBLIC_OPERAND (P, A64_PRINT_num_nonzero);
+    DEF_PUBLIC_OPERAND (H, A64_PRINT_hi_regpair);
+    DEF_PUBLIC_OPERAND (I, A64_PRINT_dup_or_int);
+    DEF_PUBLIC_OPERAND (m, A64_PRINT_cc_code);
+    DEF_PUBLIC_OPERAND (M, A64_PRINT_inv_cc_code);
+    DEF_PUBLIC_OPERAND (N, A64_PRINT_neg_dup_const);
+    DEF_PUBLIC_OPERAND (h, A64_PRINT_scalar_h_reg);
+    DEF_PUBLIC_OPERAND (q, A64_PRINT_simd_q_reg);
+    DEF_PUBLIC_OPERAND (Z, A64_PRINT_sve_reg);
+    DEF_PUBLIC_OPERAND (s, A64_PRINT_scalar_s_reg);
+    DEF_PUBLIC_OPERAND (S, A64_PRINT_simd_reg_plus_0);
+    DEF_PUBLIC_OPERAND (T, A64_PRINT_simd_reg_plus_1);
+    DEF_PUBLIC_OPERAND (U, A64_PRINT_simd_reg_plus_2);
+    DEF_PUBLIC_OPERAND (V, A64_PRINT_simd_reg_plus_3);
+    DEF_PUBLIC_OPERAND (R, A64_PRINT_scalar_intreg_plus_1);
+    DEF_PUBLIC_OPERAND (w, A64_PRINT_gpr_w);
+    DEF_PUBLIC_OPERAND (L, A64_PRINT_output_const_addr);
+    DEF_PUBLIC_OPERAND (G, A64_PRINT_output_addr_or_reloc);
+    DEF_PUBLIC_OPERAND (k, A64_PRINT_cond_cc_code);
+    DEF_PUBLIC_OPERAND (K, A64_PRINT_pred_reg);
+    DEF_PUBLIC_OPERAND (x, A64_PRINT_gpr_x);
+    DEF_PUBLIC_OPERAND (X, A64_PRINT_bottom_16bits);
+    DEF_PUBLIC_OPERAND (y, A64_PRINT_addr_ldp_stp_np);
+    DEF_PUBLIC_OPERAND (z, A64_PRINT_addr_ldp_stp);
+
+#undef DEF_PUBLIC_OPERAND
+#undef DEF_PRIVATE_OPERAND
+#undef DEF_PUBLIC_OPERAND_EXT
+#undef DEF_PRIVATE_OPERAND_EXT
+  }
+};
+
+/* Force the static initialization.  */
+static operands_cache_initializer init_operands_cache;
+
+/* Perform lookup of print operand based on TOKEN.  */
+static aarch64_print_operand_info
+aarch64_lookup_operand (const char *token)
+{
+  if (auto e = operands_cache.get (token))
+    return *e;
+
+  return { A64_PRINT_UNKNOWN, false, nullptr };
+}
+
+/* Perform lookup of print operand based on legacy single-character CODE,
+   recording the printable form in TOKEN for diagnostics.  */
+
+static aarch64_print_operand_info
+aarch64_lookup_operand (int code, std::string &token)
+{
+  /* CODE 0 is the default operand syntax.  */
+  if (code == 0)
+    return { A64_PRINT_operand, true, nullptr };
+
+  if (code > UCHAR_MAX)
+    {
+      const char *name = output_operand_modifier_name (code);
+      if (!name)
+       return { A64_PRINT_UNKNOWN, false, nullptr };
+      token = name;
+      if (auto e = operands_cache.get (token.c_str ()))
+       {
+         if (output_operand_modifier_user_p (code) && !e->user_p)
+           return { A64_PRINT_UNKNOWN, false, nullptr };
+         return *e;
+       }
+      return { A64_PRINT_UNKNOWN, false, nullptr };
+    }
+
+  token += (char) code;
+  return aarch64_lookup_operand (token.c_str ());
+}
+
 /* Print operand X to file F in a target specific manner according to CODE.
-   The acceptable formatting commands given by CODE are:
-     'c':              An integer or symbol address without a preceding #
-                       sign.
-     'C':              Take the duplicated element in a vector constant
-                       and print it in hex.
-     'D':              Take the duplicated element in a vector constant
-                       and print it as an unsigned integer, in decimal.
-     'e':              Print the sign/zero-extend size as a character 8->b,
-                       16->h, 32->w.  Can also be used for masks:
-                       0xff->b, 0xffff->h, 0xffffffff->w.
-     'I':              If the operand is a duplicated vector constant,
-                       replace it with the duplicated scalar.  If the
-                       operand is then a floating-point constant, replace
-                       it with the integer bit representation.  Print the
-                       transformed constant as a signed decimal number.
-     'p':              Prints N such that 2^N == X (X must be power of 2 and
-                       const int).
-     'P':              Print the number of non-zero bits in X (a const_int).
-     'H':              Print the higher numbered register of a pair (TImode)
-                       of regs.
-     'm':              Print a condition (eq, ne, etc).
-     'M':              Same as 'm', but invert condition.
-     'N':              Take the duplicated element in a vector constant
-                       and print the negative of it in decimal.
-     'b/h/s/d/q':      Print a scalar FP/SIMD register name.
-     'Z':              Same for SVE registers.  ('z' was already taken.)
-                       Note that it is not necessary to use %Z for operands
-                       that have SVE modes.  The convention is to use %Z
-                       only for non-SVE (or potentially non-SVE) modes.
-     'S/T/U/V':                Print a FP/SIMD register name for a register 
list.
-                       The register printed is the FP/SIMD register name
-                       of X + 0/1/2/3 for S/T/U/V.
-     'R':              Print a scalar Integer/FP/SIMD register name + 1.
-     'X':              Print bottom 16 bits of integer constant in hex.
-     'w/x':            Print a general register name or the zero register
-                       (32-bit or 64-bit).
-     '0':              Print a normal operand, if it's a general register,
-                       then we assume DImode.
-     'k':              Print NZCV for conditional compare instructions.
-     'K':              Print a predicate register as pn<N> rather than p<N>
-     'A':              Output address constant representing the first
-                       argument of X, specifying a relocation offset
-                       if appropriate.
-     'L':              Output constant address specified by X
-                       with a relocation offset if appropriate.
-     'G':              Prints address of X, specifying a PC relative
-                       relocation mode if appropriate.
-     'y':              Output address of LDP or STP - this is used for
-                       some LDP/STPs which don't use a PARALLEL in their
-                       pattern (so the mode needs to be adjusted).
-     'z':              Output address of a typical LDP or STP.  */
+   The acceptable formatting commands given by CODE are documented on the
+   enum aarch64_print_operands.  */
 
 static void
-aarch64_print_operand (FILE *f, rtx x, const char * const *p)
+aarch64_print_operand (FILE *f, rtx x, int code)
 {
   rtx elt;
-  int code = p ? (unsigned char)**p : 0;
-  switch (code)
+  std::string token;
+  aarch64_print_operand_info print_info = aarch64_lookup_operand (code, token);
+  aarch64_print_operands_t print_code = print_info.code;
+  switch (print_code)
     {
-    case 'c':
+    case A64_PRINT_constants:
       if (CONST_INT_P (x))
        fprintf (f, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
       else
@@ -13248,16 +13398,18 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
          if (SYMBOL_REF_P (base))
            output_addr_const (f, x);
          else
-           output_operand_lossage ("unsupported operand for code '%c'", code);
+           output_operand_lossage ("unsupported operand for code '%%%s'",
+                                   token.c_str ());
        }
       break;
 
-    case 'e':
+    case A64_PRINT_extended:
       {
        x = unwrap_const_vec_duplicate (x);
        if (!CONST_INT_P (x))
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
 
@@ -13270,19 +13422,21 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
          fputc ('w', f);
        else
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
       }
       break;
 
-    case 'p':
+    case A64_PRINT_power2n:
       {
        int n;
 
        if (!CONST_INT_P (x) || (n = exact_log2 (INTVAL (x))) < 0)
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
 
@@ -13290,17 +13444,18 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       }
       break;
 
-    case 'P':
+    case A64_PRINT_num_nonzero:
       if (!CONST_INT_P (x))
        {
-         output_operand_lossage ("invalid operand for '%%%c'", code);
+         output_operand_lossage ("invalid operand for '%%%s'",
+                                 token.c_str ());
          return;
        }
 
       asm_fprintf (f, "%u", popcount_hwi (INTVAL (x)));
       break;
 
-    case 'H':
+    case A64_PRINT_hi_regpair:
       if (x == const0_rtx)
        {
          asm_fprintf (f, "xzr");
@@ -13309,47 +13464,50 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
 
       if (!REG_P (x) || !GP_REGNUM_P (REGNO (x) + 1))
        {
-         output_operand_lossage ("invalid operand for '%%%c'", code);
+         output_operand_lossage ("invalid operand for '%%%s'",
+                                 token.c_str ());
          return;
        }
 
       asm_fprintf (f, "%s", reg_names [REGNO (x) + 1]);
       break;
 
-    case 'I':
+    case A64_PRINT_dup_or_int:
       {
        x = aarch64_bit_representation (unwrap_const_vec_duplicate (x));
        if (CONST_INT_P (x))
          asm_fprintf (f, "%wd", INTVAL (x));
        else
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
        break;
       }
 
-    case 'M':
-    case 'm':
+    case A64_PRINT_inv_cc_code:
+    case A64_PRINT_cc_code:
       {
         int cond_code;
        /* CONST_TRUE_RTX means al/nv (al is the default, don't print it).  */
        if (x == const_true_rtx)
          {
-           if (code == 'M')
+           if (token == "M")
              fputs ("nv", f);
            return;
          }
 
         if (!COMPARISON_P (x))
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
 
         cond_code = aarch64_get_condition_code (x);
         gcc_assert (cond_code >= 0);
-       if (code == 'M')
+       if (token == "M")
          cond_code = AARCH64_INVERSE_CONDITION_CODE (cond_code);
        if (GET_MODE (XEXP (x, 0)) == CC_NZCmode)
          fputs (aarch64_sve_condition_codes[cond_code], f);
@@ -13358,7 +13516,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       }
       break;
 
-    case 'N':
+    case A64_PRINT_neg_dup_const:
       if (!const_vec_duplicate_p (x, &elt))
        {
          output_operand_lossage ("invalid vector constant");
@@ -13377,39 +13535,46 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
        }
       break;
 
-    case 'b':
-    case 'h':
-    case 's':
-    case 'd':
-    case 'q':
-    case 'Z':
-      code = TOLOWER (code);
-      if (!REG_P (x) || !FP_REGNUM_P (REGNO (x)))
-       {
-         output_operand_lossage ("incompatible floating point / vector 
register operand for '%%%c'", code);
-         return;
-       }
-      asm_fprintf (f, "%c%d", code, REGNO (x) - V0_REGNUM);
+    case A64_PRINT_scalar_b_reg:
+    case A64_PRINT_scalar_h_reg:
+    case A64_PRINT_scalar_s_reg:
+    case A64_PRINT_scalar_d_reg:
+    case A64_PRINT_simd_q_reg:
+    case A64_PRINT_sve_reg:
+      {
+       int code = TOLOWER (token[0]);
+       if (!REG_P (x) || !FP_REGNUM_P (REGNO (x)))
+         {
+           output_operand_lossage ("incompatible floating point / vector 
register operand for '%%%s'",
+                                   token.c_str ());
+           return;
+         }
+       asm_fprintf (f, "%c%d", code, REGNO (x) - V0_REGNUM);
+      }
       break;
 
-    case 'S':
-    case 'T':
-    case 'U':
-    case 'V':
-      if (!REG_P (x) || (!FP_REGNUM_P (REGNO (x)) && !PR_REGNUM_P (REGNO (x))))
-       {
-         output_operand_lossage ("incompatible operand for '%%%c'", code);
-         return;
-       }
-      if (PR_REGNUM_P (REGNO (x)))
-       asm_fprintf (f, "p%d", REGNO (x) - P0_REGNUM + (code - 'S'));
-      else
-       asm_fprintf (f, "%c%d",
-                    aarch64_sve_data_mode_p (GET_MODE (x)) ? 'z' : 'v',
-                    REGNO (x) - V0_REGNUM + (code - 'S'));
+    case A64_PRINT_simd_reg_plus_0:
+    case A64_PRINT_simd_reg_plus_1:
+    case A64_PRINT_simd_reg_plus_2:
+    case A64_PRINT_simd_reg_plus_3:
+      {
+       int code = token[0];
+       if (!REG_P (x)
+           || (!FP_REGNUM_P (REGNO (x)) && !PR_REGNUM_P (REGNO (x))))
+         {
+           output_operand_lossage ("incompatible operand for '%%%c'", code);
+           return;
+         }
+       if (PR_REGNUM_P (REGNO (x)))
+         asm_fprintf (f, "p%d", REGNO (x) - P0_REGNUM + (code - 'S'));
+       else
+         asm_fprintf (f, "%c%d",
+                      aarch64_sve_data_mode_p (GET_MODE (x)) ? 'z' : 'v',
+                      REGNO (x) - V0_REGNUM + (code - 'S'));
+      }
       break;
 
-    case 'R':
+    case A64_PRINT_scalar_intreg_plus_1:
       if (REG_P (x) && FP_REGNUM_P (REGNO (x))
          && (aarch64_advsimd_partial_struct_mode_p (GET_MODE (x))))
        asm_fprintf (f, "d%d", REGNO (x) - V0_REGNUM + 1);
@@ -13418,25 +13583,26 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       else if (REG_P (x) && GP_REGNUM_P (REGNO (x)))
        asm_fprintf (f, "x%d", REGNO (x) - R0_REGNUM + 1);
       else
-       output_operand_lossage ("incompatible register operand for '%%%c'",
-                               code);
+       output_operand_lossage ("incompatible register operand for '%%%s'",
+                               token.c_str ());
       break;
 
-    case 'X':
+    case A64_PRINT_bottom_16bits:
       if (!CONST_INT_P (x))
        {
-         output_operand_lossage ("invalid operand for '%%%c'", code);
+         output_operand_lossage ("invalid operand for '%%%s'", token.c_str ());
          return;
        }
       asm_fprintf (f, "0x%wx", UINTVAL (x) & 0xffff);
       break;
 
-    case 'C':
+    case A64_PRINT_dup_as_hex:
       {
        /* Print a replicated constant in hex.  */
        if (!const_vec_duplicate_p (x, &elt) || !CONST_INT_P (elt))
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
        scalar_mode inner_mode = GET_MODE_INNER (GET_MODE (x));
@@ -13444,13 +13610,14 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       }
       break;
 
-    case 'D':
+    case A64_PRINT_dup_as_unsigned_dec:
       {
        /* Print a replicated constant in decimal, treating it as
           unsigned.  */
        if (!const_vec_duplicate_p (x, &elt) || !CONST_INT_P (elt))
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
        scalar_mode inner_mode = GET_MODE_INNER (GET_MODE (x));
@@ -13458,29 +13625,29 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       }
       break;
 
-    case 'w':
-    case 'x':
+    case A64_PRINT_gpr_w:
+    case A64_PRINT_gpr_x:
       if (aarch64_const_zero_rtx_p (x))
        {
-         asm_fprintf (f, "%czr", code);
+         asm_fprintf (f, "%czr", token[0]);
          break;
        }
 
       if (REG_P (x) && GP_REGNUM_P (REGNO (x)))
        {
-         asm_fprintf (f, "%c%d", code, REGNO (x) - R0_REGNUM);
+         asm_fprintf (f, "%c%d", token[0], REGNO (x) - R0_REGNUM);
          break;
        }
 
       if (REG_P (x) && REGNO (x) == SP_REGNUM)
        {
-         asm_fprintf (f, "%ssp", code == 'w' ? "w" : "");
+         asm_fprintf (f, "%ssp", token == "w" ? "w" : "");
          break;
        }
 
       /* Fall through */
 
-    case 0:
+    case A64_PRINT_operand:
       if (x == NULL)
        {
          output_operand_lossage ("missing operand");
@@ -13581,7 +13748,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
        }
       break;
 
-    case 'A':
+    case A64_PRINT_output_addr:
       if (GET_CODE (x) == HIGH)
        x = XEXP (x, 0);
 
@@ -13617,7 +13784,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       output_addr_const (asm_out_file, x);
       break;
 
-    case 'L':
+    case A64_PRINT_output_const_addr:
       switch (aarch64_classify_symbolic_expression (x))
        {
        case SYMBOL_SMALL_GOT_4G:
@@ -13658,7 +13825,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       output_addr_const (asm_out_file, x);
       break;
 
-    case 'G':
+    case A64_PRINT_output_addr_or_reloc:
       switch (aarch64_classify_symbolic_expression (x))
        {
        case SYMBOL_TLSLE24:
@@ -13670,13 +13837,14 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       output_addr_const (asm_out_file, x);
       break;
 
-    case 'k':
+    case A64_PRINT_cond_cc_code:
       {
        HOST_WIDE_INT cond_code;
 
        if (!CONST_INT_P (x))
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
 
@@ -13686,40 +13854,43 @@ aarch64_print_operand (FILE *f, rtx x, const char * 
const *p)
       }
       break;
 
-    case 'K':
+    case A64_PRINT_pred_reg:
       if (!REG_P (x) || !PR_REGNUM_P (REGNO (x)))
        {
-         output_operand_lossage ("invalid operand for '%%%c'", code);
+         output_operand_lossage ("invalid operand for '%%%s'", token.c_str ());
          return;
        }
       asm_fprintf (f, "pn%d", REGNO (x) - P0_REGNUM);
       break;
 
-    case 'y':
-    case 'z':
+    case A64_PRINT_addr_ldp_stp_np:
+    case A64_PRINT_addr_ldp_stp:
       {
        machine_mode mode = GET_MODE (x);
 
        if (!MEM_P (x)
-           || (code == 'y'
+           || (token == "y"
                && maybe_ne (GET_MODE_SIZE (mode), 8)
                && maybe_ne (GET_MODE_SIZE (mode), 16)
                && maybe_ne (GET_MODE_SIZE (mode), 32)))
          {
-           output_operand_lossage ("invalid operand for '%%%c'", code);
+           output_operand_lossage ("invalid operand for '%%%s'",
+                                   token.c_str ());
            return;
          }
 
        if (!aarch64_print_address_internal (f, mode, XEXP (x, 0),
-                                           code == 'y'
+                                           token == "y"
                                            ? ADDR_QUERY_LDP_STP_N
                                            : ADDR_QUERY_LDP_STP))
-         output_operand_lossage ("invalid operand prefix '%%%c'", code);
+         output_operand_lossage ("invalid operand prefix '%%%s'",
+                                 token.c_str ());
       }
       break;
 
     default:
-      output_operand_lossage ("invalid operand prefix '%%%c'", code);
+      output_operand_lossage ("invalid operand prefix '%%%s'",
+                             token.c_str ());
       return;
     }
 }


-- 
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 13a63a936d5956c1ef38d2314f0e618d31e918e9..438c109596e9a2c8483edd5cf98a57358f2fae22 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -13178,67 +13178,217 @@ sizetochar (int size)
     }
 }
 
+/* Print operands supported by AArch64.  */
+typedef enum aarch64_print_operands {
+  /* An integer or symbol address without a preceding # sign.  */
+  A64_PRINT_constants,
+  /* Print the sign/zero-extend size as a character 8->b, 16->h, 32->w.  Can
+     also be used for masks: 0xff->b, 0xffff->h, 0xffffffff->w.  */
+  A64_PRINT_extended,
+  /* Prints N such that 2^N == X (X must be power of 2 and const int). */
+  A64_PRINT_power2n,
+  /* Print the number of non-zero bits in X (a const_int).  */
+  A64_PRINT_num_nonzero,
+  /* Print the higher numbered register of a pair (TImode) of regs.  */
+  A64_PRINT_hi_regpair,
+  /* If the operand is a duplicated vector constant, replace it with the
+     duplicated scalar.  If the operand is then a floating-point constant,
+     replace it with the integer bit representation.  Print the transformed
+     constant as a signed decimal number.  */
+  A64_PRINT_dup_or_int,
+  /* Print a condition (eq, ne, etc).  */
+  A64_PRINT_cc_code,
+  /* Same as 'm', but invert condition.  */
+  A64_PRINT_inv_cc_code,
+  /* Take the duplicated element in a vector constant and print the negative
+     of it in decimal.  */
+  A64_PRINT_neg_dup_const,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_b_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_h_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_s_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_scalar_d_reg,
+  /* Print a scalar FP/SIMD register name.  */
+  A64_PRINT_simd_q_reg,
+  /* Same for SVE registers.  ('z' was already taken.) Note that it is not
+     necessary to use %Z for operands that have SVE modes.  The convention is to
+     use %Z only for non-SVE (or potentially non-SVE) modes.  */
+  A64_PRINT_sve_reg,
+  /* Print a FP/SIMD register name for a register list.  The register printed is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_0,
+  /* Print a FP/SIMD register name for a register list.  The register printed is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_1,
+  /* Print a FP/SIMD register name for a register list.  The register printed is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_2,
+  /* Print a FP/SIMD register name for a register list.  The register printed is
+     the FP/SIMD register name of X + 0/1/2/3 for S/T/U/V.  */
+  A64_PRINT_simd_reg_plus_3,
+  /* Print a scalar Integer/FP/SIMD register name + 1.  */
+  A64_PRINT_scalar_intreg_plus_1,
+  /* Print bottom 16 bits of integer constant in hex.  */
+  A64_PRINT_bottom_16bits,
+  /* Take the duplicated element in a vector constant and print it in hex.  */
+  A64_PRINT_dup_as_hex,
+  /* Take the duplicated element in a vector constant and print it as an
+     unsigned integer, in decimal.  */
+  A64_PRINT_dup_as_unsigned_dec,
+  /* Print a general register name or the zero register (32-bit or 64-bit).  */
+  A64_PRINT_gpr_w,
+  /* Print a general register name or the zero register (32-bit or 64-bit).  */
+  A64_PRINT_gpr_x,
+  /* Print a normal operand, if it's a general register, then we assume
+     DImode.  */
+  A64_PRINT_operand,
+  /* Output address constant representing the first argument of X, specifying a
+     relocation offset if appropriate.  */
+  A64_PRINT_output_addr,
+  /* Output constant address specified by X with a relocation offset if
+     appropriate.  */
+  A64_PRINT_output_const_addr,
+  /* Prints address of X, specifying a PC relative relocation mode if
+     appropriate.  */
+  A64_PRINT_output_addr_or_reloc,
+  /* Print NZCV for conditional compare instructions.  */
+  A64_PRINT_cond_cc_code,
+  /* Print a predicate register as pn<N> rather than p<N>.  */
+  A64_PRINT_pred_reg,
+  /* Output address of LDP or STP - this is used for some LDP/STPs which don't
+     use a PARALLEL in their pattern (so the mode needs to be adjusted).  */
+  A64_PRINT_addr_ldp_stp_np,
+  /* Output address of a typical LDP or STP.  */
+  A64_PRINT_addr_ldp_stp,
+  /* Unknown print operand.  */
+  A64_PRINT_UNKNOWN
+} aarch64_print_operands_t;
+
+struct aarch64_print_operand_info
+{
+  aarch64_print_operands_t code;
+  bool user_p;
+  void *extra;
+};
+
+static hash_map<nofree_string_hash, aarch64_print_operand_info> operands_cache;
+
+struct operands_cache_initializer
+{
+  void add (const char *token, aarch64_print_operands_t code,
+	    bool user_p = true, void *extra = nullptr)
+  {
+    operands_cache.put (token, { code, user_p, extra });
+  }
+
+  operands_cache_initializer ()
+  {
+#define DEF_PUBLIC_OPERAND(NAME, CODE) add (#NAME, CODE)
+#define DEF_PRIVATE_OPERAND(NAME, CODE) add (#NAME, CODE, false)
+#define DEF_PUBLIC_OPERAND_EXT(NAME, CODE, EXTRA) \
+  add (#NAME, CODE, true, (void *) (uintptr_t) (EXTRA))
+#define DEF_PRIVATE_OPERAND_EXT(NAME, CODE, EXTRA) \
+  add (#NAME, CODE, false, (void *) (uintptr_t) (EXTRA))
+
+    DEF_PUBLIC_OPERAND (A, A64_PRINT_output_addr);
+    DEF_PUBLIC_OPERAND (b, A64_PRINT_scalar_b_reg);
+    DEF_PUBLIC_OPERAND (c, A64_PRINT_constants);
+    DEF_PUBLIC_OPERAND (C, A64_PRINT_dup_as_hex);
+    DEF_PUBLIC_OPERAND (d, A64_PRINT_scalar_d_reg);
+    DEF_PUBLIC_OPERAND (D, A64_PRINT_dup_as_unsigned_dec);
+    DEF_PUBLIC_OPERAND (e, A64_PRINT_extended);
+    DEF_PUBLIC_OPERAND (p, A64_PRINT_power2n);
+    DEF_PUBLIC_OPERAND (P, A64_PRINT_num_nonzero);
+    DEF_PUBLIC_OPERAND (H, A64_PRINT_hi_regpair);
+    DEF_PUBLIC_OPERAND (I, A64_PRINT_dup_or_int);
+    DEF_PUBLIC_OPERAND (m, A64_PRINT_cc_code);
+    DEF_PUBLIC_OPERAND (M, A64_PRINT_inv_cc_code);
+    DEF_PUBLIC_OPERAND (N, A64_PRINT_neg_dup_const);
+    DEF_PUBLIC_OPERAND (h, A64_PRINT_scalar_h_reg);
+    DEF_PUBLIC_OPERAND (q, A64_PRINT_simd_q_reg);
+    DEF_PUBLIC_OPERAND (Z, A64_PRINT_sve_reg);
+    DEF_PUBLIC_OPERAND (s, A64_PRINT_scalar_s_reg);
+    DEF_PUBLIC_OPERAND (S, A64_PRINT_simd_reg_plus_0);
+    DEF_PUBLIC_OPERAND (T, A64_PRINT_simd_reg_plus_1);
+    DEF_PUBLIC_OPERAND (U, A64_PRINT_simd_reg_plus_2);
+    DEF_PUBLIC_OPERAND (V, A64_PRINT_simd_reg_plus_3);
+    DEF_PUBLIC_OPERAND (R, A64_PRINT_scalar_intreg_plus_1);
+    DEF_PUBLIC_OPERAND (w, A64_PRINT_gpr_w);
+    DEF_PUBLIC_OPERAND (L, A64_PRINT_output_const_addr);
+    DEF_PUBLIC_OPERAND (G, A64_PRINT_output_addr_or_reloc);
+    DEF_PUBLIC_OPERAND (k, A64_PRINT_cond_cc_code);
+    DEF_PUBLIC_OPERAND (K, A64_PRINT_pred_reg);
+    DEF_PUBLIC_OPERAND (x, A64_PRINT_gpr_x);
+    DEF_PUBLIC_OPERAND (X, A64_PRINT_bottom_16bits);
+    DEF_PUBLIC_OPERAND (y, A64_PRINT_addr_ldp_stp_np);
+    DEF_PUBLIC_OPERAND (z, A64_PRINT_addr_ldp_stp);
+
+#undef DEF_PUBLIC_OPERAND
+#undef DEF_PRIVATE_OPERAND
+#undef DEF_PUBLIC_OPERAND_EXT
+#undef DEF_PRIVATE_OPERAND_EXT
+  }
+};
+
+/* Force the static initialization.  */
+static operands_cache_initializer init_operands_cache;
+
+/* Perform lookup of print operand based on TOKEN.  */
+static aarch64_print_operand_info
+aarch64_lookup_operand (const char *token)
+{
+  if (auto e = operands_cache.get (token))
+    return *e;
+
+  return { A64_PRINT_UNKNOWN, false, nullptr };
+}
+
+/* Perform lookup of print operand based on legacy single-character CODE,
+   recording the printable form in TOKEN for diagnostics.  */
+
+static aarch64_print_operand_info
+aarch64_lookup_operand (int code, std::string &token)
+{
+  /* CODE 0 is the default operand syntax.  */
+  if (code == 0)
+    return { A64_PRINT_operand, true, nullptr };
+
+  if (code > UCHAR_MAX)
+    {
+      const char *name = output_operand_modifier_name (code);
+      if (!name)
+	return { A64_PRINT_UNKNOWN, false, nullptr };
+      token = name;
+      if (auto e = operands_cache.get (token.c_str ()))
+	{
+	  if (output_operand_modifier_user_p (code) && !e->user_p)
+	    return { A64_PRINT_UNKNOWN, false, nullptr };
+	  return *e;
+	}
+      return { A64_PRINT_UNKNOWN, false, nullptr };
+    }
+
+  token += (char) code;
+  return aarch64_lookup_operand (token.c_str ());
+}
+
 /* Print operand X to file F in a target specific manner according to CODE.
-   The acceptable formatting commands given by CODE are:
-     'c':		An integer or symbol address without a preceding #
-			sign.
-     'C':		Take the duplicated element in a vector constant
-			and print it in hex.
-     'D':		Take the duplicated element in a vector constant
-			and print it as an unsigned integer, in decimal.
-     'e':		Print the sign/zero-extend size as a character 8->b,
-			16->h, 32->w.  Can also be used for masks:
-			0xff->b, 0xffff->h, 0xffffffff->w.
-     'I':		If the operand is a duplicated vector constant,
-			replace it with the duplicated scalar.  If the
-			operand is then a floating-point constant, replace
-			it with the integer bit representation.  Print the
-			transformed constant as a signed decimal number.
-     'p':		Prints N such that 2^N == X (X must be power of 2 and
-			const int).
-     'P':		Print the number of non-zero bits in X (a const_int).
-     'H':		Print the higher numbered register of a pair (TImode)
-			of regs.
-     'm':		Print a condition (eq, ne, etc).
-     'M':		Same as 'm', but invert condition.
-     'N':		Take the duplicated element in a vector constant
-			and print the negative of it in decimal.
-     'b/h/s/d/q':	Print a scalar FP/SIMD register name.
-     'Z':		Same for SVE registers.  ('z' was already taken.)
-			Note that it is not necessary to use %Z for operands
-			that have SVE modes.  The convention is to use %Z
-			only for non-SVE (or potentially non-SVE) modes.
-     'S/T/U/V':		Print a FP/SIMD register name for a register list.
-			The register printed is the FP/SIMD register name
-			of X + 0/1/2/3 for S/T/U/V.
-     'R':		Print a scalar Integer/FP/SIMD register name + 1.
-     'X':		Print bottom 16 bits of integer constant in hex.
-     'w/x':		Print a general register name or the zero register
-			(32-bit or 64-bit).
-     '0':		Print a normal operand, if it's a general register,
-			then we assume DImode.
-     'k':		Print NZCV for conditional compare instructions.
-     'K':		Print a predicate register as pn<N> rather than p<N>
-     'A':		Output address constant representing the first
-			argument of X, specifying a relocation offset
-			if appropriate.
-     'L':		Output constant address specified by X
-			with a relocation offset if appropriate.
-     'G':		Prints address of X, specifying a PC relative
-			relocation mode if appropriate.
-     'y':		Output address of LDP or STP - this is used for
-			some LDP/STPs which don't use a PARALLEL in their
-			pattern (so the mode needs to be adjusted).
-     'z':		Output address of a typical LDP or STP.  */
+   The acceptable formatting commands given by CODE are documented on the
+   enum aarch64_print_operands.  */
 
 static void
-aarch64_print_operand (FILE *f, rtx x, const char * const *p)
+aarch64_print_operand (FILE *f, rtx x, int code)
 {
   rtx elt;
-  int code = p ? (unsigned char)**p : 0;
-  switch (code)
+  std::string token;
+  aarch64_print_operand_info print_info = aarch64_lookup_operand (code, token);
+  aarch64_print_operands_t print_code = print_info.code;
+  switch (print_code)
     {
-    case 'c':
+    case A64_PRINT_constants:
       if (CONST_INT_P (x))
 	fprintf (f, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
       else
@@ -13248,16 +13398,18 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
 	  if (SYMBOL_REF_P (base))
 	    output_addr_const (f, x);
 	  else
-	    output_operand_lossage ("unsupported operand for code '%c'", code);
+	    output_operand_lossage ("unsupported operand for code '%%%s'",
+				    token.c_str ());
 	}
       break;
 
-    case 'e':
+    case A64_PRINT_extended:
       {
 	x = unwrap_const_vec_duplicate (x);
 	if (!CONST_INT_P (x))
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 
@@ -13270,19 +13422,21 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
 	  fputc ('w', f);
 	else
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
       }
       break;
 
-    case 'p':
+    case A64_PRINT_power2n:
       {
 	int n;
 
 	if (!CONST_INT_P (x) || (n = exact_log2 (INTVAL (x))) < 0)
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 
@@ -13290,17 +13444,18 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       }
       break;
 
-    case 'P':
+    case A64_PRINT_num_nonzero:
       if (!CONST_INT_P (x))
 	{
-	  output_operand_lossage ("invalid operand for '%%%c'", code);
+	  output_operand_lossage ("invalid operand for '%%%s'",
+				  token.c_str ());
 	  return;
 	}
 
       asm_fprintf (f, "%u", popcount_hwi (INTVAL (x)));
       break;
 
-    case 'H':
+    case A64_PRINT_hi_regpair:
       if (x == const0_rtx)
 	{
 	  asm_fprintf (f, "xzr");
@@ -13309,47 +13464,50 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
 
       if (!REG_P (x) || !GP_REGNUM_P (REGNO (x) + 1))
 	{
-	  output_operand_lossage ("invalid operand for '%%%c'", code);
+	  output_operand_lossage ("invalid operand for '%%%s'",
+				  token.c_str ());
 	  return;
 	}
 
       asm_fprintf (f, "%s", reg_names [REGNO (x) + 1]);
       break;
 
-    case 'I':
+    case A64_PRINT_dup_or_int:
       {
 	x = aarch64_bit_representation (unwrap_const_vec_duplicate (x));
 	if (CONST_INT_P (x))
 	  asm_fprintf (f, "%wd", INTVAL (x));
 	else
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 	break;
       }
 
-    case 'M':
-    case 'm':
+    case A64_PRINT_inv_cc_code:
+    case A64_PRINT_cc_code:
       {
         int cond_code;
 	/* CONST_TRUE_RTX means al/nv (al is the default, don't print it).  */
 	if (x == const_true_rtx)
 	  {
-	    if (code == 'M')
+	    if (token == "M")
 	      fputs ("nv", f);
 	    return;
 	  }
 
         if (!COMPARISON_P (x))
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 
         cond_code = aarch64_get_condition_code (x);
         gcc_assert (cond_code >= 0);
-	if (code == 'M')
+	if (token == "M")
 	  cond_code = AARCH64_INVERSE_CONDITION_CODE (cond_code);
 	if (GET_MODE (XEXP (x, 0)) == CC_NZCmode)
 	  fputs (aarch64_sve_condition_codes[cond_code], f);
@@ -13358,7 +13516,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       }
       break;
 
-    case 'N':
+    case A64_PRINT_neg_dup_const:
       if (!const_vec_duplicate_p (x, &elt))
 	{
 	  output_operand_lossage ("invalid vector constant");
@@ -13377,39 +13535,46 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
 	}
       break;
 
-    case 'b':
-    case 'h':
-    case 's':
-    case 'd':
-    case 'q':
-    case 'Z':
-      code = TOLOWER (code);
-      if (!REG_P (x) || !FP_REGNUM_P (REGNO (x)))
-	{
-	  output_operand_lossage ("incompatible floating point / vector register operand for '%%%c'", code);
-	  return;
-	}
-      asm_fprintf (f, "%c%d", code, REGNO (x) - V0_REGNUM);
+    case A64_PRINT_scalar_b_reg:
+    case A64_PRINT_scalar_h_reg:
+    case A64_PRINT_scalar_s_reg:
+    case A64_PRINT_scalar_d_reg:
+    case A64_PRINT_simd_q_reg:
+    case A64_PRINT_sve_reg:
+      {
+	int code = TOLOWER (token[0]);
+	if (!REG_P (x) || !FP_REGNUM_P (REGNO (x)))
+	  {
+	    output_operand_lossage ("incompatible floating point / vector register operand for '%%%s'",
+				    token.c_str ());
+	    return;
+	  }
+	asm_fprintf (f, "%c%d", code, REGNO (x) - V0_REGNUM);
+      }
       break;
 
-    case 'S':
-    case 'T':
-    case 'U':
-    case 'V':
-      if (!REG_P (x) || (!FP_REGNUM_P (REGNO (x)) && !PR_REGNUM_P (REGNO (x))))
-	{
-	  output_operand_lossage ("incompatible operand for '%%%c'", code);
-	  return;
-	}
-      if (PR_REGNUM_P (REGNO (x)))
-	asm_fprintf (f, "p%d", REGNO (x) - P0_REGNUM + (code - 'S'));
-      else
-	asm_fprintf (f, "%c%d",
-		     aarch64_sve_data_mode_p (GET_MODE (x)) ? 'z' : 'v',
-		     REGNO (x) - V0_REGNUM + (code - 'S'));
+    case A64_PRINT_simd_reg_plus_0:
+    case A64_PRINT_simd_reg_plus_1:
+    case A64_PRINT_simd_reg_plus_2:
+    case A64_PRINT_simd_reg_plus_3:
+      {
+	int code = token[0];
+	if (!REG_P (x)
+	    || (!FP_REGNUM_P (REGNO (x)) && !PR_REGNUM_P (REGNO (x))))
+	  {
+	    output_operand_lossage ("incompatible operand for '%%%c'", code);
+	    return;
+	  }
+	if (PR_REGNUM_P (REGNO (x)))
+	  asm_fprintf (f, "p%d", REGNO (x) - P0_REGNUM + (code - 'S'));
+	else
+	  asm_fprintf (f, "%c%d",
+		       aarch64_sve_data_mode_p (GET_MODE (x)) ? 'z' : 'v',
+		       REGNO (x) - V0_REGNUM + (code - 'S'));
+      }
       break;
 
-    case 'R':
+    case A64_PRINT_scalar_intreg_plus_1:
       if (REG_P (x) && FP_REGNUM_P (REGNO (x))
 	  && (aarch64_advsimd_partial_struct_mode_p (GET_MODE (x))))
 	asm_fprintf (f, "d%d", REGNO (x) - V0_REGNUM + 1);
@@ -13418,25 +13583,26 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       else if (REG_P (x) && GP_REGNUM_P (REGNO (x)))
 	asm_fprintf (f, "x%d", REGNO (x) - R0_REGNUM + 1);
       else
-	output_operand_lossage ("incompatible register operand for '%%%c'",
-				code);
+	output_operand_lossage ("incompatible register operand for '%%%s'",
+				token.c_str ());
       break;
 
-    case 'X':
+    case A64_PRINT_bottom_16bits:
       if (!CONST_INT_P (x))
 	{
-	  output_operand_lossage ("invalid operand for '%%%c'", code);
+	  output_operand_lossage ("invalid operand for '%%%s'", token.c_str ());
 	  return;
 	}
       asm_fprintf (f, "0x%wx", UINTVAL (x) & 0xffff);
       break;
 
-    case 'C':
+    case A64_PRINT_dup_as_hex:
       {
 	/* Print a replicated constant in hex.  */
 	if (!const_vec_duplicate_p (x, &elt) || !CONST_INT_P (elt))
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 	scalar_mode inner_mode = GET_MODE_INNER (GET_MODE (x));
@@ -13444,13 +13610,14 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       }
       break;
 
-    case 'D':
+    case A64_PRINT_dup_as_unsigned_dec:
       {
 	/* Print a replicated constant in decimal, treating it as
 	   unsigned.  */
 	if (!const_vec_duplicate_p (x, &elt) || !CONST_INT_P (elt))
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 	scalar_mode inner_mode = GET_MODE_INNER (GET_MODE (x));
@@ -13458,29 +13625,29 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       }
       break;
 
-    case 'w':
-    case 'x':
+    case A64_PRINT_gpr_w:
+    case A64_PRINT_gpr_x:
       if (aarch64_const_zero_rtx_p (x))
 	{
-	  asm_fprintf (f, "%czr", code);
+	  asm_fprintf (f, "%czr", token[0]);
 	  break;
 	}
 
       if (REG_P (x) && GP_REGNUM_P (REGNO (x)))
 	{
-	  asm_fprintf (f, "%c%d", code, REGNO (x) - R0_REGNUM);
+	  asm_fprintf (f, "%c%d", token[0], REGNO (x) - R0_REGNUM);
 	  break;
 	}
 
       if (REG_P (x) && REGNO (x) == SP_REGNUM)
 	{
-	  asm_fprintf (f, "%ssp", code == 'w' ? "w" : "");
+	  asm_fprintf (f, "%ssp", token == "w" ? "w" : "");
 	  break;
 	}
 
       /* Fall through */
 
-    case 0:
+    case A64_PRINT_operand:
       if (x == NULL)
 	{
 	  output_operand_lossage ("missing operand");
@@ -13581,7 +13748,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
 	}
       break;
 
-    case 'A':
+    case A64_PRINT_output_addr:
       if (GET_CODE (x) == HIGH)
 	x = XEXP (x, 0);
 
@@ -13617,7 +13784,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       output_addr_const (asm_out_file, x);
       break;
 
-    case 'L':
+    case A64_PRINT_output_const_addr:
       switch (aarch64_classify_symbolic_expression (x))
 	{
 	case SYMBOL_SMALL_GOT_4G:
@@ -13658,7 +13825,7 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       output_addr_const (asm_out_file, x);
       break;
 
-    case 'G':
+    case A64_PRINT_output_addr_or_reloc:
       switch (aarch64_classify_symbolic_expression (x))
 	{
 	case SYMBOL_TLSLE24:
@@ -13670,13 +13837,14 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       output_addr_const (asm_out_file, x);
       break;
 
-    case 'k':
+    case A64_PRINT_cond_cc_code:
       {
 	HOST_WIDE_INT cond_code;
 
 	if (!CONST_INT_P (x))
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 
@@ -13686,40 +13854,43 @@ aarch64_print_operand (FILE *f, rtx x, const char * const *p)
       }
       break;
 
-    case 'K':
+    case A64_PRINT_pred_reg:
       if (!REG_P (x) || !PR_REGNUM_P (REGNO (x)))
 	{
-	  output_operand_lossage ("invalid operand for '%%%c'", code);
+	  output_operand_lossage ("invalid operand for '%%%s'", token.c_str ());
 	  return;
 	}
       asm_fprintf (f, "pn%d", REGNO (x) - P0_REGNUM);
       break;
 
-    case 'y':
-    case 'z':
+    case A64_PRINT_addr_ldp_stp_np:
+    case A64_PRINT_addr_ldp_stp:
       {
 	machine_mode mode = GET_MODE (x);
 
 	if (!MEM_P (x)
-	    || (code == 'y'
+	    || (token == "y"
 		&& maybe_ne (GET_MODE_SIZE (mode), 8)
 		&& maybe_ne (GET_MODE_SIZE (mode), 16)
 		&& maybe_ne (GET_MODE_SIZE (mode), 32)))
 	  {
-	    output_operand_lossage ("invalid operand for '%%%c'", code);
+	    output_operand_lossage ("invalid operand for '%%%s'",
+				    token.c_str ());
 	    return;
 	  }
 
 	if (!aarch64_print_address_internal (f, mode, XEXP (x, 0),
-					    code == 'y'
+					    token == "y"
 					    ? ADDR_QUERY_LDP_STP_N
 					    : ADDR_QUERY_LDP_STP))
-	  output_operand_lossage ("invalid operand prefix '%%%c'", code);
+	  output_operand_lossage ("invalid operand prefix '%%%s'",
+				  token.c_str ());
       }
       break;
 
     default:
-      output_operand_lossage ("invalid operand prefix '%%%c'", code);
+      output_operand_lossage ("invalid operand prefix '%%%s'",
+			      token.c_str ());
       return;
     }
 }

Reply via email to