diff options
| author | 2020-08-27 16:26:17 +0100 | |
|---|---|---|
| committer | 2020-09-25 09:16:33 +0000 | |
| commit | a3bd4ec050e10fbfb6df0fe024bc6f3851bcc326 (patch) | |
| tree | 8a373f87b05b3580f564bd8561bf0dd4ebb9161e | |
| parent | b0f405e1482df602fc57ee2ed4434456c4dc2555 (diff) | |
Introduce Long.divideUnsigned() intrinsic on ARM64.
Extends the 082-inline-execute test and reorders
divideUnsigned intrinsic code before VarHandle code.
Test: 082-inline-execute.
Test: testrunner.py --target --optimizing --64
Bug: 156736938
Change-Id: I8acf3db184da30640aff36cf02570ae0c6d2b88c
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 59 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 1 | ||||
| -rw-r--r-- | runtime/image.cc | 2 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_intrinsics.cc | 1 | ||||
| -rw-r--r-- | runtime/intrinsics_list.h | 1 | ||||
| -rw-r--r-- | test/082-inline-execute/src/Main.java | 35 |
8 files changed, 78 insertions, 23 deletions
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index b02b32ea8c..a547551b7f 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -3342,6 +3342,43 @@ void IntrinsicCodeGeneratorARM64::VisitFP16LessEquals(HInvoke* invoke) { GenerateFP16Compare(invoke, codegen_, masm, ls); } +static void GenerateDivideUnsigned(HInvoke* invoke, CodeGeneratorARM64* codegen) { + LocationSummary* locations = invoke->GetLocations(); + MacroAssembler* masm = codegen->GetVIXLAssembler(); + DataType::Type type = invoke->GetType(); + DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64); + + Register dividend = RegisterFrom(locations->InAt(0), type); + Register divisor = RegisterFrom(locations->InAt(1), type); + Register out = RegisterFrom(locations->Out(), type); + + // Check if divisor is zero, bail to managed implementation to handle. + SlowPathCodeARM64* slow_path = + new (codegen->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke); + codegen->AddSlowPath(slow_path); + __ Cbz(divisor, slow_path->GetEntryLabel()); + + __ Udiv(out, dividend, divisor); + + __ Bind(slow_path->GetExitLabel()); +} + +void IntrinsicLocationsBuilderARM64::VisitIntegerDivideUnsigned(HInvoke* invoke) { + CreateIntIntToIntSlowPathCallLocations(allocator_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitIntegerDivideUnsigned(HInvoke* invoke) { + GenerateDivideUnsigned(invoke, codegen_); +} + +void IntrinsicLocationsBuilderARM64::VisitLongDivideUnsigned(HInvoke* invoke) { + CreateIntIntToIntSlowPathCallLocations(allocator_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitLongDivideUnsigned(HInvoke* invoke) { + GenerateDivideUnsigned(invoke, codegen_); +} + // Check access mode and the primitive type from VarHandle.varType. // The `var_type_no_rb`, if valid, shall be filled with VarHandle.varType read without read barrier. static void GenerateVarHandleAccessModeAndVarTypeChecks(HInvoke* invoke, @@ -3709,28 +3746,6 @@ void IntrinsicCodeGeneratorARM64::VisitVarHandleSet(HInvoke* invoke) { __ Bind(slow_path->GetExitLabel()); } -void IntrinsicLocationsBuilderARM64::VisitIntegerDivideUnsigned(HInvoke* invoke) { - CreateIntIntToIntSlowPathCallLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitIntegerDivideUnsigned(HInvoke* invoke) { - LocationSummary* locations = invoke->GetLocations(); - MacroAssembler* masm = GetVIXLAssembler(); - Register dividend = WRegisterFrom(locations->InAt(0)); - Register divisor = WRegisterFrom(locations->InAt(1)); - Register out = WRegisterFrom(locations->Out()); - - // Check if divisor is zero, bail to managed implementation to handle. - SlowPathCodeARM64* slow_path = - new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke); - codegen_->AddSlowPath(slow_path); - __ Cbz(divisor, slow_path->GetEntryLabel()); - - __ Udiv(out, dividend, divisor); - - __ Bind(slow_path->GetExitLabel()); -} - UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index b8df06093b..19f55e1542 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -3018,6 +3018,7 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerDivideUnsigned) +UNIMPLEMENTED_INTRINSIC(ARMVIXL, LongDivideUnsigned) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32UpdateBytes) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32UpdateByteBuffer) diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 87880d707a..045cacd8c7 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -4501,6 +4501,7 @@ UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(X86, LongDivideUnsigned) UNIMPLEMENTED_INTRINSIC(X86, CRC32Update) UNIMPLEMENTED_INTRINSIC(X86, CRC32UpdateBytes) UNIMPLEMENTED_INTRINSIC(X86, CRC32UpdateByteBuffer) diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index eaa3abe380..7ebc632f2b 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2735,6 +2735,7 @@ UNIMPLEMENTED_INTRINSIC(X86_64, FP16Greater) UNIMPLEMENTED_INTRINSIC(X86_64, FP16GreaterEquals) UNIMPLEMENTED_INTRINSIC(X86_64, FP16Less) UNIMPLEMENTED_INTRINSIC(X86_64, FP16LessEquals) +UNIMPLEMENTED_INTRINSIC(X86_64, LongDivideUnsigned) UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOfAfter); diff --git a/runtime/image.cc b/runtime/image.cc index 13c9bd0d46..d91106a8ac 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -29,7 +29,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '8', '6', '\0' }; // Integer.divideUnsigned +const uint8_t ImageHeader::kImageVersion[] = { '0', '8', '7', '\0' }; // Long.divideUnsigned ImageHeader::ImageHeader(uint32_t image_reservation_size, uint32_t component_count, diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc index ced4132472..c174ede962 100644 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ b/runtime/interpreter/interpreter_intrinsics.cc @@ -440,6 +440,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, UNIMPLEMENTED_CASE(FloatIsNaN /* (F)Z */) UNIMPLEMENTED_CASE(FloatIntBitsToFloat /* (I)F */) UNIMPLEMENTED_CASE(IntegerDivideUnsigned /* (II)I */) + UNIMPLEMENTED_CASE(LongDivideUnsigned /* (JJ)J */) INTRINSIC_CASE(IntegerReverse) INTRINSIC_CASE(IntegerReverseBytes) INTRINSIC_CASE(IntegerBitCount) diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h index edfa15985f..be1ca46803 100644 --- a/runtime/intrinsics_list.h +++ b/runtime/intrinsics_list.h @@ -111,6 +111,7 @@ V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "reverseBytes", "(J)J") \ V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "bitCount", "(J)I") \ V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "compare", "(JJ)I") \ + V(LongDivideUnsigned, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kCanThrow, "Ljava/lang/Long;", "divideUnsigned", "(JJ)J") \ V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "highestOneBit", "(J)J") \ V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "lowestOneBit", "(J)J") \ V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "numberOfLeadingZeros", "(J)I") \ diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java index b565985ea7..5597947cfc 100644 --- a/test/082-inline-execute/src/Main.java +++ b/test/082-inline-execute/src/Main.java @@ -83,6 +83,7 @@ public class Main { test_Memory_pokeInt(); test_Memory_pokeLong(); test_Integer_divideUnsigned(); + test_Long_divideUnsigned(); test_Integer_numberOfTrailingZeros(); test_Long_numberOfTrailingZeros(); test_Integer_rotateRight(); @@ -1402,6 +1403,40 @@ public class Main { } } + + private static final long BIG_LONG_VALUE = 739287620162442240L; + + public static void test_Long_divideUnsigned() { + Assert.assertEquals(Long.divideUnsigned(100L, 10L), 10L); + Assert.assertEquals(Long.divideUnsigned(100L, 1L), 100L); + Assert.assertEquals(Long.divideUnsigned(1024L, 128L), 8L); + Assert.assertEquals(Long.divideUnsigned(12345678L, 264L), 46763L); + Assert.assertEquals(Long.divideUnsigned(13L, 5L), 2L); + Assert.assertEquals(Long.divideUnsigned(-2L, 2L), Long.MAX_VALUE); + Assert.assertEquals(Long.divideUnsigned(-1L, 2L), Long.MAX_VALUE); + Assert.assertEquals(Long.divideUnsigned(100000L, -1L), 0L); + Assert.assertEquals(Long.divideUnsigned(Long.MAX_VALUE, -1L), 0L); + Assert.assertEquals(Long.divideUnsigned(-2L, -1L), 0L); + Assert.assertEquals(Long.divideUnsigned(-1L, -2L), 1L); + Assert.assertEquals(Long.divideUnsigned(-173448L, 13L), 1418980313362259859L); + Assert.assertEquals(Long.divideUnsigned(Long.MIN_VALUE, 2L), (1L << 62)); + Assert.assertEquals(Long.divideUnsigned(-1L, Long.MIN_VALUE), 1L); + Assert.assertEquals(Long.divideUnsigned(Long.MAX_VALUE, Long.MIN_VALUE), 0L); + Assert.assertEquals(Long.divideUnsigned(Long.MIN_VALUE, Long.MAX_VALUE), 1L); + Assert.assertEquals(Long.divideUnsigned(Long.MAX_VALUE, 1L), Long.MAX_VALUE); + Assert.assertEquals(Long.divideUnsigned(Long.MIN_VALUE, 1L), Long.MIN_VALUE); + Assert.assertEquals(Long.divideUnsigned(BIG_LONG_VALUE, BIG_LONG_VALUE), 1L); + Assert.assertEquals(Long.divideUnsigned(BIG_LONG_VALUE, 1L), BIG_LONG_VALUE); + Assert.assertEquals(Long.divideUnsigned(BIG_LONG_VALUE, 1024L), 721960566564885L); + Assert.assertEquals(Long.divideUnsigned(BIG_LONG_VALUE, 0x1FFFFFFFFL), 86064406L); + + try { + Long.divideUnsigned(1L, 0L); + Assert.fail("Unreachable"); + } catch (ArithmeticException expected) { + } + } + public static void test_Integer_numberOfLeadingZeros() { Assert.assertEquals(Integer.numberOfLeadingZeros(0), Integer.SIZE); Assert.assertEquals(Integer.numberOfLeadingZeros(1), Integer.SIZE - 1); |