Merge "Revert "Always parse debug info for reachability sensitive methods in R8.""
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3ed662f..6906161 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -237,12 +237,6 @@
     if (options.quiet) {
       System.setOut(new PrintStream(ByteStreams.nullOutputStream()));
     }
-    // TODO(b/65390962): Remove this warning once the CF backend is complete.
-    if (options.isGeneratingClassFiles() && !options.testing.suppressExperimentalCfBackendWarning) {
-      options.reporter.warning(new StringDiagnostic(
-          "R8 support for generating Java classfiles is incomplete and experimental. "
-              + "Even if R8 appears to succeed, the generated output is likely incorrect."));
-    }
     try {
       AndroidApiLevel oLevel = AndroidApiLevel.O;
       if (options.minApiLevel >= oLevel.getLevel()
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 3798c3f..bdbf44f 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "1.4.10-dev";
+  public static final String LABEL = "1.4.11-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index 64395de..16a03e2 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -10,17 +10,21 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.Argument;
+import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
 import com.android.tools.r8.ir.code.NewInstance;
+import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.StackValue;
 import com.android.tools.r8.ir.code.Value;
 import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -221,6 +225,7 @@
   public Map<Value, TypeInfo> computeVerificationTypes() {
     computingVerificationTypes = true;
     types = new HashMap<>();
+    List<ConstNumber> nullsUsedInPhis = new ArrayList<>();
     Set<Value> worklist = new HashSet<>();
     {
       InstructionIterator it = code.instructionIterator();
@@ -261,6 +266,12 @@
           } else if (instruction.outType().isObject()) {
             Value outValue = instruction.outValue();
             if (instruction.hasInvariantOutType()) {
+              if (instruction.isConstNumber()) {
+                assert instruction.asConstNumber().isZero();
+                if (outValue.numberOfAllUsers() == outValue.numberOfPhiUsers()) {
+                  nullsUsedInPhis.add(instruction.asConstNumber());
+                }
+              }
               DexType type = instruction.computeVerificationType(this);
               types.put(outValue, createInitializedType(type));
               addUsers(outValue, worklist);
@@ -284,6 +295,20 @@
       }
     }
     computingVerificationTypes = false;
+    for (ConstNumber instruction : nullsUsedInPhis) {
+      TypeInfo refinedType = null;
+      for (Phi phi : instruction.outValue().uniquePhiUsers()) {
+        if (refinedType == null) {
+          refinedType = types.get(phi);
+        } else if (refinedType.getDexType() != types.get(phi).getDexType()) {
+          refinedType = null;
+          break;
+        }
+      }
+      if (refinedType != null) {
+        types.put(instruction.outValue(), refinedType);
+      }
+    }
     return types;
   }
 
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 f3b58db..a658474 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
@@ -346,10 +346,12 @@
       previousFallthrough = fallthrough;
     } while (block != null);
     // TODO(mkroghj) Move computation of stack-height to CF instructions.
-    CfLabel endLabel = ensureLabel();
-    for (LocalVariableInfo info : openLocalVariables.values()) {
-      info.setEnd(endLabel);
-      localVariablesTable.add(info);
+    if (!openLocalVariables.isEmpty()) {
+      CfLabel endLabel = ensureLabel();
+      for (LocalVariableInfo info : openLocalVariables.values()) {
+        info.setEnd(endLabel);
+        localVariablesTable.add(info);
+      }
     }
     return new CfCode(
         method.method,
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 05fd603..6288eaa 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -36,6 +36,7 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
@@ -93,6 +94,7 @@
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 public class IRConverter {
@@ -1241,20 +1243,116 @@
     }
   }
 
+  /**
+   * For each block, we look to see if the header matches:
+   *
+   * <pre>
+   *   pseudo-instructions*
+   *   v2 <- long-{mul,div} v0 v1
+   *   pseudo-instructions*
+   *   v5 <- long-{add,sub} v3 v4
+   * </pre>
+   *
+   * where v2 ~=~ v3 or v2 ~=~ v4 (with ~=~ being equal or an alias of) and the block is not a
+   * fallthrough target.
+   */
   private void materializeInstructionBeforeLongOperationsWorkaround(IRCode code) {
     if (!options.canHaveDex2OatLinkedListBug()) {
       return;
     }
+    DexItemFactory factory = options.itemFactory;
+    final Supplier<DexMethod> javaLangLangSignum =
+        Suppliers.memoize(
+            () ->
+                factory.createMethod(
+                    factory.createString("Ljava/lang/Long;"),
+                    factory.createString("signum"),
+                    factory.intDescriptor,
+                    new DexString[] {factory.longDescriptor}));
     for (BasicBlock block : code.blocks) {
       InstructionListIterator it = block.listIterator();
-      Instruction firstMaterializing =
-          it.nextUntil(IRConverter::isMaterializingInstructionOnArtArmVersionM);
-      if (needsInstructionBeforeLongOperation(firstMaterializing)) {
-        ensureInstructionBefore(code, firstMaterializing, it);
+      Instruction firstMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
+      if (!isLongMulOrDiv(firstMaterializing)) {
+        continue;
+      }
+      Instruction secondMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
+      if (!isLongAddOrSub(secondMaterializing)) {
+        continue;
+      }
+      if (isFallthoughTarget(block)) {
+        continue;
+      }
+      Value outOfMulOrDiv = firstMaterializing.outValue();
+      for (Value inOfAddOrSub : secondMaterializing.inValues()) {
+        if (isAliasOf(inOfAddOrSub, outOfMulOrDiv)) {
+          it = block.listIterator();
+          it.nextUntil(i -> i == firstMaterializing);
+          Value longValue = firstMaterializing.inValues().get(0);
+          InvokeStatic invokeLongSignum =
+              new InvokeStatic(
+                  javaLangLangSignum.get(), null, Collections.singletonList(longValue));
+          ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
+          return;
+        }
       }
     }
   }
 
+  private static boolean isAliasOf(Value usedValue, Value definingValue) {
+    while (true) {
+      if (usedValue == definingValue) {
+        return true;
+      }
+      Instruction definition = usedValue.definition;
+      if (definition == null || !definition.isMove()) {
+        return false;
+      }
+      usedValue = definition.asMove().src();
+    }
+  }
+
+  private static boolean isNotPseudoInstruction(Instruction instruction) {
+    return !(instruction.isDebugInstruction() || instruction.isMove());
+  }
+
+  private static boolean isLongMulOrDiv(Instruction instruction) {
+    return instruction != null
+        && instruction.outValue() != null
+        && instruction.outValue().getTypeLattice().isLong()
+        && (instruction.isMul() || instruction.isDiv());
+  }
+
+  private static boolean isLongAddOrSub(Instruction instruction) {
+    return instruction != null
+        && instruction.outValue() != null
+        && instruction.outValue().getTypeLattice().isLong()
+        && (instruction.isAdd() || instruction.isSub());
+  }
+
+  private static boolean isFallthoughTarget(BasicBlock block) {
+    for (BasicBlock pred : block.getPredecessors()) {
+      if (pred.exit().fallthroughBlock() == block) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void ensureThrowingInstructionBefore(
+      IRCode code, Instruction addBefore, InstructionListIterator it, Instruction instruction) {
+    Instruction check = it.previous();
+    assert addBefore == check;
+    BasicBlock block = check.getBlock();
+    if (block.hasCatchHandlers()) {
+      // Split the block and copy back catch handlers to the header block.
+      BasicBlock split = it.split(code);
+      block.copyCatchHandlers(code, code.listIterator(code.blocks.size()), split);
+      it = block.listIterator(block.getInstructions().size() - 1);
+    }
+    instruction.setPosition(addBefore.getPosition());
+    it.add(instruction);
+  }
+
   private static void ensureInstructionBefore(
       IRCode code, Instruction addBefore, InstructionListIterator it) {
     // Force materialize a constant-zero before the long operation.
@@ -1273,33 +1371,6 @@
     it.add(fixitUser);
   }
 
-  private static boolean needsInstructionBeforeLongOperation(Instruction instruction) {
-    // The cortex fixup will only trigger on long sub and long add instructions.
-    if (!((instruction.isAdd() || instruction.isSub()) && instruction.outType().isWide())) {
-      return false;
-    }
-    // If the block with the instruction is a fallthrough block, then it can't end up being
-    // preceded by the incorrectly linked prologue/epilogue..
-    BasicBlock block = instruction.getBlock();
-    for (BasicBlock pred : block.getPredecessors()) {
-      if (pred.exit().fallthroughBlock() == block) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  private static boolean isMaterializingInstructionOnArtArmVersionM(Instruction instruction) {
-    return !instruction.isDebugInstruction()
-        && !instruction.isMove()
-        && !isPossiblyNonMaterializingLongOperationOnArtArmVersionM(instruction);
-  }
-
-  private static boolean isPossiblyNonMaterializingLongOperationOnArtArmVersionM(
-      Instruction instruction) {
-    return (instruction.isMul() || instruction.isDiv()) && instruction.outType().isWide();
-  }
-
   private void printC1VisualizerHeader(DexEncodedMethod method) {
     if (printer != null) {
       printer.begin("compilation");
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 41463fa..a3c805f 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -483,7 +483,6 @@
     public boolean forceJumboStringProcessing = false;
     public boolean nondeterministicCycleElimination = false;
     public Set<Inliner.Reason> validInliningReasons = null;
-    public boolean suppressExperimentalCfBackendWarning = false;
   }
 
   private boolean hasMinApi(AndroidApiLevel level) {
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 8312729..190db23 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -67,6 +67,11 @@
   }
 
   @Override
+  public DXTestBuilder addProgramClassFileData(Collection<byte[]> classes) {
+    throw new Unimplemented("No support for adding classfile data directly");
+  }
+
+  @Override
   public DXTestBuilder addProgramFiles(Collection<Path> files) {
     injars.addAll(files);
     return self();
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 4e0bedf..6feb460 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -147,6 +147,12 @@
         "No support for adding paths directly (we need to compute the descriptor)");
   }
 
+  @Override
+  public JvmTestBuilder addProgramClassFileData(Collection<byte[]> files) {
+    throw new Unimplemented(
+        "No support for adding classfile data directly (we need to compute the descriptor)");
+  }
+
   public JvmTestBuilder addClasspath(Path... paths) {
     return addClasspath(Arrays.asList(paths));
   }
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 28ce1e6..fa4c41c 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -184,6 +184,12 @@
   }
 
   @Override
+  public ProguardTestBuilder addProgramClassFileData(Collection<byte[]> classes) {
+    throw new Unimplemented(
+        "No support for adding classfile data directly (we need to compute the descriptor)");
+  }
+
+  @Override
   public ProguardTestBuilder addKeepRules(Collection<String> rules) {
     config.addAll(rules);
     return self();
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 4977d94..7f200c1 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -39,6 +39,12 @@
 
   public abstract T addProgramFiles(Collection<Path> files);
 
+  public abstract T addProgramClassFileData(Collection<byte[]> classes);
+
+  public T addProgramClassFileData(byte[]... classes) {
+    return addProgramClassFileData(Arrays.asList(classes));
+  }
+
   public T addProgramClasses(Class<?>... classes) {
     return addProgramClasses(Arrays.asList(classes));
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 12d1990..bf704ea 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.TestBase.Backend.DEX;
 
 import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.debug.CfDebugTestConfig;
 import com.android.tools.r8.debug.DebugTestConfig;
@@ -98,4 +99,17 @@
     ProcessResult result = ToolHelper.runArtRaw(out.toString(), mainClass);
     return createRunResult(app, result);
   }
+
+  public TestRunResult runDex2Oat() throws IOException {
+    return runDex2Oat(ToolHelper.getDexVm());
+  }
+
+  public TestRunResult runDex2Oat(DexVm vm) throws IOException {
+    assert getBackend() == DEX;
+    Path tmp = state.getNewTempFolder();
+    Path jarFile = tmp.resolve("out.jar");
+    Path oatFile = tmp.resolve("out.oat");
+    app.writeToZip(jarFile, OutputMode.DexIndexed);
+    return new TestRunResult(app, ToolHelper.runDex2OatRaw(jarFile, oatFile, vm));
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 810d292..9452a63 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.debug.DebugTestConfig;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidAppConsumers;
@@ -113,6 +114,14 @@
   }
 
   @Override
+  public T addProgramClassFileData(Collection<byte[]> classes) {
+    for (byte[] clazz : classes) {
+      builder.addClassProgramData(clazz, Origin.unknown());
+    }
+    return self();
+  }
+
+  @Override
   public T addProgramFiles(Collection<Path> files) {
     builder.addProgramFiles(files);
     return self();
@@ -124,4 +133,9 @@
     builder.addLibraryFiles(files);
     return self();
   }
+
+  public T noDesugaring() {
+    builder.setDisableDesugaring(true);
+    return self();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index 46dc4cc..8b6461f 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -26,6 +26,14 @@
     this.result = result;
   }
 
+  public String getStdOut() {
+    return result.stdout;
+  }
+
+  public String getStdErr() {
+    return result.stderr;
+  }
+
   public TestRunResult assertSuccess() {
     assertEquals(errorMessage("Expected run to succeed."), 0, result.exitCode);
     return this;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index d4639a1..70be34e 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1438,39 +1438,42 @@
   }
 
   public static void runDex2Oat(Path file, Path outFile) throws IOException {
-    DexVm vm = getDexVm();
+    runDex2Oat(file, outFile, getDexVm());
+  }
+
+  public static void runDex2Oat(Path file, Path outFile, DexVm vm) throws IOException {
+    ProcessResult result = runDex2OatRaw(file, outFile, vm);
+    if (result.exitCode != 0) {
+      fail("dex2oat failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
+    }
+    if (result.stderr != null && result.stderr.contains("Verification error")) {
+      fail("Verification error: \n" + result.stderr);
+    }
+  }
+
+  public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm vm) throws IOException {
+    Assume.assumeTrue(ToolHelper.isDex2OatSupported());
     if (vm.isOlderThanOrEqual(DexVm.ART_5_1_1_HOST)) {
       // TODO(b/79191363): Support running dex2oat for past android versions.
       // Run default dex2oat for tests on old runtimes.
       vm = DexVm.ART_DEFAULT;
     }
-    runDex2Oat(file, outFile, vm);
-  }
-
-  public static void runDex2Oat(Path file, Path outFile, DexVm vm) throws IOException {
-    Assume.assumeTrue(ToolHelper.isDex2OatSupported());
     // TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
     Assume.assumeTrue(!ToolHelper.isWindows());
     assert Files.exists(file);
     assert ByteStreams.toByteArray(Files.newInputStream(file)).length > 0;
     List<String> command = new ArrayList<>();
     command.add(getDex2OatPath(vm).toString());
-    command.add("--android-root=" + getProductPath(vm));
+    command.add("--android-root=" + getProductPath(vm) + "/system");
     command.add("--runtime-arg");
     command.add("-Xnorelocate");
-    command.add("--boot-image=" + getProductBootImagePath(vm));
     command.add("--dex-file=" + file.toAbsolutePath());
     command.add("--oat-file=" + outFile.toAbsolutePath());
+    // TODO(zerny): Create a proper interface for invoking dex2oat. Hardcoding arm64 here is a hack!
     command.add("--instruction-set=arm64");
     ProcessBuilder builder = new ProcessBuilder(command);
     builder.environment().put("LD_LIBRARY_PATH", getDexVmLibPath(vm).toString());
-    ProcessResult result = runProcess(builder);
-    if (result.exitCode != 0) {
-      fail("dex2oat failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
-    }
-    if (result.stderr.contains("Verification error")) {
-      fail("Verification error: \n" + result.stderr);
-    }
+    return runProcess(builder);
   }
 
   public static ProcessResult runProguardRaw(
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
index 095d7e9..bfd3b76 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -265,7 +265,6 @@
         options -> {
           options.dataResourceConsumer = dataResourceConsumer;
           options.proguardMapConsumer = proguardMapConsumer;
-          options.testing.suppressExperimentalCfBackendWarning = true;
         });
   }
 
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
index c3311a4..410ae0a 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
@@ -325,10 +325,7 @@
                     .setProgramConsumer(emptyConsumer(backend))
                     .addLibraryFiles(runtimeJar(backend))
                     .setProguardMapConsumer(StringConsumer.emptyConsumer())
-                    .build(),
-                options -> {
-                  options.testing.suppressExperimentalCfBackendWarning = true;
-                }));
+                    .build()));
     // All classes are kept, and renamed.
     assertThat(inspector.clazz("Simple"), isRenamed());
     assertThat(inspector.clazz("Base"), isRenamed());
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
index 6877953..1c4e31b 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
@@ -190,10 +190,7 @@
                     .setProgramConsumer(emptyConsumer(backend))
                     .addLibraryFiles(runtimeJar(backend))
                     .setProguardMapConsumer(StringConsumer.emptyConsumer())
-                    .build(),
-                options -> {
-                  options.testing.suppressExperimentalCfBackendWarning = true;
-                }));
+                    .build()));
     // All classes are kept, and renamed.
     ClassSubject clazz = inspector.clazz("Fields");
     assertThat(clazz, isRenamed());
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
index 706bdd4..3c74a5b 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
@@ -212,10 +212,7 @@
                     .setProgramConsumer(emptyConsumer(backend))
                     .addLibraryFiles(runtimeJar(backend))
                     .setProguardMapConsumer(StringConsumer.emptyConsumer())
