From 38e764f7aca71c03fa3d0643e396f075e16b84c8 Mon Sep 17 00:00:00 2001 From: Weiliang Lin Date: Sat, 11 Apr 2015 09:02:22 +0800 Subject: [PATCH] [x86] Introduce vandps/vandpd/vxorps/vxorpd. R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/1072343002 Cr-Commit-Position: refs/heads/master@{#27768} --- src/compiler/ia32/code-generator-ia32.cc | 36 ++++- src/compiler/ia32/instruction-codes-ia32.h | 4 + src/compiler/ia32/instruction-selector-ia32.cc | 24 ++- src/compiler/x64/code-generator-x64.cc | 60 +++++++- src/compiler/x64/instruction-codes-x64.h | 4 + src/compiler/x64/instruction-selector-x64.cc | 24 ++- src/ia32/assembler-ia32.cc | 20 +++ src/ia32/assembler-ia32.h | 24 +++ src/ia32/disasm-ia32.cc | 34 +++++ src/x64/assembler-x64.cc | 40 +++++ src/x64/assembler-x64.h | 24 +++ src/x64/disasm-x64.cc | 51 ++++++- test/cctest/test-disasm-ia32.cc | 10 ++ test/cctest/test-disasm-x64.cc | 10 ++ .../ia32/instruction-selector-ia32-unittest.cc | 164 ++++++++++++++------- .../x64/instruction-selector-x64-unittest.cc | 164 ++++++++++++++------- 16 files changed, 566 insertions(+), 127 deletions(-) diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index 586d548..aaa34dc 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -480,7 +480,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { break; case kSSEFloat32Abs: { // TODO(bmeurer): Use 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psrlq(kScratchDoubleReg, 33); __ andps(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -488,7 +487,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { } case kSSEFloat32Neg: { // TODO(bmeurer): Use 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psllq(kScratchDoubleReg, 31); __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -542,7 +540,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { } case kSSEFloat64Abs: { // TODO(bmeurer): Use 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psrlq(kScratchDoubleReg, 1); __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -550,7 +547,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { } case kSSEFloat64Neg: { // TODO(bmeurer): Use 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psllq(kScratchDoubleReg, 63); __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -683,6 +679,38 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { i.InputOperand(1)); break; } + case kAVXFloat32Abs: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psrlq(kScratchDoubleReg, 33); + CpuFeatureScope avx_scope(masm(), AVX); + __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); + break; + } + case kAVXFloat32Neg: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psllq(kScratchDoubleReg, 31); + CpuFeatureScope avx_scope(masm(), AVX); + __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); + break; + } + case kAVXFloat64Abs: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psrlq(kScratchDoubleReg, 1); + CpuFeatureScope avx_scope(masm(), AVX); + __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); + break; + } + case kAVXFloat64Neg: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psllq(kScratchDoubleReg, 63); + CpuFeatureScope avx_scope(masm(), AVX); + __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, i.InputOperand(0)); + break; + } case kIA32Movsxbl: __ movsx_b(i.OutputRegister(), i.MemoryOperand()); break; diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h index 472dd57..3962040 100644 --- a/src/compiler/ia32/instruction-codes-ia32.h +++ b/src/compiler/ia32/instruction-codes-ia32.h @@ -76,6 +76,10 @@ namespace compiler { V(AVXFloat64Div) \ V(AVXFloat64Max) \ V(AVXFloat64Min) \ + V(AVXFloat64Abs) \ + V(AVXFloat64Neg) \ + V(AVXFloat32Abs) \ + V(AVXFloat32Neg) \ V(IA32Movsxbl) \ V(IA32Movzxbl) \ V(IA32Movb) \ diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index 93644a9..1eadc02 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -153,6 +153,18 @@ void VisitRROFloat(InstructionSelector* selector, Node* node, } } + +void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input, + ArchOpcode avx_opcode, ArchOpcode sse_opcode) { + IA32OperandGenerator g(selector); + if (selector->IsSupported(AVX)) { + selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input)); + } else { + selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input)); + } +} + + } // namespace @@ -684,8 +696,8 @@ void InstructionSelector::VisitFloat32Sub(Node* node) { IA32OperandGenerator g(this); Float32BinopMatcher m(node); if (m.left().IsMinusZero()) { - Emit(kSSEFloat32Neg, g.DefineSameAsFirst(node), - g.UseRegister(m.right().node())); + VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg, + kSSEFloat32Neg); return; } VisitRROFloat(this, node, kAVXFloat32Sub, kSSEFloat32Sub); @@ -708,8 +720,8 @@ void InstructionSelector::VisitFloat64Sub(Node* node) { } } } - Emit(kSSEFloat64Neg, g.DefineSameAsFirst(node), - g.UseRegister(m.right().node())); + VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg, + kSSEFloat64Neg); return; } VisitRROFloat(this, node, kAVXFloat64Sub, kSSEFloat64Sub); @@ -767,13 +779,13 @@ void InstructionSelector::VisitFloat64Min(Node* node) { void InstructionSelector::VisitFloat32Abs(Node* node) { IA32OperandGenerator g(this); - Emit(kSSEFloat32Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0))); + VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs); } void InstructionSelector::VisitFloat64Abs(Node* node) { IA32OperandGenerator g(this); - Emit(kSSEFloat64Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0))); + VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs); } diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index c13e169..1e5d62f 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -729,7 +729,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { break; case kSSEFloat32Abs: { // TODO(bmeurer): Use RIP relative 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psrlq(kScratchDoubleReg, 33); __ andps(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -737,7 +736,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { } case kSSEFloat32Neg: { // TODO(bmeurer): Use RIP relative 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psllq(kScratchDoubleReg, 31); __ xorps(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -810,7 +808,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { break; case kSSEFloat64Abs: { // TODO(bmeurer): Use RIP relative 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psrlq(kScratchDoubleReg, 1); __ andpd(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -818,7 +815,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { } case kSSEFloat64Neg: { // TODO(bmeurer): Use RIP relative 128-bit constants. - // TODO(turbofan): Add AVX version with relaxed register constraints. __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); __ psllq(kScratchDoubleReg, 63); __ xorpd(i.OutputDoubleRegister(), kScratchDoubleReg); @@ -957,6 +953,62 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { case kAVXFloat64Min: ASSEMBLE_AVX_BINOP(vminsd); break; + case kAVXFloat32Abs: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psrlq(kScratchDoubleReg, 33); + CpuFeatureScope avx_scope(masm(), AVX); + if (instr->InputAt(0)->IsDoubleRegister()) { + __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputDoubleRegister(0)); + } else { + __ vandps(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputOperand(0)); + } + break; + } + case kAVXFloat32Neg: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psllq(kScratchDoubleReg, 31); + CpuFeatureScope avx_scope(masm(), AVX); + if (instr->InputAt(0)->IsDoubleRegister()) { + __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputDoubleRegister(0)); + } else { + __ vxorps(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputOperand(0)); + } + break; + } + case kAVXFloat64Abs: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psrlq(kScratchDoubleReg, 1); + CpuFeatureScope avx_scope(masm(), AVX); + if (instr->InputAt(0)->IsDoubleRegister()) { + __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputDoubleRegister(0)); + } else { + __ vandpd(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputOperand(0)); + } + break; + } + case kAVXFloat64Neg: { + // TODO(bmeurer): Use RIP relative 128-bit constants. + __ pcmpeqd(kScratchDoubleReg, kScratchDoubleReg); + __ psllq(kScratchDoubleReg, 63); + CpuFeatureScope avx_scope(masm(), AVX); + if (instr->InputAt(0)->IsDoubleRegister()) { + __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputDoubleRegister(0)); + } else { + __ vxorpd(i.OutputDoubleRegister(), kScratchDoubleReg, + i.InputOperand(0)); + } + break; + } case kX64Movsxbl: ASSEMBLE_MOVX(movsxbl); __ AssertZeroExtended(i.OutputRegister()); diff --git a/src/compiler/x64/instruction-codes-x64.h b/src/compiler/x64/instruction-codes-x64.h index 87e0110..428b7dc 100644 --- a/src/compiler/x64/instruction-codes-x64.h +++ b/src/compiler/x64/instruction-codes-x64.h @@ -94,6 +94,10 @@ namespace compiler { V(AVXFloat64Div) \ V(AVXFloat64Max) \ V(AVXFloat64Min) \ + V(AVXFloat64Abs) \ + V(AVXFloat64Neg) \ + V(AVXFloat32Abs) \ + V(AVXFloat32Neg) \ V(X64Movsxbl) \ V(X64Movzxbl) \ V(X64Movb) \ diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index 68bc035..21db735 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -856,6 +856,18 @@ void VisitFloatBinop(InstructionSelector* selector, Node* node, } } + +void VisitFloatUnop(InstructionSelector* selector, Node* node, Node* input, + ArchOpcode avx_opcode, ArchOpcode sse_opcode) { + X64OperandGenerator g(selector); + if (selector->IsSupported(AVX)) { + selector->Emit(avx_opcode, g.DefineAsRegister(node), g.Use(input)); + } else { + selector->Emit(sse_opcode, g.DefineSameAsFirst(node), g.UseRegister(input)); + } +} + + } // namespace @@ -868,8 +880,8 @@ void InstructionSelector::VisitFloat32Sub(Node* node) { X64OperandGenerator g(this); Float32BinopMatcher m(node); if (m.left().IsMinusZero()) { - Emit(kSSEFloat32Neg, g.DefineSameAsFirst(node), - g.UseRegister(m.right().node())); + VisitFloatUnop(this, node, m.right().node(), kAVXFloat32Neg, + kSSEFloat32Neg); return; } VisitFloatBinop(this, node, kAVXFloat32Sub, kSSEFloat32Sub); @@ -898,7 +910,7 @@ void InstructionSelector::VisitFloat32Min(Node* node) { void InstructionSelector::VisitFloat32Abs(Node* node) { X64OperandGenerator g(this); - Emit(kSSEFloat32Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0))); + VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat32Abs, kSSEFloat32Abs); } @@ -929,8 +941,8 @@ void InstructionSelector::VisitFloat64Sub(Node* node) { } } } - Emit(kSSEFloat64Neg, g.DefineSameAsFirst(node), - g.UseRegister(m.right().node())); + VisitFloatUnop(this, node, m.right().node(), kAVXFloat64Neg, + kSSEFloat64Neg); return; } VisitFloatBinop(this, node, kAVXFloat64Sub, kSSEFloat64Sub); @@ -968,7 +980,7 @@ void InstructionSelector::VisitFloat64Min(Node* node) { void InstructionSelector::VisitFloat64Abs(Node* node) { X64OperandGenerator g(this); - Emit(kSSEFloat64Abs, g.DefineSameAsFirst(node), g.Use(node->InputAt(0))); + VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs); } diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index 98caaeb..a3c19af 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -2665,6 +2665,26 @@ void Assembler::vss(byte op, XMMRegister dst, XMMRegister src1, } +void Assembler::vps(byte op, XMMRegister dst, XMMRegister src1, + const Operand& src2) { + DCHECK(IsEnabled(AVX)); + EnsureSpace ensure_space(this); + emit_vex_prefix(src1, kL128, kNone, k0F, kWIG); + EMIT(op); + emit_sse_operand(dst, src2); +} + + +void Assembler::vpd(byte op, XMMRegister dst, XMMRegister src1, + const Operand& src2) { + DCHECK(IsEnabled(AVX)); + EnsureSpace ensure_space(this); + emit_vex_prefix(src1, kL128, k66, k0F, kWIG); + EMIT(op); + emit_sse_operand(dst, src2); +} + + void Assembler::bmi1(byte op, Register reg, Register vreg, const Operand& rm) { DCHECK(IsEnabled(BMI1)); EnsureSpace ensure_space(this); diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index bb8098d..48f0603 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -1398,6 +1398,30 @@ class Assembler : public AssemblerBase { } void rorx(Register dst, const Operand& src, byte imm8); +#define PACKED_OP_LIST(V) \ + V(and, 0x54) \ + V(xor, 0x57) + +#define AVX_PACKED_OP_DECLARE(name, opcode) \ + void v##name##ps(XMMRegister dst, XMMRegister src1, XMMRegister src2) { \ + vps(opcode, dst, src1, Operand(src2)); \ + } \ + void v##name##ps(XMMRegister dst, XMMRegister src1, const Operand& src2) { \ + vps(opcode, dst, src1, src2); \ + } \ + void v##name##pd(XMMRegister dst, XMMRegister src1, XMMRegister src2) { \ + vpd(opcode, dst, src1, Operand(src2)); \ + } \ + void v##name##pd(XMMRegister dst, XMMRegister src1, const Operand& src2) { \ + vpd(opcode, dst, src1, src2); \ + } + + PACKED_OP_LIST(AVX_PACKED_OP_DECLARE); + void vps(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2); + void vps(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2); + void vpd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2); + void vpd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2); + // Prefetch src position into cache level. // Level 1, 2 or 3 specifies CPU cache level. Level 0 specifies a // non-temporal diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc index d131277..80ac528 100644 --- a/src/ia32/disasm-ia32.cc +++ b/src/ia32/disasm-ia32.cc @@ -985,6 +985,40 @@ int DisassemblerIA32::AVXInstruction(byte* data) { default: UnimplementedInstruction(); } + } else if (vex_none() && vex_0f()) { + int mod, regop, rm, vvvv = vex_vreg(); + get_modrm(*current, &mod, ®op, &rm); + switch (opcode) { + case 0x54: + AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + case 0x57: + AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + default: + UnimplementedInstruction(); + } + } else if (vex_66() && vex_0f()) { + int mod, regop, rm, vvvv = vex_vreg(); + get_modrm(*current, &mod, ®op, &rm); + switch (opcode) { + case 0x54: + AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + case 0x57: + AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + default: + UnimplementedInstruction(); + } } else { UnimplementedInstruction(); } diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 7637b33..cafa402 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -3510,6 +3510,46 @@ void Assembler::vsd(byte op, XMMRegister dst, XMMRegister src1, } +void Assembler::vps(byte op, XMMRegister dst, XMMRegister src1, + XMMRegister src2) { + DCHECK(IsEnabled(AVX)); + EnsureSpace ensure_space(this); + emit_vex_prefix(dst, src1, src2, kL128, kNone, k0F, kWIG); + emit(op); + emit_sse_operand(dst, src2); +} + + +void Assembler::vps(byte op, XMMRegister dst, XMMRegister src1, + const Operand& src2) { + DCHECK(IsEnabled(AVX)); + EnsureSpace ensure_space(this); + emit_vex_prefix(dst, src1, src2, kL128, kNone, k0F, kWIG); + emit(op); + emit_sse_operand(dst, src2); +} + + +void Assembler::vpd(byte op, XMMRegister dst, XMMRegister src1, + XMMRegister src2) { + DCHECK(IsEnabled(AVX)); + EnsureSpace ensure_space(this); + emit_vex_prefix(dst, src1, src2, kL128, k66, k0F, kWIG); + emit(op); + emit_sse_operand(dst, src2); +} + + +void Assembler::vpd(byte op, XMMRegister dst, XMMRegister src1, + const Operand& src2) { + DCHECK(IsEnabled(AVX)); + EnsureSpace ensure_space(this); + emit_vex_prefix(dst, src1, src2, kL128, k66, k0F, kWIG); + emit(op); + emit_sse_operand(dst, src2); +} + + void Assembler::vucomiss(XMMRegister dst, XMMRegister src) { DCHECK(IsEnabled(AVX)); EnsureSpace ensure_space(this); diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index 291ee7f..27f0441 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -1582,6 +1582,30 @@ class Assembler : public AssemblerBase { void rorxl(Register dst, Register src, byte imm8); void rorxl(Register dst, const Operand& src, byte imm8); +#define PACKED_OP_LIST(V) \ + V(and, 0x54) \ + V(xor, 0x57) + +#define AVX_PACKED_OP_DECLARE(name, opcode) \ + void v##name##ps(XMMRegister dst, XMMRegister src1, XMMRegister src2) { \ + vps(opcode, dst, src1, src2); \ + } \ + void v##name##ps(XMMRegister dst, XMMRegister src1, const Operand& src2) { \ + vps(opcode, dst, src1, src2); \ + } \ + void v##name##pd(XMMRegister dst, XMMRegister src1, XMMRegister src2) { \ + vpd(opcode, dst, src1, src2); \ + } \ + void v##name##pd(XMMRegister dst, XMMRegister src1, const Operand& src2) { \ + vpd(opcode, dst, src1, src2); \ + } + + PACKED_OP_LIST(AVX_PACKED_OP_DECLARE); + void vps(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2); + void vps(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2); + void vpd(byte op, XMMRegister dst, XMMRegister src1, XMMRegister src2); + void vpd(byte op, XMMRegister dst, XMMRegister src1, const Operand& src2); + // Debugging void Print(); diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc index 4799a32..c70684d 100644 --- a/src/x64/disasm-x64.cc +++ b/src/x64/disasm-x64.cc @@ -876,13 +876,7 @@ int DisassemblerX64::SetCC(byte* data) { int DisassemblerX64::AVXInstruction(byte* data) { byte opcode = *data; byte* current = data + 1; - if (vex_0f() && opcode == 0x2e) { - int mod, regop, rm; - get_modrm(*current, &mod, ®op, &rm); - AppendToBuffer("vucomis%c %s,", vex_66() ? 'd' : 's', - NameOfXMMRegister(regop)); - current += PrintRightXMMOperand(current); - } else if (vex_66() && vex_0f38()) { + if (vex_66() && vex_0f38()) { int mod, regop, rm, vvvv = vex_vreg(); get_modrm(*current, &mod, ®op, &rm); switch (opcode) { @@ -1137,6 +1131,49 @@ int DisassemblerX64::AVXInstruction(byte* data) { default: UnimplementedInstruction(); } + } else if (vex_none() && vex_0f()) { + int mod, regop, rm, vvvv = vex_vreg(); + get_modrm(*current, &mod, ®op, &rm); + switch (opcode) { + case 0x2e: + AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; + case 0x54: + AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + case 0x57: + AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + default: + UnimplementedInstruction(); + } + } else if (vex_66() && vex_0f()) { + int mod, regop, rm, vvvv = vex_vreg(); + get_modrm(*current, &mod, ®op, &rm); + switch (opcode) { + case 0x2e: + AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop)); + current += PrintRightXMMOperand(current); + break; + case 0x54: + AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + case 0x57: + AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop), + NameOfXMMRegister(vvvv)); + current += PrintRightXMMOperand(current); + break; + default: + UnimplementedInstruction(); + } + } else { UnimplementedInstruction(); } diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc index 52df2fd..aeaa995 100644 --- a/test/cctest/test-disasm-ia32.cc +++ b/test/cctest/test-disasm-ia32.cc @@ -525,6 +525,16 @@ TEST(DisasmIa320) { __ vminss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); __ vmaxss(xmm0, xmm1, xmm2); __ vmaxss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); + + __ vandps(xmm0, xmm1, xmm2); + __ vandps(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); + __ vxorps(xmm0, xmm1, xmm2); + __ vxorps(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); + + __ vandpd(xmm0, xmm1, xmm2); + __ vandpd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); + __ vxorpd(xmm0, xmm1, xmm2); + __ vxorpd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); } } diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc index 072b3b8..bcfe507 100644 --- a/test/cctest/test-disasm-x64.cc +++ b/test/cctest/test-disasm-x64.cc @@ -525,6 +525,16 @@ TEST(DisasmX64) { __ vmaxsd(xmm9, xmm1, Operand(rbx, rcx, times_1, 10000)); __ vucomisd(xmm9, xmm1); __ vucomisd(xmm8, Operand(rbx, rdx, times_2, 10981)); + + __ vandps(xmm0, xmm9, xmm2); + __ vandps(xmm9, xmm1, Operand(rbx, rcx, times_4, 10000)); + __ vxorps(xmm0, xmm1, xmm9); + __ vxorps(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000)); + + __ vandpd(xmm0, xmm9, xmm2); + __ vandpd(xmm9, xmm1, Operand(rbx, rcx, times_4, 10000)); + __ vxorpd(xmm0, xmm1, xmm9); + __ vxorpd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000)); } } diff --git a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc index f43de4a..4c8e0c0 100644 --- a/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -640,36 +640,68 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) { TEST_F(InstructionSelectorTest, Float32Abs) { - StreamBuilder m(this, kMachFloat32, kMachFloat32); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float32Abs(p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Abs(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Abs(p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } TEST_F(InstructionSelectorTest, Float64Abs) { - StreamBuilder m(this, kMachFloat64, kMachFloat64); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float64Abs(p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Abs(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Abs(p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } @@ -706,34 +738,66 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { TEST_F(InstructionSelectorTest, Float32SubWithMinusZeroAndParameter) { - StreamBuilder m(this, kMachFloat32, kMachFloat32); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat32Neg, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat32Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat32Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } TEST_F(InstructionSelectorTest, Float64SubWithMinusZeroAndParameter) { - StreamBuilder m(this, kMachFloat64, kMachFloat64); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat64Neg, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat64Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat64Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } diff --git a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index 226b55a..0b46b32 100644 --- a/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -997,36 +997,68 @@ TEST_F(InstructionSelectorTest, Int32Shl4BecomesLea) { TEST_F(InstructionSelectorTest, Float32Abs) { - StreamBuilder m(this, kMachFloat32, kMachFloat32); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float32Abs(p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Abs(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat32Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Abs(p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat32Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } TEST_F(InstructionSelectorTest, Float64Abs) { - StreamBuilder m(this, kMachFloat64, kMachFloat64); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float64Abs(p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Abs(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat64Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_TRUE(s.IsSameAsFirst(s[0]->Output())); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Abs(p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat64Abs, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } @@ -1063,34 +1095,66 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { TEST_F(InstructionSelectorTest, Float32SubWithMinusZeroAndParameter) { - StreamBuilder m(this, kMachFloat32, kMachFloat32); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat32Neg, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat32Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat32, kMachFloat32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float32Sub(m.Float32Constant(-0.0f), p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat32Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } TEST_F(InstructionSelectorTest, Float64SubWithMinusZeroAndParameter) { - StreamBuilder m(this, kMachFloat64, kMachFloat64); - Node* const p0 = m.Parameter(0); - Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); - m.Return(n); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kSSEFloat64Neg, s[0]->arch_opcode()); - ASSERT_EQ(1U, s[0]->InputCount()); - EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); - ASSERT_EQ(1U, s[0]->OutputCount()); - EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); - EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kSSEFloat64Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } + { + StreamBuilder m(this, kMachFloat64, kMachFloat64); + Node* const p0 = m.Parameter(0); + Node* const n = m.Float64Sub(m.Float64Constant(-0.0), p0); + m.Return(n); + Stream s = m.Build(AVX); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kAVXFloat64Neg, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_none, s[0]->flags_mode()); + } } -- 2.7.4