blob: 6a1d3b1287d89643d679e2ea9966455749ec46fb [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.lightir;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.IRToLirFinalizer;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.Timing;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class TrivialPhiLirRegression299417534Test extends TestBase {
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withDefaultCfRuntime().build();
}
private final TestParameters parameters;
public TrivialPhiLirRegression299417534Test(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testR8() throws Exception {
BooleanBox foundPhi = new BooleanBox(false);
testForR8(parameters.getBackend())
.addProgramClasses(TestClass.class)
.addKeepClassAndMembersRules(TestClass.class)
.addOptionsModification(
o ->
o.testing.irModifier =
(code, appView) -> {
if (!code.context().getReference().getName().toString().equals("foo")) {
return;
}
foundPhi.set(true);
// Update the return phi to be trivial and have both its cases be 'v2' from
// the code.
// v3 <- phi(v1, v2)
// becomes
// v3 <- phi(v2, v2)
List<BasicBlock> exits = code.computeNormalExitBlocks();
assertEquals(1, exits.size());
BasicBlock exit = exits.get(0);
assertEquals(1, exit.getPhis().size());
List<Value> operands = exit.getPhis().get(0).getOperands();
assertEquals(2, operands.size());
Value op1 = operands.get(0);
Value op2 = operands.get(1);
Value withNonPhiUse = op1.hasUsers() ? op1 : op2;
Value withOnlyPhiUse = op1.hasUsers() ? op2 : op1;
assertFalse(withOnlyPhiUse.hasUsers());
withNonPhiUse.replacePhiUsers(withOnlyPhiUse);
Phi trivialPhiBeforeLir = exit.getPhis().get(0);
assertTrue(trivialPhiBeforeLir.isTrivialPhi());
// Finalize the IR via LIR and rebuild it again.
Timing timing = Timing.empty();
BytecodeMetadataProvider metadataProvider = BytecodeMetadataProvider.empty();
IRToLirFinalizer finalizer = new IRToLirFinalizer(appView);
LirCode<Integer> lirCode =
finalizer.finalizeCode(code, metadataProvider, timing);
code.context().setCode(lirCode, appView);
IRCode irCode = code.context().buildIR(appView);
Phi trivialPhiAfterLir =
irCode.computeNormalExitBlocks().get(0).getPhis().get(0);
assertTrue(trivialPhiAfterLir.isTrivialPhi());
})
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("true");
assertTrue(foundPhi.get());
}
static class TestClass {
public static boolean foo(boolean v0) {
boolean v1 = v0 ? true : false;
boolean v2 = v1 ? true : false;
boolean v3 = v0 ? v1 : v2;
return v3;
}
public static void main(String[] args) {
System.out.println(foo(args.length == 0));
}
}
}