Commit 6a08d18d authored by Jaroslav Sevcik's avatar Jaroslav Sevcik Committed by Commit Bot

[turbofan] Better type and truncation for speculative additive ops.

This helps with patterns such as

((a[i] + n) + m) | 0

where we know n and m are small integers, and a[i] is a holey smi
array where we have never read a hole so far.

In that case, we still perform the additions with overflow checks
since we currently only propagate/use the truncation if the operation
outcome is in the safe-integer range (without taking feedback into
account).  The problem here is that both 'n + a[i]' and '(n + a[i]) +
m' have type Union(Range(..., ...), NaN), even though the NaN will
never pass the Smi check on a[i].

This CL changes restricts the static type of 
SpeculativeSafeInteger(Add|Subtract) to the safe integer range. 
This is safe because we will always either truncate or use the feedback
(i.e., deopt if the inputs are not Signed32).  In either case, the 
result will always be in safe-integer range.

As a result, we will perform the second addition without
overflow check. Getting rid of the overflow check on the first
is done in a separate CL.

Bug: v8:5267,v8:6764
Change-Id: I27dba0fda832fc1f04477db6dd3495d5b4b2bd0b
Reviewed-on: https://chromium-review.googlesource.com/634903
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47763}
parent d667bf4a
...@@ -599,6 +599,26 @@ Type* OperationTyper::NumberSubtract(Type* lhs, Type* rhs) { ...@@ -599,6 +599,26 @@ Type* OperationTyper::NumberSubtract(Type* lhs, Type* rhs) {
return type; return type;
} }
Type* OperationTyper::SpeculativeSafeIntegerAdd(Type* lhs, Type* rhs) {
Type* result = SpeculativeNumberAdd(lhs, rhs);
// If we have a Smi or Int32 feedback, the representation selection will
// either truncate or it will check the inputs (i.e., deopt if not int32).
// In either case the result will be in the safe integer range, so we
// can bake in the type here. This needs to be in sync with
// SimplifiedLowering::VisitSpeculativeAdditiveOp.
return Type::Intersect(result, cache_.kSafeInteger, zone());
}
Type* OperationTyper::SpeculativeSafeIntegerSubtract(Type* lhs, Type* rhs) {
Type* result = SpeculativeNumberSubtract(lhs, rhs);
// If we have a Smi or Int32 feedback, the representation selection will
// either truncate or it will check the inputs (i.e., deopt if not int32).
// In either case the result will be in the safe integer range, so we
// can bake in the type here. This needs to be in sync with
// SimplifiedLowering::VisitSpeculativeAdditiveOp.
return result = Type::Intersect(result, cache_.kSafeInteger, zone());
}
Type* OperationTyper::NumberMultiply(Type* lhs, Type* rhs) { Type* OperationTyper::NumberMultiply(Type* lhs, Type* rhs) {
DCHECK(lhs->Is(Type::Number())); DCHECK(lhs->Is(Type::Number()));
DCHECK(rhs->Is(Type::Number())); DCHECK(rhs->Is(Type::Number()));
...@@ -987,18 +1007,6 @@ SPECULATIVE_NUMBER_BINOP(NumberShiftRight) ...@@ -987,18 +1007,6 @@ SPECULATIVE_NUMBER_BINOP(NumberShiftRight)
SPECULATIVE_NUMBER_BINOP(NumberShiftRightLogical) SPECULATIVE_NUMBER_BINOP(NumberShiftRightLogical)
#undef SPECULATIVE_NUMBER_BINOP #undef SPECULATIVE_NUMBER_BINOP
Type* OperationTyper::SpeculativeSafeIntegerAdd(Type* lhs, Type* rhs) {
lhs = SpeculativeToNumber(lhs);
rhs = SpeculativeToNumber(rhs);
return NumberAdd(lhs, rhs);
}
Type* OperationTyper::SpeculativeSafeIntegerSubtract(Type* lhs, Type* rhs) {
lhs = SpeculativeToNumber(lhs);
rhs = SpeculativeToNumber(rhs);
return NumberSubtract(lhs, rhs);
}
Type* OperationTyper::SpeculativeToNumber(Type* type) { Type* OperationTyper::SpeculativeToNumber(Type* type) {
return ToNumber(Type::Intersect(type, Type::NumberOrOddball(), zone())); return ToNumber(Type::Intersect(type, Type::NumberOrOddball(), zone()));
} }
......
...@@ -1262,37 +1262,46 @@ class RepresentationSelector { ...@@ -1262,37 +1262,46 @@ class RepresentationSelector {
void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation, void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation,
SimplifiedLowering* lowering) { SimplifiedLowering* lowering) {
Type* left_upper = GetUpperBound(node->InputAt(0));
Type* right_upper = GetUpperBound(node->InputAt(1));
// Only eliminate eliminate the node if the ToNumber conversion cannot // Only eliminate eliminate the node if the ToNumber conversion cannot
// cause any observable side-effect and if we know for sure that it // cause any observable side-effect and if we know for sure that it
// is a number addition (we must exclude strings). // is a number addition (we must exclude strings).
if (BothInputsAre(node, Type::NumberOrOddball())) { if (left_upper->Is(Type::NumberOrOddball()) &&
right_upper->Is(Type::NumberOrOddball())) {
if (truncation.IsUnused()) return VisitUnused(node); if (truncation.IsUnused()) return VisitUnused(node);
} }
if (BothInputsAre(node, type_cache_.kAdditiveSafeIntegerOrMinusZero) && if (left_upper->Is(type_cache_.kAdditiveSafeIntegerOrMinusZero) &&
(GetUpperBound(node)->Is(Type::Signed32()) || right_upper->Is(type_cache_.kAdditiveSafeIntegerOrMinusZero)) {
// If we know how to interpret the result or if the users only care
// about the low 32-bits, we can truncate to Word32 do a wrapping
// addition.
if (GetUpperBound(node)->Is(Type::Signed32()) ||
GetUpperBound(node)->Is(Type::Unsigned32()) || GetUpperBound(node)->Is(Type::Unsigned32()) ||
truncation.IsUsedAsWord32())) { truncation.IsUsedAsWord32()) {
// => Int32Add/Sub // => Int32Add/Sub
VisitWord32TruncatingBinop(node); VisitWord32TruncatingBinop(node);
if (lower()) ChangeToPureOp(node, Int32Op(node)); if (lower()) ChangeToPureOp(node, Int32Op(node));
return; return;
} }
}
// Try to use type feedback. // Try to use type feedback.
NumberOperationHint hint = NumberOperationHintOf(node->op()); NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == NumberOperationHint::kSignedSmall || DCHECK(hint == NumberOperationHint::kSignedSmall ||
hint == NumberOperationHint::kSigned32) { hint == NumberOperationHint::kSigned32);
Type* left_feedback_type = TypeOf(node->InputAt(0)); Type* left_feedback_type = TypeOf(node->InputAt(0));
Type* right_feedback_type = TypeOf(node->InputAt(1)); Type* right_feedback_type = TypeOf(node->InputAt(1));
// Handle the case when no int32 checks on inputs are necessary (but // Handle the case when no int32 checks on inputs are necessary (but
// an overflow check is needed on the output). // an overflow check is needed on the output). Note that we do not
// TODO(jarin) We should not look at the upper bound because the typer // have to do any check if at most one side can be minus zero.
// could have already baked in some feedback into the upper bound. if (left_upper->Is(Type::Signed32OrMinusZero()) &&
if (BothInputsAre(node, Type::Signed32()) || right_upper->Is(Type::Signed32OrMinusZero()) &&
(BothInputsAre(node, Type::Signed32OrMinusZero()) && (left_upper->Is(Type::Signed32()) ||
GetUpperBound(node)->Is(type_cache_.kSafeInteger))) { right_upper->Is(Type::Signed32()))) {
VisitBinop(node, UseInfo::TruncatingWord32(), VisitBinop(node, UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32, Type::Signed32()); MachineRepresentation::kWord32, Type::Signed32());
} else { } else {
...@@ -1311,8 +1320,7 @@ class RepresentationSelector { ...@@ -1311,8 +1320,7 @@ class RepresentationSelector {
// a minus zero check for the right hand side, since we already // a minus zero check for the right hand side, since we already
// know that the left hand side is a proper Signed32 value, // know that the left hand side is a proper Signed32 value,
// potentially guarded by a check. // potentially guarded by a check.
UseInfo right_use = UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros);
CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros);
VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32, VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32,
Type::Signed32()); Type::Signed32());
} }
...@@ -1329,15 +1337,6 @@ class RepresentationSelector { ...@@ -1329,15 +1337,6 @@ class RepresentationSelector {
return; return;
} }
// default case => Float64Add/Sub
VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
MachineRepresentation::kFloat64, Type::Number());
if (lower()) {
ChangeToPureOp(node, Float64Op(node));
}
return;
}
void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation, void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
SimplifiedLowering* lowering) { SimplifiedLowering* lowering) {
// ToNumber(x) can throw if x is either a Receiver or a Symbol, so we can // ToNumber(x) can throw if x is either a Receiver or a Symbol, so we can
......
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