[2/2,RFC,17] AArch64: example aarch64 for multi-letter operand support

Message ID adYPahttR1BY90lT@arm.com
State New
Headers
Series [1/2,RFC,17] [middle-end: Supporting multi character string formatters |

Commit Message

Tamar Christina April 8, 2026, 8:18 a.m. UTC
  This is an example conversion of how we can implement multiple characters print
operands.

This switches the single character switch statemen with a switch statement on an
enum value instead and uses a hash_map to map the string tokens to the enum.

This also allows us to internally name the operands something more human
friendly.  i.e. A64_PRINT_sve_reg is more descriptive than 'Z'.

Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.

Any comments?

Thanks,
Tamar

gcc/ChangeLog:

	* config/aarch64/aarch64-sme.md (@aarch64_sme_<optab><mode><mode>):
	Test conversion on one of the patterns we can cleanup.
	* config/aarch64/aarch64.cc (struct operands_cache_initializer): New.
	(aarch64_lookup_operand): New.
	(aarch64_print_operand): Refactor and use.

---


--
  

Patch

diff --git a/gcc/config/aarch64/aarch64-sme.md b/gcc/config/aarch64/aarch64-sme.md
index f24e91997fd640f82c11353dd196fe334daec630..dfa0cb718ffb42fb35b711557142363a264ef75a 100644
--- a/gcc/config/aarch64/aarch64-sme.md
+++ b/gcc/config/aarch64/aarch64-sme.md
@@ -897,10 +897,7 @@  (define_insn "@aarch64_sme_<optab><mode><mode>"
 	   (const_int 1)]
 	  SME_READZ_HV))]
   "TARGET_STREAMING_SME2p1"
-  {
-    operands[3] = GEN_INT (<vector_count> - 1);
-    return "movaz\t%0, za%1<hv>.<Vetype>[%w2, 0:%3]";
-  }
+  "movaz\t%0, za%1<hv>.<Vetype>[%w2, 0:%[SME_VC]0]"
 )
 
 (define_insn "*aarch64_sme_<optab><mode><mode>_plus"
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 1bf54641f581e90bb629d2fcd2f0d32a2c9474f9..2e69ee1b7583876bf1c15b67397a066bc5224633 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -12955,67 +12955,178 @@  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;
+
+static hash_map<nofree_string_hash, aarch64_print_operands_t> operands_cache;
+
+struct operands_cache_initializer
+{
+  operands_cache_initializer ()
+  {
+    operands_cache.put ("A", A64_PRINT_output_addr);
+    operands_cache.put ("b", A64_PRINT_scalar_b_reg);
+    operands_cache.put ("c", A64_PRINT_constants);
+    operands_cache.put ("C", A64_PRINT_dup_as_hex);
+    operands_cache.put ("d", A64_PRINT_scalar_d_reg);
+    operands_cache.put ("D", A64_PRINT_dup_as_unsigned_dec);
+    operands_cache.put ("e", A64_PRINT_extended);
+    operands_cache.put ("p", A64_PRINT_power2n);
+    operands_cache.put ("P", A64_PRINT_num_nonzero);
+    operands_cache.put ("H", A64_PRINT_hi_regpair);
+    operands_cache.put ("I", A64_PRINT_dup_or_int);
+    operands_cache.put ("m", A64_PRINT_cc_code);
+    operands_cache.put ("M", A64_PRINT_inv_cc_code);
+    operands_cache.put ("N", A64_PRINT_neg_dup_const);
+    operands_cache.put ("h", A64_PRINT_scalar_h_reg);
+    operands_cache.put ("q", A64_PRINT_simd_q_reg);
+    operands_cache.put ("Z", A64_PRINT_sve_reg);
+    operands_cache.put ("s", A64_PRINT_scalar_s_reg);
+    operands_cache.put ("S", A64_PRINT_simd_reg_plus_0);
+    operands_cache.put ("T", A64_PRINT_simd_reg_plus_1);
+    operands_cache.put ("U", A64_PRINT_simd_reg_plus_2);
+    operands_cache.put ("V", A64_PRINT_simd_reg_plus_3);
+    operands_cache.put ("R", A64_PRINT_scalar_intreg_plus_1);
+    operands_cache.put ("w", A64_PRINT_gpr_w);
+    operands_cache.put ("L", A64_PRINT_output_const_addr);
+    operands_cache.put ("G", A64_PRINT_output_addr_or_reloc);
+    operands_cache.put ("k", A64_PRINT_cond_cc_code);
+    operands_cache.put ("K", A64_PRINT_pred_reg);
+    operands_cache.put ("x", A64_PRINT_gpr_x);
+    operands_cache.put ("X", A64_PRINT_bottom_16bits);
+    operands_cache.put ("y", A64_PRINT_addr_ldp_stp_np);
+    operands_cache.put ("z", A64_PRINT_addr_ldp_stp);
+  }
+};
+
+/* Force the static initialization.  */
+static operands_cache_initializer init_operands_cache;
+
+/* Perform lookup of print operand based on current string.  */
+static aarch64_print_operands_t
+aarch64_lookup_operand (const char * const *p, std::string &parsed)
+{
+  /* If p is null then it's the same as the special numerical operand 0.  */
+  if (!p)
+    return A64_PRINT_operand;
+
+  /* Parse the token, multiline tokens must end in a number.  */
+  if (**p == '[')
+    {
+	char v = **(++p);
+	while (v != ']')
+	  {
+	    parsed += v;
+	    v = **(++p);
+	  }
+    }
+  else
+    parsed += **p;
+
+  if (auto e = operands_cache.get (parsed.c_str ()))
+    return *e;
+
+  return A64_PRINT_UNKNOWN;
+}
+
 /* 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)
 {
   rtx elt;
-  int code = p ? (unsigned char)**p : 0;
-  switch (code)
+  std::string token;
+  switch (aarch64_lookup_operand (p, token))
     {
-    case 'c':
+    case A64_PRINT_constants:
       if (CONST_INT_P (x))
 	fprintf (f, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
       else
@@ -13025,16 +13136,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;
 	  }
 
@@ -13047,19 +13160,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;
 	  }
 
@@ -13067,17 +13182,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");
@@ -13086,47 +13202,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);
@@ -13135,7 +13254,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");
@@ -13154,39 +13273,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);
@@ -13195,25 +13321,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));
@@ -13221,13 +13348,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));
@@ -13235,29 +13363,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");
@@ -13358,7 +13486,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);
 
@@ -13394,7 +13522,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:
@@ -13435,7 +13563,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:
@@ -13447,13 +13575,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;
 	  }
 
@@ -13463,40 +13592,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;
     }
 }