Commit 6463c0f0 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Hook in compare op builtins with feedback in generic lowering

If --turbo-nci is enabled, use compare op builtins with feedback
collection during generic lowering.

Bug: v8:8888
Change-Id: I886020e2ee280f65388d9987c70958546f99e0f3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2215821Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68100}
parent d47ab50b
......@@ -324,7 +324,7 @@ void BinaryOp_WithFeedbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {rdx, // kLeft
rax, // kRight
rdi, // Slot
rdi, // kSlot
rbx}; // kMaybeFeedbackVector
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......@@ -342,7 +342,7 @@ void Compare_WithFeedbackDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {rdx, // kLeft
rax, // kRight
rdi, // Slot
rdi, // kSlot
rbx}; // kMaybeFeedbackVector
data->InitializePlatformSpecific(arraysize(registers), registers);
}
......
......@@ -247,10 +247,6 @@ class BytecodeGraphBuilder {
// type feedback.
BinaryOperationHint GetBinaryOperationHint(int operand_index);
// Helper function to create compare operation hint from the recorded
// type feedback.
CompareOperationHint GetCompareOperationHint();
// Helper function to create for-in mode from the recorded type feedback.
ForInMode GetForInMode(int operand_index);
......@@ -443,10 +439,11 @@ class BytecodeGraphBuilder {
TickCounter* const tick_counter_;
static int const kBinaryOperationHintIndex = 1;
static int const kCountOperationHintIndex = 0;
static int const kBinaryOperationSmiHintIndex = 1;
static int const kUnaryOperationHintIndex = 0;
static constexpr int kBinaryOperationHintIndex = 1;
static constexpr int kBinaryOperationSmiHintIndex = 1;
static constexpr int kCompareOperationHintIndex = 1;
static constexpr int kCountOperationHintIndex = 0;
static constexpr int kUnaryOperationHintIndex = 0;
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder);
};
......@@ -2761,14 +2758,6 @@ BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint(
return broker()->GetFeedbackForBinaryOperation(source);
}
// Helper function to create compare operation hint from the recorded type
// feedback.
CompareOperationHint BytecodeGraphBuilder::GetCompareOperationHint() {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(1);
FeedbackSource source(feedback_vector(), slot);
return broker()->GetFeedbackForCompareOperation(source);
}
// Helper function to create for-in mode from the recorded type feedback.
ForInMode BytecodeGraphBuilder::GetForInMode(int operand_index) {
FeedbackSlot slot = bytecode_iterator().GetSlotOperand(operand_index);
......@@ -3014,27 +3003,39 @@ void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) {
}
void BytecodeGraphBuilder::VisitTestEqual() {
BuildCompareOp(javascript()->Equal(GetCompareOperationHint()));
FeedbackSource feedback = CreateFeedbackSource(
bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex).ToInt());
BuildCompareOp(javascript()->Equal(feedback));
}
void BytecodeGraphBuilder::VisitTestEqualStrict() {
BuildCompareOp(javascript()->StrictEqual(GetCompareOperationHint()));
FeedbackSource feedback = CreateFeedbackSource(
bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex).ToInt());
BuildCompareOp(javascript()->StrictEqual(feedback));
}
void BytecodeGraphBuilder::VisitTestLessThan() {
BuildCompareOp(javascript()->LessThan(GetCompareOperationHint()));
FeedbackSource feedback = CreateFeedbackSource(
bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex).ToInt());
BuildCompareOp(javascript()->LessThan(feedback));
}
void BytecodeGraphBuilder::VisitTestGreaterThan() {
BuildCompareOp(javascript()->GreaterThan(GetCompareOperationHint()));
FeedbackSource feedback = CreateFeedbackSource(
bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex).ToInt());
BuildCompareOp(javascript()->GreaterThan(feedback));
}
void BytecodeGraphBuilder::VisitTestLessThanOrEqual() {
BuildCompareOp(javascript()->LessThanOrEqual(GetCompareOperationHint()));
FeedbackSource feedback = CreateFeedbackSource(
bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex).ToInt());
BuildCompareOp(javascript()->LessThanOrEqual(feedback));
}
void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() {
BuildCompareOp(javascript()->GreaterThanOrEqual(GetCompareOperationHint()));
FeedbackSource feedback = CreateFeedbackSource(
bytecode_iterator().GetSlotOperand(kCompareOperationHintIndex).ToInt());
BuildCompareOp(javascript()->GreaterThanOrEqual(feedback));
}
void BytecodeGraphBuilder::VisitTestReferenceEqual() {
......
......@@ -73,12 +73,7 @@ REPLACE_STUB_CALL(BitwiseXor)
REPLACE_STUB_CALL(ShiftLeft)
REPLACE_STUB_CALL(ShiftRight)
REPLACE_STUB_CALL(ShiftRightLogical)
REPLACE_STUB_CALL(LessThan)
REPLACE_STUB_CALL(LessThanOrEqual)
REPLACE_STUB_CALL(GreaterThan)
REPLACE_STUB_CALL(GreaterThanOrEqual)
REPLACE_STUB_CALL(HasProperty)
REPLACE_STUB_CALL(Equal)
REPLACE_STUB_CALL(ToLength)
REPLACE_STUB_CALL(ToNumber)
REPLACE_STUB_CALL(ToNumberConvertBigInt)
......@@ -136,18 +131,13 @@ void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
}
void JSGenericLowering::LowerJSStrictEqual(Node* node) {
// The === operator doesn't need the current context.
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
Callable callable = Builtins::CallableFor(isolate(), Builtins::kStrictEqual);
node->RemoveInput(4); // control
ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
Operator::kEliminatable);
}
void JSGenericLowering::ReplaceUnaryOpWithBuiltinCall(
Node* node, Builtins::Name builtin_without_feedback,
Builtins::Name builtin_with_feedback) {
DCHECK(node->opcode() == IrOpcode::kJSBitwiseNot ||
node->opcode() == IrOpcode::kJSDecrement ||
node->opcode() == IrOpcode::kJSIncrement ||
node->opcode() == IrOpcode::kJSNegate);
const FeedbackParameter& p = FeedbackParameterOf(node->op());
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
......@@ -181,6 +171,65 @@ DEF_UNARY_LOWERING(Increment)
DEF_UNARY_LOWERING(Negate)
#undef DEF_UNARY_LOWERING
void JSGenericLowering::ReplaceCompareOpWithBuiltinCall(
Node* node, Builtins::Name builtin_without_feedback,
Builtins::Name builtin_with_feedback) {
DCHECK(node->opcode() == IrOpcode::kJSEqual ||
node->opcode() == IrOpcode::kJSGreaterThan ||
node->opcode() == IrOpcode::kJSGreaterThanOrEqual ||
node->opcode() == IrOpcode::kJSLessThan ||
node->opcode() == IrOpcode::kJSLessThanOrEqual);
Builtins::Name builtin_id;
const FeedbackParameter& p = FeedbackParameterOf(node->op());
if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
node->InsertInput(zone(), 2, slot);
node->InsertInput(zone(), 3, feedback_vector);
builtin_id = builtin_with_feedback;
} else {
builtin_id = builtin_without_feedback;
}
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
Callable callable = Builtins::CallableFor(isolate(), builtin_id);
ReplaceWithStubCall(node, callable, flags);
}
#define DEF_COMPARE_LOWERING(Name) \
void JSGenericLowering::LowerJS##Name(Node* node) { \
ReplaceCompareOpWithBuiltinCall(node, Builtins::k##Name, \
Builtins::k##Name##_WithFeedback); \
}
DEF_COMPARE_LOWERING(Equal)
DEF_COMPARE_LOWERING(GreaterThan)
DEF_COMPARE_LOWERING(GreaterThanOrEqual)
DEF_COMPARE_LOWERING(LessThan)
DEF_COMPARE_LOWERING(LessThanOrEqual)
#undef DEF_COMPARE_LOWERING
void JSGenericLowering::LowerJSStrictEqual(Node* node) {
// The === operator doesn't need the current context.
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
node->RemoveInput(4); // control
Builtins::Name builtin_id;
const FeedbackParameter& p = FeedbackParameterOf(node->op());
if (CollectFeedbackInGenericLowering() && p.feedback().IsValid()) {
Node* feedback_vector = jsgraph()->HeapConstant(p.feedback().vector);
Node* slot = jsgraph()->UintPtrConstant(p.feedback().slot.ToInt());
node->InsertInput(zone(), 2, slot);
node->InsertInput(zone(), 3, feedback_vector);
builtin_id = Builtins::kStrictEqual_WithFeedback;
} else {
builtin_id = Builtins::kStrictEqual;
}
Callable callable = Builtins::CallableFor(isolate(), builtin_id);
ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags,
Operator::kEliminatable);
}
namespace {
bool ShouldUseMegamorphicLoadBuiltin(FeedbackSource const& source,
JSHeapBroker* broker) {
......
......@@ -45,6 +45,9 @@ class JSGenericLowering final : public AdvancedReducer {
void ReplaceUnaryOpWithBuiltinCall(Node* node,
Builtins::Name builtin_without_feedback,
Builtins::Name builtin_with_feedback);
void ReplaceCompareOpWithBuiltinCall(Node* node,
Builtins::Name builtin_without_feedback,
Builtins::Name builtin_with_feedback);
Zone* zone() const;
Isolate* isolate() const;
......
......@@ -85,6 +85,28 @@ Reduction JSHeapCopyReducer::Reduce(Node* node) {
}
break;
}
case IrOpcode::kJSBitwiseNot:
case IrOpcode::kJSDecrement:
case IrOpcode::kJSIncrement:
case IrOpcode::kJSNegate: {
FeedbackParameter const& p = FeedbackParameterOf(node->op());
if (p.feedback().IsValid()) {
broker()->ProcessFeedbackForBinaryOperation(p.feedback());
}
break;
}
case IrOpcode::kJSEqual:
case IrOpcode::kJSGreaterThan:
case IrOpcode::kJSGreaterThanOrEqual:
case IrOpcode::kJSLessThan:
case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSStrictEqual: {
FeedbackParameter const& p = FeedbackParameterOf(node->op());
if (p.feedback().IsValid()) {
broker()->ProcessFeedbackForCompareOperation(p.feedback());
}
break;
}
case IrOpcode::kJSCreateFunctionContext: {
CreateFunctionContextParameters const& p =
CreateFunctionContextParametersOf(node->op());
......
......@@ -226,14 +226,20 @@ std::ostream& operator<<(std::ostream& os, FeedbackParameter const& p) {
}
FeedbackParameter const& FeedbackParameterOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSDecrement ||
op->opcode() == IrOpcode::kJSBitwiseNot ||
DCHECK(op->opcode() == IrOpcode::kJSBitwiseNot ||
op->opcode() == IrOpcode::kJSCreateEmptyLiteralArray ||
op->opcode() == IrOpcode::kJSDecrement ||
op->opcode() == IrOpcode::kJSEqual ||
op->opcode() == IrOpcode::kJSGreaterThan ||
op->opcode() == IrOpcode::kJSGreaterThanOrEqual ||
op->opcode() == IrOpcode::kJSIncrement ||
op->opcode() == IrOpcode::kJSInstanceOf ||
op->opcode() == IrOpcode::kJSLessThan ||
op->opcode() == IrOpcode::kJSLessThanOrEqual ||
op->opcode() == IrOpcode::kJSNegate ||
op->opcode() == IrOpcode::kJSStoreDataPropertyInLiteral ||
op->opcode() == IrOpcode::kJSStoreInArrayLiteral);
op->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
op->opcode() == IrOpcode::kJSStrictEqual);
return OpParameter<FeedbackParameter>(op);
}
......@@ -641,16 +647,6 @@ BinaryOperationHint BinaryOperationHintOf(const Operator* op) {
return OpParameter<BinaryOperationHint>(op);
}
CompareOperationHint CompareOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kJSEqual ||
op->opcode() == IrOpcode::kJSStrictEqual ||
op->opcode() == IrOpcode::kJSLessThan ||
op->opcode() == IrOpcode::kJSGreaterThan ||
op->opcode() == IrOpcode::kJSLessThanOrEqual ||
op->opcode() == IrOpcode::kJSGreaterThanOrEqual);
return OpParameter<CompareOperationHint>(op);
}
#define CACHED_OP_LIST(V) \
V(BitwiseOr, Operator::kNoProperties, 2, 1) \
V(BitwiseXor, Operator::kNoProperties, 2, 1) \
......@@ -707,16 +703,14 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
#define BINARY_OP_LIST(V) V(Add)
#define COMPARE_EQUAL_OP_LIST(V) \
V(Equal, Operator::kNoProperties) \
#define COMPARE_OP_LIST(V) \
V(Equal, Operator::kNoProperties) \
V(GreaterThan, Operator::kNoProperties) \
V(GreaterThanOrEqual, Operator::kNoProperties) \
V(LessThan, Operator::kNoProperties) \
V(LessThanOrEqual, Operator::kNoProperties) \
V(StrictEqual, Operator::kPure)
#define COMPARE_OP_LIST(V) \
V(LessThan, Operator::kNoProperties) \
V(GreaterThan, Operator::kNoProperties) \
V(LessThanOrEqual, Operator::kNoProperties) \
V(GreaterThanOrEqual, Operator::kNoProperties)
struct JSOperatorGlobalCache final {
#define CACHED_OP(Name, properties, value_input_count, value_output_count) \
struct Name##Operator final : public Operator { \
......@@ -753,38 +747,6 @@ struct JSOperatorGlobalCache final {
Name##Operator<BinaryOperationHint::kAny> k##Name##AnyOperator;
BINARY_OP_LIST(BINARY_OP)
#undef BINARY_OP
#define COMPARE_OP(Name, properties) \
template <CompareOperationHint kHint> \
struct Name##Operator final : public Operator1<CompareOperationHint> { \
Name##Operator() \
: Operator1<CompareOperationHint>( \
IrOpcode::kJS##Name, properties, "JS" #Name, 2, 1, 1, 1, 1, \
Operator::ZeroIfNoThrow(properties), kHint) {} \
}; \
Name##Operator<CompareOperationHint::kNone> k##Name##NoneOperator; \
Name##Operator<CompareOperationHint::kSignedSmall> \
k##Name##SignedSmallOperator; \
Name##Operator<CompareOperationHint::kNumber> k##Name##NumberOperator; \
Name##Operator<CompareOperationHint::kNumberOrOddball> \
k##Name##NumberOrOddballOperator; \
Name##Operator<CompareOperationHint::kInternalizedString> \
k##Name##InternalizedStringOperator; \
Name##Operator<CompareOperationHint::kString> k##Name##StringOperator; \
Name##Operator<CompareOperationHint::kSymbol> k##Name##SymbolOperator; \
Name##Operator<CompareOperationHint::kBigInt> k##Name##BigIntOperator; \
Name##Operator<CompareOperationHint::kReceiver> k##Name##ReceiverOperator; \
Name##Operator<CompareOperationHint::kReceiverOrNullOrUndefined> \
k##Name##ReceiverOrNullOrUndefinedOperator; \
Name##Operator<CompareOperationHint::kAny> k##Name##AnyOperator;
COMPARE_OP_LIST(COMPARE_OP)
COMPARE_EQUAL_OP_LIST(COMPARE_OP)
// Only equality provides an additional operator for NumberOrBoolean.
EqualOperator<CompareOperationHint::kNumberOrBoolean>
kEqualNumberOrBooleanOperator;
StrictEqualOperator<CompareOperationHint::kNumberOrBoolean>
kStrictEqualNumberOrBooleanOperator;
#undef COMPARE_OP
};
namespace {
......@@ -839,75 +801,16 @@ BINARY_OP_LIST(BINARY_OP)
UNARY_OP_LIST(UNARY_OP)
#undef UNARY_OP
#define COMPARE_OP(Name, ...) \
const Operator* JSOperatorBuilder::Name(CompareOperationHint hint) { \
switch (hint) { \
case CompareOperationHint::kNone: \
return &cache_.k##Name##NoneOperator; \
case CompareOperationHint::kSignedSmall: \
return &cache_.k##Name##SignedSmallOperator; \
case CompareOperationHint::kNumber: \
return &cache_.k##Name##NumberOperator; \
case CompareOperationHint::kNumberOrBoolean: \
/* Not supported for operations other than equality */ \
UNIMPLEMENTED(); \
case CompareOperationHint::kNumberOrOddball: \
return &cache_.k##Name##NumberOrOddballOperator; \
case CompareOperationHint::kInternalizedString: \
return &cache_.k##Name##InternalizedStringOperator; \
case CompareOperationHint::kString: \
return &cache_.k##Name##StringOperator; \
case CompareOperationHint::kSymbol: \
return &cache_.k##Name##SymbolOperator; \
case CompareOperationHint::kBigInt: \
return &cache_.k##Name##BigIntOperator; \
case CompareOperationHint::kReceiver: \
return &cache_.k##Name##ReceiverOperator; \
case CompareOperationHint::kReceiverOrNullOrUndefined: \
return &cache_.k##Name##ReceiverOrNullOrUndefinedOperator; \
case CompareOperationHint::kAny: \
return &cache_.k##Name##AnyOperator; \
} \
UNREACHABLE(); \
return nullptr; \
#define COMPARE_OP(Name, Properties) \
const Operator* JSOperatorBuilder::Name(FeedbackSource const& feedback) { \
FeedbackParameter parameters(feedback); \
return new (zone()) Operator1<FeedbackParameter>( \
IrOpcode::kJS##Name, Properties, "JS" #Name, 2, 1, 1, 1, 1, \
Operator::ZeroIfNoThrow(Properties), parameters); \
}
COMPARE_OP_LIST(COMPARE_OP)
#undef COMPARE_OP
#define COMPARE_EQUAL_OP(Name, ...) \
const Operator* JSOperatorBuilder::Name(CompareOperationHint hint) { \
switch (hint) { \
case CompareOperationHint::kNone: \
return &cache_.k##Name##NoneOperator; \
case CompareOperationHint::kSignedSmall: \
return &cache_.k##Name##SignedSmallOperator; \
case CompareOperationHint::kNumber: \
return &cache_.k##Name##NumberOperator; \
case CompareOperationHint::kNumberOrBoolean: \
return &cache_.k##Name##NumberOrBooleanOperator; \
case CompareOperationHint::kNumberOrOddball: \
return &cache_.k##Name##NumberOrOddballOperator; \
case CompareOperationHint::kInternalizedString: \
return &cache_.k##Name##InternalizedStringOperator; \
case CompareOperationHint::kString: \
return &cache_.k##Name##StringOperator; \
case CompareOperationHint::kSymbol: \
return &cache_.k##Name##SymbolOperator; \
case CompareOperationHint::kBigInt: \
return &cache_.k##Name##BigIntOperator; \
case CompareOperationHint::kReceiver: \
return &cache_.k##Name##ReceiverOperator; \
case CompareOperationHint::kReceiverOrNullOrUndefined: \
return &cache_.k##Name##ReceiverOrNullOrUndefinedOperator; \
case CompareOperationHint::kAny: \
return &cache_.k##Name##AnyOperator; \
} \
UNREACHABLE(); \
return nullptr; \
}
COMPARE_EQUAL_OP_LIST(COMPARE_EQUAL_OP)
#undef COMPARE_EQUAL_OP
const Operator* JSOperatorBuilder::StoreDataPropertyInLiteral(
const FeedbackSource& feedback) {
FeedbackParameter parameters(feedback);
......@@ -1483,7 +1386,6 @@ Handle<ScopeInfo> ScopeInfoOf(const Operator* op) {
#undef BINARY_OP_LIST
#undef CACHED_OP_LIST
#undef COMPARE_OP_LIST
#undef COMPARE_EQUAL_OP_LIST
} // namespace compiler
} // namespace internal
......
......@@ -762,8 +762,6 @@ ForInMode ForInModeOf(Operator const* op) V8_WARN_UNUSED_RESULT;
BinaryOperationHint BinaryOperationHintOf(const Operator* op);
CompareOperationHint CompareOperationHintOf(const Operator* op);
int RegisterCountOf(Operator const* op) V8_WARN_UNUSED_RESULT;
int GeneratorStoreValueCountOf(const Operator* op) V8_WARN_UNUSED_RESULT;
......@@ -779,12 +777,12 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
public:
explicit JSOperatorBuilder(Zone* zone);
const Operator* Equal(CompareOperationHint hint);
const Operator* StrictEqual(CompareOperationHint hint);
const Operator* LessThan(CompareOperationHint hint);
const Operator* GreaterThan(CompareOperationHint hint);
const Operator* LessThanOrEqual(CompareOperationHint hint);
const Operator* GreaterThanOrEqual(CompareOperationHint hint);
const Operator* Equal(FeedbackSource const& feedback);
const Operator* StrictEqual(FeedbackSource const& feedback);
const Operator* LessThan(FeedbackSource const& feedback);
const Operator* GreaterThan(FeedbackSource const& feedback);
const Operator* LessThanOrEqual(FeedbackSource const& feedback);
const Operator* GreaterThanOrEqual(FeedbackSource const& feedback);
const Operator* BitwiseOr();
const Operator* BitwiseXor();
......
......@@ -38,7 +38,7 @@ class JSBinopReduction final {
bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
switch (CompareOperationHintOf(node_->op())) {
switch (GetCompareOperationHint(node_)) {
case CompareOperationHint::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
......@@ -66,36 +66,34 @@ class JSBinopReduction final {
bool IsInternalizedStringCompareOperation() {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
return (CompareOperationHintOf(node_->op()) ==
return (GetCompareOperationHint(node_) ==
CompareOperationHint::kInternalizedString) &&
BothInputsMaybe(Type::InternalizedString());
}
bool IsReceiverCompareOperation() {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
return (CompareOperationHintOf(node_->op()) ==
return (GetCompareOperationHint(node_) ==
CompareOperationHint::kReceiver) &&
BothInputsMaybe(Type::Receiver());
}
bool IsReceiverOrNullOrUndefinedCompareOperation() {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
return (CompareOperationHintOf(node_->op()) ==
return (GetCompareOperationHint(node_) ==
CompareOperationHint::kReceiverOrNullOrUndefined) &&
BothInputsMaybe(Type::ReceiverOrNullOrUndefined());
}
bool IsStringCompareOperation() {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
return (CompareOperationHintOf(node_->op()) ==
CompareOperationHint::kString) &&
return (GetCompareOperationHint(node_) == CompareOperationHint::kString) &&
BothInputsMaybe(Type::String());
}
bool IsSymbolCompareOperation() {
DCHECK_EQ(1, node_->op()->EffectOutputCount());
return (CompareOperationHintOf(node_->op()) ==
CompareOperationHint::kSymbol) &&
return (GetCompareOperationHint(node_) == CompareOperationHint::kSymbol) &&
BothInputsMaybe(Type::Symbol());
}
......@@ -417,6 +415,11 @@ class JSBinopReduction final {
return node;
}
CompareOperationHint GetCompareOperationHint(Node* node) const {
const FeedbackParameter& p = FeedbackParameterOf(node->op());
return lowering_->broker()->GetFeedbackForCompareOperation(p.feedback());
}
void update_effect(Node* effect) {
NodeProperties::ReplaceEffectInput(node_, effect);
}
......
......@@ -326,6 +326,25 @@ Handle<FeedbackVector> FeedbackVector::New(
return result;
}
// static
Handle<FeedbackVector> FeedbackVector::NewWithOneCompareSlotForTesting(
Zone* zone, Isolate* isolate) {
FeedbackVectorSpec one_slot(zone);
one_slot.AddCompareICSlot();
Handle<FeedbackMetadata> metadata = FeedbackMetadata::New(isolate, &one_slot);
Handle<SharedFunctionInfo> shared =
isolate->factory()->NewSharedFunctionInfoForBuiltin(
isolate->factory()->empty_string(), Builtins::kIllegal);
// Set the raw feedback metadata to circumvent checks that we are not
// overwriting existing metadata.
shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
ClosureFeedbackCellArray::New(isolate, shared);
return FeedbackVector::New(isolate, shared, closure_feedback_cell_array);
}
// static
void FeedbackVector::AddToVectorsForProfilingTools(
Isolate* isolate, Handle<FeedbackVector> vector) {
......
......@@ -264,6 +264,9 @@ class FeedbackVector : public HeapObject {
Isolate* isolate, Handle<SharedFunctionInfo> shared,
Handle<ClosureFeedbackCellArray> closure_feedback_cell_array);
V8_EXPORT_PRIVATE static Handle<FeedbackVector>
NewWithOneCompareSlotForTesting(Zone* zone, Isolate* isolate);
#define DEFINE_SLOT_KIND_PREDICATE(Name) \
bool Name(FeedbackSlot slot) const { return Name##Kind(GetKind(slot)); }
......
......@@ -5,6 +5,7 @@
#include "src/codegen/tick-counter.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/js-heap-copy-reducer.h"
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-properties.h"
......@@ -55,7 +56,6 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Typer typer;
Node* context_node;
BinaryOperationHint const binop_hints = BinaryOperationHint::kAny;
CompareOperationHint const compare_hints = CompareOperationHint::kAny;
Node* Parameter(Type t, int32_t index = 0) {
Node* n = graph.NewNode(common.Parameter(index), graph.start());
......@@ -89,6 +89,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
}
Node* reduce(Node* node) {
JSHeapCopyReducer heap_copy_reducer(&js_heap_broker);
CHECK(!heap_copy_reducer.Reduce(node).Changed());
JSGraph jsgraph(main_isolate(), &graph, &common, &javascript, &simplified,
&machine);
// TODO(titzer): mock the GraphReducer here for better unit testing.
......@@ -564,18 +566,28 @@ TEST(JSToString_replacement) {
}
}
namespace {
FeedbackSource FeedbackSourceWithOneCompareSlot(JSTypedLoweringTester* R) {
return FeedbackSource{FeedbackVector::NewWithOneCompareSlotForTesting(
R->main_zone(), R->main_isolate()),
FeedbackSlot{0}};
}
} // namespace
TEST(StringComparison) {
JSTypedLoweringTester R;
FeedbackSource feedback_source = FeedbackSourceWithOneCompareSlot(&R);
const Operator* ops[] = {
R.javascript.LessThan(CompareOperationHint::kAny),
R.simplified.StringLessThan(),
R.javascript.LessThanOrEqual(CompareOperationHint::kAny),
R.simplified.StringLessThanOrEqual(),
R.javascript.GreaterThan(CompareOperationHint::kAny),
R.simplified.StringLessThan(),
R.javascript.GreaterThanOrEqual(CompareOperationHint::kAny),
R.simplified.StringLessThanOrEqual()};
const Operator* ops[] = {R.javascript.LessThan(feedback_source),
R.simplified.StringLessThan(),
R.javascript.LessThanOrEqual(feedback_source),
R.simplified.StringLessThanOrEqual(),
R.javascript.GreaterThan(feedback_source),
R.simplified.StringLessThan(),
R.javascript.GreaterThanOrEqual(feedback_source),
R.simplified.StringLessThanOrEqual()};
for (size_t i = 0; i < arraysize(kStringTypes); i++) {
Node* p0 = R.Parameter(kStringTypes[i], 0);
......@@ -615,16 +627,16 @@ static void CheckIsConvertedToNumber(Node* val, Node* converted) {
TEST(NumberComparison) {
JSTypedLoweringTester R;
FeedbackSource feedback_source = FeedbackSourceWithOneCompareSlot(&R);
const Operator* ops[] = {
R.javascript.LessThan(CompareOperationHint::kAny),
R.simplified.NumberLessThan(),
R.javascript.LessThanOrEqual(CompareOperationHint::kAny),
R.simplified.NumberLessThanOrEqual(),
R.javascript.GreaterThan(CompareOperationHint::kAny),
R.simplified.NumberLessThan(),
R.javascript.GreaterThanOrEqual(CompareOperationHint::kAny),
R.simplified.NumberLessThanOrEqual()};
const Operator* ops[] = {R.javascript.LessThan(feedback_source),
R.simplified.NumberLessThan(),
R.javascript.LessThanOrEqual(feedback_source),
R.simplified.NumberLessThanOrEqual(),
R.javascript.GreaterThan(feedback_source),
R.simplified.NumberLessThan(),
R.javascript.GreaterThanOrEqual(feedback_source),
R.simplified.NumberLessThanOrEqual()};
Node* const p0 = R.Parameter(Type::Number(), 0);
Node* const p1 = R.Parameter(Type::Number(), 1);
......@@ -648,6 +660,7 @@ TEST(NumberComparison) {
TEST(MixedComparison1) {
JSTypedLoweringTester R;
FeedbackSource feedback_source = FeedbackSourceWithOneCompareSlot(&R);
Type types[] = {Type::Number(), Type::String(),
Type::Union(Type::Number(), Type::String(), R.main_zone())};
......@@ -658,8 +671,7 @@ TEST(MixedComparison1) {
for (size_t j = 0; j < arraysize(types); j++) {
Node* p1 = R.Parameter(types[j], 1);
{
const Operator* less_than =
R.javascript.LessThan(CompareOperationHint::kAny);
const Operator* less_than = R.javascript.LessThan(feedback_source);
Node* cmp = R.Binop(less_than, p0, p1);
Node* r = R.reduce(cmp);
if (types[i].Is(Type::String()) && types[j].Is(Type::String())) {
......@@ -801,14 +813,14 @@ class BinopEffectsTester {
// Helper function for strict and non-strict equality reductions.
void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l,
Node* r, IrOpcode::Value expected) {
FeedbackSource feedback_source = FeedbackSourceWithOneCompareSlot(R);
for (int j = 0; j < 2; j++) {
Node* p0 = j == 0 ? l : r;
Node* p1 = j == 1 ? l : r;
{
const Operator* op =
strict ? R->javascript.StrictEqual(CompareOperationHint::kAny)
: R->javascript.Equal(CompareOperationHint::kAny);
const Operator* op = strict ? R->javascript.StrictEqual(feedback_source)
: R->javascript.Equal(feedback_source);
Node* eq = R->Binop(op, p0, p1);
Node* r = R->reduce(eq);
R->CheckBinop(expected, r);
......@@ -870,9 +882,10 @@ TEST(StringEquality) {
TEST(RemovePureNumberBinopEffects) {
JSTypedLoweringTester R;
FeedbackSource feedback_source = FeedbackSourceWithOneCompareSlot(&R);
const Operator* ops[] = {
R.javascript.Equal(R.compare_hints),
R.javascript.Equal(feedback_source),
R.simplified.NumberEqual(),
R.javascript.Add(R.binop_hints),
R.simplified.NumberAdd(),
......@@ -884,9 +897,9 @@ TEST(RemovePureNumberBinopEffects) {
R.simplified.NumberDivide(),
R.javascript.Modulus(),
R.simplified.NumberModulus(),
R.javascript.LessThan(R.compare_hints),
R.javascript.LessThan(feedback_source),
R.simplified.NumberLessThan(),
R.javascript.LessThanOrEqual(R.compare_hints),
R.javascript.LessThanOrEqual(feedback_source),
R.simplified.NumberLessThanOrEqual(),
};
......@@ -1040,6 +1053,7 @@ TEST(Int32AddNarrowing) {
TEST(Int32Comparisons) {
JSTypedLoweringTester R;
FeedbackSource feedback_source = FeedbackSourceWithOneCompareSlot(&R);
struct Entry {
const Operator* js_op;
......@@ -1047,13 +1061,13 @@ TEST(Int32Comparisons) {
bool commute;
};
Entry ops[] = {{R.javascript.LessThan(R.compare_hints),
Entry ops[] = {{R.javascript.LessThan(feedback_source),
R.simplified.NumberLessThan(), false},
{R.javascript.LessThanOrEqual(R.compare_hints),
{R.javascript.LessThanOrEqual(feedback_source),
R.simplified.NumberLessThanOrEqual(), false},
{R.javascript.GreaterThan(R.compare_hints),
{R.javascript.GreaterThan(feedback_source),
R.simplified.NumberLessThan(), true},
{R.javascript.GreaterThanOrEqual(R.compare_hints),
{R.javascript.GreaterThanOrEqual(feedback_source),
R.simplified.NumberLessThanOrEqual(), true}};
for (size_t o = 0; o < arraysize(ops); o++) {
......
......@@ -164,6 +164,16 @@ TEST_F(JSTypedLoweringTest, JSToStringWithBoolean) {
// -----------------------------------------------------------------------------
// JSStrictEqual
namespace {
FeedbackSource FeedbackSourceWithOneCompareSlot(JSTypedLoweringTest* R) {
return FeedbackSource{
FeedbackVector::NewWithOneCompareSlotForTesting(R->zone(), R->isolate()),
FeedbackSlot{0}};
}
} // namespace
TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
Node* const the_hole = HeapConstant(factory()->the_hole_value());
Node* const context = UndefinedConstant();
......@@ -171,9 +181,9 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
Node* const control = graph()->start();
TRACED_FOREACH(Type, type, kJSTypes) {
Node* const lhs = Parameter(type);
Reduction r = Reduce(
graph()->NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
lhs, the_hole, context, effect, control));
Reduction r = Reduce(graph()->NewNode(
javascript()->StrictEqual(FeedbackSourceWithOneCompareSlot(this)), lhs,
the_hole, context, effect, control));
ASSERT_FALSE(r.Changed());
}
}
......@@ -185,9 +195,9 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
Node* const context = Parameter(Type::Any(), 2);
Node* const effect = graph()->start();
Node* const control = graph()->start();
Reduction r = Reduce(
graph()->NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
lhs, rhs, context, effect, control));
Reduction r = Reduce(graph()->NewNode(
javascript()->StrictEqual(FeedbackSourceWithOneCompareSlot(this)), lhs,
rhs, context, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsReferenceEqual(lhs, rhs));
}
......
......@@ -362,9 +362,20 @@ TEST_F(TyperTest, TypeJSShiftRight) {
TestBinaryBitOp(javascript_.ShiftRight(), shift_right);
}
namespace {
FeedbackSource FeedbackSourceWithOneCompareSlot(TyperTest* R) {
return FeedbackSource{
FeedbackVector::NewWithOneCompareSlotForTesting(R->zone(), R->isolate()),
FeedbackSlot{0}};
}
} // namespace
TEST_F(TyperTest, TypeJSLessThan) {
TestBinaryCompareOp(javascript_.LessThan(CompareOperationHint::kAny),
std::less<double>());
TestBinaryCompareOp(
javascript_.LessThan(FeedbackSourceWithOneCompareSlot(this)),
std::less<double>());
}
TEST_F(TyperTest, TypeNumberLessThan) {
......@@ -378,8 +389,9 @@ TEST_F(TyperTest, TypeSpeculativeNumberLessThan) {
}
TEST_F(TyperTest, TypeJSLessThanOrEqual) {
TestBinaryCompareOp(javascript_.LessThanOrEqual(CompareOperationHint::kAny),
std::less_equal<double>());
TestBinaryCompareOp(
javascript_.LessThanOrEqual(FeedbackSourceWithOneCompareSlot(this)),
std::less_equal<double>());
}
TEST_F(TyperTest, TypeNumberLessThanOrEqual) {
......@@ -394,19 +406,20 @@ TEST_F(TyperTest, TypeSpeculativeNumberLessThanOrEqual) {
}
TEST_F(TyperTest, TypeJSGreaterThan) {
TestBinaryCompareOp(javascript_.GreaterThan(CompareOperationHint::kAny),
std::greater<double>());
TestBinaryCompareOp(
javascript_.GreaterThan(FeedbackSourceWithOneCompareSlot(this)),
std::greater<double>());
}
TEST_F(TyperTest, TypeJSGreaterThanOrEqual) {
TestBinaryCompareOp(
javascript_.GreaterThanOrEqual(CompareOperationHint::kAny),
javascript_.GreaterThanOrEqual(FeedbackSourceWithOneCompareSlot(this)),
std::greater_equal<double>());
}
TEST_F(TyperTest, TypeJSEqual) {
TestBinaryCompareOp(javascript_.Equal(CompareOperationHint::kAny),
TestBinaryCompareOp(javascript_.Equal(FeedbackSourceWithOneCompareSlot(this)),
std::equal_to<double>());
}
......@@ -422,8 +435,9 @@ TEST_F(TyperTest, TypeSpeculativeNumberEqual) {
// For numbers there's no difference between strict and non-strict equality.
TEST_F(TyperTest, TypeJSStrictEqual) {
TestBinaryCompareOp(javascript_.StrictEqual(CompareOperationHint::kAny),
std::equal_to<double>());
TestBinaryCompareOp(
javascript_.StrictEqual(FeedbackSourceWithOneCompareSlot(this)),
std::equal_to<double>());
}
//------------------------------------------------------------------------------
......@@ -442,9 +456,10 @@ TEST_MONOTONICITY(ToString)
#undef TEST_MONOTONICITY
// JS BINOPs with CompareOperationHint
#define TEST_MONOTONICITY(name) \
TEST_F(TyperTest, Monotonicity_##name) { \
TestBinaryMonotonicity(javascript_.name(CompareOperationHint::kAny)); \
#define TEST_MONOTONICITY(name) \
TEST_F(TyperTest, Monotonicity_##name) { \
TestBinaryMonotonicity( \
javascript_.name(FeedbackSourceWithOneCompareSlot(this))); \
}
TEST_MONOTONICITY(Equal)
TEST_MONOTONICITY(StrictEqual)
......
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