summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andra Danciu <andradanciu@google.com> 2020-07-07 14:28:56 +0000
committer Vladimir Marko <vmarko@google.com> 2020-07-09 09:44:58 +0000
commitdc787f488ce151478af1149c04a10b21b2b9fc6e (patch)
tree38d402813c9c3f541630255e9f9890a9c6842c45
parent9a09e7cf11b2653e6da2b179ac03bc6bb71c81e3 (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.cc1
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc1
-rw-r--r--compiler/optimizing/intrinsics_x86.cc36
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc1
-rw-r--r--compiler/utils/x86/assembler_x86.cc7
-rw-r--r--compiler/utils/x86/assembler_x86.h1
-rw-r--r--runtime/image.cc2
-rw-r--r--runtime/interpreter/interpreter_intrinsics.cc1
-rw-r--r--runtime/intrinsics_list.h1
-rw-r--r--test/082-inline-execute/src/Main.java26
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);