[PATCH 11/23] aarch64: Add F_REQUIRES_SP and eliminate QLF_SP and QLF_WSP

Alice Carlotti alice.carlotti@arm.com
Thu May 7 16:11:56 GMT 2026


Add a new opcode flag F_REQUIRES_SP and use that to enforce the
requirement for at least one SP operand in the mov (to/from SP) opcode.

This requirement was the only reason for the existence of the QLF_SP and
QLF_WSP qualifiers.  Delete them, and remove the confusing code that
would switch between SP and non-SP qualifiers in the middle of qualifier
matching.


diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 30087f5fe3c4703253abe285f78108b68e86fc33..a604a66c573135a1432120e90a0b5e809c7a72f4 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -1017,8 +1017,6 @@ enum aarch64_opnd_qualifier
      indicating the operand data size or a specific register.  */
   AARCH64_OPND_QLF_W,	/* Wn, WZR or WSP.  */
   AARCH64_OPND_QLF_X,	/* Xn, XZR or XSP.  */
-  AARCH64_OPND_QLF_WSP,	/* WSP.  */
-  AARCH64_OPND_QLF_SP,	/* SP.  */
 
   /* Qualifying an operand which is a floating-point register, a SIMD
      vector element or a SIMD vector element list; indicating operand data
@@ -1489,7 +1487,10 @@ extern const aarch64_opcode aarch64_opcode_table[];
    to be optional, then we also implicitly specify (N+1)th operand to also be
    optional.  */
 #define F_OPD_PAIR_OPT (1ULL << 32)
-
+/* This instruction requires one of its operands to be a stack pointer.  This
+   is used for alias instructions that would otherwise overlap a different
+   instruction.  */
+#define F_REQUIRES_SP (1ULL << 44)
 /* For the instruction with size[22:23] field.  */
 #define F_OPD_SIZE (1ULL << 34)
 /* RCPC3 instruction has the field of 'size'.  */
@@ -1537,7 +1538,7 @@ extern const aarch64_opcode aarch64_opcode_table[];
 /* As above, plus PN registers.  */
 #define F_INVALID_IMM_SYMS_3 (3ULL << 42)
 
-/* Next bit is 44, and 33 is also unused.  */
+/* Next bit is 44.  */
 
 /* Instruction constraints.  */
 /* This instruction has a predication constraint on the instruction at PC+4.  */
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 8a1f0bb2c3d8445ef9e8a3da3c06140648fd7121..d44bc6dc6a4cdaaaed48e2cf286afccba91019c0 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -2044,7 +2044,6 @@ do_special_encoding (struct aarch64_inst *inst)
     {
       idx = select_operand_for_sf_field_coding (inst->opcode);
       value = (inst->operands[idx].qualifier == AARCH64_OPND_QLF_X
-	       || inst->operands[idx].qualifier == AARCH64_OPND_QLF_SP
 	       || inst->operands[idx].qualifier == AARCH64_OPND_QLF_S_D)
 	? 1 : 0;
       insert_field (FLD_sf, &inst->value, value, 0);
@@ -2054,8 +2053,7 @@ do_special_encoding (struct aarch64_inst *inst)
   if (inst->opcode->flags & F_LSE_SZ)
     {
       idx = select_operand_for_sf_field_coding (inst->opcode);
-      value = (inst->operands[idx].qualifier == AARCH64_OPND_QLF_X
-	       || inst->operands[idx].qualifier == AARCH64_OPND_QLF_SP)
+      value = (inst->operands[idx].qualifier == AARCH64_OPND_QLF_X)
 	? 1 : 0;
       insert_field (FLD_lse_sz, &inst->value, value, 0);
     }
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 9d2f98d8d1428ed0d45c28222a4212db87ba9b75..a1560a40eb3942ee2fcc098c3e03f1b8a5fe1184 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -713,41 +713,6 @@ aarch64_zero_register_p (const aarch64_opnd_info *operand)
 	  && operand->reg.regno == 31);
 }
 
