Track int parameters with bitwise AND operations

Bug: b/196017578
Change-Id: Ib6c820cce0c3069c7d3a49113182caf1535c9b95
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
index 6a72244..a897bd0 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescriptionMethodOptimizationInfoFixer.java
@@ -149,12 +149,12 @@
   }
 
   /**
-   * Function for rewriting the unused arguments on a piece of method optimization info after
-   * prototype changes were made.
+   * Function for rewriting a BitSet that stores a bit per argument on a piece of method
+   * optimization info after prototype changes were made.
    */
   @Override
-  public BitSet fixupUnusedArguments(BitSet unusedArguments) {
-    return fixupArgumentInfo(unusedArguments);
+  public BitSet fixupArguments(BitSet arguments) {
+    return fixupArgumentInfo(arguments);
   }
 
   private BitSet fixupArgumentInfo(BitSet bitSet) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index c1a7b55..7327760 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -75,6 +75,9 @@
 
   void classInitializerMayBePostponed(DexEncodedMethod method);
 
+  void setParametersWithBitwiseOperations(
+      ProgramMethod method, BitSet parametersWithBitwiseOperations);
+
   void setUnusedArguments(ProgramMethod method, BitSet unusedArguments);
 
   // Unset methods.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index b1e1a69..f596d2a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -148,6 +148,16 @@
   }
 
   @Override
+  public boolean hasParametersWithBitwiseOperations() {
+    return false;
+  }
+
+  @Override
+  public BitSet getParametersWithBitwiseOperations() {
+    return null;
+  }
+
+  @Override
   public BitSet getUnusedArguments() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 0d42b62..31775ae 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -80,6 +80,10 @@
 
   public abstract SimpleInliningConstraint getSimpleInliningConstraint();
 
+  public abstract boolean hasParametersWithBitwiseOperations();
+
+  public abstract BitSet getParametersWithBitwiseOperations();
+
   public final boolean hasUnusedArguments() {
     assert getUnusedArguments() == null || !getUnusedArguments().isEmpty();
     return getUnusedArguments() != null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index ba4ba64..892f856 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -101,6 +101,7 @@
 import com.android.tools.r8.kotlin.Kotlin;
 import com.android.tools.r8.kotlin.Kotlin.Intrinsics;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.Sets;
@@ -156,6 +157,7 @@
     computeReturnValueOnlyDependsOnArguments(feedback, definition, code, timing);
     BitSet nonNullParamOrThrow = computeNonNullParamOrThrow(feedback, definition, code, timing);
     computeNonNullParamOnNormalExits(feedback, code, nonNullParamOrThrow, timing);
+    computeParametersWithBitwiseOperations(method, code, feedback, timing);
     computeUnusedArguments(method, code, feedback, timing);
   }
 
@@ -1173,6 +1175,36 @@
     return true;
   }
 
+  private void computeParametersWithBitwiseOperations(
+      ProgramMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+    timing.begin("Compute parameters with bitwise operations");
+    computeParametersWithBitwiseOperations(method, code, feedback);
+    timing.end();
+  }
+
+  private void computeParametersWithBitwiseOperations(
+      ProgramMethod method, IRCode code, OptimizationFeedback feedback) {
+    BitSet parametersWithBitwiseOperations = new BitSet(method.getParameters().size());
+    InstructionIterator instructionIterator = code.entryBlock().iterator();
+    Argument argument = instructionIterator.next().asArgument();
+    while (argument != null) {
+      if (hasBitwiseOperation(argument)) {
+        int parameterIndex =
+            argument.getIndex() - BooleanUtils.intValue(method.getDefinition().isInstance());
+        parametersWithBitwiseOperations.set(parameterIndex);
+      }
+      argument = instructionIterator.next().asArgument();
+    }
+    if (!parametersWithBitwiseOperations.isEmpty()) {
+      feedback.setParametersWithBitwiseOperations(method, parametersWithBitwiseOperations);
+    }
+  }
+
+  private boolean hasBitwiseOperation(Argument argument) {
+    return argument.getOutType().isInt()
+        && argument.outValue().hasUserThatMatches(Instruction::isAnd);
+  }
+
   private void computeUnusedArguments(
       ProgramMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
     timing.begin("Compute unused arguments");
@@ -1191,6 +1223,8 @@
       }
       argument = instructionIterator.next().asArgument();
     }
