diff --git a/src/code-factory.cc b/src/code-factory.cc index 56dd5bace9..173f06e171 100644 --- a/src/code-factory.cc +++ b/src/code-factory.cc @@ -220,6 +220,17 @@ Callable CodeFactory::StringCompare(Isolate* isolate) { return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); } +// static +Callable CodeFactory::StringEqual(Isolate* isolate) { + StringEqualStub stub(isolate); + return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); +} + +// static +Callable CodeFactory::StringNotEqual(Isolate* isolate) { + StringNotEqualStub stub(isolate); + return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); +} // static Callable CodeFactory::SubString(Isolate* isolate) { diff --git a/src/code-factory.h b/src/code-factory.h index 5f2426c1a5..3d1ae06b15 100644 --- a/src/code-factory.h +++ b/src/code-factory.h @@ -81,6 +81,8 @@ class CodeFactory final { static Callable StringAdd(Isolate* isolate, StringAddFlags flags, PretenureFlag pretenure_flag); static Callable StringCompare(Isolate* isolate); + static Callable StringEqual(Isolate* isolate); + static Callable StringNotEqual(Isolate* isolate); static Callable SubString(Isolate* isolate); static Callable Typeof(Isolate* isolate); diff --git a/src/code-stubs.cc b/src/code-stubs.cc index d0f40f0440..3814986e43 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -7,6 +7,7 @@ #include #include "src/bootstrapper.h" +#include "src/code-factory.h" #include "src/compiler/code-stub-assembler.h" #include "src/factory.h" #include "src/gdb-jit.h" @@ -500,12 +501,12 @@ void StringLengthStub::GenerateAssembly( namespace { -enum StrictEqualMode { kStrictEqual, kStrictNotEqual }; +enum ResultMode { kDontNegateResult, kNegateResult }; void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, - StrictEqualMode mode) { - // Here's pseudo-code for the algorithm below in case of kStrictEqual mode; - // for kStrictNotEqual mode we properly negate the result. + Isolate* isolate, ResultMode mode) { + // Here's pseudo-code for the algorithm below in case of kDontNegateResult + // mode; for kNegateResult mode we properly negate the result. // // if (lhs == rhs) { // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; @@ -705,12 +706,10 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, assembler->Bind(&if_rhsisstring); { - // TODO(bmeurer): Optimize this further once the StringEqual - // functionality is available in TurboFan land. - Runtime::FunctionId function_id = (mode == kStrictEqual) - ? Runtime::kStringEqual - : Runtime::kStringNotEqual; - assembler->TailCallRuntime(function_id, context, lhs, rhs); + Callable callable = (mode == kDontNegateResult) + ? CodeFactory::StringEqual(isolate) + : CodeFactory::StringNotEqual(isolate); + assembler->TailCallStub(callable, context, lhs, rhs); } assembler->Bind(&if_rhsisnotstring); @@ -730,7 +729,7 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, assembler->Bind(&if_lhsissimd128value); { // TODO(bmeurer): Inline the Simd128Value equality check. - Runtime::FunctionId function_id = (mode == kStrictEqual) + Runtime::FunctionId function_id = (mode == kDontNegateResult) ? Runtime::kStrictEqual : Runtime::kStrictNotEqual; assembler->TailCallRuntime(function_id, context, lhs, rhs); @@ -785,22 +784,209 @@ void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, } assembler->Bind(&if_equal); - assembler->Return(assembler->BooleanConstant(mode == kStrictEqual)); + assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); assembler->Bind(&if_notequal); - assembler->Return(assembler->BooleanConstant(mode == kStrictNotEqual)); + assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); +} + +void GenerateStringEqual(compiler::CodeStubAssembler* assembler, + ResultMode mode) { + // Here's pseudo-code for the algorithm below in case of kDontNegateResult + // mode; for kNegateResult mode we properly negate the result. + // + // if (lhs == rhs) return true; + // if (lhs->length() != rhs->length()) return false; + // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { + // return false; + // } + // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { + // for (i = 0; i != lhs->length(); ++i) { + // if (lhs[i] != rhs[i]) return false; + // } + // return true; + // } + // return %StringEqual(lhs, rhs); + + typedef compiler::CodeStubAssembler::Label Label; + typedef compiler::Node Node; + typedef compiler::CodeStubAssembler::Variable Variable; + + Node* lhs = assembler->Parameter(0); + Node* rhs = assembler->Parameter(1); + Node* context = assembler->Parameter(2); + + Label if_equal(assembler), if_notequal(assembler); + + // Fast check to see if {lhs} and {rhs} refer to the same String object. + Label if_same(assembler), if_notsame(assembler); + assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); + + assembler->Bind(&if_same); + assembler->Goto(&if_equal); + + assembler->Bind(&if_notsame); + { + // The {lhs} and {rhs} don't refer to the exact same String object. + + // Load the length of {lhs} and {rhs}. + Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset); + Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset); + + // Check if the lengths of {lhs} and {rhs} are equal. + Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); + assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), + &if_lengthisequal, &if_lengthisnotequal); + + assembler->Bind(&if_lengthisequal); + { + // Load instance types of {lhs} and {rhs}. + Node* lhs_instance_type = assembler->LoadInstanceType(lhs); + Node* rhs_instance_type = assembler->LoadInstanceType(rhs); + + // Combine the instance types into a single 16-bit value, so we can check + // both of them at once. + Node* both_instance_types = assembler->Word32Or( + lhs_instance_type, + assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8))); + + // Check if both {lhs} and {rhs} are internalized. + int const kBothInternalizedMask = + kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); + int const kBothInternalizedTag = + kInternalizedTag | (kInternalizedTag << 8); + Label if_bothinternalized(assembler), if_notbothinternalized(assembler); + assembler->Branch(assembler->Word32Equal( + assembler->Word32And(both_instance_types, + assembler->Int32Constant( + kBothInternalizedMask)), + assembler->Int32Constant(kBothInternalizedTag)), + &if_bothinternalized, &if_notbothinternalized); + + assembler->Bind(&if_bothinternalized); + { + // Fast negative check for internalized-to-internalized equality. + assembler->Goto(&if_notequal); + } + + assembler->Bind(&if_notbothinternalized); + { + // Check that both {lhs} and {rhs} are flat one-byte strings. + int const kBothSeqOneByteStringMask = + kStringEncodingMask | kStringRepresentationMask | + ((kStringEncodingMask | kStringRepresentationMask) << 8); + int const kBothSeqOneByteStringTag = + kOneByteStringTag | kSeqStringTag | + ((kOneByteStringTag | kSeqStringTag) << 8); + Label if_bothonebyteseqstrings(assembler), + if_notbothonebyteseqstrings(assembler); + assembler->Branch( + assembler->Word32Equal( + assembler->Word32And( + both_instance_types, + assembler->Int32Constant(kBothSeqOneByteStringMask)), + assembler->Int32Constant(kBothSeqOneByteStringTag)), + &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings); + + assembler->Bind(&if_bothonebyteseqstrings); + { + // Compute the effective offset of the first character. + Node* begin = assembler->IntPtrConstant( + SeqOneByteString::kHeaderSize - kHeapObjectTag); + + // Compute the first offset after the string from the length. + Node* end = + assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length)); + + // Loop over the {lhs} and {rhs} strings to see if they are equal. + Variable var_offset(assembler, MachineType::PointerRepresentation()); + Label loop(assembler, &var_offset); + var_offset.Bind(begin); + assembler->Goto(&loop); + assembler->Bind(&loop); + { + // Check if {offset} equals {end}. + Node* offset = var_offset.value(); + Label if_done(assembler), if_notdone(assembler); + assembler->Branch(assembler->WordEqual(offset, end), &if_done, + &if_notdone); + + assembler->Bind(&if_notdone); + { + // Load the next characters from {lhs} and {rhs}. + Node* lhs_value = + assembler->Load(MachineType::Uint8(), lhs, offset); + Node* rhs_value = + assembler->Load(MachineType::Uint8(), rhs, offset); + + // Check if the characters match. + Label if_valueissame(assembler), if_valueisnotsame(assembler); + assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value), + &if_valueissame, &if_valueisnotsame); + + assembler->Bind(&if_valueissame); + { + // Advance to next character. + var_offset.Bind( + assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); + } + assembler->Goto(&loop); + + assembler->Bind(&if_valueisnotsame); + assembler->Goto(&if_notequal); + } + + assembler->Bind(&if_done); + assembler->Goto(&if_equal); + } + } + + assembler->Bind(&if_notbothonebyteseqstrings); + { + // TODO(bmeurer): Add fast case support for flattened cons strings; + // also add support for two byte string equality checks. + Runtime::FunctionId function_id = (mode == kDontNegateResult) + ? Runtime::kStringEqual + : Runtime::kStringNotEqual; + assembler->TailCallRuntime(function_id, context, lhs, rhs); + } + } + } + + assembler->Bind(&if_lengthisnotequal); + { + // Mismatch in length of {lhs} and {rhs}, cannot be equal. + assembler->Goto(&if_notequal); + } + } + + assembler->Bind(&if_equal); + assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult)); + + assembler->Bind(&if_notequal); + assembler->Return(assembler->BooleanConstant(mode == kNegateResult)); } } // namespace void StrictEqualStub::GenerateAssembly( compiler::CodeStubAssembler* assembler) const { - GenerateStrictEqual(assembler, kStrictEqual); + GenerateStrictEqual(assembler, isolate(), kDontNegateResult); } void StrictNotEqualStub::GenerateAssembly( compiler::CodeStubAssembler* assembler) const { - GenerateStrictEqual(assembler, kStrictNotEqual); + GenerateStrictEqual(assembler, isolate(), kNegateResult); +} + +void StringEqualStub::GenerateAssembly( + compiler::CodeStubAssembler* assembler) const { + GenerateStringEqual(assembler, kDontNegateResult); +} + +void StringNotEqualStub::GenerateAssembly( + compiler::CodeStubAssembler* assembler) const { + GenerateStringEqual(assembler, kNegateResult); } void ToBooleanStub::GenerateAssembly( diff --git a/src/code-stubs.h b/src/code-stubs.h index 595769d173..fbed23f847 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -103,6 +103,8 @@ namespace internal { V(StringLength) \ V(StrictEqual) \ V(StrictNotEqual) \ + V(StringEqual) \ + V(StringNotEqual) \ V(ToBoolean) \ /* IC Handler stubs */ \ V(ArrayBufferViewLoadField) \ @@ -653,6 +655,26 @@ class StrictNotEqualStub final : public TurboFanCodeStub { DEFINE_CODE_STUB(StrictNotEqual, TurboFanCodeStub); }; +class StringEqualStub final : public TurboFanCodeStub { + public: + explicit StringEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {} + + void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final; + + DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare); + DEFINE_CODE_STUB(StringEqual, TurboFanCodeStub); +}; + +class StringNotEqualStub final : public TurboFanCodeStub { + public: + explicit StringNotEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {} + + void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final; + + DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare); + DEFINE_CODE_STUB(StringNotEqual, TurboFanCodeStub); +}; + class ToBooleanStub final : public TurboFanCodeStub { public: explicit ToBooleanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {} diff --git a/src/compiler/code-stub-assembler.cc b/src/compiler/code-stub-assembler.cc index b340c10d89..0813cbed91 100644 --- a/src/compiler/code-stub-assembler.cc +++ b/src/compiler/code-stub-assembler.cc @@ -602,6 +602,14 @@ Node* CodeStubAssembler::CallStub(const CallInterfaceDescriptor& descriptor, return CallN(call_descriptor, target, args); } +Node* CodeStubAssembler::TailCallStub(Callable const& callable, Node* context, + Node* arg1, Node* arg2, + size_t result_size) { + Node* target = HeapConstant(callable.code()); + return TailCallStub(callable.descriptor(), target, context, arg1, arg2, + result_size); +} + Node* CodeStubAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target, Node* context, Node* arg1, Node* arg2, size_t result_size) { diff --git a/src/compiler/code-stub-assembler.h b/src/compiler/code-stub-assembler.h index 0edf7a55c9..04bc05c5c1 100644 --- a/src/compiler/code-stub-assembler.h +++ b/src/compiler/code-stub-assembler.h @@ -19,6 +19,7 @@ namespace v8 { namespace internal { +class Callable; class CallInterfaceDescriptor; class Isolate; class Factory; @@ -215,6 +216,9 @@ class CodeStubAssembler { Node* context, Node* arg1, Node* arg2, Node* arg3, Node* arg4, Node* arg5, size_t result_size = 1); + Node* TailCallStub(Callable const& callable, Node* context, Node* arg1, + Node* arg2, size_t result_size = 1); + Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target, Node* context, Node* arg1, Node* arg2, size_t result_size = 1); diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index b7c81f435d..e4251acceb 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -294,6 +294,10 @@ class RepresentationSelector { return NodeOutputInfo(MachineRepresentation::kTagged, Type::Any()); } + static NodeOutputInfo BoolTagged() { + return NodeOutputInfo(MachineRepresentation::kTagged, Type::Boolean()); + } + static NodeOutputInfo NumberTagged() { return NodeOutputInfo(MachineRepresentation::kTagged, Type::Number()); } @@ -1139,8 +1143,20 @@ class RepresentationSelector { break; } case IrOpcode::kStringEqual: { - VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::Bool()); - if (lower()) lowering->DoStringEqual(node); + VisitBinop(node, UseInfo::AnyTagged(), NodeOutputInfo::BoolTagged()); + if (lower()) { + // StringEqual(x, y) => Call(StringEqualStub, x, y, no-context) + Operator::Properties properties = node->op()->properties(); + Callable callable = CodeFactory::StringEqual(jsgraph_->isolate()); + CallDescriptor::Flags flags = CallDescriptor::kNoFlags; + CallDescriptor* desc = Linkage::GetStubCallDescriptor( + jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0, + flags, properties); + node->InsertInput(jsgraph_->zone(), 0, + jsgraph_->HeapConstant(callable.code())); + node->InsertInput(jsgraph_->zone(), 3, jsgraph_->NoContextConstant()); + NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc)); + } break; } case IrOpcode::kStringLessThan: { @@ -1890,16 +1906,6 @@ void ReplaceEffectUses(Node* node, Node* replacement) { } // namespace -void SimplifiedLowering::DoStringEqual(Node* node) { - Node* comparison = StringComparison(node); - ReplaceEffectUses(node, comparison); - node->ReplaceInput(0, comparison); - node->ReplaceInput(1, jsgraph()->SmiConstant(EQUAL)); - node->TrimInputCount(2); - NodeProperties::ChangeOp(node, machine()->WordEqual()); -} - - void SimplifiedLowering::DoStringLessThan(Node* node) { Node* comparison = StringComparison(node); ReplaceEffectUses(node, comparison); diff --git a/src/compiler/simplified-lowering.h b/src/compiler/simplified-lowering.h index 358bd97f9c..0e66835c1d 100644 --- a/src/compiler/simplified-lowering.h +++ b/src/compiler/simplified-lowering.h @@ -37,7 +37,6 @@ class SimplifiedLowering final { RepresentationChanger* changer); void DoStoreBuffer(Node* node); void DoShift(Node* node, Operator const* op, Type* rhs_type); - void DoStringEqual(Node* node); void DoStringLessThan(Node* node); void DoStringLessThanOrEqual(Node* node); diff --git a/src/crankshaft/arm/lithium-codegen-arm.cc b/src/crankshaft/arm/lithium-codegen-arm.cc index 568efe83ae..31a0472fd5 100644 --- a/src/crankshaft/arm/lithium-codegen-arm.cc +++ b/src/crankshaft/arm/lithium-codegen-arm.cc @@ -2366,9 +2366,15 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { DCHECK(ToRegister(instr->left()).is(r1)); DCHECK(ToRegister(instr->right()).is(r0)); - Handle code = CodeFactory::StringCompare(isolate()).code(); - CallCode(code, RelocInfo::CODE_TARGET, instr); - __ cmp(r0, Operand::Zero()); + if (Token::IsOrderedRelationalCompareOp(instr->op())) { + Handle code = CodeFactory::StringCompare(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ cmp(r0, Operand::Zero()); + } else { + Handle code = CodeFactory::StringEqual(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ CompareRoot(r0, Heap::kTrueValueRootIndex); + } EmitBranch(instr, ComputeCompareCondition(instr->op())); } diff --git a/src/crankshaft/arm64/lithium-codegen-arm64.cc b/src/crankshaft/arm64/lithium-codegen-arm64.cc index abb0e71ea4..6e9d604be8 100644 --- a/src/crankshaft/arm64/lithium-codegen-arm64.cc +++ b/src/crankshaft/arm64/lithium-codegen-arm64.cc @@ -5193,10 +5193,18 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { DCHECK(ToRegister(instr->left()).is(x1)); DCHECK(ToRegister(instr->right()).is(x0)); - Handle code = CodeFactory::StringCompare(isolate()).code(); - CallCode(code, RelocInfo::CODE_TARGET, instr); + if (Token::IsOrderedRelationalCompareOp(instr->op())) { + Handle code = CodeFactory::StringCompare(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); - EmitCompareAndBranch(instr, TokenToCondition(instr->op(), false), x0, 0); + EmitCompareAndBranch(instr, TokenToCondition(instr->op(), false), x0, 0); + } else { + Handle code = CodeFactory::StringEqual(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ CompareRoot(x0, Heap::kTrueValueRootIndex); + + EmitBranch(instr, TokenToCondition(instr->op(), false)); + } } diff --git a/src/crankshaft/ia32/lithium-codegen-ia32.cc b/src/crankshaft/ia32/lithium-codegen-ia32.cc index f292b949da..2ba7b3fa0a 100644 --- a/src/crankshaft/ia32/lithium-codegen-ia32.cc +++ b/src/crankshaft/ia32/lithium-codegen-ia32.cc @@ -2168,9 +2168,15 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { DCHECK(ToRegister(instr->left()).is(edx)); DCHECK(ToRegister(instr->right()).is(eax)); - Handle code = CodeFactory::StringCompare(isolate()).code(); - CallCode(code, RelocInfo::CODE_TARGET, instr); - __ test(eax, eax); + if (Token::IsOrderedRelationalCompareOp(instr->op())) { + Handle code = CodeFactory::StringCompare(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ test(eax, eax); + } else { + Handle code = CodeFactory::StringEqual(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ CompareRoot(eax, Heap::kTrueValueRootIndex); + } EmitBranch(instr, ComputeCompareCondition(instr->op())); } diff --git a/src/crankshaft/mips/lithium-codegen-mips.cc b/src/crankshaft/mips/lithium-codegen-mips.cc index 1073f86af0..dd908dea5c 100644 --- a/src/crankshaft/mips/lithium-codegen-mips.cc +++ b/src/crankshaft/mips/lithium-codegen-mips.cc @@ -2275,11 +2275,19 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { DCHECK(ToRegister(instr->left()).is(a1)); DCHECK(ToRegister(instr->right()).is(a0)); - Handle code = CodeFactory::StringCompare(isolate()).code(); - CallCode(code, RelocInfo::CODE_TARGET, instr); + if (Token::IsOrderedRelationalCompareOp(instr->op())) { + Handle code = CodeFactory::StringCompare(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); - EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, - Operand(zero_reg)); + EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, + Operand(zero_reg)); + } else { + Handle code = CodeFactory::StringEqual(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ LoadRoot(at, Heap::kTrueValueRootIndex); + + EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, Operand(at)); + } } diff --git a/src/crankshaft/mips64/lithium-codegen-mips64.cc b/src/crankshaft/mips64/lithium-codegen-mips64.cc index f8652ea843..721605aca9 100644 --- a/src/crankshaft/mips64/lithium-codegen-mips64.cc +++ b/src/crankshaft/mips64/lithium-codegen-mips64.cc @@ -2392,11 +2392,19 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { DCHECK(ToRegister(instr->left()).is(a1)); DCHECK(ToRegister(instr->right()).is(a0)); - Handle code = CodeFactory::StringCompare(isolate()).code(); - CallCode(code, RelocInfo::CODE_TARGET, instr); + if (Token::IsOrderedRelationalCompareOp(instr->op())) { + Handle code = CodeFactory::StringCompare(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); - EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, - Operand(zero_reg)); + EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, + Operand(zero_reg)); + } else { + Handle code = CodeFactory::StringEqual(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ LoadRoot(at, Heap::kTrueValueRootIndex); + + EmitBranch(instr, ComputeCompareCondition(instr->op()), v0, Operand(at)); + } } diff --git a/src/crankshaft/x64/lithium-codegen-x64.cc b/src/crankshaft/x64/lithium-codegen-x64.cc index 35855179df..f8dd6662d3 100644 --- a/src/crankshaft/x64/lithium-codegen-x64.cc +++ b/src/crankshaft/x64/lithium-codegen-x64.cc @@ -2318,9 +2318,15 @@ void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { DCHECK(ToRegister(instr->left()).is(rdx)); DCHECK(ToRegister(instr->right()).is(rax)); - Handle code = CodeFactory::StringCompare(isolate()).code(); - CallCode(code, RelocInfo::CODE_TARGET, instr); - __ testp(rax, rax); + if (Token::IsOrderedRelationalCompareOp(instr->op())) { + Handle code = CodeFactory::StringCompare(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ testp(rax, rax); + } else { + Handle code = CodeFactory::StringEqual(isolate()).code(); + CallCode(code, RelocInfo::CODE_TARGET, instr); + __ CompareRoot(rax, Heap::kTrueValueRootIndex); + } EmitBranch(instr, TokenToCondition(instr->op(), false)); } diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc index 1b752edd3c..dc790ff98a 100644 --- a/test/cctest/compiler/test-simplified-lowering.cc +++ b/test/cctest/compiler/test-simplified-lowering.cc @@ -1144,13 +1144,10 @@ TEST(LowerReferenceEqual_to_wordeq) { TEST(LowerStringOps_to_call_and_compare) { // These tests need linkage for the calls. TestingGraph t(Type::String(), Type::String()); - IrOpcode::Value compare_eq = - static_cast(t.machine()->WordEqual()->opcode()); IrOpcode::Value compare_lt = static_cast(t.machine()->IntLessThan()->opcode()); IrOpcode::Value compare_le = static_cast( t.machine()->IntLessThanOrEqual()->opcode()); - t.CheckLoweringStringBinop(compare_eq, t.simplified()->StringEqual()); t.CheckLoweringStringBinop(compare_lt, t.simplified()->StringLessThan()); t.CheckLoweringStringBinop(compare_le, t.simplified()->StringLessThanOrEqual());