MIPS32: Highest/Lowest One Bit Set:

- int java.lang.Integer.highestOneBit(int)
- int java.lang.Integer.lowestOneBit(int)
- long java.lang.Long.highestOneBit(long)
- long java.lang.Long.lowestOneBit(long)

Change-Id: I575ec6f70cf5cac620cc5d9e49ec3f7b554b4622
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 0622610..710df0a 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1663,6 +1663,119 @@
   GenIsInfinite(invoke->GetLocations(), Primitive::kPrimDouble, IsR6(), GetAssembler());
 }
 
+static void GenHighestOneBit(LocationSummary* locations,
+                             const Primitive::Type type,
+                             bool isR6,
+                             MipsAssembler* assembler) {
+  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+  if (type == Primitive::kPrimLong) {
+    Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
+    Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
+    Register out_lo = locations->Out().AsRegisterPairLow<Register>();
+    Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
+
+    if (isR6) {
+      __ ClzR6(TMP, in_hi);
+    } else {
+      __ ClzR2(TMP, in_hi);
+    }
+    __ LoadConst32(AT, 0x80000000);
+    __ Srlv(out_hi, AT, TMP);
+    __ And(out_hi, out_hi, in_hi);
+    if (isR6) {
+      __ ClzR6(TMP, in_lo);
+    } else {
+      __ ClzR2(TMP, in_lo);
+    }
+    __ Srlv(out_lo, AT, TMP);
+    __ And(out_lo, out_lo, in_lo);
+    if (isR6) {
+      __ Seleqz(out_lo, out_lo, out_hi);
+    } else {
+      __ Movn(out_lo, ZERO, out_hi);
+    }
+  } else {
+    Register in = locations->InAt(0).AsRegister<Register>();
+    Register out = locations->Out().AsRegister<Register>();
+
+    if (isR6) {
+      __ ClzR6(TMP, in);
+    } else {
+      __ ClzR2(TMP, in);
+    }
+    __ LoadConst32(AT, 0x80000000);
+    __ Srlv(AT, AT, TMP);  // Srlv shifts in the range of [0;31] bits (lower 5 bits of arg).
+    __ And(out, AT, in);   // So this is required for 0 (=shift by 32).
+  }
+}
+
+// int java.lang.Integer.highestOneBit(int)
+void IntrinsicLocationsBuilderMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
+  GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
+}
+
+// long java.lang.Long.highestOneBit(long)
+void IntrinsicLocationsBuilderMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
+  GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
+}
+
+static void GenLowestOneBit(LocationSummary* locations,
+                            const Primitive::Type type,
+                            bool isR6,
+                            MipsAssembler* assembler) {
+  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+  if (type == Primitive::kPrimLong) {
+    Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
+    Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
+    Register out_lo = locations->Out().AsRegisterPairLow<Register>();
+    Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
+
+    __ Subu(TMP, ZERO, in_lo);
+    __ And(out_lo, TMP, in_lo);
+    __ Subu(TMP, ZERO, in_hi);
+    __ And(out_hi, TMP, in_hi);
+    if (isR6) {
+      __ Seleqz(out_hi, out_hi, out_lo);
+    } else {
+      __ Movn(out_hi, ZERO, out_lo);
+    }
+  } else {
+    Register in = locations->InAt(0).AsRegister<Register>();
+    Register out = locations->Out().AsRegister<Register>();
+
+    __ Subu(TMP, ZERO, in);
+    __ And(out, TMP, in);
+  }
+}
+
+// int java.lang.Integer.lowestOneBit(int)
+void IntrinsicLocationsBuilderMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
+  GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
+}
+
+// long java.lang.Long.lowestOneBit(long)
+void IntrinsicLocationsBuilderMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
+  CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
+  GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
+}
+
 // Unimplemented intrinsics.
 
 UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
@@ -1719,11 +1832,6 @@
 UNIMPLEMENTED_INTRINSIC(MIPS, MathTan)
 UNIMPLEMENTED_INTRINSIC(MIPS, MathTanh)
 
-UNIMPLEMENTED_INTRINSIC(MIPS, IntegerHighestOneBit)
-UNIMPLEMENTED_INTRINSIC(MIPS, LongHighestOneBit)
-UNIMPLEMENTED_INTRINSIC(MIPS, IntegerLowestOneBit)
-UNIMPLEMENTED_INTRINSIC(MIPS, LongLowestOneBit)
-
 UNREACHABLE_INTRINSICS(MIPS)
 
 #undef UNIMPLEMENTED_INTRINSIC