-    feedback.setUnusedArguments(method, unusedArguments);
+    if (!unusedArguments.isEmpty()) {
+      feedback.setUnusedArguments(method, unusedArguments);
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
index 0044499..4279b3c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoFixer.java
@@ -43,5 +43,5 @@
       SimpleInliningConstraint constraint,
       SimpleInliningConstraintFactory factory);
 
-  public abstract BitSet fixupUnusedArguments(BitSet unusedArguments);
+  public abstract BitSet fixupArguments(BitSet arguments);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 7dcb035..555bd6f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -79,6 +79,7 @@
       NeverSimpleInliningConstraint.getInstance();
 
   private int maxRemovedAndroidLogLevel = MaximumRemovedAndroidLogLevelRule.NOT_SET;
+  private BitSet parametersWithBitwiseOperations = null;
   private BitSet unusedArguments = null;
 
   // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are
@@ -159,6 +160,7 @@
         .fixupNonNullParamOnNormalExits(fixer)
         .fixupNonNullParamOrThrow(fixer)
         .fixupReturnedArgumentIndex(fixer)
+        .fixupParametersWithBitwiseOperations(fixer)
         .fixupSimpleInliningConstraint(appView, fixer)
         .fixupUnusedArguments(fixer);
   }
@@ -435,13 +437,41 @@
   }
 
   @Override
+  public boolean hasParametersWithBitwiseOperations() {
+    return parametersWithBitwiseOperations != null;
+  }
+
+  @Override
+  public BitSet getParametersWithBitwiseOperations() {
+    return parametersWithBitwiseOperations;
+  }
+
+  public void setParametersWithBitwiseOperations(BitSet parametersWithBitwiseOperations) {
+    if (parametersWithBitwiseOperations != null && !parametersWithBitwiseOperations.isEmpty()) {
+      this.parametersWithBitwiseOperations = parametersWithBitwiseOperations;
+    } else {
+      this.parametersWithBitwiseOperations = null;
+    }
+  }
+
+  public MutableMethodOptimizationInfo fixupParametersWithBitwiseOperations(
+      MethodOptimizationInfoFixer fixer) {
+    return fixupParametersWithBitwiseOperations(fixer.fixupArguments(unusedArguments));
+  }
+
+  public MutableMethodOptimizationInfo fixupParametersWithBitwiseOperations(
+      BitSet parametersWithBitwiseOperations) {
+    setParametersWithBitwiseOperations(parametersWithBitwiseOperations);
+    return this;
+  }
+
+  @Override
   public BitSet getUnusedArguments() {
     return unusedArguments;
   }
 
   public MutableMethodOptimizationInfo fixupUnusedArguments(MethodOptimizationInfoFixer fixer) {
-    fixupUnusedArguments(fixer.fixupUnusedArguments(unusedArguments));
-    return this;
+    return fixupUnusedArguments(fixer.fixupArguments(unusedArguments));
   }
 
   public MutableMethodOptimizationInfo fixupUnusedArguments(BitSet unusedArguments) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 2148519..bbb1cec 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -277,6 +277,13 @@
   }
 
   @Override
+  public void setParametersWithBitwiseOperations(
+      ProgramMethod method, BitSet parametersWithBitwiseOperations) {
+    getMethodOptimizationInfoForUpdating(method)
+        .setParametersWithBitwiseOperations(parametersWithBitwiseOperations);
+  }
+
+  @Override
   public synchronized void setUnusedArguments(ProgramMethod method, BitSet unusedArguments) {
     getMethodOptimizationInfoForUpdating(method).setUnusedArguments(unusedArguments);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 3f46ce1..c3ff56a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -126,6 +126,10 @@
   public void classInitializerMayBePostponed(DexEncodedMethod method) {}
 
   @Override
+  public void setParametersWithBitwiseOperations(
+      ProgramMethod method, BitSet parametersWithBitwiseOperations) {}
+
+  @Override
   public void setUnusedArguments(ProgramMethod method, BitSet unusedArguments) {}
 
   // Unset methods.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index a0c9863..51c5bb6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -213,6 +213,15 @@
   }
 
   @Override
+  public void setParametersWithBitwiseOperations(
+      ProgramMethod method, BitSet parametersWithBitwiseOperations) {
+    method
+        .getDefinition()
+        .getMutableOptimizationInfo()
+        .setParametersWithBitwiseOperations(parametersWithBitwiseOperations);
+  }
+
+  @Override
   public void setUnusedArguments(ProgramMethod method, BitSet unusedArguments) {
     method.getDefinition().getMutableOptimizationInfo().setUnusedArguments(unusedArguments);
   }