Only consider relevant instruction desugarings for given instruction opcode

This CL creates a dense array where the element at index i is an array containing all relevant CF instruction desugarings for instructions with opcode i.

Bug: b/378464445
Change-Id: I54b36eb428affff0a077078e29251ec6128e3cbe
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index e16115e..62256b5 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -588,7 +588,7 @@
 
   @Override
   public void print(CfFieldInstruction insn) {
-    switch (insn.getOpcode()) {
+    switch (insn.getAsmOpcode()) {
       case Opcodes.GETFIELD:
         printNewInstruction("CfInstanceFieldRead", dexField(insn.getField()));
         break;
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 6341c03..fac5344 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -505,7 +505,7 @@
 
   public void print(CfFieldInstruction insn) {
     indent();
-    switch (insn.getOpcode()) {
+    switch (insn.getAsmOpcode()) {
       case Opcodes.GETFIELD:
         builder.append("getfield ");
         break;
@@ -519,7 +519,7 @@
         builder.append("putstatic ");
         break;
       default:
-        throw new Unreachable("Unexpected field-instruction opcode " + insn.getOpcode());
+        throw new Unreachable("Unexpected field-instruction opcode " + insn.getAsmOpcode());
     }
     appendField(insn.getField());
     builder.append(' ');
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index e9c6f6b..766926a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -46,11 +46,6 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getAsmOpcode();
-  }
-
-  @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
@@ -116,6 +111,7 @@
     }
   }
 
+  @Override
   public int getAsmOpcode() {
     return getAsmOpcode(opcode, type);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index fd9586f..c8a886d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -45,7 +45,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.ARRAYLENGTH;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index a0662ad..c7f5181 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -31,11 +31,7 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getLoadType();
-  }
-
-  private int getLoadType() {
+  public int getAsmOpcode() {
     switch (getType()) {
       case OBJECT:
         return Opcodes.AALOAD;
@@ -69,7 +65,7 @@
       NamingLens namingLens,
       LensCodeRewriterUtils rewriter,
       MethodVisitor visitor) {
-    visitor.visitInsn(getLoadType());
+    visitor.visitInsn(getAsmOpcode());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index f7cb0c5..461c6fc 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -29,21 +29,7 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getStoreType();
-  }
-
-  @Override
-  public boolean isArrayStore() {
-    return true;
-  }
-
-  @Override
-  public CfArrayStore asArrayStore() {
-    return this;
-  }
-
-  private int getStoreType() {
+  public int getAsmOpcode() {
     switch (getType()) {
       case OBJECT:
         return Opcodes.AASTORE;
@@ -67,6 +53,16 @@
   }
 
   @Override
+  public boolean isArrayStore() {
+    return true;
+  }
+
+  @Override
+  public CfArrayStore asArrayStore() {
+    return this;
+  }
+
+  @Override
   public void write(
       AppView<?> appView,
       ProgramMethod context,
@@ -77,7 +73,7 @@
       NamingLens namingLens,
       LensCodeRewriterUtils rewriter,
       MethodVisitor visitor) {
-    visitor.visitInsn(getStoreType());
+    visitor.visitInsn(getAsmOpcode());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 9e23bd0..915e0e9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -66,7 +66,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.CHECKCAST;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index a18c05a..490b860 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -43,11 +43,6 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getAsmOpcode();
-  }
-
-  @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
@@ -83,6 +78,7 @@
     }
   }
 
+  @Override
   public int getAsmOpcode() {
     switch (type) {
       case LONG:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 0d0838e..1d89b7d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -59,6 +59,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_CLASS_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index ed3a275..963df0f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -84,6 +84,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_DYNAMIC_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 25cb808..2379d5a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -39,6 +39,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_METHOD_HANDLE_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 2f0fb30..17a2b28 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -39,6 +39,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_METHOD_TYPE_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 09d9f3c..1e999ca 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -45,7 +45,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.ACONST_NULL;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index 9246c77..2ea3658 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -41,6 +41,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_NUMBER_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 064ee4c..9f49657 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -31,6 +31,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_STRING_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 6280303..f4509ed 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -38,6 +38,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_STRING_DEX_ITEM_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 9d91db7..2ec5bab 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -27,7 +27,7 @@
   private final DexField declaringField;
 
   private static void specify(StructuralSpecification<CfFieldInstruction, ?> spec) {
-    spec.withInt(CfFieldInstruction::getOpcode)
+    spec.withInt(CfFieldInstruction::getAsmOpcode)
         .withItem(CfFieldInstruction::getField)
         .withItem(CfFieldInstruction::getDeclaringField);
   }
@@ -66,13 +66,6 @@
     return declaringField;
   }
 
-  public abstract int getOpcode();
-
-  @Override
-  public int getCompareToId() {
-    return getOpcode();
-  }
-
   @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
@@ -112,7 +105,7 @@
     String owner = namingLens.lookupInternalName(rewrittenField.holder);
     String name = namingLens.lookupName(rewrittenDeclaringField).toString();
     String desc = namingLens.lookupDescriptor(rewrittenField.type).toString();
-    visitor.visitFieldInsn(getOpcode(), owner, name, desc);
+    visitor.visitFieldInsn(getAsmOpcode(), owner, name, desc);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 0dedc1d..54347a9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -60,6 +60,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.FRAME_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index cabbeeb..2921cd8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -33,7 +33,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.GOTO;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index 0ac4689..3f52416 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -34,7 +34,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return getOpcode();
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 24fc552..2573b67 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -34,7 +34,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return getOpcode();
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 533657e..e5ac422 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -41,7 +41,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.IINC;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index 4fa09ff..c747f57 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -45,6 +45,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.CONST_CLASS_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index 1a7c2af..69a5090 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -29,7 +29,7 @@
   }
 
   @Override
-  public int getOpcode() {
+  public int getAsmOpcode() {
     return Opcodes.GETFIELD;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index 1f8e193..908a999 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -37,7 +37,7 @@
   }
 
   @Override
-  public int getOpcode() {
+  public int getAsmOpcode() {
     return Opcodes.PUTFIELD;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index da879bd..aad5efb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -55,7 +55,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.INSTANCEOF;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 9ee017e..f3f4fe6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -47,6 +47,17 @@
   public abstract void print(CfPrinter printer);
 
   /**
+   * Returns the corresponding ASM opcode, or -1 if the given CF instruction is a synthetic kind
+   * that does not have an ASM opcode.
+   */
+  public abstract int getAsmOpcode();
+
+  /** Returns false for synthetic CF instructions that do not have an ASM opcode. */
+  public boolean hasAsmOpcode() {
+    return true;
+  }
+
+  /**
    * Base compare id for each instruction.
    *
    * <p>The id is required to be unique for each instruction class and define a order on
@@ -55,7 +66,10 @@
    * instruction is not represented externally, some non-overlapping ID defined in {@code
    * CfCompareHelper}.
    */
-  public abstract int getCompareToId();
+  public int getCompareToId() {
+    assert hasAsmOpcode();
+    return getAsmOpcode();
+  }
 
   /**
    * Compare two instructions with the same compare id.
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index fc2e576..292983c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -57,7 +57,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return getOpcode();
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index 8e39bb9..a1fed4c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -57,7 +57,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.INVOKEDYNAMIC;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index d0efa3c..73f9ca1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.HashingVisitor;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
 
 public class CfJsrRet extends CfInstruction {
 
@@ -36,8 +37,8 @@
   }
 
   @Override
-  public int getCompareToId() {
-    throw error();
+  public int getAsmOpcode() {
+    return Opcodes.RET;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 008b905..6e79310 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -34,6 +34,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.LABEL_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 0af1153..30c14b8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -38,7 +38,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return getLoadType();
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 97c4dce..0cef4f5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -48,11 +48,6 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getAsmOpcode();
-  }
-
-  @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
@@ -102,6 +97,7 @@
     }
   }
 
+  @Override
   public int getAsmOpcode() {
     return getAsmOpcode(opcode, type);
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index 6821e61..5f08b41 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -37,11 +37,6 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getAsmOpcode();
-  }
-
-  @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
@@ -71,7 +66,8 @@
     return 1;
   }
 
-  private int getAsmOpcode() {
+  @Override
+  public int getAsmOpcode() {
     return type == MonitorType.ENTER ? Opcodes.MONITORENTER : Opcodes.MONITOREXIT;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 449bdcb..c8081cf 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -67,7 +67,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.MULTIANEWARRAY;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index 9b047f8..c93606b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -38,11 +38,6 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getAsmOpcode();
-  }
-
-  @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
@@ -77,6 +72,7 @@
     printer.print(this);
   }
 
+  @Override
   public int getAsmOpcode() {
     switch (type) {
       case BYTE:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index f574223..6105e74 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -83,7 +83,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.NEW;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index f131164..e7e9d7d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -59,7 +59,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return type.isPrimitiveArrayType() ? Opcodes.NEWARRAY : Opcodes.ANEWARRAY;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 11cab35..3acf922 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -59,7 +59,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.NEW;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index 7706a69..bd28baa 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -25,7 +25,7 @@
 public class CfNop extends CfInstruction {
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.NOP;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index cadead1..fb02b64 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -40,11 +40,6 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getAsmOpcode();
-  }
-
-  @Override
   public int internalAcceptCompareTo(
       CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
     return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
@@ -87,6 +82,7 @@
     printer.print(this);
   }
 
+  @Override
   public int getAsmOpcode() {
     switch (from) {
       case INT:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfOpcodeUtils.java b/src/main/java/com/android/tools/r8/cf/code/CfOpcodeUtils.java
new file mode 100644
index 0000000..0d06079
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfOpcodeUtils.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2025, 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.cf.code;
+
+import com.android.tools.r8.graph.CfCompareHelper;
+import java.util.function.IntConsumer;
+import org.objectweb.asm.Opcodes;
+
+public class CfOpcodeUtils {
+
+  public static void acceptCfFieldInstructionOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.GETSTATIC);
+    consumer.accept(Opcodes.PUTSTATIC);
+    consumer.accept(Opcodes.GETFIELD);
+    consumer.accept(Opcodes.PUTFIELD);
+  }
+
+  public static void acceptCfInvokeOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKEVIRTUAL);
+    consumer.accept(Opcodes.INVOKESPECIAL);
+    consumer.accept(Opcodes.INVOKESTATIC);
+    consumer.accept(Opcodes.INVOKEINTERFACE);
+  }
+
+  public static void acceptCfTypeInstructionOpcodes(
+      IntConsumer consumer, IntConsumer compareToIdConsumer) {
+    consumer.accept(Opcodes.CHECKCAST);
+    consumer.accept(Opcodes.INSTANCEOF);
+    consumer.accept(Opcodes.MULTIANEWARRAY);
+    consumer.accept(Opcodes.NEW);
+    consumer.accept(Opcodes.NEWARRAY);
+    consumer.accept(Opcodes.ANEWARRAY);
+    compareToIdConsumer.accept(CfCompareHelper.CONST_DYNAMIC_COMPARE_ID);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index b52cb87..efad8ac 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -33,6 +33,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.POSITION_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index ce358df..9a14069 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -78,6 +78,16 @@
   }
 
   @Override
+  public int getAsmOpcode() {
+    return -1;
+  }
+
+  @Override
+  public boolean hasAsmOpcode() {
+    return false;
+  }
+
+  @Override
   public int getCompareToId() {
     return CfCompareHelper.RECORD_FIELD_VALUES_COMPARE_ID;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index a99482d..1ed076a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -40,22 +40,7 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getOpcode();
-  }
-
-  @Override
-  public int internalAcceptCompareTo(
-      CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
-    return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
-  }
-
-  @Override
-  public void internalAcceptHashing(HashingVisitor visitor) {
-    // Nothing to add.
-  }
-
-  private int getOpcode() {
+  public int getAsmOpcode() {
     switch (type) {
       case INT:
         return Opcodes.IRETURN;
@@ -73,6 +58,17 @@
   }
 
   @Override
+  public int internalAcceptCompareTo(
+      CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
+    return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
+  }
+
+  @Override
+  public void internalAcceptHashing(HashingVisitor visitor) {
+    // Nothing to add.
+  }
+
+  @Override
   public int bytecodeSizeUpperBound() {
     return 1;
   }
@@ -96,7 +92,7 @@
       NamingLens namingLens,
       LensCodeRewriterUtils rewriter,
       MethodVisitor visitor) {
-    visitor.visitInsn(getOpcode());
+    visitor.visitInsn(getAsmOpcode());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 5b16578..d3d8f90 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -35,7 +35,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.RETURN;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index c5c8f6e..a30bb1b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -83,7 +83,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return opcode.opcode;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
index 12467da..78ae24a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -33,7 +33,7 @@
   }
 
   @Override
-  public int getOpcode() {
+  public int getAsmOpcode() {
     return Opcodes.GETSTATIC;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index 01d9bed..df00570 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -33,7 +33,7 @@
   }
 
   @Override
-  public int getOpcode() {
+  public int getAsmOpcode() {
     return Opcodes.PUTSTATIC;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index 9e5449a..85d377d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -36,22 +36,7 @@
   }
 
   @Override
-  public int getCompareToId() {
-    return getStoreType();
-  }
-
-  @Override
-  public int internalAcceptCompareTo(
-      CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
-    return visitor.visitInt(var, other.asStore().var);
-  }
-
-  @Override
-  public void internalAcceptHashing(HashingVisitor visitor) {
-    visitor.visitInt(var);
-  }
-
-  private int getStoreType() {
+  public int getAsmOpcode() {
     switch (type) {
       case OBJECT:
         return Opcodes.ASTORE;
@@ -69,6 +54,17 @@
   }
 
   @Override
+  public int internalAcceptCompareTo(
+      CfInstruction other, CompareToVisitor visitor, CfCompareHelper helper) {
+    return visitor.visitInt(var, other.asStore().var);
+  }
+
+  @Override
+  public void internalAcceptHashing(HashingVisitor visitor) {
+    visitor.visitInt(var);
+  }
+
+  @Override
   public CfStore asStore() {
     return this;
   }
@@ -89,7 +85,7 @@
       NamingLens namingLens,
       LensCodeRewriterUtils rewriter,
       MethodVisitor visitor) {
-    visitor.visitVarInsn(getStoreType(), var);
+    visitor.visitVarInsn(getAsmOpcode(), var);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 31e7ff3..585de87 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -59,7 +59,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return kind == Kind.LOOKUP ? Opcodes.LOOKUPSWITCH : Opcodes.TABLESWITCH;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index 4b81a79..ebf5df1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -36,7 +36,7 @@
   }
 
   @Override
-  public int getCompareToId() {
+  public int getAsmOpcode() {
     return Opcodes.ATHROW;
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java b/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java
index 063123a..5897ea6 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCompareHelper.java
@@ -17,6 +17,8 @@
 
 public class CfCompareHelper {
 
+  public static final int MAX_COMPARE_ID;
+
   // Integer constants to ensure that there is a well order for all CF instructions including
   // virtual instructions represented in our internal encoding.
   public static final int CONST_CLASS_COMPARE_ID;
@@ -46,6 +48,7 @@
     LABEL_COMPARE_ID = ++lastId;
     POSITION_COMPARE_ID = ++lastId;
     RECORD_FIELD_VALUES_COMPARE_ID = ++lastId;
+    MAX_COMPARE_ID = lastId;
   }
 
   // Helper to signal that the concrete instruction is uniquely determined by its ID/opcode.
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index d38b615..7362ef4 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -191,7 +191,7 @@
             fieldInstruction = isR8InstructionSequence(code, i + 1);
           }
           if (fieldInstruction != null) {
-            return fieldInstruction.getOpcode() == Opcodes.PUTSTATIC
+            return fieldInstruction.getAsmOpcode() == Opcodes.PUTSTATIC
                 && fieldInstruction.getField().name == dexItemFactory.assertionsDisabled;
           }
         }
@@ -220,7 +220,7 @@
               && invoke.getMethod() == dexItemFactory.classMethods.desiredAssertionStatus) {
             if (instructions.get(i).isFieldInstruction()) {
               CfFieldInstruction fieldInstruction = instructions.get(i).asFieldInstruction();
-              if (fieldInstruction.getOpcode() == Opcodes.PUTSTATIC
+              if (fieldInstruction.getAsmOpcode() == Opcodes.PUTSTATIC
                   && fieldInstruction.getField().name == kotlinAssertionsEnabled) {
                 return true;
               }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index b52dbf0..6eb626d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.cf.code.CfLabel;
 import com.android.tools.r8.cf.code.CfLoad;
 import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.cf.code.CfReturn;
 import com.android.tools.r8.cf.code.CfReturnVoid;
@@ -85,6 +86,7 @@
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.function.Consumer;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 public final class BackportedMethodRewriter implements CfInstructionDesugaring {
@@ -103,6 +105,12 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+    consumer.accept(Opcodes.GETSTATIC);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     // Only invokes and static field gets are backported.
     if (!instruction.isInvoke() && !instruction.isStaticFieldGet()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java
index 67c2bf3..a3c475d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BufferCovariantReturnTypeRewriter.java
@@ -7,12 +7,14 @@
 import com.android.tools.r8.cf.code.CfCheckCast;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.google.common.collect.ImmutableList;
+import java.util.function.IntConsumer;
 
 /**
  * BufferCovariantReturnTypeRewriter rewrites the return type of invoked methods matching
@@ -27,8 +29,13 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
-    if (!isInvokeCandidate(instruction)) {
+    if (!instruction.isInvoke()) {
       return DesugarDescription.nothing();
     }
     CfInvoke cfInvoke = instruction.asInvoke();
@@ -83,10 +90,4 @@
     }
     return null;
   }
-
-  private boolean isInvokeCandidate(CfInstruction instruction) {
-    return instruction.isInvoke()
-        || instruction.isInvokeStatic()
-        || instruction.isInvokeInterface();
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
index f5db966..c2c9731 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
@@ -7,10 +7,17 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.ProgramMethod;
+import java.util.function.IntConsumer;
 
 /** Interface for desugaring a single class-file instruction. */
 public interface CfInstructionDesugaring {
 
+  CfInstructionDesugaring[] EMPTY_ARRAY = new CfInstructionDesugaring[0];
+
+  void acceptRelevantAsmOpcodes(IntConsumer consumer);
+
+  default void acceptRelevantCompareToIds(IntConsumer consumer) {}
+
   // TODO(193004879): Merge the scan and prepare methods.
   default void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
     // Default scan is to do nothing.
@@ -43,4 +50,8 @@
   default DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     throw new Unreachable();
   }
+
+  default String getName() {
+    return getClass().getTypeName();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java
index 151eb36..799729e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InvokeToPrivateRewriter.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.google.common.collect.ImmutableList;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 /**
@@ -25,6 +26,12 @@
 public class InvokeToPrivateRewriter implements CfInstructionDesugaring {
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKEINTERFACE);
+    consumer.accept(Opcodes.INVOKEVIRTUAL);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (!instruction.isInvokeVirtual() && !instruction.isInvokeInterface()) {
       return DesugarDescription.nothing();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index eda2b3d..20fbfa2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.Position;
@@ -44,6 +45,9 @@
 import com.android.tools.r8.utils.ThrowingConsumer;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -64,6 +68,8 @@
   private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
   private final DesugaredLibraryDisableDesugarer disableDesugarer;
 
+  private final CfInstructionDesugaring[][] asmOpcodeOrCompareToIdToDesugaringsMap;
+
   NonEmptyCfInstructionDesugaringCollection(
       AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) {
     this.appView = appView;
@@ -83,6 +89,14 @@
       this.interfaceMethodRewriter = null;
       this.desugaredLibraryAPIConverter = null;
       this.disableDesugarer = null;
+      desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
+      if (appView.options().isGeneratingDex()) {
+        if (appView.options().canHaveArtArrayCloneFromInterfaceMethodBug()) {
+          desugarings.add(new OutlineArrayCloneFromInterfaceMethodDesugaring(appView));
+        }
+        yieldingDesugarings.add(new UnrepresentableInDexInstructionRemover(appView));
+      }
+      this.asmOpcodeOrCompareToIdToDesugaringsMap = createAsmOpcodeOrCompareToIdToDesugaringsMap();
       return;
     }
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
@@ -165,33 +179,55 @@
       desugarings.add(varHandleDesugaring);
     }
     yieldingDesugarings.add(new UnrepresentableInDexInstructionRemover(appView));
+    asmOpcodeOrCompareToIdToDesugaringsMap = createAsmOpcodeOrCompareToIdToDesugaringsMap();
+  }
+
+  private CfInstructionDesugaring[][] createAsmOpcodeOrCompareToIdToDesugaringsMap() {
+    Int2ReferenceMap<List<CfInstructionDesugaring>> map = new Int2ReferenceOpenHashMap<>();
+    for (CfInstructionDesugaring desugaring : Iterables.concat(desugarings, yieldingDesugarings)) {
+      desugaring.acceptRelevantAsmOpcodes(
+          opcode -> registerRelevantAsmOpcodeOrCompareToId(map, desugaring, opcode));
+      desugaring.acceptRelevantCompareToIds(
+          id -> registerRelevantAsmOpcodeOrCompareToId(map, desugaring, id));
+    }
+    // Convert map to a dense array.
+    int maxAsmOpcodeOrCompareToId = CfCompareHelper.MAX_COMPARE_ID;
+    CfInstructionDesugaring[][] arrayMap =
+        new CfInstructionDesugaring[maxAsmOpcodeOrCompareToId + 1][];
+    for (Entry<List<CfInstructionDesugaring>> entry : map.int2ReferenceEntrySet()) {
+      arrayMap[entry.getIntKey()] = entry.getValue().toArray(CfInstructionDesugaring.EMPTY_ARRAY);
+    }
+    for (int i = 0; i < arrayMap.length; i++) {
+      if (arrayMap[i] == null) {
+        arrayMap[i] = CfInstructionDesugaring.EMPTY_ARRAY;
+      }
+    }
+    return arrayMap;
+  }
+
+  private void registerRelevantAsmOpcodeOrCompareToId(
+      Int2ReferenceMap<List<CfInstructionDesugaring>> asmOpcodeOrCompareToIdToDesugaringsMap,
+      CfInstructionDesugaring desugaring,
+      int opcodeOrCompareToId) {
+    if (asmOpcodeOrCompareToIdToDesugaringsMap.containsKey(opcodeOrCompareToId)) {
+      asmOpcodeOrCompareToIdToDesugaringsMap.get(opcodeOrCompareToId).add(desugaring);
+    } else {
+      asmOpcodeOrCompareToIdToDesugaringsMap.put(
+          opcodeOrCompareToId, ListUtils.newArrayList(desugaring));
+    }
   }
 
   static NonEmptyCfInstructionDesugaringCollection createForCfToCfNonDesugar(AppView<?> appView) {
     assert appView.options().desugarState.isOff();
     assert appView.options().isGeneratingClassFiles();
-    NonEmptyCfInstructionDesugaringCollection desugaringCollection =
-        new NonEmptyCfInstructionDesugaringCollection(appView, noAndroidApiLevelCompute());
-    // TODO(b/145775365): special constructor for cf-to-cf compilations with desugaring disabled.
-    //  This should be removed once we can represent invoke-special instructions in the IR.
-    desugaringCollection.desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
-    return desugaringCollection;
+    return new NonEmptyCfInstructionDesugaringCollection(appView, noAndroidApiLevelCompute());
   }
 
   static NonEmptyCfInstructionDesugaringCollection createForCfToDexNonDesugar(
       AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) {
     assert appView.options().desugarState.isOff();
     assert appView.options().isGeneratingDex();
-    NonEmptyCfInstructionDesugaringCollection desugaringCollection =
-        new NonEmptyCfInstructionDesugaringCollection(appView, apiLevelCompute);
-    desugaringCollection.desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
-    if (appView.options().canHaveArtArrayCloneFromInterfaceMethodBug()) {
-      desugaringCollection.desugarings.add(
-          new OutlineArrayCloneFromInterfaceMethodDesugaring(appView));
-    }
-    desugaringCollection.yieldingDesugarings.add(
-        new UnrepresentableInDexInstructionRemover(appView));
-    return desugaringCollection;
+    return new NonEmptyCfInstructionDesugaringCollection(appView, apiLevelCompute);
   }
 
   private void ensureCfCode(ProgramMethod method) {
@@ -430,16 +466,29 @@
       throw new Unreachable("Unexpected attempt to determine if non-CF code needs desugaring");
     }
 
-    return Iterables.any(
-        code.asCfCode().getInstructions(), instruction -> needsDesugaring(instruction, method));
+    CfCode cfCode = code.asCfCode();
+    for (CfInstruction instruction : cfCode.getInstructions()) {
+      int asmOpcodeOrCompareToId =
+          instruction.hasAsmOpcode() ? instruction.getAsmOpcode() : instruction.getCompareToId();
+      CfInstructionDesugaring[] desugaringsForInstruction =
+          asmOpcodeOrCompareToIdToDesugaringsMap[asmOpcodeOrCompareToId];
+      for (CfInstructionDesugaring desugaring : desugaringsForInstruction) {
+        if (desugaring.compute(instruction, method).needsDesugaring()) {
+          return true;
+        }
+      }
+      assert verifyNoDesugaringNeeded(instruction, method);
+    }
+    return false;
   }
 
-  private boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
-    return Iterables.any(
-            desugarings, desugaring -> desugaring.compute(instruction, context).needsDesugaring())
-        || Iterables.any(
-            yieldingDesugarings,
-            desugaring -> desugaring.compute(instruction, context).needsDesugaring());
+  private boolean verifyNoDesugaringNeeded(CfInstruction instruction, ProgramMethod context) {
+    for (CfInstructionDesugaring desugaring : Iterables.concat(desugarings, yieldingDesugarings)) {
+      assert !desugaring.compute(instruction, context).needsDesugaring()
+          : "Expected instruction to be desugared, but matched by: "
+              + desugaring.getClass().getName();
+    }
+    return true;
   }
 
   private boolean verifyNoOtherDesugaringNeeded(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/OutlineArrayCloneFromInterfaceMethodDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/OutlineArrayCloneFromInterfaceMethodDesugaring.java
index ce5fde6..b1b491e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/OutlineArrayCloneFromInterfaceMethodDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/OutlineArrayCloneFromInterfaceMethodDesugaring.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableList;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 /** This outlines calls to array clone from within interface methods. See b/342802978 */
@@ -27,11 +28,15 @@
   private final AppView<?> appView;
 
   public OutlineArrayCloneFromInterfaceMethodDesugaring(AppView<?> appView) {
-
     this.appView = appView;
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKEVIRTUAL);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     // This workaround only applies within default or static interface method.
     if (!context.getHolder().isInterface()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java b/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java
index f713b03..5253c0c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/UnrepresentableInDexInstructionRemover.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
@@ -25,6 +26,7 @@
 import com.android.tools.r8.errors.UnsupportedInvokeCustomDiagnostic;
 import com.android.tools.r8.errors.UnsupportedInvokePolymorphicMethodHandleDiagnostic;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
@@ -42,6 +44,7 @@
 import com.google.common.collect.ImmutableList.Builder;
 import java.util.List;
 import java.util.Set;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 /**
@@ -394,6 +397,19 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+    consumer.accept(Opcodes.INVOKEDYNAMIC);
+  }
+
+  @Override
+  public void acceptRelevantCompareToIds(IntConsumer consumer) {
+    consumer.accept(CfCompareHelper.CONST_DYNAMIC_COMPARE_ID);
+    consumer.accept(CfCompareHelper.CONST_METHOD_HANDLE_COMPARE_ID);
+    consumer.accept(CfCompareHelper.CONST_METHOD_TYPE_COMPARE_ID);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     for (InstructionMatcher matcher : matchers) {
       DesugarDescription result = matcher.compute(instruction);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index 259234e..e7fc2d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -16,8 +16,10 @@
 import com.android.tools.r8.cf.code.CfInstanceOf;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.contexts.CompilationContext.UniqueContext;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -47,6 +49,8 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Function;
+import java.util.function.IntConsumer;
+import org.objectweb.asm.Opcodes;
 
 /**
  * This desugaring will outline calls to library methods that are introduced after the min-api
@@ -66,6 +70,24 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfFieldInstructionOpcodes(consumer);
+    CfOpcodeUtils.acceptCfInvokeOpcodes(
+        opcode -> {
+          if (opcode != Opcodes.INVOKESPECIAL) {
+            consumer.accept(opcode);
+          }
+        });
+    consumer.accept(Opcodes.CHECKCAST);
+    consumer.accept(Opcodes.INSTANCEOF);
+  }
+
+  @Override
+  public void acceptRelevantCompareToIds(IntConsumer consumer) {
+    consumer.accept(CfCompareHelper.CONST_CLASS_COMPARE_ID);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     ComputedApiLevel computedApiLevel =
         getComputedApiLevelInstructionOnHolderWithMinApi(instruction, context);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java
index 4577688..be6c7a3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicInstructionDesugaring.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.errors.ConstantDynamicDesugarDiagnostic;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCompareHelper;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -25,6 +26,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
 
 public class ConstantDynamicInstructionDesugaring implements CfInstructionDesugaring {
 
@@ -49,6 +51,16 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    // Intentionally empty.
+  }
+
+  @Override
+  public void acceptRelevantCompareToIds(IntConsumer consumer) {
+    consumer.accept(CfCompareHelper.CONST_DYNAMIC_COMPARE_ID);
+  }
+
+  @Override
   @SuppressWarnings("ReferenceEquality")
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (!instruction.isConstDynamic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
index 9a5056b..ecaf710 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryAPIConverter.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -29,6 +30,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 @SuppressWarnings("UnusedVariable")
@@ -86,6 +88,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (!instruction.isInvoke()) {
       return DesugarDescription.nothing();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
index f3d1a6d..f4dfe72 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/disabledesugarer/DesugaredLibraryDisableDesugarer.java
@@ -4,9 +4,12 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer;
 
+import static com.android.tools.r8.utils.IntConsumerUtils.emptyIntConsumer;
+
 import com.android.tools.r8.cf.code.CfFieldInstruction;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.cf.code.CfTypeInstruction;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
@@ -16,6 +19,8 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.DesugarDescription;
 import com.google.common.collect.ImmutableList;
+import java.util.function.IntConsumer;
+import org.objectweb.asm.Opcodes;
 
 /**
  * Disables the rewriting of types in specific classes declared in the desugared library
@@ -38,6 +43,25 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfFieldInstructionOpcodes(consumer);
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+    CfOpcodeUtils.acceptCfTypeInstructionOpcodes(
+        opcode -> {
+          // Skip primitive array allocations.
+          if (opcode != Opcodes.NEWARRAY) {
+            consumer.accept(opcode);
+          }
+        },
+        emptyIntConsumer());
+  }
+
+  @Override
+  public void acceptRelevantCompareToIds(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfTypeInstructionOpcodes(emptyIntConsumer(), consumer);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     CfInstruction replacement = rewriteInstruction(instruction, context);
     if (replacement == null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java
index 17c3a51..2b7ac09 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryLibRewriter.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
@@ -24,6 +25,7 @@
 import java.util.Collections;
 import java.util.Map;
 import java.util.function.BiFunction;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 /**
@@ -89,6 +91,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (appView
         .getSyntheticItems()
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index c3a58c1..45ae3da 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.cf.code.CfFieldInstruction;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -25,6 +26,7 @@
 import java.util.Map;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 public class DesugaredLibraryRetargeter implements CfInstructionDesugaring {
@@ -58,6 +60,12 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+    consumer.accept(Opcodes.GETSTATIC);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (instruction.isStaticFieldGet()) {
       return computeStaticFieldGetDescription(instruction, context);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
index 1204cd0..e567034 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.code.CfConstNumber;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -29,6 +30,7 @@
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.function.IntConsumer;
 
 public class AlwaysThrowingInstructionDesugaring implements CfInstructionDesugaring {
 
@@ -39,6 +41,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (instruction.isInvoke()) {
       CfInvoke invoke = instruction.asInvoke();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
index b290ad9..81b9b77 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.desugar.DesugarDescription;
 import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
 import com.google.common.collect.ImmutableList;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 /** This class defines the desugaring of a single invoke-special instruction. */
@@ -31,6 +32,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKESPECIAL);
+  }
+
+  @Override
   @SuppressWarnings("ReferenceEquality")
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (!instruction.isInvokeSpecial()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index dd600b3..57cc90e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.AppInfo;
@@ -54,6 +55,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
 import java.util.function.Predicate;
 
 //
@@ -215,6 +217,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public boolean hasPreciseNeedsDesugaring() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
index 5ba70be..dd386d5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
@@ -37,6 +37,7 @@
 import java.util.Deque;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 public class LambdaInstructionDesugaring implements CfInstructionDesugaring {
@@ -55,6 +56,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKEDYNAMIC);
+  }
+
+  @Override
   public void scan(ProgramMethod method, CfInstructionDesugaringEventConsumer eventConsumer) {
     CfCode code = method.getDefinition().getCode().asCfCode();
     for (CfInstruction instruction : code.getInstructions()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
index 0550d47..6c0ee9b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.Code;
@@ -43,6 +44,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 // NestBasedAccessDesugaring contains common code between the two subclasses
@@ -136,6 +138,12 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfFieldInstructionOpcodes(consumer);
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public void prepare(
       ProgramMethod method,
       CfInstructionDesugaringEventConsumer eventConsumer,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java
index 773189b..29d66a6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfInvokeDynamic;
 import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
 import com.android.tools.r8.cf.code.CfStore;
@@ -57,6 +58,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.function.BiFunction;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 public class RecordInstructionDesugaring implements CfInstructionDesugaring {
@@ -108,6 +110,12 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+    consumer.accept(Opcodes.INVOKEDYNAMIC);
+  }
+
+  @Override
   public void prepare(
       ProgramMethod method,
       CfInstructionDesugaringEventConsumer eventConsumer,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
index 5d5672a..05c14e9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
@@ -41,6 +41,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 /** String concatenation desugaring rewriter. */
@@ -68,6 +69,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKEDYNAMIC);
+  }
+
+  @Override
   @SuppressWarnings("ReferenceEquality")
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (instruction.isInvokeDynamic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
index bb9ac0e..c81a156 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrInstructionDesugaring.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppView;
@@ -23,6 +24,7 @@
 import com.google.common.collect.ImmutableList;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 public class TwrInstructionDesugaring implements CfInstructionDesugaring {
@@ -44,10 +46,12 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
-    if (!instruction.isInvoke()) {
-      return DesugarDescription.nothing();
-    }
     if (isTwrCloseResourceInvoke(instruction)) {
       return rewriteTwrCloseResourceInvoke();
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaring.java
index 4961b64..119ad06 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/typeswitch/TypeSwitchDesugaring.java
@@ -47,6 +47,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
 public class TypeSwitchDesugaring implements CfInstructionDesugaring {
@@ -71,6 +72,13 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    consumer.accept(Opcodes.INVOKEDYNAMIC);
+    consumer.accept(Opcodes.INVOKESPECIAL);
+    consumer.accept(Opcodes.NEW);
+  }
+
+  @Override
   public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
     if (!instruction.isInvokeDynamic()) {
       // We need to replace the new MatchException with RuntimeException.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
index 273ab78..766dbf4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfLoad;
 import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfOpcodeUtils;
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
 import com.android.tools.r8.cf.code.CfStore;
@@ -43,6 +44,7 @@
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.IntConsumer;
 import java.util.function.Predicate;
 import org.objectweb.asm.Opcodes;
 
@@ -68,6 +70,11 @@
   }
 
   @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+  }
+
+  @Override
   @SuppressWarnings("ReferenceEquality")
   public void scan(
       ProgramMethod programMethod, CfInstructionDesugaringEventConsumer eventConsumer) {
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 77f5fbc..b856ae7 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4322,29 +4322,36 @@
         && !method.getDefinition().isInitializer();
   }
 
-  private boolean addToPendingDesugaring(ProgramMethod method) {
-    if (options.isInterfaceMethodDesugaringEnabled()) {
-      if (mustMoveToInterfaceCompanionMethod(method)) {
-        // TODO(b/199043500): Once "live moved methods" are tracked this can avoid the code check.
-        if (!InvalidCode.isInvalidCode(method.getDefinition().getCode())) {
-          pendingMethodMove.add(method);
+  private boolean addToPendingDesugaring(ProgramMethod method, Timing timing) {
+    try (Timing t0 = timing.begin("Analyze needs desugaring")) {
+      try (Timing t1 = timing.begin("Analyze interface method desugaring")) {
+        if (options.isInterfaceMethodDesugaringEnabled()) {
+          if (mustMoveToInterfaceCompanionMethod(method)) {
+            // TODO(b/199043500): Once "live moved methods" are tracked this can avoid the code
+            // check.
+            if (!InvalidCode.isInvalidCode(method.getDefinition().getCode())) {
+              pendingMethodMove.add(method);
+            }
+            return true;
+          }
+          ProgramMethod nonMovedMethod = pendingMethodMoveInverse.get(method);
+          if (nonMovedMethod != null) {
+            // Any non-moved code must be a proper pending item.
+            assert InvalidCode.isInvalidCode(method.getDefinition().getCode());
+            assert !InvalidCode.isInvalidCode(nonMovedMethod.getDefinition().getCode());
+            pendingMethodMove.add(nonMovedMethod);
+            return true;
         }
-        return true;
       }
-      ProgramMethod nonMovedMethod = pendingMethodMoveInverse.get(method);
-      if (nonMovedMethod != null) {
-        // Any non-moved code must be a proper pending item.
-        assert InvalidCode.isInvalidCode(method.getDefinition().getCode());
-        assert !InvalidCode.isInvalidCode(nonMovedMethod.getDefinition().getCode());
-        pendingMethodMove.add(nonMovedMethod);
-        return true;
       }
+      try (Timing t2 = timing.begin("Analyze instruction desugaring")) {
+        if (desugaring.needsDesugaring(method)) {
+          pendingCodeDesugaring.add(method);
+          return true;
+        }
+      }
+      return false;
     }
-    if (desugaring.needsDesugaring(method)) {
-      pendingCodeDesugaring.add(method);
-      return true;
-    }
-    return false;
   }
 
   private void desugar(SyntheticAdditions additions) throws ExecutionException {
@@ -4924,7 +4931,7 @@
 
     while (worklist.hasNext()) {
       EnqueuerAction action = worklist.poll();
-      action.run(this);
+      action.run(this, Timing.empty());
     }
   }
 
@@ -5117,18 +5124,23 @@
   }
 
   // Package protected due to entry point from worklist.
-  void markMethodAsLive(ProgramMethod method, ProgramDefinition context) {
+  void markMethodAsLive(ProgramMethod method, ProgramDefinition context, Timing timing) {
     assert liveMethods.contains(method);
 
     DexEncodedMethod definition = method.getDefinition();
     assert !definition.getOptimizationInfo().forceInline();
 
+    timing.begin("Clinit");
     if (definition.isStatic()) {
       markDirectAndIndirectClassInitializersAsLive(method.getHolder());
     }
+    timing.end();
 
-    traceNonDesugaredCode(method);
+    timing.begin("Trace code (non-desugared)");
+    traceNonDesugaredCode(method, timing);
+    timing.end();
 
+    timing.begin("Super");
     ProgramMethodSet superCallTargets = superInvokeDependencies.get(method.getDefinition());
     if (superCallTargets != null) {
       for (ProgramMethod superCallTarget : superCallTargets) {
@@ -5136,8 +5148,11 @@
         markVirtualMethodAsLive(superCallTarget, KeepReason.invokedViaSuperFrom(method));
       }
     }
+    timing.end();
 
+    timing.begin("Notify");
     analyses.processNewlyLiveMethod(method, context, this, worklist);
+    timing.end();
   }
 
   private void markMethodAsTargeted(ProgramMethod method, KeepReason reason) {
@@ -5177,21 +5192,27 @@
     }
   }
 
-  private void traceNonDesugaredCode(ProgramMethod method) {
+  private void traceNonDesugaredCode(ProgramMethod method, Timing timing) {
     if (getMode().isInitialTreeShaking()) {
-      if (addToPendingDesugaring(method)) {
+      if (addToPendingDesugaring(method, timing)) {
         return;
       }
     }
 
-    traceCode(method);
+    traceCode(method, timing);
   }
 
-  void traceCode(ProgramMethod method) {
+  void traceCode(ProgramMethod method, Timing timing) {
+    timing.begin("Trace code");
     DefaultEnqueuerUseRegistry registry =
         useRegistryFactory.create(appView, method, this, appView.apiLevelCompute());
+    timing.begin("Register code references");
     method.registerCodeReferences(registry);
+    timing.end();
+    timing.begin("Notify processNewlyLiveCode");
     analyses.processNewlyLiveCode(method, registry, worklist);
+    timing.end();
+    timing.end();
   }
 
   private void markReferencedTypesAsLive(ProgramMethod method) {
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
index 2b3bdf9..2303c84 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerWorklist.java
@@ -180,8 +180,15 @@
     }
 
     @Override
+    public void run(Enqueuer enqueuer, Timing timing) {
+      timing.begin(getName());
+      enqueuer.markMethodAsLive(method, context, timing);
+      timing.end();
+    }
+
+    @Override
     public void run(Enqueuer enqueuer) {
-      enqueuer.markMethodAsLive(method, context);
+      throw new Unreachable();
     }
   }
 
@@ -241,8 +248,15 @@
     }
 
     @Override
+    public void run(Enqueuer enqueuer, Timing timing) {
+      timing.begin(getName());
+      enqueuer.traceCode(method, timing);
+      timing.end();
+    }
+
+    @Override
     public void run(Enqueuer enqueuer) {
-      enqueuer.traceCode(method);
+      throw new Unreachable();
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/utils/Timing.java b/src/main/java/com/android/tools/r8/utils/Timing.java
index 696f1c7..7e4a8e1 100644
--- a/src/main/java/com/android/tools/r8/utils/Timing.java
+++ b/src/main/java/com/android/tools/r8/utils/Timing.java
@@ -23,6 +23,9 @@
 
 public class Timing implements AutoCloseable {
 
+  private static final int MINIMUM_REPORT_MS =
+      SystemPropertyUtils.parseSystemPropertyOrDefault(
+          "com.android.tools.r8.printtimes.minvalue_ms", 10);
   private static final int MINIMUM_REPORT_PERCENTAGE =
       SystemPropertyUtils.parseSystemPropertyOrDefault(
           "com.android.tools.r8.printtimes.minvalue", 2);
@@ -227,6 +230,9 @@
 
     public void report(int depth, Node top) {
       assert duration() >= 0;
+      if (durationInMs(duration()) < MINIMUM_REPORT_MS) {
+        return;
+      }
       if (percentage(duration(), top.duration()) < MINIMUM_REPORT_PERCENTAGE) {
         return;
       }
@@ -245,7 +251,8 @@
       }
       if (childTime < duration()) {
         long unaccounted = duration() - childTime;
-        if (percentage(unaccounted, top.duration()) >= MINIMUM_REPORT_PERCENTAGE) {
+        if (durationInMs(unaccounted) >= MINIMUM_REPORT_MS
+            && percentage(unaccounted, top.duration()) >= MINIMUM_REPORT_PERCENTAGE) {
           printPrefix(depth + 1);
           System.out.println(
               "("
@@ -409,6 +416,10 @@
     return new TimingMerger(title, numberOfThreads, this);
   }
 
+  private static long durationInMs(long value) {
+    return value / 1000000;
+  }
+
   private static long percentage(long part, long total) {
     return part * 100 / total;
   }
@@ -418,7 +429,7 @@
   }
 
   private static String prettyTime(long value) {
-    return (value / 1000000) + "ms";
+    return durationInMs(value) + "ms";
   }
 
   private static String prettySize(long value) {
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index 4c0102e..7989945 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -85,25 +85,25 @@
   @Override
   public boolean isInstancePut() {
     return instruction instanceof CfFieldInstruction
-        && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTFIELD;
+        && ((CfFieldInstruction) instruction).getAsmOpcode() == Opcodes.PUTFIELD;
   }
 
   @Override
   public boolean isStaticPut() {
     return instruction instanceof CfFieldInstruction
-        && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.PUTSTATIC;
+        && ((CfFieldInstruction) instruction).getAsmOpcode() == Opcodes.PUTSTATIC;
   }
 
   @Override
   public boolean isInstanceGet() {
     return instruction instanceof CfFieldInstruction
-        && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETFIELD;
+        && ((CfFieldInstruction) instruction).getAsmOpcode() == Opcodes.GETFIELD;
   }
 
   @Override
   public boolean isStaticGet() {
     return instruction instanceof CfFieldInstruction
-        && ((CfFieldInstruction) instruction).getOpcode() == Opcodes.GETSTATIC;
+        && ((CfFieldInstruction) instruction).getAsmOpcode() == Opcodes.GETSTATIC;
   }
 
   @Override