Merge "Add Swap IR instrunction"
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
index 1f2e418..0932e62 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Dup.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Dup.java
@@ -36,12 +36,12 @@
@Override
public boolean identicalNonValueNonPositionParts(Instruction other) {
- return false;
+ throw new Unreachable();
}
@Override
public int compareNonValueParts(Instruction other) {
- return 0;
+ throw new Unreachable();
}
@Override
@@ -61,10 +61,22 @@
}
@Override
- public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {}
+ public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
+ // Intentionally empty. Dup is a stack operation.
+ }
@Override
public boolean hasInvariantOutType() {
return false;
}
+
+ @Override
+ public boolean isDup() {
+ return true;
+ }
+
+ @Override
+ public Dup asDup() {
+ return this;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 44a7a8e..90e8a6a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -621,6 +621,14 @@
return null;
}
+ public boolean isDup() {
+ return false;
+ }
+
+ public Dup asDup() {
+ return null;
+ }
+
public boolean isJumpInstruction() {
return false;
}
@@ -1052,6 +1060,14 @@
return null;
}
+ public boolean isSwap() {
+ return false;
+ }
+
+ public Swap asSwap() {
+ return null;
+ }
+
public boolean isLoad() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Swap.java b/src/main/java/com/android/tools/r8/ir/code/Swap.java
new file mode 100644
index 0000000..494fbab
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/Swap.java
@@ -0,0 +1,91 @@
+// 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;
+import java.util.Arrays;
+
+public class Swap extends Instruction {
+
+ public Swap(StackValues dest, StackValues src) {
+ super(dest, src.getStackValues());
+ assert src.getStackValues().size() == 2;
+ assert !(this.inValues.get(0).type.isWide() ^ this.inValues.get(1).type.isWide());
+ }
+
+ public Swap(StackValues dest, StackValue src1, StackValue src2) {
+ super(dest, Arrays.asList(src1, src2));
+ assert !(this.inValues.get(0).type.isWide() ^ !this.inValues.get(1).type.isWide());
+ }
+
+ @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.isWide()) {
+ builder.add(new CfStackInstruction(Opcode.Dup2X2));
+ builder.add(new CfStackInstruction(Opcode.Pop2));
+ } else {
+ builder.add(new CfStackInstruction(Opcode.Swap));
+ }
+ }
+
+ @Override
+ public boolean identicalNonValueNonPositionParts(Instruction other) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int compareNonValueParts(Instruction other) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int maxInValueRegister() {
+ return 0;
+ }
+
+ @Override
+ public int maxOutValueRegister() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(
+ InliningConstraints inliningConstraints, DexType invocationContext) {
+ return inliningConstraints.forSwap();
+ }
+
+ @Override
+ public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
+ // Intentionally empty. Swap is a stack operation.
+ }
+
+ @Override
+ public boolean hasInvariantOutType() {
+ return false;
+ }
+
+ @Override
+ public boolean isSwap() {
+ return true;
+ }
+
+ @Override
+ public Swap asSwap() {
+ return this;
+ }
+}
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 7130516..cc85e39 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
@@ -237,6 +237,10 @@
return ConstraintWithTarget.ALWAYS;
}
+ public ConstraintWithTarget forSwap() {
+ return ConstraintWithTarget.ALWAYS;
+ }
+
public ConstraintWithTarget forThrow() {
return ConstraintWithTarget.ALWAYS;
}