Index: src/compiler/js-typed-lowering.cc |
diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc |
index 770ae7bf6a4740e092f8d3dc041980e7837ea160..9de549362166853612c6b458293d0b2f122f3236 100644 |
--- a/src/compiler/js-typed-lowering.cc |
+++ b/src/compiler/js-typed-lowering.cc |
@@ -141,7 +141,7 @@ class JSBinopReduction { |
node_->ReplaceUses(value); |
// Note: ReplaceUses() smashes all uses, so smash it back here. |
value->ReplaceInput(0, node_); |
- return lowering_->ReplaceWith(value); |
+ return lowering_->Replace(value); |
} |
return lowering_->Changed(node_); |
} |
@@ -504,16 +504,15 @@ Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) { |
} |
if (input_type->Is(Type::Undefined())) { |
// JSToNumber(undefined) => #NaN |
- return ReplaceWith(jsgraph()->NaNConstant()); |
+ return Replace(jsgraph()->NaNConstant()); |
} |
if (input_type->Is(Type::Null())) { |
// JSToNumber(null) => #0 |
- return ReplaceWith(jsgraph()->ZeroConstant()); |
+ return Replace(jsgraph()->ZeroConstant()); |
} |
if (input_type->Is(Type::Boolean())) { |
// JSToNumber(x:boolean) => BooleanToNumber(x) |
- return ReplaceWith( |
- graph()->NewNode(simplified()->BooleanToNumber(), input)); |
+ return Replace(graph()->NewNode(simplified()->BooleanToNumber(), input)); |
} |
// TODO(turbofan): js-typed-lowering of ToNumber(x:string) |
return NoChange(); |
@@ -584,11 +583,11 @@ Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) { |
return Changed(input); // JSToString(x:string) => x |
} |
if (input_type->Is(Type::Undefined())) { |
- return ReplaceWith(jsgraph()->HeapConstant( |
+ return Replace(jsgraph()->HeapConstant( |
graph()->zone()->isolate()->factory()->undefined_string())); |
} |
if (input_type->Is(Type::Null())) { |
- return ReplaceWith(jsgraph()->HeapConstant( |
+ return Replace(jsgraph()->HeapConstant( |
graph()->zone()->isolate()->factory()->null_string())); |
} |
// TODO(turbofan): js-typed-lowering of ToString(x:boolean) |
@@ -610,26 +609,26 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { |
} |
if (input_type->Is(Type::Undefined())) { |
// JSToBoolean(undefined) => #false |
- return ReplaceWith(jsgraph()->FalseConstant()); |
+ return Replace(jsgraph()->FalseConstant()); |
} |
if (input_type->Is(Type::Null())) { |
// JSToBoolean(null) => #false |
- return ReplaceWith(jsgraph()->FalseConstant()); |
+ return Replace(jsgraph()->FalseConstant()); |
} |
if (input_type->Is(Type::DetectableReceiver())) { |
// JSToBoolean(x:detectable) => #true |
- return ReplaceWith(jsgraph()->TrueConstant()); |
+ return Replace(jsgraph()->TrueConstant()); |
} |
if (input_type->Is(Type::Undetectable())) { |
// JSToBoolean(x:undetectable) => #false |
- return ReplaceWith(jsgraph()->FalseConstant()); |
+ return Replace(jsgraph()->FalseConstant()); |
} |
if (input_type->Is(Type::OrderedNumber())) { |
// JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) |
Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input, |
jsgraph()->ZeroConstant()); |
Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); |
- return ReplaceWith(inv); |
+ return Replace(inv); |
} |
if (input_type->Is(Type::String())) { |
// JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) |
@@ -639,7 +638,7 @@ Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { |
Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length, |
jsgraph()->ZeroConstant()); |
Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); |
- return ReplaceWith(inv); |
+ return Replace(inv); |
} |
return NoChange(); |
} |
@@ -649,16 +648,10 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
// Try to reduce the input first. |
Node* const input = node->InputAt(0); |
Reduction reduction = ReduceJSToBooleanInput(input); |
- if (reduction.Changed()) { |
- NodeProperties::ReplaceWithValue(node, reduction.replacement()); |
- return reduction; |
- } |
- Type* const input_type = NodeProperties::GetBounds(input).upper; |
- if (input->opcode() == IrOpcode::kPhi && input_type->Is(Type::Primitive())) { |
- Node* const context = node->InputAt(1); |
- // JSToBoolean(phi(x1,...,xn,control):primitive) |
- // => phi(JSToBoolean(x1),...,JSToBoolean(xn),control):boolean |
- RelaxEffects(node); |
+ if (reduction.Changed()) return reduction; |
+ if (input->opcode() == IrOpcode::kPhi) { |
+ // JSToBoolean(phi(x1,...,xn,control),context) |
+ // => phi(JSToBoolean(x1,no-context),...,JSToBoolean(xn,no-context)) |
int const input_count = input->InputCount() - 1; |
Node* const control = input->InputAt(input_count); |
DCHECK_LE(0, input_count); |
@@ -673,8 +666,14 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
if (reduction.Changed()) { |
value = reduction.replacement(); |
} else { |
- value = graph()->NewNode(javascript()->ToBoolean(), value, context, |
- graph()->start(), graph()->start()); |
+ // We must be very careful not to introduce cycles when pushing |
+ // operations into phis. It is safe for {value}, since it appears |
+ // as input to the phi that we are replacing, but it's not safe |
+ // to simply reuse the context of the {node}. However, ToBoolean() |
+ // does not require a context anyways, so it's safe to discard it |
+ // here and pass the dummy context. |
+ value = graph()->NewNode(javascript()->ToBoolean(), value, |
+ jsgraph()->NoContextConstant()); |
} |
if (i < node->InputCount()) { |
node->ReplaceInput(i, value); |
@@ -690,6 +689,37 @@ Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { |
node->TrimInputCount(input_count + 1); |
return Changed(node); |
} |
+ if (input->opcode() == IrOpcode::kSelect) { |
+ // JSToBoolean(select(c,x1,x2),context) |
+ // => select(c,JSToBoolean(x1,no-context),...,JSToBoolean(x2,no-context)) |
+ int const input_count = input->InputCount(); |
+ BranchHint const input_hint = SelectParametersOf(input->op()).hint(); |
+ DCHECK_EQ(3, input_count); |
+ DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); |
+ DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); |
+ node->set_op(common()->Select(kMachAnyTagged, input_hint)); |
+ node->InsertInput(graph()->zone(), 0, input->InputAt(0)); |
+ for (int i = 1; i < input_count; ++i) { |
+ Node* value = input->InputAt(i); |
+ // Recursively try to reduce the value first. |
+ Reduction reduction = ReduceJSToBooleanInput(value); |
+ if (reduction.Changed()) { |
+ value = reduction.replacement(); |
+ } else { |
+ // We must be very careful not to introduce cycles when pushing |
+ // operations into selects. It is safe for {value}, since it appears |
+ // as input to the select that we are replacing, but it's not safe |
+ // to simply reuse the context of the {node}. However, ToBoolean() |
+ // does not require a context anyways, so it's safe to discard it |
+ // here and pass the dummy context. |
+ value = graph()->NewNode(javascript()->ToBoolean(), value, |
+ jsgraph()->NoContextConstant()); |
+ } |
+ node->ReplaceInput(i, value); |
+ } |
+ DCHECK_EQ(3, node->InputCount()); |
+ return Changed(node); |
+ } |
return NoChange(); |
} |
@@ -915,22 +945,15 @@ Reduction JSTypedLowering::Reduce(Node* node) { |
return ReduceNumberBinop(node, simplified()->NumberModulus()); |
case IrOpcode::kJSUnaryNot: { |
Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); |
- Node* value; |
if (result.Changed()) { |
// JSUnaryNot(x:boolean) => BooleanNot(x) |
- value = |
- graph()->NewNode(simplified()->BooleanNot(), result.replacement()); |
- NodeProperties::ReplaceWithValue(node, value); |
- return Changed(value); |
+ node = result.replacement(); |
} else { |
// JSUnaryNot(x) => BooleanNot(JSToBoolean(x)) |
- value = graph()->NewNode(simplified()->BooleanNot(), node); |
node->set_op(javascript()->ToBoolean()); |
- NodeProperties::ReplaceWithValue(node, value, node); |
- // Note: ReplaceUses() smashes all uses, so smash it back here. |
- value->ReplaceInput(0, node); |
- return Changed(node); |
} |
+ Node* value = graph()->NewNode(simplified()->BooleanNot(), node); |
+ return Replace(value); |
} |
case IrOpcode::kJSToBoolean: |
return ReduceJSToBoolean(node); |