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
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'. */
/* 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. */
{
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);
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);
}
&& 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.
{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},
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. */
}
}
}
}
- 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:
}
}
+ /* 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;
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)));
#define QL_LDST_AT \
{ \
QLF2(X, imm_tag), \
- QLF2(SP, imm_tag), \
}
/* e.g. RBIT <Wd>, <Wn>. */
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 \
{ \
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),