-                    .build(),
-                options -> {
-                  options.testing.suppressExperimentalCfBackendWarning = true;
-                }));
+                    .build()));
     // All classes are kept, and renamed.
     ClassSubject clazz = inspector.clazz("Methods");
     assertThat(clazz, isRenamed());
diff --git a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
index 9ebb6cc..74e6471 100644
--- a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
+++ b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
@@ -123,7 +123,6 @@
         o -> {
           o.enableInlining = false;
           o.forceProguardCompatibility = forceProguardCompatibility;
-          o.testing.suppressExperimentalCfBackendWarning = true;
         });
   }
 
diff --git a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
new file mode 100644
index 0000000..12bd452
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
@@ -0,0 +1,54 @@
+// 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.regress.b118075510;
+
+import com.android.tools.r8.AsmTestBase;
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class Regress118075510Runner extends AsmTestBase {
+
+  public static final Class<?> CLASS = Regress118075510Test.class;
+  public static final String EXPECTED = StringUtils.lines("0", "0");
+
+  @Test
+  public void test()
+      throws CompilationFailedException, IOException, ExecutionException, NoSuchMethodException {
+    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+
+    D8TestCompileResult d8Result =
+        testForD8().addProgramClasses(CLASS).setMinApi(AndroidApiLevel.M).release().compile();
+
+    CodeInspector inspector = d8Result.inspector();
+    checkMethodContainsLongSignum(inspector, "fooNoTryCatch");
+    checkMethodContainsLongSignum(inspector, "fooWithTryCatch");
+    // Check the program runs on ART/Dalvik
+    d8Result.run(CLASS).assertSuccessWithOutput(EXPECTED);
+    // Check the program can be dex2oat compiled to arm64. This will diverge without the fixup.
+    d8Result.runDex2Oat().assertSuccess();
+  }
+
+  private void checkMethodContainsLongSignum(CodeInspector inspector, String methodName)
+      throws NoSuchMethodException {
+    MethodSubject method = inspector.method(CLASS.getMethod(methodName, long.class, long.class));
+    Assert.assertTrue(
+        "Did not contain Long.signum workaround in "
+            + methodName
+            + ":\n"
+            + method.getMethod().codeToString(),
+        method
+            .streamInstructions()
+            .anyMatch(
+                i ->
+                    i.isInvoke() && i.getMethod().qualifiedName().equals("java.lang.Long.signum")));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java
new file mode 100644
index 0000000..cc4dece
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java
@@ -0,0 +1,38 @@
+// 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.regress.b118075510;
+
+public class Regress118075510Test {
+
+  public static void fooNoTryCatch(long a, long b) {
+    // Call a method on the runner class that will not be on the classpath at runtime.
+    // This causes the optimizing 6.0.1 compiler to delegate to the old quick compiler.
+    if (a == b) Regress118075510Runner.class.getMethods();
+    // The else branch of the conditional here ends up with an invalid previous pointer at its
+    // block header (ie, previous of mul-long (2addr) points to epilogue-end which is self-linked.
+    System.out.println(a < b ? 0 : a * b + b);
+  }
+
+  public static void fooWithTryCatch(long a, long b) {
+    // Call a method on the runner class that will not be on the classpath at runtime.
+    // This causes the optimizing 6.0.1 compiler to delegate to the old quick compiler.
+    if (a == b) Regress118075510Runner.class.getMethods();
+    // The else branch of the conditional here ends up with an invalid previous pointer at its
+    // block header (ie, previous of mul-long (2addr) points to epilogue-end which is self-linked.
+    try {
+      if (a < b) {
+        System.out.println((long) 0);
+      } else {
+        System.out.println(a * b + b);
+      }
+    } catch (RuntimeException e) {
+      e.printStackTrace();
+    }
+  }
+
+  public static void main(String[] args) {
+    fooNoTryCatch(args.length, 456);
+    fooWithTryCatch(456, args.length);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java b/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java
index cbc6e1b..3ab3467 100644
--- a/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java
+++ b/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java
@@ -5,29 +5,20 @@
 
 import com.android.tools.r8.AsmTestBase;
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8;
-import com.android.tools.r8.D8Command;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.io.IOException;
-import java.nio.file.Path;
 import org.junit.Test;
 
 public class Regress77842465 extends AsmTestBase {
 
   @Test
   public void test() throws CompilationFailedException, IOException {
-
-    Path dexOut = temp.getRoot().toPath().resolve("out.jar");
-    Path oatOut = temp.getRoot().toPath().resolve("out.odex");
-
-    D8.run(D8Command.builder()
-        .addClassProgramData(Regress77842465Dump.dump(), Origin.unknown())
-        .setOutput(dexOut, OutputMode.DexIndexed)
-        .setDisableDesugaring(true)
-        .build());
-
-    ToolHelper.runDex2Oat(dexOut, oatOut);
+    testForD8()
+        .addProgramClassFileData(Regress77842465Dump.dump())
+        .noDesugaring()
+        .setMinApi(AndroidApiLevel.M)
+        .compile()
+        .runDex2Oat()
+        .assertSuccess();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 1e21552..98bb8d0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -5,8 +5,10 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.google.common.collect.Streams;
 import java.util.Iterator;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 public abstract class MethodSubject extends MemberSubject {
 
@@ -40,4 +42,8 @@
   public abstract LineNumberTable getLineNumberTable();
 
   public abstract boolean hasLocalVariableTable();
+
+  public Stream<InstructionSubject> streamInstructions() {
+    return Streams.stream(iterateInstructions());
+  }
 }