diff options
Diffstat (limited to 'deps/v8/src/compiler/simplified-lowering.cc')
-rw-r--r-- | deps/v8/src/compiler/simplified-lowering.cc | 269 |
1 files changed, 208 insertions, 61 deletions
diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc index 4acc77f22f..d0f952a9ec 100644 --- a/deps/v8/src/compiler/simplified-lowering.cc +++ b/deps/v8/src/compiler/simplified-lowering.cc @@ -88,13 +88,13 @@ MachineRepresentation MachineRepresentationFromArrayType( } UseInfo CheckedUseInfoAsWord32FromHint( - NumberOperationHint hint, CheckForMinusZeroMode minus_zero_mode = - CheckForMinusZeroMode::kCheckForMinusZero) { + NumberOperationHint hint, + IdentifyZeros identify_zeros = kDistinguishZeros) { switch (hint) { case NumberOperationHint::kSignedSmall: - return UseInfo::CheckedSignedSmallAsWord32(minus_zero_mode); + return UseInfo::CheckedSignedSmallAsWord32(identify_zeros); case NumberOperationHint::kSigned32: - return UseInfo::CheckedSigned32AsWord32(minus_zero_mode); + return UseInfo::CheckedSigned32AsWord32(identify_zeros); case NumberOperationHint::kNumber: return UseInfo::CheckedNumberAsWord32(); case NumberOperationHint::kNumberOrOddball: @@ -454,10 +454,32 @@ 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; + case IrOpcode::kCheckFloat64Hole: + new_type = Type::Intersect( + op_typer_.CheckFloat64Hole(FeedbackTypeOf(node->InputAt(0))), + info->restriction_type(), graph_zone()); + break; + + case IrOpcode::kCheckNumber: + new_type = Type::Intersect( + op_typer_.CheckNumber(FeedbackTypeOf(node->InputAt(0))), + info->restriction_type(), graph_zone()); + break; + case IrOpcode::kPhi: { new_type = TypePhi(node); if (type != nullptr) { @@ -809,6 +831,15 @@ class RepresentationSelector { if (lower()) Kill(node); } + // Helper for no-op node. + void VisitNoop(Node* node, Truncation truncation) { + if (truncation.IsUnused()) return VisitUnused(node); + MachineRepresentation representation = + GetOutputInfoForPhi(node, TypeOf(node), truncation); + VisitUnop(node, UseInfo(representation, truncation), representation); + if (lower()) DeferReplacement(node, node->InputAt(0)); + } + // Helper for binops of the R x L -> O variety. void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use, MachineRepresentation output, @@ -840,11 +871,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. @@ -1167,7 +1199,7 @@ class RepresentationSelector { // If one of the inputs is positive and/or truncation is being applied, // there is no need to return -0. CheckForMinusZeroMode mz_mode = - truncation.IsUsedAsWord32() || + truncation.IdentifiesZeroAndMinusZero() || (input0_type->Is(Type::OrderedNumber()) && input0_type->Min() > 0) || (input1_type->Is(Type::OrderedNumber()) && @@ -1226,13 +1258,23 @@ class RepresentationSelector { VisitBinop(node, UseInfo::TruncatingWord32(), MachineRepresentation::kWord32, Type::Signed32()); } else { - UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint); + // If the output's truncation is identify-zeros, we can pass it + // along. Moreover, if the operation is addition and we know the + // right-hand side is not minus zero, we do not have to distinguish + // between 0 and -0. + IdentifyZeros left_identify_zeros = truncation.identify_zeros(); + if (node->opcode() == IrOpcode::kSpeculativeNumberAdd && + !right_feedback_type->Maybe(Type::MinusZero())) { + left_identify_zeros = kIdentifyZeros; + } + UseInfo left_use = + CheckedUseInfoAsWord32FromHint(hint, left_identify_zeros); // For CheckedInt32Add and CheckedInt32Sub, we don't need to do // a minus zero check for the right hand side, since we already // know that the left hand side is a proper Signed32 value, // potentially guarded by a check. - UseInfo right_use = CheckedUseInfoAsWord32FromHint( - hint, CheckForMinusZeroMode::kDontCheckForMinusZero); + UseInfo right_use = + CheckedUseInfoAsWord32FromHint(hint, kIdentifyZeros); VisitBinop(node, left_use, right_use, MachineRepresentation::kWord32, Type::Signed32()); } @@ -2061,20 +2103,27 @@ class RepresentationSelector { return; } case IrOpcode::kNumberMax: { - // TODO(turbofan): We should consider feedback types here as well. - if (BothInputsAreUnsigned32(node)) { + // It is safe to use the feedback types for left and right hand side + // here, since we can only narrow those types and thus we can only + // promise a more specific truncation. + Type* const lhs_type = TypeOf(node->InputAt(0)); + Type* const rhs_type = TypeOf(node->InputAt(1)); + if (lhs_type->Is(Type::Unsigned32()) && + rhs_type->Is(Type::Unsigned32())) { VisitWord32TruncatingBinop(node); if (lower()) { lowering->DoMax(node, lowering->machine()->Uint32LessThan(), MachineRepresentation::kWord32); } - } else if (BothInputsAreSigned32(node)) { + } else if (lhs_type->Is(Type::Signed32()) && + rhs_type->Is(Type::Signed32())) { VisitWord32TruncatingBinop(node); if (lower()) { lowering->DoMax(node, lowering->machine()->Int32LessThan(), MachineRepresentation::kWord32); } - } else if (BothInputsAre(node, Type::PlainNumber())) { + } else if (lhs_type->Is(Type::PlainNumber()) && + rhs_type->Is(Type::PlainNumber())) { VisitFloat64Binop(node); if (lower()) { lowering->DoMax(node, lowering->machine()->Float64LessThan(), @@ -2087,20 +2136,27 @@ class RepresentationSelector { return; } case IrOpcode::kNumberMin: { - // TODO(turbofan): We should consider feedback types here as well. - if (BothInputsAreUnsigned32(node)) { + // It is safe to use the feedback types for left and right hand side + // here, since we can only narrow those types and thus we can only + // promise a more specific truncation. + Type* const lhs_type = TypeOf(node->InputAt(0)); + Type* const rhs_type = TypeOf(node->InputAt(1)); + if (lhs_type->Is(Type::Unsigned32()) && + rhs_type->Is(Type::Unsigned32())) { VisitWord32TruncatingBinop(node); if (lower()) { lowering->DoMin(node, lowering->machine()->Uint32LessThan(), MachineRepresentation::kWord32); } - } else if (BothInputsAreSigned32(node)) { + } else if (lhs_type->Is(Type::Signed32()) && + rhs_type->Is(Type::Signed32())) { VisitWord32TruncatingBinop(node); if (lower()) { lowering->DoMin(node, lowering->machine()->Int32LessThan(), MachineRepresentation::kWord32); } - } else if (BothInputsAre(node, Type::PlainNumber())) { + } else if (lhs_type->Is(Type::PlainNumber()) && + rhs_type->Is(Type::PlainNumber())) { VisitFloat64Binop(node); if (lower()) { lowering->DoMin(node, lowering->machine()->Float64LessThan(), @@ -2271,16 +2327,22 @@ class RepresentationSelector { case IrOpcode::kCheckBounds: { Type* index_type = TypeOf(node->InputAt(0)); Type* length_type = TypeOf(node->InputAt(1)); - if (index_type->Is(Type::Unsigned32())) { + if (index_type->Is(Type::Integral32OrMinusZero())) { + // Map -0 to 0, and the values in the [-2^31,-1] range to the + // [2^31,2^32-1] range, which will be considered out-of-bounds + // as well, because the {length_type} is limited to Unsigned31. VisitBinop(node, UseInfo::TruncatingWord32(), MachineRepresentation::kWord32); - if (lower() && index_type->Max() < length_type->Min()) { - // The bounds check is redundant if we already know that - // the index is within the bounds of [0.0, length[. - DeferReplacement(node, node->InputAt(0)); + if (lower()) { + if (index_type->Min() >= 0.0 && + index_type->Max() < length_type->Min()) { + // The bounds check is redundant if we already know that + // the index is within the bounds of [0.0, length[. + DeferReplacement(node, node->InputAt(0)); + } } } else { - VisitBinop(node, UseInfo::CheckedSigned32AsWord32(), + VisitBinop(node, UseInfo::CheckedSigned32AsWord32(kIdentifyZeros), UseInfo::TruncatingWord32(), MachineRepresentation::kWord32); } @@ -2315,19 +2377,9 @@ class RepresentationSelector { return; } case IrOpcode::kCheckNumber: { - if (InputIs(node, Type::Number())) { - if (truncation.IsUsedAsWord32()) { - VisitUnop(node, UseInfo::TruncatingWord32(), - MachineRepresentation::kWord32); - } else { - // TODO(jarin,bmeurer): We need to go to Tagged here, because - // otherwise we cannot distinguish the hole NaN (which might need to - // be treated as undefined). We should have a dedicated Type for - // that at some point, and maybe even a dedicated truncation. - VisitUnop(node, UseInfo::AnyTagged(), - MachineRepresentation::kTagged); - } - if (lower()) DeferReplacement(node, node->InputAt(0)); + Type* const input_type = TypeOf(node->InputAt(0)); + if (input_type->Is(Type::Number())) { + VisitNoop(node, truncation); } else { VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged); } @@ -2346,7 +2398,8 @@ class RepresentationSelector { } case IrOpcode::kCheckSmi: { if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) { - VisitUnop(node, UseInfo::CheckedSignedSmallAsWord32(), + VisitUnop(node, + UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros), MachineRepresentation::kWord32); } else { VisitUnop(node, UseInfo::CheckedSignedSmallAsTaggedSigned(), @@ -2541,10 +2594,56 @@ 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; } + case IrOpcode::kObjectIsNaN: { + Type* const input_type = GetUpperBound(node->InputAt(0)); + if (input_type->Is(Type::NaN())) { + VisitUnop(node, UseInfo::None(), MachineRepresentation::kBit); + if (lower()) { + DeferReplacement(node, lowering->jsgraph()->Int32Constant(1)); + } + } else if (!input_type->Maybe(Type::NaN())) { + VisitUnop(node, UseInfo::Any(), MachineRepresentation::kBit); + if (lower()) { + DeferReplacement(node, lowering->jsgraph()->Int32Constant(0)); + } + } else if (input_type->Is(Type::Number())) { + VisitUnop(node, UseInfo::TruncatingFloat64(), + MachineRepresentation::kBit); + if (lower()) { + // ObjectIsNaN(x:kRepFloat64) => Word32Equal(Float64Equal(x,x),#0) + Node* const input = node->InputAt(0); + node->ReplaceInput( + 0, jsgraph_->graph()->NewNode( + lowering->machine()->Float64Equal(), input, input)); + node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0)); + NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal()); + } + } else { + VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kBit); + } + return; + } case IrOpcode::kObjectIsNonCallable: { VisitObjectIs(node, Type::NonCallable(), lowering); return; @@ -2566,14 +2665,26 @@ class RepresentationSelector { VisitObjectIs(node, Type::String(), lowering); return; } + case IrOpcode::kObjectIsSymbol: { + VisitObjectIs(node, Type::Symbol(), lowering); + return; + } case IrOpcode::kObjectIsUndetectable: { VisitObjectIs(node, Type::Undetectable(), lowering); return; } - case IrOpcode::kNewRestParameterElements: + case IrOpcode::kArgumentsFrame: { + SetOutput(node, MachineType::PointerRepresentation()); + return; + } + case IrOpcode::kArgumentsLength: { + VisitUnop(node, UseInfo::PointerInt(), + MachineRepresentation::kTaggedSigned); + return; + } case IrOpcode::kNewUnmappedArgumentsElements: { - ProcessRemainingInputs(node, 0); - SetOutput(node, MachineRepresentation::kTaggedPointer); + VisitBinop(node, UseInfo::PointerInt(), UseInfo::TaggedSigned(), + MachineRepresentation::kTaggedPointer); return; } case IrOpcode::kArrayBufferWasNeutered: { @@ -2581,13 +2692,36 @@ class RepresentationSelector { return; } case IrOpcode::kCheckFloat64Hole: { - CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op()); - ProcessInput(node, 0, UseInfo::TruncatingFloat64()); - ProcessRemainingInputs(node, 1); - SetOutput(node, MachineRepresentation::kFloat64); - if (truncation.IsUsedAsFloat64() && - mode == CheckFloat64HoleMode::kAllowReturnHole) { - if (lower()) DeferReplacement(node, node->InputAt(0)); + Type* const input_type = TypeOf(node->InputAt(0)); + if (input_type->Is(Type::Number())) { + VisitNoop(node, truncation); + } else { + CheckFloat64HoleMode mode = CheckFloat64HoleModeOf(node->op()); + switch (mode) { + case CheckFloat64HoleMode::kAllowReturnHole: + if (truncation.IsUnused()) return VisitUnused(node); + if (truncation.IsUsedAsWord32()) { + VisitUnop(node, UseInfo::TruncatingWord32(), + MachineRepresentation::kWord32); + if (lower()) DeferReplacement(node, node->InputAt(0)); + } else if (truncation.IsUsedAsFloat64()) { + VisitUnop(node, UseInfo::TruncatingFloat64(), + MachineRepresentation::kFloat64); + if (lower()) DeferReplacement(node, node->InputAt(0)); + } else { + VisitUnop( + node, + UseInfo(MachineRepresentation::kFloat64, Truncation::Any()), + MachineRepresentation::kFloat64, Type::Number()); + } + break; + case CheckFloat64HoleMode::kNeverReturnHole: + VisitUnop( + node, + UseInfo(MachineRepresentation::kFloat64, Truncation::Any()), + MachineRepresentation::kFloat64, Type::Number()); + break; + } } return; } @@ -2687,7 +2821,8 @@ class RepresentationSelector { case IrOpcode::kBeginRegion: case IrOpcode::kProjection: case IrOpcode::kOsrValue: - case IrOpcode::kArgumentsObjectState: + case IrOpcode::kArgumentsElementsState: + case IrOpcode::kArgumentsLengthState: // All JavaScript operators except JSToNumber have uniform handling. #define OPCODE_CASE(name) case IrOpcode::k##name: JS_SIMPLE_BINOP_LIST(OPCODE_CASE) @@ -2842,7 +2977,6 @@ void SimplifiedLowering::DoJSToNumberTruncatesToFloat64( Node* frame_state = node->InputAt(2); Node* effect = node->InputAt(3); Node* control = node->InputAt(4); - Node* throwing; Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value); Node* branch0 = @@ -2860,10 +2994,18 @@ void SimplifiedLowering::DoJSToNumberTruncatesToFloat64( Node* efalse0 = effect; Node* vfalse0; { - throwing = vfalse0 = efalse0 = + vfalse0 = efalse0 = if_false0 = graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context, frame_state, efalse0, if_false0); - if_false0 = graph()->NewNode(common()->IfSuccess(), throwing); + + // Update potential {IfException} uses of {node} to point to the above + // {ToNumber} stub call node instead. + Node* on_exception = nullptr; + if (NodeProperties::IsExceptionalCall(node, &on_exception)) { + NodeProperties::ReplaceControlInput(on_exception, vfalse0); + NodeProperties::ReplaceEffectInput(on_exception, efalse0); + if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0); + } Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0); Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); @@ -2905,10 +3047,9 @@ void SimplifiedLowering::DoJSToNumberTruncatesToFloat64( if (edge.from()->opcode() == IrOpcode::kIfSuccess) { edge.from()->ReplaceUses(control); edge.from()->Kill(); - } else if (edge.from()->opcode() == IrOpcode::kIfException) { - edge.UpdateTo(throwing); } else { - UNREACHABLE(); + DCHECK(edge.from()->opcode() != IrOpcode::kIfException); + edge.UpdateTo(control); } } else if (NodeProperties::IsEffectEdge(edge)) { edge.UpdateTo(effect); @@ -2926,7 +3067,6 @@ void SimplifiedLowering::DoJSToNumberTruncatesToWord32( Node* frame_state = node->InputAt(2); Node* effect = node->InputAt(3); Node* control = node->InputAt(4); - Node* throwing; Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value); Node* branch0 = @@ -2941,10 +3081,18 @@ void SimplifiedLowering::DoJSToNumberTruncatesToWord32( Node* efalse0 = effect; Node* vfalse0; { - throwing = vfalse0 = efalse0 = + vfalse0 = efalse0 = if_false0 = graph()->NewNode(ToNumberOperator(), ToNumberCode(), value, context, frame_state, efalse0, if_false0); - if_false0 = graph()->NewNode(common()->IfSuccess(), throwing); + + // Update potential {IfException} uses of {node} to point to the above + // {ToNumber} stub call node instead. + Node* on_exception = nullptr; + if (NodeProperties::IsExceptionalCall(node, &on_exception)) { + NodeProperties::ReplaceControlInput(on_exception, vfalse0); + NodeProperties::ReplaceEffectInput(on_exception, efalse0); + if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0); + } Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0); Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0); @@ -2982,10 +3130,9 @@ void SimplifiedLowering::DoJSToNumberTruncatesToWord32( if (edge.from()->opcode() == IrOpcode::kIfSuccess) { edge.from()->ReplaceUses(control); edge.from()->Kill(); - } else if (edge.from()->opcode() == IrOpcode::kIfException) { - edge.UpdateTo(throwing); } else { - UNREACHABLE(); + DCHECK(edge.from()->opcode() != IrOpcode::kIfException); + edge.UpdateTo(control); } } else if (NodeProperties::IsEffectEdge(edge)) { edge.UpdateTo(effect); |