Added SAD test. Generalized vector analysis of narrow type.

Rationale:
The new example shows that scalar type of array reference does not
reflect signed-ness or unsigned-ness of vector operation. Instead
the vectorizer's analysis looks at zero or sign extension to determine
what operation is required and passes this as explicit or implicit
attribute to the code generator. So don't use packed data type to
decide what operation to perform. This become relevant while switching
to explicit signed and unsigned data types, where we want to pass the
right type to make this decision in the future

Test: test-art-host test-art-target

Bug: 64091002

Change-Id: I49a8827a13dd703910effcb5a5ebc4b9646cd1e8
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 6c918a3..7e37018 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -71,6 +71,12 @@
   return false;
 }
 
+// Forward declaration.
+static bool IsZeroExtensionAndGet(HInstruction* instruction,
+                                  DataType::Type type,
+                                  /*out*/ HInstruction** operand,
+                                  bool to64 = false);
+
 // Detect a sign extension in instruction from the given type. The to64 parameter
 // denotes if result is long, and thus sign extension from int can be included.
 // Returns the promoted operand on success.
@@ -124,9 +130,19 @@
         return false;
     }
   }
-  // Explicit type conversion to long.
-  if (instruction->IsTypeConversion() && instruction->GetType() == DataType::Type::kInt64) {
-    return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+  // Explicit type conversions.
+  if (instruction->IsTypeConversion()) {
+    DataType::Type from = instruction->InputAt(0)->GetType();
+    switch (instruction->GetType()) {
+      case DataType::Type::kInt64:
+        return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+      case DataType::Type::kInt16:
+        return type == DataType::Type::kUint16 &&
+               from == DataType::Type::kUint16 &&
+               IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64);
+      default:
+        return false;
+    }
   }
   return false;
 }
@@ -137,7 +153,7 @@
 static bool IsZeroExtensionAndGet(HInstruction* instruction,
                                   DataType::Type type,
                                   /*out*/ HInstruction** operand,
-                                  bool to64 = false) {
+                                  bool to64) {
   // Accept any already wider constant that would be handled properly by zero
   // extension when represented in the *width* of the given narrower data type
   // (the fact that byte/short/int normally sign extend does not matter here).
@@ -200,9 +216,19 @@
       }
     }
   }
-  // Explicit type conversion to long.
-  if (instruction->IsTypeConversion() && instruction->GetType() == DataType::Type::kInt64) {
-    return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+  // Explicit type conversions.
+  if (instruction->IsTypeConversion()) {
+    DataType::Type from = instruction->InputAt(0)->GetType();
+    switch (instruction->GetType()) {
+      case DataType::Type::kInt64:
+        return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+      case DataType::Type::kUint16:
+        return type == DataType::Type::kInt16 &&
+               from == DataType::Type::kInt16 &&
+               IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64);
+      default:
+        return false;
+    }
   }
   return false;
 }
@@ -1885,9 +1911,17 @@
   bool is_unsigned = false;
   DataType::Type sub_type = a->GetType();
   if (a->IsTypeConversion()) {
-    sub_type = a->InputAt(0)->GetType();
+    HInstruction* hunt = a;
+    while (hunt->IsTypeConversion()) {
+      hunt = hunt->InputAt(0);
+    }
+    sub_type = hunt->GetType();
   } else if (b->IsTypeConversion()) {
-    sub_type = b->InputAt(0)->GetType();
+    HInstruction* hunt = a;
+    while (hunt->IsTypeConversion()) {
+      hunt = hunt->InputAt(0);
+    }
+    sub_type = hunt->GetType();
   }
   if (reduction_type != sub_type &&
       (!IsNarrowerOperands(a, b, sub_type, &r, &s, &is_unsigned) || is_unsigned)) {