[turbofan] Introduce PlainPrimitiveToNumber.
This should solve the problem with missing checkpoints after JSToNumber (PlainPrimitiveToNumber is marked no-write, so the frame-state propagation should see through it.) Unfortunately, this also duplicates the word32- and float64-truncation magic that we have for JSToNumber in "simplified lowering". Review-Url: https://codereview.chromium.org/2059653002 Cr-Commit-Position: refs/heads/master@{#36881}
This commit is contained in:
parent
d0c7775d7c
commit
2890137bdc
@ -454,6 +454,14 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
break;
|
||||
case IrOpcode::kCheckIf:
|
||||
state = LowerCheckIf(node, frame_state, *effect, *control);
|
||||
case IrOpcode::kPlainPrimitiveToNumber:
|
||||
state = LowerPlainPrimitiveToNumber(node, *effect, *control);
|
||||
break;
|
||||
case IrOpcode::kPlainPrimitiveToWord32:
|
||||
state = LowerPlainPrimitiveToWord32(node, *effect, *control);
|
||||
break;
|
||||
case IrOpcode::kPlainPrimitiveToFloat64:
|
||||
state = LowerPlainPrimitiveToFloat64(node, *effect, *control);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@ -1330,7 +1338,6 @@ Node* EffectControlLinearizer::ChangeSmiToInt32(Node* value) {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Node* EffectControlLinearizer::ObjectIsSmi(Node* value) {
|
||||
return graph()->NewNode(
|
||||
machine()->WordEqual(),
|
||||
@ -1347,6 +1354,128 @@ Node* EffectControlLinearizer::SmiShiftBitsConstant() {
|
||||
return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
|
||||
}
|
||||
|
||||
EffectControlLinearizer::ValueEffectControl
|
||||
EffectControlLinearizer::LowerPlainPrimitiveToNumber(Node* node, Node* effect,
|
||||
Node* control) {
|
||||
Node* value = node->InputAt(0);
|
||||
Node* result = effect =
|
||||
graph()->NewNode(ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(),
|
||||
value, jsgraph()->NoContextConstant(), effect, control);
|
||||
return ValueEffectControl(result, effect, control);
|
||||
}
|
||||
|
||||
EffectControlLinearizer::ValueEffectControl
|
||||
EffectControlLinearizer::LowerPlainPrimitiveToWord32(Node* node, Node* effect,
|
||||
Node* control) {
|
||||
Node* value = node->InputAt(0);
|
||||
|
||||
Node* check0 = ObjectIsSmi(value);
|
||||
Node* branch0 =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
|
||||
|
||||
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
||||
Node* etrue0 = effect;
|
||||
Node* vtrue0 = ChangeSmiToInt32(value);
|
||||
|
||||
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
||||
Node* efalse0 = effect;
|
||||
Node* vfalse0;
|
||||
{
|
||||
vfalse0 = efalse0 = graph()->NewNode(
|
||||
ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value,
|
||||
jsgraph()->NoContextConstant(), efalse0, if_false0);
|
||||
|
||||
Node* check1 = ObjectIsSmi(vfalse0);
|
||||
Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
|
||||
|
||||
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
|
||||
Node* etrue1 = efalse0;
|
||||
Node* vtrue1 = ChangeSmiToInt32(vfalse0);
|
||||
|
||||
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
|
||||
Node* efalse1 = efalse0;
|
||||
Node* vfalse1;
|
||||
{
|
||||
vfalse1 = efalse1 = graph()->NewNode(
|
||||
simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
|
||||
efalse1, if_false1);
|
||||
vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
|
||||
}
|
||||
|
||||
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
|
||||
efalse0 =
|
||||
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
|
||||
vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
|
||||
vtrue1, vfalse1, if_false0);
|
||||
}
|
||||
|
||||
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
|
||||
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
|
||||
value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
|
||||
vtrue0, vfalse0, control);
|
||||
return ValueEffectControl(value, effect, control);
|
||||
}
|
||||
|
||||
EffectControlLinearizer::ValueEffectControl
|
||||
EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node, Node* effect,
|
||||
Node* control) {
|
||||
Node* value = node->InputAt(0);
|
||||
|
||||
Node* check0 = ObjectIsSmi(value);
|
||||
Node* branch0 =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
|
||||
|
||||
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
|
||||
Node* etrue0 = effect;
|
||||
Node* vtrue0;
|
||||
{
|
||||
vtrue0 = ChangeSmiToInt32(value);
|
||||
vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
|
||||
}
|
||||
|
||||
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
|
||||
Node* efalse0 = effect;
|
||||
Node* vfalse0;
|
||||
{
|
||||
vfalse0 = efalse0 = graph()->NewNode(
|
||||
ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value,
|
||||
jsgraph()->NoContextConstant(), efalse0, if_false0);
|
||||
|
||||
Node* check1 = ObjectIsSmi(vfalse0);
|
||||
Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
|
||||
|
||||
Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
|
||||
Node* etrue1 = efalse0;
|
||||
Node* vtrue1;
|
||||
{
|
||||
vtrue1 = ChangeSmiToInt32(vfalse0);
|
||||
vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
|
||||
}
|
||||
|
||||
Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
|
||||
Node* efalse1 = efalse0;
|
||||
Node* vfalse1;
|
||||
{
|
||||
vfalse1 = efalse1 = graph()->NewNode(
|
||||
simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
|
||||
efalse1, if_false1);
|
||||
}
|
||||
|
||||
if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
|
||||
efalse0 =
|
||||
graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
|
||||
vfalse0 =
|
||||
graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
|
||||
vtrue1, vfalse1, if_false0);
|
||||
}
|
||||
|
||||
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
|
||||
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
|
||||
value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
|
||||
vtrue0, vfalse0, control);
|
||||
return ValueEffectControl(value, effect, control);
|
||||
}
|
||||
|
||||
Factory* EffectControlLinearizer::factory() const {
|
||||
return isolate()->factory();
|
||||
}
|
||||
@ -1355,6 +1484,18 @@ Isolate* EffectControlLinearizer::isolate() const {
|
||||
return jsgraph()->isolate();
|
||||
}
|
||||
|
||||
Operator const* EffectControlLinearizer::ToNumberOperator() {
|
||||
if (!to_number_operator_.is_set()) {
|
||||
Callable callable = CodeFactory::ToNumber(isolate());
|
||||
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
|
||||
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
|
||||
isolate(), graph()->zone(), callable.descriptor(), 0, flags,
|
||||
Operator::kNoThrow);
|
||||
to_number_operator_.set(common()->Call(desc));
|
||||
}
|
||||
return to_number_operator_.get();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -91,6 +91,13 @@ class EffectControlLinearizer {
|
||||
Node* control);
|
||||
ValueEffectControl LowerCheckIf(Node* node, Node* frame_state, Node* effect,
|
||||
Node* control);
|
||||
ValueEffectControl LowerPlainPrimitiveToNumber(Node* node, Node* effect,
|
||||
Node* control);
|
||||
ValueEffectControl LowerPlainPrimitiveToWord32(Node* node, Node* effect,
|
||||
Node* control);
|
||||
ValueEffectControl LowerPlainPrimitiveToFloat64(Node* node, Node* effect,
|
||||
Node* control);
|
||||
|
||||
ValueEffectControl AllocateHeapNumberWithValue(Node* node, Node* effect,
|
||||
Node* control);
|
||||
ValueEffectControl BuildCheckedFloat64ToInt32(Node* value, Node* frame_state,
|
||||
@ -99,6 +106,7 @@ class EffectControlLinearizer {
|
||||
Node* frame_state,
|
||||
Node* effect,
|
||||
Node* control);
|
||||
|
||||
Node* ChangeInt32ToSmi(Node* value);
|
||||
Node* ChangeUint32ToSmi(Node* value);
|
||||
Node* ChangeInt32ToFloat64(Node* value);
|
||||
@ -119,9 +127,13 @@ class EffectControlLinearizer {
|
||||
SimplifiedOperatorBuilder* simplified() const;
|
||||
MachineOperatorBuilder* machine() const;
|
||||
|
||||
Operator const* ToNumberOperator();
|
||||
|
||||
JSGraph* js_graph_;
|
||||
Schedule* schedule_;
|
||||
Zone* temp_zone_;
|
||||
|
||||
SetOncePointer<Operator const> to_number_operator_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -24,6 +24,11 @@ Node* JSGraph::AllocateInOldSpaceStubConstant() {
|
||||
HeapConstant(isolate()->builtins()->AllocateInOldSpace()));
|
||||
}
|
||||
|
||||
Node* JSGraph::ToNumberBuiltinConstant() {
|
||||
return CACHED(kToNumberBuiltinConstant,
|
||||
HeapConstant(isolate()->builtins()->ToNumber()));
|
||||
}
|
||||
|
||||
Node* JSGraph::CEntryStubConstant(int result_size) {
|
||||
if (result_size == 1) {
|
||||
return CACHED(kCEntryStubConstant,
|
||||
|
@ -41,6 +41,7 @@ class JSGraph : public ZoneObject {
|
||||
// Canonicalized global constants.
|
||||
Node* AllocateInNewSpaceStubConstant();
|
||||
Node* AllocateInOldSpaceStubConstant();
|
||||
Node* ToNumberBuiltinConstant();
|
||||
Node* CEntryStubConstant(int result_size);
|
||||
Node* EmptyFixedArrayConstant();
|
||||
Node* EmptyLiteralsArrayConstant();
|
||||
@ -146,6 +147,7 @@ class JSGraph : public ZoneObject {
|
||||
enum CachedNode {
|
||||
kAllocateInNewSpaceStubConstant,
|
||||
kAllocateInOldSpaceStubConstant,
|
||||
kToNumberBuiltinConstant,
|
||||
kCEntryStubConstant,
|
||||
kEmptyFixedArrayConstant,
|
||||
kEmptyLiteralsArrayConstant,
|
||||
|
@ -289,10 +289,7 @@ class JSBinopReduction final {
|
||||
if (NodeProperties::GetType(node)->Is(Type::NumberOrUndefined())) {
|
||||
return node;
|
||||
}
|
||||
// TODO(bmeurer): Introduce PlainPrimitiveToNumber here.
|
||||
return graph()->NewNode(
|
||||
javascript()->ToNumber(), node, jsgraph()->NoContextConstant(),
|
||||
lowering_->EmptyFrameState(), graph()->start(), graph()->start());
|
||||
return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
|
||||
}
|
||||
|
||||
Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
|
||||
@ -869,20 +866,10 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
|
||||
}
|
||||
Type* const input_type = NodeProperties::GetType(input);
|
||||
if (input_type->Is(Type::PlainPrimitive())) {
|
||||
if (NodeProperties::GetContextInput(node) !=
|
||||
jsgraph()->NoContextConstant() ||
|
||||
NodeProperties::GetEffectInput(node) != graph()->start() ||
|
||||
NodeProperties::GetControlInput(node) != graph()->start()) {
|
||||
// JSToNumber(x:plain-primitive,context,effect,control)
|
||||
// => JSToNumber(x,no-context,start,start)
|
||||
RelaxEffectsAndControls(node);
|
||||
NodeProperties::ReplaceContextInput(node, jsgraph()->NoContextConstant());
|
||||
NodeProperties::ReplaceControlInput(node, graph()->start());
|
||||
NodeProperties::ReplaceEffectInput(node, graph()->start());
|
||||
DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
|
||||
NodeProperties::ReplaceFrameStateInput(node, 0, EmptyFrameState());
|
||||
return Changed(node);
|
||||
}
|
||||
RelaxEffectsAndControls(node);
|
||||
node->TrimInputCount(1);
|
||||
NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
|
||||
return Changed(node);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
@ -175,6 +175,9 @@
|
||||
|
||||
#define SIMPLIFIED_OP_LIST(V) \
|
||||
SIMPLIFIED_COMPARE_BINOP_LIST(V) \
|
||||
V(PlainPrimitiveToNumber) \
|
||||
V(PlainPrimitiveToWord32) \
|
||||
V(PlainPrimitiveToFloat64) \
|
||||
V(BooleanNot) \
|
||||
V(BooleanToNumber) \
|
||||
V(SpeculativeNumberAdd) \
|
||||
|
@ -1639,6 +1639,24 @@ class RepresentationSelector {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kPlainPrimitiveToNumber:
|
||||
ProcessInput(node, 0, UseInfo::AnyTagged());
|
||||
if (truncation.TruncatesToWord32()) {
|
||||
SetOutput(node, MachineRepresentation::kWord32);
|
||||
if (lower()) {
|
||||
NodeProperties::ChangeOp(node,
|
||||
simplified()->PlainPrimitiveToWord32());
|
||||
}
|
||||
} else if (truncation.TruncatesToFloat64()) {
|
||||
SetOutput(node, MachineRepresentation::kFloat64);
|
||||
if (lower()) {
|
||||
NodeProperties::ChangeOp(node,
|
||||
simplified()->PlainPrimitiveToFloat64());
|
||||
}
|
||||
} else {
|
||||
SetOutput(node, MachineRepresentation::kTagged);
|
||||
}
|
||||
return;
|
||||
case IrOpcode::kObjectIsCallable:
|
||||
case IrOpcode::kObjectIsNumber:
|
||||
case IrOpcode::kObjectIsReceiver:
|
||||
@ -1808,6 +1826,8 @@ class RepresentationSelector {
|
||||
case IrOpcode::kCheckedFloat64ToInt32:
|
||||
case IrOpcode::kCheckedTaggedToInt32:
|
||||
case IrOpcode::kCheckedTaggedToFloat64:
|
||||
case IrOpcode::kPlainPrimitiveToWord32:
|
||||
case IrOpcode::kPlainPrimitiveToFloat64:
|
||||
FATAL("Representation inference: unsupported opcodes.");
|
||||
break;
|
||||
|
||||
|
@ -212,6 +212,9 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
|
||||
V(NumberIsHoleNaN, Operator::kNoProperties, 1) \
|
||||
V(StringFromCharCode, Operator::kNoProperties, 1) \
|
||||
V(StringToNumber, Operator::kNoProperties, 1) \
|
||||
V(PlainPrimitiveToNumber, Operator::kNoWrite, 1) \
|
||||
V(PlainPrimitiveToWord32, Operator::kNoWrite, 1) \
|
||||
V(PlainPrimitiveToFloat64, Operator::kNoWrite, 1) \
|
||||
V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1) \
|
||||
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
|
||||
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
|
||||
|
@ -172,6 +172,10 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
|
||||
const Operator* StringFromCharCode();
|
||||
const Operator* StringToNumber();
|
||||
|
||||
const Operator* PlainPrimitiveToNumber();
|
||||
const Operator* PlainPrimitiveToWord32();
|
||||
const Operator* PlainPrimitiveToFloat64();
|
||||
|
||||
const Operator* ChangeTaggedSignedToInt32();
|
||||
const Operator* ChangeTaggedToInt32();
|
||||
const Operator* ChangeTaggedToUint32();
|
||||
|
@ -1759,6 +1759,18 @@ Type* Typer::Visitor::TypeNumberShiftRightLogical(Node* node) {
|
||||
return Type::Unsigned32();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypePlainPrimitiveToNumber(Node* node) {
|
||||
return TypeUnaryOp(node, ToNumber);
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypePlainPrimitiveToWord32(Node* node) {
|
||||
return Type::Integral32();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypePlainPrimitiveToFloat64(Node* node) {
|
||||
return Type::Number();
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeNumberImul(Node* node) { return Type::Signed32(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberClz32(Node* node) {
|
||||
|
@ -762,6 +762,16 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
CheckValueInputIs(node, 0, Type::Number());
|
||||
CheckUpperIs(node, Type::Boolean());
|
||||
break;
|
||||
case IrOpcode::kPlainPrimitiveToNumber:
|
||||
// Type is Number.
|
||||
CheckUpperIs(node, Type::Number());
|
||||
break;
|
||||
case IrOpcode::kPlainPrimitiveToWord32:
|
||||
CheckUpperIs(node, Type::Number());
|
||||
break;
|
||||
case IrOpcode::kPlainPrimitiveToFloat64:
|
||||
CheckUpperIs(node, Type::Number());
|
||||
break;
|
||||
case IrOpcode::kStringEqual:
|
||||
case IrOpcode::kStringLessThan:
|
||||
case IrOpcode::kStringLessThanOrEqual:
|
||||
|
@ -492,7 +492,7 @@ TEST(JSToNumberOfNumberOrOtherPrimitive) {
|
||||
for (size_t i = 0; i < arraysize(others); i++) {
|
||||
Type* t = Type::Union(Type::Number(), others[i], R.main_zone());
|
||||
Node* r = R.ReduceUnop(R.javascript.ToNumber(), t);
|
||||
CHECK_EQ(IrOpcode::kJSToNumber, r->opcode());
|
||||
CHECK_EQ(IrOpcode::kPlainPrimitiveToNumber, r->opcode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,8 +321,7 @@ TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
|
||||
Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
|
||||
EmptyFrameState(), effect, control));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
|
||||
graph()->start(), control));
|
||||
EXPECT_THAT(r.replacement(), IsPlainPrimitiveToNumber(input));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2311,6 +2311,7 @@ IS_UNOP_MATCHER(Float64ExtractLowWord32)
|
||||
IS_UNOP_MATCHER(Float64ExtractHighWord32)
|
||||
IS_UNOP_MATCHER(NumberToInt32)
|
||||
IS_UNOP_MATCHER(NumberToUint32)
|
||||
IS_UNOP_MATCHER(PlainPrimitiveToNumber)
|
||||
IS_UNOP_MATCHER(ObjectIsReceiver)
|
||||
IS_UNOP_MATCHER(ObjectIsSmi)
|
||||
IS_UNOP_MATCHER(StringFromCharCode)
|
||||
|
@ -375,6 +375,7 @@ Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
|
||||
Matcher<Node*> IsParameter(const Matcher<int> index_matcher);
|
||||
Matcher<Node*> IsLoadFramePointer();
|
||||
Matcher<Node*> IsLoadParentFramePointer();
|
||||
Matcher<Node*> IsPlainPrimitiveToNumber(const Matcher<Node*>& input_matcher);
|
||||
|
||||
Matcher<Node*> IsInt32PairAdd(const Matcher<Node*>& a_matcher,
|
||||
const Matcher<Node*>& b_matcher,
|
||||
|
Loading…
Reference in New Issue
Block a user