int DisassemblerX64::twoByteOpcodeInstruction()

in runtime/disassembler-x64.cpp [1243:1583]


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;
      getModRM(*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) {
        getModRM(*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) {
        getModRM(*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) {
        getModRM(*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 {
      getModRM(*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,", rexW() ? '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 ", rexW() ? '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 = kXmmInstructions[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;
      getModRM(*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;
      getModRM(*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;
      getModRM(*current, &mod, &regop, &rm);
      print("cvttsd2si%s %s,", operandSizeCode(), nameOfCPURegister(regop));
      current += printRightXMMOperand(current);
    } else if (opcode == 0x2D) {
      // CVTSD2SI: Convert scalar double-precision FP to integer.
      int mod, regop, rm;
      getModRM(*current, &mod, &regop, &rm);
      print("cvtsd2si%s %s,", operandSizeCode(), 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;
      getModRM(*current, &mod, &regop, &rm);
      const char* mnemonic =
          opcode == 0x5A ? "cvtsd2ss" : kXmmInstructions[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;
      getModRM(*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;
      getModRM(*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;
      getModRM(*current, &mod, &regop, &rm);
      print("cvt%sss2si%s %s,", truncating ? "t" : "", operandSizeCode(),
            nameOfCPURegister(regop));
      current += printRightXMMOperand(current);
    } else if (0x51 <= opcode && opcode <= 0x5F) {
      int mod, regop, rm;
      getModRM(*current, &mod, &regop, &rm);
      const char* mnemonic =
          opcode == 0x5A ? "cvtss2sd" : kXmmInstructions[opcode & 0xF].ss_name;
      print("%s %s,", mnemonic, nameOfXMMRegister(regop));
      current += printRightXMMOperand(current);
    } else if (opcode == 0x7E) {
      int mod, regop, rm;
      getModRM(*current, &mod, &regop, &rm);
      print("movq %s, ", nameOfXMMRegister(regop));
      current += printRightXMMOperand(current);
    } else if (opcode == 0xE6) {
      int mod, regop, rm;
      getModRM(*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;
    getModRM(*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;
    getModRM(*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;
    getModRM(*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;
    getModRM(*current, &mod, &regop, &rm);
    print("movups ");
    current += printRightXMMOperand(current);
    print(",%s", nameOfXMMRegister(regop));
  } else if (opcode == 0x50) {
    int mod, regop, rm;
    getModRM(*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* mnemonics[] = {"movups", nullptr,    "movhlps",
                                      nullptr,  "unpcklps", "unpckhps",
                                      "movlhps"};
    const char* mnemonic = mnemonics[opcode - 0x10];
    if (mnemonic == nullptr) {
      unimplementedInstruction();
      mnemonic = "???";
    }
    int mod, regop, rm;
    getModRM(*current, &mod, &regop, &rm);
    print("%s %s,", mnemonic, nameOfXMMRegister(regop));
    current += printRightXMMOperand(current);
  } else if (0x51 <= opcode && opcode <= 0x5F) {
    int mod, regop, rm;
    getModRM(*current, &mod, &regop, &rm);
    const char* mnemonic =
        opcode == 0x5A ? "cvtps2pd" : kXmmInstructions[opcode & 0xF].ps_name;
    print("%s %s,", mnemonic, nameOfXMMRegister(regop));
    current += printRightXMMOperand(current);
  } else if (opcode == 0xC2 || opcode == 0xC6) {
    int mod, regop, rm;
    getModRM(*current, &mod, &regop, &rm);
    if (opcode == 0xC2) {
      print("cmpps %s,", nameOfXMMRegister(regop));
      current += printRightXMMOperand(current);
      print(" [%s]", kXmmConditionalCodeSuffix[*current]);
    } else {
      DCHECK(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, operandSizeCode());
    int mod, regop, rm;
    getModRM(*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 if (opcode == 0x0B) {
    print("ud2");
  } else {
    unimplementedInstruction();
  }
  return static_cast<int>(current - data);
}