MIPS32: int java.lang.*.numberOfLeadingZeros

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

Change-Id: Icaf746cb807863f944ff4ebb5da6e6b2846eac58
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 9f16462..a974739 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -426,6 +426,60 @@
              GetAssembler());
 }
 
+static void GenNumberOfLeadingZeroes(LocationSummary* locations,
+                                     bool is64bit,
+                                     bool isR6,
+                                     MipsAssembler* assembler) {
+  Register out = locations->Out().AsRegister<Register>();
+  if (is64bit) {
+    Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
+    Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
+
+    if (isR6) {
+      __ ClzR6(AT, in_hi);
+      __ ClzR6(TMP, in_lo);
+      __ Seleqz(TMP, TMP, in_hi);
+    } else {
+      __ ClzR2(AT, in_hi);
+      __ ClzR2(TMP, in_lo);
+      __ Movn(TMP, ZERO, in_hi);
+    }
+    __ Addu(out, AT, TMP);
+  } else {
+    Register in = locations->InAt(0).AsRegister<Register>();
+
+    if (isR6) {
+      __ ClzR6(out, in);
+    } else {
+      __ ClzR2(out, in);
+    }
+  }
+}
+
+// int java.lang.Integer.numberOfLeadingZeros(int i)
+void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
+  GenNumberOfLeadingZeroes(invoke->GetLocations(),
+                           false,
+                           codegen_->GetInstructionSetFeatures().IsR6(),
+                           GetAssembler());
+}
+
+// int java.lang.Long.numberOfLeadingZeros(long i)
+void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
+  GenNumberOfLeadingZeroes(invoke->GetLocations(),
+                           true,
+                           codegen_->GetInstructionSetFeatures().IsR6(),
+                           GetAssembler());
+}
+
 // int java.lang.Integer.reverse(int)
 void IntrinsicLocationsBuilderMIPS::VisitIntegerReverse(HInvoke* invoke) {
   CreateIntToIntLocations(arena_, invoke);
@@ -564,8 +618,6 @@
 void IntrinsicCodeGeneratorMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
 }
 
-UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros)
-UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros)
 UNIMPLEMENTED_INTRINSIC(MathAbsDouble)
 UNIMPLEMENTED_INTRINSIC(MathAbsFloat)
 UNIMPLEMENTED_INTRINSIC(MathAbsInt)
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 86e5762..5a4de82 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -302,6 +302,46 @@
   EmitR(0, rs, rt, rd, 0, 0x27);
 }
 
+void MipsAssembler::Movz(Register rd, Register rs, Register rt) {
+  CHECK(!IsR6());
+  EmitR(0, rs, rt, rd, 0, 0x0A);
+}
+
+void MipsAssembler::Movn(Register rd, Register rs, Register rt) {
+  CHECK(!IsR6());
+  EmitR(0, rs, rt, rd, 0, 0x0B);
+}
+
+void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) {
+  CHECK(IsR6());
+  EmitR(0, rs, rt, rd, 0, 0x35);
+}
+
+void MipsAssembler::Selnez(Register rd, Register rs, Register rt) {
+  CHECK(IsR6());
+  EmitR(0, rs, rt, rd, 0, 0x37);
+}
+
+void MipsAssembler::ClzR6(Register rd, Register rs) {
+  CHECK(IsR6());
+  EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10);
+}
+
+void MipsAssembler::ClzR2(Register rd, Register rs) {
+  CHECK(!IsR6());
+  EmitR(0x1C, rs, rd, rd, 0, 0x20);
+}
+
+void MipsAssembler::CloR6(Register rd, Register rs) {
+  CHECK(IsR6());
+  EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11);
+}
+
+void MipsAssembler::CloR2(Register rd, Register rs) {
+  CHECK(!IsR6());
+  EmitR(0x1C, rs, rd, rd, 0, 0x21);
+}
+
 void MipsAssembler::Seb(Register rd, Register rt) {
   EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20);
 }
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 6a37cc9..91ec804 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -133,6 +133,15 @@
   void Xori(Register rt, Register rs, uint16_t imm16);
   void Nor(Register rd, Register rs, Register rt);
 
+  void Movz(Register rd, Register rs, Register rt);  // R2
+  void Movn(Register rd, Register rs, Register rt);  // R2
+  void Seleqz(Register rd, Register rs, Register rt);  // R6
+  void Selnez(Register rd, Register rs, Register rt);  // R6
+  void ClzR6(Register rd, Register rs);
+  void ClzR2(Register rd, Register rs);
+  void CloR6(Register rd, Register rs);
+  void CloR2(Register rd, Register rs);
+
   void Seb(Register rd, Register rt);  // R2+
   void Seh(Register rd, Register rt);  // R2+
   void Wsbh(Register rd, Register rt);  // R2+