Add LirToLirDesugaredLibraryRetargeter

This adds support for running the DesugaredLibraryRetargeter cf-to-cf and lir-to-lir.

This only implements lir-to-lir retargeting for fields. It remains to implement lir-to-lir retargeting for methods.

Bug: b/391572031
Change-Id: I16357caecd01c0f45c9abf404f5d602752682bb4
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 8370d23..1ff5fe1 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
@@ -67,7 +67,7 @@
 import com.android.tools.r8.ir.desugar.backports.TypedArrayMethodRewrites;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.LibraryDesugaringOptions;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.AutoCloseableRetargeterHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterHelper;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.synthesis.SyntheticNaming;
@@ -220,7 +220,7 @@
     BackportedMethodRewriter.RewritableMethods rewritableMethods =
         new BackportedMethodRewriter.RewritableMethods(appView);
     rewritableMethods.visit(methods);
-    new DesugaredLibraryRetargeter(appView).visit(methods);
+    new DesugaredLibraryRetargeterHelper(appView).visit(methods);
     new AutoCloseableRetargeterHelper(options.getMinApiLevel(), options.dexItemFactory())
         .visit(methods);
     rewritableMethods.visitFields(fields);
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 b66ceee..06c814d 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
@@ -23,6 +23,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.disabledesugarer.DesugaredLibraryDisableDesugarer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.AutoCloseableRetargeter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.CfToCfDesugaredLibraryLibRewriter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.CfToCfDesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryLibRewriter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.icce.AlwaysThrowingInstructionDesugaring;
@@ -65,7 +66,7 @@
   private final List<CfInstructionDesugaring> yieldingDesugarings = new ArrayList<>();
 
   private final NestBasedAccessDesugaring nestBasedAccessDesugaring;
-  private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
+  private final CfToCfDesugaredLibraryRetargeter desugaredLibraryRetargeter;
   private final InterfaceMethodRewriter interfaceMethodRewriter;
   private final CfToCfDesugaredLibraryApiConverter desugaredLibraryAPIConverter;
   private final DesugaredLibraryDisableDesugarer disableDesugarer;
@@ -112,14 +113,7 @@
     if (desugaredLibRewriter != null) {
       desugarings.add(desugaredLibRewriter);
     }
-    desugaredLibraryRetargeter =
-        appView
-                .options()
-                .getLibraryDesugaringOptions()
-                .getMachineDesugaredLibrarySpecification()
-                .hasRetargeting()
-            ? new DesugaredLibraryRetargeter(appView)
-            : null;
+    desugaredLibraryRetargeter = DesugaredLibraryRetargeter.createCfToCf(appView);
     if (desugaredLibraryRetargeter != null) {
       desugarings.add(desugaredLibraryRetargeter);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
index d59d1cb..b3904bf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.LirToLirDesugaredLibraryApiConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryLibRewriter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryLibRewriter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.optimize.DeadCodeRemover;
@@ -97,6 +98,8 @@
             appView, profileCollectionAdditions);
     LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter =
         DesugaredLibraryLibRewriter.createLirToLir(appView, eventConsumer);
+    LirToLirDesugaredLibraryRetargeter desugaredLibraryRetargeter =
+        LirToLirDesugaredLibraryRetargeter.createLirToLir(appView);
     // TODO(b/391572031): Implement lir-to-lir interface method rewriting.
     InterfaceMethodRewriter interfaceMethodRewriter = null;
     LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter =
@@ -117,6 +120,7 @@
                           appView,
                           desugaredLibraryAPIConverter,
                           desugaredLibraryLibRewriter,
+                          desugaredLibraryRetargeter,
                           interfaceMethodRewriter,
                           eventConsumer,
                           method,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
index 867641b..1c3e14a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaringGraphLens.java
@@ -34,6 +34,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryConversionCfProvider;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.LirToLirDesugaredLibraryApiConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryLibRewriter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.LirToLirDesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.optimize.CustomLensCodeRewriter;
 import java.util.ArrayList;
@@ -45,6 +46,7 @@
 
   private final LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter;
   private final LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter;
+  private final LirToLirDesugaredLibraryRetargeter desugaredLibraryRetargeter;
 
   @SuppressWarnings("UnusedVariable")
   private final InterfaceMethodRewriter interfaceMethodRewriter;
