Commit d9cda16c authored by paul.lind@imgtec.com's avatar paul.lind@imgtec.com

MIPS: [turbofan] Make VisitBranch and friends to backend specific.

Port r24546 (c3443cd)

Original commit message:
This is required to fix a tricky branch fusion bug on ARM, which was
caused by the interaction between the architecture-independent and
architecture-specific parts of the InstructionSelector. In the end it
wasn't worth sharing a few common lines of code for the additional
complexity, especially if we also want to properly support architectures
without any dedicated flags register (i.e. MIPS).

TEST=mjsunit,unittests
BUG=
R=paul.lind@imgtec.com

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

Patch from Balazs Kilvady <balazs.kilvady@imgtec.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24571 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 55f77c28
...@@ -401,21 +401,21 @@ void InstructionSelector::VisitFloat64Sqrt(Node* node) { ...@@ -401,21 +401,21 @@ void InstructionSelector::VisitFloat64Sqrt(Node* node) {
Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0))); Emit(kMipsSqrtD, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
} }
void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
BasicBlock* deoptimization) { void InstructionSelector::VisitCall(Node* node) {
MipsOperandGenerator g(this); MipsOperandGenerator g(this);
CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); CallDescriptor* descriptor = OpParameter<CallDescriptor*>(node);
FrameStateDescriptor* frame_state_descriptor = NULL; FrameStateDescriptor* frame_state_descriptor = NULL;
if (descriptor->NeedsFrameState()) { if (descriptor->NeedsFrameState()) {
frame_state_descriptor = frame_state_descriptor =
GetFrameStateDescriptor(call->InputAt(descriptor->InputCount())); GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
} }
CallBuffer buffer(zone(), descriptor, frame_state_descriptor); CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
// Compute InstructionOperands for inputs and outputs. // Compute InstructionOperands for inputs and outputs.
InitializeCallBuffer(call, &buffer, true, false); InitializeCallBuffer(node, &buffer, true, false);
// TODO(dcarney): might be possible to use claim/poke instead // TODO(dcarney): might be possible to use claim/poke instead
// Push any stack arguments. // Push any stack arguments.
...@@ -447,26 +447,11 @@ void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, ...@@ -447,26 +447,11 @@ void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
Instruction* call_instr = Instruction* call_instr =
Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(), Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
buffer.instruction_args.size(), &buffer.instruction_args.front()); buffer.instruction_args.size(), &buffer.instruction_args.front());
call_instr->MarkAsCall(); call_instr->MarkAsCall();
if (deoptimization != NULL) {
DCHECK(continuation != NULL);
call_instr->MarkAsControl();
}
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
FlagsContinuation* cont) {
VisitBinop(this, node, kMipsAddOvf, cont);
} }
void InstructionSelector::VisitInt32SubWithOverflow(Node* node, namespace {
FlagsContinuation* cont) {
VisitBinop(this, node, kMipsSubOvf, cont);
}
// Shared routine for multiple compare operations. // Shared routine for multiple compare operations.
static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
...@@ -485,10 +470,21 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -485,10 +470,21 @@ static void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
} }
// Shared routine for multiple float compare operations.
void VisitFloat64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
MipsOperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
VisitCompare(selector, kMipsCmpD, g.UseRegister(left), g.UseRegister(right),
cont);
}
// Shared routine for multiple word compare operations. // Shared routine for multiple word compare operations.
static void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont, InstructionCode opcode, FlagsContinuation* cont,
bool commutative) { bool commutative) {
MipsOperandGenerator g(selector); MipsOperandGenerator g(selector);
Node* left = node->InputAt(0); Node* left = node->InputAt(0);
Node* right = node->InputAt(1); Node* right = node->InputAt(1);
...@@ -508,35 +504,138 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -508,35 +504,138 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node,
} }
void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { void VisitWordCompare(InstructionSelector* selector, Node* node,
switch (node->opcode()) { FlagsContinuation* cont) {
case IrOpcode::kWord32And: VisitWordCompare(selector, node, kMipsCmp, cont, false);
// TODO(plind): understand the significance of 'IR and' special case. }
return VisitWordCompare(this, node, kMipsTst, cont, true);
default:
break;
}
MipsOperandGenerator g(this);
void VisitWordTest(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
MipsOperandGenerator g(selector);
// kMipsTst is a pseudo-instruction to do logical 'and' and leave the result // kMipsTst is a pseudo-instruction to do logical 'and' and leave the result
// in a dedicated tmp register. // in a dedicated tmp register.
VisitCompare(this, kMipsTst, g.UseRegister(node), g.UseRegister(node), cont); VisitCompare(selector, kMipsTst, g.UseRegister(node), g.UseRegister(node),
cont);
} }
} // namespace
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) {
MipsOperandGenerator g(this);
Node* user = branch;
Node* value = branch->InputAt(0);
FlagsContinuation cont(kNotEqual, tbranch, fbranch);
// If we can fall through to the true block, invert the branch.
if (IsNextInAssemblyOrder(tbranch)) {
cont.Negate();
cont.SwapBlocks();
}
// Try to combine with comparisons against 0 by simply inverting the branch.
while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) {
Int32BinopMatcher m(value);
if (m.right().Is(0)) {
user = value;
value = m.left().node();
cont.Negate();
} else {
break;
}
}
// Try to combine the branch with a comparison.
if (CanCover(user, value)) {
switch (value->opcode()) {
case IrOpcode::kWord32And:
// TODO(plind): understand the significance of 'IR and' special case.
return VisitWordCompare(this, value, kMipsTst, &cont, true);
default:
break;
}
}
void InstructionSelector::VisitWord32Compare(Node* node, // Branch could not be combined with a compare, emit compare against 0.
FlagsContinuation* cont) { return VisitWordTest(this, value, &cont);
VisitWordCompare(this, node, kMipsCmp, cont, false);
} }
void InstructionSelector::VisitFloat64Compare(Node* node, void InstructionSelector::VisitWord32Equal(Node* const node) {
FlagsContinuation* cont) { Node* const user = node;
MipsOperandGenerator g(this); FlagsContinuation cont(kEqual, node);
Node* left = node->InputAt(0); Int32BinopMatcher m(user);
Node* right = node->InputAt(1); if (m.right().Is(0)) {
VisitCompare(this, kMipsCmpD, g.UseRegister(left), g.UseRegister(right), Node* const value = m.left().node();
cont); return VisitWordTest(this, value, &cont);
}
VisitWordCompare(this, node, &cont);
}
void InstructionSelector::VisitInt32LessThan(Node* node) {
FlagsContinuation cont(kSignedLessThan, node);
VisitWordCompare(this, node, &cont);
}
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kSignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont);
}
void InstructionSelector::VisitUint32LessThan(Node* node) {
FlagsContinuation cont(kUnsignedLessThan, node);
VisitWordCompare(this, node, &cont);
}
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
VisitWordCompare(this, node, &cont);
}
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMipsAddOvf, &cont);
}
FlagsContinuation cont;
VisitBinop(this, node, kMipsAddOvf, &cont);
}
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = node->FindProjection(1)) {
FlagsContinuation cont(kOverflow, ovf);
return VisitBinop(this, node, kMipsSubOvf, &cont);
}
FlagsContinuation cont;
VisitBinop(this, node, kMipsSubOvf, &cont);
}
void InstructionSelector::VisitFloat64Equal(Node* node) {
FlagsContinuation cont(kUnorderedEqual, node);
VisitFloat64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThan(Node* node) {
FlagsContinuation cont(kUnorderedLessThan, node);
VisitFloat64Compare(this, node, &cont);
}
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
VisitFloat64Compare(this, node, &cont);
} }
} // namespace compiler } // namespace compiler
......
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