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") {
"src/compiler/state-values-utils.h",
"src/compiler/tail-call-optimization.cc",
"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.h",
"src/compiler/value-numbering-reducer.cc",
......
......@@ -1457,9 +1457,9 @@ HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
HValue* left = GetParameter(BinaryOpICStub::kLeft);
HValue* right = GetParameter(BinaryOpICStub::kRight);
Type* left_type = state.GetLeftType(zone());
Type* right_type = state.GetRightType(zone());
Type* result_type = state.GetResultType(zone());
Type* left_type = state.GetLeftType();
Type* right_type = state.GetRightType();
Type* result_type = state.GetResultType();
DCHECK(!left_type->Is(Type::None()) && !right_type->Is(Type::None()) &&
(state.HasSideEffects() || !result_type->Is(Type::None())));
......@@ -1538,9 +1538,9 @@ HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() {
HValue* left = GetParameter(BinaryOpWithAllocationSiteStub::kLeft);
HValue* right = GetParameter(BinaryOpWithAllocationSiteStub::kRight);
Type* left_type = state.GetLeftType(zone());
Type* right_type = state.GetRightType(zone());
Type* result_type = state.GetResultType(zone());
Type* left_type = state.GetLeftType();
Type* right_type = state.GetRightType();
Type* result_type = state.GetResultType();
HAllocationMode allocation_mode(allocation_site);
return BuildBinaryOperation(state.op(), left, right, left_type, right_type,
......
......@@ -15,6 +15,7 @@
#include "src/compiler/node-properties.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/state-values-utils.h"
#include "src/compiler/type-hint-analyzer.h"
#include "src/parsing/parser.h"
namespace v8 {
......@@ -428,7 +429,8 @@ class AstGraphBuilder::FrameStateBeforeAndAfter {
AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
TypeHintAnalysis* type_hint_analysis)
: isolate_(info->isolate()),
local_zone_(local_zone),
info_(info),
......@@ -444,6 +446,7 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
input_buffer_(nullptr),
exit_controls_(local_zone),
loop_assignment_analysis_(loop),
type_hint_analysis_(type_hint_analysis),
state_values_cache_(jsgraph),
liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
local_zone),
......@@ -2166,7 +2169,9 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
FrameStateBeforeAndAfter states(this, expr->value()->id());
Node* right = 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(),
OutputFrameStateCombine::Push());
}
......@@ -2725,9 +2730,10 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
// Create node to perform +1/-1 operation.
Node* value;
{
// TODO(bmeurer): Cleanup this feedback/bailout mess!
FrameStateBeforeAndAfter states(this, BailoutId::None());
value =
BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
value = BuildBinaryOp(old_value, jsgraph()->OneConstant(),
expr->binary_op(), TypeFeedbackId::None());
// This should never deoptimize outside strong mode because otherwise we
// have converted to number before.
states.AddToNode(value, is_strong(language_mode()) ? expr->ToNumberId()
......@@ -2810,7 +2816,8 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
FrameStateBeforeAndAfter states(this, expr->right()->id());
Node* right = 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());
ast_context()->ProduceValue(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;
BinaryOperationHints hints;
if (!type_hint_analysis_ ||
!type_hint_analysis_->GetBinaryOperationHints(feedback_id, &hints)) {
hints = BinaryOperationHints::Any();
}
switch (op) {
case Token::BIT_OR:
js_op = javascript()->BitwiseOr(language_mode());
js_op = javascript()->BitwiseOr(language_mode(), hints);
break;
case Token::BIT_AND:
js_op = javascript()->BitwiseAnd(language_mode());
js_op = javascript()->BitwiseAnd(language_mode(), hints);
break;
case Token::BIT_XOR:
js_op = javascript()->BitwiseXor(language_mode());
js_op = javascript()->BitwiseXor(language_mode(), hints);
break;
case Token::SHL:
js_op = javascript()->ShiftLeft(language_mode());
js_op = javascript()->ShiftLeft(language_mode(), hints);
break;
case Token::SAR:
js_op = javascript()->ShiftRight(language_mode());
js_op = javascript()->ShiftRight(language_mode(), hints);
break;
case Token::SHR:
js_op = javascript()->ShiftRightLogical(language_mode());
js_op = javascript()->ShiftRightLogical(language_mode(), hints);
break;
case Token::ADD:
js_op = javascript()->Add(language_mode());
js_op = javascript()->Add(language_mode(), hints);
break;
case Token::SUB:
js_op = javascript()->Subtract(language_mode());
js_op = javascript()->Subtract(language_mode(), hints);
break;
case Token::MUL:
js_op = javascript()->Multiply(language_mode());
js_op = javascript()->Multiply(language_mode(), hints);
break;
case Token::DIV:
js_op = javascript()->Divide(language_mode());
js_op = javascript()->Divide(language_mode(), hints);
break;
case Token::MOD:
js_op = javascript()->Modulus(language_mode());
js_op = javascript()->Modulus(language_mode(), hints);
break;
default:
UNREACHABLE();
......
......@@ -13,15 +13,20 @@
namespace v8 {
namespace internal {
// Forward declarations.
class BitVector;
namespace compiler {
// Forward declarations.
class ControlBuilder;
class Graph;
class LoopAssignmentAnalysis;
class LoopBuilder;
class Node;
class TypeHintAnalysis;
// The AstGraphBuilder produces a high-level IR graph, based on an
// underlying AST. The produced graph can either be compiled into a
......@@ -30,7 +35,8 @@ class Node;
class AstGraphBuilder : public AstVisitor {
public:
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.
bool CreateGraph(bool stack_check = true);
......@@ -106,6 +112,9 @@ class AstGraphBuilder : public AstVisitor {
// Result of loop assignment analysis performed before graph creation.
LoopAssignmentAnalysis* loop_assignment_analysis_;
// Result of type hint analysis performed before graph creation.
TypeHintAnalysis* type_hint_analysis_;
// Cache for StateValues nodes for frame states.
StateValuesCache state_values_cache_;
......@@ -344,7 +353,8 @@ class AstGraphBuilder : public AstVisitor {
Node* BuildThrow(Node* exception_value);
// 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
// stack and build a call node using the given call operator.
......
......@@ -832,67 +832,79 @@ void BytecodeGraphBuilder::BuildBinaryOp(
void BytecodeGraphBuilder::VisitAdd(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Add(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Add(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitSub(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Subtract(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Subtract(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitMul(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Multiply(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Multiply(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitDiv(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Divide(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Divide(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitMod(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->Modulus(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->Modulus(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitBitwiseOr(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->BitwiseOr(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->BitwiseOr(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitBitwiseXor(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->BitwiseXor(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->BitwiseXor(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitBitwiseAnd(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->BitwiseAnd(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->BitwiseAnd(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitShiftLeft(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftLeft(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->ShiftLeft(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitShiftRight(
const interpreter::BytecodeArrayIterator& iterator) {
BuildBinaryOp(javascript()->ShiftRight(language_mode()), iterator);
BinaryOperationHints hints = BinaryOperationHints::Any();
BuildBinaryOp(javascript()->ShiftRight(language_mode(), hints), iterator);
}
void BytecodeGraphBuilder::VisitShiftRightLogical(
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) {
}
#define REPLACE_BINARY_OP_IC_CALL(op, token) \
void JSGenericLowering::Lower##op(Node* node) { \
#define REPLACE_BINARY_OP_IC_CALL(Op, token) \
void JSGenericLowering::Lower##Op(Node* node) { \
BinaryOperationParameters const& p = \
BinaryOperationParametersOf(node->op()); \
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); \
ReplaceWithStubCall(node, CodeFactory::BinaryOpIC( \
isolate(), token, \
strength(OpParameter<LanguageMode>(node))), \
ReplaceWithStubCall(node, \
CodeFactory::BinaryOpIC(isolate(), token, \
strength(p.language_mode())), \
CallDescriptor::kPatchableCallSiteWithNop | flags); \
}
REPLACE_BINARY_OP_IC_CALL(JSBitwiseOr, Token::BIT_OR)
......
......@@ -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,
CallConstructParameters const& rhs) {
return lhs.arity() == rhs.arity() && lhs.feedback() == rhs.feedback();
......@@ -472,18 +512,7 @@ const CreateLiteralParameters& CreateLiteralParametersOf(const Operator* op) {
V(LessThan, Operator::kNoProperties, 2, 1) \
V(GreaterThan, Operator::kNoProperties, 2, 1) \
V(LessThanOrEqual, 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)
V(GreaterThanOrEqual, Operator::kNoProperties, 2, 1)
struct JSOperatorGlobalCache final {
......@@ -557,6 +586,138 @@ CACHED_OP_LIST_WITH_LANGUAGE_MODE(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(
size_t arity, LanguageMode language_mode, VectorSlotPair const& feedback,
ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) {
......
......@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_JS_OPERATOR_H_
#define V8_COMPILER_JS_OPERATOR_H_
#include "src/compiler/type-hints.h"
#include "src/runtime/runtime.h"
namespace v8 {
......@@ -54,6 +55,34 @@ size_t hash_value(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
// used as a parameter by JSCallConstruct operators.
class CallConstructParameters final {
......@@ -446,17 +475,27 @@ class JSOperatorBuilder final : public ZoneObject {
const Operator* GreaterThan(LanguageMode language_mode);
const Operator* LessThanOrEqual(LanguageMode language_mode);
const Operator* GreaterThanOrEqual(LanguageMode language_mode);
const Operator* BitwiseOr(LanguageMode language_mode);
const Operator* BitwiseXor(LanguageMode language_mode);
const Operator* BitwiseAnd(LanguageMode language_mode);
const Operator* ShiftLeft(LanguageMode language_mode);
const Operator* ShiftRight(LanguageMode language_mode);
const Operator* ShiftRightLogical(LanguageMode language_mode);
const Operator* Add(LanguageMode language_mode);
const Operator* Subtract(LanguageMode language_mode);
const Operator* Multiply(LanguageMode language_mode);
const Operator* Divide(LanguageMode language_mode);
const Operator* Modulus(LanguageMode language_mode);
const Operator* BitwiseOr(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* BitwiseXor(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* BitwiseAnd(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* ShiftLeft(LanguageMode language_mode,
BinaryOperationHints hints);
const Operator* ShiftRight(LanguageMode language_mode,
BinaryOperationHints hints);
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* ToBoolean();
......
......@@ -218,7 +218,16 @@ class JSBinopReduction final {
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); }
......
......@@ -55,6 +55,7 @@
#include "src/compiler/simplified-operator.h"
#include "src/compiler/simplified-operator-reducer.h"
#include "src/compiler/tail-call-optimization.h"
#include "src/compiler/type-hint-analyzer.h"
#include "src/compiler/typer.h"
#include "src/compiler/value-numbering-reducer.h"
#include "src/compiler/verifier.h"
......@@ -210,6 +211,12 @@ class PipelineData {
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_; }
void set_schedule(Schedule* schedule) {
DCHECK(!schedule_);
......@@ -234,6 +241,7 @@ class PipelineData {
graph_zone_ = nullptr;
graph_ = nullptr;
loop_assignment_ = nullptr;
type_hint_analysis_ = nullptr;
simplified_ = nullptr;
machine_ = nullptr;
common_ = nullptr;
......@@ -301,6 +309,7 @@ class PipelineData {
// TODO(dcarney): make this into a ZoneObject.
base::SmartPointer<SourcePositionTable> source_positions_;
LoopAssignmentAnalysis* loop_assignment_;
TypeHintAnalysis* type_hint_analysis_ = nullptr;
SimplifiedOperatorBuilder* simplified_;
MachineOperatorBuilder* machine_;
CommonOperatorBuilder* common_;
......@@ -363,8 +372,10 @@ class AstGraphBuilderWithPositions final : public AstGraphBuilder {
AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info,
JSGraph* jsgraph,
LoopAssignmentAnalysis* loop_assignment,
TypeHintAnalysis* type_hint_analysis,
SourcePositionTable* source_positions)
: AstGraphBuilder(local_zone, info, jsgraph, loop_assignment),
: AstGraphBuilder(local_zone, info, jsgraph, loop_assignment,
type_hint_analysis),
source_positions_(source_positions),
start_position_(info->shared_info()->start_position()) {}
......@@ -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 {
static const char* phase_name() { return "graph builder"; }
......@@ -490,7 +513,7 @@ struct GraphBuilderPhase {
} else {
AstGraphBuilderWithPositions graph_builder(
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);
}
......@@ -1074,6 +1097,10 @@ Handle<Code> Pipeline::GenerateCode() {
Run<LoopAssignmentAnalysisPhase>();
}
if (info()->is_typing_enabled()) {
Run<TypeHintAnalysisPhase>();
}
Run<GraphBuilderPhase>();
if (data.compilation_failed()) return Handle<Code>::null();
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(
}
Type* BinaryOpICState::GetResultType(Zone* zone) const {
Type* BinaryOpICState::GetResultType() const {
Kind result_kind = result_kind_;
if (HasSideEffects()) {
result_kind = NONE;
} 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) {
return Type::Unsigned32(zone);
return Type::Unsigned32();
}
DCHECK_NE(GENERIC, result_kind);
return KindToType(result_kind, zone);
return KindToType(result_kind);
}
......@@ -320,20 +320,20 @@ const char* BinaryOpICState::KindToString(Kind kind) {
// static
Type* BinaryOpICState::KindToType(Kind kind, Zone* zone) {
Type* BinaryOpICState::KindToType(Kind kind) {
switch (kind) {
case NONE:
return Type::None(zone);
return Type::None();
case SMI:
return Type::SignedSmall(zone);
return Type::SignedSmall();
case INT32:
return Type::Signed32(zone);
return Type::Signed32();
case NUMBER:
return Type::Number(zone);
return Type::Number();
case STRING:
return Type::String(zone);
return Type::String();
case GENERIC:
return Type::Any(zone);
return Type::Any();
}
UNREACHABLE();
return NULL;
......
......@@ -120,9 +120,9 @@ class BinaryOpICState final BASE_EMBEDDED {
Token::Value op() const { return op_; }
Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
Type* GetLeftType(Zone* zone) const { return KindToType(left_kind_, zone); }
Type* GetRightType(Zone* zone) const { return KindToType(right_kind_, zone); }
Type* GetResultType(Zone* zone) const;
Type* GetLeftType() const { return KindToType(left_kind_); }
Type* GetRightType() const { return KindToType(right_kind_); }
Type* GetResultType() const;
void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);
......@@ -136,7 +136,7 @@ class BinaryOpICState final BASE_EMBEDDED {
Kind UpdateKind(Handle<Object> object, Kind kind) const;
static const char* KindToString(Kind kind);
static Type* KindToType(Kind kind, Zone* zone);
static Type* KindToType(Kind kind);
static bool KindMaybeSmi(Kind kind) {
return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
}
......
......@@ -245,9 +245,9 @@ void TypeFeedbackOracle::BinaryType(TypeFeedbackId id,
BinaryOpICState state(isolate(), code->extra_ic_state());
DCHECK_EQ(op, state.op());
*left = state.GetLeftType(zone());
*right = state.GetRightType(zone());
*result = state.GetResultType(zone());
*left = state.GetLeftType();
*right = state.GetRightType();
*result = state.GetResultType();
*fixed_right_arg = state.fixed_right_arg();
AllocationSite* first_allocation_site = code->FindFirstAllocationSite();
......@@ -265,7 +265,7 @@ Type* TypeFeedbackOracle::CountType(TypeFeedbackId id) {
Handle<Code> code = Handle<Code>::cast(object);
DCHECK_EQ(Code::BINARY_OP_IC, code->kind());
BinaryOpICState state(isolate(), code->extra_ic_state());
return state.GetLeftType(zone());
return state.GetLeftType();
}
......
......@@ -1041,6 +1041,13 @@ class TypeFeedbackId {
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 {
public:
......
......@@ -228,8 +228,8 @@ TEST(SpecializeToContext) {
t.graph()->NewNode(t.simplified()->ChangeTaggedToInt32(), other_load);
Node* add = t.graph()->NewNode(
t.javascript()->Add(LanguageMode::SLOPPY), value_use, other_use,
param_context, t.jsgraph()->EmptyFrameState(),
t.javascript()->Add(LanguageMode::SLOPPY, BinaryOperationHints::Any()),
value_use, other_use, param_context, t.jsgraph()->EmptyFrameState(),
t.jsgraph()->EmptyFrameState(), other_load, start);
Node* ret =
......
......@@ -63,6 +63,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
Graph graph;
Typer typer;
Node* context_node;
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* Parameter(Type* t, int32_t index = 0) {
Node* n = graph.NewNode(common.Parameter(index), graph.start());
......@@ -268,7 +269,8 @@ TEST_WITH_STRONG(AddNumber1) {
for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
Node* p0 = R.Parameter(kNumberTypes[i], 0);
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);
R.CheckBinop(IrOpcode::kNumberAdd, r);
......@@ -281,11 +283,16 @@ TEST_WITH_STRONG(AddNumber1) {
TEST_WITH_STRONG(NumberBinops) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Add(language_mode), R.simplified.NumberAdd(),
R.javascript.Subtract(language_mode), R.simplified.NumberSubtract(),
R.javascript.Multiply(language_mode), R.simplified.NumberMultiply(),
R.javascript.Divide(language_mode), R.simplified.NumberDivide(),
R.javascript.Modulus(language_mode), R.simplified.NumberModulus(),
R.javascript.Add(language_mode, R.hints),
R.simplified.NumberAdd(),
R.javascript.Subtract(language_mode, R.hints),
R.simplified.NumberSubtract(),
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) {
......@@ -328,11 +335,11 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester {
explicit JSBitwiseShiftTypedLoweringTester(LanguageMode language_mode)
: JSTypedLoweringTester(), language_mode_(language_mode) {
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++, javascript.ShiftRight(language_mode_), true);
set(i++, javascript.ShiftRight(language_mode_, hints), true);
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);
}
static const int kNumberOps = 6;
......@@ -386,11 +393,11 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester {
explicit JSBitwiseTypedLoweringTester(LanguageMode language_mode)
: JSTypedLoweringTester(), language_mode_(language_mode) {
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++, javascript.BitwiseXor(language_mode_), true);
set(i++, javascript.BitwiseXor(language_mode_, hints), 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);
}
static const int kNumberOps = 6;
......@@ -740,14 +747,14 @@ TEST_WITH_STRONG(RemoveToNumberEffects) {
case 2:
effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
case 3:
effect_use = R.graph.NewNode(R.javascript.Add(language_mode), ton, ton,
R.context(), frame_state, frame_state, ton,
R.start());
effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints),
ton, ton, R.context(), frame_state,
frame_state, ton, R.start());
break;
case 4:
effect_use = R.graph.NewNode(R.javascript.Add(language_mode), p0, p0,
R.context(), frame_state, frame_state, ton,
R.start());
effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints),
p0, p0, R.context(), frame_state,
frame_state, ton, R.start());
break;
case 5:
effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
......@@ -910,13 +917,20 @@ TEST_WITH_STRONG(RemovePureNumberBinopEffects) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Equal(), R.simplified.NumberEqual(),
R.javascript.Add(language_mode), R.simplified.NumberAdd(),
R.javascript.Subtract(language_mode), R.simplified.NumberSubtract(),
R.javascript.Multiply(language_mode), R.simplified.NumberMultiply(),
R.javascript.Divide(language_mode), R.simplified.NumberDivide(),
R.javascript.Modulus(language_mode), R.simplified.NumberModulus(),
R.javascript.LessThan(language_mode), R.simplified.NumberLessThan(),
R.javascript.Equal(),
R.simplified.NumberEqual(),
R.javascript.Add(language_mode, R.hints),
R.simplified.NumberAdd(),
R.javascript.Subtract(language_mode, R.hints),
R.simplified.NumberSubtract(),
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.simplified.NumberLessThanOrEqual(),
};
......@@ -939,11 +953,11 @@ TEST(OrderNumberBinopEffects1) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Subtract(LanguageMode::SLOPPY),
R.javascript.Subtract(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberSubtract(),
R.javascript.Multiply(LanguageMode::SLOPPY),
R.javascript.Multiply(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberMultiply(),
R.javascript.Divide(LanguageMode::SLOPPY),
R.javascript.Divide(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberDivide(),
};
......@@ -967,13 +981,13 @@ TEST(OrderNumberBinopEffects2) {
JSTypedLoweringTester R;
const Operator* ops[] = {
R.javascript.Add(LanguageMode::SLOPPY),
R.javascript.Add(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberAdd(),
R.javascript.Subtract(LanguageMode::SLOPPY),
R.javascript.Subtract(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberSubtract(),
R.javascript.Multiply(LanguageMode::SLOPPY),
R.javascript.Multiply(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberMultiply(),
R.javascript.Divide(LanguageMode::SLOPPY),
R.javascript.Divide(LanguageMode::SLOPPY, R.hints),
R.simplified.NumberDivide(),
};
......
......@@ -187,17 +187,6 @@ const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = {
SHARED(GreaterThan, 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(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
};
......
......@@ -522,15 +522,17 @@ TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32());
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) {
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftLeft(language_mode), lhs, NumberConstant(rhs),
context, EmptyFrameState(), EmptyFrameState(), effect, control));
Reduction r = Reduce(
graph()->NewNode(javascript()->ShiftLeft(language_mode, hints), lhs,
NumberConstant(rhs), context, EmptyFrameState(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs))));
......@@ -540,6 +542,7 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32());
Node* const rhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant();
......@@ -547,7 +550,7 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftLeft(language_mode), lhs, rhs, context,
javascript()->ShiftLeft(language_mode, hints), lhs, rhs, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs));
......@@ -560,15 +563,17 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32());
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) {
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRight(language_mode), lhs, NumberConstant(rhs),
context, EmptyFrameState(), EmptyFrameState(), effect, control));
Reduction r = Reduce(
graph()->NewNode(javascript()->ShiftRight(language_mode, hints), lhs,
NumberConstant(rhs), context, EmptyFrameState(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs))));
......@@ -578,6 +583,7 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Signed32());
Node* const rhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant();
......@@ -585,7 +591,7 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRight(language_mode), lhs, rhs, context,
javascript()->ShiftRight(language_mode, hints), lhs, rhs, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs));
......@@ -599,16 +605,17 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
TEST_F(JSTypedLoweringTest,
JSShiftRightLogicalWithUnsigned32AndConstant) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant();
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FORRANGE(double, rhs, 0, 31) {
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(
graph()->NewNode(javascript()->ShiftRightLogical(language_mode), lhs,
NumberConstant(rhs), context, EmptyFrameState(),
EmptyFrameState(), effect, control));
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRightLogical(language_mode, hints), lhs,
NumberConstant(rhs), context, EmptyFrameState(), EmptyFrameState(),
effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs))));
......@@ -617,8 +624,8 @@ TEST_F(JSTypedLoweringTest,
}
TEST_F(JSTypedLoweringTest,
JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
Node* const lhs = Parameter(Type::Unsigned32());
Node* const rhs = Parameter(Type::Unsigned32());
Node* const context = UndefinedConstant();
......@@ -626,8 +633,8 @@ TEST_F(JSTypedLoweringTest,
Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction r = Reduce(graph()->NewNode(
javascript()->ShiftRightLogical(language_mode), lhs, rhs, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
javascript()->ShiftRightLogical(language_mode, hints), lhs, rhs,
context, EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs));
}
......@@ -978,6 +985,7 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) {
TEST_F(JSTypedLoweringTest, JSAddWithString) {
BinaryOperationHints const hints = BinaryOperationHints::Any();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Node* lhs = Parameter(Type::String(), 0);
Node* rhs = Parameter(Type::String(), 1);
......@@ -986,9 +994,9 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) {
Node* frame_state1 = EmptyFrameState();
Node* effect = graph()->start();
Node* control = graph()->start();
Reduction r = Reduce(graph()->NewNode(javascript()->Add(language_mode), lhs,
rhs, context, frame_state0,
frame_state1, effect, control));
Reduction r = Reduce(
graph()->NewNode(javascript()->Add(language_mode, hints), lhs, rhs,
context, frame_state0, frame_state1, effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsCall(_, IsHeapConstant(CodeFactory::StringAdd(
......
......@@ -51,6 +51,7 @@ class TyperTest : public TypedGraphTest {
Types<Type, Type*, Zone> types_;
JSOperatorBuilder javascript_;
BinaryOperationHints const hints_ = BinaryOperationHints::Any();
Node* context_node_;
v8::base::RandomNumberGenerator* rng_;
std::vector<double> integers;
......@@ -239,68 +240,78 @@ int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
TEST_F(TyperTest, TypeJSAdd) {
TestBinaryArithOp(javascript_.Add(LanguageMode::SLOPPY), std::plus<double>());
TestBinaryArithOp(javascript_.Add(LanguageMode::STRONG), std::plus<double>());
TestBinaryArithOp(javascript_.Add(LanguageMode::SLOPPY, hints_),
std::plus<double>());
TestBinaryArithOp(javascript_.Add(LanguageMode::STRONG, hints_),
std::plus<double>());
}
TEST_F(TyperTest, TypeJSSubtract) {
TestBinaryArithOp(javascript_.Subtract(LanguageMode::SLOPPY),
TestBinaryArithOp(javascript_.Subtract(LanguageMode::SLOPPY, hints_),
std::minus<double>());
TestBinaryArithOp(javascript_.Subtract(LanguageMode::STRONG),
TestBinaryArithOp(javascript_.Subtract(LanguageMode::STRONG, hints_),
std::minus<double>());
}
TEST_F(TyperTest, TypeJSMultiply) {
TestBinaryArithOp(javascript_.Multiply(LanguageMode::SLOPPY),
TestBinaryArithOp(javascript_.Multiply(LanguageMode::SLOPPY, hints_),
std::multiplies<double>());
TestBinaryArithOp(javascript_.Multiply(LanguageMode::STRONG),
TestBinaryArithOp(javascript_.Multiply(LanguageMode::STRONG, hints_),
std::multiplies<double>());
}
TEST_F(TyperTest, TypeJSDivide) {
TestBinaryArithOp(javascript_.Divide(LanguageMode::SLOPPY),
TestBinaryArithOp(javascript_.Divide(LanguageMode::SLOPPY, hints_),
std::divides<double>());
TestBinaryArithOp(javascript_.Divide(LanguageMode::STRONG),
TestBinaryArithOp(javascript_.Divide(LanguageMode::STRONG, hints_),
std::divides<double>());
}
TEST_F(TyperTest, TypeJSModulus) {
TestBinaryArithOp(javascript_.Modulus(LanguageMode::SLOPPY), modulo);
TestBinaryArithOp(javascript_.Modulus(LanguageMode::STRONG), modulo);
TestBinaryArithOp(javascript_.Modulus(LanguageMode::SLOPPY, hints_), modulo);
TestBinaryArithOp(javascript_.Modulus(LanguageMode::STRONG, hints_), modulo);
}
TEST_F(TyperTest, TypeJSBitwiseOr) {
TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::SLOPPY), bit_or);
TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::STRONG), bit_or);
TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::SLOPPY, hints_), bit_or);
TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::STRONG, hints_), bit_or);
}
TEST_F(TyperTest, TypeJSBitwiseAnd) {
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::SLOPPY), bit_and);
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::STRONG), bit_and);
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::SLOPPY, hints_),
bit_and);
TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::STRONG, hints_),
bit_and);
}
TEST_F(TyperTest, TypeJSBitwiseXor) {
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::SLOPPY), bit_xor);
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::STRONG), bit_xor);
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::SLOPPY, hints_),
bit_xor);
TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::STRONG, hints_),
bit_xor);
}
TEST_F(TyperTest, TypeJSShiftLeft) {
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::SLOPPY), shift_left);
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::STRONG), shift_left);
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::SLOPPY, hints_),
shift_left);
TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::STRONG, hints_),
shift_left);
}
TEST_F(TyperTest, TypeJSShiftRight) {
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::SLOPPY), shift_right);
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::STRONG), shift_right);
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::SLOPPY, hints_),
shift_right);
TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::STRONG, hints_),
shift_right);
}
......@@ -362,47 +373,48 @@ TEST_F(TyperTest, TypeJSStrictNotEqual) {
// Monotonicity
// List should be in sync with JS_SIMPLE_BINOP_LIST.
#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) \
#define TEST_BINARY_MONOTONICITY(name) \
TEST_F(TyperTest, Monotonicity_##name) { \
TestBinaryMonotonicity(javascript_.name()); \
}
JSBINOP_LIST(TEST_FUNC)
#undef TEST_FUNC
TEST_BINARY_MONOTONICITY(Equal)
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) { \
TestBinaryMonotonicity(javascript_.name(LanguageMode::SLOPPY)); \
TestBinaryMonotonicity(javascript_.name(LanguageMode::STRONG)); \
}
JSBINOP_WITH_STRONG_LIST(TEST_FUNC)
#undef TEST_FUNC
TEST_BINARY_MONOTONICITY(LessThan)
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 @@
'../../src/compiler/state-values-utils.h',
'../../src/compiler/tail-call-optimization.cc',
'../../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.h',
'../../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