X86: Implement VarHandle.getAndAdd intrinsic
This commit implements VarHandle getAndAdd intrinsic. This also implied
adding xadd instruction and tests for it.
Test: art/test.py --host -r -t 712-varhandle-invocation --32
Test: m test-art-host-gtest
Bug: 65872996
Change-Id: I84dd95ba6464c8a73ace03a13817147c7099677a
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index c8ea229..da53138 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -3677,6 +3677,29 @@
}
+void X86Assembler::xaddb(const Address& address, ByteRegister reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC0);
+ EmitOperand(reg, address);
+}
+
+void X86Assembler::xaddw(const Address& address, Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOperandSizeOverride();
+ EmitUint8(0x0F);
+ EmitUint8(0xC1);
+ EmitOperand(reg, address);
+}
+
+void X86Assembler::xaddl(const Address& address, Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC1);
+ EmitOperand(reg, address);
+}
+
+
void X86Assembler::mfence() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index c546927..1c4f826 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -817,6 +817,10 @@
void cmpxchgl(const Address& address, Register reg);
void cmpxchg8b(const Address& address);
+ void xaddb(const Address& address, ByteRegister reg);
+ void xaddw(const Address& address, Register reg);
+ void xaddl(const Address& address, Register reg);
+
void mfence();
X86Assembler* fs();
@@ -859,6 +863,30 @@
lock()->cmpxchg8b(address);
}
+ void LockXaddb(const Address& address, Register reg) {
+ // For testing purpose
+ lock()->xaddb(address, static_cast<ByteRegister>(reg));
+ }
+
+ void LockXaddb(const Address& address, ByteRegister reg) {
+ lock()->xaddb(address, reg);
+ }
+
+ void LockXaddw(const Address& address, Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ // We make sure that the operand size override bytecode is emited before the lock bytecode.
+ // We test against clang which enforces this bytecode order.
+ EmitOperandSizeOverride();
+ EmitUint8(0xF0);
+ EmitUint8(0x0F);
+ EmitUint8(0xC1);
+ EmitOperand(reg, address);
+ }
+
+ void LockXaddl(const Address& address, Register reg) {
+ lock()->xaddl(address, reg);
+ }
+
//
// Misc. functionality
//
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index d1c2cbe..ee0f8a1 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -351,6 +351,21 @@
"lock cmpxchg8b {mem}"), "lock_cmpxchg8b");
}
+TEST_F(AssemblerX86Test, LockXaddb) {
+ DriverStr(RepeatAw(&x86::X86Assembler::LockXaddb,
+ "lock xaddb %{reg}, {mem}"), "lock_xaddb");
+}
+
+TEST_F(AssemblerX86Test, LockXaddw) {
+ DriverStr(RepeatAr(&x86::X86Assembler::LockXaddw,
+ "lock xaddw %{reg}, {mem}"), "lock_xaddw");
+}
+
+TEST_F(AssemblerX86Test, LockXaddl) {
+ DriverStr(RepeatAR(&x86::X86Assembler::LockXaddl,
+ "lock xaddl %{reg}, {mem}"), "lock_xaddl");
+}
+
TEST_F(AssemblerX86Test, FPUIntegerLoadS) {
DriverStr(RepeatA(&x86::X86Assembler::filds, "fildl {mem}"), "fildd");
}