[turbofan] Properly support Number feedback for binary operators.

Previously Ignition would collect precise Number feedback for binary
operators, but TurboFan would just ignore that and treat it the same as
NumberOrOddball. That however generates a lot of unnecessary code, plus
it defeats redundancy elimination if the same input is also used by
compare operations, which do properly distinguish feedback Number and
NumberOrOddball.

This CL adds the missing bits to connect the existing functionality
properly, i.e. adding the missing BinaryOperationHint and using the
NumberOperationHint::kNumber in the representation selection for tagged
inputs.

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2923543003
Cr-Commit-Position: refs/heads/master@{#45732}
This commit is contained in:
bmeurer 2017-06-06 07:06:11 -07:00 committed by Commit Bot
parent bdf0ea99df
commit 8a15026270
11 changed files with 88 additions and 51 deletions

View File

@ -1811,6 +1811,7 @@ Node* EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node) {
Node* EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(
Node* node, Node* frame_state) {
CheckTaggedInputMode mode = CheckTaggedInputModeOf(node->op());
Node* value = node->InputAt(0);
auto if_not_smi = __ MakeLabel<1>();
@ -1824,8 +1825,8 @@ Node* EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(
// Otherwise, check that it's a heap number or oddball and truncate the value
// to int32.
__ Bind(&if_not_smi);
Node* number = BuildCheckedHeapNumberOrOddballToFloat64(
CheckTaggedInputMode::kNumberOrOddball, value, frame_state);
Node* number =
BuildCheckedHeapNumberOrOddballToFloat64(mode, value, frame_state);
number = __ TruncateFloat64ToWord32(number);
__ Goto(&done, number);

View File

@ -643,6 +643,7 @@ struct JSOperatorGlobalCache final {
Name##Operator<BinaryOperationHint::kSignedSmall> \
k##Name##SignedSmallOperator; \
Name##Operator<BinaryOperationHint::kSigned32> k##Name##Signed32Operator; \
Name##Operator<BinaryOperationHint::kNumber> k##Name##NumberOperator; \
Name##Operator<BinaryOperationHint::kNumberOrOddball> \
k##Name##NumberOrOddballOperator; \
Name##Operator<BinaryOperationHint::kString> k##Name##StringOperator; \
@ -696,6 +697,8 @@ CACHED_OP_LIST(CACHED_OP)
return &cache_.k##Name##SignedSmallOperator; \
case BinaryOperationHint::kSigned32: \
return &cache_.k##Name##Signed32Operator; \
case BinaryOperationHint::kNumber: \
return &cache_.k##Name##NumberOperator; \
case BinaryOperationHint::kNumberOrOddball: \
return &cache_.k##Name##NumberOrOddballOperator; \
case BinaryOperationHint::kString: \

View File

@ -25,6 +25,9 @@ bool BinaryOperationHintToNumberOperationHint(
case BinaryOperationHint::kSigned32:
*number_hint = NumberOperationHint::kSigned32;
return true;
case BinaryOperationHint::kNumber:
*number_hint = NumberOperationHint::kNumber;
return true;
case BinaryOperationHint::kNumberOrOddball:
*number_hint = NumberOperationHint::kNumberOrOddball;
return true;

View File

@ -533,7 +533,8 @@ JSTypedLowering::JSTypedLowering(Editor* editor,
Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
JSBinopReduction r(this, node);
NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == NumberOperationHint::kNumberOrOddball &&
if ((hint == NumberOperationHint::kNumber ||
hint == NumberOperationHint::kNumberOrOddball) &&
r.BothInputsAre(Type::PlainPrimitive()) &&
r.NeitherInputCanBe(Type::StringOrReceiver())) {
// SpeculativeNumberAdd(x:-string, y:-string) =>
@ -621,7 +622,8 @@ Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
JSBinopReduction r(this, node);
NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == NumberOperationHint::kNumberOrOddball &&
if ((hint == NumberOperationHint::kNumber ||
hint == NumberOperationHint::kNumberOrOddball) &&
r.BothInputsAre(Type::NumberOrOddball())) {
r.ConvertInputsToNumber();
return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),

View File

@ -674,22 +674,11 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord32);
}
} else if (output_rep == MachineRepresentation::kTaggedSigned) {
if (output_type->Is(Type::Signed32())) {
} else if (IsAnyTagged(output_rep)) {
if (output_rep == MachineRepresentation::kTaggedSigned &&
output_type->Is(Type::SignedSmall())) {
op = simplified()->ChangeTaggedSignedToInt32();
} else if (use_info.truncation().IsUsedAsWord32()) {
if (use_info.type_check() != TypeCheckKind::kNone) {
op = simplified()->CheckedTruncateTaggedToWord32();
} else {
op = simplified()->TruncateTaggedToWord32();
}
} else {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord32);
}
} else if (output_rep == MachineRepresentation::kTagged ||
output_rep == MachineRepresentation::kTaggedPointer) {
if (output_type->Is(Type::Signed32())) {
} else if (output_type->Is(Type::Signed32())) {
op = simplified()->ChangeTaggedToInt32();
} else if (use_info.type_check() == TypeCheckKind::kSignedSmall) {
op = simplified()->CheckedTaggedSignedToInt32();
@ -703,8 +692,12 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
} else if (use_info.truncation().IsUsedAsWord32()) {
if (output_type->Is(Type::NumberOrOddball())) {
op = simplified()->TruncateTaggedToWord32();
} else if (use_info.type_check() != TypeCheckKind::kNone) {
op = simplified()->CheckedTruncateTaggedToWord32();
} else if (use_info.type_check() == TypeCheckKind::kNumber) {
op = simplified()->CheckedTruncateTaggedToWord32(
CheckTaggedInputMode::kNumber);
} else if (use_info.type_check() == TypeCheckKind::kNumberOrOddball) {
op = simplified()->CheckedTruncateTaggedToWord32(
CheckTaggedInputMode::kNumberOrOddball);
} else {
return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord32);
@ -726,8 +719,8 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
return TypeError(node, output_rep, output_type,
MachineRepresentation::kWord32);
}
} else {
DCHECK_EQ(TypeCheckKind::kNumberOrOddball, use_info.type_check());
} else if (use_info.type_check() == TypeCheckKind::kNumber ||
use_info.type_check() == TypeCheckKind::kNumberOrOddball) {
return node;
}
} else if (output_rep == MachineRepresentation::kWord8 ||

View File

@ -284,7 +284,8 @@ std::ostream& operator<<(std::ostream& os, CheckTaggedInputMode mode) {
}
CheckTaggedInputMode CheckTaggedInputModeOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kCheckedTaggedToFloat64, op->opcode());
DCHECK(op->opcode() == IrOpcode::kCheckedTaggedToFloat64 ||
op->opcode() == IrOpcode::kCheckedTruncateTaggedToWord32);
return OpParameter<CheckTaggedInputMode>(op);
}
@ -514,32 +515,31 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(SpeculativeNumberLessThan) \
V(SpeculativeNumberLessThanOrEqual)
#define CHECKED_OP_LIST(V) \
V(CheckBounds, 2, 1) \
V(CheckHeapObject, 1, 1) \
V(CheckIf, 1, 0) \
V(CheckInternalizedString, 1, 1) \
V(CheckNumber, 1, 1) \
V(CheckReceiver, 1, 1) \
V(CheckSmi, 1, 1) \
V(CheckString, 1, 1) \
V(CheckSeqString, 1, 1) \
V(CheckSymbol, 1, 1) \
V(CheckTaggedHole, 1, 0) \
V(CheckNotTaggedHole, 1, 0) \
V(CheckedInt32Add, 2, 1) \
V(CheckedInt32Sub, 2, 1) \
V(CheckedInt32Div, 2, 1) \
V(CheckedInt32Mod, 2, 1) \
V(CheckedUint32Div, 2, 1) \
V(CheckedUint32Mod, 2, 1) \
V(CheckedUint32ToInt32, 1, 1) \
V(CheckedUint32ToTaggedSigned, 1, 1) \
V(CheckedInt32ToTaggedSigned, 1, 1) \
V(CheckedTaggedSignedToInt32, 1, 1) \
V(CheckedTaggedToTaggedSigned, 1, 1) \
V(CheckedTaggedToTaggedPointer, 1, 1) \
V(CheckedTruncateTaggedToWord32, 1, 1)
#define CHECKED_OP_LIST(V) \
V(CheckBounds, 2, 1) \
V(CheckHeapObject, 1, 1) \
V(CheckIf, 1, 0) \
V(CheckInternalizedString, 1, 1) \
V(CheckNumber, 1, 1) \
V(CheckReceiver, 1, 1) \
V(CheckSmi, 1, 1) \
V(CheckString, 1, 1) \
V(CheckSeqString, 1, 1) \
V(CheckSymbol, 1, 1) \
V(CheckTaggedHole, 1, 0) \
V(CheckNotTaggedHole, 1, 0) \
V(CheckedInt32Add, 2, 1) \
V(CheckedInt32Sub, 2, 1) \
V(CheckedInt32Div, 2, 1) \
V(CheckedInt32Mod, 2, 1) \
V(CheckedUint32Div, 2, 1) \
V(CheckedUint32Mod, 2, 1) \
V(CheckedUint32ToInt32, 1, 1) \
V(CheckedUint32ToTaggedSigned, 1, 1) \
V(CheckedInt32ToTaggedSigned, 1, 1) \
V(CheckedTaggedSignedToInt32, 1, 1) \
V(CheckedTaggedToTaggedSigned, 1, 1) \
V(CheckedTaggedToTaggedPointer, 1, 1)
struct SimplifiedOperatorGlobalCache final {
#define PURE(Name, properties, value_input_count, control_input_count) \
@ -666,6 +666,20 @@ struct SimplifiedOperatorGlobalCache final {
CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrOddball>
kCheckedTaggedToFloat64NumberOrOddballOperator;
template <CheckTaggedInputMode kMode>
struct CheckedTruncateTaggedToWord32Operator final
: public Operator1<CheckTaggedInputMode> {
CheckedTruncateTaggedToWord32Operator()
: Operator1<CheckTaggedInputMode>(
IrOpcode::kCheckedTruncateTaggedToWord32,
Operator::kFoldable | Operator::kNoThrow,
"CheckedTruncateTaggedToWord32", 1, 1, 1, 1, 1, 0, kMode) {}
};
CheckedTruncateTaggedToWord32Operator<CheckTaggedInputMode::kNumber>
kCheckedTruncateTaggedToWord32NumberOperator;
CheckedTruncateTaggedToWord32Operator<CheckTaggedInputMode::kNumberOrOddball>
kCheckedTruncateTaggedToWord32NumberOrOddballOperator;
template <CheckFloat64HoleMode kMode>
struct CheckFloat64HoleNaNOperator final
: public Operator1<CheckFloat64HoleMode> {
@ -822,6 +836,17 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64(
UNREACHABLE();
}
const Operator* SimplifiedOperatorBuilder::CheckedTruncateTaggedToWord32(
CheckTaggedInputMode mode) {
switch (mode) {
case CheckTaggedInputMode::kNumber:
return &cache_.kCheckedTruncateTaggedToWord32NumberOperator;
case CheckTaggedInputMode::kNumberOrOddball:
return &cache_.kCheckedTruncateTaggedToWord32NumberOrOddballOperator;
}
UNREACHABLE();
}
const Operator* SimplifiedOperatorBuilder::CheckMaps(CheckMapsFlags flags,
ZoneHandleSet<Map> maps) {
CheckMapsParameters const parameters(flags, maps);

View File

@ -435,7 +435,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* CheckedTaggedToFloat64(CheckTaggedInputMode);
const Operator* CheckedTaggedToTaggedSigned();
const Operator* CheckedTaggedToTaggedPointer();
const Operator* CheckedTruncateTaggedToWord32();
const Operator* CheckedTruncateTaggedToWord32(CheckTaggedInputMode);
const Operator* CheckFloat64Hole(CheckFloat64HoleMode);
const Operator* CheckTaggedHole();

View File

@ -147,6 +147,7 @@ BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
case BinaryOperationFeedback::kSignedSmall:
return BinaryOperationHint::kSignedSmall;
case BinaryOperationFeedback::kNumber:
return BinaryOperationHint::kNumber;
case BinaryOperationFeedback::kNumberOrOddball:
return BinaryOperationHint::kNumberOrOddball;
case BinaryOperationFeedback::kString:

View File

@ -15,6 +15,8 @@ std::ostream& operator<<(std::ostream& os, BinaryOperationHint hint) {
return os << "SignedSmall";
case BinaryOperationHint::kSigned32:
return os << "Signed32";
case BinaryOperationHint::kNumber:
return os << "Number";
case BinaryOperationHint::kNumberOrOddball:
return os << "NumberOrOddball";
case BinaryOperationHint::kString:

View File

@ -16,6 +16,7 @@ enum class BinaryOperationHint : uint8_t {
kNone,
kSignedSmall,
kSigned32,
kNumber,
kNumberOrOddball,
kString,
kAny

View File

@ -9,6 +9,7 @@
foo(1.1, 0.1);
foo(0.1, 1.1);
foo(true, false);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
@ -33,6 +34,7 @@
foo(1.1, 0.1);
foo(0.1, 1.1);
foo(true, false);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
@ -57,6 +59,7 @@
foo(1.1, 0.1);
foo(0.1, 1.1);
foo(true, false);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
@ -81,6 +84,7 @@
foo(1.1, 0.1);
foo(0.1, 1.1);
foo(true, false);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
@ -105,6 +109,7 @@
foo(1.1, 0.1);
foo(0.1, 1.1);
foo(true, false);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);
@ -129,6 +134,7 @@
foo(1.1, 0.1);
foo(0.1, 1.1);
foo(true, false);
%OptimizeFunctionOnNextCall(foo);
foo(undefined, 1.1);
assertOptimized(foo);