int DisassemblerX64::TwoByteOpcodeInstruction()

in runtime/vm/compiler/assembler/disassembler_x86.cc [1272:1609]


int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
  uint8_t opcode = *(data + 1);
  uint8_t* current = data + 2;
  // At return, "current" points to the start of the next instruction.
  const char* mnemonic = TwoByteMnemonic(opcode);
  if (operand_size_ == 0x66) {
    // 0x66 0x0F prefix.
    int mod, regop, rm;
    if (opcode == 0xC6) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("shufpd %s, ", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
      Print(" [%x]", *current);
      current++;
    } else if (opcode == 0x3A) {
      uint8_t third_byte = *current;
      current = data + 3;
      if (third_byte == 0x16) {
        get_modrm(*current, &mod, &regop, &rm);
        Print("pextrd ");  // reg/m32, xmm, imm8
        current += PrintRightOperand(current);
        Print(",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
        current += 1;
      } else if (third_byte == 0x17) {
        get_modrm(*current, &mod, &regop, &rm);
        Print("extractps ");  // reg/m32, xmm, imm8
        current += PrintRightOperand(current);
        Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
        current += 1;
      } else if (third_byte == 0x0b) {
        get_modrm(*current, &mod, &regop, &rm);
        // roundsd xmm, xmm/m64, imm8
        Print("roundsd %s, ", NameOfCPURegister(regop));
        current += PrintRightOperand(current);
        Print(", %d", (*current) & 3);
        current += 1;
      } else {
        UnimplementedInstruction();
      }
    } else {
      get_modrm(*current, &mod, &regop, &rm);
      if (opcode == 0x1f) {
        current++;
        if (rm == 4) {  // SIB byte present.
          current++;
        }
        if (mod == 1) {  // Byte displacement.
          current += 1;
        } else if (mod == 2) {  // 32-bit displacement.
          current += 4;
        }  // else no immediate displacement.
        Print("nop");
      } else if (opcode == 0x28) {
        Print("movapd %s, ", NameOfXMMRegister(regop));
        current += PrintRightXMMOperand(current);
      } else if (opcode == 0x29) {
        Print("movapd ");
        current += PrintRightXMMOperand(current);
        Print(", %s", NameOfXMMRegister(regop));
      } else if (opcode == 0x38) {
        current += Print660F38Instruction(current);
      } else if (opcode == 0x6E) {
        Print("mov%c %s,", rex_w() ? 'q' : 'd', NameOfXMMRegister(regop));
        current += PrintRightOperand(current);
      } else if (opcode == 0x6F) {
        Print("movdqa %s,", NameOfXMMRegister(regop));
        current += PrintRightXMMOperand(current);
      } else if (opcode == 0x7E) {
        Print("mov%c ", rex_w() ? 'q' : 'd');
        current += PrintRightOperand(current);
        Print(",%s", NameOfXMMRegister(regop));
      } else if (opcode == 0x7F) {
        Print("movdqa ");
        current += PrintRightXMMOperand(current);
        Print(",%s", NameOfXMMRegister(regop));
      } else if (opcode == 0xD6) {
        Print("movq ");
        current += PrintRightXMMOperand(current);
        Print(",%s", NameOfXMMRegister(regop));
      } else if (opcode == 0x50) {
        Print("movmskpd %s,", NameOfCPURegister(regop));
        current += PrintRightXMMOperand(current);
      } else if (opcode == 0xD7) {
        Print("pmovmskb %s,", NameOfCPURegister(regop));
        current += PrintRightXMMOperand(current);
      } else {
        const char* mnemonic = "?";
        if (opcode == 0x5A) {
          mnemonic = "cvtpd2ps";
        } else if (0x51 <= opcode && opcode <= 0x5F) {
          mnemonic = xmm_instructions[opcode & 0xF].pd_name;
        } else if (opcode == 0x14) {
          mnemonic = "unpcklpd";
        } else if (opcode == 0x15) {
          mnemonic = "unpckhpd";
        } else if (opcode == 0x2E) {
          mnemonic = "ucomisd";
        } else if (opcode == 0x2F) {
          mnemonic = "comisd";
        } else if (opcode == 0xFE) {
          mnemonic = "paddd";
        } else if (opcode == 0xFA) {
          mnemonic = "psubd";
        } else if (opcode == 0xEF) {
          mnemonic = "pxor";
        } else {
          UnimplementedInstruction();
        }
        Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
        current += PrintRightXMMOperand(current);
      }
    }
  } else if (group_1_prefix_ == 0xF2) {
    // Beginning of instructions with prefix 0xF2.

    if (opcode == 0x11 || opcode == 0x10) {
      // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
      Print("movsd ");
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      if (opcode == 0x11) {
        current += PrintRightXMMOperand(current);
        Print(",%s", NameOfXMMRegister(regop));
      } else {
        Print("%s,", NameOfXMMRegister(regop));
        current += PrintRightXMMOperand(current);
      }
    } else if (opcode == 0x2A) {
      // CVTSI2SD: integer to XMM double conversion.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("%sd %s,", mnemonic, NameOfXMMRegister(regop));
      current += PrintRightOperand(current);
    } else if (opcode == 0x2C) {
      // CVTTSD2SI:
      // Convert with truncation scalar double-precision FP to integer.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("cvttsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0x2D) {
      // CVTSD2SI: Convert scalar double-precision FP to integer.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("cvtsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (0x51 <= opcode && opcode <= 0x5F) {
      // XMM arithmetic. Get the F2 0F prefix version of the mnemonic.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      const char* mnemonic =
          opcode == 0x5A ? "cvtsd2ss" : xmm_instructions[opcode & 0xF].sd_name;
      Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
    } else {
      UnimplementedInstruction();
    }
  } else if (group_1_prefix_ == 0xF3) {
    // Instructions with prefix 0xF3.
    if (opcode == 0x11 || opcode == 0x10) {
      // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
      Print("movss ");
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      if (opcode == 0x11) {
        current += PrintRightOperand(current);
        Print(",%s", NameOfXMMRegister(regop));
      } else {
        Print("%s,", NameOfXMMRegister(regop));
        current += PrintRightOperand(current);
      }
    } else if (opcode == 0x2A) {
      // CVTSI2SS: integer to XMM single conversion.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("%ss %s,", mnemonic, NameOfXMMRegister(regop));
      current += PrintRightOperand(current);
    } else if (opcode == 0x2C || opcode == 0x2D) {
      bool truncating = (opcode & 1) == 0;
      // CVTTSS2SI/CVTSS2SI:
      // Convert (with truncation) scalar single-precision FP to dword integer.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("cvt%sss2si%s %s,", truncating ? "t" : "", operand_size_code(),
            NameOfCPURegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (0x51 <= opcode && opcode <= 0x5F) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      const char* mnemonic =
          opcode == 0x5A ? "cvtss2sd" : xmm_instructions[opcode & 0xF].ss_name;
      Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0x7E) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("movq %s, ", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0xE6) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      Print("cvtdq2pd %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0xB8) {
      // POPCNT.
      current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
    } else if (opcode == 0xBD) {
      // LZCNT (rep BSR encoding).
      current += PrintOperands("lzcnt", REG_OPER_OP_ORDER, current);
    } else {
      UnimplementedInstruction();
    }
  } else if (opcode == 0x1F) {
    // NOP
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    current++;
    if (rm == 4) {  // SIB byte present.
      current++;
    }
    if (mod == 1) {  // Byte displacement.
      current += 1;
    } else if (mod == 2) {  // 32-bit displacement.
      current += 4;
    }  // else no immediate displacement.
    Print("nop");

  } else if (opcode == 0x28 || opcode == 0x2f) {
    // ...s xmm, xmm/m128
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    const char* mnemonic = opcode == 0x28 ? "movaps" : "comiss";
    Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
    current += PrintRightXMMOperand(current);
  } else if (opcode == 0x29) {
    // movaps xmm/m128, xmm
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    Print("movaps ");
    current += PrintRightXMMOperand(current);
    Print(",%s", NameOfXMMRegister(regop));
  } else if (opcode == 0x11) {
    // movups xmm/m128, xmm
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    Print("movups ");
    current += PrintRightXMMOperand(current);
    Print(",%s", NameOfXMMRegister(regop));
  } else if (opcode == 0x50) {
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    Print("movmskps %s,", NameOfCPURegister(regop));
    current += PrintRightXMMOperand(current);
  } else if (opcode == 0xA2 || opcode == 0x31) {
    // RDTSC or CPUID
    Print("%s", mnemonic);
  } else if ((opcode & 0xF0) == 0x40) {
    // CMOVcc: conditional move.
    int condition = opcode & 0x0F;
    const InstructionDesc& idesc = cmov_instructions[condition];
    byte_size_operand_ = idesc.byte_size_operation;
    current += PrintOperands(idesc.mnem, idesc.op_order_, current);
  } else if (0x10 <= opcode && opcode <= 0x16) {
    // ...ps xmm, xmm/m128
    static const char* const mnemonics[] = {
        "movups", NULL, "movhlps", NULL, "unpcklps", "unpckhps", "movlhps"};
    const char* mnemonic = mnemonics[opcode - 0x10];
    if (mnemonic == NULL) {
      UnimplementedInstruction();
      mnemonic = "???";
    }
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
    current += PrintRightXMMOperand(current);
  } else if (0x51 <= opcode && opcode <= 0x5F) {
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    const char* mnemonic =
        opcode == 0x5A ? "cvtps2pd" : xmm_instructions[opcode & 0xF].ps_name;
    Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
    current += PrintRightXMMOperand(current);
  } else if (opcode == 0xC2 || opcode == 0xC6) {
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    if (opcode == 0xC2) {
      Print("cmpps %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
      Print(" [%s]", xmm_conditional_code_suffix[*current]);
    } else {
      ASSERT(opcode == 0xC6);
      Print("shufps %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
      Print(" [%x]", *current);
    }
    current++;
  } else if ((opcode & 0xF0) == 0x80) {
    // Jcc: Conditional jump (branch).
    current = data + JumpConditional(data);

  } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
             opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 ||
             opcode == 0xB1 || opcode == 0xBC || opcode == 0xBD) {
    // Size-extending moves, IMUL, cmpxchg, BSF, BSR.
    current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
  } else if ((opcode & 0xF0) == 0x90) {
    // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
    current = data + SetCC(data);
  } else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) ||
             (opcode == 0xAB) || (opcode == 0xA3)) {
    // SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test).
    Print("%s%s ", mnemonic, operand_size_code());
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    current += PrintRightOperand(current);
    Print(",%s", NameOfCPURegister(regop));
    if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
      // Done.
    } else if ((opcode == 0xA5) || (opcode == 0xAD)) {
      Print(",cl");
    } else {
      Print(",");
      current += PrintImmediate(current, BYTE_SIZE);
    }
  } else if (opcode == 0xBA && (*current & 0x60) == 0x60) {
    // bt? immediate instruction
    int r = (*current >> 3) & 7;
    static const char* const names[4] = {"bt", "bts", "btr", "btc"};
    Print("%s ", names[r - 4]);
    current += PrintRightOperand(current);
    uint8_t bit = *current++;
    Print(",%d", bit);
  } else {
    UnimplementedInstruction();
  }
  return static_cast<int>(current - data);
}