@@ -62,6 +64,7 @@
       AppView<? extends AppInfoWithClassHierarchy> appView,
       LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter,
       LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter,
+      LirToLirDesugaredLibraryRetargeter desugaredLibraryRetargeter,
       InterfaceMethodRewriter interfaceMethodRewriter,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod method,
@@ -69,6 +72,7 @@
     super(appView);
     this.desugaredLibraryAPIConverter = desugaredLibraryAPIConverter;
     this.desugaredLibraryLibRewriter = desugaredLibraryLibRewriter;
+    this.desugaredLibraryRetargeter = desugaredLibraryRetargeter;
     this.interfaceMethodRewriter = interfaceMethodRewriter;
     this.eventConsumer = eventConsumer;
     this.method = method;
@@ -87,7 +91,9 @@
 
   @Override
   protected FieldLookupResult internalDescribeLookupField(FieldLookupResult previous) {
-    // TODO(b/391572031): Implement field access desugaring.
+    if (desugaredLibraryRetargeter != null) {
+      return desugaredLibraryRetargeter.lookupField(previous, method, this);
+    }
     return previous;
   }
 
@@ -105,6 +111,14 @@
       }
     }
 
+    if (desugaredLibraryRetargeter != null) {
+      MethodLookupResult result =
+          desugaredLibraryRetargeter.lookupMethod(previous, method, methodProcessingContext, this);
+      if (result != previous) {
+        return result;
+      }
+    }
+
     if (desugaredLibraryAPIConverter != null) {
       return desugaredLibraryAPIConverter.lookupMethod(
           previous, method, methodProcessingContext, this);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java
new file mode 100644
index 0000000..aed15b8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java
@@ -0,0 +1,160 @@
+// 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.ir.desugar.desugaredlibrary.retargeter;
+
+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;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.MethodResolutionResult;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.DesugarDescription;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
+import java.util.Collections;
+import java.util.function.BiFunction;
+import java.util.function.IntConsumer;
+import org.objectweb.asm.Opcodes;
+
+public class CfToCfDesugaredLibraryRetargeter extends DesugaredLibraryRetargeter
+    implements CfInstructionDesugaring {
+
+  CfToCfDesugaredLibraryRetargeter(AppView<?> appView) {
+    super(appView);
+  }
+
+  @Override
+  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
+    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
+    consumer.accept(Opcodes.GETSTATIC);
+  }
+
+  @Override
+  public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
+    if (instruction.isInvoke()) {
+      return computeInvokeDescription(instruction, context);
+    } else if (instruction.isStaticFieldGet()) {
+      return computeStaticFieldGetDescription(instruction, context);
+    } else {
+      return DesugarDescription.nothing();
+    }
+  }
+
+  private DesugarDescription computeInvokeDescription(
+      CfInstruction instruction, ProgramMethod context) {
+    if (appView.dexItemFactory().multiDexTypes.contains(context.getContextType())) {
+      return DesugarDescription.nothing();
+    }
+    CfInvoke cfInvoke = instruction.asInvoke();
+    DexMethod invokedMethod = cfInvoke.getMethod();
+    AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+    MethodResolutionResult resolutionResult =
+        appInfo.resolveMethodLegacy(invokedMethod, cfInvoke.isInterface());
+    if (!resolutionResult.isSingleResolution()) {
+      return DesugarDescription.nothing();
+    }
+    assert resolutionResult.getSingleTarget() != null;
+    DexMethod singleTarget = resolutionResult.getSingleTarget().getReference();
+    if (cfInvoke.isInvokeStatic()) {
+      DexMethod retarget = staticRetarget.get(singleTarget);
+      return ensureInvokeRetargetingResult(retarget);
+    }
+    DesugarDescription retarget = computeNonStaticRetarget(singleTarget, false);
+    if (!retarget.needsDesugaring()) {
+      return DesugarDescription.nothing();
+    }
+    if (cfInvoke.isInvokeSuper(context.getHolderType())) {
+      DexClassAndMethod superTarget =
+          appInfo.lookupSuperTarget(invokedMethod, context, appView, appInfo);
+      if (superTarget != null) {
+        assert !superTarget.getDefinition().isStatic();
+        return computeNonStaticRetarget(superTarget.getReference(), true);
+      }
+    }
+    return retarget;
+  }
+
+  private DesugarDescription computeNonStaticRetarget(DexMethod singleTarget, boolean superInvoke) {
+    EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(singleTarget);
+    if (descriptor != null) {
+      return createWithTarget(
+          (eventConsumer, methodProcessingContext) ->
+              superInvoke
+                  ? syntheticHelper.ensureForwardingMethod(descriptor, eventConsumer)
+                  : syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
+    }
+    if (covariantRetarget.containsKey(singleTarget)) {
+      return createWithTarget(
+          (eventConsumer, methodProcessingContext) ->
+              syntheticHelper.ensureCovariantRetargetMethod(
+                  singleTarget,
+                  covariantRetarget.get(singleTarget),
+                  eventConsumer,
+                  methodProcessingContext));
+    }
+    return ensureInvokeRetargetingResult(nonEmulatedVirtualRetarget.get(singleTarget));
+  }
+
+  private DesugarDescription computeStaticFieldGetDescription(
+      CfInstruction instruction, ProgramMethod context) {
+    CfFieldInstruction fieldInstruction = instruction.asFieldInstruction();
+    DexField retargetField = getRetargetField(fieldInstruction.getField(), context);
+    if (retargetField == null) {
+      return DesugarDescription.nothing();
+    }
+    return DesugarDescription.builder()
+        .setDesugarRewrite(
+            (position,
+                freshLocalProvider,
+                localStackAllocator,
+                desugaringInfo,
+                eventConsumer,
+                context1,
+                methodProcessingContext,
+                desugarings,
+                dexItemFactory) ->
+                Collections.singletonList(fieldInstruction.createWithField(retargetField)))
+        .build();
+  }
+
+  DesugarDescription ensureInvokeRetargetingResult(DexMethod retarget) {
+    if (retarget == null) {
+      return DesugarDescription.nothing();
+    }
+    return createWithTarget(
+        (eventConsumer, methodProcessingContext) ->
+            syntheticHelper.ensureRetargetMethod(retarget, eventConsumer));
+  }
+
+  private DesugarDescription createWithTarget(
+      BiFunction<CfInstructionDesugaringEventConsumer, MethodProcessingContext, DexMethod>
+          methodProvider) {
+    return DesugarDescription.builder()
+        .setDesugarRewrite(
+            (position,
+                freshLocalProvider,
+                localStackAllocator,
+                desugaringInfo,
+                eventConsumer,
+                context,
+                methodProcessingContext,
+                desugarings,
+                dexItemFactory) -> {
+              DexMethod newInvokeTarget =
+                  methodProvider.apply(eventConsumer, methodProcessingContext);
+              assert appView.definitionFor(newInvokeTarget.getHolderType()) != null;
+              assert !appView.definitionFor(newInvokeTarget.getHolderType()).isInterface();
+              return Collections.singletonList(
+                  new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, false));
+            })
+        .build();
+  }
+}
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 ac1766d..d340582 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
@@ -1,44 +1,28 @@
 // Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-
 package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
