Reland^2 "[Liftoff] Implement f32.copysign and f64.copysign"

This is a reland of 6afe7d1815.
The reason for the revert is fixed in https://crrev.com/c/1219633.

Original change's description:
> [Liftoff] Implement f32.copysign and f64.copysign
>
> These are two of the few missing instructions. This CL implements them
> for ia32 and x64, and bails out on other platforms.
> On x64, we are using the BTR instruction since we cannot have 64-bit
> immediates.
>
> Drive-by: Fix naming of existing bt/bts instructions on x64.
>
> R=titzer@chromium.org
>
> Bug: v8:6600
> Change-Id: Ib8532ca811160cd61f4ba7c06b04ce093861c872
> Reviewed-on: https://chromium-review.googlesource.com/1174383
> Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
> Reviewed-by: Ben Titzer <titzer@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#55780}

Bug: v8:6600
Change-Id: Ie14ba3a14848ba8e67f97e66d3379178f35dea40

TBR=titzer@chromium.org

Change-Id: Ie14ba3a14848ba8e67f97e66d3379178f35dea40
Reviewed-on: https://chromium-review.googlesource.com/1219693
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55817}
This commit is contained in:
Clemens Hammacher 2018-09-12 09:29:11 +02:00 committed by Commit Bot
parent 651bd0dec2
commit a39fcbd288
15 changed files with 148 additions and 15 deletions

View File

@ -161,6 +161,7 @@ UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_BINOP(f32_copysign)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
@ -174,6 +175,7 @@ UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_BINOP(f64_copysign)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP_RETURN_TRUE(f64_ceil)

View File

@ -626,6 +626,16 @@ void LiftoffAssembler::emit_i32_to_intptr(Register dst, Register src) {
Sxtw(dst, src);
}
void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
BAILOUT("f32_copysign");
}
void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
BAILOUT("f64_copysign");
}
bool LiftoffAssembler::emit_type_conversion(WasmOpcode opcode,
LiftoffRegister dst,
LiftoffRegister src, Label* trap) {

View File

@ -1025,6 +1025,20 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
liftoff::MinOrMax::kMax);
}
void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
static constexpr int kF32SignBit = 1 << 31;
Register scratch = GetUnusedRegister(kGpReg).gp();
Register scratch2 =
GetUnusedRegister(kGpReg, LiftoffRegList::ForRegs(scratch)).gp();
Movd(scratch, lhs); // move {lhs} into {scratch}.
and_(scratch, Immediate(~kF32SignBit)); // clear sign bit in {scratch}.
Movd(scratch2, rhs); // move {rhs} into {scratch2}.
and_(scratch2, Immediate(kF32SignBit)); // isolate sign bit in {scratch2}.
or_(scratch, scratch2); // combine {scratch2} into {scratch}.
Movd(dst, scratch); // move result into {dst}.
}
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint32_t kSignBit = uint32_t{1} << 31;
if (dst == src) {
@ -1134,6 +1148,24 @@ void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
liftoff::MinOrMax::kMin);
}
void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
static constexpr int kF32SignBit = 1 << 31;
// On ia32, we cannot hold the whole f64 value in a gp register, so we just
// operate on the upper half (UH).
Register scratch = GetUnusedRegister(kGpReg).gp();
Register scratch2 =
GetUnusedRegister(kGpReg, LiftoffRegList::ForRegs(scratch)).gp();
Pextrd(scratch, lhs, 1); // move UH of {lhs} into {scratch}.
and_(scratch, Immediate(~kF32SignBit)); // clear sign bit in {scratch}.
Pextrd(scratch2, rhs, 1); // move UH of {rhs} into {scratch2}.
and_(scratch2, Immediate(kF32SignBit)); // isolate sign bit in {scratch2}.
or_(scratch, scratch2); // combine {scratch2} into {scratch}.
movsd(dst, lhs); // move {lhs} into {dst}.
Pinsrd(dst, scratch, 1); // insert {scratch} into UH of {dst}.
}
void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,

