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

[turbofan] Also consume number type feedback for abstract equality.

This allows us to consume the type hints gathered by the CompareIC for
the abstract equality and inequality operators. We need to distinguish
Number and NumberOrOddball feedback now, as abstract equality doesn't
truncate null and undefined to Number.

R=epertoso@chromium.org
BUG=v8:4583

Review-Url: https://codereview.chromium.org/2222983002
Cr-Commit-Position: refs/heads/master@{#38432}
parent 3c437762
......@@ -1667,41 +1667,54 @@ EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node,
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
Node* value, Node* frame_state, Node* effect, Node* control) {
CheckTaggedInputMode mode, Node* value, Node* frame_state, Node* effect,
Node* control) {
Node* value_map = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
Node* check_number = graph()->NewNode(machine()->WordEqual(), value_map,
jsgraph()->HeapNumberMapConstant());
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check_number, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
// For oddballs also contain the numeric value, let us just check that
// we have an oddball here.
Node* efalse = effect;
Node* instance_type = efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
efalse, if_false);
Node* check_oddball =
graph()->NewNode(machine()->Word32Equal(), instance_type,
jsgraph()->Int32Constant(ODDBALL_TYPE));
if_false = efalse =
graph()->NewNode(common()->DeoptimizeUnless(
DeoptimizeReason::kNotAHeapNumberUndefinedBoolean),
check_oddball, frame_state, efalse, if_false);
STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
switch (mode) {
case CheckTaggedInputMode::kNumber: {
control = effect = graph()->NewNode(
common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber),
check_number, frame_state, effect, control);
break;
}
case CheckTaggedInputMode::kNumberOrOddball: {
Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
check_number, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* etrue = effect;
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
// For oddballs also contain the numeric value, let us just check that
// we have an oddball here.
Node* efalse = effect;
Node* instance_type = efalse = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
value_map, efalse, if_false);
Node* check_oddball =
graph()->NewNode(machine()->Word32Equal(), instance_type,
jsgraph()->Int32Constant(ODDBALL_TYPE));
if_false = efalse = graph()->NewNode(
common()->DeoptimizeUnless(
DeoptimizeReason::kNotAHeapNumberUndefinedBoolean),
check_oddball, frame_state, efalse, if_false);
STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
break;
}
}
Node* result = effect = graph()->NewNode(
value = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
effect, control);
return ValueEffectControl(result, effect, control);
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
......@@ -1709,6 +1722,7 @@ EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node,
Node* frame_state,
Node* effect,
Node* control) {
CheckTaggedInputMode mode = CheckTaggedInputModeOf(node->op());
Node* value = node->InputAt(0);
Node* check = ObjectIsSmi(value);
......@@ -1724,7 +1738,7 @@ EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node,
// Otherwise, check heap numberness and load the number.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
ValueEffectControl number_state = BuildCheckedHeapNumberOrOddballToFloat64(
value, frame_state, effect, if_false);
mode, value, frame_state, effect, if_false);
Node* merge =
graph()->NewNode(common()->Merge(2), if_true, number_state.control);
......@@ -1789,7 +1803,8 @@ EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(Node* node,
// to int32.
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
ValueEffectControl false_state = BuildCheckedHeapNumberOrOddballToFloat64(
value, frame_state, effect, if_false);
CheckTaggedInputMode::kNumberOrOddball, value, frame_state, effect,
if_false);
false_state.value =
graph()->NewNode(machine()->TruncateFloat64ToWord32(), false_state.value);
......
......@@ -160,10 +160,9 @@ class EffectControlLinearizer {
ValueEffectControl BuildCheckedFloat64ToInt32(CheckForMinusZeroMode mode,
Node* value, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl BuildCheckedHeapNumberOrOddballToFloat64(Node* value,
Node* frame_state,
Node* effect,
Node* control);
ValueEffectControl BuildCheckedHeapNumberOrOddballToFloat64(
CheckTaggedInputMode mode, Node* value, Node* frame_state, Node* effect,
Node* control);
Node* ChangeInt32ToSmi(Node* value);
Node* ChangeUint32ToSmi(Node* value);
......
......@@ -63,6 +63,9 @@ class JSBinopReduction final {
case CompareOperationHints::kSignedSmall:
*hint = NumberOperationHint::kSignedSmall;
return true;
case CompareOperationHints::kNumber:
*hint = NumberOperationHint::kNumber;
return true;
case CompareOperationHints::kNumberOrOddball:
*hint = NumberOperationHint::kNumberOrOddball;
return true;
......@@ -159,7 +162,8 @@ class JSBinopReduction final {
return lowering_->Changed(node_);
}
Reduction ChangeToSpeculativeOperator(const Operator* op, Type* upper_bound) {
Reduction ChangeToSpeculativeOperator(const Operator* op, bool invert,
Type* upper_bound) {
DCHECK_EQ(1, op->EffectInputCount());
DCHECK_EQ(1, op->EffectOutputCount());
DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
......@@ -202,6 +206,14 @@ class JSBinopReduction final {
NodeProperties::SetType(node_,
Type::Intersect(node_type, upper_bound, zone()));
if (invert) {
// Insert an boolean not to invert the value.
Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
node_->ReplaceUses(value);
// Note: ReplaceUses() smashes all uses, so smash it back here.
value->ReplaceInput(0, node_);
return lowering_->Replace(value);
}
return lowering_->Changed(node_);
}
......@@ -209,6 +221,10 @@ class JSBinopReduction final {
return ChangeToPureOperator(op, false, type);
}
Reduction ChangeToSpeculativeOperator(const Operator* op, Type* type) {
return ChangeToSpeculativeOperator(op, false, type);
}
bool LeftInputIs(Type* t) { return left_type()->Is(t); }
bool RightInputIs(Type* t) { return right_type()->Is(t); }
......@@ -692,9 +708,6 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::Number())) {
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
}
if (r.BothInputsAre(Type::String())) {
return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
}
......@@ -721,6 +734,17 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
}
return Changed(node);
}
NumberOperationHint hint;
if (r.BothInputsAre(Type::Signed32()) ||
r.BothInputsAre(Type::Unsigned32())) {
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
} else if (r.GetCompareNumberOperationHint(&hint)) {
return r.ChangeToSpeculativeOperator(
simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean());
} else if (r.BothInputsAre(Type::Number())) {
return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
}
return NoChange();
}
......
......@@ -373,8 +373,13 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
} else if (output_type->Is(Type::NumberOrOddball())) {
// TODO(jarin) Here we should check that truncation is Number.
op = simplified()->TruncateTaggedToFloat64();
} else if (use_info.type_check() == TypeCheckKind::kNumber ||
(use_info.type_check() == TypeCheckKind::kNumberOrOddball &&
!output_type->Maybe(Type::BooleanOrNullOrNumber()))) {
op = simplified()->CheckedTaggedToFloat64(CheckTaggedInputMode::kNumber);
} else if (use_info.type_check() == TypeCheckKind::kNumberOrOddball) {
op = simplified()->CheckedTaggedToFloat64();
op = simplified()->CheckedTaggedToFloat64(
CheckTaggedInputMode::kNumberOrOddball);
}
} else if (output_rep == MachineRepresentation::kFloat32) {
op = machine()->ChangeFloat32ToFloat64();
......
......@@ -78,6 +78,7 @@ enum class TypeCheckKind : uint8_t {
kNone,
kSignedSmall,
kSigned32,
kNumber,
kNumberOrOddball
};
......@@ -89,6 +90,8 @@ inline std::ostream& operator<<(std::ostream& os, TypeCheckKind type_check) {
return os << "SignedSmall";
case TypeCheckKind::kSigned32:
return os << "Signed32";
case TypeCheckKind::kNumber:
return os << "Number";
case TypeCheckKind::kNumberOrOddball:
return os << "NumberOrOddball";
}
......@@ -146,6 +149,14 @@ class UseInfo {
return UseInfo(MachineRepresentation::kWord32, Truncation::Any(),
TypeCheckKind::kSigned32);
}
static UseInfo CheckedNumberAsFloat64() {
return UseInfo(MachineRepresentation::kFloat64, Truncation::Float64(),
TypeCheckKind::kNumber);
}
static UseInfo CheckedNumberAsWord32() {
return UseInfo(MachineRepresentation::kWord32, Truncation::Word32(),
TypeCheckKind::kNumber);
}
static UseInfo CheckedNumberOrOddballAsFloat64() {
return UseInfo(MachineRepresentation::kFloat64, Truncation::Any(),
TypeCheckKind::kNumberOrOddball);
......
......@@ -93,6 +93,8 @@ UseInfo CheckedUseInfoAsWord32FromHint(NumberOperationHint hint) {
return UseInfo::CheckedSignedSmallAsWord32();
case NumberOperationHint::kSigned32:
return UseInfo::CheckedSigned32AsWord32();
case NumberOperationHint::kNumber:
return UseInfo::CheckedNumberAsWord32();
case NumberOperationHint::kNumberOrOddball:
return UseInfo::CheckedNumberOrOddballAsWord32();
}
......@@ -100,6 +102,22 @@ UseInfo CheckedUseInfoAsWord32FromHint(NumberOperationHint hint) {
return UseInfo::None();
}
UseInfo CheckedUseInfoAsFloat64FromHint(NumberOperationHint hint) {
switch (hint) {
case NumberOperationHint::kSignedSmall:
case NumberOperationHint::kSigned32:
// Not used currently.
UNREACHABLE();
break;
case NumberOperationHint::kNumber:
return UseInfo::CheckedNumberAsFloat64();
case NumberOperationHint::kNumberOrOddball:
return UseInfo::CheckedNumberOrOddballAsFloat64();
}
UNREACHABLE();
return UseInfo::None();
}
UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
switch (rep) {
case MachineRepresentation::kTagged:
......@@ -1347,18 +1365,21 @@ class RepresentationSelector {
}
// Try to use type feedback.
NumberOperationHint hint = NumberOperationHintOf(node->op());
if (hint == NumberOperationHint::kSignedSmall) {
VisitBinop(node, UseInfo::CheckedSigned32AsWord32(),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Int32Op(node));
return;
switch (hint) {
case NumberOperationHint::kSignedSmall:
case NumberOperationHint::kSigned32:
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Int32Op(node));
return;
case NumberOperationHint::kNumber:
case NumberOperationHint::kNumberOrOddball:
VisitBinop(node, CheckedUseInfoAsFloat64FromHint(hint),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Float64Op(node));
return;
}
DCHECK_EQ(NumberOperationHint::kNumberOrOddball, hint);
// default case => Float64 comparison
VisitBinop(node, UseInfo::CheckedNumberOrOddballAsFloat64(),
MachineRepresentation::kBit);
if (lower()) ChangeToPureOp(node, Float64Op(node));
UNREACHABLE();
return;
}
......
......@@ -249,6 +249,26 @@ CheckTaggedHoleMode CheckTaggedHoleModeOf(const Operator* op) {
return OpParameter<CheckTaggedHoleMode>(op);
}
size_t hash_value(CheckTaggedInputMode mode) {
return static_cast<size_t>(mode);
}
std::ostream& operator<<(std::ostream& os, CheckTaggedInputMode mode) {
switch (mode) {
case CheckTaggedInputMode::kNumber:
return os << "Number";
case CheckTaggedInputMode::kNumberOrOddball:
return os << "NumberOrOddball";
}
UNREACHABLE();
return os;
}
CheckTaggedInputMode CheckTaggedInputModeOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kCheckedTaggedToFloat64, op->opcode());
return OpParameter<CheckTaggedInputMode>(op);
}
std::ostream& operator<<(std::ostream& os, GrowFastElementsFlags flags) {
bool empty = true;
if (flags & GrowFastElementsFlag::kArrayObject) {
......@@ -300,6 +320,8 @@ std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) {
return os << "SignedSmall";
case NumberOperationHint::kSigned32:
return os << "Signed32";
case NumberOperationHint::kNumber:
return os << "Number";
case NumberOperationHint::kNumberOrOddball:
return os << "NumberOrOddball";
}
......@@ -429,7 +451,6 @@ NumberOperationHint NumberOperationHintOf(const Operator* op) {
V(CheckedUint32Mod, 2, 1) \
V(CheckedUint32ToInt32, 1, 1) \
V(CheckedTaggedSignedToInt32, 1, 1) \
V(CheckedTaggedToFloat64, 1, 1) \
V(CheckedTruncateTaggedToWord32, 1, 1)
struct SimplifiedOperatorGlobalCache final {
......@@ -496,6 +517,20 @@ struct SimplifiedOperatorGlobalCache final {
CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero>
kCheckedTaggedToInt32DontCheckForMinusZeroOperator;
template <CheckTaggedInputMode kMode>
struct CheckedTaggedToFloat64Operator final
: public Operator1<CheckTaggedInputMode> {
CheckedTaggedToFloat64Operator()
: Operator1<CheckTaggedInputMode>(
IrOpcode::kCheckedTaggedToFloat64,
Operator::kFoldable | Operator::kNoThrow,
"CheckedTaggedToFloat64", 1, 1, 1, 1, 1, 0, kMode) {}
};
CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumber>
kCheckedTaggedToFloat64NumberOperator;
CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrOddball>
kCheckedTaggedToFloat64NumberOrOddballOperator;
template <CheckFloat64HoleMode kMode>
struct CheckFloat64HoleNaNOperator final
: public Operator1<CheckFloat64HoleMode> {
......@@ -555,6 +590,7 @@ struct SimplifiedOperatorGlobalCache final {
Name##Operator<NumberOperationHint::kSignedSmall> \
k##Name##SignedSmallOperator; \
Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \
Name##Operator<NumberOperationHint::kNumber> k##Name##NumberOperator; \
Name##Operator<NumberOperationHint::kNumberOrOddball> \
k##Name##NumberOrOddballOperator;
SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
......@@ -633,6 +669,18 @@ const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32(
return nullptr;
}
const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64(
CheckTaggedInputMode mode) {
switch (mode) {
case CheckTaggedInputMode::kNumber:
return &cache_.kCheckedTaggedToFloat64NumberOperator;
case CheckTaggedInputMode::kNumberOrOddball:
return &cache_.kCheckedTaggedToFloat64NumberOrOddballOperator;
}
UNREACHABLE();
return nullptr;
}
const Operator* SimplifiedOperatorBuilder::CheckMaps(int map_input_count) {
// TODO(bmeurer): Cache the most important versions of this operator.
DCHECK_LT(0, map_input_count);
......@@ -743,6 +791,8 @@ const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
return &cache_.k##Name##SignedSmallOperator; \
case NumberOperationHint::kSigned32: \
return &cache_.k##Name##Signed32Operator; \
case NumberOperationHint::kNumber: \
return &cache_.k##Name##NumberOperator; \
case NumberOperationHint::kNumberOrOddball: \
return &cache_.k##Name##NumberOrOddballOperator; \
} \
......
......@@ -130,6 +130,17 @@ std::ostream& operator<<(std::ostream&, CheckTaggedHoleMode);
CheckTaggedHoleMode CheckTaggedHoleModeOf(const Operator*) WARN_UNUSED_RESULT;
enum class CheckTaggedInputMode : uint8_t {
kNumber,
kNumberOrOddball,
};
size_t hash_value(CheckTaggedInputMode);
std::ostream& operator<<(std::ostream&, CheckTaggedInputMode);
CheckTaggedInputMode CheckTaggedInputModeOf(const Operator*) WARN_UNUSED_RESULT;
enum class CheckForMinusZeroMode : uint8_t {
kCheckForMinusZero,
kDontCheckForMinusZero,
......@@ -173,6 +184,7 @@ ElementsTransition ElementsTransitionOf(const Operator* op) WARN_UNUSED_RESULT;
enum class NumberOperationHint : uint8_t {
kSignedSmall, // Inputs were always Smi so far, output was in Smi range.
kSigned32, // Inputs and output were Signed32 so far.
kNumber, // Inputs were Number, output was Number.
kNumberOrOddball, // Inputs were Number or Oddball, output was Number.
};
......@@ -323,7 +335,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* CheckedFloat64ToInt32(CheckForMinusZeroMode);
const Operator* CheckedTaggedSignedToInt32();
const Operator* CheckedTaggedToInt32(CheckForMinusZeroMode);
const Operator* CheckedTaggedToFloat64();
const Operator* CheckedTaggedToFloat64(CheckTaggedInputMode);
const Operator* CheckedTruncateTaggedToWord32();
const Operator* CheckFloat64Hole(CheckFloat64HoleMode);
......
......@@ -26,7 +26,7 @@ BinaryOperationHints::Hint ToBinaryOperationHint(Type* type) {
}
CompareOperationHints::Hint ToCompareOperationHint(
CompareICState::State state) {
Token::Value op, CompareICState::State state) {
switch (state) {
case CompareICState::UNINITIALIZED:
return CompareOperationHints::kNone;
......@@ -35,7 +35,9 @@ CompareOperationHints::Hint ToCompareOperationHint(
case CompareICState::SMI:
return CompareOperationHints::kSignedSmall;
case CompareICState::NUMBER:
return CompareOperationHints::kNumberOrOddball;
return Token::IsOrderedRelationalCompareOp(op)
? CompareOperationHints::kNumberOrOddball
: CompareOperationHints::kNumber;
case CompareICState::STRING:
return CompareOperationHints::kString;
case CompareICState::INTERNALIZED_STRING:
......@@ -79,9 +81,10 @@ bool TypeHintAnalysis::GetCompareOperationHints(
if (raw_map != nullptr) Map::TryUpdate(handle(raw_map)).ToHandle(&map);
CompareICStub stub(code->stub_key(), code->GetIsolate());
*hints = CompareOperationHints(ToCompareOperationHint(stub.left()),
ToCompareOperationHint(stub.right()),
ToCompareOperationHint(stub.state()));
*hints =
CompareOperationHints(ToCompareOperationHint(stub.op(), stub.left()),
ToCompareOperationHint(stub.op(), stub.right()),
ToCompareOperationHint(stub.op(), stub.state()));
return true;
}
......
......@@ -39,6 +39,8 @@ std::ostream& operator<<(std::ostream& os, CompareOperationHints::Hint hint) {
return os << "Boolean";
case CompareOperationHints::kSignedSmall:
return os << "SignedSmall";
case CompareOperationHints::kNumber:
return os << "Number";
case CompareOperationHints::kNumberOrOddball:
return os << "NumberOrOddball";
case CompareOperationHints::kString:
......
......@@ -64,6 +64,7 @@ class CompareOperationHints final {
kNone,
kBoolean,
kSignedSmall,
kNumber,
kNumberOrOddball,
kString,
kInternalizedString,
......
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