[turbofan] Collect and use SignedSmall input feedback for Divide.
For Divide operations like r = a / b where r has only truncated uses (i.e. only used in bitwise operations), we used to generate a Float64Div unless we statically knew something about a and b, even if a and b have always been integers so far. Crankshaft was able to generate an integer division here, because Fullcodegen collected feedback independently for inputs and outputs of binary operations. This adds new BinaryOperationFeedback::kSignedSmallInputs, which is used specifically for Divide to state that we have seen only SignedSmall inputs thus far, but the outputs weren't always in the SignedSmall range. The issue was discovered in a WebGL Triangulation library and reported via https://twitter.com/mourner/status/895708603117518848 after Node 8.3.0 was released with I+TF. R=jarin@chromium.org Bug: v8:6698 Change-Id: I830e421a3bf91fc8fa3665cbb706bc13675a6d2b Reviewed-on: https://chromium-review.googlesource.com/612063 Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org> Cr-Commit-Position: refs/heads/master@{#47302}
This commit is contained in:
parent
f984eb1bbb
commit
622852e5a6
@ -599,6 +599,8 @@ struct JSOperatorGlobalCache final {
|
|||||||
Name##Operator<BinaryOperationHint::kNone> k##Name##NoneOperator; \
|
Name##Operator<BinaryOperationHint::kNone> k##Name##NoneOperator; \
|
||||||
Name##Operator<BinaryOperationHint::kSignedSmall> \
|
Name##Operator<BinaryOperationHint::kSignedSmall> \
|
||||||
k##Name##SignedSmallOperator; \
|
k##Name##SignedSmallOperator; \
|
||||||
|
Name##Operator<BinaryOperationHint::kSignedSmallInputs> \
|
||||||
|
k##Name##SignedSmallInputsOperator; \
|
||||||
Name##Operator<BinaryOperationHint::kSigned32> k##Name##Signed32Operator; \
|
Name##Operator<BinaryOperationHint::kSigned32> k##Name##Signed32Operator; \
|
||||||
Name##Operator<BinaryOperationHint::kNumber> k##Name##NumberOperator; \
|
Name##Operator<BinaryOperationHint::kNumber> k##Name##NumberOperator; \
|
||||||
Name##Operator<BinaryOperationHint::kNumberOrOddball> \
|
Name##Operator<BinaryOperationHint::kNumberOrOddball> \
|
||||||
@ -652,6 +654,8 @@ CACHED_OP_LIST(CACHED_OP)
|
|||||||
return &cache_.k##Name##NoneOperator; \
|
return &cache_.k##Name##NoneOperator; \
|
||||||
case BinaryOperationHint::kSignedSmall: \
|
case BinaryOperationHint::kSignedSmall: \
|
||||||
return &cache_.k##Name##SignedSmallOperator; \
|
return &cache_.k##Name##SignedSmallOperator; \
|
||||||
|
case BinaryOperationHint::kSignedSmallInputs: \
|
||||||
|
return &cache_.k##Name##SignedSmallInputsOperator; \
|
||||||
case BinaryOperationHint::kSigned32: \
|
case BinaryOperationHint::kSigned32: \
|
||||||
return &cache_.k##Name##Signed32Operator; \
|
return &cache_.k##Name##Signed32Operator; \
|
||||||
case BinaryOperationHint::kNumber: \
|
case BinaryOperationHint::kNumber: \
|
||||||
|
@ -22,6 +22,9 @@ bool BinaryOperationHintToNumberOperationHint(
|
|||||||
case BinaryOperationHint::kSignedSmall:
|
case BinaryOperationHint::kSignedSmall:
|
||||||
*number_hint = NumberOperationHint::kSignedSmall;
|
*number_hint = NumberOperationHint::kSignedSmall;
|
||||||
return true;
|
return true;
|
||||||
|
case BinaryOperationHint::kSignedSmallInputs:
|
||||||
|
*number_hint = NumberOperationHint::kSignedSmallInputs;
|
||||||
|
return true;
|
||||||
case BinaryOperationHint::kSigned32:
|
case BinaryOperationHint::kSigned32:
|
||||||
*number_hint = NumberOperationHint::kSigned32;
|
*number_hint = NumberOperationHint::kSigned32;
|
||||||
return true;
|
return true;
|
||||||
|
@ -91,6 +91,7 @@ UseInfo CheckedUseInfoAsWord32FromHint(
|
|||||||
IdentifyZeros identify_zeros = kDistinguishZeros) {
|
IdentifyZeros identify_zeros = kDistinguishZeros) {
|
||||||
switch (hint) {
|
switch (hint) {
|
||||||
case NumberOperationHint::kSignedSmall:
|
case NumberOperationHint::kSignedSmall:
|
||||||
|
case NumberOperationHint::kSignedSmallInputs:
|
||||||
return UseInfo::CheckedSignedSmallAsWord32(identify_zeros);
|
return UseInfo::CheckedSignedSmallAsWord32(identify_zeros);
|
||||||
case NumberOperationHint::kSigned32:
|
case NumberOperationHint::kSigned32:
|
||||||
return UseInfo::CheckedSigned32AsWord32(identify_zeros);
|
return UseInfo::CheckedSigned32AsWord32(identify_zeros);
|
||||||
@ -105,6 +106,7 @@ UseInfo CheckedUseInfoAsWord32FromHint(
|
|||||||
UseInfo CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint) {
|
UseInfo CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint) {
|
||||||
switch (hint) {
|
switch (hint) {
|
||||||
case NumberOperationHint::kSignedSmall:
|
case NumberOperationHint::kSignedSmall:
|
||||||
|
case NumberOperationHint::kSignedSmallInputs:
|
||||||
case NumberOperationHint::kSigned32:
|
case NumberOperationHint::kSigned32:
|
||||||
// Not used currently.
|
// Not used currently.
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1654,8 +1656,8 @@ class RepresentationSelector {
|
|||||||
// Try to use type feedback.
|
// Try to use type feedback.
|
||||||
NumberOperationHint hint = NumberOperationHintOf(node->op());
|
NumberOperationHint hint = NumberOperationHintOf(node->op());
|
||||||
switch (hint) {
|
switch (hint) {
|
||||||
|
case NumberOperationHint::kSigned32:
|
||||||
case NumberOperationHint::kSignedSmall:
|
case NumberOperationHint::kSignedSmall:
|
||||||
case NumberOperationHint::kSigned32: {
|
|
||||||
if (propagate()) {
|
if (propagate()) {
|
||||||
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
|
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
|
||||||
MachineRepresentation::kBit);
|
MachineRepresentation::kBit);
|
||||||
@ -1679,7 +1681,9 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
case NumberOperationHint::kSignedSmallInputs:
|
||||||
|
// This doesn't make sense for compare operations.
|
||||||
|
UNREACHABLE();
|
||||||
case NumberOperationHint::kNumberOrOddball:
|
case NumberOperationHint::kNumberOrOddball:
|
||||||
// Abstract and strict equality don't perform ToNumber conversions
|
// Abstract and strict equality don't perform ToNumber conversions
|
||||||
// on Oddballs, so make sure we don't accidentially sneak in a
|
// on Oddballs, so make sure we don't accidentially sneak in a
|
||||||
@ -1850,20 +1854,22 @@ class RepresentationSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hint == NumberOperationHint::kSignedSmall ||
|
if (hint == NumberOperationHint::kSigned32 ||
|
||||||
hint == NumberOperationHint::kSigned32) {
|
hint == NumberOperationHint::kSignedSmall ||
|
||||||
|
hint == NumberOperationHint::kSignedSmallInputs) {
|
||||||
// If the result is truncated, we only need to check the inputs.
|
// If the result is truncated, we only need to check the inputs.
|
||||||
if (truncation.IsUsedAsWord32()) {
|
if (truncation.IsUsedAsWord32()) {
|
||||||
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
|
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
|
||||||
MachineRepresentation::kWord32);
|
MachineRepresentation::kWord32);
|
||||||
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
|
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
|
||||||
} else {
|
return;
|
||||||
|
} else if (hint != NumberOperationHint::kSignedSmallInputs) {
|
||||||
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
|
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
|
||||||
MachineRepresentation::kWord32, Type::Signed32());
|
MachineRepresentation::kWord32, Type::Signed32());
|
||||||
if (lower()) ChangeToInt32OverflowOp(node);
|
if (lower()) ChangeToInt32OverflowOp(node);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// default case => Float64Div
|
// default case => Float64Div
|
||||||
VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
|
VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
|
||||||
@ -2656,6 +2662,7 @@ class RepresentationSelector {
|
|||||||
switch (hint) {
|
switch (hint) {
|
||||||
case NumberOperationHint::kSigned32:
|
case NumberOperationHint::kSigned32:
|
||||||
case NumberOperationHint::kSignedSmall:
|
case NumberOperationHint::kSignedSmall:
|
||||||
|
case NumberOperationHint::kSignedSmallInputs:
|
||||||
VisitUnop(node, CheckedUseInfoAsWord32FromHint(hint),
|
VisitUnop(node, CheckedUseInfoAsWord32FromHint(hint),
|
||||||
MachineRepresentation::kWord32, Type::Signed32());
|
MachineRepresentation::kWord32, Type::Signed32());
|
||||||
break;
|
break;
|
||||||
|
@ -401,6 +401,8 @@ std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) {
|
|||||||
switch (hint) {
|
switch (hint) {
|
||||||
case NumberOperationHint::kSignedSmall:
|
case NumberOperationHint::kSignedSmall:
|
||||||
return os << "SignedSmall";
|
return os << "SignedSmall";
|
||||||
|
case NumberOperationHint::kSignedSmallInputs:
|
||||||
|
return os << "SignedSmallInputs";
|
||||||
case NumberOperationHint::kSigned32:
|
case NumberOperationHint::kSigned32:
|
||||||
return os << "Signed32";
|
return os << "Signed32";
|
||||||
case NumberOperationHint::kNumber:
|
case NumberOperationHint::kNumber:
|
||||||
@ -780,6 +782,8 @@ struct SimplifiedOperatorGlobalCache final {
|
|||||||
}; \
|
}; \
|
||||||
Name##Operator<NumberOperationHint::kSignedSmall> \
|
Name##Operator<NumberOperationHint::kSignedSmall> \
|
||||||
k##Name##SignedSmallOperator; \
|
k##Name##SignedSmallOperator; \
|
||||||
|
Name##Operator<NumberOperationHint::kSignedSmallInputs> \
|
||||||
|
k##Name##SignedSmallInputsOperator; \
|
||||||
Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \
|
Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \
|
||||||
Name##Operator<NumberOperationHint::kNumber> k##Name##NumberOperator; \
|
Name##Operator<NumberOperationHint::kNumber> k##Name##NumberOperator; \
|
||||||
Name##Operator<NumberOperationHint::kNumberOrOddball> \
|
Name##Operator<NumberOperationHint::kNumberOrOddball> \
|
||||||
@ -940,6 +944,8 @@ const Operator* SimplifiedOperatorBuilder::SpeculativeToNumber(
|
|||||||
switch (hint) {
|
switch (hint) {
|
||||||
case NumberOperationHint::kSignedSmall:
|
case NumberOperationHint::kSignedSmall:
|
||||||
return &cache_.kSpeculativeToNumberSignedSmallOperator;
|
return &cache_.kSpeculativeToNumberSignedSmallOperator;
|
||||||
|
case NumberOperationHint::kSignedSmallInputs:
|
||||||
|
break;
|
||||||
case NumberOperationHint::kSigned32:
|
case NumberOperationHint::kSigned32:
|
||||||
return &cache_.kSpeculativeToNumberSigned32Operator;
|
return &cache_.kSpeculativeToNumberSigned32Operator;
|
||||||
case NumberOperationHint::kNumber:
|
case NumberOperationHint::kNumber:
|
||||||
@ -1067,6 +1073,8 @@ const Operator* SimplifiedOperatorBuilder::StringFromCodePoint(
|
|||||||
switch (hint) { \
|
switch (hint) { \
|
||||||
case NumberOperationHint::kSignedSmall: \
|
case NumberOperationHint::kSignedSmall: \
|
||||||
return &cache_.k##Name##SignedSmallOperator; \
|
return &cache_.k##Name##SignedSmallOperator; \
|
||||||
|
case NumberOperationHint::kSignedSmallInputs: \
|
||||||
|
return &cache_.k##Name##SignedSmallInputsOperator; \
|
||||||
case NumberOperationHint::kSigned32: \
|
case NumberOperationHint::kSigned32: \
|
||||||
return &cache_.k##Name##Signed32Operator; \
|
return &cache_.k##Name##Signed32Operator; \
|
||||||
case NumberOperationHint::kNumber: \
|
case NumberOperationHint::kNumber: \
|
||||||
|
@ -234,8 +234,9 @@ Handle<Map> FastMapParameterOf(const Operator* op);
|
|||||||
|
|
||||||
// A hint for speculative number operations.
|
// A hint for speculative number operations.
|
||||||
enum class NumberOperationHint : uint8_t {
|
enum class NumberOperationHint : uint8_t {
|
||||||
kSignedSmall, // Inputs were always Smi so far, output was in Smi range.
|
kSignedSmall, // Inputs were Smi, output was in Smi.
|
||||||
kSigned32, // Inputs and output were Signed32 so far.
|
kSignedSmallInputs, // Inputs were Smi, output was Number.
|
||||||
|
kSigned32, // Inputs were Signed32, output was Number.
|
||||||
kNumber, // Inputs were Number, output was Number.
|
kNumber, // Inputs were Number, output was Number.
|
||||||
kNumberOrOddball, // Inputs were Number or Oddball, output was Number.
|
kNumberOrOddball, // Inputs were Number or Oddball, output was Number.
|
||||||
};
|
};
|
||||||
|
@ -181,6 +181,8 @@ BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
|
|||||||
return BinaryOperationHint::kNone;
|
return BinaryOperationHint::kNone;
|
||||||
case BinaryOperationFeedback::kSignedSmall:
|
case BinaryOperationFeedback::kSignedSmall:
|
||||||
return BinaryOperationHint::kSignedSmall;
|
return BinaryOperationHint::kSignedSmall;
|
||||||
|
case BinaryOperationFeedback::kSignedSmallInputs:
|
||||||
|
return BinaryOperationHint::kSignedSmallInputs;
|
||||||
case BinaryOperationFeedback::kNumber:
|
case BinaryOperationFeedback::kNumber:
|
||||||
return BinaryOperationHint::kNumber;
|
return BinaryOperationHint::kNumber;
|
||||||
case BinaryOperationFeedback::kNumberOrOddball:
|
case BinaryOperationFeedback::kNumberOrOddball:
|
||||||
|
@ -1254,7 +1254,7 @@ inline uint32_t ObjectHash(Address address) {
|
|||||||
// Type feedback is encoded in such a way that, we can combine the feedback
|
// Type feedback is encoded in such a way that, we can combine the feedback
|
||||||
// at different points by performing an 'OR' operation. Type feedback moves
|
// at different points by performing an 'OR' operation. Type feedback moves
|
||||||
// to a more generic type when we combine feedback.
|
// to a more generic type when we combine feedback.
|
||||||
// kSignedSmall -> kNumber -> kNumberOrOddball -> kAny
|
// kSignedSmall -> kSignedSmallInputs -> kNumber -> kNumberOrOddball -> kAny
|
||||||
// kString -> kAny
|
// kString -> kAny
|
||||||
// TODO(mythria): Remove kNumber type when crankshaft can handle Oddballs
|
// TODO(mythria): Remove kNumber type when crankshaft can handle Oddballs
|
||||||
// similar to Numbers. We don't need kNumber feedback for Turbofan. Extra
|
// similar to Numbers. We don't need kNumber feedback for Turbofan. Extra
|
||||||
@ -1266,10 +1266,11 @@ class BinaryOperationFeedback {
|
|||||||
enum {
|
enum {
|
||||||
kNone = 0x0,
|
kNone = 0x0,
|
||||||
kSignedSmall = 0x1,
|
kSignedSmall = 0x1,
|
||||||
kNumber = 0x3,
|
kSignedSmallInputs = 0x3,
|
||||||
kNumberOrOddball = 0x7,
|
kNumber = 0x7,
|
||||||
kString = 0x8,
|
kNumberOrOddball = 0xF,
|
||||||
kAny = 0x1F
|
kString = 0x10,
|
||||||
|
kAny = 0x3F
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -463,7 +463,8 @@ Node* BinaryOpAssembler::Generate_DivideWithFeedback(
|
|||||||
|
|
||||||
BIND(&bailout);
|
BIND(&bailout);
|
||||||
{
|
{
|
||||||
var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kNumber));
|
var_type_feedback->Bind(
|
||||||
|
SmiConstant(BinaryOperationFeedback::kSignedSmallInputs));
|
||||||
Node* value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
|
Node* value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
|
||||||
var_result.Bind(AllocateHeapNumberWithValue(value));
|
var_result.Bind(AllocateHeapNumberWithValue(value));
|
||||||
Goto(&end);
|
Goto(&end);
|
||||||
|
@ -13,6 +13,8 @@ std::ostream& operator<<(std::ostream& os, BinaryOperationHint hint) {
|
|||||||
return os << "None";
|
return os << "None";
|
||||||
case BinaryOperationHint::kSignedSmall:
|
case BinaryOperationHint::kSignedSmall:
|
||||||
return os << "SignedSmall";
|
return os << "SignedSmall";
|
||||||
|
case BinaryOperationHint::kSignedSmallInputs:
|
||||||
|
return os << "SignedSmallInputs";
|
||||||
case BinaryOperationHint::kSigned32:
|
case BinaryOperationHint::kSigned32:
|
||||||
return os << "Signed32";
|
return os << "Signed32";
|
||||||
case BinaryOperationHint::kNumber:
|
case BinaryOperationHint::kNumber:
|
||||||
|
@ -15,6 +15,7 @@ namespace internal {
|
|||||||
enum class BinaryOperationHint : uint8_t {
|
enum class BinaryOperationHint : uint8_t {
|
||||||
kNone,
|
kNone,
|
||||||
kSignedSmall,
|
kSignedSmall,
|
||||||
|
kSignedSmallInputs,
|
||||||
kSigned32,
|
kSigned32,
|
||||||
kNumber,
|
kNumber,
|
||||||
kNumberOrOddball,
|
kNumberOrOddball,
|
||||||
|
@ -620,7 +620,7 @@ TEST(InterpreterBinaryOpTypeFeedback) {
|
|||||||
BinaryOperationFeedback::kSignedSmall},
|
BinaryOperationFeedback::kSignedSmall},
|
||||||
{Token::Value::DIV, ast_factory.NewSmi(3), ast_factory.NewSmi(2),
|
{Token::Value::DIV, ast_factory.NewSmi(3), ast_factory.NewSmi(2),
|
||||||
isolate->factory()->NewHeapNumber(3.0 / 2.0),
|
isolate->factory()->NewHeapNumber(3.0 / 2.0),
|
||||||
BinaryOperationFeedback::kNumber},
|
BinaryOperationFeedback::kSignedSmallInputs},
|
||||||
{Token::Value::DIV, ast_factory.NewNumber(3.1415), ast_factory.NewSmi(3),
|
{Token::Value::DIV, ast_factory.NewNumber(3.1415), ast_factory.NewSmi(3),
|
||||||
isolate->factory()->NewHeapNumber(3.1415 / 3),
|
isolate->factory()->NewHeapNumber(3.1415 / 3),
|
||||||
BinaryOperationFeedback::kNumber},
|
BinaryOperationFeedback::kNumber},
|
||||||
|
Loading…
Reference in New Issue
Block a user