Index: src/compiler/arm64/instruction-selector-arm64.cc |
diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc |
index 26a289613483065ac8dab4ccf3561743d4a26656..557fe864615429f2f208c2acc71ba9139f684eae 100644 |
--- a/src/compiler/arm64/instruction-selector-arm64.cc |
+++ b/src/compiler/arm64/instruction-selector-arm64.cc |
@@ -289,8 +289,13 @@ void VisitBinop(InstructionSelector* selector, Node* node, |
DCHECK_GE(arraysize(inputs), input_count); |
DCHECK_GE(arraysize(outputs), output_count); |
- selector->Emit(cont->Encode(opcode), output_count, outputs, input_count, |
- inputs); |
+ opcode = cont->Encode(opcode); |
+ if (cont->IsDeoptimize()) { |
+ selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, |
+ cont->frame_state()); |
+ } else { |
+ selector->Emit(opcode, output_count, outputs, input_count, inputs); |
+ } |
} |
@@ -1674,6 +1679,9 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
if (cont->IsBranch()) { |
selector->Emit(opcode, g.NoOutput(), left, right, |
g.Label(cont->true_block()), g.Label(cont->false_block())); |
+ } else if (cont->IsDeoptimize()) { |
+ selector->EmitDeoptimize(opcode, g.NoOutput(), left, right, |
+ cont->frame_state()); |
} else { |
DCHECK(cont->IsSet()); |
selector->Emit(opcode, g.DefineAsRegister(cont->result()), left, right); |
@@ -1789,85 +1797,72 @@ void VisitFloat64Compare(InstructionSelector* selector, Node* node, |
} |
} |
-} // namespace |
- |
- |
-void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
- BasicBlock* fbranch) { |
- OperandGenerator g(this); |
- Node* user = branch; |
- Node* value = branch->InputAt(0); |
- |
- FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
- |
- // 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)) { |
+void VisitWordCompareZero(InstructionSelector* selector, Node* user, |
+ Node* value, FlagsContinuation* cont) { |
+ Arm64OperandGenerator g(selector); |
+ while (selector->CanCover(user, value)) { |
switch (value->opcode()) { |
- case IrOpcode::kWord32Equal: |
- cont.OverwriteAndNegateIfEqual(kEqual); |
- return VisitWord32Compare(this, value, &cont); |
+ case IrOpcode::kWord32Equal: { |
+ Int32BinopMatcher m(value); |
+ if (m.right().Is(0)) { |
+ user = value; |
+ value = m.left().node(); |
+ cont->Negate(); |
+ continue; |
+ } |
+ cont->OverwriteAndNegateIfEqual(kEqual); |
+ return VisitWord32Compare(selector, value, cont); |
+ } |
case IrOpcode::kInt32LessThan: |
- cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
- return VisitWord32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kSignedLessThan); |
+ return VisitWord32Compare(selector, value, cont); |
case IrOpcode::kInt32LessThanOrEqual: |
- cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
- return VisitWord32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
+ return VisitWord32Compare(selector, value, cont); |
case IrOpcode::kUint32LessThan: |
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
- return VisitWord32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); |
+ return VisitWord32Compare(selector, value, cont); |
case IrOpcode::kUint32LessThanOrEqual: |
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
- return VisitWord32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
+ return VisitWord32Compare(selector, value, cont); |
case IrOpcode::kWord64Equal: |
- cont.OverwriteAndNegateIfEqual(kEqual); |
- return VisitWordCompare(this, value, kArm64Cmp, &cont, false, |
+ cont->OverwriteAndNegateIfEqual(kEqual); |
+ return VisitWordCompare(selector, value, kArm64Cmp, cont, false, |
kArithmeticImm); |
case IrOpcode::kInt64LessThan: |
- cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
- return VisitWordCompare(this, value, kArm64Cmp, &cont, false, |
+ cont->OverwriteAndNegateIfEqual(kSignedLessThan); |
+ return VisitWordCompare(selector, value, kArm64Cmp, cont, false, |
kArithmeticImm); |
case IrOpcode::kInt64LessThanOrEqual: |
- cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
- return VisitWordCompare(this, value, kArm64Cmp, &cont, false, |
+ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
+ return VisitWordCompare(selector, value, kArm64Cmp, cont, false, |
kArithmeticImm); |
case IrOpcode::kUint64LessThan: |
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
- return VisitWordCompare(this, value, kArm64Cmp, &cont, false, |
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan); |
+ return VisitWordCompare(selector, value, kArm64Cmp, cont, false, |
kArithmeticImm); |
case IrOpcode::kUint64LessThanOrEqual: |
- cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
- return VisitWordCompare(this, value, kArm64Cmp, &cont, false, |
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
+ return VisitWordCompare(selector, value, kArm64Cmp, cont, false, |
kArithmeticImm); |
case IrOpcode::kFloat32Equal: |
- cont.OverwriteAndNegateIfEqual(kEqual); |
- return VisitFloat32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kEqual); |
+ return VisitFloat32Compare(selector, value, cont); |
case IrOpcode::kFloat32LessThan: |
- cont.OverwriteAndNegateIfEqual(kFloatLessThan); |
- return VisitFloat32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kFloatLessThan); |
+ return VisitFloat32Compare(selector, value, cont); |
case IrOpcode::kFloat32LessThanOrEqual: |
- cont.OverwriteAndNegateIfEqual(kFloatLessThanOrEqual); |
- return VisitFloat32Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual); |
+ return VisitFloat32Compare(selector, value, cont); |
case IrOpcode::kFloat64Equal: |
- cont.OverwriteAndNegateIfEqual(kEqual); |
- return VisitFloat64Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kEqual); |
+ return VisitFloat64Compare(selector, value, cont); |
case IrOpcode::kFloat64LessThan: |
- cont.OverwriteAndNegateIfEqual(kFloatLessThan); |
- return VisitFloat64Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kFloatLessThan); |
+ return VisitFloat64Compare(selector, value, cont); |
case IrOpcode::kFloat64LessThanOrEqual: |
- cont.OverwriteAndNegateIfEqual(kFloatLessThanOrEqual); |
- return VisitFloat64Compare(this, value, &cont); |
+ cont->OverwriteAndNegateIfEqual(kFloatLessThanOrEqual); |
+ return VisitFloat64Compare(selector, value, cont); |
case IrOpcode::kProjection: |
// Check if this is the overflow output projection of an |
// <Operation>WithOverflow node. |
@@ -1879,24 +1874,24 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
// *AFTER* this branch). |
Node* const node = value->InputAt(0); |
Node* const result = NodeProperties::FindProjection(node, 0); |
- if (result == nullptr || IsDefined(result)) { |
+ if (result == nullptr || selector->IsDefined(result)) { |
switch (node->opcode()) { |
case IrOpcode::kInt32AddWithOverflow: |
- cont.OverwriteAndNegateIfEqual(kOverflow); |
- return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, |
- kArithmeticImm, &cont); |
+ cont->OverwriteAndNegateIfEqual(kOverflow); |
+ return VisitBinop<Int32BinopMatcher>( |
+ selector, node, kArm64Add32, kArithmeticImm, cont); |
case IrOpcode::kInt32SubWithOverflow: |
- cont.OverwriteAndNegateIfEqual(kOverflow); |
- return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, |
- kArithmeticImm, &cont); |
+ cont->OverwriteAndNegateIfEqual(kOverflow); |
+ return VisitBinop<Int32BinopMatcher>( |
+ selector, node, kArm64Sub32, kArithmeticImm, cont); |
case IrOpcode::kInt64AddWithOverflow: |
- cont.OverwriteAndNegateIfEqual(kOverflow); |
- return VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, |
- kArithmeticImm, &cont); |
+ cont->OverwriteAndNegateIfEqual(kOverflow); |
+ return VisitBinop<Int64BinopMatcher>(selector, node, kArm64Add, |
+ kArithmeticImm, cont); |
case IrOpcode::kInt64SubWithOverflow: |
- cont.OverwriteAndNegateIfEqual(kOverflow); |
- return VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, |
- kArithmeticImm, &cont); |
+ cont->OverwriteAndNegateIfEqual(kOverflow); |
+ return VisitBinop<Int64BinopMatcher>(selector, node, kArm64Sub, |
+ kArithmeticImm, cont); |
default: |
break; |
} |
@@ -1904,55 +1899,84 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
} |
break; |
case IrOpcode::kInt32Add: |
- return VisitWordCompare(this, value, kArm64Cmn32, &cont, true, |
+ return VisitWordCompare(selector, value, kArm64Cmn32, cont, true, |
kArithmeticImm); |
case IrOpcode::kInt32Sub: |
- return VisitWord32Compare(this, value, &cont); |
+ return VisitWord32Compare(selector, value, cont); |
case IrOpcode::kWord32And: { |
Int32BinopMatcher m(value); |
- if (m.right().HasValue() && |
+ if (cont->IsBranch() && m.right().HasValue() && |
(base::bits::CountPopulation32(m.right().Value()) == 1)) { |
// If the mask has only one bit set, we can use tbz/tbnz. |
- DCHECK((cont.condition() == kEqual) || |
- (cont.condition() == kNotEqual)); |
- Emit(cont.Encode(kArm64TestAndBranch32), g.NoOutput(), |
- g.UseRegister(m.left().node()), |
- g.TempImmediate( |
- base::bits::CountTrailingZeros32(m.right().Value())), |
- g.Label(cont.true_block()), g.Label(cont.false_block())); |
+ DCHECK((cont->condition() == kEqual) || |
+ (cont->condition() == kNotEqual)); |
+ selector->Emit( |
+ cont->Encode(kArm64TestAndBranch32), g.NoOutput(), |
+ g.UseRegister(m.left().node()), |
+ g.TempImmediate( |
+ base::bits::CountTrailingZeros32(m.right().Value())), |
+ g.Label(cont->true_block()), g.Label(cont->false_block())); |
return; |
} |
- return VisitWordCompare(this, value, kArm64Tst32, &cont, true, |
+ return VisitWordCompare(selector, value, kArm64Tst32, cont, true, |
kLogical32Imm); |
} |
case IrOpcode::kWord64And: { |
Int64BinopMatcher m(value); |
- if (m.right().HasValue() && |
+ if (cont->IsBranch() && m.right().HasValue() && |
(base::bits::CountPopulation64(m.right().Value()) == 1)) { |
// If the mask has only one bit set, we can use tbz/tbnz. |
- DCHECK((cont.condition() == kEqual) || |
- (cont.condition() == kNotEqual)); |
- Emit(cont.Encode(kArm64TestAndBranch), g.NoOutput(), |
- g.UseRegister(m.left().node()), |
- g.TempImmediate( |
- base::bits::CountTrailingZeros64(m.right().Value())), |
- g.Label(cont.true_block()), g.Label(cont.false_block())); |
+ DCHECK((cont->condition() == kEqual) || |
+ (cont->condition() == kNotEqual)); |
+ selector->Emit( |
+ cont->Encode(kArm64TestAndBranch), g.NoOutput(), |
+ g.UseRegister(m.left().node()), |
+ g.TempImmediate( |
+ base::bits::CountTrailingZeros64(m.right().Value())), |
+ g.Label(cont->true_block()), g.Label(cont->false_block())); |
return; |
} |
- return VisitWordCompare(this, value, kArm64Tst, &cont, true, |
+ return VisitWordCompare(selector, value, kArm64Tst, cont, true, |
kLogical64Imm); |
} |
default: |
break; |
} |
+ break; |
} |
// Branch could not be combined with a compare, compare against 0 and branch. |
- Emit(cont.Encode(kArm64CompareAndBranch32), g.NoOutput(), |
- g.UseRegister(value), g.Label(cont.true_block()), |
- g.Label(cont.false_block())); |
+ if (cont->IsBranch()) { |
+ selector->Emit(cont->Encode(kArm64CompareAndBranch32), g.NoOutput(), |
+ g.UseRegister(value), g.Label(cont->true_block()), |
+ g.Label(cont->false_block())); |
+ } else { |
+ DCHECK(cont->IsDeoptimize()); |
+ selector->EmitDeoptimize(cont->Encode(kArm64Tst32), g.NoOutput(), |
+ g.UseRegister(value), g.UseRegister(value), |
+ cont->frame_state()); |
+ } |
+} |
+ |
+} // namespace |
+ |
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
+ BasicBlock* fbranch) { |
+ FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
+ VisitWordCompareZero(this, branch, branch->InputAt(0), &cont); |
+} |
+ |
+void InstructionSelector::VisitDeoptimizeIf(Node* node) { |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForDeoptimize(kNotEqual, node->InputAt(1)); |
+ VisitWordCompareZero(this, node, node->InputAt(0), &cont); |
} |
+void InstructionSelector::VisitDeoptimizeUnless(Node* node) { |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForDeoptimize(kEqual, node->InputAt(1)); |
+ VisitWordCompareZero(this, node, node->InputAt(0), &cont); |
+} |
void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { |
Arm64OperandGenerator g(this); |
@@ -1984,7 +2008,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { |
void InstructionSelector::VisitWord32Equal(Node* const node) { |
Node* const user = node; |
- FlagsContinuation cont(kEqual, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); |
Int32BinopMatcher m(user); |
if (m.right().Is(0)) { |
Node* const value = m.left().node(); |
@@ -2018,32 +2042,34 @@ void InstructionSelector::VisitWord32Equal(Node* const node) { |
void InstructionSelector::VisitInt32LessThan(Node* node) { |
- FlagsContinuation cont(kSignedLessThan, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); |
VisitWord32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) { |
- FlagsContinuation cont(kSignedLessThanOrEqual, node); |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); |
VisitWord32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitUint32LessThan(Node* node) { |
- FlagsContinuation cont(kUnsignedLessThan, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); |
VisitWord32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) { |
- FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); |
VisitWord32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitWord64Equal(Node* const node) { |
Node* const user = node; |
- FlagsContinuation cont(kEqual, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); |
Int64BinopMatcher m(user); |
if (m.right().Is(0)) { |
Node* const value = m.left().node(); |
@@ -2064,7 +2090,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) { |
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont(kOverflow, ovf); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, |
kArithmeticImm, &cont); |
} |
@@ -2075,7 +2101,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont(kOverflow, ovf); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, |
kArithmeticImm, &cont); |
} |
@@ -2086,7 +2112,7 @@ void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { |
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont(kOverflow, ovf); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
return VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm, |
&cont); |
} |
@@ -2097,7 +2123,7 @@ void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { |
void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { |
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
- FlagsContinuation cont(kOverflow, ovf); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
return VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, kArithmeticImm, |
&cont); |
} |
@@ -2107,61 +2133,65 @@ void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { |
void InstructionSelector::VisitInt64LessThan(Node* node) { |
- FlagsContinuation cont(kSignedLessThan, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kSignedLessThan, node); |
VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm); |
} |
void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) { |
- FlagsContinuation cont(kSignedLessThanOrEqual, node); |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForSet(kSignedLessThanOrEqual, node); |
VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm); |
} |
void InstructionSelector::VisitUint64LessThan(Node* node) { |
- FlagsContinuation cont(kUnsignedLessThan, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kUnsignedLessThan, node); |
VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm); |
} |
void InstructionSelector::VisitUint64LessThanOrEqual(Node* node) { |
- FlagsContinuation cont(kUnsignedLessThanOrEqual, node); |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForSet(kUnsignedLessThanOrEqual, node); |
VisitWordCompare(this, node, kArm64Cmp, &cont, false, kArithmeticImm); |
} |
void InstructionSelector::VisitFloat32Equal(Node* node) { |
- FlagsContinuation cont(kEqual, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); |
VisitFloat32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitFloat32LessThan(Node* node) { |
- FlagsContinuation cont(kFloatLessThan, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node); |
VisitFloat32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitFloat32LessThanOrEqual(Node* node) { |
- FlagsContinuation cont(kFloatLessThanOrEqual, node); |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForSet(kFloatLessThanOrEqual, node); |
VisitFloat32Compare(this, node, &cont); |
} |
void InstructionSelector::VisitFloat64Equal(Node* node) { |
- FlagsContinuation cont(kEqual, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node); |
VisitFloat64Compare(this, node, &cont); |
} |
void InstructionSelector::VisitFloat64LessThan(Node* node) { |
- FlagsContinuation cont(kFloatLessThan, node); |
+ FlagsContinuation cont = FlagsContinuation::ForSet(kFloatLessThan, node); |
VisitFloat64Compare(this, node, &cont); |
} |
void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) { |
- FlagsContinuation cont(kFloatLessThanOrEqual, node); |
+ FlagsContinuation cont = |
+ FlagsContinuation::ForSet(kFloatLessThanOrEqual, node); |
VisitFloat64Compare(this, node, &cont); |
} |