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) { |