-/* Return true if the operand *OPERAND that has the operand code
-   OPERAND->TYPE and been qualified by OPERAND->QUALIFIER can be also
-   qualified by the qualifier TARGET.  */
-
-static inline bool
-operand_also_qualified_p (const struct aarch64_opnd_info *operand,
-			  aarch64_opnd_qualifier_t target)
-{
-  switch (operand->qualifier)
-    {
-    case AARCH64_OPND_QLF_W:
-      if (target == AARCH64_OPND_QLF_WSP && aarch64_stack_pointer_p (operand))
-	return true;
-      break;
-    case AARCH64_OPND_QLF_X:
-      if (target == AARCH64_OPND_QLF_SP && aarch64_stack_pointer_p (operand))
-	return true;
-      break;
-    case AARCH64_OPND_QLF_WSP:
-      if (target == AARCH64_OPND_QLF_W
-	  && operand_maybe_stack_pointer (aarch64_operands + operand->type))
-	return true;
-      break;
-    case AARCH64_OPND_QLF_SP:
-      if (target == AARCH64_OPND_QLF_X
-	  && operand_maybe_stack_pointer (aarch64_operands + operand->type))
-	return true;
-      break;
-    default:
-      break;
-    }
-
-  return false;
-}
-
 /* Given qualifier sequence list QSEQ_LIST and the known qualifier KNOWN_QLF
    for operand KNOWN_IDX, return the expected qualifier for operand IDX.
 
@@ -829,8 +794,6 @@ static const struct operand_qualifier_data aarch64_opnd_qualifiers[] =
 
   {4, 1, 0x0, "w", OQK_OPD_VARIANT},
   {8, 1, 0x1, "x", OQK_OPD_VARIANT},
-  {4, 1, 0x0, "wsp", OQK_OPD_VARIANT},
-  {8, 1, 0x1, "sp", OQK_OPD_VARIANT},
 
   {1, 1, 0x0, "b", OQK_OPD_VARIANT},
   {2, 1, 0x1, "h", OQK_OPD_VARIANT},
@@ -1089,15 +1052,7 @@ aarch64_find_best_match (const aarch64_inst *inst,
 	      continue;
 	    }
 	  else if (*qualifiers != inst->operands[j].qualifier)
-	    {
-	      /* Unless the target qualifier can also qualify the operand
-		 (which has already had a non-nil qualifier), non-equal
-		 qualifiers are generally un-matched.  */
-	      if (operand_also_qualified_p (inst->operands + j, *qualifiers))
-		continue;
-	      else
-		invalid += 1;
-	    }
+	    invalid += 1;
 	  else
 	    continue;	/* Equal qualifiers are certainly matched.  */
 	}
@@ -1866,20 +1821,6 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 		}
 	   }
 	}
-      switch (qualifier)
-	{
-	case AARCH64_OPND_QLF_WSP:
-	case AARCH64_OPND_QLF_SP:
-	  if (!aarch64_stack_pointer_p (opnd))
-	    {
-	      set_other_error (mismatch_detail, idx,
-		       _("stack pointer register expected"));
-	      return false;
-	    }
-	  break;
-	default:
-	  break;
-	}
       break;
 
     case AARCH64_OPND_CLASS_SVE_REG:
@@ -3624,6 +3565,29 @@ aarch64_match_operands_constraint (aarch64_inst *inst,
 	}
     }
 
+  /* Check constraints involving multiple operands.  */
+  if (inst->opcode->flags & F_REQUIRES_SP)
+    {
+      bool sp_found = false;
+      for (i = 0; i < AARCH64_MAX_OPND_NUM; ++i)
+	{
+	  enum aarch64_opnd type = inst->opcode->operands[i];
+	  if (type == AARCH64_OPND_NIL)
+	    break;
+	  if (aarch64_stack_pointer_p (&(inst->operands[i])))
+	    {
+	      sp_found = true;
+	      break;
+	    }
+	}
+      if (!sp_found)
+	{
+	  set_other_error (mismatch_detail, -1,
+			   _("expected at least one stack pointer operand"));
+	  return false;
+	}
+    }
+
   DEBUG_TRACE ("PASS");
 
   return true;
