| // Copyright (c) 2018, 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.analysis.type; |
| |
| import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.DOUBLE; |
| import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.FLOAT; |
| import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.INT; |
| import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.LONG; |
| import static org.junit.Assert.assertEquals; |
| |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.TestParametersCollection; |
| import com.android.tools.r8.errors.Unreachable; |
| import com.android.tools.r8.ir.analysis.AnalysisTestBase; |
| import com.android.tools.r8.ir.code.ConstNumber; |
| import com.android.tools.r8.ir.code.IRCode; |
| import com.android.tools.r8.ir.code.Instruction; |
| import com.android.tools.r8.smali.SmaliBuilder; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.StringUtils; |
| import com.google.common.collect.ImmutableList; |
| import java.util.function.Consumer; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| @RunWith(Parameterized.class) |
| public class TypeConstraintOnTrivialPhiTest extends AnalysisTestBase { |
| |
| private enum Config { |
| INT, |
| FLOAT, |
| LONG, |
| DOUBLE; |
| |
| public boolean isSingle() { |
| return this == INT || this == FLOAT; |
| } |
| |
| public String getTestName() { |
| return toString().toLowerCase() + "ConstraintOnTrivialPhiTest"; |
| } |
| |
| public String getConstInstruction() { |
| return isSingle() ? "const/4 v0, 0x0" : "const-wide v0, 0x0"; |
| } |
| |
| public String getMoveInstruction() { |
| return isSingle() ? "move v1, v0" : "move-wide v2, v0"; |
| } |
| |
| public String getInvokeStaticInstruction() { |
| switch (this) { |
| case INT: |
| return "invoke-static {v1}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;"; |
| case FLOAT: |
| return "invoke-static {v1}, Ljava/lang/Float;->toString(F)Ljava/lang/String;"; |
| case LONG: |
| return "invoke-static {v2, v3}, Ljava/lang/Long;->toString(J)Ljava/lang/String;"; |
| case DOUBLE: |
| return "invoke-static {v2, v3}, Ljava/lang/Double;->toString(D)Ljava/lang/String;"; |
| } |
| throw new Unreachable(); |
| } |
| } |
| |
| @Parameterized.Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withAllRuntimes().build(); |
| } |
| |
| public TypeConstraintOnTrivialPhiTest(TestParameters parameters) throws Exception { |
| super(parameters, buildApp(), "TestClass"); |
| } |
| |
| public static AndroidApp buildApp() throws Exception { |
| SmaliBuilder smaliBuilder = new SmaliBuilder("TestClass"); |
| for (Config config : Config.values()) { |
| String code = |
| StringUtils.lines( |
| config.getConstInstruction(), |
| ":label_1", |
| "if-eqz p0, :label_2", |
| config.getMoveInstruction(), |
| config.getInvokeStaticInstruction(), |
| ":label_2", |
| "goto :label_1"); |
| smaliBuilder.addStaticMethod("void", config.getTestName(), ImmutableList.of("int"), 4, code); |
| } |
| return smaliBuilder.build(); |
| } |
| |
| @Test |
| public void testIntConstraintOnTrivialPhi() throws Exception { |
| buildAndCheckIR("intConstraintOnTrivialPhiTest", testInspector(INT)); |
| } |
| |
| @Test |
| public void testFloatConstraintOnTrivialPhi() throws Exception { |
| buildAndCheckIR("floatConstraintOnTrivialPhiTest", testInspector(FLOAT)); |
| } |
| |
| @Test |
| public void testLongConstraintOnTrivialPhi() throws Exception { |
| buildAndCheckIR("longConstraintOnTrivialPhiTest", testInspector(LONG)); |
| } |
| |
| @Test |
| public void testDoubleConstraintOnTrivialPhi() throws Exception { |
| buildAndCheckIR("doubleConstraintOnTrivialPhiTest", testInspector(DOUBLE)); |
| } |
| |
| private static Consumer<IRCode> testInspector(TypeLatticeElement expectedType) { |
| return code -> { |
| ConstNumber constNumberInstruction = getMatchingInstruction(code, Instruction::isConstNumber); |
| assertEquals(expectedType, constNumberInstruction.outValue().getTypeLattice()); |
| }; |
| } |
| } |