Add Dup as an IR code instruction
Change-Id: I66f76267fff30242caae8229d79a25197586a41b
diff --git a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
index 22bbf46..dbfcbf2 100644
--- a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.StackValue;
+import com.android.tools.r8.ir.code.StackValues;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
@@ -116,7 +117,9 @@
Instruction next = it.next();
Value outValue = next.outValue();
if (outValue != null) {
- outValue.setNeedsRegister(!(outValue instanceof StackValue));
+ boolean isStackValue =
+ (outValue instanceof StackValue) || (outValue instanceof StackValues);
+ outValue.setNeedsRegister(!isStackValue);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Dup.java b/src/main/java/com/android/tools/r8/ir/code/Dup.java
new file mode 100644
index 0000000..1f2e418
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/Dup.java
@@ -0,0 +1,70 @@
+// 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.code;
+
+import com.android.tools.r8.cf.LoadStoreHelper;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.conversion.CfBuilder;
+import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
+
+public class Dup extends Instruction {
+
+ public Dup(StackValues dest, StackValue src) {
+ super(dest, src);
+ }
+
+ @Override
+ public void buildDex(DexBuilder builder) {
+ throw new Unreachable("This classfile-specific IR should not be inserted in the Dex backend.");
+ }
+
+ @Override
+ public void buildCf(CfBuilder builder) {
+ if (this.inValues.get(0).type == ValueType.LONG_OR_DOUBLE) {
+ builder.add(new CfStackInstruction(Opcode.Dup2));
+ } else {
+ builder.add(new CfStackInstruction(Opcode.Dup));
+ }
+ }
+
+ @Override
+ public boolean identicalNonValueNonPositionParts(Instruction other) {
+ return false;
+ }
+
+ @Override
+ public int compareNonValueParts(Instruction other) {
+ return 0;
+ }
+
+ @Override
+ public int maxInValueRegister() {
+ return 0;
+ }
+
+ @Override
+ public int maxOutValueRegister() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, DexType invocationContext) {
+ return inliningConstraints.forDup();
+ }
+
+ @Override
+ public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {}
+
+ @Override
+ public boolean hasInvariantOutType() {
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValues.java b/src/main/java/com/android/tools/r8/ir/code/StackValues.java
new file mode 100644
index 0000000..475572e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValues.java
@@ -0,0 +1,50 @@
+// 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.code;
+
+import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import java.util.List;
+
+/**
+ * {@link StackValues} allow us to represent stack operations that produces two or more elements on
+ * the stack while using the same logic for instructions.
+ */
+public class StackValues extends Value {
+
+ private final int height;
+ private final List<StackValue> stackValues;
+
+ public StackValues(TypeLatticeElement typeLattice, int height, List<StackValue> stackValues) {
+ super(Value.UNDEFINED_NUMBER, typeLattice, null);
+ this.height = height;
+ this.stackValues = stackValues;
+ assert height >= 0;
+ assert stackValues.size() >= 2;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public List<StackValue> getStackValues() {
+ return stackValues;
+ }
+
+ @Override
+ public boolean needsRegister() {
+ return false;
+ }
+
+ @Override
+ public void setNeedsRegister(boolean value) {
+ assert !value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ return String.format("s%d+%d", height, stackValues.size() - 1);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 8816326..ea6cac0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -36,6 +36,7 @@
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.StackValue;
+import com.android.tools.r8.ir.code.StackValues;
import com.android.tools.r8.ir.code.Store;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.CodeRewriter;
@@ -363,6 +364,11 @@
if (outValue instanceof StackValue) {
stack.push(outValue);
}
+ if (outValue instanceof StackValues) {
+ for (StackValue outVal : ((StackValues) outValue).getStackValues()) {
+ stack.push(outVal);
+ }
+ }
}
if (instruction.isDebugLocalsChange()) {
if (instruction.asDebugLocalsChange().apply(pendingLocals)) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index de657de..7130516 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -94,6 +94,10 @@
return ConstraintWithTarget.ALWAYS;
}
+ public ConstraintWithTarget forDup() {
+ return ConstraintWithTarget.ALWAYS;
+ }
+
public ConstraintWithTarget forInstanceGet(DexField field, DexType invocationContext) {
DexField lookup = graphLense.lookupField(field);
return forFieldInstruction(
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 9345bb9..d98496e 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -26,6 +26,8 @@
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Or;
import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.StackValue;
+import com.android.tools.r8.ir.code.StackValues;
import com.android.tools.r8.ir.code.Sub;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.Xor;
@@ -2520,7 +2522,11 @@
// For instructions that define values which have no use create a live range covering
// the instruction. This will typically be instructions that can have side effects even
// if their output is not used.
- if (!definition.isUsed()) {
+ if (definition instanceof StackValues) {
+ for (StackValue value : ((StackValues) definition).getStackValues()) {
+ live.remove(value);
+ }
+ } else if (!definition.isUsed()) {
addLiveRange(
definition,
block,