[vm/compiler] Canonicalize v1 = Phi(v2, v1)
Previously, compiler canonicalized Phi instructions which reference
only one value (modulo redefinitions):
v1 = Phi(v2, v2, ..., v2)
This change extends the canonicalization rule to also allow the Phi
to reference itself:
v1 = Phi(v2, v2, ...., v2, v1, ...., v1)
Such Phi instructions may occur in loops when local variable is not
mutated (remains the same on the back-edge).
TEST=ci
Change-Id: I2838c4307a6dd3067d52624db66487ba4682538c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195043
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index ccf3340..777e394 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -5851,8 +5851,9 @@
bool look_for_redefinition = false;
for (intptr_t i = 1; i < InputCount(); ++i) {
Definition* def = InputAt(i)->definition();
- if (def != first) {
- if (def->OriginalDefinition() != first_origin) return nullptr;
+ if ((def != first) && (def != this)) {
+ Definition* origin = def->OriginalDefinition();
+ if ((origin != first_origin) && (origin != this)) return nullptr;
look_for_redefinition = true;
}
}
@@ -5865,7 +5866,7 @@
bool found = false;
do {
Definition* def = value->definition();
- if (def == redef) {
+ if ((def == redef) || (def == this)) {
found = true;
break;
}
@@ -5973,7 +5974,8 @@
if (create_array == nullptr) {
// Do not try to fold interpolate if array is an OSR argument.
ASSERT(flow_graph->IsCompiledForOsr());
- ASSERT(value()->definition()->IsPhi());
+ ASSERT(value()->definition()->IsPhi() ||
+ value()->definition()->IsParameter());
return this;
}
// Check if the string interpolation has only constant inputs.
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index fa13d6a..3a0286c 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -261,4 +261,56 @@
kUnboxedInt64, kUnboxedUint32));
}
+ISOLATE_UNIT_TEST_CASE(IL_PhiCanonicalization) {
+ using compiler::BlockBuilder;
+
+ CompilerState S(thread, /*is_aot=*/false, /*is_optimizing=*/true);
+
+ FlowGraphBuilderHelper H;
+
+ auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
+ auto b2 = H.JoinEntry();
+ auto b3 = H.TargetEntry();
+ auto b4 = H.TargetEntry();
+
+ Definition* v0;
+ ReturnInstr* ret;
+ PhiInstr* phi;
+
+ {
+ BlockBuilder builder(H.flow_graph(), normal_entry);
+ v0 = builder.AddParameter(0, 0, /*with_frame=*/true, kTagged);
+ builder.AddInstruction(new GotoInstr(b2, S.GetNextDeoptId()));
+ }
+
+ {
+ BlockBuilder builder(H.flow_graph(), b2);
+ phi = new PhiInstr(b2, 2);
+ phi->SetInputAt(0, new Value(v0));
+ phi->SetInputAt(1, new Value(phi));
+ builder.AddPhi(phi);
+ builder.AddBranch(new StrictCompareInstr(
+ InstructionSource(), Token::kEQ_STRICT,
+ new Value(H.IntConstant(1)), new Value(phi),
+ /*needs_number_check=*/false, S.GetNextDeoptId()),
+ b3, b4);
+ }
+
+ {
+ BlockBuilder builder(H.flow_graph(), b3);
+ builder.AddInstruction(new GotoInstr(b2, S.GetNextDeoptId()));
+ }
+
+ {
+ BlockBuilder builder(H.flow_graph(), b4);
+ ret = builder.AddReturn(new Value(phi));
+ }
+
+ H.FinishGraph();
+
+ H.flow_graph()->Canonicalize();
+
+ EXPECT(ret->value()->definition() == v0);
+}
+
} // namespace dart