Move LIR/IR conversion into IRConverter.
Bug: b/225838009
Change-Id: I390238f99425a4e966fe3e214adf916ad3fd85d9
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index ff70fed..25d775a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.optimize.DeadCodeRemover.DeadInstructionResult;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LIRBuilder;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.List;
@@ -215,6 +216,11 @@
return LibraryMethodReadSetModeling.getModeledReadSetOrUnknown(appView, this);
}
+ @Override
+ public void buildLIR(LIRBuilder<Value> builder) {
+ builder.addInvokeDirect(getInvokedMethod(), arguments());
+ }
+
public static class Builder extends InvokeMethod.Builder<Builder, InvokeDirect> {
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 33f3f28..1dc485b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -81,6 +81,9 @@
import com.android.tools.r8.ir.optimize.outliner.Outliner;
import com.android.tools.r8.ir.optimize.string.StringBuilderAppendOptimizer;
import com.android.tools.r8.ir.optimize.string.StringOptimizer;
+import com.android.tools.r8.lightir.IR2LIRConverter;
+import com.android.tools.r8.lightir.LIR2IRBuilder;
+import com.android.tools.r8.lightir.LIRCode;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
@@ -1611,6 +1614,9 @@
OptimizationFeedback feedback,
BytecodeMetadataProvider bytecodeMetadataProvider,
Timing timing) {
+ if (options.testing.roundtripThroughLIR) {
+ code = roundtripThroughLIR(code, feedback, bytecodeMetadataProvider, timing);
+ }
if (options.isGeneratingClassFiles()) {
finalizeToCf(code, feedback, bytecodeMetadataProvider, timing);
} else {
@@ -1619,6 +1625,16 @@
}
}
+ private IRCode roundtripThroughLIR(
+ IRCode code,
+ OptimizationFeedback feedback,
+ BytecodeMetadataProvider bytecodeMetadataProvider,
+ Timing timing) {
+ LIRCode lirCode = IR2LIRConverter.translate(code);
+ IRCode irCode = LIR2IRBuilder.translate(code.context(), lirCode, appView);
+ return irCode;
+ }
+
private void finalizeToCf(
IRCode code,
OptimizationFeedback feedback,
diff --git a/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java b/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java
new file mode 100644
index 0000000..f4a2e5f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/IR2LIRConverter.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2022, 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 com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.Value;
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+
+public class IR2LIRConverter {
+
+ public static LIRCode translate(IRCode irCode) {
+ Reference2IntMap<Value> values = new Reference2IntOpenHashMap<>();
+ int index = 0;
+ for (Instruction instruction : irCode.instructions()) {
+ if (instruction.hasOutValue()) {
+ values.put(instruction.outValue(), index);
+ }
+ index++;
+ }
+ LIRBuilder<Value> builder =
+ new LIRBuilder<Value>(values::getInt).setMetadata(irCode.metadata());
+ BasicBlockIterator blockIt = irCode.listIterator();
+ while (blockIt.hasNext()) {
+ BasicBlock block = blockIt.next();
+ // TODO(b/225838009): Support control flow.
+ assert !block.hasPhis();
+ InstructionIterator it = block.iterator();
+ while (it.hasNext()) {
+ Instruction instruction = it.next();
+ instruction.buildLIR(builder);
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIR2IRBuilder.java b/src/main/java/com/android/tools/r8/lightir/LIR2IRBuilder.java
index 76f1040..3fb39c8 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIR2IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIR2IRBuilder.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.code.ConstString;
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.InvokeVirtual;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
@@ -31,13 +32,7 @@
public class LIR2IRBuilder {
- private final AppView<?> appView;
-
- public LIR2IRBuilder(AppView<?> appView) {
- this.appView = appView;
- }
-
- public IRCode translate(ProgramMethod method, LIRCode lirCode) {
+ public static IRCode translate(ProgramMethod method, LIRCode lirCode, AppView<?> appView) {
Parser parser = new Parser(lirCode, appView);
parser.parseArguments(method);
lirCode.forEach(view -> view.accept(parser));
@@ -170,6 +165,15 @@
}
@Override
+ public void onInvokeDirect(DexMethod target, IntList arguments) {
+ // TODO(b/225838009): Maintain is-interface bit.
+ Value dest = getInvokeInstructionOutputValue(target);
+ List<Value> ssaArgumentValues = getSsaValues(arguments);
+ InvokeDirect instruction = new InvokeDirect(target, dest, ssaArgumentValues);
+ addInstruction(instruction);
+ }
+
+ @Override
public void onInvokeVirtual(DexMethod target, IntList arguments) {
// TODO(b/225838009): Maintain is-interface bit.
Value dest = getInvokeInstructionOutputValue(target);
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java b/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
index 06e642b..7d3505c 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIRBuilder.java
@@ -115,7 +115,7 @@
return writeConstantReferencingInstruction(LIROpcodes.GETSTATIC, field);
}
- public LIRBuilder<V> addInvokeVirtual(DexMethod method, List<V> arguments) {
+ public LIRBuilder<V> addInvokeInstruction(int opcode, DexMethod method, List<V> arguments) {
instructionCount++;
int argumentOprandSize = constantIndexSize(method);
int[] argumentIndexes = new int[arguments.size()];
@@ -125,7 +125,7 @@
argumentIndexes[i++] = argumentIndex;
argumentOprandSize += valueIndexSize(argumentIndex);
}
- writer.writeInstruction(LIROpcodes.INVOKEVIRTUAL, argumentOprandSize);
+ writer.writeInstruction(opcode, argumentOprandSize);
writeConstantIndex(method);
for (int argumentIndex : argumentIndexes) {
writeValueIndex(argumentIndex);
@@ -133,6 +133,14 @@
return this;
}
+ public LIRBuilder<V> addInvokeDirect(DexMethod method, List<V> arguments) {
+ return addInvokeInstruction(LIROpcodes.INVOKEDIRECT, method, arguments);
+ }
+
+ public LIRBuilder<V> addInvokeVirtual(DexMethod method, List<V> arguments) {
+ return addInvokeInstruction(LIROpcodes.INVOKEVIRTUAL, method, arguments);
+ }
+
public LIRBuilder<V> addReturn(V value) {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java b/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
index 2141611..6d906ed 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIROpcodes.java
@@ -181,6 +181,7 @@
int LCONST = 201;
int FCONST = 202;
int DCONST = 203;
+ int INVOKEDIRECT = 204;
static String toString(int opcode) {
switch (opcode) {
diff --git a/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java
index 8ffc285..a0afc52 100644
--- a/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LIRParsedInstructionCallback.java
@@ -36,6 +36,10 @@
public void onInvokeMethodInstruction(DexMethod method, IntList arguments) {}
+ public void onInvokeDirect(DexMethod method, IntList arguments) {
+ onInvokeMethodInstruction(method, arguments);
+ }
+
public void onInvokeVirtual(DexMethod method, IntList arguments) {
onInvokeMethodInstruction(method, arguments);
}
@@ -70,13 +74,17 @@
}
break;
}
+ case LIROpcodes.INVOKEDIRECT:
+ {
+ DexMethod target = getInvokeInstructionTarget(view);
+ IntList arguments = getInvokeInstructionArguments(view);
+ onInvokeDirect(target, arguments);
+ break;
+ }
case LIROpcodes.INVOKEVIRTUAL:
{
- DexMethod target = (DexMethod) getConstantItem(view.getNextConstantOperand());
- IntList arguments = new IntArrayList();
- while (view.hasMoreOperands()) {
- arguments.add(view.getNextValueOperand());
- }
+ DexMethod target = getInvokeInstructionTarget(view);
+ IntList arguments = getInvokeInstructionArguments(view);
onInvokeVirtual(target, arguments);
break;
}
@@ -95,4 +103,16 @@
throw new Unimplemented("No dispatch for opcode " + LIROpcodes.toString(view.getOpcode()));
}
}
+
+ private DexMethod getInvokeInstructionTarget(LIRInstructionView view) {
+ return (DexMethod) getConstantItem(view.getNextConstantOperand());
+ }
+
+ private IntList getInvokeInstructionArguments(LIRInstructionView view) {
+ IntList arguments = new IntArrayList();
+ while (view.hasMoreOperands()) {
+ arguments.add(view.getNextValueOperand());
+ }
+ return arguments;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index d784613..f02405c 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1793,6 +1793,7 @@
public static class TestingOptions {
public boolean neverReuseCfLocalRegisters = false;
+ public boolean roundtripThroughLIR = false;
private boolean hasReadCheckDeterminism = false;
private DeterminismChecker determinismChecker = null;
diff --git a/src/test/java/com/android/tools/r8/lightir/LIRRoundtripTest.java b/src/test/java/com/android/tools/r8/lightir/LIRRoundtripTest.java
index 6bf8f98..82c0d55 100644
--- a/src/test/java/com/android/tools/r8/lightir/LIRRoundtripTest.java
+++ b/src/test/java/com/android/tools/r8/lightir/LIRRoundtripTest.java
@@ -3,45 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.lightir;
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
+import static org.junit.Assume.assumeTrue;
+
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.Marker;
-import com.android.tools.r8.dex.Marker.Tool;
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.ClassKind;
-import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.JarApplicationReader;
-import com.android.tools.r8.graph.JarClassFileReader;
-import com.android.tools.r8.graph.LazyLoadedDexApplication.Builder;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
-import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.BasicBlockIterator;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionIterator;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.optimize.CodeRewriter;
-import com.android.tools.r8.ir.optimize.DeadCodeRemover;
-import com.android.tools.r8.jar.CfApplicationWriter;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.Timing;
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-import java.nio.file.Path;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -57,47 +23,18 @@
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withDefaultCfRuntime().build();
+ return getTestParameters().withDefaultRuntimes().build();
}
private final TestParameters parameters;
- private AppView<?> appView;
- private ProgramMethod method;
public LIRRoundtripTest(TestParameters parameters) {
this.parameters = parameters;
}
- @Before
- public void setUp() throws Exception {
- DexItemFactory factory = new DexItemFactory();
- InternalOptions options = new InternalOptions(factory, new Reporter());
- options.programConsumer = ClassFileConsumer.emptyConsumer();
- Builder builder = DexApplication.builder(options, Timing.empty());
- JarClassFileReader<DexProgramClass> reader =
- new JarClassFileReader<>(
- new JarApplicationReader(options),
- clazz -> {
- builder.addProgramClass(clazz);
- clazz
- .programMethods()
- .forEach(
- m -> {
- if (m.getReference().qualifiedName().endsWith("main")) {
- method = m;
- }
- });
- },
- ClassKind.PROGRAM);
- reader.read(Origin.unknown(), ToolHelper.getClassAsBytes(TestClass.class));
- appView =
- AppView.createForD8(
- AppInfo.createInitialAppInfo(
- builder.build(), GlobalSyntheticsStrategy.forNonSynthesizing()));
- }
-
@Test
public void testReference() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
testForJvm()
.addProgramClasses(TestClass.class)
.run(parameters.getRuntime(), TestClass.class)
@@ -106,66 +43,15 @@
@Test
public void testRoundtrip() throws Exception {
- IRCode irCode1 = translateCf2IR();
- LIRCode lirCode = translateIR2LIR(irCode1);
- IRCode irCode2 = translateLIR2IR(lirCode);
- translateIR2Cf(irCode2);
- Path out = writeToFile();
- testForJvm()
- .addProgramFiles(out)
+ testForD8(parameters.getBackend())
+ .release()
+ .addProgramClasses(TestClass.class)
+ .addOptionsModification(
+ o -> {
+ o.testing.forceIRForCfToCfDesugar = true;
+ o.testing.roundtripThroughLIR = true;
+ })
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("Hello, world!");
}
-
- private Path writeToFile() {
- Path out = temp.getRoot().toPath().resolve("out.jar");
- Marker fakeMarker = new Marker(Tool.D8);
- ArchiveConsumer consumer = new ArchiveConsumer(out);
- new CfApplicationWriter(appView, fakeMarker).write(consumer);
- consumer.finished(appView.reporter());
- return out;
- }
-
- private IRCode translateCf2IR() {
- CfCode cfCode = method.getDefinition().getCode().asCfCode();
- return cfCode.buildIR(method, appView, Origin.unknown());
- }
-
- private LIRCode translateIR2LIR(IRCode irCode) {
- Reference2IntMap<Value> values = new Reference2IntOpenHashMap<>();
- int index = 0;
- for (Instruction instruction : irCode.instructions()) {
- if (instruction.hasOutValue()) {
- values.put(instruction.outValue(), index);
- }
- index++;
- }
- LIRBuilder<Value> builder =
- new LIRBuilder<Value>(values::getInt).setMetadata(irCode.metadata());
- BasicBlockIterator blockIt = irCode.listIterator();
- while (blockIt.hasNext()) {
- BasicBlock block = blockIt.next();
- // TODO(b/225838009): Support control flow.
- assert !block.hasPhis();
- InstructionIterator it = block.iterator();
- while (it.hasNext()) {
- Instruction instruction = it.next();
- instruction.buildLIR(builder);
- }
- }
- return builder.build();
- }
-
- private IRCode translateLIR2IR(LIRCode lirCode) {
- return new LIR2IRBuilder(appView).translate(method, lirCode);
- }
-
- private void translateIR2Cf(IRCode irCode) {
- CodeRewriter codeRewriter = new CodeRewriter(appView);
- DeadCodeRemover deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
- CfCode cfCode =
- new CfBuilder(appView, method, irCode, BytecodeMetadataProvider.empty())
- .build(deadCodeRemover);
- method.setCode(cfCode, appView);
- }
}