diff options
author | 2020-07-07 14:28:56 +0000 | |
---|---|---|
committer | 2020-07-09 09:44:58 +0000 | |
commit | dc787f488ce151478af1149c04a10b21b2b9fc6e (patch) | |
tree | 38d402813c9c3f541630255e9f9890a9c6842c45 | |
parent | 9a09e7cf11b2653e6da2b179ac03bc6bb71c81e3 (diff) |
Make Integer.divideUnsigned intrinsic for x86.
Bug: 156736938
Test: Added a test to 082-inline-execute.
Test: art/test.py --host --32 -r -t 082-inline-execute
Change-Id: Id516126fce10f2fa52b95c1b2b107ca7bf45e347
-rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 36 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 1 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 7 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.h | 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 | 26 |
10 files changed, 76 insertions, 1 deletions
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 93a99b1bfc..4b495e7fc0 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -3328,6 +3328,7 @@ void IntrinsicCodeGeneratorARM64::VisitFP16LessEquals(HInvoke* invoke) { } UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) +UNIMPLEMENTED_INTRINSIC(ARM64, IntegerDivideUnsigned) UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 450af5513b..c5284c5978 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -3017,6 +3017,7 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent) +UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerDivideUnsigned) 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 2dad2f1378..15ac627d73 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -3027,6 +3027,42 @@ void IntrinsicLocationsBuilderX86::VisitReachabilityFence(HInvoke* invoke) { void IntrinsicCodeGeneratorX86::VisitReachabilityFence(HInvoke* invoke ATTRIBUTE_UNUSED) { } +void IntrinsicLocationsBuilderX86::VisitIntegerDivideUnsigned(HInvoke* invoke) { + LocationSummary* locations = new (allocator_) LocationSummary(invoke, + LocationSummary::kCallOnSlowPath, + kIntrinsified); + locations->SetInAt(0, Location::RegisterLocation(EAX)); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + // Intel uses edx:eax as the dividend. + locations->AddTemp(Location::RegisterLocation(EDX)); +} + +void IntrinsicCodeGeneratorX86::VisitIntegerDivideUnsigned(HInvoke* invoke) { + X86Assembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + Location out = locations->Out(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + Register edx = locations->GetTemp(0).AsRegister<Register>(); + Register second_reg = second.AsRegister<Register>(); + + DCHECK_EQ(EAX, first.AsRegister<Register>()); + DCHECK_EQ(EAX, out.AsRegister<Register>()); + DCHECK_EQ(EDX, edx); + + // Check if divisor is zero, bail to managed implementation to handle. + __ testl(second_reg, second_reg); + SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke); + codegen_->AddSlowPath(slow_path); + __ j(kEqual, slow_path->GetEntryLabel()); + + __ xorl(edx, edx); + __ divl(second_reg); + + __ Bind(slow_path->GetExitLabel()); +} + UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble) UNIMPLEMENTED_INTRINSIC(X86, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite) diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index af3fd76ce6..a5832bb749 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2686,6 +2686,7 @@ void IntrinsicCodeGeneratorX86_64::VisitReachabilityFence(HInvoke* invoke ATTRIB UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(X86_64, IntegerDivideUnsigned) UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update) UNIMPLEMENTED_INTRINSIC(X86_64, CRC32UpdateBytes) diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 3280d0b316..c86b1cd522 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -3166,6 +3166,13 @@ void X86Assembler::idivl(Register reg) { } +void X86Assembler::divl(Register reg) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0xF7); + EmitUint8(0xF0 | reg); +} + + void X86Assembler::imull(Register dst, Register src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x0F); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index 27fde26c80..522d57a63d 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -723,6 +723,7 @@ class X86Assembler final : public Assembler { void cdq(); void idivl(Register reg); + void divl(Register reg); void imull(Register dst, Register src); void imull(Register reg, const Immediate& imm); diff --git a/runtime/image.cc b/runtime/image.cc index 782c0c6dd9..13c9bd0d46 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', '5', '\0' }; // Single-image. +const uint8_t ImageHeader::kImageVersion[] = { '0', '8', '6', '\0' }; // Integer.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 63bd9673e6..ced4132472 100644 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ b/runtime/interpreter/interpreter_intrinsics.cc @@ -439,6 +439,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, UNIMPLEMENTED_CASE(FloatIsInfinite /* (F)Z */) UNIMPLEMENTED_CASE(FloatIsNaN /* (F)Z */) UNIMPLEMENTED_CASE(FloatIntBitsToFloat /* (I)F */) + UNIMPLEMENTED_CASE(IntegerDivideUnsigned /* (II)I */) INTRINSIC_CASE(IntegerReverse) INTRINSIC_CASE(IntegerReverseBytes) INTRINSIC_CASE(IntegerBitCount) diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h index fc4734ef74..edfa15985f 100644 --- a/runtime/intrinsics_list.h +++ b/runtime/intrinsics_list.h @@ -99,6 +99,7 @@ V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "reverseBytes", "(I)I") \ V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "bitCount", "(I)I") \ V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "compare", "(II)I") \ + V(IntegerDivideUnsigned, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kCanThrow, "Ljava/lang/Integer;", "divideUnsigned", "(II)I") \ V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "highestOneBit", "(I)I") \ V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "lowestOneBit", "(I)I") \ V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "numberOfLeadingZeros", "(I)I") \ diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java index 072f0e68ee..81afee1caf 100644 --- a/test/082-inline-execute/src/Main.java +++ b/test/082-inline-execute/src/Main.java @@ -82,6 +82,7 @@ public class Main { test_Memory_pokeShort(); test_Memory_pokeInt(); test_Memory_pokeLong(); + test_Integer_divideUnsigned(); test_Integer_numberOfTrailingZeros(); test_Long_numberOfTrailingZeros(); test_Integer_rotateRight(); @@ -1376,6 +1377,31 @@ public class Main { return 0; } + public static void test_Integer_divideUnsigned() { + Assert.assertEquals(Integer.divideUnsigned(100, 10), 10); + Assert.assertEquals(Integer.divideUnsigned(100, 1), 100); + Assert.assertEquals(Integer.divideUnsigned(1024, 128), 8); + Assert.assertEquals(Integer.divideUnsigned(12345678, 264), 46763); + Assert.assertEquals(Integer.divideUnsigned(13, 5), 2); + Assert.assertEquals(Integer.divideUnsigned(-2, 2), Integer.MAX_VALUE); + Assert.assertEquals(Integer.divideUnsigned(-1, 2), Integer.MAX_VALUE); + Assert.assertEquals(Integer.divideUnsigned(100000, -1), 0); + Assert.assertEquals(Integer.divideUnsigned(Integer.MAX_VALUE, -1), 0); + Assert.assertEquals(Integer.divideUnsigned(-2, -1), 0); + Assert.assertEquals(Integer.divideUnsigned(-173448, 13), 330368757); + Assert.assertEquals(Integer.divideUnsigned(Integer.MIN_VALUE, 2), (1 << 30)); + Assert.assertEquals(Integer.divideUnsigned(-1, Integer.MIN_VALUE), 1); + Assert.assertEquals(Integer.divideUnsigned(Integer.MAX_VALUE, Integer.MIN_VALUE), 0); + Assert.assertEquals(Integer.divideUnsigned(Integer.MIN_VALUE, Integer.MAX_VALUE), 1); + + try { + Integer.divideUnsigned(1, 0); + } catch (ArithmeticException e) { + return; + } + Assert.fail("Unreachable"); + } + public static void test_Integer_numberOfLeadingZeros() { Assert.assertEquals(Integer.numberOfLeadingZeros(0), Integer.SIZE); Assert.assertEquals(Integer.numberOfLeadingZeros(1), Integer.SIZE - 1); |