- for (op = i.operands; --op >= 0; )
- /* Reject eight bit registers, except where the template
- requires them. (eg. movzb) */
- if ((i.types[op] & Reg8) != 0
- && (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
- {
- as_bad (_("`%%%s' not allowed with `%s%c'"),
- i.op[op].regs->reg_name,
- i.tm.name,
- i.suffix);
- return;
- }
- /* Warn if the e prefix on a general reg is missing. */
- else if (((i.types[op] & Reg16) != 0
- || (i.types[op] & Reg32) != 0)
- && (i.tm.operand_types[op] & (Reg32|Acc)) != 0)
- {
- /* Prohibit these changes in the 64bit mode, since
- the lowering is more complicated. */
- as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
- i.op[op].regs->reg_name,
- i.suffix);
- }
- }
- else if (i.suffix == WORD_MNEM_SUFFIX)
- {
- int op;
- for (op = i.operands; --op >= 0;)
- /* Reject eight bit registers, except where the template
- requires them. (eg. movzb) */
- if ((i.types[op] & Reg8) != 0
- && (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
- {
- as_bad (_("`%%%s' not allowed with `%s%c'"),
- i.op[op].regs->reg_name,
- i.tm.name,
- i.suffix);
- return;
- }
- /* Warn if the e prefix on a general reg is present. */
- else if ((!quiet_warnings || flag_code == CODE_64BIT)
- && (i.types[op] & Reg32) != 0
- && (i.tm.operand_types[op] & (Reg16|Acc)) != 0)
- {
- /* Prohibit these changes in the 64bit mode, since
- the lowering is more complicated. */
- if (flag_code == CODE_64BIT)
- as_bad (_("Incorrect register `%%%s' used with`%c' suffix"),
- i.op[op].regs->reg_name,
- i.suffix);
- else
+ if (t == current_templates->end)
+ {
+ /* We found no match. */
+ as_bad (_("suffix or operands invalid for `%s'"),
+ current_templates->start->name);
+ return 0;
+ }
+
+ if (!quiet_warnings)
+ {
+ if (!intel_syntax
+ && ((i.types[0] & JumpAbsolute)
+ != (t->operand_types[0] & JumpAbsolute)))
+ {
+ as_warn (_("indirect %s without `*'"), t->name);
+ }
+
+ if ((t->opcode_modifier & (IsPrefix | IgnoreSize))
+ == (IsPrefix | IgnoreSize))
+ {
+ /* Warn them that a data or address size prefix doesn't
+ affect assembly of the next line of code. */
+ as_warn (_("stand-alone `%s' prefix"), t->name);
+ }
+ }
+
+ /* Copy the template we found. */
+ i.tm = *t;
+ if (found_reverse_match)
+ {
+ /* If we found a reverse match we must alter the opcode
+ direction bit. found_reverse_match holds bits to change
+ (different for int & float insns). */
+
+ i.tm.base_opcode ^= found_reverse_match;
+
+ i.tm.operand_types[0] = t->operand_types[1];
+ i.tm.operand_types[1] = t->operand_types[0];
+ }
+
+ return 1;
+}
+
+static int
+check_string ()
+{
+ int mem_op = (i.types[0] & AnyMem) ? 0 : 1;
+ if ((i.tm.operand_types[mem_op] & EsSeg) != 0)
+ {
+ if (i.seg[0] != NULL && i.seg[0] != &es)
+ {
+ as_bad (_("`%s' operand %d must use `%%es' segment"),
+ i.tm.name,
+ mem_op + 1);
+ return 0;
+ }
+ /* There's only ever one segment override allowed per instruction.
+ This instruction possibly has a legal segment override on the
+ second operand, so copy the segment to where non-string
+ instructions store it, allowing common code. */
+ i.seg[0] = i.seg[1];
+ }
+ else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0)
+ {
+ if (i.seg[1] != NULL && i.seg[1] != &es)
+ {
+ as_bad (_("`%s' operand %d must use `%%es' segment"),
+ i.tm.name,
+ mem_op + 2);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+process_suffix ()
+{
+ /* If matched instruction specifies an explicit instruction mnemonic
+ suffix, use it. */
+ if (i.tm.opcode_modifier & (Size16 | Size32 | Size64))
+ {
+ if (i.tm.opcode_modifier & Size16)
+ i.suffix = WORD_MNEM_SUFFIX;
+ else if (i.tm.opcode_modifier & Size64)
+ i.suffix = QWORD_MNEM_SUFFIX;
+ else
+ i.suffix = LONG_MNEM_SUFFIX;
+ }
+ else if (i.reg_operands)
+ {
+ /* If there's no instruction mnemonic suffix we try to invent one
+ based on register operands. */
+ if (!i.suffix)
+ {
+ /* We take i.suffix from the last register operand specified,
+ Destination register type is more significant than source
+ register type. */
+ int op;
+ for (op = i.operands; --op >= 0;)
+ if ((i.types[op] & Reg)
+ && !(i.tm.operand_types[op] & InOutPortReg))
+ {
+ i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX :
+ (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX :
+ (i.types[op] & Reg64) ? QWORD_MNEM_SUFFIX :
+ LONG_MNEM_SUFFIX);
+ break;
+ }
+ }
+ else if (i.suffix == BYTE_MNEM_SUFFIX)
+ {
+ if (!check_byte_reg ())
+ return 0;
+ }
+ else if (i.suffix == LONG_MNEM_SUFFIX)
+ {
+ if (!check_long_reg ())
+ return 0;
+ }
+ else if (i.suffix == QWORD_MNEM_SUFFIX)
+ {
+ if (!check_qword_reg ())
+ return 0;
+ }
+ else if (i.suffix == WORD_MNEM_SUFFIX)
+ {
+ if (!check_word_reg ())
+ return 0;
+ }
+ else if (intel_syntax && (i.tm.opcode_modifier & IgnoreSize))
+ /* Do nothing if the instruction is going to ignore the prefix. */
+ ;
+ else
+ abort ();
+ }
+ else if ((i.tm.opcode_modifier & DefaultSize) && !i.suffix)
+ {
+ i.suffix = stackop_size;
+ }
+
+ /* Change the opcode based on the operand size given by i.suffix;
+ We need not change things for byte insns. */
+
+ if (!i.suffix && (i.tm.opcode_modifier & W))
+ {
+ as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction"));
+ return 0;
+ }
+
+ /* For movzx and movsx, need to check the register type. */
+ if (intel_syntax
+ && (i.tm.base_opcode == 0xfb6 || i.tm.base_opcode == 0xfbe)
+ && i.suffix == BYTE_MNEM_SUFFIX)
+ {
+ unsigned int prefix = DATA_PREFIX_OPCODE;
+
+ if ((i.op[1].regs->reg_type & Reg16) != 0)
+ if (!add_prefix (prefix))
+ return 0;
+ }
+
+ if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+ {
+ /* It's not a byte, select word/dword operation. */
+ if (i.tm.opcode_modifier & W)
+ {
+ if (i.tm.opcode_modifier & ShortForm)
+ i.tm.base_opcode |= 8;
+ else
+ i.tm.base_opcode |= 1;
+ }
+
+ /* Now select between word & dword operations via the operand
+ size prefix, except for instructions that will ignore this
+ prefix anyway. */
+ if (i.suffix != QWORD_MNEM_SUFFIX
+ && (i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
+ && !(i.tm.opcode_modifier & IgnoreSize))
+ {
+ unsigned int prefix = DATA_PREFIX_OPCODE;
+ if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
+ prefix = ADDR_PREFIX_OPCODE;
+
+ if (!add_prefix (prefix))
+ return 0;
+ }
+
+ if (i.suffix != QWORD_MNEM_SUFFIX && (flag_code == CODE_64BIT)
+ && !(i.tm.opcode_modifier & IgnoreSize)
+ && (i.tm.opcode_modifier & JumpByte))
+ {
+ if (!add_prefix (ADDR_PREFIX_OPCODE))
+ return 0;
+ }
+
+ /* Set mode64 for an operand. */
+ if (i.suffix == QWORD_MNEM_SUFFIX
+ && (i.tm.opcode_modifier & NoRex64) == 0)
+ {
+ i.rex |= REX_MODE64;
+ if (flag_code < CODE_64BIT)
+ {
+ as_bad (_("64bit operations available only in 64bit modes."));
+ return 0;
+ }
+ }
+
+ /* Size floating point instruction. */
+ if (i.suffix == LONG_MNEM_SUFFIX)
+ {
+ if (i.tm.opcode_modifier & FloatMF)
+ i.tm.base_opcode ^= 4;
+ }
+ }
+
+ return 1;
+}
+
+static int
+check_byte_reg ()
+{
+ int op;
+ for (op = i.operands; --op >= 0;)
+ {
+ /* If this is an eight bit register, it's OK. If it's the 16 or
+ 32 bit version of an eight bit register, we will just use the
+ low portion, and that's OK too. */
+ if (i.types[op] & Reg8)
+ continue;
+
+ /* movzx and movsx should not generate this warning. */
+ if (intel_syntax
+ && (i.tm.base_opcode == 0xfb7
+ || i.tm.base_opcode == 0xfb6
+ || i.tm.base_opcode == 0x63
+ || i.tm.base_opcode == 0xfbe
+ || i.tm.base_opcode == 0xfbf))
+ continue;
+
+ if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4
+#if 0
+ /* Check that the template allows eight bit regs. This
+ kills insns such as `orb $1,%edx', which maybe should be
+ allowed. */
+ && (i.tm.operand_types[op] & (Reg8 | InOutPortReg))
+#endif
+ )
+ {
+ /* Prohibit these changes in the 64bit mode, since the
+ lowering is more complicated. */
+ if (flag_code == CODE_64BIT
+ && (i.tm.operand_types[op] & InOutPortReg) == 0)
+ {
+ as_bad (_("Incorrect register `%%%s' used with `%c' suffix"),
+ i.op[op].regs->reg_name,
+ i.suffix);
+ return 0;
+ }