Add missing instructions to the IA-32 disasembler
Added newly added instructions to test-disasem-ia32.cc and implemented the missi ng ones in the disasembler. Added some asserts to 8-bit instructions which only work with eax, ebx, ecx and edx (al, bl, cl and dl). Removed the loope instruction. Review URL: http://codereview.chromium.org/548002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3577 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
c860533020
commit
658ca2f174
@ -575,6 +575,7 @@ void Assembler::leave() {
|
||||
|
||||
|
||||
void Assembler::mov_b(Register dst, const Operand& src) {
|
||||
ASSERT(dst.code() < 4);
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
EMIT(0x8A);
|
||||
@ -592,6 +593,7 @@ void Assembler::mov_b(const Operand& dst, int8_t imm8) {
|
||||
|
||||
|
||||
void Assembler::mov_b(const Operand& dst, Register src) {
|
||||
ASSERT(src.code() < 4);
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
EMIT(0x88);
|
||||
@ -1208,6 +1210,7 @@ void Assembler::sub(Register dst, const Operand& src) {
|
||||
|
||||
|
||||
void Assembler::subb(Register dst, const Operand& src) {
|
||||
ASSERT(dst.code() < 4);
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
EMIT(0x2A);
|
||||
@ -1600,21 +1603,8 @@ void Assembler::j(Condition cc, Handle<Code> code, Hint hint) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::loope(Label* L) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
// Only short backward jumps.
|
||||
ASSERT(L->is_bound());
|
||||
int offs = L->pos() - pc_offset();
|
||||
const int kLoopInstructionSize = 2;
|
||||
ASSERT(is_int8(offs - kLoopInstructionSize));
|
||||
EMIT(0xE1);
|
||||
EMIT((offs - kLoopInstructionSize) & 0xFF);
|
||||
}
|
||||
|
||||
// FPU instructions
|
||||
|
||||
|
||||
void Assembler::fld(int i) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
|
@ -676,9 +676,6 @@ class Assembler : public Malloced {
|
||||
void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
|
||||
void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
|
||||
|
||||
// Loop instruction using ecx as counter.
|
||||
void loope(Label* L);
|
||||
|
||||
// Floating-point operations
|
||||
void fld(int i);
|
||||
|
||||
|
@ -9637,48 +9637,51 @@ void SubStringStub::Generate(MacroAssembler* masm) {
|
||||
void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
Register counter,
|
||||
Register scratch1,
|
||||
Register scratch2) {
|
||||
ASSERT(counter.is(ecx));
|
||||
Register scratch2,
|
||||
Register scratch3) {
|
||||
Label compare_lengths, compare_lengths_1;
|
||||
|
||||
// Find minimum length. If either length is zero just compare lengths.
|
||||
__ mov(counter, FieldOperand(left, String::kLengthOffset));
|
||||
__ test(counter, Operand(counter));
|
||||
__ j(zero, &compare_lengths_1);
|
||||
__ mov(scratch1, FieldOperand(right, String::kLengthOffset));
|
||||
__ mov(scratch1, FieldOperand(left, String::kLengthOffset));
|
||||
__ test(scratch1, Operand(scratch1));
|
||||
__ j(zero, &compare_lengths_1);
|
||||
__ cmp(counter, Operand(scratch1));
|
||||
__ mov(scratch2, FieldOperand(right, String::kLengthOffset));
|
||||
__ test(scratch2, Operand(scratch2));
|
||||
__ j(zero, &compare_lengths_1);
|
||||
__ cmp(scratch1, Operand(scratch2));
|
||||
if (CpuFeatures::IsSupported(CMOV)) {
|
||||
CpuFeatures::Scope use_cmov(CMOV);
|
||||
__ cmov(greater, counter, Operand(scratch1));
|
||||
__ cmov(greater, scratch1, Operand(scratch2));
|
||||
} else {
|
||||
Label l;
|
||||
__ j(less, &l);
|
||||
__ mov(counter, scratch1);
|
||||
__ mov(scratch1, scratch2);
|
||||
__ bind(&l);
|
||||
}
|
||||
|
||||
Label result_greater, result_less;
|
||||
Label loop;
|
||||
// Compare next character.
|
||||
__ mov(scratch2, Immediate(-1)); // Index into strings.
|
||||
__ mov(scratch3, Immediate(-1)); // Index into strings.
|
||||
__ bind(&loop);
|
||||
// Compare characters.
|
||||
__ add(Operand(scratch2), Immediate(1));
|
||||
__ mov_b(scratch1, Operand(left,
|
||||
scratch2,
|
||||
Label character_compare_done;
|
||||
__ add(Operand(scratch3), Immediate(1));
|
||||
__ mov_b(scratch2, Operand(left,
|
||||
scratch3,
|
||||
times_1,
|
||||
SeqAsciiString::kHeaderSize - kHeapObjectTag));
|
||||
__ subb(scratch1, Operand(right,
|
||||
scratch2,
|
||||
__ subb(scratch2, Operand(right,
|
||||
scratch3,
|
||||
times_1,
|
||||
SeqAsciiString::kHeaderSize - kHeapObjectTag));
|
||||
__ loope(&loop);
|
||||
__ j(not_equal, &character_compare_done);
|
||||
__ sub(Operand(scratch1), Immediate(1));
|
||||
__ j(not_zero, &loop);
|
||||
// If min length characters match compare lengths otherwise last character
|
||||
// compare is the result.
|
||||
__ bind(&character_compare_done);
|
||||
__ j(equal, &compare_lengths);
|
||||
__ j(less, &result_less);
|
||||
__ jmp(&result_greater);
|
||||
@ -9686,9 +9689,9 @@ void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
|
||||
// Compare lengths.
|
||||
Label result_not_equal;
|
||||
__ bind(&compare_lengths);
|
||||
__ mov(counter, FieldOperand(left, String::kLengthOffset));
|
||||
__ mov(scratch1, FieldOperand(left, String::kLengthOffset));
|
||||
__ bind(&compare_lengths_1);
|
||||
__ sub(counter, FieldOperand(right, String::kLengthOffset));
|
||||
__ sub(scratch1, FieldOperand(right, String::kLengthOffset));
|
||||
__ j(not_zero, &result_not_equal);
|
||||
|
||||
// Result is EQUAL.
|
||||
|
@ -813,16 +813,13 @@ class StringCompareStub: public StringStubBase {
|
||||
}
|
||||
|
||||
// Compare two flat ascii strings and returns result in eax after popping two
|
||||
// arguments from the stack. Due to the instructions used there are certain
|
||||
// constraints on the registers that can be passed.
|
||||
// counter must be ecx
|
||||
// scratch1 most be one of eax, ebx or edx
|
||||
// arguments from the stack.
|
||||
static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
|
||||
Register left,
|
||||
Register right,
|
||||
Register counter,
|
||||
Register scratch1,
|
||||
Register scratch2);
|
||||
Register scratch2,
|
||||
Register scratch3);
|
||||
|
||||
private:
|
||||
Major MajorKey() { return StringCompare; }
|
||||
|
@ -117,11 +117,6 @@ static const char* jump_conditional_mnem[] = {
|
||||
};
|
||||
|
||||
|
||||
static const char* loop_mnem[] = {
|
||||
"loopne", "loope", "loop"
|
||||
};
|
||||
|
||||
|
||||
static const char* set_conditional_mnem[] = {
|
||||
/*0*/ "seto", "setno", "setc", "setnc",
|
||||
/*4*/ "setz", "setnz", "setna", "seta",
|
||||
@ -143,7 +138,6 @@ enum InstructionType {
|
||||
ZERO_OPERANDS_INSTR,
|
||||
TWO_OPERANDS_INSTR,
|
||||
JUMP_CONDITIONAL_SHORT_INSTR,
|
||||
LOOP_INSTR,
|
||||
REGISTER_INSTR,
|
||||
MOVE_REG_INSTR,
|
||||
CALL_JUMP_INSTR,
|
||||
@ -173,7 +167,6 @@ class InstructionTable {
|
||||
byte end,
|
||||
const char* mnem);
|
||||
void AddJumpConditionalShort();
|
||||
void AddLoop();
|
||||
};
|
||||
|
||||
|
||||
@ -198,7 +191,6 @@ void InstructionTable::Init() {
|
||||
CopyTable(call_jump_instr, CALL_JUMP_INSTR);
|
||||
CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
|
||||
AddJumpConditionalShort();
|
||||
AddLoop();
|
||||
SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
|
||||
SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
|
||||
SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
|
||||
@ -242,16 +234,6 @@ void InstructionTable::AddJumpConditionalShort() {
|
||||
}
|
||||
|
||||
|
||||
void InstructionTable::AddLoop() {
|
||||
for (byte b = 0xE0; b <= 0xE2; b++) {
|
||||
InstructionDesc* id = &instructions_[b];
|
||||
ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
|
||||
id->mnem = loop_mnem[b & 0x03];
|
||||
id->type = LOOP_INSTR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static InstructionTable instruction_table;
|
||||
|
||||
|
||||
@ -348,7 +330,6 @@ class DisassemblerIA32 {
|
||||
int JumpShort(byte* data);
|
||||
int JumpConditional(byte* data, const char* comment);
|
||||
int JumpConditionalShort(byte* data, const char* comment);
|
||||
int Loop(byte* data);
|
||||
int SetCC(byte* data);
|
||||
int CMov(byte* data);
|
||||
int FPUInstruction(byte* data);
|
||||
@ -636,17 +617,6 @@ int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
|
||||
}
|
||||
|
||||
|
||||
// Returns number of bytes used, including *data.
|
||||
int DisassemblerIA32::Loop(byte* data) {
|
||||
byte cond = *data & 0x03;
|
||||
byte b = *(data+1);
|
||||
byte* dest = data + static_cast<int8_t>(b) + 2;
|
||||
const char* mnem = loop_mnem[cond];
|
||||
AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
// Returns number of bytes used, including *data.
|
||||
int DisassemblerIA32::SetCC(byte* data) {
|
||||
ASSERT_EQ(0x0F, *data);
|
||||
@ -885,10 +855,6 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
data += JumpConditionalShort(data, branch_hint);
|
||||
break;
|
||||
|
||||
case LOOP_INSTR:
|
||||
data += Loop(data);
|
||||
break;
|
||||
|
||||
case REGISTER_INSTR:
|
||||
AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
|
||||
data++;
|
||||
@ -1042,7 +1008,16 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
|
||||
case 0x80:
|
||||
{ data++;
|
||||
AppendToBuffer("%s ", "cmpb");
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
const char* mnem = NULL;
|
||||
printf("%d\n", regop);
|
||||
switch (regop) {
|
||||
case 5: mnem = "subb"; break;
|
||||
case 7: mnem = "cmpb"; break;
|
||||
default: UnimplementedInstruction();
|
||||
}
|
||||
AppendToBuffer("%s ", mnem);
|
||||
data += PrintRightOperand(data);
|
||||
int32_t imm = *data;
|
||||
AppendToBuffer(",0x%x", imm);
|
||||
@ -1092,6 +1067,19 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
NameOfXMMRegister(regop),
|
||||
NameOfXMMRegister(rm));
|
||||
data++;
|
||||
} else if (*data == 0x6F) {
|
||||
data++;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
|
||||
data += PrintRightOperand(data);
|
||||
} else if (*data == 0x7F) {
|
||||
AppendToBuffer("movdqa ");
|
||||
data++;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
data += PrintRightOperand(data);
|
||||
AppendToBuffer(",%s", NameOfXMMRegister(regop));
|
||||
} else {
|
||||
UnimplementedInstruction();
|
||||
}
|
||||
@ -1128,6 +1116,11 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
data += 2;
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
AppendToBuffer("subb eax,0x%x", *reinterpret_cast<uint8_t*>(data+1));
|
||||
data += 2;
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
|
||||
data += 5;
|
||||
@ -1198,9 +1191,29 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
break;
|
||||
|
||||
case 0xF3:
|
||||
if (*(data+1) == 0x0F && *(data+2) == 0x2C) {
|
||||
data += 3;
|
||||
data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
|
||||
if (*(data+1) == 0x0F) {
|
||||
if (*(data+2) == 0x2C) {
|
||||
data += 3;
|
||||
data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
|
||||
} else if (*(data+2) == 0x6F) {
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
|
||||
data += PrintRightOperand(data);
|
||||
} else if (*(data+2) == 0x7F) {
|
||||
AppendToBuffer("movdqu ");
|
||||
data += 3;
|
||||
int mod, regop, rm;
|
||||
get_modrm(*data, &mod, ®op, &rm);
|
||||
data += PrintRightOperand(data);
|
||||
AppendToBuffer(",%s", NameOfXMMRegister(regop));
|
||||
} else {
|
||||
UnimplementedInstruction();
|
||||
}
|
||||
} else if (*(data+1) == 0xA5) {
|
||||
data += 2;
|
||||
AppendToBuffer("rep_movs");
|
||||
} else {
|
||||
UnimplementedInstruction();
|
||||
}
|
||||
@ -1220,6 +1233,9 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
|
||||
}
|
||||
|
||||
int instr_len = data - instr;
|
||||
if (instr_len == 0) {
|
||||
printf("%02x", *data);
|
||||
}
|
||||
ASSERT(instr_len > 0); // Ensure progress.
|
||||
|
||||
int outp = 0;
|
||||
|
@ -57,7 +57,7 @@ static void DummyStaticFunction(Object* result) {
|
||||
TEST(DisasmIa320) {
|
||||
InitializeVM();
|
||||
v8::HandleScope scope;
|
||||
v8::internal::byte buffer[1024];
|
||||
v8::internal::byte buffer[2048];
|
||||
Assembler assm(buffer, sizeof buffer);
|
||||
DummyStaticFunction(NULL); // just bloody use it (DELETE; debugging)
|
||||
|
||||
@ -223,13 +223,16 @@ TEST(DisasmIa320) {
|
||||
|
||||
__ sub(Operand(ebx), Immediate(12));
|
||||
__ sub(Operand(edx, ecx, times_4, 10000), Immediate(12));
|
||||
__ subb(Operand(edx, ecx, times_4, 10000), 100);
|
||||
__ subb(Operand(eax), 100);
|
||||
__ subb(eax, Operand(edx, ecx, times_4, 10000));
|
||||
|
||||
__ xor_(ebx, 12345);
|
||||
|
||||
__ imul(edx, ecx, 12);
|
||||
__ imul(edx, ecx, 1000);
|
||||
|
||||
|
||||
__ rep_movs();
|
||||
|
||||
__ sub(edx, Operand(ebx, ecx, times_4, 10000));
|
||||
__ sub(edx, Operand(ebx));
|
||||
@ -365,6 +368,12 @@ TEST(DisasmIa320) {
|
||||
__ movdbl(xmm1, Operand(ebx, ecx, times_4, 10000));
|
||||
__ movdbl(Operand(ebx, ecx, times_4, 10000), xmm1);
|
||||
__ comisd(xmm0, xmm1);
|
||||
|
||||
// 128 bit move instructions.
|
||||
__ movdqa(xmm0, Operand(ebx, ecx, times_4, 10000));
|
||||
__ movdqa(Operand(ebx, ecx, times_4, 10000), xmm0);
|
||||
__ movdqu(xmm0, Operand(ebx, ecx, times_4, 10000));
|
||||
__ movdqu(Operand(ebx, ecx, times_4, 10000), xmm0);
|
||||
}
|
||||
|
||||
// cmov.
|
||||
|
Loading…
Reference in New Issue
Block a user