blob: 27a3cba9f347b20aac8daec544745ac2404b0d48 [file] [log] [blame]
// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion.passes;
import com.android.tools.r8.algorithms.scc.SCC;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.UnusedArgument;
import com.android.tools.r8.ir.code.Value;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Set;
public class TrivialPhiSimplifier {
public static void replaceUnusedArgumentTrivialPhis(UnusedArgument unusedArgument) {
replaceTrivialPhis(unusedArgument.outValue());
for (Phi phiUser : unusedArgument.outValue().uniquePhiUsers()) {
phiUser.removeTrivialPhi();
}
assert !unusedArgument.outValue().hasPhiUsers();
}
@SuppressWarnings("ReferenceEquality")
public static void ensureDirectStringNewToInit(AppView<?> appView, IRCode code) {
boolean changed = false;
DexItemFactory dexItemFactory = appView.dexItemFactory();
for (Instruction instruction : code.instructions()) {
if (instruction.isInvokeDirect()) {
InvokeDirect invoke = instruction.asInvokeDirect();
DexMethod method = invoke.getInvokedMethod();
if (dexItemFactory.isConstructor(method)
&& method.holder == dexItemFactory.stringType
&& invoke.getReceiver().isPhi()) {
NewInstance newInstance = findNewInstance(invoke.getReceiver().asPhi());
replaceTrivialPhis(newInstance.outValue());
if (invoke.getReceiver().isPhi()) {
throw new CompilationError(
"Failed to remove trivial phis between new-instance and <init>");
}
newInstance.markNoSpilling();
changed = true;
}
}
}
assert !changed || code.isConsistentSSA(appView);
}
private static NewInstance findNewInstance(Phi phi) {
Set<Phi> seen = Sets.newIdentityHashSet();
Set<Value> values = Sets.newIdentityHashSet();
recursiveAddOperands(phi, seen, values);
if (values.size() != 1) {
throw new CompilationError("Failed to identify unique new-instance for <init>");
}
Value newInstanceValue = values.iterator().next();
if (newInstanceValue.definition == null || !newInstanceValue.definition.isNewInstance()) {
throw new CompilationError("Invalid defining value for call to <init>");
}
return newInstanceValue.definition.asNewInstance();
}
private static void recursiveAddOperands(Phi phi, Set<Phi> seen, Set<Value> values) {
for (Value operand : phi.getOperands()) {
if (!operand.isPhi()) {
values.add(operand);
} else {
Phi phiOp = operand.asPhi();
if (seen.add(phiOp)) {
recursiveAddOperands(phiOp, seen, values);
}
}
}
}
// We compute the set of strongly connected phis making use of the out value and replace all
// trivial ones by the out value.
// This is a simplified variant of the removeRedundantPhis algorithm in Section 3.2 of:
// http://compilers.cs.uni-saarland.de/papers/bbhlmz13cc.pdf
private static void replaceTrivialPhis(Value outValue) {
List<Set<Value>> components = new SCC<Value>(Value::uniquePhiUsers).computeSCC(outValue);
for (int i = components.size() - 1; i >= 0; i--) {
Set<Value> component = components.get(i);
if (component.size() == 1 && component.iterator().next() == outValue) {
continue;
}
Set<Phi> trivialPhis = Sets.newIdentityHashSet();
for (Value value : component) {
boolean isTrivial = true;
Phi p = value.asPhi();
for (Value op : p.getOperands()) {
if (op != outValue && !component.contains(op)) {
isTrivial = false;
break;
}
}
if (isTrivial) {
trivialPhis.add(p);
}
}
for (Phi trivialPhi : trivialPhis) {
for (Value op : trivialPhi.getOperands()) {
op.removePhiUser(trivialPhi);
}
trivialPhi.replaceUsers(outValue);
trivialPhi.getBlock().removePhi(trivialPhi);
}
}
}
}