diff options
-rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 47 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.h | 10 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86_test.cc | 27 |
3 files changed, 72 insertions, 12 deletions
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index adc7bcc0f4..b6708de81c 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -2887,9 +2887,22 @@ void X86Assembler::fprem() { } -void X86Assembler::xchgb(Register reg, const Address& address) { - // For testing purpose - xchgb(static_cast<ByteRegister>(reg), address); +bool X86Assembler::try_xchg_eax(Register dst, Register src) { + if (src != EAX && dst != EAX) { + return false; + } + if (dst == EAX) { + std::swap(src, dst); + } + EmitUint8(0x90 + dst); + return true; +} + + +void X86Assembler::xchgb(ByteRegister dst, ByteRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x86); + EmitRegisterOperand(dst, src); } @@ -2900,6 +2913,29 @@ void X86Assembler::xchgb(ByteRegister reg, const Address& address) { } +void X86Assembler::xchgb(Register dst, Register src) { + xchgb(static_cast<ByteRegister>(dst), static_cast<ByteRegister>(src)); +} + + +void X86Assembler::xchgb(Register reg, const Address& address) { + xchgb(static_cast<ByteRegister>(reg), address); +} + + +void X86Assembler::xchgw(Register dst, Register src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOperandSizeOverride(); + if (try_xchg_eax(dst, src)) { + // A short version for AX. + return; + } + // General case. + EmitUint8(0x87); + EmitRegisterOperand(dst, src); +} + + void X86Assembler::xchgw(Register reg, const Address& address) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitOperandSizeOverride(); @@ -2910,6 +2946,11 @@ void X86Assembler::xchgw(Register reg, const Address& address) { void X86Assembler::xchgl(Register dst, Register src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); + if (try_xchg_eax(dst, src)) { + // A short version for EAX. + return; + } + // General case. EmitUint8(0x87); EmitRegisterOperand(dst, src); } diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index db92a80a4e..f6e7fbc8cd 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -736,8 +736,14 @@ class X86Assembler final : public Assembler { void fptan(); void fprem(); + void xchgb(ByteRegister dst, ByteRegister src); void xchgb(ByteRegister reg, const Address& address); + + // Wrappers for `xchgb` that accept `Register` instead of `ByteRegister` (used for testing). + void xchgb(Register dst, Register src); void xchgb(Register reg, const Address& address); + + void xchgw(Register dst, Register src); void xchgw(Register reg, const Address& address); void xchgl(Register dst, Register src); @@ -1044,6 +1050,10 @@ class X86Assembler final : public Assembler { uint8_t EmitVexPrefixByteTwo(bool W, int SET_VEX_L, int SET_VEX_PP); + + // Helper function to emit a shorter variant of XCHG for when at least one operand is EAX/AX. + bool try_xchg_eax(Register dst, Register src); + ConstantArea constant_area_; bool has_AVX_; // x86 256bit SIMD AVX. bool has_AVX2_; // x86 256bit SIMD AVX 2.0. diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index b7b1d33a74..92ce788f11 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -331,19 +331,28 @@ TEST_F(AssemblerX86Test, LoadLongConstant) { DriverStr(expected, "LoadLongConstant"); } -TEST_F(AssemblerX86Test, Xchgb) { - DriverStr(RepeatwA(&x86::X86Assembler::xchgb, - "xchgb {mem}, %{reg}"), "xchgb"); +TEST_F(AssemblerX86Test, XchgbReg) { + DriverStr(Repeatww(&x86::X86Assembler::xchgb, "xchgb %{reg2}, %{reg1}"), "xchgb"); } -TEST_F(AssemblerX86Test, Xchgw) { - DriverStr(RepeatrA(&x86::X86Assembler::xchgw, - "xchgw {mem}, %{reg}"), "xchgw"); +TEST_F(AssemblerX86Test, XchgbMem) { + DriverStr(RepeatwA(&x86::X86Assembler::xchgb, "xchgb {mem}, %{reg}"), "xchgb"); } -TEST_F(AssemblerX86Test, Xchgl) { - DriverStr(RepeatRA(&x86::X86Assembler::xchgl, - "xchgl {mem}, %{reg}"), "xchgl"); +TEST_F(AssemblerX86Test, XchgwReg) { + DriverStr(Repeatrr(&x86::X86Assembler::xchgw, "xchgw %{reg2}, %{reg1}"), "xchgw"); +} + +TEST_F(AssemblerX86Test, XchgwMem) { + DriverStr(RepeatrA(&x86::X86Assembler::xchgw, "xchgw {mem}, %{reg}"), "xchgw"); +} + +TEST_F(AssemblerX86Test, XchglReg) { + DriverStr(RepeatRR(&x86::X86Assembler::xchgl, "xchgl %{reg2}, %{reg1}"), "xchgl"); +} + +TEST_F(AssemblerX86Test, XchglMem) { + DriverStr(RepeatRA(&x86::X86Assembler::xchgl, "xchgl {mem}, %{reg}"), "xchgl"); } TEST_F(AssemblerX86Test, Cmpxchgb) { |