Commit 911f38c4 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[x64] Introduce negb and negw instructions

This CL introduces the negb and negw instructions (8-bit and 16-bit
versions of neg) in the x64 assembler. These instructions are needed to
implement I32AtomicSub8U and similar WebAssembly instructions
efficiently.

The existing implementation was embedded in a generic macro, and it was
difficult to change it without introducing also the 8-bit and 16-bit
versions of many other instructions. This would have introduced a lot
of dead code. Instead this CL extracted the neg instructions from the
macro and implements them directly. This should be fine because the
assembler does not change much, and approachability of the code is
improved.

R=clemensb@chromium.org

Bug: v8:10108
Change-Id: I46099bbebd47f864311a67da3ba8ddc4fe4cd35d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2019165
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65989}
parent 261a22e2
......@@ -142,6 +142,22 @@ void Assembler::emit_optional_rex_32(Operand op) {
if (op.data().rex != 0) emit(0x40 | op.data().rex);
}
void Assembler::emit_optional_rex_8(Register reg) {
if (!reg.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(reg);
}
}
void Assembler::emit_optional_rex_8(Register reg, Operand op) {
if (!reg.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(reg, op);
} else {
emit_optional_rex_32(reg, op);
}
}
// byte 1 of 3-byte VEX
void Assembler::emit_vex3_byte1(XMMRegister reg, XMMRegister rm,
LeadingOpcode m) {
......
......@@ -1204,12 +1204,7 @@ void Assembler::lock() {
void Assembler::xaddb(Operand dst, Register src) {
EnsureSpace ensure_space(this);
if (!src.is_byte_register()) {
// Register is not one of al, bl, cl, dl. Its encoding needs REX.
emit_rex_32(src, dst);
} else {
emit_optional_rex_32(src, dst);
}
emit_optional_rex_8(src, dst);
emit(0x0F);
emit(0xC0);
emit_operand(src, dst);
......@@ -2012,18 +2007,62 @@ void Assembler::mulq(Register src) {
emit_modrm(0x4, src);
}
void Assembler::emit_neg(Register dst, int size) {
void Assembler::negb(Register reg) {
EnsureSpace ensure_space(this);
emit_rex(dst, size);
emit_optional_rex_8(reg);
emit(0xF6);
emit_modrm(0x3, reg);
}
void Assembler::negw(Register reg) {
EnsureSpace ensure_space(this);
emit(0x66);
emit_optional_rex_32(reg);
emit(0xF7);
emit_modrm(0x3, dst);
emit_modrm(0x3, reg);
}
void Assembler::emit_neg(Operand dst, int size) {
void Assembler::negl(Register reg) {
EnsureSpace ensure_space(this);
emit_rex_64(dst);
emit_optional_rex_32(reg);
emit(0xF7);
emit_modrm(0x3, reg);
}
void Assembler::negq(Register reg) {
EnsureSpace ensure_space(this);
emit_rex_64(reg);
emit(0xF7);
emit_modrm(0x3, reg);
}
void Assembler::negb(Operand op) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(op);
emit(0xF6);
emit_operand(0x3, op);
}
void Assembler::negw(Operand op) {
EnsureSpace ensure_space(this);
emit(0x66);
emit_optional_rex_32(op);
emit(0xF7);
emit_operand(0x3, op);
}
void Assembler::negl(Operand op) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(op);
emit(0xF7);
emit_operand(0x3, op);
}
void Assembler::negq(Operand op) {
EnsureSpace ensure_space(this);
emit_rex_64(op);
emit(0xF7);
emit_operand(3, dst);
emit_operand(0x3, op);
}
void Assembler::nop() {
......
......@@ -225,7 +225,6 @@ static_assert(sizeof(Operand) <= 2 * kSystemPointerSize,
V(mov) \
V(movzxb) \
V(movzxw) \
V(neg) \
V(not) \
V(or) \
V(repmovs) \
......@@ -612,6 +611,15 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void xaddl(Operand dst, Register src);
void xaddq(Operand dst, Register src);
void negb(Register reg);
void negw(Register reg);
void negl(Register reg);
void negq(Register reg);
void negb(Operand op);
void negw(Operand op);
void negl(Operand op);
void negq(Operand op);
void cmpxchgb(Operand dst, Register src);
void cmpxchgw(Operand dst, Register src);
......@@ -1836,6 +1844,13 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// numbers have a high bit set.
inline void emit_optional_rex_32(Operand op);
// Calls emit_rex_32(Register) for all non-byte registers.
inline void emit_optional_rex_8(Register reg);
// Calls emit_rex_32(Register, Operand) for all non-byte registers, and
// emit_optional_rex_32(Register, Operand) for byte registers.
inline void emit_optional_rex_8(Register reg, Operand op);
void emit_rex(int size) {
if (size == kInt64Size) {
emit_rex_64();
......
......@@ -679,7 +679,7 @@ int DisassemblerX64::F6F7Instruction(byte* data) {
byte modrm = *(data + 1);
int mod, regop, rm;
get_modrm(modrm, &mod, &regop, &rm);
if (mod == 3 && regop != 0) {
if (regop != 0) {
const char* mnem = nullptr;
switch (regop) {
case 2:
......@@ -703,8 +703,18 @@ int DisassemblerX64::F6F7Instruction(byte* data) {
default:
UnimplementedInstruction();
}
AppendToBuffer("%s%c %s", mnem, operand_size_code(), NameOfCPURegister(rm));
return 2;
if (mod == 3) {
AppendToBuffer("%s%c %s", mnem, operand_size_code(),
NameOfCPURegister(rm));
return 2;
} else if (mod == 1) {
AppendToBuffer("%s%c ", mnem, operand_size_code());
int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
return 1 + count;
} else {
UnimplementedInstruction();
return 2;
}
} else if (regop == 0) {
AppendToBuffer("test%c ", operand_size_code());
int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
......
......@@ -189,7 +189,17 @@ TEST(DisasmX64) {
__ idivq(rdx);
__ mull(rdx);
__ mulq(rdx);
__ negb(rdx);
__ negb(r10);
__ negw(rdx);
__ negl(rdx);
__ negq(rdx);
__ negb(Operand(rsp, 12));
__ negw(Operand(rsp, 12));
__ negl(Operand(rsp, 12));
__ negb(Operand(rsp, 12));
__ notq(rdx);
__ testq(Operand(rbx, rcx, times_4, 10000), rdx);
......
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