Commit 5af6017d authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add binary operation hints for javascript operators.

This is the initial support for binary operation hints on javascript
binary operators, i.e. JSAdd, JSSubtract and so on. The hints are
extracted from the fullcodegen code object before graph building and the
AstGraphBuilder puts those hints on the operators if available.

R=jarin@chromium.org
BUG=v8:4583
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#32443}
parent da566d89
...@@ -886,6 +886,10 @@ source_set("v8_base") { ...@@ -886,6 +886,10 @@ source_set("v8_base") {
"src/compiler/state-values-utils.h", "src/compiler/state-values-utils.h",
"src/compiler/tail-call-optimization.cc", "src/compiler/tail-call-optimization.cc",
"src/compiler/tail-call-optimization.h", "src/compiler/tail-call-optimization.h",
"src/compiler/type-hint-analyzer.cc",
"src/compiler/type-hint-analyzer.h",
"src/compiler/type-hints.cc",
"src/compiler/type-hints.h",
"src/compiler/typer.cc", "src/compiler/typer.cc",
"src/compiler/typer.h", "src/compiler/typer.h",
"src/compiler/value-numbering-reducer.cc", "src/compiler/value-numbering-reducer.cc",
......
...@@ -1457,9 +1457,9 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() { ...@@ -1457,9 +1457,9 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
HValue* left = GetParameter(BinaryOpICStub::kLeft); HValue* left = GetParameter(BinaryOpICStub::kLeft);
HValue* right = GetParameter(BinaryOpICStub::kRight); HValue* right = GetParameter(BinaryOpICStub::kRight);
Type* left_type = state.GetLeftType(zone()); Type* left_type = state.GetLeftType();
Type* right_type = state.GetRightType(zone()); Type* right_type = state.GetRightType();
Type* result_type = state.GetResultType(zone()); Type* result_type = state.GetResultType();
DCHECK(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) && DCHECK(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) &&
(state.HasSideEffects() || !result_type->Is(Type::None()))); (state.HasSideEffects() || !result_type->Is(Type::None())));
...@@ -1538,9 +1538,9 @@ HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() { ...@@ -1538,9 +1538,9 @@ HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() {
HValue* left = GetParameter(BinaryOpWithAllocationSiteStub::kLeft); HValue* left = GetParameter(BinaryOpWithAllocationSiteStub::kLeft);
HValue* right = GetParameter(BinaryOpWithAllocationSiteStub::kRight); HValue* right = GetParameter(BinaryOpWithAllocationSiteStub::kRight);
Type* left_type = state.GetLeftType(zone()); Type* left_type = state.GetLeftType();
Type* right_type = state.GetRightType(zone()); Type* right_type = state.GetRightType();
Type* result_type = state.GetResultType(zone()); Type* result_type = state.GetResultType();
HAllocationMode allocation_mode(allocation_site); HAllocationMode allocation_mode(allocation_site);
return BuildBinaryOperation(state.op(), left, right, left_type, right_type, return BuildBinaryOperation(state.op(), left, right, left_type, right_type,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h" #include "src/compiler/operator-properties.h"
#include "src/compiler/state-values-utils.h" #include "src/compiler/state-values-utils.h"
#include "src/compiler/type-hint-analyzer.h"
#include "src/parsing/parser.h" #include "src/parsing/parser.h"
namespace v8 { namespace v8 {
...@@ -428,7 +429,8 @@ class AstGraphBuilder::FrameStateBeforeAndAfter { ...@@ -428,7 +429,8 @@ class AstGraphBuilder::FrameStateBeforeAndAfter {
AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
JSGraph* jsgraph, LoopAssignmentAnalysis* loop) JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
TypeHintAnalysis* type_hint_analysis)
: isolate_(info->isolate()), : isolate_(info->isolate()),
local_zone_(local_zone), local_zone_(local_zone),
info_(info), info_(info),
...@@ -444,6 +446,7 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, ...@@ -444,6 +446,7 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
input_buffer_(nullptr), input_buffer_(nullptr),
exit_controls_(local_zone), exit_controls_(local_zone),
loop_assignment_analysis_(loop), loop_assignment_analysis_(loop),
type_hint_analysis_(type_hint_analysis),
state_values_cache_(jsgraph), state_values_cache_(jsgraph),
liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()), liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
local_zone), local_zone),
...@@ -2166,7 +2169,9 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) { ...@@ -2166,7 +2169,9 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
FrameStateBeforeAndAfter states(this, expr->value()->id()); FrameStateBeforeAndAfter states(this, expr->value()->id());
Node* right = environment()->Pop(); Node* right = environment()->Pop();
Node* left = environment()->Pop(); Node* left = environment()->Pop();
value = BuildBinaryOp(left, right, expr->binary_op()); value =
BuildBinaryOp(left, right, expr->binary_op(),
expr->binary_operation()->BinaryOperationFeedbackId());
states.AddToNode(value, expr->binary_operation()->id(), states.AddToNode(value, expr->binary_operation()->id(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push());
} }
...@@ -2725,9 +2730,10 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { ...@@ -2725,9 +2730,10 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
// Create node to perform +1/-1 operation. // Create node to perform +1/-1 operation.
Node* value; Node* value;
{ {
// TODO(bmeurer): Cleanup this feedback/bailout mess!
FrameStateBeforeAndAfter states(this, BailoutId::None()); FrameStateBeforeAndAfter states(this, BailoutId::None());
value = value = BuildBinaryOp(old_value, jsgraph()->OneConstant(),
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op()); expr->binary_op(), TypeFeedbackId::None());
// This should never deoptimize outside strong mode because otherwise we // This should never deoptimize outside strong mode because otherwise we
// have converted to number before. // have converted to number before.
states.AddToNode(value, is_strong(language_mode()) ? expr->ToNumberId() states.AddToNode(value, is_strong(language_mode()) ? expr->ToNumberId()
...@@ -2810,7 +2816,8 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { ...@@ -2810,7 +2816,8 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
FrameStateBeforeAndAfter states(this, expr->right()->id()); FrameStateBeforeAndAfter states(this, expr->right()->id());
Node* right = environment()->Pop(); Node* right = environment()->Pop();
Node* left = environment()->Pop(); Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->op()); Node* value = BuildBinaryOp(left, right, expr->op(),
expr->BinaryOperationFeedbackId());
states.AddToNode(value, expr->id(), ast_context()->GetStateCombine()); states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value); ast_context()->ProduceValue(value);
} }
...@@ -3781,41 +3788,47 @@ Node* AstGraphBuilder::BuildThrow(Node* exception_value) { ...@@ -3781,41 +3788,47 @@ Node* AstGraphBuilder::BuildThrow(Node* exception_value) {
} }
Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) { Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op,
TypeFeedbackId feedback_id) {
const Operator* js_op; const Operator* js_op;
BinaryOperationHints hints;
if (!type_hint_analysis_ ||
!type_hint_analysis_->GetBinaryOperationHints(feedback_id, &hints)) {
hints = BinaryOperationHints::Any();
}
switch (op) { switch (op) {
case Token::BIT_OR: case Token::BIT_OR:
js_op = javascript()->BitwiseOr(language_mode()); js_op = javascript()->BitwiseOr(language_mode(), hints);
break; break;
case Token::BIT_AND: case Token::BIT_AND:
js_op = javascript()->BitwiseAnd(language_mode()); js_op = javascript()->BitwiseAnd(language_mode(), hints);
break; break;
case Token::BIT_XOR: case Token::BIT_XOR:
js_op = javascript()->BitwiseXor(language_mode()); js_op = javascript()->BitwiseXor(language_mode(), hints);
break; break;
case Token::SHL: case Token::SHL:
js_op = javascript()->ShiftLeft(language_mode()); js_op = javascript()->ShiftLeft(language_mode(), hints);
break; break;
case Token::SAR: case Token::SAR:
js_op = javascript()->ShiftRight(language_mode()); js_op = javascript()->ShiftRight(language_mode(), hints);
break; break;
case Token::SHR: case Token::SHR:
js_op = javascript()->ShiftRightLogical(language_mode()); js_op = javascript()->ShiftRightLogical(language_mode(), hints);
break; break;
case Token::ADD: case Token::ADD:
js_op = javascript()->Add(language_mode()); js_op = javascript()->Add(language_mode(), hints);
break; break;
case Token::SUB: case Token::SUB:
js_op = javascript()->Subtract(language_mode()); js_op = javascript()->Subtract(language_mode(), hints);
break; break;
case Token::MUL: case Token::MUL:
js_op = javascript()->Multiply(language_mode()); js_op = javascript()->Multiply(language_mode(), hints);
break; break;
case Token::DIV: case Token::DIV:
js_op = javascript()->Divide(language_mode()); js_op = javascript()->Divide(language_mode(), hints);
break; break;
case Token::MOD: case Token::MOD:
js_op = javascript()->Modulus(language_mode()); js_op = javascript()->Modulus(language_mode(), hints);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -13,15 +13,20 @@ ...@@ -13,15 +13,20 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Forward declarations.
class BitVector; class BitVector;
namespace compiler { namespace compiler {
// Forward declarations.
class ControlBuilder; class ControlBuilder;
class Graph; class Graph;
class LoopAssignmentAnalysis; class LoopAssignmentAnalysis;
class LoopBuilder; class LoopBuilder;
class Node; class Node;
class TypeHintAnalysis;
// The AstGraphBuilder produces a high-level IR graph, based on an // The AstGraphBuilder produces a high-level IR graph, based on an
// underlying AST. The produced graph can either be compiled into a // underlying AST. The produced graph can either be compiled into a
...@@ -30,7 +35,8 @@ class Node; ...@@ -30,7 +35,8 @@ class Node;
class AstGraphBuilder : public AstVisitor { class AstGraphBuilder : public AstVisitor {
public: public:
AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph, AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph,
LoopAssignmentAnalysis* loop_assignment = NULL); LoopAssignmentAnalysis* loop_assignment = nullptr,
TypeHintAnalysis* type_hint_analysis = nullptr);
// Creates a graph by visiting the entire AST. // Creates a graph by visiting the entire AST.
bool CreateGraph(bool stack_check = true); bool CreateGraph(bool stack_check = true);
...@@ -106,6 +112,9 @@ class AstGraphBuilder : public AstVisitor { ...@@ -106,6 +112,9 @@ class AstGraphBuilder : public AstVisitor {
// Result of loop assignment analysis performed before graph creation. // Result of loop assignment analysis performed before graph creation.
LoopAssignmentAnalysis* loop_assignment_analysis_; LoopAssignmentAnalysis* loop_assignment_analysis_;
// Result of type hint analysis performed before graph creation.
TypeHintAnalysis* type_hint_analysis_;
// Cache for StateValues nodes for frame states. // Cache for StateValues nodes for frame states.
StateValuesCache state_values_cache_; StateValuesCache state_values_cache_;
...@@ -344,7 +353,8 @@ class AstGraphBuilder : public AstVisitor { ...@@ -344,7 +353,8 @@ class AstGraphBuilder : public AstVisitor {
Node* BuildThrow(Node* exception_value); Node* BuildThrow(Node* exception_value);
// Builders for binary operations. // Builders for binary operations.
Node* BuildBinaryOp(Node* left, Node* right, Token::Value op); Node* BuildBinaryOp(Node* left, Node* right, Token::Value op,
TypeFeedbackId feedback_id);
// Process arguments to a call by popping {arity} elements off the operand // Process arguments to a call by popping {arity} elements off the operand
// stack and build a call node using the given call operator. // stack and build a call node using the given call operator.
......
...@@ -832,67 +832,79 @@ void BytecodeGraphBuilder::BuildBinaryOp( ...@@ -832,67 +832,79 @@ void BytecodeGraphBuilder::BuildBinaryOp(
void BytecodeGraphBuilder::VisitAdd( void BytecodeGraphBuilder::VisitAdd(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Add(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Add(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitSub( void BytecodeGraphBuilder::VisitSub(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Subtract(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Subtract(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitMul( void BytecodeGraphBuilder::VisitMul(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Multiply(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Multiply(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitDiv( void BytecodeGraphBuilder::VisitDiv(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Divide(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Divide(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitMod( void BytecodeGraphBuilder::VisitMod(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Modulus(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Modulus(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitBitwiseOr( void BytecodeGraphBuilder::VisitBitwiseOr(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->BitwiseOr(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->BitwiseOr(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitBitwiseXor( void BytecodeGraphBuilder::VisitBitwiseXor(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->BitwiseXor(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->BitwiseXor(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitBitwiseAnd( void BytecodeGraphBuilder::VisitBitwiseAnd(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->BitwiseAnd(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->BitwiseAnd(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitShiftLeft( void BytecodeGraphBuilder::VisitShiftLeft(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftLeft(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->ShiftLeft(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitShiftRight( void BytecodeGraphBuilder::VisitShiftRight(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftRight(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->ShiftRight(language_mode(), hints), iterator);
} }
void BytecodeGraphBuilder::VisitShiftRightLogical( void BytecodeGraphBuilder::VisitShiftRightLogical(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftRightLogical(language_mode()), iterator); BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->ShiftRightLogical(language_mode(), hints),
iterator);
} }
......
...@@ -63,12 +63,14 @@ Reduction JSGenericLowering::Reduce(Node* node) { ...@@ -63,12 +63,14 @@ Reduction JSGenericLowering::Reduce(Node* node) {
} }
#define REPLACE_BINARY_OP_IC_CALL(op, token) \ #define REPLACE_BINARY_OP_IC_CALL(Op, token) \
void JSGenericLowering::Lower##op(Node* node) { \ void JSGenericLowering::Lower##Op(Node* node) { \
BinaryOperationParameters const& p = \
BinaryOperationParametersOf(node->op()); \
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); \ CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); \
ReplaceWithStubCall(node, CodeFactory::BinaryOpIC( \ ReplaceWithStubCall(node, \
isolate(), token, \ CodeFactory::BinaryOpIC(isolate(), token, \
strength(OpParameter<LanguageMode>(node))), \ strength(p.language_mode())), \
CallDescriptor::kPatchableCallSiteWithNop | flags); \ CallDescriptor::kPatchableCallSiteWithNop | flags); \
} }
REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR) REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
......
...@@ -63,6 +63,46 @@ std::ostream& operator<<(std::ostream& os, TailCallMode mode) { ...@@ -63,6 +63,46 @@ std::ostream& operator<<(std::ostream& os, TailCallMode mode) {
} }
bool operator==(BinaryOperationParameters const& lhs,
BinaryOperationParameters const& rhs) {
return lhs.language_mode() == rhs.language_mode() &&
lhs.hints() == rhs.hints();
}
bool operator!=(BinaryOperationParameters const& lhs,
BinaryOperationParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(BinaryOperationParameters const& p) {
return base::hash_combine(p.language_mode(), p.hints());
}
std::ostream& operator<<(std::ostream& os, BinaryOperationParameters const& p) {
return os << p.language_mode() << ", " << p.hints();
}
BinaryOperationParameters const& BinaryOperationParametersOf(
Operator const* op) {
DCHECK(op->opcode() == IrOpcode::kJSBitwiseOr ||
op->opcode() == IrOpcode::kJSBitwiseXor ||
op->opcode() == IrOpcode::kJSBitwiseAnd ||
op->opcode() == IrOpcode::kJSShiftLeft ||
op->opcode() == IrOpcode::kJSShiftRight ||
op->opcode() == IrOpcode::kJSShiftRightLogical ||
op->opcode() == IrOpcode::kJSAdd ||
op->opcode() == IrOpcode::kJSSubtract ||
op->opcode() == IrOpcode::kJSMultiply ||
op->opcode() == IrOpcode::kJSDivide ||
op->opcode() == IrOpcode::kJSModulus);
return OpParameter<BinaryOperationParameters>(op);
}
bool operator==(CallConstructParameters const& lhs, bool operator==(CallConstructParameters const& lhs,
CallConstructParameters const& rhs) { CallConstructParameters const& rhs) {
return lhs.arity() == rhs.arity() && lhs.feedback() == rhs.feedback(); return lhs.arity() == rhs.arity() && lhs.feedback() == rhs.feedback();
...@@ -472,18 +512,7 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) { ...@@ -472,18 +512,7 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) {
V(LessThan, Operator::kNoProperties, 2, 1) \ V(LessThan, Operator::kNoProperties, 2, 1) \
V(GreaterThan, Operator::kNoProperties, 2, 1) \ V(GreaterThan, Operator::kNoProperties, 2, 1) \
V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \ V(LessThanOrEqual, Operator::kNoProperties, 2, 1) \
V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1) \ V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1)
V(BitwiseOr, Operator::kNoProperties, 2, 1) \
V(BitwiseXor, Operator::kNoProperties, 2, 1) \
V(BitwiseAnd, Operator::kNoProperties, 2, 1) \
V(ShiftLeft, Operator::kNoProperties, 2, 1) \
V(ShiftRight, Operator::kNoProperties, 2, 1) \
V(ShiftRightLogical, Operator::kNoProperties, 2, 1) \
V(Add, Operator::kNoProperties, 2, 1) \
V(Subtract, Operator::kNoProperties, 2, 1) \
V(Multiply, Operator::kNoProperties, 2, 1) \
V(Divide, Operator::kNoProperties, 2, 1) \
V(Modulus, Operator::kNoProperties, 2, 1)
struct JSOperatorGlobalCache final { struct JSOperatorGlobalCache final {
...@@ -557,6 +586,138 @@ CACHED_OP_LIST_WITH_LANGUAGE_MODE(CACHED_WITH_LANGUAGE_MODE) ...@@ -557,6 +586,138 @@ CACHED_OP_LIST_WITH_LANGUAGE_MODE(CACHED_WITH_LANGUAGE_MODE)
#undef CACHED_WITH_LANGUAGE_MODE #undef CACHED_WITH_LANGUAGE_MODE
const Operator* JSOperatorBuilder::BitwiseOr(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSBitwiseOr, Operator::kNoProperties, // opcode
"JSBitwiseOr", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::BitwiseXor(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSBitwiseXor, Operator::kNoProperties, // opcode
"JSBitwiseXor", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::BitwiseAnd(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSBitwiseAnd, Operator::kNoProperties, // opcode
"JSBitwiseAnd", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::ShiftLeft(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSShiftLeft, Operator::kNoProperties, // opcode
"JSShiftLeft", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::ShiftRight(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSShiftRight, Operator::kNoProperties, // opcode
"JSShiftRight", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::ShiftRightLogical(
LanguageMode language_mode, BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSShiftRightLogical, Operator::kNoProperties, // opcode
"JSShiftRightLogical", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::Add(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSAdd, Operator::kNoProperties, // opcode
"JSAdd", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::Subtract(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSSubtract, Operator::kNoProperties, // opcode
"JSSubtract", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::Multiply(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSMultiply, Operator::kNoProperties, // opcode
"JSMultiply", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::Divide(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSDivide, Operator::kNoProperties, // opcode
"JSDivide", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::Modulus(LanguageMode language_mode,
BinaryOperationHints hints) {
// TODO(turbofan): Cache most important versions of this operator.
BinaryOperationParameters parameters(language_mode, hints);
return new (zone()) Operator1<BinaryOperationParameters>( //--
IrOpcode::kJSModulus, Operator::kNoProperties, // opcode
"JSModulus", // name
2, 1, 1, 1, 1, 2, // inputs/outputs
parameters); // parameter
}
const Operator* JSOperatorBuilder::CallFunction( const Operator* JSOperatorBuilder::CallFunction(
size_t arity, LanguageMode language_mode, VectorSlotPair const& feedback, size_t arity, LanguageMode language_mode, VectorSlotPair const& feedback,
ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) { ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_JS_OPERATOR_H_ #ifndef V8_COMPILER_JS_OPERATOR_H_
#define V8_COMPILER_JS_OPERATOR_H_ #define V8_COMPILER_JS_OPERATOR_H_
#include "src/compiler/type-hints.h"
#include "src/runtime/runtime.h" #include "src/runtime/runtime.h"
namespace v8 { namespace v8 {
...@@ -54,6 +55,34 @@ size_t hash_value(TailCallMode); ...@@ -54,6 +55,34 @@ size_t hash_value(TailCallMode);
std::ostream& operator<<(std::ostream&, TailCallMode); std::ostream& operator<<(std::ostream&, TailCallMode);
// Defines the language mode and hints for a JavaScript binary operations.
// This is used as parameter by JSAdd, JSSubtract, etc. operators.
class BinaryOperationParameters final {
public:
BinaryOperationParameters(LanguageMode language_mode,
BinaryOperationHints hints)
: language_mode_(language_mode), hints_(hints) {}
LanguageMode language_mode() const { return language_mode_; }
BinaryOperationHints hints() const { return hints_; }
private:
LanguageMode const language_mode_;
BinaryOperationHints const hints_;
};
bool operator==(BinaryOperationParameters const&,
BinaryOperationParameters const&);
bool operator!=(BinaryOperationParameters const&,
BinaryOperationParameters const&);
size_t hash_value(BinaryOperationParameters const&);
std::ostream& operator<<(std::ostream&, BinaryOperationParameters const&);
BinaryOperationParameters const& BinaryOperationParametersOf(Operator const*);
// Defines the arity and the feedback for a JavaScript constructor call. This is // Defines the arity and the feedback for a JavaScript constructor call. This is
// used as a parameter by JSCallConstruct operators. // used as a parameter by JSCallConstruct operators.
class CallConstructParameters final { class CallConstructParameters final {
...@@ -446,17 +475,27 @@ class JSOperatorBuilder final : public ZoneObject { ...@@ -446,17 +475,27 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* GreaterThan(LanguageMode language_mode); const Operator* GreaterThan(LanguageMode language_mode);
const Operator* LessThanOrEqual(LanguageMode language_mode); const Operator* LessThanOrEqual(LanguageMode language_mode);
const Operator* GreaterThanOrEqual(LanguageMode language_mode); const Operator* GreaterThanOrEqual(LanguageMode language_mode);
const Operator* BitwiseOr(LanguageMode language_mode); const Operator* BitwiseOr(LanguageMode language_mode,
const Operator* BitwiseXor(LanguageMode language_mode); BinaryOperationHints hints);
const Operator* BitwiseAnd(LanguageMode language_mode); const Operator* BitwiseXor(LanguageMode language_mode,
const Operator* ShiftLeft(LanguageMode language_mode); BinaryOperationHints hints);
const Operator* ShiftRight(LanguageMode language_mode); const Operator* BitwiseAnd(LanguageMode language_mode,
const Operator* ShiftRightLogical(LanguageMode language_mode); BinaryOperationHints hints);
const Operator* Add(LanguageMode language_mode); const Operator* ShiftLeft(LanguageMode language_mode,
const Operator* Subtract(LanguageMode language_mode); BinaryOperationHints hints);
const Operator* Multiply(LanguageMode language_mode); const Operator* ShiftRight(LanguageMode language_mode,
const Operator* Divide(LanguageMode language_mode); BinaryOperationHints hints);
const Operator* Modulus(LanguageMode language_mode); const Operator* ShiftRightLogical(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* Add(LanguageMode language_mode, BinaryOperationHints hints);
const Operator* Subtract(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* Multiply(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* Divide(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* Modulus(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* UnaryNot(); const Operator* UnaryNot();
const Operator* ToBoolean(); const Operator* ToBoolean();
......
...@@ -218,7 +218,16 @@ class JSBinopReduction final { ...@@ -218,7 +218,16 @@ class JSBinopReduction final {
return ChangeToPureOperator(op, false, type); return ChangeToPureOperator(op, false, type);
} }
bool IsStrong() { return is_strong(OpParameter<LanguageMode>(node_)); } // TODO(turbofan): Strong mode should be killed soonish!
bool IsStrong() const {
if (node_->opcode() == IrOpcode::kJSLessThan ||
node_->opcode() == IrOpcode::kJSLessThanOrEqual ||
node_->opcode() == IrOpcode::kJSGreaterThan ||
node_->opcode() == IrOpcode::kJSGreaterThanOrEqual) {
return is_strong(OpParameter<LanguageMode>(node_));
}
return is_strong(BinaryOperationParametersOf(node_->op()).language_mode());
}
bool LeftInputIs(Type* t) { return left_type()->Is(t); } bool LeftInputIs(Type* t) { return left_type()->Is(t); }
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include "src/compiler/simplified-operator-reducer.h" #include "src/compiler/simplified-operator-reducer.h"
#include "src/compiler/tail-call-optimization.h" #include "src/compiler/tail-call-optimization.h"
#include "src/compiler/type-hint-analyzer.h"
#include "src/compiler/typer.h" #include "src/compiler/typer.h"
#include "src/compiler/value-numbering-reducer.h" #include "src/compiler/value-numbering-reducer.h"
#include "src/compiler/verifier.h" #include "src/compiler/verifier.h"
...@@ -210,6 +211,12 @@ class PipelineData { ...@@ -210,6 +211,12 @@ class PipelineData {
loop_assignment_ = loop_assignment; loop_assignment_ = loop_assignment;
} }
TypeHintAnalysis* type_hint_analysis() const { return type_hint_analysis_; }
void set_type_hint_analysis(TypeHintAnalysis* type_hint_analysis) {
DCHECK_NULL(type_hint_analysis_);
type_hint_analysis_ = type_hint_analysis;
}
Schedule* schedule() const { return schedule_; } Schedule* schedule() const { return schedule_; }
void set_schedule(Schedule* schedule) { void set_schedule(Schedule* schedule) {
DCHECK(!schedule_); DCHECK(!schedule_);
...@@ -234,6 +241,7 @@ class PipelineData { ...@@ -234,6 +241,7 @@ class PipelineData {
graph_zone_ = nullptr; graph_zone_ = nullptr;
graph_ = nullptr; graph_ = nullptr;
loop_assignment_ = nullptr; loop_assignment_ = nullptr;
type_hint_analysis_ = nullptr;
simplified_ = nullptr; simplified_ = nullptr;
machine_ = nullptr; machine_ = nullptr;
common_ = nullptr; common_ = nullptr;
...@@ -301,6 +309,7 @@ class PipelineData { ...@@ -301,6 +309,7 @@ class PipelineData {
// TODO(dcarney): make this into a ZoneObject. // TODO(dcarney): make this into a ZoneObject.
base::SmartPointer<SourcePositionTable> source_positions_; base::SmartPointer<SourcePositionTable> source_positions_;
LoopAssignmentAnalysis* loop_assignment_; LoopAssignmentAnalysis* loop_assignment_;
TypeHintAnalysis* type_hint_analysis_ = nullptr;
SimplifiedOperatorBuilder* simplified_; SimplifiedOperatorBuilder* simplified_;
MachineOperatorBuilder* machine_; MachineOperatorBuilder* machine_;
CommonOperatorBuilder* common_; CommonOperatorBuilder* common_;
...@@ -363,8 +372,10 @@ class AstGraphBuilderWithPositions final : public AstGraphBuilder { ...@@ -363,8 +372,10 @@ class AstGraphBuilderWithPositions final : public AstGraphBuilder {
AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info, AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info,
JSGraph* jsgraph, JSGraph* jsgraph,
LoopAssignmentAnalysis* loop_assignment, LoopAssignmentAnalysis* loop_assignment,
TypeHintAnalysis* type_hint_analysis,
SourcePositionTable* source_positions) SourcePositionTable* source_positions)
: AstGraphBuilder(local_zone, info, jsgraph, loop_assignment), : AstGraphBuilder(local_zone, info, jsgraph, loop_assignment,
type_hint_analysis),
source_positions_(source_positions), source_positions_(source_positions),
start_position_(info->shared_info()->start_position()) {} start_position_(info->shared_info()->start_position()) {}
...@@ -476,6 +487,18 @@ struct LoopAssignmentAnalysisPhase { ...@@ -476,6 +487,18 @@ struct LoopAssignmentAnalysisPhase {
}; };
struct TypeHintAnalysisPhase {
static const char* phase_name() { return "type hint analysis"; }
void Run(PipelineData* data, Zone* temp_zone) {
TypeHintAnalyzer analyzer(data->graph_zone());
Handle<Code> code(data->info()->shared_info()->code(), data->isolate());
TypeHintAnalysis* type_hint_analysis = analyzer.Analyze(code);
data->set_type_hint_analysis(type_hint_analysis);
}
};
struct GraphBuilderPhase { struct GraphBuilderPhase {
static const char* phase_name() { return "graph builder"; } static const char* phase_name() { return "graph builder"; }
...@@ -490,7 +513,7 @@ struct GraphBuilderPhase { ...@@ -490,7 +513,7 @@ struct GraphBuilderPhase {
} else { } else {
AstGraphBuilderWithPositions graph_builder( AstGraphBuilderWithPositions graph_builder(
temp_zone, data->info(), data->jsgraph(), data->loop_assignment(), temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
data->source_positions()); data->type_hint_analysis(), data->source_positions());
succeeded = graph_builder.CreateGraph(stack_check); succeeded = graph_builder.CreateGraph(stack_check);
} }
...@@ -1074,6 +1097,10 @@ Handle<Code> Pipeline::GenerateCode() { ...@@ -1074,6 +1097,10 @@ Handle<Code> Pipeline::GenerateCode() {
Run<LoopAssignmentAnalysisPhase>(); Run<LoopAssignmentAnalysisPhase>();
} }
if (info()->is_typing_enabled()) {
Run<TypeHintAnalysisPhase>();
}
Run<GraphBuilderPhase>(); Run<GraphBuilderPhase>();
if (data.compilation_failed()) return Handle<Code>::null(); if (data.compilation_failed()) return Handle<Code>::null();
RunPrintAndVerify("Initial untyped", true); RunPrintAndVerify("Initial untyped", true);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/type-hint-analyzer.h"
#include "src/assembler.h"
#include "src/compiler/type-hints.h"
#include "src/ic/ic-state.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
// TODO(bmeurer): This detour via types is ugly.
BinaryOperationHints::Hint ToHint(Type* type) {
if (type->Is(Type::None())) return BinaryOperationHints::kNone;
if (type->Is(Type::SignedSmall())) return BinaryOperationHints::kSignedSmall;
if (type->Is(Type::Signed32())) return BinaryOperationHints::kSigned32;
if (type->Is(Type::Number())) return BinaryOperationHints::kNumber;
if (type->Is(Type::String())) return BinaryOperationHints::kString;
return BinaryOperationHints::kAny;
}
} // namespace
bool TypeHintAnalysis::GetBinaryOperationHints(
TypeFeedbackId id, BinaryOperationHints* hints) const {
auto i = infos_.find(id);
if (i == infos_.end()) return false;
Handle<Code> code = i->second;
DCHECK_EQ(Code::BINARY_OP_IC, code->kind());
BinaryOpICState state(code->GetIsolate(), code->extra_ic_state());
*hints = BinaryOperationHints(ToHint(state.GetLeftType()),
ToHint(state.GetRightType()),
ToHint(state.GetResultType()));
return true;
}
TypeHintAnalysis* TypeHintAnalyzer::Analyze(Handle<Code> code) {
DisallowHeapAllocation no_gc;
TypeHintAnalysis::Infos infos(zone());
Isolate* const isolate = code->GetIsolate();
int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
for (RelocIterator it(*code, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
switch (target->kind()) {
case Code::BINARY_OP_IC: {
// Add this feedback to the {infos}.
TypeFeedbackId id(static_cast<unsigned>(rinfo->data()));
infos.insert(std::make_pair(id, handle(target, isolate)));
break;
}
default:
// Ignore the remaining code objects.
break;
}
}
return new (zone()) TypeHintAnalysis(infos);
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_TYPE_HINT_ANALYZER_H_
#define V8_COMPILER_TYPE_HINT_ANALYZER_H_
#include "src/handles.h"
#include "src/utils.h"
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
namespace compiler {
// Forward declarations.
class BinaryOperationHints;
// The result of analyzing type hints.
class TypeHintAnalysis final : public ZoneObject {
public:
typedef ZoneMap<TypeFeedbackId, Handle<Code>> Infos;
explicit TypeHintAnalysis(Infos const& infos) : infos_(infos) {}
bool GetBinaryOperationHints(TypeFeedbackId id,
BinaryOperationHints* hints) const;
private:
Infos const infos_;
};
// The class that performs type hint analysis on the fullcodegen code object.
class TypeHintAnalyzer final {
public:
explicit TypeHintAnalyzer(Zone* zone) : zone_(zone) {}
TypeHintAnalysis* Analyze(Handle<Code> code);
private:
Zone* zone() const { return zone_; }
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(TypeHintAnalyzer);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_TYPE_HINT_ANALYZER_H_
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/type-hints.h"
namespace v8 {
namespace internal {
namespace compiler {
std::ostream& operator<<(std::ostream& os, BinaryOperationHints::Hint hint) {
switch (hint) {
case BinaryOperationHints::kNone:
return os << "None";
case BinaryOperationHints::kSignedSmall:
return os << "SignedSmall";
case BinaryOperationHints::kSigned32:
return os << "Signed32";
case BinaryOperationHints::kNumber:
return os << "Number";
case BinaryOperationHints::kString:
return os << "String";
case BinaryOperationHints::kAny:
return os << "Any";
}
UNREACHABLE();
return os;
}
std::ostream& operator<<(std::ostream& os, BinaryOperationHints hints) {
return os << hints.left() << "*" << hints.right() << "->" << hints.result();
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_COMPILER_TYPE_HINTS_H_
#define V8_COMPILER_TYPE_HINTS_H_
#include "src/utils.h"
namespace v8 {
namespace internal {
namespace compiler {
// Type hints for an binary operation.
class BinaryOperationHints final {
public:
enum Hint { kNone, kSignedSmall, kSigned32, kNumber, kString, kAny };
BinaryOperationHints() : BinaryOperationHints(kNone, kNone, kNone) {}
BinaryOperationHints(Hint left, Hint right, Hint result)
: bit_field_(LeftField::encode(left) | RightField::encode(right) |
ResultField::encode(result)) {}
static BinaryOperationHints Any() {
return BinaryOperationHints(kAny, kAny, kAny);
}
Hint left() const { return LeftField::decode(bit_field_); }
Hint right() const { return RightField::decode(bit_field_); }
Hint result() const { return ResultField::decode(bit_field_); }
bool operator==(BinaryOperationHints const& that) const {
return this->bit_field_ == that.bit_field_;
}
bool operator!=(BinaryOperationHints const& that) const {
return !(*this == that);
}
friend size_t hash_value(BinaryOperationHints const& hints) {
return hints.bit_field_;
}
private:
typedef BitField<Hint, 0, 3> LeftField;
typedef BitField<Hint, 3, 3> RightField;
typedef BitField<Hint, 6, 3> ResultField;
uint32_t bit_field_;
};
std::ostream& operator<<(std::ostream&, BinaryOperationHints::Hint);
std::ostream& operator<<(std::ostream&, BinaryOperationHints);
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_TYPE_HINTS_H_
...@@ -191,17 +191,17 @@ void BinaryOpICState::GenerateAheadOfTime( ...@@ -191,17 +191,17 @@ void BinaryOpICState::GenerateAheadOfTime(
} }
Type* BinaryOpICState::GetResultType(Zone* zone) const { Type* BinaryOpICState::GetResultType() const {
Kind result_kind = result_kind_; Kind result_kind = result_kind_;
if (HasSideEffects()) { if (HasSideEffects()) {
result_kind = NONE; result_kind = NONE;
} else if (result_kind == GENERIC && op_ == Token::ADD) { } else if (result_kind == GENERIC && op_ == Token::ADD) {
return Type::Union(Type::Number(zone), Type::String(zone), zone); return Type::NumberOrString();
} else if (result_kind == NUMBER && op_ == Token::SHR) { } else if (result_kind == NUMBER && op_ == Token::SHR) {
return Type::Unsigned32(zone); return Type::Unsigned32();
} }
DCHECK_NE(GENERIC, result_kind); DCHECK_NE(GENERIC, result_kind);
return KindToType(result_kind, zone); return KindToType(result_kind);
} }
...@@ -320,20 +320,20 @@ const char* BinaryOpICState::KindToString(Kind kind) { ...@@ -320,20 +320,20 @@ const char* BinaryOpICState::KindToString(Kind kind) {
// static // static
Type* BinaryOpICState::KindToType(Kind kind, Zone* zone) { Type* BinaryOpICState::KindToType(Kind kind) {
switch (kind) { switch (kind) {
case NONE: case NONE:
return Type::None(zone); return Type::None();
case SMI: case SMI:
return Type::SignedSmall(zone); return Type::SignedSmall();
case INT32: case INT32:
return Type::Signed32(zone); return Type::Signed32();
case NUMBER: case NUMBER:
return Type::Number(zone); return Type::Number();
case STRING: case STRING:
return Type::String(zone); return Type::String();
case GENERIC: case GENERIC:
return Type::Any(zone); return Type::Any();
} }
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
......
...@@ -120,9 +120,9 @@ class BinaryOpICState final BASE_EMBEDDED { ...@@ -120,9 +120,9 @@ class BinaryOpICState final BASE_EMBEDDED {
Token::Value op() const { return op_; } Token::Value op() const { return op_; }
Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, zone); } Type* GetLeftType() const { return KindToType(left_kind_); }
Type* GetRightType(Zone* zone) const { return KindToType(right_kind_, zone); } Type* GetRightType() const { return KindToType(right_kind_); }
Type* GetResultType(Zone* zone) const; Type* GetResultType() const;
void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result); void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);
...@@ -136,7 +136,7 @@ class BinaryOpICState final BASE_EMBEDDED { ...@@ -136,7 +136,7 @@ class BinaryOpICState final BASE_EMBEDDED {
Kind UpdateKind(Handle<Object> object, Kind kind) const; Kind UpdateKind(Handle<Object> object, Kind kind) const;
static const char* KindToString(Kind kind); static const char* KindToString(Kind kind);
static Type* KindToType(Kind kind, Zone* zone); static Type* KindToType(Kind kind);
static bool KindMaybeSmi(Kind kind) { static bool KindMaybeSmi(Kind kind) {
return (kind >= SMI && kind <= NUMBER) || kind == GENERIC; return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
} }
......
...@@ -245,9 +245,9 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, ...@@ -245,9 +245,9 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
BinaryOpICState state(isolate(), code->extra_ic_state()); BinaryOpICState state(isolate(), code->extra_ic_state());
DCHECK_EQ(op, state.op()); DCHECK_EQ(op, state.op());
*left = state.GetLeftType(zone()); *left = state.GetLeftType();
*right = state.GetRightType(zone()); *right = state.GetRightType();
*result = state.GetResultType(zone()); *result = state.GetResultType();
*fixed_right_arg = state.fixed_right_arg(); *fixed_right_arg = state.fixed_right_arg();
AllocationSite* first_allocation_site = code->FindFirstAllocationSite(); AllocationSite* first_allocation_site = code->FindFirstAllocationSite();
...@@ -265,7 +265,7 @@ Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) { ...@@ -265,7 +265,7 @@ Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) {
Handle<Code> code = Handle<Code>::cast(object); Handle<Code> code = Handle<Code>::cast(object);
DCHECK_EQ(Code::BINARY_OP_IC, code->kind()); DCHECK_EQ(Code::BINARY_OP_IC, code->kind());
BinaryOpICState state(isolate(), code->extra_ic_state()); BinaryOpICState state(isolate(), code->extra_ic_state());
return state.GetLeftType(zone()); return state.GetLeftType();
} }
......
...@@ -1041,6 +1041,13 @@ class TypeFeedbackId { ...@@ -1041,6 +1041,13 @@ class TypeFeedbackId {
int id_; int id_;
}; };
inline bool operator<(TypeFeedbackId lhs, TypeFeedbackId rhs) {
return lhs.ToInt() < rhs.ToInt();
}
inline bool operator>(TypeFeedbackId lhs, TypeFeedbackId rhs) {
return lhs.ToInt() > rhs.ToInt();
}
class FeedbackVectorSlot { class FeedbackVectorSlot {
public: public:
......
...@@ -228,8 +228,8 @@ TEST(SpecializeToContext) { ...@@ -228,8 +228,8 @@ TEST(SpecializeToContext) {
t.graph()->NewNode(t.simplified()->ChangeTaggedToInt32(), other_load); t.graph()->NewNode(t.simplified()->ChangeTaggedToInt32(), other_load);
Node* add = t.graph()->NewNode( Node* add = t.graph()->NewNode(
t.javascript()->Add(LanguageMode::SLOPPY), value_use, other_use, t.javascript()->Add(LanguageMode::SLOPPY, BinaryOperationHints::Any()),
param_context, t.jsgraph()->EmptyFrameState(), value_use, other_use, param_context, t.jsgraph()->EmptyFrameState(),
t.jsgraph()->EmptyFrameState(), other_load, start); t.jsgraph()->EmptyFrameState(), other_load, start);
Node* ret = Node* ret =
......
...@@ -63,6 +63,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -63,6 +63,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Graph graph; Graph graph;
Typer typer; Typer typer;
Node* context_node; Node* context_node;
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* Parameter(Type* t, int32_t index = 0) { Node* Parameter(Type* t, int32_t index = 0) {
Node* n = graph.NewNode(common.Parameter(index), graph.start()); Node* n = graph.NewNode(common.Parameter(index), graph.start());
...@@ -268,7 +269,8 @@ TEST_WITH_STRONG(AddNumber1) { ...@@ -268,7 +269,8 @@ TEST_WITH_STRONG(AddNumber1) {
for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
Node* p0 = R.Parameter(kNumberTypes[i], 0); Node* p0 = R.Parameter(kNumberTypes[i], 0);
Node* p1 = R.Parameter(kNumberTypes[i], 1); Node* p1 = R.Parameter(kNumberTypes[i], 1);
Node* add = R.Binop(R.javascript.Add(language_mode), p0, p1); Node* add = R.Binop(
R.javascript.Add(language_mode, BinaryOperationHints::Any()), p0, p1);
Node* r = R.reduce(add); Node* r = R.reduce(add);
R.CheckBinop(IrOpcode::kNumberAdd, r); R.CheckBinop(IrOpcode::kNumberAdd, r);
...@@ -281,11 +283,16 @@ TEST_WITH_STRONG(AddNumber1) { ...@@ -281,11 +283,16 @@ TEST_WITH_STRONG(AddNumber1) {
TEST_WITH_STRONG(NumberBinops) { TEST_WITH_STRONG(NumberBinops) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Add(language_mode), R.simplified.NumberAdd(), R.javascript.Add(language_mode, R.hints),
R.javascript.Subtract(language_mode), R.simplified.NumberSubtract(), R.simplified.NumberAdd(),
R.javascript.Multiply(language_mode), R.simplified.NumberMultiply(), R.javascript.Subtract(language_mode, R.hints),
R.javascript.Divide(language_mode), R.simplified.NumberDivide(), R.simplified.NumberSubtract(),
R.javascript.Modulus(language_mode), R.simplified.NumberModulus(), R.javascript.Multiply(language_mode, R.hints),
R.simplified.NumberMultiply(),
R.javascript.Divide(language_mode, R.hints),
R.simplified.NumberDivide(),
R.javascript.Modulus(language_mode, R.hints),
R.simplified.NumberModulus(),
}; };
for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
...@@ -328,11 +335,11 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { ...@@ -328,11 +335,11 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester {
explicit JSBitwiseShiftTypedLoweringTester(LanguageMode language_mode) explicit JSBitwiseShiftTypedLoweringTester(LanguageMode language_mode)
: JSTypedLoweringTester(), language_mode_(language_mode) { : JSTypedLoweringTester(), language_mode_(language_mode) {
int i = 0; int i = 0;
set(i++, javascript.ShiftLeft(language_mode_), true); set(i++, javascript.ShiftLeft(language_mode_, hints), true);
set(i++, simplified.NumberShiftLeft(), false); set(i++, simplified.NumberShiftLeft(), false);
set(i++, javascript.ShiftRight(language_mode_), true); set(i++, javascript.ShiftRight(language_mode_, hints), true);
set(i++, simplified.NumberShiftRight(), false); set(i++, simplified.NumberShiftRight(), false);
set(i++, javascript.ShiftRightLogical(language_mode_), false); set(i++, javascript.ShiftRightLogical(language_mode_, hints), false);
set(i++, simplified.NumberShiftRightLogical(), false); set(i++, simplified.NumberShiftRightLogical(), false);
} }
static const int kNumberOps = 6; static const int kNumberOps = 6;
...@@ -386,11 +393,11 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { ...@@ -386,11 +393,11 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester {
explicit JSBitwiseTypedLoweringTester(LanguageMode language_mode) explicit JSBitwiseTypedLoweringTester(LanguageMode language_mode)
: JSTypedLoweringTester(), language_mode_(language_mode) { : JSTypedLoweringTester(), language_mode_(language_mode) {
int i = 0; int i = 0;
set(i++, javascript.BitwiseOr(language_mode_), true); set(i++, javascript.BitwiseOr(language_mode_, hints), true);
set(i++, simplified.NumberBitwiseOr(), true); set(i++, simplified.NumberBitwiseOr(), true);
set(i++, javascript.BitwiseXor(language_mode_), true); set(i++, javascript.BitwiseXor(language_mode_, hints), true);
set(i++, simplified.NumberBitwiseXor(), true); set(i++, simplified.NumberBitwiseXor(), true);
set(i++, javascript.BitwiseAnd(language_mode_), true); set(i++, javascript.BitwiseAnd(language_mode_, hints), true);
set(i++, simplified.NumberBitwiseAnd(), true); set(i++, simplified.NumberBitwiseAnd(), true);
} }
static const int kNumberOps = 6; static const int kNumberOps = 6;
...@@ -740,14 +747,14 @@ TEST_WITH_STRONG(RemoveToNumberEffects) { ...@@ -740,14 +747,14 @@ TEST_WITH_STRONG(RemoveToNumberEffects) {
case 2: case 2:
effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
case 3: case 3:
effect_use = R.graph.NewNode(R.javascript.Add(language_mode), ton, ton, effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints),
R.context(), frame_state, frame_state, ton, ton, ton, R.context(), frame_state,
R.start()); frame_state, ton, R.start());
break; break;
case 4: case 4:
effect_use = R.graph.NewNode(R.javascript.Add(language_mode), p0, p0, effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints),
R.context(), frame_state, frame_state, ton, p0, p0, R.context(), frame_state,
R.start()); frame_state, ton, R.start());
break; break;
case 5: case 5:
effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start()); effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
...@@ -910,13 +917,20 @@ TEST_WITH_STRONG(RemovePureNumberBinopEffects) { ...@@ -910,13 +917,20 @@ TEST_WITH_STRONG(RemovePureNumberBinopEffects) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Equal(), R.simplified.NumberEqual(), R.javascript.Equal(),
R.javascript.Add(language_mode), R.simplified.NumberAdd(), R.simplified.NumberEqual(),
R.javascript.Subtract(language_mode), R.simplified.NumberSubtract(), R.javascript.Add(language_mode, R.hints),
R.javascript.Multiply(language_mode), R.simplified.NumberMultiply(), R.simplified.NumberAdd(),
R.javascript.Divide(language_mode), R.simplified.NumberDivide(), R.javascript.Subtract(language_mode, R.hints),
R.javascript.Modulus(language_mode), R.simplified.NumberModulus(), R.simplified.NumberSubtract(),
R.javascript.LessThan(language_mode), R.simplified.NumberLessThan(), R.javascript.Multiply(language_mode, R.hints),
R.simplified.NumberMultiply(),
R.javascript.Divide(language_mode, R.hints),
R.simplified.NumberDivide(),
R.javascript.Modulus(language_mode, R.hints),
R.simplified.NumberModulus(),
R.javascript.LessThan(language_mode),
R.simplified.NumberLessThan(),
R.javascript.LessThanOrEqual(language_mode), R.javascript.LessThanOrEqual(language_mode),
R.simplified.NumberLessThanOrEqual(), R.simplified.NumberLessThanOrEqual(),
}; };
...@@ -939,11 +953,11 @@ TEST(OrderNumberBinopEffects1) { ...@@ -939,11 +953,11 @@ TEST(OrderNumberBinopEffects1) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Subtract(LanguageMode::SLOPPY), R.javascript.Subtract(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberSubtract(), R.simplified.NumberSubtract(),
R.javascript.Multiply(LanguageMode::SLOPPY), R.javascript.Multiply(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberMultiply(), R.simplified.NumberMultiply(),
R.javascript.Divide(LanguageMode::SLOPPY), R.javascript.Divide(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberDivide(), R.simplified.NumberDivide(),
}; };
...@@ -967,13 +981,13 @@ TEST(OrderNumberBinopEffects2) { ...@@ -967,13 +981,13 @@ TEST(OrderNumberBinopEffects2) {
JSTypedLoweringTester R; JSTypedLoweringTester R;
const Operator* ops[] = { const Operator* ops[] = {
R.javascript.Add(LanguageMode::SLOPPY), R.javascript.Add(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberAdd(), R.simplified.NumberAdd(),
R.javascript.Subtract(LanguageMode::SLOPPY), R.javascript.Subtract(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberSubtract(), R.simplified.NumberSubtract(),
R.javascript.Multiply(LanguageMode::SLOPPY), R.javascript.Multiply(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberMultiply(), R.simplified.NumberMultiply(),
R.javascript.Divide(LanguageMode::SLOPPY), R.javascript.Divide(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberDivide(), R.simplified.NumberDivide(),
}; };
......
...@@ -187,17 +187,6 @@ const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = { ...@@ -187,17 +187,6 @@ const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = {
SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(BitwiseOr, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(BitwiseXor, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(BitwiseAnd, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ShiftLeft, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ShiftRight, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Add, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Subtract, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Multiply, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Divide, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
SHARED(Modulus, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2),
#undef SHARED #undef SHARED
}; };
......
...@@ -522,15 +522,17 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) { ...@@ -522,15 +522,17 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) { TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32()); Node* const lhs = Parameter(Type::Signed32());
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
Node* const effect = graph()->start(); Node* const effect = graph()->start();
Node* const control = graph()->start(); Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) { TRACED_FORRANGE(double, rhs, 0, 31) {
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode( Reduction r = Reduce(
javascript()->ShiftLeft(language_mode), lhs, NumberConstant(rhs), graph()->NewNode(javascript()->ShiftLeft(language_mode, hints), lhs,
context, EmptyFrameState(), EmptyFrameState(), effect, control)); NumberConstant(rhs), context, EmptyFrameState(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), EXPECT_THAT(r.replacement(),
IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs)))); IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs))));
...@@ -540,6 +542,7 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) { ...@@ -540,6 +542,7 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) { TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32()); Node* const lhs = Parameter(Type::Signed32());
Node* const rhs = Parameter(Type::Unsigned32()); Node* const rhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
...@@ -547,7 +550,7 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) { ...@@ -547,7 +550,7 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
Node* const control = graph()->start(); Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode( Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftLeft(language_mode), lhs, rhs, context, javascript()->ShiftLeft(language_mode, hints), lhs, rhs, context,
EmptyFrameState(), EmptyFrameState(), effect, control)); EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs)); EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs));
...@@ -560,15 +563,17 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) { ...@@ -560,15 +563,17 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) { TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32()); Node* const lhs = Parameter(Type::Signed32());
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
Node* const effect = graph()->start(); Node* const effect = graph()->start();
Node* const control = graph()->start(); Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) { TRACED_FORRANGE(double, rhs, 0, 31) {
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode( Reduction r = Reduce(
javascript()->ShiftRight(language_mode), lhs, NumberConstant(rhs), graph()->NewNode(javascript()->ShiftRight(language_mode, hints), lhs,
context, EmptyFrameState(), EmptyFrameState(), effect, control)); NumberConstant(rhs), context, EmptyFrameState(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), EXPECT_THAT(r.replacement(),
IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs)))); IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs))));
...@@ -578,6 +583,7 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) { ...@@ -578,6 +583,7 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) { TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32()); Node* const lhs = Parameter(Type::Signed32());
Node* const rhs = Parameter(Type::Unsigned32()); Node* const rhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
...@@ -585,7 +591,7 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) { ...@@ -585,7 +591,7 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
Node* const control = graph()->start(); Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode( Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRight(language_mode), lhs, rhs, context, javascript()->ShiftRight(language_mode, hints), lhs, rhs, context,
EmptyFrameState(), EmptyFrameState(), effect, control)); EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs)); EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs));
...@@ -599,16 +605,17 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) { ...@@ -599,16 +605,17 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
TEST_F(JSTypedLoweringTest, TEST_F(JSTypedLoweringTest,
JSShiftRightLogicalWithUnsigned32AndConstant) { JSShiftRightLogicalWithUnsigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Unsigned32()); Node* const lhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
Node* const effect = graph()->start(); Node* const effect = graph()->start();
Node* const control = graph()->start(); Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) { TRACED_FORRANGE(double, rhs, 0, 31) {
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce( Reduction r = Reduce(graph()->NewNode(
graph()->NewNode(javascript()->ShiftRightLogical(language_mode), lhs, javascript()->ShiftRightLogical(language_mode, hints), lhs,
NumberConstant(rhs), context, EmptyFrameState(), NumberConstant(rhs), context, EmptyFrameState(), EmptyFrameState(),
EmptyFrameState(), effect, control)); effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), EXPECT_THAT(r.replacement(),
IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs)))); IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs))));
...@@ -617,8 +624,8 @@ TEST_F(JSTypedLoweringTest, ...@@ -617,8 +624,8 @@ TEST_F(JSTypedLoweringTest,
} }
TEST_F(JSTypedLoweringTest, TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
JSShiftRightLogicalWithUnsigned32AndUnsigned32) { BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Unsigned32()); Node* const lhs = Parameter(Type::Unsigned32());
Node* const rhs = Parameter(Type::Unsigned32()); Node* const rhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant(); Node* const context = UndefinedConstant();
...@@ -626,8 +633,8 @@ TEST_F(JSTypedLoweringTest, ...@@ -626,8 +633,8 @@ TEST_F(JSTypedLoweringTest,
Node* const control = graph()->start(); Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode( Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRightLogical(language_mode), lhs, rhs, context, javascript()->ShiftRightLogical(language_mode, hints), lhs, rhs,
EmptyFrameState(), EmptyFrameState(), effect, control)); context, EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs)); EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs));
} }
...@@ -978,6 +985,7 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) { ...@@ -978,6 +985,7 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) {
TEST_F(JSTypedLoweringTest, JSAddWithString) { TEST_F(JSTypedLoweringTest, JSAddWithString) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Node* lhs = Parameter(Type::String(), 0); Node* lhs = Parameter(Type::String(), 0);
Node* rhs = Parameter(Type::String(), 1); Node* rhs = Parameter(Type::String(), 1);
...@@ -986,9 +994,9 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) { ...@@ -986,9 +994,9 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) {
Node* frame_state1 = EmptyFrameState(); Node* frame_state1 = EmptyFrameState();
Node* effect = graph()->start(); Node* effect = graph()->start();
Node* control = graph()->start(); Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->Add(language_mode), lhs, Reduction r = Reduce(
rhs, context, frame_state0, graph()->NewNode(javascript()->Add(language_mode, hints), lhs, rhs,
frame_state1, effect, control)); context, frame_state0, frame_state1, effect, control));
ASSERT_TRUE(r.Changed()); ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), EXPECT_THAT(r.replacement(),
IsCall(_, IsHeapConstant(CodeFactory::StringAdd( IsCall(_, IsHeapConstant(CodeFactory::StringAdd(
......
...@@ -51,6 +51,7 @@ class TyperTest : public TypedGraphTest { ...@@ -51,6 +51,7 @@ class TyperTest : public TypedGraphTest {
Types<Type, Type*, Zone> types_; Types<Type, Type*, Zone> types_;
JSOperatorBuilder javascript_; JSOperatorBuilder javascript_;
BinaryOperationHints const hints_ = BinaryOperationHints::Any();
Node* context_node_; Node* context_node_;
v8::base::RandomNumberGenerator* rng_; v8::base::RandomNumberGenerator* rng_;
std::vector<double> integers; std::vector<double> integers;
...@@ -239,68 +240,78 @@ int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; } ...@@ -239,68 +240,78 @@ int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
TEST_F(TyperTest, TypeJSAdd) { TEST_F(TyperTest, TypeJSAdd) {
TestBinaryArithOp(javascript_.Add(LanguageMode::SLOPPY), std::plus<double>()); TestBinaryArithOp(javascript_.Add(LanguageMode::SLOPPY, hints_),
TestBinaryArithOp(javascript_.Add(LanguageMode::STRONG), std::plus<double>()); std::plus<double>());
TestBinaryArithOp(javascript_.Add(LanguageMode::STRONG, hints_),
std::plus<double>());
} }
TEST_F(TyperTest, TypeJSSubtract) { TEST_F(TyperTest, TypeJSSubtract) {
TestBinaryArithOp(javascript_.Subtract(LanguageMode::SLOPPY), TestBinaryArithOp(javascript_.Subtract(LanguageMode::SLOPPY, hints_),
std::minus<double>()); std::minus<double>());
TestBinaryArithOp(javascript_.Subtract(LanguageMode::STRONG), TestBinaryArithOp(javascript_.Subtract(LanguageMode::STRONG, hints_),
std::minus<double>()); std::minus<double>());
} }
TEST_F(TyperTest, TypeJSMultiply) { TEST_F(TyperTest, TypeJSMultiply) {
TestBinaryArithOp(javascript_.Multiply(LanguageMode::SLOPPY), TestBinaryArithOp(javascript_.Multiply(LanguageMode::SLOPPY, hints_),
std::multiplies<double>()); std::multiplies<double>());
TestBinaryArithOp(javascript_.Multiply(LanguageMode::STRONG), TestBinaryArithOp(javascript_.Multiply(LanguageMode::STRONG, hints_),
std::multiplies<double>()); std::multiplies<double>());
} }
TEST_F(TyperTest, TypeJSDivide) { TEST_F(TyperTest, TypeJSDivide) {
TestBinaryArithOp(javascript_.Divide(LanguageMode::SLOPPY), TestBinaryArithOp(javascript_.Divide(LanguageMode::SLOPPY, hints_),
std::divides<double>()); std::divides<double>());
TestBinaryArithOp(javascript_.Divide(LanguageMode::STRONG), TestBinaryArithOp(javascript_.Divide(LanguageMode::STRONG, hints_),
std::divides<double>()); std::divides<double>());
} }
TEST_F(TyperTest, TypeJSModulus) { TEST_F(TyperTest, TypeJSModulus) {
TestBinaryArithOp(javascript_.Modulus(LanguageMode::SLOPPY), modulo); TestBinaryArithOp(javascript_.Modulus(LanguageMode::SLOPPY, hints_), modulo);
TestBinaryArithOp(javascript_.Modulus(LanguageMode::STRONG), modulo); TestBinaryArithOp(javascript_.Modulus(LanguageMode::STRONG, hints_), modulo);
} }
TEST_F(TyperTest, TypeJSBitwiseOr) { TEST_F(TyperTest, TypeJSBitwiseOr) {
TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::SLOPPY), bit_or); TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::SLOPPY, hints_), bit_or);
TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::STRONG), bit_or); TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::STRONG, hints_), bit_or);
} }
TEST_F(TyperTest, TypeJSBitwiseAnd) { TEST_F(TyperTest, TypeJSBitwiseAnd) {
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::SLOPPY), bit_and); TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::SLOPPY, hints_),
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::STRONG), bit_and); bit_and);
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::STRONG, hints_),
bit_and);
} }
TEST_F(TyperTest, TypeJSBitwiseXor) { TEST_F(TyperTest, TypeJSBitwiseXor) {
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::SLOPPY), bit_xor); TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::SLOPPY, hints_),
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::STRONG), bit_xor); bit_xor);
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::STRONG, hints_),
bit_xor);
} }
TEST_F(TyperTest, TypeJSShiftLeft) { TEST_F(TyperTest, TypeJSShiftLeft) {
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::SLOPPY), shift_left); TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::SLOPPY, hints_),
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::STRONG), shift_left); shift_left);
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::STRONG, hints_),
shift_left);
} }
TEST_F(TyperTest, TypeJSShiftRight) { TEST_F(TyperTest, TypeJSShiftRight) {
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::SLOPPY), shift_right); TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::SLOPPY, hints_),
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::STRONG), shift_right); shift_right);
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::STRONG, hints_),
shift_right);
} }
...@@ -362,47 +373,48 @@ TEST_F(TyperTest, TypeJSStrictNotEqual) { ...@@ -362,47 +373,48 @@ TEST_F(TyperTest, TypeJSStrictNotEqual) {
// Monotonicity // Monotonicity
// List should be in sync with JS_SIMPLE_BINOP_LIST. #define TEST_BINARY_MONOTONICITY(name) \
#define JSBINOP_LIST(V) \
V(Equal) \
V(NotEqual) \
V(StrictEqual) \
V(StrictNotEqual)
#define JSBINOP_WITH_STRONG_LIST(V) \
V(LessThan) \
V(GreaterThan) \
V(LessThanOrEqual) \
V(GreaterThanOrEqual) \
V(BitwiseOr) \
V(BitwiseXor) \
V(BitwiseAnd) \
V(ShiftLeft) \
V(ShiftRight) \
V(ShiftRightLogical) \
V(Add) \
V(Subtract) \
V(Multiply) \
V(Divide) \
V(Modulus)
#define TEST_FUNC(name) \
TEST_F(TyperTest, Monotonicity_##name) { \ TEST_F(TyperTest, Monotonicity_##name) { \
TestBinaryMonotonicity(javascript_.name()); \ TestBinaryMonotonicity(javascript_.name()); \
} }
JSBINOP_LIST(TEST_FUNC) TEST_BINARY_MONOTONICITY(Equal)
#undef TEST_FUNC TEST_BINARY_MONOTONICITY(NotEqual)
TEST_BINARY_MONOTONICITY(StrictEqual)
TEST_BINARY_MONOTONICITY(StrictNotEqual)
#undef TEST_BINARY_MONOTONICITY
#define TEST_FUNC(name) \ #define TEST_BINARY_MONOTONICITY(name) \
TEST_F(TyperTest, Monotonicity_##name) { \ TEST_F(TyperTest, Monotonicity_##name) { \
TestBinaryMonotonicity(javascript_.name(LanguageMode::SLOPPY)); \ TestBinaryMonotonicity(javascript_.name(LanguageMode::SLOPPY)); \
TestBinaryMonotonicity(javascript_.name(LanguageMode::STRONG)); \ TestBinaryMonotonicity(javascript_.name(LanguageMode::STRONG)); \
} }
JSBINOP_WITH_STRONG_LIST(TEST_FUNC) TEST_BINARY_MONOTONICITY(LessThan)
#undef TEST_FUNC TEST_BINARY_MONOTONICITY(GreaterThan)
TEST_BINARY_MONOTONICITY(LessThanOrEqual)
TEST_BINARY_MONOTONICITY(GreaterThanOrEqual)
#undef TEST_BINARY_MONOTONICITY
#define TEST_BINARY_MONOTONICITY(name) \
TEST_F(TyperTest, Monotonicity_##name) { \
TestBinaryMonotonicity( \
javascript_.name(LanguageMode::SLOPPY, BinaryOperationHints::Any())); \
TestBinaryMonotonicity( \
javascript_.name(LanguageMode::STRONG, BinaryOperationHints::Any())); \
}
TEST_BINARY_MONOTONICITY(BitwiseOr)
TEST_BINARY_MONOTONICITY(BitwiseXor)
TEST_BINARY_MONOTONICITY(BitwiseAnd)
TEST_BINARY_MONOTONICITY(ShiftLeft)
TEST_BINARY_MONOTONICITY(ShiftRight)
TEST_BINARY_MONOTONICITY(ShiftRightLogical)
TEST_BINARY_MONOTONICITY(Add)
TEST_BINARY_MONOTONICITY(Subtract)
TEST_BINARY_MONOTONICITY(Multiply)
TEST_BINARY_MONOTONICITY(Divide)
TEST_BINARY_MONOTONICITY(Modulus)
#undef TEST_BINARY_MONOTONICITY
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
......
...@@ -625,6 +625,10 @@ ...@@ -625,6 +625,10 @@
'../../src/compiler/state-values-utils.h', '../../src/compiler/state-values-utils.h',
'../../src/compiler/tail-call-optimization.cc', '../../src/compiler/tail-call-optimization.cc',
'../../src/compiler/tail-call-optimization.h', '../../src/compiler/tail-call-optimization.h',
'../../src/compiler/type-hint-analyzer.cc',
'../../src/compiler/type-hint-analyzer.h',
'../../src/compiler/type-hints.cc',
'../../src/compiler/type-hints.h',
'../../src/compiler/typer.cc', '../../src/compiler/typer.cc',
'../../src/compiler/typer.h', '../../src/compiler/typer.h',
'../../src/compiler/value-numbering-reducer.cc', '../../src/compiler/value-numbering-reducer.cc',
......
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