true, // kIntrinsicFloatCvt
true, // kIntrinsicReverseBits
true, // kIntrinsicReverseBytes
+ true, // kIntrinsicNumberOfLeadingZeros
true, // kIntrinsicAbsInt
true, // kIntrinsicAbsLong
true, // kIntrinsicAbsFloat
static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static");
+static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros],
+ "NumberOfLeadingZeros must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static");
static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static");
"putObjectVolatile", // kNameCachePutObjectVolatile
"putOrderedObject", // kNameCachePutOrderedObject
"arraycopy", // kNameCacheArrayCopy
+ "numberOfLeadingZeros", // kNameCacheNumberOfLeadingZeros
};
const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32),
INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64),
+ INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32),
+ INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64),
+
INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
intrinsic.d.data & kIntrinsicFlagIsOrdered);
case kIntrinsicSystemArrayCopyCharArray:
return backend->GenInlinedArrayCopyCharArray(info);
+ case kIntrinsicNumberOfLeadingZeros:
+ return false; // not implemented in quick
default:
LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
return false; // avoid warning "control reaches end of non-void function"
kNameCachePutObjectVolatile,
kNameCachePutOrderedObject,
kNameCacheArrayCopy,
+ kNameCacheNumberOfLeadingZeros,
kNameCacheLast
};
LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
UNREACHABLE();
}
+ case kIntrinsicNumberOfLeadingZeros:
+ switch (GetType(method.d.data, true)) {
+ case Primitive::kPrimInt:
+ return Intrinsics::kIntegerNumberOfLeadingZeros;
+ case Primitive::kPrimLong:
+ return Intrinsics::kLongNumberOfLeadingZeros;
+ default:
+ LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
+ UNREACHABLE();
+ }
// Abs.
case kIntrinsicAbsDouble:
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
}
+static void GenNumberOfLeadingZeros(LocationSummary* locations,
+ Primitive::Type type,
+ ArmAssembler* assembler) {
+ Location in = locations->InAt(0);
+ Register out = locations->Out().AsRegister<Register>();
+
+ DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong));
+
+ if (type == Primitive::kPrimLong) {
+ Register in_reg_lo = in.AsRegisterPairLow<Register>();
+ Register in_reg_hi = in.AsRegisterPairHigh<Register>();
+ Label end;
+ __ clz(out, in_reg_hi);
+ __ CompareAndBranchIfNonZero(in_reg_hi, &end);
+ __ clz(out, in_reg_lo);
+ __ AddConstant(out, 32);
+ __ Bind(&end);
+ } else {
+ __ clz(out, in.AsRegister<Register>());
+ }
+}
+
+void IntrinsicLocationsBuilderARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
+ GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+}
+
+void IntrinsicLocationsBuilderARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
+ LocationSummary* locations = new (arena_) LocationSummary(invoke,
+ LocationSummary::kNoCall,
+ kIntrinsified);
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+}
+
+void IntrinsicCodeGeneratorARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
+ GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+}
+
static void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
Location in = locations->InAt(0);
Location out = locations->Out();
GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetVIXLAssembler());
}
+static void GenNumberOfLeadingZeros(LocationSummary* locations,
+ Primitive::Type type,
+ vixl::MacroAssembler* masm) {
+ DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+ Location in = locations->InAt(0);
+ Location out = locations->Out();
+
+ __ Clz(RegisterFrom(out, type), RegisterFrom(in, type));
+}
+
+void IntrinsicLocationsBuilderARM64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
+ GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler());
+}
+
+void IntrinsicLocationsBuilderARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
+ GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
+}
+
static void GenReverse(LocationSummary* locations,
Primitive::Type type,
vixl::MacroAssembler* masm) {
V(FloatIntBitsToFloat, kStatic) \
V(IntegerReverse, kStatic) \
V(IntegerReverseBytes, kStatic) \
+ V(IntegerNumberOfLeadingZeros, kStatic) \
V(LongReverse, kStatic) \
V(LongReverseBytes, kStatic) \
+ V(LongNumberOfLeadingZeros, kStatic) \
V(ShortReverseBytes, kStatic) \
V(MathAbsDouble, kStatic) \
V(MathAbsFloat, kStatic) \
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros)
+UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros)
#undef UNIMPLEMENTED_INTRINSIC
UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros)
+UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros)
#undef UNIMPLEMENTED_INTRINSIC
__ GetAdjustedPosition(label.Position()));
}
+TEST_F(AssemblerThumb2Test, Clz) {
+ __ clz(arm::R0, arm::R1);
+
+ const char* expected = "clz r0, r1\n";
+
+ DriverStr(expected, "clz");
+}
+
} // namespace art
} // else unknown instruction
break;
}
+ case 0x2B: { // 0101011
+ // CLZ - 111 11 0101011 mmmm 1111 dddd 1000 mmmm
+ if ((instr & 0xf0f0) == 0xf080) {
+ opcode << "clz";
+ ArmRegister Rm(instr, 0);
+ ArmRegister Rd(instr, 8);
+ args << Rd << ", " << Rm;
+ ArmRegister Rm2(instr, 16);
+ if (Rm.r != Rm2.r || Rm.r == 13 || Rm.r == 15 || Rd.r == 13 || Rd.r == 15) {
+ args << " (UNPREDICTABLE)";
+ }
+ }
+ break;
+ }
default: // more formats
if ((op2 >> 4) == 2) { // 010xxxx
// data processing (register)
kIntrinsicFloatCvt,
kIntrinsicReverseBits,
kIntrinsicReverseBytes,
+ kIntrinsicNumberOfLeadingZeros,
kIntrinsicAbsInt,
kIntrinsicAbsLong,
kIntrinsicAbsFloat,
test_Long_reverseBytes();
test_Integer_reverse();
test_Long_reverse();
+ test_Integer_numberOfLeadingZeros();
+ test_Long_numberOfLeadingZeros();
test_StrictMath_abs_I();
test_StrictMath_abs_J();
test_StrictMath_min_I();
return (r1 / i1) + (r2 / i2) + i3 + i4 + i5 + i6 + i7 + i8;
}
+ public static void test_Integer_numberOfLeadingZeros() {
+ Assert.assertEquals(Integer.numberOfLeadingZeros(0), Integer.SIZE);
+ for (int i = 0; i < Integer.SIZE; i++) {
+ Assert.assertEquals(Integer.numberOfLeadingZeros(1 << i), Integer.SIZE - 1 - i);
+ Assert.assertEquals(Integer.numberOfLeadingZeros((1 << i) | 1), Integer.SIZE - 1 - i);
+ Assert.assertEquals(Integer.numberOfLeadingZeros(0xFFFFFFFF >>> i), i);
+ }
+ }
+
+ public static void test_Long_numberOfLeadingZeros() {
+ Assert.assertEquals(Long.numberOfLeadingZeros(0L), Long.SIZE);
+ for (int i = 0; i < Long.SIZE; i++) {
+ Assert.assertEquals(Long.numberOfLeadingZeros(1L << i), Long.SIZE - 1 - i);
+ Assert.assertEquals(Long.numberOfLeadingZeros((1L << i) | 1L), Long.SIZE - 1 - i);
+ Assert.assertEquals(Long.numberOfLeadingZeros(0xFFFFFFFFFFFFFFFFL >>> i), i);
+ }
+ }
+
static Object runtime;
static Method address_of;
static Method new_non_movable_array;