Look at phis in ReplaceUsesDominatedBy.
When the instruction does not dominate the phi, but the instruction
that it is replacing does by being an input, do the replacement.
It was a missed improvement opportunity before, but the String.<init>
handling in the builder needs it for correctness.
bug: 111758226
Test: 563-checker-fakestring
Change-Id: I37f01e1aabc2a1f60e21fc57728f07248adbc946
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 8f822cc..79a7e2c 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1301,6 +1301,15 @@
++it;
if (dominator->StrictlyDominates(user)) {
user->ReplaceInput(replacement, index);
+ } else if (user->IsPhi() && !user->AsPhi()->IsCatchPhi()) {
+ // If the input flows from a block dominated by `dominator`, we can replace it.
+ // We do not perform this for catch phis as we don't have control flow support
+ // for their inputs.
+ const ArenaVector<HBasicBlock*>& predecessors = user->GetBlock()->GetPredecessors();
+ HBasicBlock* predecessor = predecessors[index];
+ if (dominator->GetBlock()->Dominates(predecessor)) {
+ user->ReplaceInput(replacement, index);
+ }
}
}
}
diff --git a/test/563-checker-fakestring/smali/TestCase.smali b/test/563-checker-fakestring/smali/TestCase.smali
index 9d10bd7..0fe39ee 100644
--- a/test/563-checker-fakestring/smali/TestCase.smali
+++ b/test/563-checker-fakestring/smali/TestCase.smali
@@ -305,3 +305,35 @@
return-object v0
.end method
+
+## CHECK-START: java.lang.String TestCase.loopAndStringInitAndPhi(byte[], boolean) register (after)
+## CHECK: NewInstance
+## CHECK-NOT: NewInstance
+## CHECK-DAG: <<Invoke1:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
+## CHECK-DAG: <<Invoke2:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
+## CHECK-DAG: <<Phi:l\d+>> Phi [<<Invoke2>>,<<Invoke1>>]
+## CHECK-DAG: Return [<<Phi>>]
+.method public static loopAndStringInitAndPhi([BZ)Ljava/lang/String;
+ .registers 4
+
+ if-nez p1, :allocate_other
+ new-instance v0, Ljava/lang/String;
+
+ # Loop
+ :loop_header
+ if-eqz p1, :loop_exit
+ goto :loop_header
+
+ :loop_exit
+ const-string v1, "UTF8"
+ invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
+ goto : exit
+
+ :allocate_other
+ const-string v1, "UTF8"
+ new-instance v0, Ljava/lang/String;
+ invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
+ :exit
+ return-object v0
+
+.end method
diff --git a/test/563-checker-fakestring/src/Main.java b/test/563-checker-fakestring/src/Main.java
index 3639d59..df9e9dc 100644
--- a/test/563-checker-fakestring/src/Main.java
+++ b/test/563-checker-fakestring/src/Main.java
@@ -113,7 +113,6 @@
result = (String) m.invoke(null, new Object[] { testData, false });
assertEqual(testString, result);
}
-
{
Method m = c.getMethod(
"deoptimizeNewInstanceAfterLoop", int[].class, byte[].class, int.class);
@@ -127,6 +126,13 @@
}
}
}
+ {
+ Method m = c.getMethod("loopAndStringInitAndPhi", byte[].class, boolean.class);
+ String result = (String) m.invoke(null, new Object[] { testData, true });
+ assertEqual(testString, result);
+ result = (String) m.invoke(null, new Object[] { testData, false });
+ assertEqual(testString, result);
+ }
}
public static boolean doThrow = false;