Commit e6ca0146 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce a SpeculativeToNumber operator.

Add a dedicated operator for ToNumber(x) with feedback instead of
translating to SpeculativeNumberMultiply(x,1), which allows us to
treat the case where x is already a Number specially, ignoring the
feedback on the operator. This recovers most of the regression in
the crypto benchmark.

BUG=chromium:709398,v8:6214,v8:5267
R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2802113003
Cr-Commit-Position: refs/heads/master@{#44484}
parent e434d11f
......@@ -2053,8 +2053,7 @@ void BytecodeGraphBuilder::VisitToNumber() {
Node* node = nullptr;
FeedbackSlot slot =
feedback_vector()->ToSlot(bytecode_iterator().GetIndexOperand(1));
if (Node* simplified = TryBuildSimplifiedBinaryOp(
javascript()->Multiply(), object, jsgraph()->OneConstant(), slot)) {
if (Node* simplified = TryBuildSimplifiedToNumber(object, slot)) {
node = simplified;
} else {
node = NewNode(javascript()->ToNumber(), object);
......@@ -2481,6 +2480,19 @@ Node* BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op,
return nullptr;
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedToNumber(Node* value,
FeedbackSlot slot) {
Node* effect = environment()->GetEffectDependency();
Node* control = environment()->GetControlDependency();
Reduction early_reduction = type_hint_lowering().ReduceToNumberOperation(
value, effect, control, slot);
if (early_reduction.Changed()) {
ApplyEarlyReduction(early_reduction);
return early_reduction.replacement();
}
return nullptr;
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedLoadNamed(const Operator* op,
Node* receiver,
FeedbackSlot slot) {
......
......@@ -180,6 +180,7 @@ class BytecodeGraphBuilder {
// any other invocation of {NewNode} would do.
Node* TryBuildSimplifiedBinaryOp(const Operator* op, Node* left, Node* right,
FeedbackSlot slot);
Node* TryBuildSimplifiedToNumber(Node* input, FeedbackSlot slot);
Node* TryBuildSimplifiedLoadNamed(const Operator* op, Node* receiver,
FeedbackSlot slot);
Node* TryBuildSimplifiedLoadKeyed(const Operator* op, Node* receiver,
......
......@@ -14,6 +14,30 @@ namespace v8 {
namespace internal {
namespace compiler {
namespace {
bool BinaryOperationHintToNumberOperationHint(
BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
switch (binop_hint) {
case BinaryOperationHint::kSignedSmall:
*number_hint = NumberOperationHint::kSignedSmall;
return true;
case BinaryOperationHint::kSigned32:
*number_hint = NumberOperationHint::kSigned32;
return true;
case BinaryOperationHint::kNumberOrOddball:
*number_hint = NumberOperationHint::kNumberOrOddball;
return true;
case BinaryOperationHint::kAny:
case BinaryOperationHint::kNone:
case BinaryOperationHint::kString:
break;
}
return false;
}
} // namespace
class JSSpeculativeBinopBuilder final {
public:
JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
......@@ -40,22 +64,8 @@ class JSSpeculativeBinopBuilder final {
}
bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
switch (GetBinaryOperationHint()) {
case BinaryOperationHint::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
case BinaryOperationHint::kSigned32:
*hint = NumberOperationHint::kSigned32;
return true;
case BinaryOperationHint::kNumberOrOddball:
*hint = NumberOperationHint::kNumberOrOddball;
return true;
case BinaryOperationHint::kAny:
case BinaryOperationHint::kNone:
case BinaryOperationHint::kString:
break;
}
return false;
return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
hint);
}
bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
......@@ -228,6 +238,22 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
return Reduction();
}
Reduction JSTypeHintLowering::ReduceToNumberOperation(Node* input, Node* effect,
Node* control,
FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
BinaryOpICNexus nexus(feedback_vector(), slot);
NumberOperationHint hint;
if (BinaryOperationHintToNumberOperationHint(
nexus.GetBinaryOperationFeedback(), &hint)) {
Node* node = jsgraph()->graph()->NewNode(
jsgraph()->simplified()->SpeculativeToNumber(hint), input, effect,
control);
return Reduction(node);
}
return Reduction();
}
Reduction JSTypeHintLowering::ReduceLoadNamedOperation(
const Operator* op, Node* obj, Node* effect, Node* control,
FeedbackSlot slot) const {
......
......@@ -55,6 +55,10 @@ class JSTypeHintLowering {
Node* effect, Node* control,
FeedbackSlot slot) const;
// Potential reduction to ToNumber operations
Reduction ReduceToNumberOperation(Node* value, Node* effect, Node* control,
FeedbackSlot slot) const;
// Potential reduction of property access operations.
Reduction ReduceLoadNamedOperation(const Operator* op, Node* obj,
Node* effect, Node* control,
......
......@@ -84,6 +84,7 @@ class V8_EXPORT_PRIVATE JSTypedLowering final
Reduction ReduceUI32Shift(Node* node, Signedness signedness);
Reduction ReduceCreateConsString(Node* node);
Reduction ReduceSpeculativeNumberAdd(Node* node);
Reduction ReduceSpeculativeNumberMultiply(Node* node);
Reduction ReduceSpeculativeNumberBinop(Node* node);
Reduction ReduceSpeculativeNumberComparison(Node* node);
......
......@@ -317,7 +317,8 @@ InductionVariable* LoopVariableOptimizer::TryGetInductionVariable(Node* phi) {
// TODO(jarin) Support both sides.
if (arith->InputAt(0) != phi) {
if (arith->InputAt(0)->opcode() != IrOpcode::kJSToNumber ||
if ((arith->InputAt(0)->opcode() != IrOpcode::kJSToNumber &&
arith->InputAt(0)->opcode() != IrOpcode::kSpeculativeToNumber) ||
arith->InputAt(0)->InputAt(0) != phi) {
return nullptr;
}
......
......@@ -301,6 +301,8 @@
V(NumberToUint8Clamped) \
V(NumberSilenceNaN)
#define SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) V(SpeculativeToNumber)
#define SIMPLIFIED_OTHER_OP_LIST(V) \
V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \
......@@ -356,6 +358,7 @@
SIMPLIFIED_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_NUMBER_UNOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) \
SIMPLIFIED_OTHER_OP_LIST(V)
// Opcodes for Machine-level operators.
......
......@@ -968,11 +968,11 @@ Type* OperationTyper::NumberPow(Type* lhs, Type* rhs) {
return Type::Number();
}
#define SPECULATIVE_NUMBER_BINOP(Name) \
Type* OperationTyper::Speculative##Name(Type* lhs, Type* rhs) { \
lhs = ToNumber(Type::Intersect(lhs, Type::NumberOrOddball(), zone())); \
rhs = ToNumber(Type::Intersect(rhs, Type::NumberOrOddball(), zone())); \
return Name(lhs, rhs); \
#define SPECULATIVE_NUMBER_BINOP(Name) \
Type* OperationTyper::Speculative##Name(Type* lhs, Type* rhs) { \
lhs = SpeculativeToNumber(lhs); \
rhs = SpeculativeToNumber(rhs); \
return Name(lhs, rhs); \
}
SPECULATIVE_NUMBER_BINOP(NumberAdd)
SPECULATIVE_NUMBER_BINOP(NumberSubtract)
......@@ -987,6 +987,10 @@ SPECULATIVE_NUMBER_BINOP(NumberShiftRight)
SPECULATIVE_NUMBER_BINOP(NumberShiftRightLogical)
#undef SPECULATIVE_NUMBER_BINOP
Type* OperationTyper::SpeculativeToNumber(Type* type) {
return ToNumber(Type::Intersect(type, Type::NumberOrOddball(), zone()));
}
Type* OperationTyper::ToPrimitive(Type* type) {
if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) {
return type;
......
......@@ -39,6 +39,7 @@ class V8_EXPORT_PRIVATE OperationTyper {
// Number unary operators.
#define DECLARE_METHOD(Name) Type* Name(Type* type);
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
// Number binary operators.
......
......@@ -454,6 +454,16 @@ class RepresentationSelector {
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(Name) \
case IrOpcode::k##Name: { \
new_type = \
Type::Intersect(op_typer_.Name(FeedbackTypeOf(node->InputAt(0))), \
info->restriction_type(), graph_zone()); \
break; \
}
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
case IrOpcode::kPlainPrimitiveToNumber:
new_type = op_typer_.ToNumber(FeedbackTypeOf(node->InputAt(0)));
break;
......@@ -840,11 +850,12 @@ class RepresentationSelector {
}
// Helper for unops of the I -> O variety.
void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output) {
void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output,
Type* restriction_type = Type::Any()) {
DCHECK_EQ(1, node->op()->ValueInputCount());
ProcessInput(node, 0, input_use);
ProcessRemainingInputs(node, 1);
SetOutput(node, output);
SetOutput(node, output, restriction_type);
}
// Helper for leaf nodes.
......@@ -2572,6 +2583,23 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kSpeculativeToNumber: {
NumberOperationHint const hint = NumberOperationHintOf(node->op());
switch (hint) {
case NumberOperationHint::kSigned32:
case NumberOperationHint::kSignedSmall:
VisitUnop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
break;
case NumberOperationHint::kNumber:
case NumberOperationHint::kNumberOrOddball:
VisitUnop(node, CheckedUseInfoAsFloat64FromHint(hint),
MachineRepresentation::kFloat64);
break;
}
if (lower()) DeferReplacement(node, node->InputAt(0));
return;
}
case IrOpcode::kObjectIsDetectableCallable: {
VisitObjectIs(node, Type::DetectableCallable(), lowering);
return;
......
......@@ -371,7 +371,8 @@ size_t hash_value(NumberOperationHint hint) {
}
NumberOperationHint NumberOperationHintOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberAdd ||
DCHECK(op->opcode() == IrOpcode::kSpeculativeToNumber ||
op->opcode() == IrOpcode::kSpeculativeNumberAdd ||
op->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
op->opcode() == IrOpcode::kSpeculativeNumberMultiply ||
op->opcode() == IrOpcode::kSpeculativeNumberDivide ||
......@@ -696,6 +697,26 @@ struct SimplifiedOperatorGlobalCache final {
SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
#undef SPECULATIVE_NUMBER_BINOP
template <NumberOperationHint kHint>
struct SpeculativeToNumberOperator final
: public Operator1<NumberOperationHint> {
SpeculativeToNumberOperator()
: Operator1<NumberOperationHint>(
IrOpcode::kSpeculativeToNumber, // opcode
Operator::kFoldable | Operator::kNoThrow, // flags
"SpeculativeToNumber", // name
1, 1, 1, 1, 1, 0, // counts
kHint) {} // parameter
};
SpeculativeToNumberOperator<NumberOperationHint::kSignedSmall>
kSpeculativeToNumberSignedSmallOperator;
SpeculativeToNumberOperator<NumberOperationHint::kSigned32>
kSpeculativeToNumberSigned32Operator;
SpeculativeToNumberOperator<NumberOperationHint::kNumber>
kSpeculativeToNumberNumberOperator;
SpeculativeToNumberOperator<NumberOperationHint::kNumberOrOddball>
kSpeculativeToNumberNumberOrOddballOperator;
#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
LoadBuffer##Type##Operator() \
......@@ -807,6 +828,22 @@ const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole(
return nullptr;
}
const Operator* SimplifiedOperatorBuilder::SpeculativeToNumber(
NumberOperationHint hint) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
return &cache_.kSpeculativeToNumberSignedSmallOperator;
case NumberOperationHint::kSigned32:
return &cache_.kSpeculativeToNumberSigned32Operator;
case NumberOperationHint::kNumber:
return &cache_.kSpeculativeToNumberNumberOperator;
case NumberOperationHint::kNumberOrOddball:
return &cache_.kSpeculativeToNumberNumberOrOddballOperator;
}
UNREACHABLE();
return nullptr;
}
const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() {
return &cache_.kEnsureWritableFastElements;
}
......
......@@ -381,6 +381,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringFromCodePoint(UnicodeEncoding encoding);
const Operator* StringIndexOf();
const Operator* SpeculativeToNumber(NumberOperationHint hint);
const Operator* PlainPrimitiveToNumber();
const Operator* PlainPrimitiveToWord32();
const Operator* PlainPrimitiveToFloat64();
......
......@@ -96,6 +96,8 @@ Reduction TypedOptimization::Reduce(Node* node) {
return ReduceReferenceEqual(node);
case IrOpcode::kSelect:
return ReduceSelect(node);
case IrOpcode::kSpeculativeToNumber:
return ReduceSpeculativeToNumber(node);
default:
break;
}
......@@ -311,6 +313,18 @@ Reduction TypedOptimization::ReduceSelect(Node* node) {
return NoChange();
}
Reduction TypedOptimization::ReduceSpeculativeToNumber(Node* node) {
DCHECK_EQ(IrOpcode::kSpeculativeToNumber, node->opcode());
Node* const input = NodeProperties::GetValueInput(node, 0);
Type* const input_type = NodeProperties::GetType(input);
if (input_type->Is(Type::Number())) {
// SpeculativeToNumber(x:number) => x
ReplaceWithValue(node, input);
return Replace(input);
}
return NoChange();
}
Factory* TypedOptimization::factory() const { return isolate()->factory(); }
Graph* TypedOptimization::graph() const { return jsgraph()->graph(); }
......
......@@ -52,6 +52,7 @@ class V8_EXPORT_PRIVATE TypedOptimization final
Reduction ReducePhi(Node* node);
Reduction ReduceReferenceEqual(Node* node);
Reduction ReduceSelect(Node* node);
Reduction ReduceSpeculativeToNumber(Node* node);
CompilationDependencies* dependencies() const { return dependencies_; }
Factory* factory() const;
......
......@@ -108,6 +108,7 @@ class Typer::Visitor : public Reducer {
case IrOpcode::k##x: \
return UpdateType(node, TypeUnaryOp(node, x));
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x:
......@@ -173,6 +174,7 @@ class Typer::Visitor : public Reducer {
case IrOpcode::k##x: \
return TypeUnaryOp(node, x);
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
#define DECLARE_CASE(x) case IrOpcode::k##x:
......@@ -274,6 +276,7 @@ class Typer::Visitor : public Reducer {
return t->operation_typer_.Name(type); \
}
SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_METHOD)
SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_METHOD)
#undef DECLARE_METHOD
#define DECLARE_METHOD(Name) \
static Type* Name(Type* lhs, Type* rhs, Typer* t) { \
......
......@@ -914,6 +914,11 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Unsigned32());
break;
case IrOpcode::kSpeculativeToNumber:
// Any -> Number
CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::Number());
break;
case IrOpcode::kPlainPrimitiveToNumber:
// PlainPrimitive -> Number
CheckValueInputIs(node, 0, Type::PlainPrimitive());
......
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