Commit 384e764a authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm][turbofan] Add effect output to trap conditionals

TrapIf and TrapUnless had an effect input, but not an effect output.
This is not canonical for Turbofan graphs. This CL puts them properly
into the effect chain.

Drive-by:
- Remove premature optimization in WasmGraphBuilder::TrapIfEq{32,64}.
- Change LoadFromObject to Load when loading from a stack slot.

Change-Id: I3fc43e693fa0507406dc31208e487026b0e5156b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3714240Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81318}
parent 49d15209
...@@ -175,17 +175,31 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) { ...@@ -175,17 +175,31 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) {
if (branch_condition.IsSet()) { if (branch_condition.IsSet()) {
bool condition_value = branch_condition.is_true; bool condition_value = branch_condition.is_true;
if (condition_value == trapping_condition) { if (condition_value == trapping_condition) {
// Special case: Trap directly inside a branch without sibling nodes. // Special case: Trap directly below an IfTrue/IfFalse without sibling
// Replace the branch with the trap. // nodes. Replace the branch with the trap.
// condition control condition control //
// | \ / \ / // condition effect control
// | Branch TrapIf // | \ / \ /
// | / \ ==> | // | X X
// | IfTrue IfFalse <subgraph2> // | / \ / \
// | / | // | / Branch \
// TrapIf <subraph2> Dead // | / / | \
// | | // | / IfTrue IfFalse \
// <subgraph1> <subgraph1> // | | / | \
// | | / control2 effect2
// TrapIf
// | \
// control1 effect1
//
// --- becomes ---
//
// condition effect control
// \ | /
// \ | /
// TrapIf
// / \
// control2 effect2
//
// (and symmetrically for TrapUnless.) // (and symmetrically for TrapUnless.)
if (((trapping_condition && if (((trapping_condition &&
control_input->opcode() == IrOpcode::kIfTrue) || control_input->opcode() == IrOpcode::kIfTrue) ||
...@@ -201,10 +215,22 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) { ...@@ -201,10 +215,22 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) {
} }
DCHECK_NOT_NULL(other_if_branch); DCHECK_NOT_NULL(other_if_branch);
Node* effect_input = NodeProperties::GetEffectInput(node);
Node* other_effect = nullptr;
for (Node* use : effect_input->uses()) {
if (use != node) {
DCHECK_EQ(other_effect, nullptr);
other_effect = use;
}
}
DCHECK_NOT_NULL(other_effect);
node->ReplaceInput(NodeProperties::FirstControlIndex(node), node->ReplaceInput(NodeProperties::FirstControlIndex(node),
NodeProperties::GetControlInput(branch)); NodeProperties::GetControlInput(branch));
ReplaceWithValue(node, dead(), dead(), dead()); ReplaceWithValue(node, dead(), dead(), dead());
ReplaceWithValue(other_if_branch, node, node, node); ReplaceWithValue(other_if_branch, dead(), dead(), node);
other_effect->ReplaceInput(
NodeProperties::FirstEffectIndex(other_effect), node);
other_if_branch->Kill(); other_if_branch->Kill();
control_input->Kill(); control_input->Kill();
branch->Kill(); branch->Kill();
...@@ -215,14 +241,16 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) { ...@@ -215,14 +241,16 @@ Reduction BranchElimination::ReduceTrapConditional(Node* node) {
// General case: This will always trap. Mark its outputs as dead and // General case: This will always trap. Mark its outputs as dead and
// connect it to graph()->end(). // connect it to graph()->end().
ReplaceWithValue(node, dead(), dead(), dead()); ReplaceWithValue(node, dead(), dead(), dead());
Node* effect = NodeProperties::GetEffectInput(node); Node* control = graph()->NewNode(common()->Throw(), node, node);
Node* control = graph()->NewNode(common()->Throw(), effect, node);
NodeProperties::MergeControlToEnd(graph(), common(), control); NodeProperties::MergeControlToEnd(graph(), common(), control);
Revisit(graph()->end()); Revisit(graph()->end());
return Changed(node); return Changed(node);
} else { } else {
// This will not trap, remove it. // This will not trap, remove it by relaxing effect/control.
return Replace(control_input); RelaxEffectsAndControls(node);
Node* control = NodeProperties::GetControlInput(node);
node->Kill();
return Replace(control); // Irrelevant argument
} }
} }
return UpdateStatesHelper(node, from_input, condition, node, return UpdateStatesHelper(node, from_input, condition, node,
......
...@@ -491,14 +491,17 @@ Reduction CommonOperatorReducer::ReduceTrapConditional(Node* trap) { ...@@ -491,14 +491,17 @@ Reduction CommonOperatorReducer::ReduceTrapConditional(Node* trap) {
// This will always trap. Mark its outputs as dead and connect it to // This will always trap. Mark its outputs as dead and connect it to
// graph()->end(). // graph()->end().
ReplaceWithValue(trap, dead(), dead(), dead()); ReplaceWithValue(trap, dead(), dead(), dead());
Node* effect = NodeProperties::GetEffectInput(trap); Node* control = graph()->NewNode(common()->Throw(), trap, trap);
Node* control = graph()->NewNode(common()->Throw(), effect, trap);
NodeProperties::MergeControlToEnd(graph(), common(), control); NodeProperties::MergeControlToEnd(graph(), common(), control);
Revisit(graph()->end()); Revisit(graph()->end());
return Changed(trap); return Changed(trap);
} else { } else {
// This will not trap, remove it. // This will not trap, remove it by relaxing effect/control.
return Replace(NodeProperties::GetControlInput(trap)); Node* control = NodeProperties::GetControlInput(trap);
ReplaceWithValue(trap, dead());
trap->Kill();
// The argument below is irrelevant, picked {control} for debugging.
return Replace(control);
} }
} }
......
...@@ -768,7 +768,7 @@ struct CommonOperatorGlobalCache final { ...@@ -768,7 +768,7 @@ struct CommonOperatorGlobalCache final {
IrOpcode::kTrapIf, // opcode IrOpcode::kTrapIf, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties Operator::kFoldable | Operator::kNoThrow, // properties
"TrapIf", // name "TrapIf", // name
1, 1, 1, 0, 0, 1, // counts 1, 1, 1, 0, 1, 1, // counts
trap_id) {} // parameter trap_id) {} // parameter
}; };
#define CACHED_TRAP_IF(Trap) \ #define CACHED_TRAP_IF(Trap) \
...@@ -783,7 +783,7 @@ struct CommonOperatorGlobalCache final { ...@@ -783,7 +783,7 @@ struct CommonOperatorGlobalCache final {
IrOpcode::kTrapUnless, // opcode IrOpcode::kTrapUnless, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties Operator::kFoldable | Operator::kNoThrow, // properties
"TrapUnless", // name "TrapUnless", // name
1, 1, 1, 0, 0, 1, // counts 1, 1, 1, 0, 1, 1, // counts
trap_id) {} // parameter trap_id) {} // parameter
}; };
#define CACHED_TRAP_UNLESS(Trap) \ #define CACHED_TRAP_UNLESS(Trap) \
...@@ -1010,7 +1010,7 @@ const Operator* CommonOperatorBuilder::TrapIf(TrapId trap_id) { ...@@ -1010,7 +1010,7 @@ const Operator* CommonOperatorBuilder::TrapIf(TrapId trap_id) {
IrOpcode::kTrapIf, // opcode IrOpcode::kTrapIf, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties Operator::kFoldable | Operator::kNoThrow, // properties
"TrapIf", // name "TrapIf", // name
1, 1, 1, 0, 0, 1, // counts 1, 1, 1, 0, 1, 1, // counts
trap_id); // parameter trap_id); // parameter
} }
...@@ -1029,7 +1029,7 @@ const Operator* CommonOperatorBuilder::TrapUnless(TrapId trap_id) { ...@@ -1029,7 +1029,7 @@ const Operator* CommonOperatorBuilder::TrapUnless(TrapId trap_id) {
IrOpcode::kTrapUnless, // opcode IrOpcode::kTrapUnless, // opcode
Operator::kFoldable | Operator::kNoThrow, // properties Operator::kFoldable | Operator::kNoThrow, // properties
"TrapUnless", // name "TrapUnless", // name
1, 1, 1, 0, 0, 1, // counts 1, 1, 1, 0, 1, 1, // counts
trap_id); // parameter trap_id); // parameter
} }
......
...@@ -54,6 +54,8 @@ bool CanAllocate(const Node* node) { ...@@ -54,6 +54,8 @@ bool CanAllocate(const Node* node) {
case IrOpcode::kStoreLane: case IrOpcode::kStoreLane:
case IrOpcode::kStoreToObject: case IrOpcode::kStoreToObject:
case IrOpcode::kInitializeImmutableInObject: case IrOpcode::kInitializeImmutableInObject:
case IrOpcode::kTrapIf:
case IrOpcode::kTrapUnless:
case IrOpcode::kUnalignedLoad: case IrOpcode::kUnalignedLoad:
case IrOpcode::kUnalignedStore: case IrOpcode::kUnalignedStore:
case IrOpcode::kUnreachable: case IrOpcode::kUnreachable:
......
...@@ -1155,7 +1155,7 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -1155,7 +1155,7 @@ struct SimplifiedOperatorGlobalCache final {
IsNullOperator kIsNull; IsNullOperator kIsNull;
struct IsNotNullOperator final : public Operator { struct IsNotNullOperator final : public Operator {
explicit IsNotNullOperator() IsNotNullOperator()
: Operator(IrOpcode::kIsNotNull, Operator::kPure, "IsNotNull", 1, 0, 0, : Operator(IrOpcode::kIsNotNull, Operator::kPure, "IsNotNull", 1, 0, 0,
1, 0, 0) {} 1, 0, 0) {}
}; };
...@@ -1173,7 +1173,7 @@ struct SimplifiedOperatorGlobalCache final { ...@@ -1173,7 +1173,7 @@ struct SimplifiedOperatorGlobalCache final {
: Operator( : Operator(
IrOpcode::kAssertNotNull, IrOpcode::kAssertNotNull,
Operator::kNoWrite | Operator::kNoThrow | Operator::kIdempotent, Operator::kNoWrite | Operator::kNoThrow | Operator::kIdempotent,
"AssertNotNull", 1, 1, 1, 1, 0, 1) {} "AssertNotNull", 1, 1, 1, 1, 1, 1) {}
}; };
AssertNotNullOperator kAssertNotNull; AssertNotNullOperator kAssertNotNull;
#endif #endif
......
...@@ -1144,8 +1144,6 @@ Node* WasmGraphBuilder::AssertNotNull(Node* object, ...@@ -1144,8 +1144,6 @@ Node* WasmGraphBuilder::AssertNotNull(Node* object,
void WasmGraphBuilder::TrapIfEq32(wasm::TrapReason reason, Node* node, void WasmGraphBuilder::TrapIfEq32(wasm::TrapReason reason, Node* node,
int32_t val, int32_t val,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
Int32Matcher m(node);
if (m.HasResolvedValue() && !m.Is(val)) return;
if (val == 0) { if (val == 0) {
TrapIfFalse(reason, node, position); TrapIfFalse(reason, node, position);
} else { } else {
...@@ -1163,8 +1161,6 @@ void WasmGraphBuilder::ZeroCheck32(wasm::TrapReason reason, Node* node, ...@@ -1163,8 +1161,6 @@ void WasmGraphBuilder::ZeroCheck32(wasm::TrapReason reason, Node* node,
void WasmGraphBuilder::TrapIfEq64(wasm::TrapReason reason, Node* node, void WasmGraphBuilder::TrapIfEq64(wasm::TrapReason reason, Node* node,
int64_t val, int64_t val,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
Int64Matcher m(node);
if (m.HasResolvedValue() && !m.Is(val)) return;
TrapIfTrue(reason, gasm_->Word64Equal(node, Int64Constant(val)), position); TrapIfTrue(reason, gasm_->Word64Equal(node, Int64Constant(val)), position);
} }
...@@ -2314,18 +2310,17 @@ Node* WasmGraphBuilder::GetExceptionValues(Node* except_obj, ...@@ -2314,18 +2310,17 @@ Node* WasmGraphBuilder::GetExceptionValues(Node* except_obj,
Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right, Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
ZeroCheck32(wasm::kTrapDivByZero, right, position); ZeroCheck32(wasm::kTrapDivByZero, right, position);
Node* before = control(); Node* previous_effect = effect();
Node* denom_is_m1; Node* denom_is_m1;
Node* denom_is_not_m1; Node* denom_is_not_m1;
BranchExpectFalse(gasm_->Word32Equal(right, Int32Constant(-1)), &denom_is_m1, BranchExpectFalse(gasm_->Word32Equal(right, Int32Constant(-1)), &denom_is_m1,
&denom_is_not_m1); &denom_is_not_m1);
SetControl(denom_is_m1); SetControl(denom_is_m1);
TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position); TrapIfEq32(wasm::kTrapDivUnrepresentable, left, kMinInt, position);
if (control() != denom_is_m1) { Node* merge = Merge(control(), denom_is_not_m1);
SetControl(Merge(denom_is_not_m1, control())); SetEffectControl(graph()->NewNode(mcgraph()->common()->EffectPhi(2), effect(),
} else { previous_effect, merge),
SetControl(before); merge);
}
return gasm_->Int32Div(left, right); return gasm_->Int32Div(left, right);
} }
...@@ -2528,7 +2523,7 @@ Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right, ...@@ -2528,7 +2523,7 @@ Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
MachineType::Int64(), wasm::kTrapDivByZero, position); MachineType::Int64(), wasm::kTrapDivByZero, position);
} }
ZeroCheck64(wasm::kTrapDivByZero, right, position); ZeroCheck64(wasm::kTrapDivByZero, right, position);
Node* before = control(); Node* previous_effect = effect();
Node* denom_is_m1; Node* denom_is_m1;
Node* denom_is_not_m1; Node* denom_is_not_m1;
BranchExpectFalse(gasm_->Word64Equal(right, Int64Constant(-1)), &denom_is_m1, BranchExpectFalse(gasm_->Word64Equal(right, Int64Constant(-1)), &denom_is_m1,
...@@ -2536,11 +2531,10 @@ Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right, ...@@ -2536,11 +2531,10 @@ Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right,
SetControl(denom_is_m1); SetControl(denom_is_m1);
TrapIfEq64(wasm::kTrapDivUnrepresentable, left, TrapIfEq64(wasm::kTrapDivUnrepresentable, left,
std::numeric_limits<int64_t>::min(), position); std::numeric_limits<int64_t>::min(), position);
if (control() != denom_is_m1) { Node* merge = Merge(control(), denom_is_not_m1);
SetControl(Merge(denom_is_not_m1, control())); SetEffectControl(graph()->NewNode(mcgraph()->common()->EffectPhi(2), effect(),
} else { previous_effect, merge),
SetControl(before); merge);
}
return gasm_->Int64Div(left, right); return gasm_->Int64Div(left, right);
} }
...@@ -2598,7 +2592,7 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right, ...@@ -2598,7 +2592,7 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right,
ZeroCheck32(trap_zero, call, position); ZeroCheck32(trap_zero, call, position);
TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position); TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position);
return gasm_->LoadFromObject(result_type, stack_slot, 0); return gasm_->Load(result_type, stack_slot, 0);
} }
Node* WasmGraphBuilder::IsNull(Node* object) { Node* WasmGraphBuilder::IsNull(Node* object) {
......
...@@ -119,16 +119,15 @@ Reduction WasmGCOperatorReducer::ReduceWasmTypeCast(Node* node) { ...@@ -119,16 +119,15 @@ Reduction WasmGCOperatorReducer::ReduceWasmTypeCast(Node* node) {
Node* non_trapping_condition = object_type.type.is_nullable() Node* non_trapping_condition = object_type.type.is_nullable()
? gasm_.IsNull(object) ? gasm_.IsNull(object)
: gasm_.Int32Constant(0); : gasm_.Int32Constant(0);
Node* trap = gasm_.TrapUnless(SetType(non_trapping_condition, wasm::kWasmI32),
gasm_.TrapUnless(SetType(non_trapping_condition, wasm::kWasmI32), TrapId::kTrapIllegalCast);
TrapId::kTrapIllegalCast);
// TODO(manoskouk): Improve the type when we have nullref. // TODO(manoskouk): Improve the type when we have nullref.
Node* null_node = gasm_.Null(); Node* null_node = gasm_.Null();
ReplaceWithValue( ReplaceWithValue(
node, node,
SetType(null_node, wasm::ValueType::Ref(rtt_type.type.ref_index(), SetType(null_node, wasm::ValueType::Ref(rtt_type.type.ref_index(),
wasm::kNullable)), wasm::kNullable)),
effect, trap); gasm_.effect(), gasm_.control());
node->Kill(); node->Kill();
return Replace(null_node); return Replace(null_node);
} }
......
...@@ -125,9 +125,8 @@ Reduction WasmTyper::Reduce(Node* node) { ...@@ -125,9 +125,8 @@ Reduction WasmTyper::Reduce(Node* node) {
previous_effect); previous_effect);
node->ReplaceInput(NodeProperties::FirstControlIndex(node), node->ReplaceInput(NodeProperties::FirstControlIndex(node),
previous_control); previous_control);
// We do not replace {object}'s effect input to {node} because {node}
// has no effect output.
object->ReplaceInput(NodeProperties::FirstValueIndex(object), node); object->ReplaceInput(NodeProperties::FirstValueIndex(object), node);
object->ReplaceInput(NodeProperties::FirstEffectIndex(object), node);
object->ReplaceInput(NodeProperties::FirstControlIndex(object), node); object->ReplaceInput(NodeProperties::FirstControlIndex(object), node);
Revisit(object); Revisit(object);
} }
......
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