Revert^2 "ART: Redundant AND operation removal optimization"

Re-enables the original CL plus fixes a bug in
InstructionSimplifierVisitor::VisitTypeConversion, where
there was no check for non-constant input for the And.

This reverts commit 050686452146e1f5d31aed560c682d992c376fed.

Test: compile duckduckgo.apk.
Test: 458-checker-instruct-simplification
Test: test_art_target, test_art_host.

Change-Id: Iecf13f492fb1d1769726d187093e455216f2c2c6
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index a75639f..91b2e8b 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -24,6 +24,7 @@
 #include "intrinsics.h"
 #include "intrinsics_utils.h"
 #include "mirror/class-inl.h"
+#include "optimizing/data_type.h"
 #include "optimizing/nodes.h"
 #include "scoped_thread_state_change-inl.h"
 #include "sharpening.h"
@@ -112,7 +113,6 @@
   void VisitDeoptimize(HDeoptimize* deoptimize) override;
   void VisitVecMul(HVecMul* instruction) override;
   void VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet* instruction) override;
-
   void SimplifySystemArrayCopy(HInvoke* invoke);
   void SimplifyStringEquals(HInvoke* invoke);
   void SimplifyFP2Int(HInvoke* invoke);
@@ -1185,6 +1185,33 @@
       !(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32);
 }
 
+static bool CanRemoveRedundantAnd(HConstant* and_right,
+                                  HConstant* shr_right,
+                                  DataType::Type result_type) {
+  int64_t and_cst = Int64FromConstant(and_right);
+  int64_t shr_cst = Int64FromConstant(shr_right);
+
+  // In the following sequence A is the input value, D is the result:
+  // B := A & x
+  // C := B >> r
+  // D := TypeConv(n-bit type) C
+
+  // The value of D is entirely dependent on the bits [n-1:0] of C, which in turn are dependent
+  // on bits [r+n-1:r] of B.
+  // Therefore, if the AND does not change bits [r+n-1:r] of A then it will not affect D.
+  // This can be checked by ensuring that bits [r+n-1:r] of the AND Constant are 1.
+
+  // For example: return (byte) ((value & 0xff00) >> 8)
+  //              return (byte) ((value & 0xff000000) >> 31)
+
+  // The mask sets bits [r+n-1:r] to 1, and all others to 0.
+  int64_t mask = DataType::MaxValueOfIntegralType(DataType::ToUnsigned(result_type)) << shr_cst;
+
+  // If the result of a bitwise AND between the mask and the AND constant is the original mask, then
+  // the AND does not change bits [r+n-1:r], meaning that it is redundant and can be removed.
+  return ((and_cst & mask) == mask);
+}
+
 static inline bool TryReplaceFieldOrArrayGetType(HInstruction* maybe_get, DataType::Type new_type) {
   if (maybe_get->IsInstanceFieldGet()) {
     maybe_get->AsInstanceFieldGet()->SetType(new_type);
@@ -1305,6 +1332,36 @@
         return;
       }
     }
+  } else if (input->IsShr() && DataType::IsIntegralType(result_type) &&
+            // Optimization only applies to lossy Type Conversions.
+            !IsTypeConversionLossless(input_type, result_type)) {
+    DCHECK(DataType::IsIntegralType(input_type));
+    HShr* shr_op = input->AsShr();
+    HConstant* shr_right = shr_op->GetConstantRight();
+    HInstruction* shr_left = shr_op->GetLeastConstantLeft();
+    if (shr_right != nullptr && shr_left->IsAnd()) {
+      // Optimization needs AND -> SHR -> TypeConversion pattern.
+      HAnd* and_op = shr_left->AsAnd();
+      HConstant* and_right = and_op->GetConstantRight();
+      HInstruction* and_left = and_op->GetLeastConstantLeft();
+      if (and_right != nullptr &&
+          !DataType::IsUnsignedType(and_left->GetType()) &&
+          !DataType::IsUnsignedType(result_type) &&
+          !DataType::IsUnsignedType(and_right->GetType()) &&
+          (DataType::Size(and_left->GetType()) < 8) &&
+          (DataType::Size(result_type) == 1)) {
+        // TODO: Support Unsigned Types.
+        // TODO: Support Long Types.
+        // TODO: Support result types other than byte.
+        if (and_op->HasOnlyOneNonEnvironmentUse() &&
+            CanRemoveRedundantAnd(and_right, shr_right, result_type)) {
+          and_op->ReplaceWith(and_left);
+          and_op->GetBlock()->RemoveInstruction(and_op);
+          RecordSimplification();
+          return;
+        }
+      }
+    }
   } else if (input->IsAnd() && DataType::IsIntegralType(result_type)) {
     DCHECK(DataType::IsIntegralType(input_type));
     HAnd* input_and = input->AsAnd();