ART: Generalize "x >> (s & m)" simplification.

Extend the simplification from
  x SHIFT (s & mask), mask contains relevant bits
where SHIFT is Shl/Shr/UShr/Ror to
  x SHIFT (s | mask), mask does not contain relevant bits,
  x SHIFT (s ^ mask), mask does not contain relevant bits,
  x SHIFT (s + mask), mask does not contain relevant bits,
  x SHIFT (s - mask), mask does not contain relevant bits,
  x SHIFT ((type)s), s is non-64-bit integral type.

The simplification for the TypeConversion case is motivated
by the work to introduce Uint8 and convert '& 0xff' to
TypeConversion. This CL makes sure the old simplifications
shall still work. The simplifications for Or/Xor/Add/Sub
are added just because we can.

Test: Add tests to 548-checker-instruct-simplification.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 23964345
Change-Id: I71210cb63496fae607a457a627f115260669c2c9
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 1a2494a..cf1cbd5 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -360,18 +360,36 @@
   }
 
   // Shift operations implicitly mask the shift amount according to the type width. Get rid of
-  // unnecessary explicit masking operations on the shift amount.
+  // unnecessary And/Or/Xor/Add/Sub/TypeConversion operations on the shift amount that do not
+  // affect the relevant bits.
   // Replace code looking like
-  //    AND masked_shift, shift, <superset of implicit mask>
-  //    SHL dst, value, masked_shift
+  //    AND adjusted_shift, shift, <superset of implicit mask>
+  //    [OR/XOR/ADD/SUB adjusted_shift, shift, <value not overlapping with implicit mask>]
+  //    [<conversion-from-integral-non-64-bit-type> adjusted_shift, shift]
+  //    SHL dst, value, adjusted_shift
   // with
   //    SHL dst, value, shift
-  if (shift_amount->IsAnd()) {
-    HAnd* and_insn = shift_amount->AsAnd();
-    HConstant* mask = and_insn->GetConstantRight();
-    if ((mask != nullptr) && ((Int64FromConstant(mask) & implicit_mask) == implicit_mask)) {
-      instruction->ReplaceInput(and_insn->GetLeastConstantLeft(), 1);
+  if (shift_amount->IsAnd() ||
+      shift_amount->IsOr() ||
+      shift_amount->IsXor() ||
+      shift_amount->IsAdd() ||
+      shift_amount->IsSub()) {
+    int64_t required_result = shift_amount->IsAnd() ? implicit_mask : 0;
+    HBinaryOperation* bin_op = shift_amount->AsBinaryOperation();
+    HConstant* mask = bin_op->GetConstantRight();
+    if (mask != nullptr && (Int64FromConstant(mask) & implicit_mask) == required_result) {
+      instruction->ReplaceInput(bin_op->GetLeastConstantLeft(), 1);
       RecordSimplification();
+      return;
+    }
+  } else if (shift_amount->IsTypeConversion()) {
+    DCHECK_NE(shift_amount->GetType(), DataType::Type::kBool);  // We never convert to bool.
+    DataType::Type source_type = shift_amount->InputAt(0)->GetType();
+    // Non-integral and 64-bit source types require an explicit type conversion.
+    if (DataType::IsIntegralType(source_type) && !DataType::Is64BitType(source_type)) {
+      instruction->ReplaceInput(shift_amount->AsTypeConversion()->GetInput(), 1);
+      RecordSimplification();
+      return;
     }
   }
 }