Commit ddc626e1 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Int64Lowering of I64Shl on ia32.

I64Shl is lowered to a new turbofan operator, WasmWord64Shl. The new
operator takes 3 inputs, the low-word input, the high-word input, and
the shift, and produces 2 output, the low-word output and the high-word
output.

At the moment I implemented the lowering only for ia32, but I think the
CL is already big enough. I will add the other platforms in separate
CLs.

R=titzer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#34546}
parent b455e2b2
...@@ -769,6 +769,7 @@ void InstructionSelector::VisitWord32Sar(Node* node) { ...@@ -769,6 +769,7 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
VisitShift(this, node, TryMatchASR); VisitShift(this, node, TryMatchASR);
} }
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitWord32Ror(Node* node) { void InstructionSelector::VisitWord32Ror(Node* node) {
VisitShift(this, node, TryMatchROR); VisitShift(this, node, TryMatchROR);
......
...@@ -632,6 +632,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -632,6 +632,14 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
__ sar_cl(i.OutputOperand()); __ sar_cl(i.OutputOperand());
} }
break; break;
case kIA32PairShl:
if (HasImmediateInput(instr, 2)) {
__ PairShl(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));
}
break;
case kIA32Ror: case kIA32Ror:
if (HasImmediateInput(instr, 1)) { if (HasImmediateInput(instr, 1)) {
__ ror(i.OutputOperand(), i.InputInt5(1)); __ ror(i.OutputOperand(), i.InputInt5(1));
......
...@@ -29,6 +29,7 @@ namespace compiler { ...@@ -29,6 +29,7 @@ namespace compiler {
V(IA32Shl) \ V(IA32Shl) \
V(IA32Shr) \ V(IA32Shr) \
V(IA32Sar) \ V(IA32Sar) \
V(IA32PairShl) \
V(IA32Ror) \ V(IA32Ror) \
V(IA32Lzcnt) \ V(IA32Lzcnt) \
V(IA32Tzcnt) \ V(IA32Tzcnt) \
...@@ -105,7 +106,6 @@ namespace compiler { ...@@ -105,7 +106,6 @@ namespace compiler {
V(IA32Poke) \ V(IA32Poke) \
V(IA32StackCheck) V(IA32StackCheck)
// Addressing modes represent the "shape" of inputs to an instruction. // Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes // Many instructions support multiple addressing modes. Addressing modes
// are encoded into the InstructionCode of the instruction and tell the // are encoded into the InstructionCode of the instruction and tell the
......
...@@ -31,6 +31,7 @@ int InstructionScheduler::GetTargetInstructionFlags( ...@@ -31,6 +31,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kIA32Shl: case kIA32Shl:
case kIA32Shr: case kIA32Shr:
case kIA32Sar: case kIA32Sar:
case kIA32PairShl:
case kIA32Ror: case kIA32Ror:
case kIA32Lzcnt: case kIA32Lzcnt:
case kIA32Tzcnt: case kIA32Tzcnt:
......
...@@ -585,6 +585,26 @@ void InstructionSelector::VisitWord32Sar(Node* node) { ...@@ -585,6 +585,26 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
VisitShift(this, node, kIA32Sar); VisitShift(this, node, kIA32Sar);
} }
void InstructionSelector::VisitWord32PairShl(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(kIA32PairShl, 2, outputs, 3, inputs);
}
void InstructionSelector::VisitWord32Ror(Node* node) { void InstructionSelector::VisitWord32Ror(Node* node) {
VisitShift(this, node, kIA32Ror); VisitShift(this, node, kIA32Ror);
......
...@@ -1150,6 +1150,10 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -1150,6 +1150,10 @@ void InstructionSelector::VisitNode(Node* node) {
} }
case IrOpcode::kCheckedStore: case IrOpcode::kCheckedStore:
return VisitCheckedStore(node); return VisitCheckedStore(node);
case IrOpcode::kWord32PairShl:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
return VisitWord32PairShl(node);
default: default:
V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d", V8_Fatal(__FILE__, __LINE__, "Unexpected operator #%d:%s @ node #%d",
node->opcode(), node->op()->mnemonic(), node->id()); node->opcode(), node->op()->mnemonic(), node->id());
...@@ -1373,6 +1377,10 @@ void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) { ...@@ -1373,6 +1377,10 @@ void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
#endif // V8_TARGET_ARCH_32_BIT #endif // V8_TARGET_ARCH_32_BIT
// 32 bit targets do not implement the following instructions.
#if V8_TARGET_ARCH_64_BIT
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
#endif // V8_TARGET_ARCH_64_BIT
void InstructionSelector::VisitFinishRegion(Node* node) { void InstructionSelector::VisitFinishRegion(Node* node) {
OperandGenerator g(this); OperandGenerator g(this);
...@@ -1451,6 +1459,7 @@ void InstructionSelector::VisitProjection(Node* node) { ...@@ -1451,6 +1459,7 @@ void InstructionSelector::VisitProjection(Node* node) {
case IrOpcode::kTryTruncateFloat64ToInt64: case IrOpcode::kTryTruncateFloat64ToInt64:
case IrOpcode::kTryTruncateFloat32ToUint64: case IrOpcode::kTryTruncateFloat32ToUint64:
case IrOpcode::kTryTruncateFloat64ToUint64: case IrOpcode::kTryTruncateFloat64ToUint64:
case IrOpcode::kWord32PairShl:
if (ProjectionIndexOf(node->op()) == 0u) { if (ProjectionIndexOf(node->op()) == 0u) {
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value)); Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
} else { } else {
......
...@@ -289,6 +289,28 @@ void Int64Lowering::LowerNode(Node* node) { ...@@ -289,6 +289,28 @@ void Int64Lowering::LowerNode(Node* node) {
break; break;
} }
// kExprI64Shl: // kExprI64Shl:
case IrOpcode::kWord64Shl: {
// 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()->Word32PairShl());
// 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;
}
// kExprI64ShrU: // kExprI64ShrU:
// kExprI64ShrS: // kExprI64ShrS:
// kExprI64Eq: // kExprI64Eq:
......
...@@ -195,7 +195,8 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) { ...@@ -195,7 +195,8 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \ V(Float64InsertHighWord32, Operator::kNoProperties, 2, 0, 1) \
V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \ V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \
V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \ V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \
V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1) V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1) \
V(Word32PairShl, Operator::kNoProperties, 3, 0, 2)
#define PURE_OPTIONAL_OP_LIST(V) \ #define PURE_OPTIONAL_OP_LIST(V) \
V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \ V(Word32Ctz, Operator::kNoProperties, 1, 0, 1) \
......
...@@ -179,6 +179,8 @@ class MachineOperatorBuilder final : public ZoneObject { ...@@ -179,6 +179,8 @@ class MachineOperatorBuilder final : public ZoneObject {
const OptionalOperator Word64Ctz(); const OptionalOperator Word64Ctz();
const Operator* Word64Equal(); const Operator* Word64Equal();
const Operator* Word32PairShl();
const Operator* Int32Add(); const Operator* Int32Add();
const Operator* Int32AddWithOverflow(); const Operator* Int32AddWithOverflow();
const Operator* Int32Sub(); const Operator* Int32Sub();
......
...@@ -397,6 +397,7 @@ void InstructionSelector::VisitWord32Sar(Node* node) { ...@@ -397,6 +397,7 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
VisitRRO(this, kMipsSar, node); VisitRRO(this, kMipsSar, node);
} }
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitWord32Ror(Node* node) { void InstructionSelector::VisitWord32Ror(Node* node) {
VisitRRO(this, kMipsRor, node); VisitRRO(this, kMipsRor, node);
......
...@@ -333,7 +333,8 @@ ...@@ -333,7 +333,8 @@
V(LoadFramePointer) \ V(LoadFramePointer) \
V(LoadParentFramePointer) \ V(LoadParentFramePointer) \
V(CheckedLoad) \ V(CheckedLoad) \
V(CheckedStore) V(CheckedStore) \
V(Word32PairShl)
#define VALUE_OP_LIST(V) \ #define VALUE_OP_LIST(V) \
COMMON_OP_LIST(V) \ COMMON_OP_LIST(V) \
......
...@@ -324,6 +324,9 @@ class RawMachineAssembler { ...@@ -324,6 +324,9 @@ class RawMachineAssembler {
Node* Uint64Mod(Node* a, Node* b) { Node* Uint64Mod(Node* a, Node* b) {
return AddNode(machine()->Uint64Mod(), a, b); return AddNode(machine()->Uint64Mod(), a, b);
} }
Node* Word32PairShl(Node* low_word, Node* high_word, Node* shift) {
return AddNode(machine()->Word32PairShl(), low_word, high_word, shift);
}
#define INTPTR_BINOP(prefix, name) \ #define INTPTR_BINOP(prefix, name) \
Node* IntPtr##name(Node* a, Node* b) { \ Node* IntPtr##name(Node* a, Node* b) { \
......
...@@ -2441,6 +2441,7 @@ Type* Typer::Visitor::TypeCheckedStore(Node* node) { ...@@ -2441,6 +2441,7 @@ Type* Typer::Visitor::TypeCheckedStore(Node* node) {
return nullptr; return nullptr;
} }
Type* Typer::Visitor::TypeWord32PairShl(Node* node) { return Type::Internal(); }
// Heap constants. // Heap constants.
......
...@@ -951,6 +951,7 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -951,6 +951,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kFloat64ExtractHighWord32: case IrOpcode::kFloat64ExtractHighWord32:
case IrOpcode::kFloat64InsertLowWord32: case IrOpcode::kFloat64InsertLowWord32:
case IrOpcode::kFloat64InsertHighWord32: case IrOpcode::kFloat64InsertHighWord32:
case IrOpcode::kWord32PairShl:
case IrOpcode::kLoadStackPointer: case IrOpcode::kLoadStackPointer:
case IrOpcode::kLoadFramePointer: case IrOpcode::kLoadFramePointer:
case IrOpcode::kLoadParentFramePointer: case IrOpcode::kLoadParentFramePointer:
......
...@@ -509,9 +509,12 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, ...@@ -509,9 +509,12 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
op = m->Word64Xor(); op = m->Word64Xor();
break; break;
// kExprI64Shl: // kExprI64Shl:
// kExprI64ShrU: case wasm::kExprI64Shl:
// kExprI64ShrS: op = m->Word64Shl();
// kExprI64Eq: break;
// kExprI64ShrU:
// kExprI64ShrS:
// kExprI64Eq:
case wasm::kExprI64Eq: case wasm::kExprI64Eq:
op = m->Word64Equal(); op = m->Word64Equal();
break; break;
...@@ -598,9 +601,6 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left, ...@@ -598,9 +601,6 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
op = m->Uint64Mod(); op = m->Uint64Mod();
return graph()->NewNode(op, left, right, return graph()->NewNode(op, left, right,
trap_->ZeroCheck64(kTrapRemByZero, right)); trap_->ZeroCheck64(kTrapRemByZero, right));
case wasm::kExprI64Shl:
op = m->Word64Shl();
break;
case wasm::kExprI64ShrU: case wasm::kExprI64ShrU:
op = m->Word64Shr(); op = m->Word64Shr();
break; break;
......
...@@ -546,6 +546,7 @@ void InstructionSelector::VisitWord32Sar(Node* node) { ...@@ -546,6 +546,7 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
VisitShift(this, node, kX87Sar); VisitShift(this, node, kX87Sar);
} }
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitWord32Ror(Node* node) { void InstructionSelector::VisitWord32Ror(Node* node) {
VisitShift(this, node, kX87Ror); VisitShift(this, node, kX87Ror);
......
...@@ -1075,12 +1075,20 @@ void Assembler::sbb(Register dst, const Operand& src) { ...@@ -1075,12 +1075,20 @@ void Assembler::sbb(Register dst, const Operand& src) {
emit_operand(dst, src); emit_operand(dst, src);
} }
void Assembler::shld(Register dst, Register src, uint8_t shift) {
DCHECK(is_uint5(shift));
EnsureSpace ensure_space(this);
EMIT(0x0F);
EMIT(0xA4);
emit_operand(src, Operand(dst));
EMIT(shift);
}
void Assembler::shld(Register dst, const Operand& src) { void Assembler::shld_cl(Register dst, Register src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
EMIT(0x0F); EMIT(0x0F);
EMIT(0xA5); EMIT(0xA5);
emit_operand(dst, src); emit_operand(src, Operand(dst));
} }
......
...@@ -738,8 +738,8 @@ class Assembler : public AssemblerBase { ...@@ -738,8 +738,8 @@ class Assembler : public AssemblerBase {
void sbb(Register dst, const Operand& src); void sbb(Register dst, const Operand& src);
void shld(Register dst, Register src) { shld(dst, Operand(src)); } void shld(Register dst, Register src, uint8_t shift);
void shld(Register dst, const Operand& src); void shld_cl(Register dst, Register src);
void shl(Register dst, uint8_t imm8) { shl(Operand(dst), imm8); } void shl(Register dst, uint8_t imm8) { shl(Operand(dst), imm8); }
void shl(const Operand& dst, uint8_t imm8); void shl(const Operand& dst, uint8_t imm8);
......
...@@ -1218,20 +1218,34 @@ static const char* F0Mnem(byte f0byte) { ...@@ -1218,20 +1218,34 @@ static const char* F0Mnem(byte f0byte) {
switch (f0byte) { switch (f0byte) {
case 0x0B: case 0x0B:
return "ud2"; return "ud2";
case 0x18: return "prefetch"; case 0x18:
case 0xA2: return "cpuid"; return "prefetch";
case 0xBE: return "movsx_b"; case 0xA2:
case 0xBF: return "movsx_w"; return "cpuid";
case 0xB6: return "movzx_b"; case 0xBE:
case 0xB7: return "movzx_w"; return "movsx_b";
case 0xAF: return "imul"; case 0xBF:
case 0xA5: return "shld"; return "movsx_w";
case 0xAD: return "shrd"; case 0xB6:
case 0xAC: return "shrd"; // 3-operand version. return "movzx_b";
case 0xAB: return "bts"; case 0xB7:
return "movzx_w";
case 0xAF:
return "imul";
case 0xA4:
return "shld";
case 0xA5:
return "shld";
case 0xAD:
return "shrd";
case 0xAC:
return "shrd"; // 3-operand version.
case 0xAB:
return "bts";
case 0xBC: case 0xBC:
return "bsf"; return "bsf";
case 0xBD: return "bsr"; case 0xBD:
return "bsr";
default: return NULL; default: return NULL;
} }
} }
...@@ -1470,8 +1484,17 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, ...@@ -1470,8 +1484,17 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
data += SetCC(data); data += SetCC(data);
} else if ((f0byte & 0xF0) == 0x40) { } else if ((f0byte & 0xF0) == 0x40) {
data += CMov(data); data += CMov(data);
} else if (f0byte == 0xA4) {
data += 2;
AppendToBuffer("%s ", f0mnem);
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
int8_t imm8 = static_cast<int8_t>(data[1]);
data += 2;
AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
NameOfCPURegister(regop), static_cast<int>(imm8));
} else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
// shrd, shld, bts // shrd, shld_cl, bts
data += 2; data += 2;
AppendToBuffer("%s ", f0mnem); AppendToBuffer("%s ", f0mnem);
int mod, regop, rm; int mod, regop, rm;
......
...@@ -682,7 +682,6 @@ void MacroAssembler::DebugBreak() { ...@@ -682,7 +682,6 @@ void MacroAssembler::DebugBreak() {
call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT); call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
} }
void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) { void MacroAssembler::Cvtsi2sd(XMMRegister dst, const Operand& src) {
xorps(dst, dst); xorps(dst, dst);
cvtsi2sd(dst, src); cvtsi2sd(dst, src);
...@@ -707,6 +706,27 @@ void MacroAssembler::Cvtui2ss(XMMRegister dst, Register src, Register tmp) { ...@@ -707,6 +706,27 @@ void MacroAssembler::Cvtui2ss(XMMRegister dst, Register src, Register tmp) {
bind(&jmp_return); bind(&jmp_return);
} }
void MacroAssembler::PairShl(Register dst, Register src, uint8_t shift) {
if (shift >= 32) {
mov(dst, src);
shl(dst, shift - 32);
xor_(src, src);
} else {
shld(dst, src, shift);
shl(src, shift);
}
}
void MacroAssembler::PairShl_cl(Register dst, Register src) {
shld_cl(dst, src);
shl_cl(src);
Label done;
test(ecx, Immediate(0x20));
j(equal, &done, Label::kNear);
mov(dst, src);
xor_(src, src);
bind(&done);
}
bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) { bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
static const int kMaxImmediateBits = 17; static const int kMaxImmediateBits = 17;
......
...@@ -370,6 +370,9 @@ class MacroAssembler: public Assembler { ...@@ -370,6 +370,9 @@ class MacroAssembler: public Assembler {
void Cvtui2ss(XMMRegister dst, Register src, Register tmp); void Cvtui2ss(XMMRegister dst, Register src, Register tmp);
void PairShl(Register dst, Register src, uint8_t imm8);
void PairShl_cl(Register dst, Register src);
// Support for constant splitting. // Support for constant splitting.
bool IsUnsafeImmediate(const Immediate& x); bool IsUnsafeImmediate(const Immediate& x);
void SafeMove(Register dst, const Immediate& x); void SafeMove(Register dst, const Immediate& x);
......
...@@ -119,7 +119,8 @@ TEST(DisasmIa320) { ...@@ -119,7 +119,8 @@ TEST(DisasmIa320) {
__ nop(); __ nop();
__ imul(edx, ecx); __ imul(edx, ecx);
__ shld(edx, ecx); __ shld(edx, ecx, 10);
__ shld_cl(edx, ecx);
__ shrd(edx, ecx); __ shrd(edx, ecx);
__ bts(edx, ecx); __ bts(edx, ecx);
__ bts(Operand(ebx, ecx, times_4, 0), ecx); __ bts(Operand(ebx, ecx, times_4, 0), ecx);
...@@ -214,7 +215,6 @@ TEST(DisasmIa320) { ...@@ -214,7 +215,6 @@ TEST(DisasmIa320) {
__ sar(Operand(ebx, ecx, times_4, 10000), 6); __ sar(Operand(ebx, ecx, times_4, 10000), 6);
__ sar_cl(Operand(ebx, ecx, times_4, 10000)); __ sar_cl(Operand(ebx, ecx, times_4, 10000));
__ sbb(edx, Operand(ebx, ecx, times_4, 10000)); __ sbb(edx, Operand(ebx, ecx, times_4, 10000));
__ shld(edx, Operand(ebx, ecx, times_4, 10000));
__ shl(edx, 1); __ shl(edx, 1);
__ shl(edx, 6); __ shl(edx, 6);
__ shl_cl(edx); __ shl_cl(edx);
......
...@@ -51,6 +51,39 @@ TEST(Run_WasmI64Xor) { ...@@ -51,6 +51,39 @@ TEST(Run_WasmI64Xor) {
} }
} }
// kExprI64Shl: // kExprI64Shl:
#if !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_X87 && !V8_TARGET_ARCH_ARM
TEST(Run_WasmI64Shl) {
{
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
BUILD(r, WASM_I64_SHL(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<int64_t> r(MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(0)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 0, r.Call(*i)); }
}
{
WasmRunner<int64_t> r(MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(32)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 32, r.Call(*i)); }
}
{
WasmRunner<int64_t> r(MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(20)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 20, r.Call(*i)); }
}
{
WasmRunner<int64_t> r(MachineType::Int64());
BUILD(r, WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_I64V_1(40)));
FOR_UINT64_INPUTS(i) { CHECK_EQ(*i << 40, r.Call(*i)); }
}
}
#endif
// kExprI64ShrU: // kExprI64ShrU:
// kExprI64ShrS: // kExprI64ShrS:
// kExprI64Eq: // kExprI64Eq:
......
...@@ -356,6 +356,23 @@ TEST_F(Int64LoweringTest, Int64Xor) { ...@@ -356,6 +356,23 @@ TEST_F(Int64LoweringTest, Int64Xor) {
start(), start())); start(), start()));
} }
// kExprI64Shl: // kExprI64Shl:
TEST_F(Int64LoweringTest, Int64Shl) {
if (4 != kPointerSize) return;
LowerGraph(graph()->NewNode(machine()->Word64Shl(), Int64Constant(value(0)),
Int64Constant(value(1))),
MachineRepresentation::kWord64);
Capture<Node*> shl;
Matcher<Node*> shl_matcher = IsWord32PairShl(
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(&shl), shl_matcher)),
IsProjection(1, AllOf(CaptureEq(&shl), shl_matcher)),
start(), start()));
}
// kExprI64ShrU: // kExprI64ShrU:
// kExprI64ShrS: // kExprI64ShrS:
// kExprI64Eq: // kExprI64Eq:
......
...@@ -1406,6 +1406,42 @@ class IsLoadContextMatcher final : public NodeMatcher { ...@@ -1406,6 +1406,42 @@ class IsLoadContextMatcher final : public NodeMatcher {
const Matcher<Node*> context_matcher_; const Matcher<Node*> context_matcher_;
}; };
class IsTernopMatcher final : public NodeMatcher {
public:
IsTernopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& mid_matcher,
const Matcher<Node*>& rhs_matcher)
: NodeMatcher(opcode),
lhs_matcher_(lhs_matcher),
mid_matcher_(mid_matcher),
rhs_matcher_(rhs_matcher) {}
void DescribeTo(std::ostream* os) const final {
NodeMatcher::DescribeTo(os);
*os << " whose lhs (";
lhs_matcher_.DescribeTo(os);
*os << ") and mid (";
mid_matcher_.DescribeTo(os);
*os << ") and rhs (";
rhs_matcher_.DescribeTo(os);
*os << ")";
}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
lhs_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "mid",
mid_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2), "rhs",
rhs_matcher_, listener));
}
private:
const Matcher<Node*> lhs_matcher_;
const Matcher<Node*> mid_matcher_;
const Matcher<Node*> rhs_matcher_;
};
class IsBinopMatcher final : public NodeMatcher { class IsBinopMatcher final : public NodeMatcher {
public: public:
...@@ -1484,7 +1520,6 @@ class IsParameterMatcher final : public NodeMatcher { ...@@ -1484,7 +1520,6 @@ class IsParameterMatcher final : public NodeMatcher {
} // namespace } // namespace
Matcher<Node*> IsDead() { Matcher<Node*> IsDead() {
return MakeMatcher(new NodeMatcher(IrOpcode::kDead)); return MakeMatcher(new NodeMatcher(IrOpcode::kDead));
} }
...@@ -2069,6 +2104,15 @@ Matcher<Node*> IsLoadFramePointer() { ...@@ -2069,6 +2104,15 @@ Matcher<Node*> IsLoadFramePointer() {
return MakeMatcher(new NodeMatcher(IrOpcode::kLoadFramePointer)); return MakeMatcher(new NodeMatcher(IrOpcode::kLoadFramePointer));
} }
#define IS_TERNOP_MATCHER(Name) \
Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \
const Matcher<Node*>& mid_matcher, \
const Matcher<Node*>& rhs_matcher) { \
return MakeMatcher(new IsTernopMatcher(IrOpcode::k##Name, lhs_matcher, \
mid_matcher, rhs_matcher)); \
}
IS_TERNOP_MATCHER(Word32PairShl)
#define IS_BINOP_MATCHER(Name) \ #define IS_BINOP_MATCHER(Name) \
Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \ Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \
......
...@@ -358,6 +358,10 @@ Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher); ...@@ -358,6 +358,10 @@ Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
Matcher<Node*> IsParameter(const Matcher<int> index_matcher); Matcher<Node*> IsParameter(const Matcher<int> index_matcher);
Matcher<Node*> IsLoadFramePointer(); Matcher<Node*> IsLoadFramePointer();
Matcher<Node*> IsWord32PairShl(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& mid_matcher,
const Matcher<Node*>& rhs_matcher);
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
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