tc-i386.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,311 行 · 第 1/5 页
C
2,311 行
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]; } /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */ if (SYSV386_COMPAT && intel_syntax && (i.tm.base_opcode & 0xfffffde0) == 0xdce0) i.tm.base_opcode ^= FloatR; if (i.tm.opcode_modifier & FWait) if (! add_prefix (FWAIT_OPCODE)) return; /* Check string instruction segment overrides. */ if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0) { 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; } /* 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; } } } if (i.reg_operands && flag_code < CODE_64BIT) { int op; for (op = i.operands; --op >= 0;) if ((i.types[op] & Reg) && (i.op[op].regs->reg_flags & (RegRex64|RegRex))) { as_bad (_("Extended register `%%%s' available only in 64bit mode."), i.op[op].regs->reg_name); return; } } /* 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) { 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);#if REGISTER_WARNINGS if (!quiet_warnings && (i.tm.operand_types[op] & InOutPortReg) == 0) as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), (i.op[op].regs + (i.types[op] & Reg16 ? REGNAM_AL - REGNAM_AX : REGNAM_AL - REGNAM_EAX))->reg_name, i.op[op].regs->reg_name, i.suffix);#endif continue; } /* Any other register is bad. */ if (i.types[op] & (Reg | RegMMX | RegXMM | SReg2 | SReg3 | Control | Debug | Test | FloatReg | FloatAcc)) { as_bad (_("`%%%s' not allowed with `%s%c'"), i.op[op].regs->reg_name, i.tm.name, i.suffix); return; } } } else if (i.suffix == LONG_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 missing. */ else if ((!quiet_warnings || flag_code == CODE_64BIT) && (i.types[op] & Reg16) != 0 && (i.tm.operand_types[op] & (Reg32|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);#if REGISTER_WARNINGS else as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name, i.op[op].regs->reg_name, i.suffix);#endif } /* Warn if the r prefix on a general reg is missing. */ else if ((i.types[op] & Reg64) != 0 && (i.tm.operand_types[op] & (Reg32|Acc)) != 0) { as_bad (_("Incorrect register `%%%s' used with`%c' suffix"), i.op[op].regs->reg_name, i.suffix); } } else if (i.suffix == QWORD_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 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 REGISTER_WARNINGS as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name, i.op[op].regs->reg_name, i.suffix);#endif } } 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; } /* Make still unresolved immediate matches conform to size of immediate given in i.suffix. Note: overlap2 cannot be an immediate! */ if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S)) && overlap0 != Imm8 && overlap0 != Imm8S && overlap0 != Imm16 && overlap0 != Imm32S && overlap0 != Imm32 && overlap0 != Imm64) { if (i.suffix) { overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX ? (Imm8 | Imm8S) : (i.suffix == WORD_MNEM_SUFFIX ? Imm16 : (i.suffix == QWORD_MNEM_SUFFIX ? Imm64 | Imm32S : Imm32))); } else if (overlap0 == (Imm16 | Imm32S | Imm32) || overlap0 == (Imm16 | Imm32) || overlap0 == (Imm16 | Imm32S)) { overlap0 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32S; } if (overlap0 != Imm8 && overlap0 != Imm8S && overlap0 != Imm16 && overlap0 != Imm32S && overlap0 != Imm32 && overlap0 != Imm64) { as_bad (_("no instruction mnemonic suffix given; can't determine immediate size")); return; } } if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32)) && overlap1 != Imm8 && overlap1 != Imm8S && overlap1 != Imm16 && overlap1 != Imm32S && overlap1 != Imm32 && overlap1 != Imm64) { if (i.suffix) { overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX ? (Imm8 | Imm8S) : (i.suffix == WORD_MNEM_SUFFIX ? Imm16 : (i.suffix == QWORD_MNEM_SUFFIX ? Imm64 | Imm32S : Imm32))); } else if (overlap1 == (Imm16 | Imm32 | Imm32S) || overlap1 == (Imm16 | Imm32) || overlap1 == (Imm16 | Imm32S)) { overlap1 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32S; } if (overlap1 != Imm8 && overlap1 != Imm8S && overlap1 != Imm16 && overlap1 != Imm32S && overlap1 != Imm32 && overlap1 != Imm64) { as_bad (_("no instruction mnemonic suffix given; can't determine immediate size %x %c"),overlap1, i.suffix); return; } } assert ((overlap2 & Imm) == 0); i.types[0] = overlap0; if (overlap0 & ImplicitRegister) i.reg_operands--; if (overlap0 & Imm1) i.imm_operands = 0; /* kludge for shift insns. */ i.types[1] = overlap1; if (overlap1 & ImplicitRegister) i.reg_operands--; i.types[2] = overlap2; if (overlap2 & ImplicitRegister) i.reg_operands--; /* Finalize opcode. First, we 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; } /* For movzx and movsx, need to check the register type. */ if (intel_syntax && (i.tm.base_opcode == 0xfb6 || i.tm.base_opcode == 0xfbe)) if (i.suffix && 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; } 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; } /* Set mode64 for an operand. */ if (i.suffix == QWORD_MNEM_SUFFIX && !(i.tm.opcode_modifier & NoRex64)) { i.rex.mode64 = 1; if (flag_code < CODE_64BIT) { as_bad (_("64bit operations available only in 64bit modes.")); return; } } /* Size floating point instruction. */ if (i.suffix == LONG_MNEM_SUFFIX) { if (i.tm.opcode_modifier & FloatMF) i.tm.base_opcode ^= 4; } } if (i.tm.opcode_modifier & ImmExt) { /* These AMD 3DNow! and Intel Katmai New Instructions have an opcode suffix which is coded in the same place as an 8-bit immediate field would be. Here we fake an 8-bit immediate operand from the opcode suffix stored in tm.extension_opcode. */ expressionS *exp; assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS); exp = &im_expressions[i.imm_operands++]; i.op[i.operands].imms = exp; i.types[i.operands++] = Imm8; exp->X_op = O_constant; exp->X_add_number = i.tm.extension_opcode; i.tm.extension_opcode = None; } /* For insns with operands there are more diddles to do to the opcode. */ if (i.operands) { /* Default segment register this instruction will use for memory accesses. 0 means unknown. This is only for optimizing out unnecessary segment overrides. */ const seg_entry *default_seg = 0; /* The imul $imm, %reg instruction is converted into imul $imm, %reg, %reg, and the clr %reg instruction is converted into xor %reg, %reg. */ if (i.tm.opcode_modifier & regKludge) { unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1; /* Pretend we saw the extra register operand. */ assert (i.op[first_reg_op + 1].regs == 0); i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; i.types[first_reg_op + 1] = i.types[first_reg_op]; i.reg_operands = 2; } if (i.tm.opcode_modifier & ShortForm) { /* The register or float register operand is in operand 0 or 1. */ unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; /* Register goes in low 3
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?