View File

@ -484,6 +484,8 @@ class LiftoffAssembler : public TurboAssembler {
DoubleRegister rhs);
inline void emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
inline void emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
// f32 unops.
inline void emit_f32_abs(DoubleRegister dst, DoubleRegister src);
@ -507,6 +509,8 @@ class LiftoffAssembler : public TurboAssembler {
DoubleRegister rhs);
inline void emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
inline void emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs);
// f64 unops.
inline void emit_f64_abs(DoubleRegister dst, DoubleRegister src);

View File

@ -888,12 +888,14 @@ class LiftoffCompiler {
CASE_FLOAT_BINOP(F32Div, F32, f32_div)
CASE_FLOAT_BINOP(F32Min, F32, f32_min)
CASE_FLOAT_BINOP(F32Max, F32, f32_max)
CASE_FLOAT_BINOP(F32CopySign, F32, f32_copysign)
CASE_FLOAT_BINOP(F64Add, F64, f64_add)
CASE_FLOAT_BINOP(F64Sub, F64, f64_sub)
CASE_FLOAT_BINOP(F64Mul, F64, f64_mul)
CASE_FLOAT_BINOP(F64Div, F64, f64_div)
CASE_FLOAT_BINOP(F64Min, F64, f64_min)
CASE_FLOAT_BINOP(F64Max, F64, f64_max)
CASE_FLOAT_BINOP(F64CopySign, F64, f64_copysign)
case WasmOpcode::kExprI32DivS:
EmitBinOp<kWasmI32, kWasmI32>([this, decoder](LiftoffRegister dst,
LiftoffRegister lhs,

View File

@ -83,10 +83,12 @@ class LiftoffRegister {
public:
explicit LiftoffRegister(Register reg) : LiftoffRegister(reg.code()) {
DCHECK_NE(0, kLiftoffAssemblerGpCacheRegs & reg.bit());
DCHECK_EQ(reg, gp());
}
explicit LiftoffRegister(DoubleRegister reg)
: LiftoffRegister(kAfterMaxLiftoffGpRegCode + reg.code()) {
DCHECK_NE(0, kLiftoffAssemblerFpCacheRegs & reg.bit());
DCHECK_EQ(reg, fp());
}

View File

@ -814,6 +814,11 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
bind(&done);
}
void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
BAILOUT("f32_copysign");
}
void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
Label ool, done;
@ -836,6 +841,11 @@ void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
bind(&done);
}
void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
BAILOUT("f64_copysign");
}
#define FP_BINOP(name, instruction) \
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
DoubleRegister rhs) { \

View File

@ -693,6 +693,11 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
bind(&done);
}
void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
BAILOUT("f32_copysign");
}
void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
Label ool, done;
@ -715,6 +720,11 @@ void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
bind(&done);
}
void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
BAILOUT("f64_copysign");
}
#define FP_BINOP(name, instruction) \
void LiftoffAssembler::emit_##name(DoubleRegister dst, DoubleRegister lhs, \
DoubleRegister rhs) { \

View File

@ -166,6 +166,7 @@ UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_BINOP(f32_copysign)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
@ -179,6 +180,7 @@ UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_BINOP(f64_copysign)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP_RETURN_TRUE(f64_ceil)

View File

@ -166,6 +166,7 @@ UNIMPLEMENTED_FP_BINOP(f32_mul)
UNIMPLEMENTED_FP_BINOP(f32_div)
UNIMPLEMENTED_FP_BINOP(f32_min)
UNIMPLEMENTED_FP_BINOP(f32_max)
UNIMPLEMENTED_FP_BINOP(f32_copysign)
UNIMPLEMENTED_FP_UNOP(f32_abs)
UNIMPLEMENTED_FP_UNOP(f32_neg)
UNIMPLEMENTED_FP_UNOP(f32_ceil)
@ -179,6 +180,7 @@ UNIMPLEMENTED_FP_BINOP(f64_mul)
UNIMPLEMENTED_FP_BINOP(f64_div)
UNIMPLEMENTED_FP_BINOP(f64_min)
UNIMPLEMENTED_FP_BINOP(f64_max)
UNIMPLEMENTED_FP_BINOP(f64_copysign)
UNIMPLEMENTED_FP_UNOP(f64_abs)
UNIMPLEMENTED_FP_UNOP(f64_neg)
UNIMPLEMENTED_FP_UNOP_RETURN_TRUE(f64_ceil)

View File

@ -23,9 +23,11 @@ namespace wasm {
namespace liftoff {
constexpr Register kScratchRegister2 = r11;
static_assert(kScratchRegister != kScratchRegister2, "collision");
static_assert((kLiftoffAssemblerGpCacheRegs &
Register::ListOf<kScratchRegister>()) == 0,
"scratch register must not be used as cache registers");
Register::ListOf<kScratchRegister, kScratchRegister2>()) == 0,
"scratch registers must not be used as cache registers");
constexpr DoubleRegister kScratchDoubleReg2 = xmm14;
static_assert(kScratchDoubleReg != kScratchDoubleReg2, "collision");
@ -898,6 +900,17 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
liftoff::MinOrMax::kMax);
}
void LiftoffAssembler::emit_f32_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
static constexpr int kF32SignBit = 1 << 31;
Movd(kScratchRegister, lhs);
andl(kScratchRegister, Immediate(~kF32SignBit));
Movd(liftoff::kScratchRegister2, rhs);
andl(liftoff::kScratchRegister2, Immediate(kF32SignBit));
orl(kScratchRegister, liftoff::kScratchRegister2);
Movd(dst, kScratchRegister);
}
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint32_t kSignBit = uint32_t{1} << 31;
if (dst == src) {
@ -1007,6 +1020,20 @@ void LiftoffAssembler::emit_f64_min(DoubleRegister dst, DoubleRegister lhs,
liftoff::MinOrMax::kMin);
}
void LiftoffAssembler::emit_f64_copysign(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
// Extract sign bit from {rhs} into {kScratchRegister2}.
Movq(liftoff::kScratchRegister2, rhs);
shrq(liftoff::kScratchRegister2, Immediate(63));
shlq(liftoff::kScratchRegister2, Immediate(63));
// Reset sign bit of {lhs} (in {kScratchRegister}).
Movq(kScratchRegister, lhs);
btrq(kScratchRegister, Immediate(63));
// Combine both values into {kScratchRegister} and move into {dst}.
orq(kScratchRegister, liftoff::kScratchRegister2);
Movq(dst, kScratchRegister);
}
void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
DoubleRegister rhs) {
liftoff::EmitFloatMinOrMax<double>(this, dst, lhs, rhs,

View File

@ -943,7 +943,7 @@ void Assembler::bswapq(Register dst) {
emit(0xC8 + dst.low_bits());
}
void Assembler::bt(Operand dst, Register src) {
void Assembler::btq(Operand dst, Register src) {
EnsureSpace ensure_space(this);
emit_rex_64(src, dst);
emit(0x0F);
@ -951,7 +951,7 @@ void Assembler::bt(Operand dst, Register src) {
emit_operand(src, dst);
}
void Assembler::bts(Operand dst, Register src) {
void Assembler::btsq(Operand dst, Register src) {
EnsureSpace ensure_space(this);
emit_rex_64(src, dst);
emit(0x0F);
@ -959,6 +959,23 @@ void Assembler::bts(Operand dst, Register src) {
emit_operand(src, dst);
}
void Assembler::btsq(Register dst, Immediate imm8) {
EnsureSpace ensure_space(this);
emit_rex_64(dst);
emit(0x0F);
emit(0xBA);
emit_modrm(0x5, dst);
emit(imm8.value_);
}
void Assembler::btrq(Register dst, Immediate imm8) {
EnsureSpace ensure_space(this);
emit_rex_64(dst);
emit(0x0F);
emit(0xBA);
emit_modrm(0x6, dst);
emit(imm8.value_);
}
void Assembler::bsrl(Register dst, Register src) {
EnsureSpace ensure_space(this);

View File

@ -856,8 +856,10 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// Bit operations.
void bswapl(Register dst);
void bswapq(Register dst);
void bt(Operand dst, Register src);
void bts(Operand dst, Register src);
void btq(Operand dst, Register src);
void btsq(Operand dst, Register src);
void btsq(Register dst, Immediate imm8);
void btrq(Register dst, Immediate imm8);
void bsrq(Register dst, Register src);
void bsrq(Register dst, Operand src);
void bsrl(Register dst, Register src);

View File

@ -1816,7 +1816,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
AppendToBuffer(",0x%x", (*current) & 7);
current += 1;
} else {
const char* mnemonic = "?";
const char* mnemonic;
if (opcode == 0x54) {
mnemonic = "andpd";
} else if (opcode == 0x56) {
@ -2166,7 +2166,6 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
} else if (opcode == 0xA2) {
// CPUID
AppendToBuffer("%s", mnemonic);
} else if ((opcode & 0xF0) == 0x40) {
// CMOVcc: conditional move.
int condition = opcode & 0x0F;
@ -2229,13 +2228,13 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
opcode == 0xB7 || opcode == 0xAF) {
// Size-extending moves, IMUL.
current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
} else if ((opcode & 0xF0) == 0x90) {
// SETcc: Set byte on condition. Needs pointer to beginning of instruction.
current = data + SetCC(data);
} else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
// SHLD, SHRD (double-precision shift), BTS (bit set).
} else if (opcode == 0xA3 || opcode == 0xA5 || opcode == 0xAB ||
opcode == 0xAD) {
// BT (bit test), SHLD, BTS (bit test and set),
// SHRD (double-precision shift)
AppendToBuffer("%s ", mnemonic);
int mod, regop, rm;
get_modrm(*current, &mod, &regop, &rm);
@ -2245,6 +2244,14 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
} else {
AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
}
} else if (opcode == 0xBA) {
// BTS / BTR (bit test and set/reset) with immediate
int mod, regop, rm;
get_modrm(*current, &mod, &regop, &rm);
mnemonic = regop == 5 ? "bts" : regop == 6 ? "btr" : "?";
AppendToBuffer("%s ", mnemonic);
current += PrintRightOperand(current);
AppendToBuffer(",%d", *current++);
} else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
// POPCNT, CTZ, CLZ.
AppendToBuffer("%s%c ", mnemonic, operand_size_code());
@ -2297,6 +2304,8 @@ const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
case 0xA2:
return "cpuid";
case 0xA3:
return "bt";
case 0xA5:
return "shld";
case 0xAB:

View File

@ -142,8 +142,11 @@ TEST(DisasmX64) {
__ shll_cl(Operand(rdi, rax, times_4, 100));
__ shll(rdx, Immediate(1));
__ shll(rdx, Immediate(6));
__ bts(Operand(rdx, 0), rcx);
__ bts(Operand(rbx, rcx, times_4, 0), rcx);
__ btq(Operand(rdx, 0), rcx);
__ btsq(Operand(rdx, 0), rcx);
__ btsq(Operand(rbx, rcx, times_4, 0), rcx);
__ btsq(rcx, Immediate(13));
__ btrq(rcx, Immediate(13));
__ nop();
__ pushq(Immediate(12));
__ pushq(Immediate(23456));
@ -267,7 +270,6 @@ TEST(DisasmX64) {
__ xorq(rdx, Immediate(12345));
__ xorq(rdx, Operand(rbx, rcx, times_8, 10000));
__ bts(Operand(rbx, rcx, times_8, 10000), rdx);
__ pshufw(xmm5, xmm1, 3);
__ hlt();
__ int3();