ARM: VIXL32: Merge (un)signed extensions and integer additions

Test: m test-art-target-run-test-551-checker-shifter-operand
Change-Id: I041e80e51bf0954b38ab20dfa9b14aa7f6d6c53b
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index b9d4700..430cdde 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -8269,19 +8269,41 @@
   const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
 
   if (instruction->GetType() == Primitive::kPrimInt) {
-    DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
-
+    const vixl32::Register first = InputRegisterAt(instruction, 0);
+    const vixl32::Register output = OutputRegister(instruction);
     const vixl32::Register second = instruction->InputAt(1)->GetType() == Primitive::kPrimLong
         ? LowRegisterFrom(locations->InAt(1))
         : InputRegisterAt(instruction, 1);
 
-    GenerateDataProcInstruction(kind,
-                                OutputRegister(instruction),
-                                InputRegisterAt(instruction, 0),
-                                Operand(second,
-                                        ShiftFromOpKind(op_kind),
-                                        instruction->GetShiftAmount()),
-                                codegen_);
+    if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
+      DCHECK_EQ(kind, HInstruction::kAdd);
+
+      switch (op_kind) {
+        case HDataProcWithShifterOp::kUXTB:
+          __ Uxtab(output, first, second);
+          break;
+        case HDataProcWithShifterOp::kUXTH:
+          __ Uxtah(output, first, second);
+          break;
+        case HDataProcWithShifterOp::kSXTB:
+          __ Sxtab(output, first, second);
+          break;
+        case HDataProcWithShifterOp::kSXTH:
+          __ Sxtah(output, first, second);
+          break;
+        default:
+          LOG(FATAL) << "Unexpected operation kind: " << op_kind;
+          UNREACHABLE();
+      }
+    } else {
+      GenerateDataProcInstruction(kind,
+                                  output,
+                                  first,
+                                  Operand(second,
+                                          ShiftFromOpKind(op_kind),
+                                          instruction->GetShiftAmount()),
+                                  codegen_);
+    }
   } else {
     DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
 
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h
index 01304ac..8fcceed 100644
--- a/compiler/optimizing/common_arm.h
+++ b/compiler/optimizing/common_arm.h
@@ -227,14 +227,6 @@
   return Location::FpuRegisterPairLocation(low.GetCode(), high.GetCode());
 }
 
-inline bool ShifterOperandSupportsExtension(HInstruction* instruction) {
-  DCHECK(HasShifterOperand(instruction, kArm));
-  // TODO: HAdd applied to the other integral types could make use of
-  // the SXTAB, SXTAH, UXTAB and UXTAH instructions.
-  return instruction->GetType() == Primitive::kPrimLong &&
-         (instruction->IsAdd() || instruction->IsSub());
-}
-
 }  // namespace helpers
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index fe22595..a025fb1 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -29,8 +29,6 @@
 
 namespace arm {
 
-using helpers::ShifterOperandSupportsExtension;
-
 bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use,
                                                                  HInstruction* bitfield_op,
                                                                  bool do_merge) {
@@ -76,7 +74,7 @@
       : kMaxLongShiftDistance;
 
   if (HDataProcWithShifterOp::IsExtensionOp(op_kind)) {
-    if (!ShifterOperandSupportsExtension(use)) {
+    if (!use->IsAdd() && (!use->IsSub() || use->GetType() != Primitive::kPrimLong)) {
       return false;
     }
   // Shift by 1 is a special case that results in the same number and type of instructions
diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc
index e78cd78..627ab4e 100644
--- a/compiler/optimizing/scheduler_arm.cc
+++ b/compiler/optimizing/scheduler_arm.cc
@@ -269,7 +269,6 @@
   const HDataProcWithShifterOp::OpKind op_kind = instruction->GetOpKind();
 
   if (instruction->GetType() == Primitive::kPrimInt) {
-    DCHECK(!HDataProcWithShifterOp::IsExtensionOp(op_kind));
     HandleGenerateDataProcInstruction();
   } else {
     DCHECK_EQ(instruction->GetType(), Primitive::kPrimLong);
diff --git a/test/551-checker-shifter-operand/src/Main.java b/test/551-checker-shifter-operand/src/Main.java
index 951889a..3177ec0 100644
--- a/test/551-checker-shifter-operand/src/Main.java
+++ b/test/551-checker-shifter-operand/src/Main.java
@@ -327,6 +327,7 @@
    */
 
   /// CHECK-START-ARM: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm (after)
+  /// CHECK:                            DataProcWithShifterOp
   /// CHECK-NOT:                        DataProcWithShifterOp
 
   /// CHECK-START-ARM64: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm64 (after)
@@ -399,6 +400,8 @@
   }
 
   /// CHECK-START-ARM: void Main.$opt$validateExtendCharInt1(int, char) instruction_simplifier_arm (after)
+  /// CHECK:                            DataProcWithShifterOp
+  /// CHECK:                            DataProcWithShifterOp
   /// CHECK-NOT:                        DataProcWithShifterOp
 
   /// CHECK-START-ARM64: void Main.$opt$validateExtendCharInt1(int, char) instruction_simplifier_arm64 (after)
@@ -469,6 +472,8 @@
   }
 
   /// CHECK-START-ARM: void Main.$opt$validateExtendShortInt1(int, short) instruction_simplifier_arm (after)
+  /// CHECK:                            DataProcWithShifterOp
+  /// CHECK:                            DataProcWithShifterOp
   /// CHECK-NOT:                        DataProcWithShifterOp
 
   /// CHECK-START-ARM64: void Main.$opt$validateExtendShortInt1(int, short) instruction_simplifier_arm64 (after)