-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;
-import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.DesugarDescription;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.LibraryDesugaringOptions;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import java.util.Collections;
 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 {
+public abstract class DesugaredLibraryRetargeter {
 
-  private final AppView<?> appView;
-  private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
+  final AppView<?> appView;
+  final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
 
   private final Map<DexField, DexField> staticFieldRetarget;
-  private final Map<DexMethod, DexMethod> covariantRetarget;
-  private final Map<DexMethod, DexMethod> staticRetarget;
-  private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
-  private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
+  final Map<DexMethod, DexMethod> covariantRetarget;
+  final Map<DexMethod, DexMethod> staticRetarget;
+  final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
+  final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
 
   public DesugaredLibraryRetargeter(AppView<?> appView) {
     this.appView = appView;
@@ -52,116 +36,29 @@
     emulatedVirtualRetarget = specification.getEmulatedVirtualRetarget();
   }
 
-  // Used by the ListOfBackportedMethods utility.
-  public void visit(Consumer<DexMethod> consumer) {
-    staticRetarget.keySet().forEach(consumer);
-    nonEmulatedVirtualRetarget.keySet().forEach(consumer);
-    emulatedVirtualRetarget.keySet().forEach(consumer);
+  public static CfToCfDesugaredLibraryRetargeter createCfToCf(AppView<?> appView) {
+    LibraryDesugaringOptions libraryDesugaringOptions =
+        appView.options().getLibraryDesugaringOptions();
+    if (libraryDesugaringOptions.isCfToCfLibraryDesugaringEnabled()
+        && libraryDesugaringOptions.getMachineDesugaredLibrarySpecification().hasRetargeting()) {
+      return new CfToCfDesugaredLibraryRetargeter(appView);
+    }
+    return null;
   }
 
-  @Override
-  public void acceptRelevantAsmOpcodes(IntConsumer consumer) {
-    CfOpcodeUtils.acceptCfInvokeOpcodes(consumer);
-    consumer.accept(Opcodes.GETSTATIC);
+  public static LirToLirDesugaredLibraryRetargeter createLirToLir(AppView<?> appView) {
+    LibraryDesugaringOptions libraryDesugaringOptions =
+        appView.options().getLibraryDesugaringOptions();
+    if (libraryDesugaringOptions.isLirToLirLibraryDesugaringEnabled()
+        && libraryDesugaringOptions.getMachineDesugaredLibrarySpecification().hasRetargeting()) {
+      return new LirToLirDesugaredLibraryRetargeter(appView);
+    }
+    return null;
   }
 
-  @Override
-  public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
-    if (instruction.isStaticFieldGet()) {
-      return computeStaticFieldGetDescription(instruction, context);
-    }
-    if (instruction.isInvoke()) {
-      return computeInvokeDescription(instruction, context);
-    }
-    return DesugarDescription.nothing();
-  }
-
-  private DesugarDescription computeInvokeDescription(
-      CfInstruction instruction, ProgramMethod context) {
-    if (appView.dexItemFactory().multiDexTypes.contains(context.getContextType())) {
-      return DesugarDescription.nothing();
-    }
-    CfInvoke cfInvoke = instruction.asInvoke();
-    DexMethod invokedMethod = cfInvoke.getMethod();
-    AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
-    MethodResolutionResult resolutionResult =
-        appInfo.resolveMethodLegacy(invokedMethod, cfInvoke.isInterface());
-    if (!resolutionResult.isSingleResolution()) {
-      return DesugarDescription.nothing();
-    }
-    assert resolutionResult.getSingleTarget() != null;
-    DexMethod singleTarget = resolutionResult.getSingleTarget().getReference();
-    if (cfInvoke.isInvokeStatic()) {
-      DexMethod retarget = staticRetarget.get(singleTarget);
-      return ensureInvokeRetargetingResult(retarget);
-    }
-    DesugarDescription retarget = computeNonStaticRetarget(singleTarget, false);
-    if (!retarget.needsDesugaring()) {
-      return DesugarDescription.nothing();
-    }
-    if (cfInvoke.isInvokeSuper(context.getHolderType())) {
-      DexClassAndMethod superTarget =
-          appInfo.lookupSuperTarget(invokedMethod, context, appView, appInfo);
-      if (superTarget != null) {
-        assert !superTarget.getDefinition().isStatic();
-        return computeNonStaticRetarget(superTarget.getReference(), true);
-      }
-    }
-    return retarget;
-  }
-
-  private DesugarDescription createWithTarget(
-      BiFunction<CfInstructionDesugaringEventConsumer, MethodProcessingContext, DexMethod>
-          methodProvider) {
-    return DesugarDescription.builder()
-        .setDesugarRewrite(
-            (position,
-                freshLocalProvider,
-                localStackAllocator,
-                desugaringInfo,
-                eventConsumer,
-                context,
-                methodProcessingContext,
-                desugarings,
-                dexItemFactory) -> {
-              DexMethod newInvokeTarget =
-                  methodProvider.apply(eventConsumer, methodProcessingContext);
-              assert appView.definitionFor(newInvokeTarget.getHolderType()) != null;
-              assert !appView.definitionFor(newInvokeTarget.getHolderType()).isInterface();
-              return Collections.singletonList(
-                  new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, false));
-            })
-        .build();
-  }
-
-  private DesugarDescription computeStaticFieldGetDescription(
-      CfInstruction instruction, ProgramMethod context) {
-    CfFieldInstruction fieldInstruction = instruction.asFieldInstruction();
-    DexField fieldRetarget = fieldRetarget(fieldInstruction, context);
-    if (fieldRetarget == null) {
-      return DesugarDescription.nothing();
-    }
-    return DesugarDescription.builder()
-        .setDesugarRewrite(
-            (position,
-                freshLocalProvider,
-                localStackAllocator,
-                desugaringInfo,
-                eventConsumer,
-                context1,
-                methodProcessingContext,
-                desugarings,
-                dexItemFactory) ->
-                Collections.singletonList(fieldInstruction.createWithField(fieldRetarget)))
-        .build();
-  }
-
-  private DexField fieldRetarget(CfFieldInstruction fieldInstruction, ProgramMethod context) {
+  DexField getRetargetField(DexField field, ProgramMethod context) {
     DexEncodedField resolvedField =
-        appView
-            .appInfoForDesugaring()
-            .resolveField(fieldInstruction.getField(), context)
-            .getResolvedField();
+        appView.appInfoForDesugaring().resolveField(field, context).getResolvedField();
     if (resolvedField != null) {
       assert resolvedField.isStatic()
           || !staticFieldRetarget.containsKey(resolvedField.getReference());
@@ -169,34 +66,4 @@
     }
     return null;
   }
-
-  DesugarDescription ensureInvokeRetargetingResult(DexMethod retarget) {
-    if (retarget == null) {
-      return DesugarDescription.nothing();
-    }
-    return createWithTarget(
-        (eventConsumer, methodProcessingContext) ->
-            syntheticHelper.ensureRetargetMethod(retarget, eventConsumer));
-  }
-
-  private DesugarDescription computeNonStaticRetarget(DexMethod singleTarget, boolean superInvoke) {
-    EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(singleTarget);
-    if (descriptor != null) {
-      return createWithTarget(
-          (eventConsumer, methodProcessingContext) ->
-              superInvoke
-                  ? syntheticHelper.ensureForwardingMethod(descriptor, eventConsumer)
-                  : syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
-    }
-    if (covariantRetarget.containsKey(singleTarget)) {
-      return createWithTarget(
-          (eventConsumer, methodProcessingContext) ->
-              syntheticHelper.ensureCovariantRetargetMethod(
-                  singleTarget,
-                  covariantRetarget.get(singleTarget),
-                  eventConsumer,
-                  methodProcessingContext));
-    }
-    return ensureInvokeRetargetingResult(nonEmulatedVirtualRetarget.get(singleTarget));
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterHelper.java
new file mode 100644
index 0000000..4f7b732
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterHelper.java
@@ -0,0 +1,22 @@
+// 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.ir.desugar.desugaredlibrary.retargeter;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import java.util.function.Consumer;
+
+// Used by the ListOfBackportedMethods utility.
+public class DesugaredLibraryRetargeterHelper extends DesugaredLibraryRetargeter {
+
+  public DesugaredLibraryRetargeterHelper(AppView<?> appView) {
+    super(appView);
+  }
+
+  public void visit(Consumer<DexMethod> consumer) {
+    staticRetarget.keySet().forEach(consumer);
+    nonEmulatedVirtualRetarget.keySet().forEach(consumer);
+    emulatedVirtualRetarget.keySet().forEach(consumer);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java
new file mode 100644
index 0000000..0d23fbb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java
@@ -0,0 +1,42 @@
+// 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.ir.desugar.desugaredlibrary.retargeter;
+
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.R8LibraryDesugaringGraphLens;
+
+public class LirToLirDesugaredLibraryRetargeter extends DesugaredLibraryRetargeter {
+
+  LirToLirDesugaredLibraryRetargeter(AppView<?> appView) {
+    super(appView);
+  }
+
+  public FieldLookupResult lookupField(
+      FieldLookupResult previous, ProgramMethod context, R8LibraryDesugaringGraphLens lens) {
+    DexField retargetField = getRetargetField(previous.getReference(), context);
+    if (retargetField != null) {
+      assert !previous.hasReadCastType();
+      assert !previous.hasWriteCastType();
+      return FieldLookupResult.builder(lens)
+          .setReference(retargetField)
+          .setReboundReference(retargetField)
+          .build();
+    }
+    return previous;
+  }
+
+  public MethodLookupResult lookupMethod(
+      MethodLookupResult previous,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext,
+      R8LibraryDesugaringGraphLens lens) {
+    // TODO(b/391572031): Implement.
+    return previous;
+  }
+}