From: haitao.feng@intel.com Date: Thu, 24 Oct 2013 02:12:51 +0000 (+0000) Subject: Introduce xchgl, orl, roll, subl, testl and xorl into X64 assembler X-Git-Tag: upstream/4.7.83~11978 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=29bb0767704d9d920eb3a439cb98f10b80ef9068;p=platform%2Fupstream%2Fv8.git Introduce xchgl, orl, roll, subl, testl and xorl into X64 assembler R=danno@chromium.org Review URL: https://codereview.chromium.org/26780004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17352 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 135117d..9fe7b83 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -1897,7 +1897,7 @@ void Assembler::shrd(Register dst, Register src) { } -void Assembler::xchg(Register dst, Register src) { +void Assembler::xchgq(Register dst, Register src) { EnsureSpace ensure_space(this); if (src.is(rax) || dst.is(rax)) { // Single-byte encoding Register other = src.is(rax) ? dst : src; @@ -1915,6 +1915,24 @@ void Assembler::xchg(Register dst, Register src) { } +void Assembler::xchgl(Register dst, Register src) { + EnsureSpace ensure_space(this); + if (src.is(rax) || dst.is(rax)) { // Single-byte encoding + Register other = src.is(rax) ? dst : src; + emit_optional_rex_32(other); + emit(0x90 | other.low_bits()); + } else if (dst.low_bits() == 4) { + emit_optional_rex_32(dst, src); + emit(0x87); + emit_modrm(dst, src); + } else { + emit_optional_rex_32(src, dst); + emit(0x87); + emit_modrm(src, dst); + } +} + + void Assembler::store_rax(void* dst, RelocInfo::Mode mode) { EnsureSpace ensure_space(this); emit(0x48); // REX.W @@ -2033,6 +2051,14 @@ void Assembler::testl(const Operand& op, Immediate mask) { } +void Assembler::testl(const Operand& op, Register reg) { + EnsureSpace ensure_space(this); + emit_optional_rex_32(reg, op); + emit(0x85); + emit_operand(reg, op); +} + + void Assembler::testq(const Operand& op, Register reg) { EnsureSpace ensure_space(this); emit_rex_64(reg, op); diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index f462b7e..c715bce 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -755,7 +755,8 @@ class Assembler : public AssemblerBase { void cmovl(Condition cc, Register dst, const Operand& src); // Exchange two registers - void xchg(Register dst, Register src); + void xchgq(Register dst, Register src); + void xchgl(Register dst, Register src); // Arithmetics void addl(Register dst, Register src) { @@ -990,6 +991,10 @@ class Assembler : public AssemblerBase { arithmetic_op(0x09, src, dst); } + void orl(const Operand& dst, Register src) { + arithmetic_op_32(0x09, src, dst); + } + void or_(Register dst, Immediate src) { immediate_arithmetic_op(0x1, dst, src); } @@ -1015,6 +1020,10 @@ class Assembler : public AssemblerBase { shift(dst, imm8, 0x0); } + void roll(Register dst, Immediate imm8) { + shift_32(dst, imm8, 0x0); + } + void rcr(Register dst, Immediate imm8) { shift(dst, imm8, 0x3); } @@ -1122,6 +1131,10 @@ class Assembler : public AssemblerBase { arithmetic_op_32(0x2B, dst, src); } + void subl(const Operand& dst, Register src) { + arithmetic_op_32(0x29, src, dst); + } + void subl(const Operand& dst, Immediate src) { immediate_arithmetic_op_32(0x5, dst, src); } @@ -1140,6 +1153,7 @@ class Assembler : public AssemblerBase { void testb(const Operand& op, Register reg); void testl(Register dst, Register src); void testl(Register reg, Immediate mask); + void testl(const Operand& op, Register reg); void testl(const Operand& op, Immediate mask); void testq(const Operand& op, Register reg); void testq(Register dst, Register src); @@ -1165,6 +1179,10 @@ class Assembler : public AssemblerBase { immediate_arithmetic_op_32(0x6, dst, src); } + void xorl(const Operand& dst, Register src) { + arithmetic_op_32(0x31, src, dst); + } + void xorl(const Operand& dst, Immediate src) { immediate_arithmetic_op_32(0x6, dst, src); } diff --git a/src/x64/lithium-gap-resolver-x64.cc b/src/x64/lithium-gap-resolver-x64.cc index 6d07db6..8d1c2a2 100644 --- a/src/x64/lithium-gap-resolver-x64.cc +++ b/src/x64/lithium-gap-resolver-x64.cc @@ -262,7 +262,7 @@ void LGapResolver::EmitSwap(int index) { // Swap two general-purpose registers. Register src = cgen_->ToRegister(source); Register dst = cgen_->ToRegister(destination); - __ xchg(dst, src); + __ xchgq(dst, src); } else if ((source->IsRegister() && destination->IsStackSlot()) || (source->IsStackSlot() && destination->IsRegister())) { diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc index ce258ba..cd1ed28 100644 --- a/test/cctest/test-assembler-x64.cc +++ b/test/cctest/test-assembler-x64.cc @@ -51,6 +51,8 @@ typedef int (*F0)(); typedef int (*F1)(int64_t x); typedef int (*F2)(int64_t x, int64_t y); typedef int (*F3)(double x); +typedef int64_t (*F4)(int64_t* x, int64_t* y); +typedef int64_t (*F5)(int64_t x); #ifdef _WIN64 static const Register arg1 = rcx; @@ -167,6 +169,157 @@ TEST(AssemblerX64ImulOperation) { } +TEST(AssemblerX64XchglOperations) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + Assembler assm(CcTest::i_isolate(), buffer, static_cast(actual_size)); + + __ movq(rax, Operand(arg1, 0)); + __ movq(rbx, Operand(arg2, 0)); + __ xchgl(rax, rbx); + __ movq(Operand(arg1, 0), rax); + __ movq(Operand(arg2, 0), rbx); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + // Call the function from C++. + int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); + int64_t right = V8_2PART_UINT64_C(0x30000000, 40000000); + int64_t result = FUNCTION_CAST(buffer)(&left, &right); + CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 40000000), left); + CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 20000000), right); + USE(result); +} + + +TEST(AssemblerX64OrlOperations) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + Assembler assm(CcTest::i_isolate(), buffer, static_cast(actual_size)); + + __ movq(rax, Operand(arg2, 0)); + __ orl(Operand(arg1, 0), rax); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + // Call the function from C++. + int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); + int64_t right = V8_2PART_UINT64_C(0x30000000, 40000000); + int64_t result = FUNCTION_CAST(buffer)(&left, &right); + CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 60000000), left); + USE(result); +} + + +TEST(AssemblerX64RollOperations) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + Assembler assm(CcTest::i_isolate(), buffer, static_cast(actual_size)); + + __ movq(rax, arg1); + __ roll(rax, Immediate(1)); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + // Call the function from C++. + int64_t src = V8_2PART_UINT64_C(0x10000000, C0000000); + int64_t result = FUNCTION_CAST(buffer)(src); + CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 80000001), result); +} + + +TEST(AssemblerX64SublOperations) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + Assembler assm(CcTest::i_isolate(), buffer, static_cast(actual_size)); + + __ movq(rax, Operand(arg2, 0)); + __ subl(Operand(arg1, 0), rax); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + // Call the function from C++. + int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); + int64_t right = V8_2PART_UINT64_C(0x30000000, 40000000); + int64_t result = FUNCTION_CAST(buffer)(&left, &right); + CHECK_EQ(V8_2PART_UINT64_C(0x10000000, e0000000), left); + USE(result); +} + + +TEST(AssemblerX64TestlOperations) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + Assembler assm(CcTest::i_isolate(), buffer, static_cast(actual_size)); + + // Set rax with the ZF flag of the testl instruction. + Label done; + __ movq(rax, Immediate(1)); + __ movq(rbx, Operand(arg2, 0)); + __ testl(Operand(arg1, 0), rbx); + __ j(zero, &done, Label::kNear); + __ movq(rax, Immediate(0)); + __ bind(&done); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + // Call the function from C++. + int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); + int64_t right = V8_2PART_UINT64_C(0x30000000, 00000000); + int64_t result = FUNCTION_CAST(buffer)(&left, &right); + CHECK_EQ(static_cast(1), result); +} + + +TEST(AssemblerX64XorlOperations) { + // Allocate an executable page of memory. + size_t actual_size; + byte* buffer = static_cast(OS::Allocate(Assembler::kMinimalBufferSize, + &actual_size, + true)); + CHECK(buffer); + Assembler assm(CcTest::i_isolate(), buffer, static_cast(actual_size)); + + __ movq(rax, Operand(arg2, 0)); + __ xorl(Operand(arg1, 0), rax); + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + // Call the function from C++. + int64_t left = V8_2PART_UINT64_C(0x10000000, 20000000); + int64_t right = V8_2PART_UINT64_C(0x30000000, 60000000); + int64_t result = FUNCTION_CAST(buffer)(&left, &right); + CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 40000000), left); + USE(result); +} + + TEST(AssemblerX64MemoryOperands) { // Allocate an executable page of memory. size_t actual_size;