Index: src/compiler/mips64/instruction-selector-mips64.cc |
diff --git a/src/compiler/mips64/instruction-selector-mips64.cc b/src/compiler/mips64/instruction-selector-mips64.cc |
index 6e937e20d7ae9fdc4c48245b4bf3f8e760504a8a..1b3b6a6d62ccfc598253072bb32c7c83934f145a 100644 |
--- a/src/compiler/mips64/instruction-selector-mips64.cc |
+++ b/src/compiler/mips64/instruction-selector-mips64.cc |
@@ -1840,10 +1840,89 @@ void VisitWordCompare(InstructionSelector* selector, Node* node, |
} |
} |
+bool IsNodeUnsigned(Node* n) { |
+ NodeMatcher m(n); |
+ |
+ if (m.IsLoad()) { |
+ LoadRepresentation load_rep = LoadRepresentationOf(n->op()); |
+ return load_rep.IsUnsigned(); |
+ } else if (m.IsUnalignedLoad()) { |
+ UnalignedLoadRepresentation load_rep = |
+ UnalignedLoadRepresentationOf(n->op()); |
+ return load_rep.IsUnsigned(); |
+ } else { |
+ return m.IsUint32Div() || m.IsUint32LessThan() || |
+ m.IsUint32LessThanOrEqual() || m.IsUint32Mod() || |
+ m.IsUint32MulHigh() || m.IsChangeFloat64ToUint32() || |
+ m.IsTruncateFloat64ToUint32() || m.IsTruncateFloat32ToUint32(); |
+ } |
+} |
+ |
+// Shared routine for multiple word compare operations. |
+void VisitFullWord32Compare(InstructionSelector* selector, Node* node, |
+ InstructionCode opcode, FlagsContinuation* cont) { |
+ Mips64OperandGenerator g(selector); |
+ InstructionOperand leftOp = g.TempRegister(); |
+ InstructionOperand rightOp = g.TempRegister(); |
+ |
+ selector->Emit(kMips64Dshl, leftOp, g.UseRegister(node->InputAt(0)), |
+ g.TempImmediate(32)); |
+ selector->Emit(kMips64Dshl, rightOp, g.UseRegister(node->InputAt(1)), |
+ g.TempImmediate(32)); |
+ |
+ VisitCompare(selector, opcode, leftOp, rightOp, cont); |
+} |
+ |
+void VisitOptimizedWord32Compare(InstructionSelector* selector, Node* node, |
+ InstructionCode opcode, |
+ FlagsContinuation* cont) { |
+ if (FLAG_debug_code) { |
+ Mips64OperandGenerator g(selector); |
+ InstructionOperand leftOp = g.TempRegister(); |
+ InstructionOperand rightOp = g.TempRegister(); |
+ InstructionOperand optimizedResult = g.TempRegister(); |
+ InstructionOperand fullResult = g.TempRegister(); |
+ FlagsCondition condition = cont->condition(); |
+ InstructionCode testOpcode = opcode | |
+ FlagsConditionField::encode(condition) | |
+ FlagsModeField::encode(kFlags_set); |
+ |
+ selector->Emit(testOpcode, optimizedResult, g.UseRegister(node->InputAt(0)), |
+ g.UseRegister(node->InputAt(1))); |
+ |
+ selector->Emit(kMips64Dshl, leftOp, g.UseRegister(node->InputAt(0)), |
+ g.TempImmediate(32)); |
+ selector->Emit(kMips64Dshl, rightOp, g.UseRegister(node->InputAt(1)), |
+ g.TempImmediate(32)); |
+ selector->Emit(testOpcode, fullResult, leftOp, rightOp); |
+ |
+ selector->Emit( |
+ kMips64AssertEqual, g.NoOutput(), optimizedResult, fullResult, |
+ g.TempImmediate(BailoutReason::kUnsupportedNonPrimitiveCompare)); |
+ } |
+ |
+ VisitWordCompare(selector, node, opcode, cont, false); |
+} |
void VisitWord32Compare(InstructionSelector* selector, Node* node, |
FlagsContinuation* cont) { |
- VisitWordCompare(selector, node, kMips64Cmp, cont, false); |
+ // MIPS64 doesn't support Word32 compare instructions. Instead it relies |
+ // that the values in registers are correctly sign-extended and uses |
+ // Word64 comparison instead. This behavior is correct in most cases, |
+ // but doesn't work when comparing signed with unsigned operands. |
+ // We could simulate full Word32 compare in all cases but this would |
+ // create an unnecessary overhead since unsigned integers are rarely |
+ // used in JavaScript. |
+ // The solution proposed here tries to match a comparison of signed |
+ // with unsigned operand, and perform full Word32Compare only |
+ // in those cases. Unfortunately, the solution is not complete because |
+ // it might skip cases where Word32 full compare is needed, so |
+ // basically it is a hack. |
+ if (IsNodeUnsigned(node->InputAt(0)) != IsNodeUnsigned(node->InputAt(1))) { |
+ VisitFullWord32Compare(selector, node, kMips64Cmp, cont); |
+ } else { |
+ VisitOptimizedWord32Compare(selector, node, kMips64Cmp, cont); |
+ } |
} |