| Index: src/ia32/disasm-ia32.cc
|
| diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
|
| index 252376162f65c27389af66e57b1dc7d573b5a113..57d1cc929c9b778728a2dbdee77e2507007a3cf4 100644
|
| --- a/src/ia32/disasm-ia32.cc
|
| +++ b/src/ia32/disasm-ia32.cc
|
| @@ -246,6 +246,9 @@ class DisassemblerIA32 {
|
| DisassemblerIA32(const NameConverter& converter,
|
| bool abort_on_unimplemented = true)
|
| : converter_(converter),
|
| + vex_byte0_(0),
|
| + vex_byte1_(0),
|
| + vex_byte2_(0),
|
| instruction_table_(InstructionTable::get_instance()),
|
| tmp_buffer_pos_(0),
|
| abort_on_unimplemented_(abort_on_unimplemented) {
|
| @@ -260,6 +263,9 @@ class DisassemblerIA32 {
|
|
|
| private:
|
| const NameConverter& converter_;
|
| + byte vex_byte0_; // 0xc4 or 0xc5
|
| + byte vex_byte1_;
|
| + byte vex_byte2_; // only for 3 bytes vex prefix
|
| InstructionTable* instruction_table_;
|
| v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
|
| unsigned int tmp_buffer_pos_;
|
| @@ -287,6 +293,57 @@ class DisassemblerIA32 {
|
| kSAR = 7
|
| };
|
|
|
| + bool vex_128() {
|
| + DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
|
| + byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 4) != 1;
|
| + }
|
| +
|
| + bool vex_66() {
|
| + DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
|
| + byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 3) == 1;
|
| + }
|
| +
|
| + bool vex_f3() {
|
| + DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
|
| + byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 3) == 2;
|
| + }
|
| +
|
| + bool vex_f2() {
|
| + DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
|
| + byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
|
| + return (checked & 3) == 3;
|
| + }
|
| +
|
| + bool vex_w() {
|
| + if (vex_byte0_ == 0xc5) return false;
|
| + return (vex_byte2_ & 0x80) == 1;
|
| + }
|
| +
|
| + bool vex_0f() {
|
| + if (vex_byte0_ == 0xc5) return true;
|
| + return (vex_byte1_ & 3) == 1;
|
| + }
|
| +
|
| + bool vex_0f38() {
|
| + if (vex_byte0_ == 0xc5) return false;
|
| + return (vex_byte1_ & 3) == 2;
|
| + }
|
| +
|
| + bool vex_0f3a() {
|
| + if (vex_byte0_ == 0xc5) return false;
|
| + return (vex_byte1_ & 3) == 3;
|
| + }
|
| +
|
| + int vex_vreg() {
|
| + DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
|
| + byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
|
| + return ~(checked >> 3) & 0xf;
|
| + }
|
| +
|
| + char float_size_code() { return "sd"[vex_w()]; }
|
|
|
| const char* NameOfCPURegister(int reg) const {
|
| return converter_.NameOfCPURegister(reg);
|
| @@ -340,6 +397,7 @@ class DisassemblerIA32 {
|
| int FPUInstruction(byte* data);
|
| int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
|
| int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
|
| + int AVXInstruction(byte* data);
|
| void AppendToBuffer(const char* format, ...);
|
|
|
|
|
| @@ -679,6 +737,44 @@ int DisassemblerIA32::CMov(byte* data) {
|
| }
|
|
|
|
|
| +int DisassemblerIA32::AVXInstruction(byte* data) {
|
| + byte opcode = *data;
|
| + byte* current = data + 1;
|
| + if (vex_f2() && vex_0f()) {
|
| + int mod, regop, rm, vvvv = vex_vreg();
|
| + get_modrm(*current, &mod, ®op, &rm);
|
| + switch (opcode) {
|
| + case 0x58:
|
| + AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
|
| + NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0x59:
|
| + AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
|
| + NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0x5c:
|
| + AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
|
| + NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + case 0x5e:
|
| + AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
|
| + NameOfXMMRegister(vvvv));
|
| + current += PrintRightXMMOperand(current);
|
| + break;
|
| + default:
|
| + UnimplementedInstruction();
|
| + }
|
| + } else {
|
| + UnimplementedInstruction();
|
| + }
|
| +
|
| + return static_cast<int>(current - data);
|
| +}
|
| +
|
| +
|
| // Returns number of bytes used, including *data.
|
| int DisassemblerIA32::FPUInstruction(byte* data) {
|
| byte escape_opcode = *data;
|
| @@ -903,65 +999,81 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
| } else if (*data == 0x2E /*cs*/) {
|
| branch_hint = "predicted not taken";
|
| data++;
|
| + } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
|
| + vex_byte0_ = *data;
|
| + vex_byte1_ = *(data + 1);
|
| + vex_byte2_ = *(data + 2);
|
| + data += 3;
|
| + } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
|
| + vex_byte0_ = *data;
|
| + vex_byte1_ = *(data + 1);
|
| + data += 2;
|
| }
|
| +
|
| bool processed = true; // Will be set to false if the current instruction
|
| // is not in 'instructions' table.
|
| - const InstructionDesc& idesc = instruction_table_->Get(*data);
|
| - switch (idesc.type) {
|
| - case ZERO_OPERANDS_INSTR:
|
| - AppendToBuffer(idesc.mnem);
|
| - data++;
|
| - break;
|
| + // Decode AVX instructions.
|
| + if (vex_byte0_ != 0) {
|
| + data += AVXInstruction(data);
|
| + } else {
|
| + const InstructionDesc& idesc = instruction_table_->Get(*data);
|
| + switch (idesc.type) {
|
| + case ZERO_OPERANDS_INSTR:
|
| + AppendToBuffer(idesc.mnem);
|
| + data++;
|
| + break;
|
|
|
| - case TWO_OPERANDS_INSTR:
|
| - data++;
|
| - data += PrintOperands(idesc.mnem, idesc.op_order_, data);
|
| - break;
|
| + case TWO_OPERANDS_INSTR:
|
| + data++;
|
| + data += PrintOperands(idesc.mnem, idesc.op_order_, data);
|
| + break;
|
|
|
| - case JUMP_CONDITIONAL_SHORT_INSTR:
|
| - data += JumpConditionalShort(data, branch_hint);
|
| - break;
|
| + case JUMP_CONDITIONAL_SHORT_INSTR:
|
| + data += JumpConditionalShort(data, branch_hint);
|
| + break;
|
|
|
| - case REGISTER_INSTR:
|
| - AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
|
| - data++;
|
| - break;
|
| + case REGISTER_INSTR:
|
| + AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
|
| + data++;
|
| + break;
|
|
|
| - case MOVE_REG_INSTR: {
|
| - byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
|
| - AppendToBuffer("mov %s,%s",
|
| - NameOfCPURegister(*data & 0x07),
|
| - NameOfAddress(addr));
|
| - data += 5;
|
| - break;
|
| - }
|
| + case MOVE_REG_INSTR: {
|
| + byte* addr =
|
| + reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
|
| + AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
|
| + NameOfAddress(addr));
|
| + data += 5;
|
| + break;
|
| + }
|
|
|
| - case CALL_JUMP_INSTR: {
|
| - byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
|
| - AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
|
| - data += 5;
|
| - break;
|
| - }
|
| + case CALL_JUMP_INSTR: {
|
| + byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
|
| + AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
|
| + data += 5;
|
| + break;
|
| + }
|
|
|
| - case SHORT_IMMEDIATE_INSTR: {
|
| - byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
|
| - AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
|
| - data += 5;
|
| - break;
|
| - }
|
| + case SHORT_IMMEDIATE_INSTR: {
|
| + byte* addr =
|
| + reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
|
| + AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
|
| + data += 5;
|
| + break;
|
| + }
|
|
|
| - case BYTE_IMMEDIATE_INSTR: {
|
| - AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
|
| - data += 2;
|
| - break;
|
| - }
|
| + case BYTE_IMMEDIATE_INSTR: {
|
| + AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
|
| + data += 2;
|
| + break;
|
| + }
|
|
|
| - case NO_INSTR:
|
| - processed = false;
|
| - break;
|
| + case NO_INSTR:
|
| + processed = false;
|
| + break;
|
|
|
| - default:
|
| - UNIMPLEMENTED(); // This type is not implemented.
|
| + default:
|
| + UNIMPLEMENTED(); // This type is not implemented.
|
| + }
|
| }
|
| //----------------------------
|
| if (!processed) {
|
|
|