@@ -4204,9 +4168,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
     case AARCH64_OPND_SVE_Rn_SP:
     case AARCH64_OPND_Rm_SP:
       assert (opnd->qualifier == AARCH64_OPND_QLF_W
-	      || opnd->qualifier == AARCH64_OPND_QLF_WSP
-	      || opnd->qualifier == AARCH64_OPND_QLF_X
-	      || opnd->qualifier == AARCH64_OPND_QLF_SP);
+	      || opnd->qualifier == AARCH64_OPND_QLF_X);
       snprintf (buf, size, "%s",
 		style_reg (styler, get_int_reg_name (opnd->reg.regno,
 						     opnd->qualifier, 1)));
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index a6913b8073f9b99eb32ccda0a3274b8516ff6121..a7899394146e4e476ed7ff36124fc1654a116cea 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -173,7 +173,6 @@
 #define QL_LDST_AT		\
 {				\
   QLF2(X, imm_tag),		\
-  QLF2(SP, imm_tag),		\
 }
 
 /* e.g. RBIT <Wd>, <Wn>.  */
@@ -191,15 +190,6 @@
   QLF2(X,X),			\
 }
 
-/* e.g. MOV <Wd|WSP>, <Wn|WSP>, at least one SP.  */
-#define QL_I2SP			\
-{				\
-  QLF2(WSP,W),			\
-  QLF2(W,WSP),			\
-  QLF2(SP,X),			\
-  QLF2(X,SP),			\
-}
-
 /* e.g. REV <Wd>, <Wn>.  */
 #define QL_I2SAMEW		\
 {				\
@@ -3700,7 +3690,7 @@ const struct aarch64_opcode aarch64_opcode_table[] =
   CORE_INSN ("cmp",  0x6b20001f, 0x7fe0001f, addsub_ext, 0, OP2 (Rn_SP, Rm_EXT),        QL_I2_EXT, F_SUBCLASS_OTHER | F_ALIAS | F_SF),
   /* Add/subtract (immediate).  */
   CORE_INSN ("add",  0x11000000, 0x7f000000, addsub_imm, OP_ADD, OP3 (Rd_SP, Rn_SP, AIMM), QL_R2NIL, F_ARITH_ADD | F_HAS_ALIAS | F_SF),
-  CORE_INSN ("mov",  0x11000000, 0x7ffffc00, addsub_imm, 0, OP2 (Rd_SP, Rn_SP),       QL_I2SP, F_ARITH_MOV | F_ALIAS | F_SF),
+  CORE_INSN ("mov",  0x11000000, 0x7ffffc00, addsub_imm, 0, OP2 (Rd_SP, Rn_SP),       QL_I2SAME, F_ARITH_MOV | F_ALIAS | F_SF | F_REQUIRES_SP),
   CORE_INSN ("adds", 0x31000000, 0x7f000000, addsub_imm, 0, OP3 (Rd, Rn_SP, AIMM),    QL_R2NIL, F_ARITH_ADD | F_HAS_ALIAS | F_SF),
   CORE_INSN ("cmn",  0x3100001f, 0x7f00001f, addsub_imm, 0, OP2 (Rn_SP, AIMM),        QL_R1NIL, F_SUBCLASS_OTHER | F_ALIAS | F_SF),
   CORE_INSN ("sub",  0x51000000, 0x7f000000, addsub_imm, 0, OP3 (Rd_SP, Rn_SP, AIMM), QL_R2NIL, F_ARITH_SUB | F_SF),


More information about the Binutils mailing list