MIPS32: java.lang.*.reverse

- int java.lang.Integer.reverse(int)
- long java.lang.Long.reverse(long)

Change-Id: I18d0f784b9e4bffdc1bda3604f4ed7d3c57b8d68
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 3268445..9f16462 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -230,13 +230,16 @@
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
-static void GenReverseBytes(LocationSummary* locations,
-                            Primitive::Type type,
-                            MipsAssembler* assembler,
-                            bool isR2OrNewer) {
+static void GenReverse(LocationSummary* locations,
+                       Primitive::Type type,
+                       bool isR2OrNewer,
+                       bool isR6,
+                       bool reverseBits,
+                       MipsAssembler* assembler) {
   DCHECK(type == Primitive::kPrimShort ||
          type == Primitive::kPrimInt ||
          type == Primitive::kPrimLong);
+  DCHECK(type != Primitive::kPrimShort || !reverseBits);
 
   if (type == Primitive::kPrimShort) {
     Register in = locations->InAt(0).AsRegister<Register>();
@@ -273,6 +276,30 @@
       __ And(out, out, AT);
       __ Or(out, out, TMP);
     }
+    if (reverseBits) {
+      if (isR6) {
+        __ Bitswap(out, out);
+      } else {
+        __ LoadConst32(AT, 0x0F0F0F0F);
+        __ And(TMP, out, AT);
+        __ Sll(TMP, TMP, 4);
+        __ Srl(out, out, 4);
+        __ And(out, out, AT);
+        __ Or(out, TMP, out);
+        __ LoadConst32(AT, 0x33333333);
+        __ And(TMP, out, AT);
+        __ Sll(TMP, TMP, 2);
+        __ Srl(out, out, 2);
+        __ And(out, out, AT);
+        __ Or(out, TMP, out);
+        __ LoadConst32(AT, 0x55555555);
+        __ And(TMP, out, AT);
+        __ Sll(TMP, TMP, 1);
+        __ Srl(out, out, 1);
+        __ And(out, out, AT);
+        __ Or(out, TMP, out);
+      }
+    }
   } else if (type == Primitive::kPrimLong) {
     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -314,6 +341,46 @@
       __ And(out_lo, out_lo, AT);
       __ Or(out_lo, out_lo, TMP);
     }
+    if (reverseBits) {
+      if (isR6) {
+        __ Bitswap(out_hi, out_hi);
+        __ Bitswap(out_lo, out_lo);
+      } else {
+        __ LoadConst32(AT, 0x0F0F0F0F);
+        __ And(TMP, out_hi, AT);
+        __ Sll(TMP, TMP, 4);
+        __ Srl(out_hi, out_hi, 4);
+        __ And(out_hi, out_hi, AT);
+        __ Or(out_hi, TMP, out_hi);
+        __ And(TMP, out_lo, AT);
+        __ Sll(TMP, TMP, 4);
+        __ Srl(out_lo, out_lo, 4);
+        __ And(out_lo, out_lo, AT);
+        __ Or(out_lo, TMP, out_lo);
+        __ LoadConst32(AT, 0x33333333);
+        __ And(TMP, out_hi, AT);
+        __ Sll(TMP, TMP, 2);
+        __ Srl(out_hi, out_hi, 2);
+        __ And(out_hi, out_hi, AT);
+        __ Or(out_hi, TMP, out_hi);
+        __ And(TMP, out_lo, AT);
+        __ Sll(TMP, TMP, 2);
+        __ Srl(out_lo, out_lo, 2);
+        __ And(out_lo, out_lo, AT);
+        __ Or(out_lo, TMP, out_lo);
+        __ LoadConst32(AT, 0x55555555);
+        __ And(TMP, out_hi, AT);
+        __ Sll(TMP, TMP, 1);
+        __ Srl(out_hi, out_hi, 1);
+        __ And(out_hi, out_hi, AT);
+        __ Or(out_hi, TMP, out_hi);
+        __ And(TMP, out_lo, AT);
+        __ Sll(TMP, TMP, 1);
+        __ Srl(out_lo, out_lo, 1);
+        __ And(out_lo, out_lo, AT);
+        __ Or(out_lo, TMP, out_lo);
+      }
+    }
   }
 }
 
@@ -323,10 +390,12 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(),
-                  Primitive::kPrimInt,
-                  GetAssembler(),
-                  codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2());
+  GenReverse(invoke->GetLocations(),
+             Primitive::kPrimInt,
+             codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(),
+             codegen_->GetInstructionSetFeatures().IsR6(),
+             false,
+             GetAssembler());
 }
 
 // long java.lang.Long.reverseBytes(long)
@@ -335,10 +404,12 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitLongReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(),
-                  Primitive::kPrimLong,
-                  GetAssembler(),
-                  codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2());
+  GenReverse(invoke->GetLocations(),
+             Primitive::kPrimLong,
+             codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(),
+             codegen_->GetInstructionSetFeatures().IsR6(),
+             false,
+             GetAssembler());
 }
 
 // short java.lang.Short.reverseBytes(short)
@@ -347,10 +418,40 @@
 }
 
 void IntrinsicCodeGeneratorMIPS::VisitShortReverseBytes(HInvoke* invoke) {
-  GenReverseBytes(invoke->GetLocations(),
-                  Primitive::kPrimShort,
-                  GetAssembler(),
-                  codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2());
+  GenReverse(invoke->GetLocations(),
+             Primitive::kPrimShort,
+             codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(),
+             codegen_->GetInstructionSetFeatures().IsR6(),
+             false,
+             GetAssembler());
+}
+
+// int java.lang.Integer.reverse(int)
+void IntrinsicLocationsBuilderMIPS::VisitIntegerReverse(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitIntegerReverse(HInvoke* invoke) {
+  GenReverse(invoke->GetLocations(),
+             Primitive::kPrimInt,
+             codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(),
+             codegen_->GetInstructionSetFeatures().IsR6(),
+             true,
+             GetAssembler());
+}
+
+// long java.lang.Long.reverse(long)
+void IntrinsicLocationsBuilderMIPS::VisitLongReverse(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) {
+  GenReverse(invoke->GetLocations(),
+             Primitive::kPrimLong,
+             codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(),
+             codegen_->GetInstructionSetFeatures().IsR6(),
+             true,
+             GetAssembler());
 }
 
 // boolean java.lang.String.equals(Object anObject)
@@ -463,8 +564,6 @@
 void IntrinsicCodeGeneratorMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
 }
 
-UNIMPLEMENTED_INTRINSIC(IntegerReverse)
-UNIMPLEMENTED_INTRINSIC(LongReverse)
 UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros)
 UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros)
 UNIMPLEMENTED_INTRINSIC(MathAbsDouble)
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index fc7ac70..86e5762 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -314,6 +314,11 @@
   EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20);
 }
 
+void MipsAssembler::Bitswap(Register rd, Register rt) {
+  CHECK(IsR6());
+  EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20);
+}
+
 void MipsAssembler::Sll(Register rd, Register rt, int shamt) {
   CHECK(IsUint<5>(shamt)) << shamt;
   EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00);
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 1ef0992..6a37cc9 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -136,6 +136,7 @@
   void Seb(Register rd, Register rt);  // R2+
   void Seh(Register rd, Register rt);  // R2+
   void Wsbh(Register rd, Register rt);  // R2+
+  void Bitswap(Register rd, Register rt);  // R6
 
   void Sll(Register rd, Register rt, int shamt);
   void Srl(Register rd, Register rt, int shamt);