Ported ia32 optimization of revision 3487 to x64.
Review URL: http://codereview.chromium.org/597005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3821 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
503bbeb8c4
commit
96127b68e5
@ -2508,6 +2508,38 @@ void Assembler::divsd(XMMRegister dst, XMMRegister src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::xorpd(XMMRegister dst, XMMRegister src) {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
last_pc_ = pc_;
|
||||||
|
emit(0x66);
|
||||||
|
emit_optional_rex_32(dst, src);
|
||||||
|
emit(0x0f);
|
||||||
|
emit(0x57);
|
||||||
|
emit_sse_operand(dst, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::comisd(XMMRegister dst, XMMRegister src) {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
last_pc_ = pc_;
|
||||||
|
emit(0x66);
|
||||||
|
emit_optional_rex_32(dst, src);
|
||||||
|
emit(0x0f);
|
||||||
|
emit(0x2f);
|
||||||
|
emit_sse_operand(dst, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
|
||||||
|
EnsureSpace ensure_space(this);
|
||||||
|
last_pc_ = pc_;
|
||||||
|
emit(0x66);
|
||||||
|
emit_optional_rex_32(dst, src);
|
||||||
|
emit(0x0f);
|
||||||
|
emit(0x2e);
|
||||||
|
emit_sse_operand(dst, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
|
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) {
|
||||||
Register ireg = { reg.code() };
|
Register ireg = { reg.code() };
|
||||||
|
@ -1122,6 +1122,10 @@ class Assembler : public Malloced {
|
|||||||
void mulsd(XMMRegister dst, XMMRegister src);
|
void mulsd(XMMRegister dst, XMMRegister src);
|
||||||
void divsd(XMMRegister dst, XMMRegister src);
|
void divsd(XMMRegister dst, XMMRegister src);
|
||||||
|
|
||||||
|
void xorpd(XMMRegister dst, XMMRegister src);
|
||||||
|
|
||||||
|
void comisd(XMMRegister dst, XMMRegister src);
|
||||||
|
void ucomisd(XMMRegister dst, XMMRegister src);
|
||||||
|
|
||||||
void emit_sse_operand(XMMRegister dst, XMMRegister src);
|
void emit_sse_operand(XMMRegister dst, XMMRegister src);
|
||||||
void emit_sse_operand(XMMRegister reg, const Operand& adr);
|
void emit_sse_operand(XMMRegister reg, const Operand& adr);
|
||||||
@ -1168,14 +1172,6 @@ class Assembler : public Malloced {
|
|||||||
static const int kMaximalBufferSize = 512*MB;
|
static const int kMaximalBufferSize = 512*MB;
|
||||||
static const int kMinimalBufferSize = 4*KB;
|
static const int kMinimalBufferSize = 4*KB;
|
||||||
|
|
||||||
protected:
|
|
||||||
// void movsd(XMMRegister dst, const Operand& src);
|
|
||||||
// void movsd(const Operand& dst, XMMRegister src);
|
|
||||||
|
|
||||||
// void emit_sse_operand(XMMRegister reg, const Operand& adr);
|
|
||||||
// void emit_sse_operand(XMMRegister dst, XMMRegister src);
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
byte* addr_at(int pos) { return buffer_ + pos; }
|
byte* addr_at(int pos) { return buffer_ + pos; }
|
||||||
byte byte_at(int pos) { return buffer_[pos]; }
|
byte byte_at(int pos) { return buffer_[pos]; }
|
||||||
|
@ -1221,7 +1221,7 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
|
|||||||
// Compare and branch to the body if true or the next test if
|
// Compare and branch to the body if true or the next test if
|
||||||
// false. Prefer the next test as a fall through.
|
// false. Prefer the next test as a fall through.
|
||||||
ControlDestination dest(clause->body_target(), &next_test, false);
|
ControlDestination dest(clause->body_target(), &next_test, false);
|
||||||
Comparison(equal, true, &dest);
|
Comparison(node, equal, true, &dest);
|
||||||
|
|
||||||
// If the comparison fell through to the true target, jump to the
|
// If the comparison fell through to the true target, jump to the
|
||||||
// actual body.
|
// actual body.
|
||||||
@ -3585,7 +3585,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
|
|||||||
}
|
}
|
||||||
Load(left);
|
Load(left);
|
||||||
Load(right);
|
Load(right);
|
||||||
Comparison(cc, strict, destination());
|
Comparison(node, cc, strict, destination());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4867,7 +4867,8 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::Comparison(Condition cc,
|
void CodeGenerator::Comparison(AstNode* node,
|
||||||
|
Condition cc,
|
||||||
bool strict,
|
bool strict,
|
||||||
ControlDestination* dest) {
|
ControlDestination* dest) {
|
||||||
// Strict only makes sense for equality comparisons.
|
// Strict only makes sense for equality comparisons.
|
||||||
@ -4914,7 +4915,8 @@ void CodeGenerator::Comparison(Condition cc,
|
|||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
} else { // Only one side is a constant Smi.
|
} else {
|
||||||
|
// Only one side is a constant Smi.
|
||||||
// If left side is a constant Smi, reverse the operands.
|
// If left side is a constant Smi, reverse the operands.
|
||||||
// Since one side is a constant Smi, conversion order does not matter.
|
// Since one side is a constant Smi, conversion order does not matter.
|
||||||
if (left_side_constant_smi) {
|
if (left_side_constant_smi) {
|
||||||
@ -4928,6 +4930,8 @@ void CodeGenerator::Comparison(Condition cc,
|
|||||||
// Implement comparison against a constant Smi, inlining the case
|
// Implement comparison against a constant Smi, inlining the case
|
||||||
// where both sides are Smis.
|
// where both sides are Smis.
|
||||||
left_side.ToRegister();
|
left_side.ToRegister();
|
||||||
|
Register left_reg = left_side.reg();
|
||||||
|
Handle<Object> right_val = right_side.handle();
|
||||||
|
|
||||||
// Here we split control flow to the stub call and inlined cases
|
// Here we split control flow to the stub call and inlined cases
|
||||||
// before finally splitting it to the control destination. We use
|
// before finally splitting it to the control destination. We use
|
||||||
@ -4935,12 +4939,48 @@ void CodeGenerator::Comparison(Condition cc,
|
|||||||
// the first split. We manually handle the off-frame references
|
// the first split. We manually handle the off-frame references
|
||||||
// by reconstituting them on the non-fall-through path.
|
// by reconstituting them on the non-fall-through path.
|
||||||
JumpTarget is_smi;
|
JumpTarget is_smi;
|
||||||
Register left_reg = left_side.reg();
|
|
||||||
Handle<Object> right_val = right_side.handle();
|
|
||||||
|
|
||||||
Condition left_is_smi = masm_->CheckSmi(left_side.reg());
|
Condition left_is_smi = masm_->CheckSmi(left_side.reg());
|
||||||
is_smi.Branch(left_is_smi);
|
is_smi.Branch(left_is_smi);
|
||||||
|
|
||||||
|
bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
|
||||||
|
&& node->AsCompareOperation()->is_for_loop_condition();
|
||||||
|
if (!is_for_loop_compare && right_val->IsSmi()) {
|
||||||
|
// Right side is a constant smi and left side has been checked
|
||||||
|
// not to be a smi.
|
||||||
|
JumpTarget not_number;
|
||||||
|
__ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
|
||||||
|
Factory::heap_number_map());
|
||||||
|
not_number.Branch(not_equal, &left_side);
|
||||||
|
__ movsd(xmm1,
|
||||||
|
FieldOperand(left_reg, HeapNumber::kValueOffset));
|
||||||
|
int value = Smi::cast(*right_val)->value();
|
||||||
|
if (value == 0) {
|
||||||
|
__ xorpd(xmm0, xmm0);
|
||||||
|
} else {
|
||||||
|
Result temp = allocator()->Allocate();
|
||||||
|
__ movl(temp.reg(), Immediate(value));
|
||||||
|
__ cvtlsi2sd(xmm0, temp.reg());
|
||||||
|
temp.Unuse();
|
||||||
|
}
|
||||||
|
__ ucomisd(xmm1, xmm0);
|
||||||
|
// Jump to builtin for NaN.
|
||||||
|
not_number.Branch(parity_even, &left_side);
|
||||||
|
left_side.Unuse();
|
||||||
|
Condition double_cc = cc;
|
||||||
|
switch (cc) {
|
||||||
|
case less: double_cc = below; break;
|
||||||
|
case equal: double_cc = equal; break;
|
||||||
|
case less_equal: double_cc = below_equal; break;
|
||||||
|
case greater: double_cc = above; break;
|
||||||
|
case greater_equal: double_cc = above_equal; break;
|
||||||
|
default: UNREACHABLE();
|
||||||
|
}
|
||||||
|
dest->true_target()->Branch(double_cc);
|
||||||
|
dest->false_target()->Jump();
|
||||||
|
not_number.Bind(&left_side);
|
||||||
|
}
|
||||||
|
|
||||||
// Setup and call the compare stub.
|
// Setup and call the compare stub.
|
||||||
CompareStub stub(cc, strict);
|
CompareStub stub(cc, strict);
|
||||||
Result result = frame_->CallStub(&stub, &left_side, &right_side);
|
Result result = frame_->CallStub(&stub, &left_side, &right_side);
|
||||||
|
@ -484,7 +484,8 @@ class CodeGenerator: public AstVisitor {
|
|||||||
Result* right,
|
Result* right,
|
||||||
OverwriteMode overwrite_mode);
|
OverwriteMode overwrite_mode);
|
||||||
|
|
||||||
void Comparison(Condition cc,
|
void Comparison(AstNode* node,
|
||||||
|
Condition cc,
|
||||||
bool strict,
|
bool strict,
|
||||||
ControlDestination* destination);
|
ControlDestination* destination);
|
||||||
|
|
||||||
|
@ -993,56 +993,22 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
|
|||||||
byte* current = data + 2;
|
byte* current = data + 2;
|
||||||
// At return, "current" points to the start of the next instruction.
|
// At return, "current" points to the start of the next instruction.
|
||||||
const char* mnemonic = TwoByteMnemonic(opcode);
|
const char* mnemonic = TwoByteMnemonic(opcode);
|
||||||
if (opcode == 0x1F) {
|
if (operand_size_ == 0x66) {
|
||||||
// NOP
|
// 0x66 0x0F prefix.
|
||||||
int mod, regop, rm;
|
int mod, regop, rm;
|
||||||
get_modrm(*current, &mod, ®op, &rm);
|
get_modrm(*current, &mod, ®op, &rm);
|
||||||
current++;
|
const char* mnemonic = "?";
|
||||||
if (regop == 4) { // SIB byte present.
|
if (opcode == 0x57) {
|
||||||
current++;
|
mnemonic = "xorpd";
|
||||||
}
|
} else if (opcode == 0x2E) {
|
||||||
if (mod == 1) { // Byte displacement.
|
mnemonic = "comisd";
|
||||||
current += 1;
|
} else if (opcode == 0x2F) {
|
||||||
} else if (mod == 2) { // 32-bit displacement.
|
mnemonic = "ucomisd";
|
||||||
current += 4;
|
|
||||||
} // else no immediate displacement.
|
|
||||||
AppendToBuffer("nop");
|
|
||||||
|
|
||||||
} else if (opcode == 0xA2 || opcode == 0x31) {
|
|
||||||
// RDTSC or CPUID
|
|
||||||
AppendToBuffer("%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 ((opcode & 0xF0) == 0x80) {
|
|
||||||
// Jcc: Conditional jump (branch).
|
|
||||||
current = data + JumpConditional(data);
|
|
||||||
|
|
||||||
} else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
|
|
||||||
opcode == 0xB7 || opcode == 0xAF) {
|
|
||||||
// Size-extending moves, IMUL.
|
|
||||||
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 == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
|
|
||||||
// SHLD, SHRD (double-precision shift), BTS (bit set).
|
|
||||||
AppendToBuffer("%s ", mnemonic);
|
|
||||||
int mod, regop, rm;
|
|
||||||
get_modrm(*current, &mod, ®op, &rm);
|
|
||||||
current += PrintRightOperand(current);
|
|
||||||
if (opcode == 0xAB) {
|
|
||||||
AppendToBuffer(",%s", NameOfCPURegister(regop));
|
|
||||||
} else {
|
} else {
|
||||||
AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
|
UnimplementedInstruction();
|
||||||
}
|
}
|
||||||
|
AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
|
||||||
|
current += PrintRightXMMOperand(current);
|
||||||
} else if (group_1_prefix_ == 0xF2) {
|
} else if (group_1_prefix_ == 0xF2) {
|
||||||
// Beginning of instructions with prefix 0xF2.
|
// Beginning of instructions with prefix 0xF2.
|
||||||
|
|
||||||
@ -1080,6 +1046,55 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
|
|||||||
// Assert that mod is not 3, so source is memory, not an XMM register.
|
// Assert that mod is not 3, so source is memory, not an XMM register.
|
||||||
ASSERT_NE(0xC0, *current & 0xC0);
|
ASSERT_NE(0xC0, *current & 0xC0);
|
||||||
current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
|
current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
|
||||||
|
} else if (opcode == 0x1F) {
|
||||||
|
// NOP
|
||||||
|
int mod, regop, rm;
|
||||||
|
get_modrm(*current, &mod, ®op, &rm);
|
||||||
|
current++;
|
||||||
|
if (regop == 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.
|
||||||
|
AppendToBuffer("nop");
|
||||||
|
} else if (opcode == 0xA2 || opcode == 0x31) {
|
||||||
|
// RDTSC or CPUID
|
||||||
|
AppendToBuffer("%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 ((opcode & 0xF0) == 0x80) {
|
||||||
|
// Jcc: Conditional jump (branch).
|
||||||
|
current = data + JumpConditional(data);
|
||||||
|
|
||||||
|
} else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
|
||||||
|
opcode == 0xB7 || opcode == 0xAF) {
|
||||||
|
// Size-extending moves, IMUL.
|
||||||
|
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 == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
|
||||||
|
// SHLD, SHRD (double-precision shift), BTS (bit set).
|
||||||
|
AppendToBuffer("%s ", mnemonic);
|
||||||
|
int mod, regop, rm;
|
||||||
|
get_modrm(*current, &mod, ®op, &rm);
|
||||||
|
current += PrintRightOperand(current);
|
||||||
|
if (opcode == 0xAB) {
|
||||||
|
AppendToBuffer(",%s", NameOfCPURegister(regop));
|
||||||
|
} else {
|
||||||
|
AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
UnimplementedInstruction();
|
UnimplementedInstruction();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user