Commit e1b9058f authored by zhengxing.li's avatar zhengxing.li Committed by Commit bot

X87: Emit memory operands for cmp and test on ia32 and x64 when it makes sense.

  port 0e43ff56 (r34187)

  original commit message:
  The InstructionSelector now associates an effect level to every node in a block.

  The effect level of a node is the number of non-eliminatable nodes encountered from the beginning of the block to the node itself.

  With this change, on ia32 and x64, a load from memory into a register can be replaced by a memory operand if all of the following conditions hold:

  1. The only use of the load is in a 32 or 64 bit word comparison.
  2. The user node and the load node belong to the same block.
  3. The values of the operands have the same size (i.e., no need to zero-extend or sign-extend the result of the load).

BUG=

Review URL: https://codereview.chromium.org/1724473004

Cr-Commit-Position: refs/heads/master@{#34204}
parent ced09a7b
...@@ -615,18 +615,38 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -615,18 +615,38 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
} }
break; break;
case kX87Cmp: case kX87Cmp:
if (AddressingModeField::decode(instr->opcode()) != kMode_None) {
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
if (HasImmediateInput(instr, index)) {
__ cmp(operand, i.InputImmediate(index));
} else {
__ cmp(operand, i.InputRegister(index));
}
} else {
if (HasImmediateInput(instr, 1)) { if (HasImmediateInput(instr, 1)) {
__ cmp(i.InputOperand(0), i.InputImmediate(1)); __ cmp(i.InputOperand(0), i.InputImmediate(1));
} else { } else {
__ cmp(i.InputRegister(0), i.InputOperand(1)); __ cmp(i.InputRegister(0), i.InputOperand(1));
} }
}
break; break;
case kX87Test: case kX87Test:
if (AddressingModeField::decode(instr->opcode()) != kMode_None) {
size_t index = 0;
Operand operand = i.MemoryOperand(&index);
if (HasImmediateInput(instr, index)) {
__ test(operand, i.InputImmediate(index));
} else {
__ test(i.InputRegister(index), operand);
}
} else {
if (HasImmediateInput(instr, 1)) { if (HasImmediateInput(instr, 1)) {
__ test(i.InputOperand(0), i.InputImmediate(1)); __ test(i.InputOperand(0), i.InputImmediate(1));
} else { } else {
__ test(i.InputRegister(0), i.InputOperand(1)); __ test(i.InputRegister(0), i.InputOperand(1));
} }
}
break; break;
case kX87Imul: case kX87Imul:
if (HasImmediateInput(instr, 1)) { if (HasImmediateInput(instr, 1)) {
......
...@@ -993,6 +993,46 @@ bool InstructionSelector::IsTailCallAddressImmediate() { return true; } ...@@ -993,6 +993,46 @@ bool InstructionSelector::IsTailCallAddressImmediate() { return true; }
namespace { namespace {
void VisitCompareWithMemoryOperand(InstructionSelector* selector,
InstructionCode opcode, Node* left,
InstructionOperand right,
FlagsContinuation* cont) {
DCHECK(left->opcode() == IrOpcode::kLoad);
X87OperandGenerator g(selector);
size_t input_count = 0;
InstructionOperand inputs[6];
AddressingMode addressing_mode =
g.GetEffectiveAddressMemoryOperand(left, inputs, &input_count);
opcode |= AddressingModeField::encode(addressing_mode);
opcode = cont->Encode(opcode);
inputs[input_count++] = right;
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
selector->Emit(opcode, 0, nullptr, input_count, inputs);
} else {
DCHECK(cont->IsSet());
InstructionOperand output = g.DefineAsRegister(cont->result());
selector->Emit(opcode, 1, &output, input_count, inputs);
}
}
// Determines if {input} of {node} can be replaced by a memory operand.
bool CanUseMemoryOperand(InstructionSelector* selector, InstructionCode opcode,
Node* node, Node* input) {
if (input->opcode() != IrOpcode::kLoad || !selector->CanCover(node, input)) {
return false;
}
MachineRepresentation load_representation =
LoadRepresentationOf(input->op()).representation();
if (load_representation == MachineRepresentation::kWord32 ||
load_representation == MachineRepresentation::kTagged) {
return opcode == kX87Cmp || opcode == kX87Test;
}
return false;
}
// Shared routine for multiple compare operations. // Shared routine for multiple compare operations.
void VisitCompare(InstructionSelector* selector, InstructionCode opcode, void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
InstructionOperand left, InstructionOperand right, InstructionOperand left, InstructionOperand right,
...@@ -1054,26 +1094,41 @@ void VisitFloat64Compare(InstructionSelector* selector, Node* node, ...@@ -1054,26 +1094,41 @@ void VisitFloat64Compare(InstructionSelector* selector, Node* node,
} }
} }
// Shared routine for multiple word compare operations. // Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont) { InstructionCode opcode, FlagsContinuation* cont) {
X87OperandGenerator g(selector); X87OperandGenerator g(selector);
Node* const left = node->InputAt(0); Node* left = node->InputAt(0);
Node* const right = node->InputAt(1); Node* right = node->InputAt(1);
// Match immediates on left or right side of comparison. // If one of the two inputs is an immediate, make sure it's on the right.
if (!g.CanBeImmediate(right) && g.CanBeImmediate(left)) {
if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
std::swap(left, right);
}
// Match immediates on right side of comparison.
if (g.CanBeImmediate(right)) { if (g.CanBeImmediate(right)) {
VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right), cont); if (CanUseMemoryOperand(selector, opcode, node, left)) {
} else if (g.CanBeImmediate(left)) { return VisitCompareWithMemoryOperand(selector, opcode, left,
g.UseImmediate(right), cont);
}
return VisitCompare(selector, opcode, g.Use(left), g.UseImmediate(right),
cont);
}
if (g.CanBeBetterLeftOperand(right)) {
if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute(); if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
VisitCompare(selector, opcode, g.Use(right), g.UseImmediate(left), cont); std::swap(left, right);
} else {
VisitCompare(selector, opcode, left, right, cont,
node->op()->HasProperty(Operator::kCommutative));
} }
}
if (CanUseMemoryOperand(selector, opcode, node, left)) {
return VisitCompareWithMemoryOperand(selector, opcode, left,
g.UseRegister(right), cont);
}
return VisitCompare(selector, opcode, left, right, cont,
node->op()->HasProperty(Operator::kCommutative));
}
void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
......
...@@ -674,6 +674,11 @@ void Assembler::cmp(Register reg, const Operand& op) { ...@@ -674,6 +674,11 @@ void Assembler::cmp(Register reg, const Operand& op) {
emit_operand(reg, op); emit_operand(reg, op);
} }
void Assembler::cmp(const Operand& op, Register reg) {
EnsureSpace ensure_space(this);
EMIT(0x39);
emit_operand(reg, op);
}
void Assembler::cmp(const Operand& op, const Immediate& imm) { void Assembler::cmp(const Operand& op, const Immediate& imm) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
......
...@@ -671,6 +671,7 @@ class Assembler : public AssemblerBase { ...@@ -671,6 +671,7 @@ class Assembler : public AssemblerBase {
void cmp(Register reg0, Register reg1) { cmp(reg0, Operand(reg1)); } void cmp(Register reg0, Register reg1) { cmp(reg0, Operand(reg1)); }
void cmp(Register reg, const Operand& op); void cmp(Register reg, const Operand& op);
void cmp(Register reg, const Immediate& imm) { cmp(Operand(reg), imm); } void cmp(Register reg, const Immediate& imm) { cmp(Operand(reg), imm); }
void cmp(const Operand& op, Register reg);
void cmp(const Operand& op, const Immediate& imm); void cmp(const Operand& op, const Immediate& imm);
void cmp(const Operand& op, Handle<Object> handle); void cmp(const Operand& op, Handle<Object> handle);
......
...@@ -28,7 +28,6 @@ struct ByteMnemonic { ...@@ -28,7 +28,6 @@ struct ByteMnemonic {
OperandOrder op_order_; OperandOrder op_order_;
}; };
static const ByteMnemonic two_operands_instr[] = { static const ByteMnemonic two_operands_instr[] = {
{0x01, "add", OPER_REG_OP_ORDER}, {0x01, "add", OPER_REG_OP_ORDER},
{0x03, "add", REG_OPER_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
...@@ -43,6 +42,7 @@ static const ByteMnemonic two_operands_instr[] = { ...@@ -43,6 +42,7 @@ static const ByteMnemonic two_operands_instr[] = {
{0x31, "xor", OPER_REG_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
{0x33, "xor", REG_OPER_OP_ORDER}, {0x33, "xor", REG_OPER_OP_ORDER},
{0x38, "cmpb", OPER_REG_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
{0x39, "cmp", OPER_REG_OP_ORDER},
{0x3A, "cmpb", REG_OPER_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
{0x3B, "cmp", REG_OPER_OP_ORDER}, {0x3B, "cmp", REG_OPER_OP_ORDER},
{0x84, "test_b", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
...@@ -51,9 +51,7 @@ static const ByteMnemonic two_operands_instr[] = { ...@@ -51,9 +51,7 @@ static const ByteMnemonic two_operands_instr[] = {
{0x8A, "mov_b", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER},
{0x8B, "mov", REG_OPER_OP_ORDER}, {0x8B, "mov", REG_OPER_OP_ORDER},
{0x8D, "lea", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER},
{-1, "", UNSET_OP_ORDER} {-1, "", UNSET_OP_ORDER}};
};
static const ByteMnemonic zero_operands_instr[] = { static const ByteMnemonic zero_operands_instr[] = {
{0xC3, "ret", UNSET_OP_ORDER}, {0xC3, "ret", UNSET_OP_ORDER},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment