Collect the set of root aliases in the class inliner
This will be used to improve the precision of the class inliner's cost analysis. For example, reading a field from the root or an alias of the root should not contribute to the cost.
Change-Id: Ic0ad43c8b8d62febc276985a622c7699795aff54
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 90c746b..3e11ca6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -84,6 +85,11 @@
private int estimatedCombinedSizeForInlining = 0;
+ // Set of values that may be an alias of the "root" instance (including the root instance itself).
+ // TODO(b/144825216): Distinguish the "may-aliases" from the "must-aliases" such that the cost
+ // analysis is not optimistic.
+ private final Set<Value> receivers;
+
InlineCandidateProcessor(
AppView<AppInfoWithLiveness> appView,
LambdaRewriter lambdaRewriter,
@@ -99,12 +105,17 @@
this.method = method;
this.root = root;
this.isProcessedConcurrently = isProcessedConcurrently;
+ this.receivers = SetUtils.newIdentityHashSet(root.outValue());
}
int getEstimatedCombinedSizeForInlining() {
return estimatedCombinedSizeForInlining;
}
+ Set<Value> getReceivers() {
+ return receivers;
+ }
+
// Checks if the root instruction defines eligible value, i.e. the value
// exists and we have a definition of its class.
EligibilityStatus isInstanceEligible() {
@@ -258,7 +269,7 @@
*/
InstructionOrPhi areInstanceUsersEligible(Supplier<InliningOracle> defaultOracle) {
// No Phi users.
- if (eligibleInstance.numberOfPhiUsers() > 0) {
+ if (eligibleInstance.hasPhiUsers()) {
return eligibleInstance.firstPhiUser(); // Not eligible.
}
@@ -267,10 +278,12 @@
Set<Instruction> indirectUsers = Sets.newIdentityHashSet();
for (Instruction user : currentUsers) {
if (user.isAssume()) {
- if (user.outValue().numberOfPhiUsers() > 0) {
- return user.outValue().firstPhiUser(); // Not eligible.
+ Value alias = user.outValue();
+ if (alias.hasPhiUsers()) {
+ return alias.firstPhiUser(); // Not eligible.
}
- indirectUsers.addAll(user.outValue().uniqueUsers());
+ receivers.add(alias);
+ indirectUsers.addAll(alias.uniqueUsers());
continue;
}
// Field read/write.
@@ -434,6 +447,9 @@
if (methodCallsOnInstance.isEmpty()) {
return false;
}
+ assert methodCallsOnInstance.keySet().stream()
+ .map(InvokeMethodWithReceiver::getReceiver)
+ .allMatch(receivers::contains);
inliner.performForcedInlining(method, code, methodCallsOnInstance);
return true;
}
@@ -446,6 +462,7 @@
Assume<?> assumeInstruction = user.asAssume();
Value src = assumeInstruction.src();
Value dest = assumeInstruction.outValue();
+ assert receivers.contains(dest);
assert !dest.hasPhiUsers();
dest.replaceUsers(src);
removeInstruction(user);
@@ -647,7 +664,7 @@
// - if it is a regular chaining pattern where the only users of the out value are receivers to
// other invocations. In that case, we should add all indirect users of the out value to ensure
// they can also be inlined.
- private static boolean isEligibleInvokeWithAllUsersAsReceivers(
+ private boolean isEligibleInvokeWithAllUsersAsReceivers(
ClassInlinerEligibility eligibility,
InvokeMethodWithReceiver invoke,
Set<Instruction> indirectUsers) {
@@ -667,6 +684,10 @@
return false;
}
+ // Since the invoke-instruction may return the receiver, the out-value may be an alias of the
+ // receiver.
+ receivers.add(outValue);
+
Set<Instruction> currentUsers = outValue.uniqueUsers();
while (!currentUsers.isEmpty()) {
Set<Instruction> indirectOutValueUsers = Sets.newIdentityHashSet();
@@ -676,6 +697,7 @@
if (outValueAlias.hasPhiUsers() || outValueAlias.hasDebugUsers()) {
return false;
}
+ receivers.add(outValueAlias);
indirectOutValueUsers.addAll(outValueAlias.uniqueUsers());
continue;
}