Commit a72e3525 authored by haitao.feng@intel.com's avatar haitao.feng@intel.com

Refactor the arithmetic instructions for x64

R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/214753002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20329 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent dae7ecbf
......@@ -467,24 +467,30 @@ void Assembler::emit_operand(int code, const Operand& adr) {
// Assembler Instruction implementations.
void Assembler::arithmetic_op(byte opcode, Register reg, const Operand& op) {
void Assembler::arithmetic_op(byte opcode,
Register reg,
const Operand& op,
int size) {
EnsureSpace ensure_space(this);
emit_rex_64(reg, op);
emit_rex(reg, op, size);
emit(opcode);
emit_operand(reg, op);
}
void Assembler::arithmetic_op(byte opcode, Register reg, Register rm_reg) {
void Assembler::arithmetic_op(byte opcode,
Register reg,
Register rm_reg,
int size) {
EnsureSpace ensure_space(this);
ASSERT((opcode & 0xC6) == 2);
if (rm_reg.low_bits() == 4) { // Forces SIB byte.
// Swap reg and rm_reg and change opcode operand order.
emit_rex_64(rm_reg, reg);
emit_rex(rm_reg, reg, size);
emit(opcode ^ 0x02);
emit_modrm(rm_reg, reg);
} else {
emit_rex_64(reg, rm_reg);
emit_rex(reg, rm_reg, size);
emit(opcode);
emit_modrm(reg, rm_reg);
}
......@@ -520,37 +526,45 @@ void Assembler::arithmetic_op_16(byte opcode,
}
void Assembler::arithmetic_op_32(byte opcode, Register reg, Register rm_reg) {
void Assembler::arithmetic_op_8(byte opcode, Register reg, const Operand& op) {
EnsureSpace ensure_space(this);
if (!reg.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(reg);
}
emit(opcode);
emit_operand(reg, op);
}
void Assembler::arithmetic_op_8(byte opcode, Register reg, Register rm_reg) {
EnsureSpace ensure_space(this);
ASSERT((opcode & 0xC6) == 2);
if (rm_reg.low_bits() == 4) { // Forces SIB byte.
if (rm_reg.low_bits() == 4) { // Forces SIB byte.
// Swap reg and rm_reg and change opcode operand order.
emit_optional_rex_32(rm_reg, reg);
emit(opcode ^ 0x02); // E.g. 0x03 -> 0x01 for ADD.
if (!rm_reg.is_byte_register() || !reg.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(rm_reg, reg);
}
emit(opcode ^ 0x02);
emit_modrm(rm_reg, reg);
} else {
emit_optional_rex_32(reg, rm_reg);
if (!reg.is_byte_register() || !rm_reg.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(reg, rm_reg);
}
emit(opcode);
emit_modrm(reg, rm_reg);
}
}
void Assembler::arithmetic_op_32(byte opcode,
Register reg,
const Operand& rm_reg) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(reg, rm_reg);
emit(opcode);
emit_operand(reg, rm_reg);
}
void Assembler::immediate_arithmetic_op(byte subcode,
Register dst,
Immediate src) {
Immediate src,
int size) {
EnsureSpace ensure_space(this);
emit_rex_64(dst);
emit_rex(dst, size);
if (is_int8(src.value_)) {
emit(0x83);
emit_modrm(subcode, dst);
......@@ -567,9 +581,10 @@ void Assembler::immediate_arithmetic_op(byte subcode,
void Assembler::immediate_arithmetic_op(byte subcode,
const Operand& dst,
Immediate src) {
Immediate src,
int size) {
EnsureSpace ensure_space(this);
emit_rex_64(dst);
emit_rex(dst, size);
if (is_int8(src.value_)) {
emit(0x83);
emit_operand(subcode, dst);
......@@ -621,43 +636,6 @@ void Assembler::immediate_arithmetic_op_16(byte subcode,
}
void Assembler::immediate_arithmetic_op_32(byte subcode,
Register dst,
Immediate src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(dst);
if (is_int8(src.value_)) {
emit(0x83);
emit_modrm(subcode, dst);
emit(src.value_);
} else if (dst.is(rax)) {
emit(0x05 | (subcode << 3));
emitl(src.value_);
} else {
emit(0x81);
emit_modrm(subcode, dst);
emitl(src.value_);
}
}
void Assembler::immediate_arithmetic_op_32(byte subcode,
const Operand& dst,
Immediate src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(dst);
if (is_int8(src.value_)) {
emit(0x83);
emit_operand(subcode, dst);
emit(src.value_);
} else {
emit(0x81);
emit_operand(subcode, dst);
emitl(src.value_);
}
}
void Assembler::immediate_arithmetic_op_8(byte subcode,
const Operand& dst,
Immediate src) {
......@@ -675,8 +653,8 @@ void Assembler::immediate_arithmetic_op_8(byte subcode,
Immediate src) {
EnsureSpace ensure_space(this);
if (!dst.is_byte_register()) {
// Use 64-bit mode byte registers.
emit_rex_64(dst);
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(dst);
}
ASSERT(is_int8(src.value_) || is_uint8(src.value_));
emit(0x80);
......
......@@ -692,6 +692,8 @@ class Assembler : public AssemblerBase {
// - Instructions on 64-bit (quadword) operands/registers use 'q'.
// - Instructions on operands/registers with pointer size use 'p'.
STATIC_ASSERT(kPointerSize == kInt64Size || kPointerSize == kInt32Size);
#define DECLARE_INSTRUCTION(instruction) \
template<class P1> \
void instruction##p(P1 p1) { \
......@@ -818,15 +820,15 @@ class Assembler : public AssemblerBase {
void cmpb_al(Immediate src);
void cmpb(Register dst, Register src) {
arithmetic_op(0x3A, dst, src);
arithmetic_op_8(0x3A, dst, src);
}
void cmpb(Register dst, const Operand& src) {
arithmetic_op(0x3A, dst, src);
arithmetic_op_8(0x3A, dst, src);
}
void cmpb(const Operand& dst, Register src) {
arithmetic_op(0x38, src, dst);
arithmetic_op_8(0x38, src, dst);
}
void cmpb(const Operand& dst, Immediate src) {
......@@ -1382,14 +1384,16 @@ class Assembler : public AssemblerBase {
// AND, OR, XOR, or CMP. The encodings of these operations are all
// similar, differing just in the opcode or in the reg field of the
// ModR/M byte.
void arithmetic_op_8(byte opcode, Register reg, Register rm_reg);
void arithmetic_op_8(byte opcode, Register reg, const Operand& rm_reg);
void arithmetic_op_16(byte opcode, Register reg, Register rm_reg);
void arithmetic_op_16(byte opcode, Register reg, const Operand& rm_reg);
void arithmetic_op_32(byte opcode, Register reg, Register rm_reg);
void arithmetic_op_32(byte opcode, Register reg, const Operand& rm_reg);
void arithmetic_op(byte opcode, Register reg, Register rm_reg);
void arithmetic_op(byte opcode, Register reg, const Operand& rm_reg);
void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src);
// Operate on operands/registers with pointer size, 32-bit or 64-bit size.
void arithmetic_op(byte opcode, Register reg, Register rm_reg, int size);
void arithmetic_op(byte opcode,
Register reg,
const Operand& rm_reg,
int size);
// Operate on a byte in memory or register.
void immediate_arithmetic_op_8(byte subcode,
Register dst,
......@@ -1404,13 +1408,15 @@ class Assembler : public AssemblerBase {
void immediate_arithmetic_op_16(byte subcode,
const Operand& dst,
Immediate src);
// Operate on a 32-bit word in memory or register.
void immediate_arithmetic_op_32(byte subcode,
Register dst,
Immediate src);
void immediate_arithmetic_op_32(byte subcode,
const Operand& dst,
Immediate src);
// Operate on operands/registers with pointer size, 32-bit or 64-bit size.
void immediate_arithmetic_op(byte subcode,
Register dst,
Immediate src,
int size);
void immediate_arithmetic_op(byte subcode,
const Operand& dst,
Immediate src,
int size);
// Emit machine code for a shift operation.
void shift(Register dst, Immediate shift_amount, int subcode, int size);
......@@ -1428,138 +1434,63 @@ class Assembler : public AssemblerBase {
// Arithmetics
void emit_add(Register dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x03, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x03, dst, src);
}
arithmetic_op(0x03, dst, src, size);
}
void emit_add(Register dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x0, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x0, dst, src);
}
immediate_arithmetic_op(0x0, dst, src, size);
}
void emit_add(Register dst, const Operand& src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x03, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x03, dst, src);
}
arithmetic_op(0x03, dst, src, size);
}
void emit_add(const Operand& dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x1, src, dst);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x1, src, dst);
}
arithmetic_op(0x1, src, dst, size);
}
void emit_add(const Operand& dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x0, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x0, dst, src);
}
immediate_arithmetic_op(0x0, dst, src, size);
}
void emit_and(Register dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x23, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x23, dst, src);
}
arithmetic_op(0x23, dst, src, size);
}
void emit_and(Register dst, const Operand& src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x23, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x23, dst, src);
}
arithmetic_op(0x23, dst, src, size);
}
void emit_and(const Operand& dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x21, src, dst);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x21, src, dst);
}
arithmetic_op(0x21, src, dst, size);
}
void emit_and(Register dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x4, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x4, dst, src);
}
immediate_arithmetic_op(0x4, dst, src, size);
}
void emit_and(const Operand& dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x4, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x4, dst, src);
}
immediate_arithmetic_op(0x4, dst, src, size);
}
void emit_cmp(Register dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x3B, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x3B, dst, src);
}
arithmetic_op(0x3B, dst, src, size);
}
void emit_cmp(Register dst, const Operand& src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x3B, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x3B, dst, src);
}
arithmetic_op(0x3B, dst, src, size);
}
void emit_cmp(const Operand& dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x39, src, dst);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x39, src, dst);
}
arithmetic_op(0x39, src, dst, size);
}
void emit_cmp(Register dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x7, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x7, dst, src);
}
immediate_arithmetic_op(0x7, dst, src, size);
}
void emit_cmp(const Operand& dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x7, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x7, dst, src);
}
immediate_arithmetic_op(0x7, dst, src, size);
}
void emit_dec(Register dst, int size);
......@@ -1599,99 +1530,49 @@ class Assembler : public AssemblerBase {
void emit_not(const Operand& dst, int size);
void emit_or(Register dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x0B, dst, src);
} else {
arithmetic_op_32(0x0B, dst, src);
}
arithmetic_op(0x0B, dst, src, size);
}
void emit_or(Register dst, const Operand& src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x0B, dst, src);
} else {
arithmetic_op_32(0x0B, dst, src);
}
arithmetic_op(0x0B, dst, src, size);
}
void emit_or(const Operand& dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x9, src, dst);
} else {
arithmetic_op_32(0x9, src, dst);
}
arithmetic_op(0x9, src, dst, size);
}
void emit_or(Register dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x1, dst, src);
} else {
immediate_arithmetic_op_32(0x1, dst, src);
}
immediate_arithmetic_op(0x1, dst, src, size);
}
void emit_or(const Operand& dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x1, dst, src);
} else {
immediate_arithmetic_op_32(0x1, dst, src);
}
immediate_arithmetic_op(0x1, dst, src, size);
}
void emit_repmovs(int size);
void emit_sbb(Register dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x1b, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x1b, dst, src);
}
arithmetic_op(0x1b, dst, src, size);
}
void emit_sub(Register dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x2B, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x2B, dst, src);
}
arithmetic_op(0x2B, dst, src, size);
}
void emit_sub(Register dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x5, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x5, dst, src);
}
immediate_arithmetic_op(0x5, dst, src, size);
}
void emit_sub(Register dst, const Operand& src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x2B, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x2B, dst, src);
}
arithmetic_op(0x2B, dst, src, size);
}
void emit_sub(const Operand& dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x29, src, dst);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x29, src, dst);
}
arithmetic_op(0x29, src, dst, size);
}
void emit_sub(const Operand& dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x5, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x5, dst, src);
}
immediate_arithmetic_op(0x5, dst, src, size);
}
void emit_test(Register dst, Register src, int size);
......@@ -1703,52 +1584,29 @@ class Assembler : public AssemblerBase {
void emit_xchg(Register dst, Register src, int size);
void emit_xor(Register dst, Register src, int size) {
if (size == kInt64Size) {
if (dst.code() == src.code()) {
arithmetic_op_32(0x33, dst, src);
} else {
arithmetic_op(0x33, dst, src);
}
if (size == kInt64Size && dst.code() == src.code()) {
// 32 bit operations zero the top 32 bits of 64 bit registers. Therefore
// there is no need to make this a 64 bit operation.
arithmetic_op(0x33, dst, src, kInt32Size);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x33, dst, src);
arithmetic_op(0x33, dst, src, size);
}
}
void emit_xor(Register dst, const Operand& src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x33, dst, src);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x33, dst, src);
}
arithmetic_op(0x33, dst, src, size);
}
void emit_xor(Register dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x6, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x6, dst, src);
}
immediate_arithmetic_op(0x6, dst, src, size);
}
void emit_xor(const Operand& dst, Immediate src, int size) {
if (size == kInt64Size) {
immediate_arithmetic_op(0x6, dst, src);
} else {
ASSERT(size == kInt32Size);
immediate_arithmetic_op_32(0x6, dst, src);
}
immediate_arithmetic_op(0x6, dst, src, size);
}
void emit_xor(const Operand& dst, Register src, int size) {
if (size == kInt64Size) {
arithmetic_op(0x31, src, dst);
} else {
ASSERT(size == kInt32Size);
arithmetic_op_32(0x31, src, dst);
}
arithmetic_op(0x31, src, dst, size);
}
friend class CodePatcher;
......
......@@ -141,6 +141,37 @@ TEST(AssemblerX64ArithmeticOperations) {
}
TEST(AssemblerX64CmpbOperation) {
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
&actual_size,
true));
CHECK(buffer);
Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
// Assemble a function that compare argument byte returing 1 if equal else 0.
// On Windows, it compares rcx with rdx which does not require REX prefix;
// on Linux, it compares rdi with rsi which requires REX prefix.
Label done;
__ movq(rax, Immediate(1));
__ cmpb(arg1, arg2);
__ j(equal, &done);
__ movq(rax, Immediate(0));
__ bind(&done);
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
// Call the function from C++.
int result = FUNCTION_CAST<F2>(buffer)(0x1002, 0x2002);
CHECK_EQ(1, result);
result = FUNCTION_CAST<F2>(buffer)(0x1002, 0x2003);
CHECK_EQ(0, result);
}
TEST(AssemblerX64ImulOperation) {
// Allocate an executable page of memory.
size_t actual_size;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment