From 240b7db9c78685c603278bb1ac136b35de37b8c3 Mon Sep 17 00:00:00 2001 From: ahaas Date: Wed, 9 Mar 2016 08:37:29 -0800 Subject: [PATCH] [wasm] Int64Lowering of I64ShrU and I64ShrS on ia32. I implemented I64ShrU and I64ShrS the same as I64Shl in https://codereview.chromium.org/1756863002 R=titzer@chromium.org Review URL: https://codereview.chromium.org/1768233002 Cr-Commit-Position: refs/heads/master@{#34630} --- src/compiler/arm/instruction-selector-arm.cc | 4 ++ src/compiler/ia32/code-generator-ia32.cc | 22 ++++++- src/compiler/ia32/instruction-codes-ia32.h | 4 +- .../ia32/instruction-scheduler-ia32.cc | 4 +- .../ia32/instruction-selector-ia32.cc | 44 ++++++++++++- src/compiler/instruction-selector.cc | 14 ++++ src/compiler/int64-lowering.cc | 44 +++++++++++++ src/compiler/machine-operator.cc | 4 +- src/compiler/machine-operator.h | 2 + .../mips/instruction-selector-mips.cc | 4 ++ src/compiler/opcodes.h | 4 +- src/compiler/ppc/instruction-selector-ppc.cc | 5 ++ src/compiler/raw-machine-assembler.h | 6 ++ src/compiler/typer.cc | 4 ++ src/compiler/verifier.cc | 2 + src/compiler/wasm-compiler.cc | 12 ++-- src/compiler/x87/instruction-selector-x87.cc | 4 ++ src/ia32/assembler-ia32.cc | 25 ++++--- src/ia32/assembler-ia32.h | 11 ++-- src/ia32/code-stubs-ia32.cc | 2 +- src/ia32/disasm-ia32.cc | 5 +- src/ia32/macro-assembler-ia32.cc | 66 +++++++++++++++---- src/ia32/macro-assembler-ia32.h | 8 ++- test/cctest/test-disasm-ia32.cc | 5 +- test/cctest/wasm/test-run-wasm-64.cc | 66 +++++++++++++++++++ .../compiler/int64-lowering-unittest.cc | 30 +++++++++ test/unittests/compiler/node-test-utils.cc | 2 + test/unittests/compiler/node-test-utils.h | 7 ++ 28 files changed, 362 insertions(+), 48 deletions(-) diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc index a5388c5f49..e0d6228918 100644 --- a/src/compiler/arm/instruction-selector-arm.cc +++ b/src/compiler/arm/instruction-selector-arm.cc @@ -788,6 +788,10 @@ void InstructionSelector::VisitWord32PairShl(Node* node) { Emit(kArmPairLsl, 2, outputs, 3, inputs); } +void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); } + +void InstructionSelector::VisitWord32PairSar(Node* node) { UNIMPLEMENTED(); } + void InstructionSelector::VisitWord32Ror(Node* node) { VisitShift(this, node, TryMatchROR); } diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index 482376d6aa..dcbac2d406 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -680,12 +680,28 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { __ sar_cl(i.OutputOperand()); } break; - case kIA32PairShl: + case kIA32ShlPair: if (HasImmediateInput(instr, 2)) { - __ PairShl(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); + __ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); } else { // Shift has been loaded into CL by the register allocator. - __ PairShl_cl(i.InputRegister(1), i.InputRegister(0)); + __ ShlPair_cl(i.InputRegister(1), i.InputRegister(0)); + } + break; + case kIA32ShrPair: + if (HasImmediateInput(instr, 2)) { + __ ShrPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); + } else { + // Shift has been loaded into CL by the register allocator. + __ ShrPair_cl(i.InputRegister(1), i.InputRegister(0)); + } + break; + case kIA32SarPair: + if (HasImmediateInput(instr, 2)) { + __ SarPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2)); + } else { + // Shift has been loaded into CL by the register allocator. + __ SarPair_cl(i.InputRegister(1), i.InputRegister(0)); } break; case kIA32Ror: diff --git a/src/compiler/ia32/instruction-codes-ia32.h b/src/compiler/ia32/instruction-codes-ia32.h index 38add2540f..15316f05c7 100644 --- a/src/compiler/ia32/instruction-codes-ia32.h +++ b/src/compiler/ia32/instruction-codes-ia32.h @@ -29,7 +29,9 @@ namespace compiler { V(IA32Shl) \ V(IA32Shr) \ V(IA32Sar) \ - V(IA32PairShl) \ + V(IA32ShlPair) \ + V(IA32ShrPair) \ + V(IA32SarPair) \ V(IA32Ror) \ V(IA32Lzcnt) \ V(IA32Tzcnt) \ diff --git a/src/compiler/ia32/instruction-scheduler-ia32.cc b/src/compiler/ia32/instruction-scheduler-ia32.cc index c8d9366a0b..82d75cb10f 100644 --- a/src/compiler/ia32/instruction-scheduler-ia32.cc +++ b/src/compiler/ia32/instruction-scheduler-ia32.cc @@ -31,7 +31,9 @@ int InstructionScheduler::GetTargetInstructionFlags( case kIA32Shl: case kIA32Shr: case kIA32Sar: - case kIA32PairShl: + case kIA32ShlPair: + case kIA32ShrPair: + case kIA32SarPair: case kIA32Ror: case kIA32Lzcnt: case kIA32Tzcnt: diff --git a/src/compiler/ia32/instruction-selector-ia32.cc b/src/compiler/ia32/instruction-selector-ia32.cc index 35c3660a24..e197eb6af4 100644 --- a/src/compiler/ia32/instruction-selector-ia32.cc +++ b/src/compiler/ia32/instruction-selector-ia32.cc @@ -601,7 +601,49 @@ void InstructionSelector::VisitWord32PairShl(Node* node) { g.DefineAsFixed(node, eax), g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)}; - Emit(kIA32PairShl, 2, outputs, 3, inputs); + Emit(kIA32ShlPair, 2, outputs, 3, inputs); +} + +void InstructionSelector::VisitWord32PairShr(Node* node) { + IA32OperandGenerator g(this); + + Node* shift = node->InputAt(2); + InstructionOperand shift_operand; + if (g.CanBeImmediate(shift)) { + shift_operand = g.UseImmediate(shift); + } else { + shift_operand = g.UseFixed(shift, ecx); + } + InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax), + g.UseFixed(node->InputAt(1), edx), + shift_operand}; + + InstructionOperand outputs[] = { + g.DefineAsFixed(node, eax), + g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)}; + + Emit(kIA32ShrPair, 2, outputs, 3, inputs); +} + +void InstructionSelector::VisitWord32PairSar(Node* node) { + IA32OperandGenerator g(this); + + Node* shift = node->InputAt(2); + InstructionOperand shift_operand; + if (g.CanBeImmediate(shift)) { + shift_operand = g.UseImmediate(shift); + } else { + shift_operand = g.UseFixed(shift, ecx); + } + InstructionOperand inputs[] = {g.UseFixed(node->InputAt(0), eax), + g.UseFixed(node->InputAt(1), edx), + shift_operand}; + + InstructionOperand outputs[] = { + g.DefineAsFixed(node, eax), + g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)}; + + Emit(kIA32SarPair, 2, outputs, 3, inputs); } void InstructionSelector::VisitWord32Ror(Node* node) { diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 5fc0f3c134..33d0ba0ab7 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -1154,6 +1154,14 @@ void InstructionSelector::VisitNode(Node* node) { MarkAsWord32(NodeProperties::FindProjection(node, 0)); MarkAsWord32(NodeProperties::FindProjection(node, 1)); return VisitWord32PairShl(node); + case IrOpcode::kWord32PairShr: + MarkAsWord32(NodeProperties::FindProjection(node, 0)); + MarkAsWord32(NodeProperties::FindProjection(node, 1)); + return VisitWord32PairShr(node); + case IrOpcode::kWord32PairSar: + MarkAsWord32(NodeProperties::FindProjection(node, 0)); + MarkAsWord32(NodeProperties::FindProjection(node, 1)); + return VisitWord32PairSar(node); default: V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d", node->opcode(), node->op()->mnemonic(), node->id()); @@ -1380,6 +1388,10 @@ void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) { // 32 bit targets do not implement the following instructions. #if V8_TARGET_ARCH_64_BIT void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); } + +void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); } + +void InstructionSelector::VisitWord32PairSar(Node* node) { UNIMPLEMENTED(); } #endif // V8_TARGET_ARCH_64_BIT void InstructionSelector::VisitFinishRegion(Node* node) { @@ -1460,6 +1472,8 @@ void InstructionSelector::VisitProjection(Node* node) { case IrOpcode::kTryTruncateFloat32ToUint64: case IrOpcode::kTryTruncateFloat64ToUint64: case IrOpcode::kWord32PairShl: + case IrOpcode::kWord32PairShr: + case IrOpcode::kWord32PairSar: if (ProjectionIndexOf(node->op()) == 0u) { Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value)); } else { diff --git a/src/compiler/int64-lowering.cc b/src/compiler/int64-lowering.cc index 7b0fa9e27f..4e592c1256 100644 --- a/src/compiler/int64-lowering.cc +++ b/src/compiler/int64-lowering.cc @@ -312,7 +312,51 @@ void Int64Lowering::LowerNode(Node* node) { break; } // kExprI64ShrU: + case IrOpcode::kWord64Shr: { + // TODO(turbofan): if the shift count >= 32, then we can set the low word + // of the output to 0 and just calculate the high word. + DCHECK(node->InputCount() == 2); + Node* shift = node->InputAt(1); + if (HasReplacementLow(shift)) { + // We do not have to care about the high word replacement, because + // the shift can only be between 0 and 63 anyways. + node->ReplaceInput(1, GetReplacementLow(shift)); + } + + Node* value = node->InputAt(0); + node->ReplaceInput(0, GetReplacementLow(value)); + node->InsertInput(zone(), 1, GetReplacementHigh(value)); + + NodeProperties::ChangeOp(node, machine()->Word32PairShr()); + // We access the additional return values through projections. + Node* low_node = graph()->NewNode(common()->Projection(0), node); + Node* high_node = graph()->NewNode(common()->Projection(1), node); + ReplaceNode(node, low_node, high_node); + break; + } // kExprI64ShrS: + case IrOpcode::kWord64Sar: { + // TODO(turbofan): if the shift count >= 32, then we can set the low word + // of the output to 0 and just calculate the high word. + DCHECK(node->InputCount() == 2); + Node* shift = node->InputAt(1); + if (HasReplacementLow(shift)) { + // We do not have to care about the high word replacement, because + // the shift can only be between 0 and 63 anyways. + node->ReplaceInput(1, GetReplacementLow(shift)); + } + + Node* value = node->InputAt(0); + node->ReplaceInput(0, GetReplacementLow(value)); + node->InsertInput(zone(), 1, GetReplacementHigh(value)); + + NodeProperties::ChangeOp(node, machine()->Word32PairSar()); + // We access the additional return values through projections. + Node* low_node = graph()->NewNode(common()->Projection(0), node); + Node* high_node = graph()->NewNode(common()->Projection(1), node); + ReplaceNode(node, low_node, high_node); + break; + } // kExprI64Eq: case IrOpcode::kWord64Equal: { DCHECK(node->InputCount() == 2); diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc index a2c5bc8b7c..cd23c3e3c0 100644 --- a/src/compiler/machine-operator.cc +++ b/src/compiler/machine-operator.cc @@ -196,7 +196,9 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) { V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \ V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \ V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1) \ - V(Word32PairShl, Operator::kNoProperties, 3, 0, 2) + V(Word32PairShl, Operator::kNoProperties, 3, 0, 2) \ + V(Word32PairShr, Operator::kNoProperties, 3, 0, 2) \ + V(Word32PairSar, Operator::kNoProperties, 3, 0, 2) #define PURE_OPTIONAL_OP_LIST(V) \ V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \ diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h index fda941743d..1ae0cef0a2 100644 --- a/src/compiler/machine-operator.h +++ b/src/compiler/machine-operator.h @@ -180,6 +180,8 @@ class MachineOperatorBuilder final : public ZoneObject { const Operator* Word64Equal(); const Operator* Word32PairShl(); + const Operator* Word32PairShr(); + const Operator* Word32PairSar(); const Operator* Int32Add(); const Operator* Int32AddWithOverflow(); diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc index 83dbdf6e42..3cd0dae3ce 100644 --- a/src/compiler/mips/instruction-selector-mips.cc +++ b/src/compiler/mips/instruction-selector-mips.cc @@ -397,6 +397,10 @@ void InstructionSelector::VisitWord32Sar(Node* node) { void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); } +void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); } + +void InstructionSelector::VisitWord32PairSar(Node* node) { UNIMPLEMENTED(); } + void InstructionSelector::VisitWord32Ror(Node* node) { VisitRRO(this, kMipsRor, node); } diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index ca292f82ae..eda8a0a2b7 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -334,7 +334,9 @@ V(LoadParentFramePointer) \ V(CheckedLoad) \ V(CheckedStore) \ - V(Word32PairShl) + V(Word32PairShl) \ + V(Word32PairShr) \ + V(Word32PairSar) #define VALUE_OP_LIST(V) \ COMMON_OP_LIST(V) \ diff --git a/src/compiler/ppc/instruction-selector-ppc.cc b/src/compiler/ppc/instruction-selector-ppc.cc index b7527258d8..15e6b86402 100644 --- a/src/compiler/ppc/instruction-selector-ppc.cc +++ b/src/compiler/ppc/instruction-selector-ppc.cc @@ -723,6 +723,11 @@ void InstructionSelector::VisitWord32Shr(Node* node) { VisitRRO(this, kPPC_ShiftRight32, node, kShift32Imm); } +#if !V8_TARGET_ARCH_PPC64 +void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); } + +void InstructionSelector::VisitWord32PairSar(Node* node) { UNIMPLEMENTED(); } +#endif #if V8_TARGET_ARCH_PPC64 void InstructionSelector::VisitWord64Shr(Node* node) { diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h index 82c323390a..affb02e91a 100644 --- a/src/compiler/raw-machine-assembler.h +++ b/src/compiler/raw-machine-assembler.h @@ -327,6 +327,12 @@ class RawMachineAssembler { Node* Word32PairShl(Node* low_word, Node* high_word, Node* shift) { return AddNode(machine()->Word32PairShl(), low_word, high_word, shift); } + Node* Word32PairShr(Node* low_word, Node* high_word, Node* shift) { + return AddNode(machine()->Word32PairShr(), low_word, high_word, shift); + } + Node* Word32PairSar(Node* low_word, Node* high_word, Node* shift) { + return AddNode(machine()->Word32PairSar(), low_word, high_word, shift); + } #define INTPTR_BINOP(prefix, name) \ Node* IntPtr##name(Node* a, Node* b) { \ diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 2a9f3bfad8..2477acb210 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -2443,6 +2443,10 @@ Type* Typer::Visitor::TypeCheckedStore(Node* node) { Type* Typer::Visitor::TypeWord32PairShl(Node* node) { return Type::Internal(); } +Type* Typer::Visitor::TypeWord32PairShr(Node* node) { return Type::Internal(); } + +Type* Typer::Visitor::TypeWord32PairSar(Node* node) { return Type::Internal(); } + // Heap constants. diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index a872811995..ff3b2efa45 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -952,6 +952,8 @@ void Verifier::Visitor::Check(Node* node) { case IrOpcode::kFloat64InsertLowWord32: case IrOpcode::kFloat64InsertHighWord32: case IrOpcode::kWord32PairShl: + case IrOpcode::kWord32PairShr: + case IrOpcode::kWord32PairSar: case IrOpcode::kLoadStackPointer: case IrOpcode::kLoadFramePointer: case IrOpcode::kLoadParentFramePointer: diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc index 3b8441a97a..80475ba006 100644 --- a/src/compiler/wasm-compiler.cc +++ b/src/compiler/wasm-compiler.cc @@ -511,7 +511,13 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, op = m->Word64Shl(); break; // kExprI64ShrU: + case wasm::kExprI64ShrU: + op = m->Word64Shr(); + break; // kExprI64ShrS: + case wasm::kExprI64ShrS: + op = m->Word64Sar(); + break; // kExprI64Eq: case wasm::kExprI64Eq: op = m->Word64Equal(); @@ -599,12 +605,6 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, op = m->Uint64Mod(); return graph()->NewNode(op, left, right, trap_->ZeroCheck64(kTrapRemByZero, right)); - case wasm::kExprI64ShrU: - op = m->Word64Shr(); - break; - case wasm::kExprI64ShrS: - op = m->Word64Sar(); - break; case wasm::kExprI64Ror: op = m->Word64Ror(); break; diff --git a/src/compiler/x87/instruction-selector-x87.cc b/src/compiler/x87/instruction-selector-x87.cc index ae67f5f9fc..a93906db55 100644 --- a/src/compiler/x87/instruction-selector-x87.cc +++ b/src/compiler/x87/instruction-selector-x87.cc @@ -565,6 +565,10 @@ void InstructionSelector::VisitWord32PairShl(Node* node) { Emit(kX87PairShl, 2, outputs, 3, inputs); } +void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); } + +void InstructionSelector::VisitWord32PairSar(Node* node) { UNIMPLEMENTED(); } + void InstructionSelector::VisitWord32Ror(Node* node) { VisitShift(this, node, kX87Ror); } diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index d8cd8e3045..88f6f9669d 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -1068,7 +1068,6 @@ void Assembler::sar_cl(const Operand& dst) { emit_operand(edi, dst); } - void Assembler::sbb(Register dst, const Operand& src) { EnsureSpace ensure_space(this); EMIT(0x1B); @@ -1112,15 +1111,6 @@ void Assembler::shl_cl(const Operand& dst) { emit_operand(esp, dst); } - -void Assembler::shrd(Register dst, const Operand& src) { - EnsureSpace ensure_space(this); - EMIT(0x0F); - EMIT(0xAD); - emit_operand(dst, src); -} - - void Assembler::shr(const Operand& dst, uint8_t imm8) { EnsureSpace ensure_space(this); DCHECK(is_uint5(imm8)); // illegal shift count @@ -1141,6 +1131,21 @@ void Assembler::shr_cl(const Operand& dst) { emit_operand(ebp, dst); } +void Assembler::shrd(Register dst, Register src, uint8_t shift) { + DCHECK(is_uint5(shift)); + EnsureSpace ensure_space(this); + EMIT(0x0F); + EMIT(0xAC); + emit_operand(dst, Operand(src)); + EMIT(shift); +} + +void Assembler::shrd_cl(const Operand& dst, Register src) { + EnsureSpace ensure_space(this); + EMIT(0x0F); + EMIT(0xAD); + emit_operand(src, dst); +} void Assembler::sub(const Operand& dst, const Immediate& x) { EnsureSpace ensure_space(this); diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index 890646abba..57179dd168 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -738,21 +738,20 @@ class Assembler : public AssemblerBase { void sbb(Register dst, const Operand& src); - void shld(Register dst, Register src, uint8_t shift); - void shld_cl(Register dst, Register src); - void shl(Register dst, uint8_t imm8) { shl(Operand(dst), imm8); } void shl(const Operand& dst, uint8_t imm8); void shl_cl(Register dst) { shl_cl(Operand(dst)); } void shl_cl(const Operand& dst); - - void shrd(Register dst, Register src) { shrd(dst, Operand(src)); } - void shrd(Register dst, const Operand& src); + void shld(Register dst, Register src, uint8_t shift); + void shld_cl(Register dst, Register src); void shr(Register dst, uint8_t imm8) { shr(Operand(dst), imm8); } void shr(const Operand& dst, uint8_t imm8); void shr_cl(Register dst) { shr_cl(Operand(dst)); } void shr_cl(const Operand& dst); + void shrd(Register dst, Register src, uint8_t shift); + void shrd_cl(Register dst, Register src) { shrd_cl(Operand(dst), src); } + void shrd_cl(const Operand& dst, Register src); void sub(Register dst, const Immediate& imm) { sub(Operand(dst), imm); } void sub(const Operand& dst, const Immediate& x); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index c4ccdfdf9d..8bc6a8800b 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -275,7 +275,7 @@ void DoubleToIStub::Generate(MacroAssembler* masm) { Immediate(static_cast(Double::kSignificandMask >> 32))); __ add(result_reg, Immediate(static_cast(Double::kHiddenBit >> 32))); - __ shrd(result_reg, scratch1); + __ shrd_cl(scratch1, result_reg); __ shr_cl(result_reg); __ test(ecx, Immediate(32)); __ cmov(not_equal, scratch1, result_reg); diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc index 722ac63f56..fab31ccd51 100644 --- a/src/ia32/disasm-ia32.cc +++ b/src/ia32/disasm-ia32.cc @@ -1484,7 +1484,8 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, data += SetCC(data); } else if ((f0byte & 0xF0) == 0x40) { data += CMov(data); - } else if (f0byte == 0xA4) { + } else if (f0byte == 0xA4 || f0byte == 0xAC) { + // shld, shrd data += 2; AppendToBuffer("%s ", f0mnem); int mod, regop, rm; @@ -1494,7 +1495,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector out_buffer, AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm), NameOfCPURegister(regop), static_cast(imm8)); } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { - // shrd, shld_cl, bts + // shrd_cl, shld_cl, bts data += 2; AppendToBuffer("%s ", f0mnem); int mod, regop, rm; diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 4d01e06674..87f0ea9677 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -706,25 +706,69 @@ void MacroAssembler::Cvtui2ss(XMMRegister dst, Register src, Register tmp) { bind(&jmp_return); } -void MacroAssembler::PairShl(Register dst, Register src, uint8_t shift) { +void MacroAssembler::ShlPair(Register high, Register low, uint8_t shift) { if (shift >= 32) { - mov(dst, src); - shl(dst, shift - 32); - xor_(src, src); + mov(high, low); + shl(high, shift - 32); + xor_(low, low); } else { - shld(dst, src, shift); - shl(src, shift); + shld(high, low, shift); + shl(low, shift); } } -void MacroAssembler::PairShl_cl(Register dst, Register src) { - shld_cl(dst, src); - shl_cl(src); +void MacroAssembler::ShlPair_cl(Register high, Register low) { + shld_cl(high, low); + shl_cl(low); Label done; test(ecx, Immediate(0x20)); j(equal, &done, Label::kNear); - mov(dst, src); - xor_(src, src); + mov(high, low); + xor_(low, low); + bind(&done); +} + +void MacroAssembler::ShrPair(Register high, Register low, uint8_t shift) { + if (shift >= 32) { + mov(low, high); + shr(low, shift - 32); + xor_(high, high); + } else { + shrd(high, low, shift); + shr(high, shift); + } +} + +void MacroAssembler::ShrPair_cl(Register high, Register low) { + shrd_cl(low, high); + shr_cl(high); + Label done; + test(ecx, Immediate(0x20)); + j(equal, &done, Label::kNear); + mov(low, high); + xor_(high, high); + bind(&done); +} + +void MacroAssembler::SarPair(Register high, Register low, uint8_t shift) { + if (shift >= 32) { + mov(low, high); + sar(low, shift - 32); + sar(high, 31); + } else { + shrd(high, low, shift); + sar(high, shift); + } +} + +void MacroAssembler::SarPair_cl(Register high, Register low) { + shrd_cl(low, high); + sar_cl(high); + Label done; + test(ecx, Immediate(0x20)); + j(equal, &done, Label::kNear); + mov(low, high); + sar(high, 31); bind(&done); } diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 342ca5c918..748d3edaeb 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -374,8 +374,12 @@ class MacroAssembler: public Assembler { void Cvtui2ss(XMMRegister dst, Register src, Register tmp); - void PairShl(Register dst, Register src, uint8_t imm8); - void PairShl_cl(Register dst, Register src); + void ShlPair(Register high, Register low, uint8_t imm8); + void ShlPair_cl(Register high, Register low); + void ShrPair(Register high, Register low, uint8_t imm8); + void ShrPair_cl(Register high, Register src); + void SarPair(Register high, Register low, uint8_t imm8); + void SarPair_cl(Register high, Register low); // Support for constant splitting. bool IsUnsafeImmediate(const Immediate& x); diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc index de8854b852..c999076ebb 100644 --- a/test/cctest/test-disasm-ia32.cc +++ b/test/cctest/test-disasm-ia32.cc @@ -121,7 +121,8 @@ TEST(DisasmIa320) { __ imul(edx, ecx); __ shld(edx, ecx, 10); __ shld_cl(edx, ecx); - __ shrd(edx, ecx); + __ shrd(edx, ecx, 10); + __ shrd_cl(edx, ecx); __ bts(edx, ecx); __ bts(Operand(ebx, ecx, times_4, 0), ecx); __ nop(); @@ -221,7 +222,7 @@ TEST(DisasmIa320) { __ shl(Operand(ebx, ecx, times_4, 10000), 1); __ shl(Operand(ebx, ecx, times_4, 10000), 6); __ shl_cl(Operand(ebx, ecx, times_4, 10000)); - __ shrd(edx, Operand(ebx, ecx, times_4, 10000)); + __ shrd_cl(Operand(ebx, ecx, times_4, 10000), edx); __ shr(edx, 1); __ shr(edx, 7); __ shr_cl(edx); diff --git a/test/cctest/wasm/test-run-wasm-64.cc b/test/cctest/wasm/test-run-wasm-64.cc index 08e1d51943..d9c0b6035d 100644 --- a/test/cctest/wasm/test-run-wasm-64.cc +++ b/test/cctest/wasm/test-run-wasm-64.cc @@ -85,7 +85,73 @@ TEST(Run_WasmI64Shl) { } #endif // kExprI64ShrU: +#if !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_X87 && !V8_TARGET_ARCH_ARM +TEST(Run_WasmI64ShrU) { + { + WasmRunner r(MachineType::Int64(), MachineType::Int64()); + BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + FOR_UINT64_INPUTS(i) { + for (int64_t j = 1; j < 64; j++) { + CHECK_EQ(*i >> j, r.Call(*i, j)); + } + } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(0))); + FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(32))); + FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(20))); + FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_I64V_1(40))); + FOR_UINT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); } + } +} +#endif // kExprI64ShrS: +#if !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_X87 && !V8_TARGET_ARCH_ARM +TEST(Run_WasmI64ShrS) { + { + WasmRunner r(MachineType::Int64(), MachineType::Int64()); + BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + FOR_INT64_INPUTS(i) { + for (int64_t j = 1; j < 64; j++) { + CHECK_EQ(*i >> j, r.Call(*i, j)); + } + } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(0))); + FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 0, r.Call(*i)); } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(32))); + FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 32, r.Call(*i)); } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(20))); + FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 20, r.Call(*i)); } + } + { + WasmRunner r(MachineType::Int64()); + BUILD(r, WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_I64V_1(40))); + FOR_INT64_INPUTS(i) { CHECK_EQ(*i >> 40, r.Call(*i)); } + } +} +#endif // kExprI64Eq: TEST(Run_WasmI64Eq) { WasmRunner r(MachineType::Int64(), MachineType::Int64()); diff --git a/test/unittests/compiler/int64-lowering-unittest.cc b/test/unittests/compiler/int64-lowering-unittest.cc index db4851386b..ad980ac3f6 100644 --- a/test/unittests/compiler/int64-lowering-unittest.cc +++ b/test/unittests/compiler/int64-lowering-unittest.cc @@ -350,7 +350,37 @@ TEST_F(Int64LoweringTest, Int64Shl) { start(), start())); } // kExprI64ShrU: +TEST_F(Int64LoweringTest, Int64ShrU) { + LowerGraph(graph()->NewNode(machine()->Word64Shr(), Int64Constant(value(0)), + Int64Constant(value(1))), + MachineRepresentation::kWord64); + + Capture shr; + Matcher shr_matcher = IsWord32PairShr( + IsInt32Constant(low_word_value(0)), IsInt32Constant(high_word_value(0)), + IsInt32Constant(low_word_value(1))); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsProjection(0, AllOf(CaptureEq(&shr), shr_matcher)), + IsProjection(1, AllOf(CaptureEq(&shr), shr_matcher)), + start(), start())); +} // kExprI64ShrS: +TEST_F(Int64LoweringTest, Int64ShrS) { + LowerGraph(graph()->NewNode(machine()->Word64Sar(), Int64Constant(value(0)), + Int64Constant(value(1))), + MachineRepresentation::kWord64); + + Capture sar; + Matcher sar_matcher = IsWord32PairSar( + IsInt32Constant(low_word_value(0)), IsInt32Constant(high_word_value(0)), + IsInt32Constant(low_word_value(1))); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsProjection(0, AllOf(CaptureEq(&sar), sar_matcher)), + IsProjection(1, AllOf(CaptureEq(&sar), sar_matcher)), + start(), start())); +} // kExprI64Eq: TEST_F(Int64LoweringTest, Int64Eq) { LowerGraph(graph()->NewNode(machine()->Word64Equal(), Int64Constant(value(0)), diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc index 3ce9c729e8..1bbbe3977c 100644 --- a/test/unittests/compiler/node-test-utils.cc +++ b/test/unittests/compiler/node-test-utils.cc @@ -2113,6 +2113,8 @@ Matcher IsLoadFramePointer() { } IS_TERNOP_MATCHER(Word32PairShl) +IS_TERNOP_MATCHER(Word32PairShr) +IS_TERNOP_MATCHER(Word32PairSar) #define IS_BINOP_MATCHER(Name) \ Matcher Is##Name(const Matcher& lhs_matcher, \ diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h index 463160e15f..1e86db3cb5 100644 --- a/test/unittests/compiler/node-test-utils.h +++ b/test/unittests/compiler/node-test-utils.h @@ -361,6 +361,13 @@ Matcher IsLoadFramePointer(); Matcher IsWord32PairShl(const Matcher& lhs_matcher, const Matcher& mid_matcher, const Matcher& rhs_matcher); +Matcher IsWord32PairShr(const Matcher& lhs_matcher, + const Matcher& mid_matcher, + const Matcher& rhs_matcher); + +Matcher IsWord32PairSar(const Matcher& lhs_matcher, + const Matcher& mid_matcher, + const Matcher& rhs_matcher); } // namespace compiler } // namespace internal