Commit 498920f9 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Also optimize unsigned division by constant.

TEST=cctest,mjsunit,unittests
R=jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25061}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25061 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e634bdb2
...@@ -1126,6 +1126,14 @@ void MacroAssembler::Smulh(const Register& rd, ...@@ -1126,6 +1126,14 @@ void MacroAssembler::Smulh(const Register& rd,
} }
void MacroAssembler::Umull(const Register& rd, const Register& rn,
const Register& rm) {
DCHECK(allow_macro_instructions_);
DCHECK(!rd.IsZero());
umaddl(rd, rn, rm, xzr);
}
void MacroAssembler::Stnp(const CPURegister& rt, void MacroAssembler::Stnp(const CPURegister& rt,
const CPURegister& rt2, const CPURegister& rt2,
const MemOperand& dst) { const MemOperand& dst) {
......
...@@ -490,6 +490,7 @@ class MacroAssembler : public Assembler { ...@@ -490,6 +490,7 @@ class MacroAssembler : public Assembler {
inline void Smulh(const Register& rd, inline void Smulh(const Register& rd,
const Register& rn, const Register& rn,
const Register& rm); const Register& rm);
inline void Umull(const Register& rd, const Register& rn, const Register& rm);
inline void Stnp(const CPURegister& rt, inline void Stnp(const CPURegister& rt,
const CPURegister& rt2, const CPURegister& rt2,
const MemOperand& dst); const MemOperand& dst);
......
...@@ -248,6 +248,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -248,6 +248,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
i.InputRegister(2)); i.InputRegister(2));
DCHECK_EQ(LeaveCC, i.OutputSBit()); DCHECK_EQ(LeaveCC, i.OutputSBit());
break; break;
case kArmUmull:
__ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
i.InputRegister(1), i.OutputSBit());
break;
case kArmSdiv: { case kArmSdiv: {
CpuFeatureScope scope(masm(), SUDIV); CpuFeatureScope scope(masm(), SUDIV);
__ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1)); __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
......
...@@ -28,6 +28,7 @@ namespace compiler { ...@@ -28,6 +28,7 @@ namespace compiler {
V(ArmMls) \ V(ArmMls) \
V(ArmSmmul) \ V(ArmSmmul) \
V(ArmSmmla) \ V(ArmSmmla) \
V(ArmUmull) \
V(ArmSdiv) \ V(ArmSdiv) \
V(ArmUdiv) \ V(ArmUdiv) \
V(ArmMov) \ V(ArmMov) \
......
...@@ -86,6 +86,7 @@ class ArmOperandGenerator : public OperandGenerator { ...@@ -86,6 +86,7 @@ class ArmOperandGenerator : public OperandGenerator {
case kArmMls: case kArmMls:
case kArmSmmul: case kArmSmmul:
case kArmSmmla: case kArmSmmla:
case kArmUmull:
case kArmSdiv: case kArmSdiv:
case kArmUdiv: case kArmUdiv:
case kArmBfc: case kArmBfc:
...@@ -658,6 +659,15 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) { ...@@ -658,6 +659,15 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) {
} }
void InstructionSelector::VisitUint32MulHigh(Node* node) {
ArmOperandGenerator g(this);
InstructionOperand* outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
InstructionOperand* inputs[] = {g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1))};
Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
}
static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode, static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode, ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
InstructionOperand* result_operand, InstructionOperand* result_operand,
......
...@@ -267,6 +267,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -267,6 +267,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Smull: case kArm64Smull:
__ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1)); __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
break; break;
case kArm64Umull:
__ Umull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
break;
case kArm64Madd: case kArm64Madd:
__ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1), __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
i.InputRegister(2)); i.InputRegister(2));
......
...@@ -37,6 +37,7 @@ namespace compiler { ...@@ -37,6 +37,7 @@ namespace compiler {
V(Arm64Mul) \ V(Arm64Mul) \
V(Arm64Mul32) \ V(Arm64Mul32) \
V(Arm64Smull) \ V(Arm64Smull) \
V(Arm64Umull) \
V(Arm64Madd) \ V(Arm64Madd) \
V(Arm64Madd32) \ V(Arm64Madd32) \
V(Arm64Msub) \ V(Arm64Msub) \
......
...@@ -778,6 +778,16 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) { ...@@ -778,6 +778,16 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) {
} }
void InstructionSelector::VisitUint32MulHigh(Node* node) {
// TODO(arm64): Can we do better here?
Arm64OperandGenerator g(this);
InstructionOperand* const smull_operand = g.TempRegister();
Emit(kArm64Umull, smull_operand, g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1)));
Emit(kArm64Lsr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
}
void InstructionSelector::VisitInt32Div(Node* node) { void InstructionSelector::VisitInt32Div(Node* node) {
VisitRRR(this, kArm64Idiv32, node); VisitRRR(this, kArm64Idiv32, node);
} }
......
...@@ -53,7 +53,7 @@ Node* ChangeLowering::HeapNumberValueIndexConstant() { ...@@ -53,7 +53,7 @@ Node* ChangeLowering::HeapNumberValueIndexConstant() {
Node* ChangeLowering::SmiMaxValueConstant() { Node* ChangeLowering::SmiMaxValueConstant() {
const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize() const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize()
: SmiTagging<8>::SmiValueSize(); : SmiTagging<8>::SmiValueSize();
return jsgraph()->IntPtrConstant( return jsgraph()->Int32Constant(
-(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1)); -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
} }
......
...@@ -247,6 +247,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -247,6 +247,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kIA32ImulHigh: case kIA32ImulHigh:
__ imul(i.InputRegister(1)); __ imul(i.InputRegister(1));
break; break;
case kIA32UmulHigh:
__ mul(i.InputRegister(1));
break;
case kIA32Idiv: case kIA32Idiv:
__ cdq(); __ cdq();
__ idiv(i.InputOperand(1)); __ idiv(i.InputOperand(1));
......
...@@ -21,6 +21,7 @@ namespace compiler { ...@@ -21,6 +21,7 @@ namespace compiler {
V(IA32Sub) \ V(IA32Sub) \
V(IA32Imul) \ V(IA32Imul) \
V(IA32ImulHigh) \ V(IA32ImulHigh) \
V(IA32UmulHigh) \
V(IA32Idiv) \ V(IA32Idiv) \
V(IA32Udiv) \ V(IA32Udiv) \
V(IA32Not) \ V(IA32Not) \
......
...@@ -646,22 +646,43 @@ void InstructionSelector::VisitInt32Mul(Node* node) { ...@@ -646,22 +646,43 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
} }
void InstructionSelector::VisitInt32MulHigh(Node* node) { namespace {
IA32OperandGenerator g(this);
Emit(kIA32ImulHigh, g.DefineAsFixed(node, edx), void VisitMulHigh(InstructionSelector* selector, Node* node,
g.UseFixed(node->InputAt(0), eax), ArchOpcode opcode) {
g.UseUniqueRegister(node->InputAt(1))); IA32OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsFixed(node, edx),
g.UseFixed(node->InputAt(0), eax),
g.UseUniqueRegister(node->InputAt(1)));
} }
static inline void VisitDiv(InstructionSelector* selector, Node* node, void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
ArchOpcode opcode) {
IA32OperandGenerator g(selector); IA32OperandGenerator g(selector);
InstructionOperand* temps[] = {g.TempRegister(edx)}; InstructionOperand* temps[] = {g.TempRegister(edx)};
size_t temp_count = arraysize(temps);
selector->Emit(opcode, g.DefineAsFixed(node, eax), selector->Emit(opcode, g.DefineAsFixed(node, eax),
g.UseFixed(node->InputAt(0), eax), g.UseFixed(node->InputAt(0), eax),
g.UseUnique(node->InputAt(1)), temp_count, temps); g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
}
void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
IA32OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsFixed(node, edx),
g.UseFixed(node->InputAt(0), eax),
g.UseUnique(node->InputAt(1)));
}
} // namespace
void InstructionSelector::VisitInt32MulHigh(Node* node) {
VisitMulHigh(this, node, kIA32ImulHigh);
}
void InstructionSelector::VisitUint32MulHigh(Node* node) {
VisitMulHigh(this, node, kIA32UmulHigh);
} }
...@@ -675,15 +696,6 @@ void InstructionSelector::VisitUint32Div(Node* node) { ...@@ -675,15 +696,6 @@ void InstructionSelector::VisitUint32Div(Node* node) {
} }
static inline void VisitMod(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
IA32OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsFixed(node, edx),
g.UseFixed(node->InputAt(0), eax),
g.UseUnique(node->InputAt(1)));
}
void InstructionSelector::VisitInt32Mod(Node* node) { void InstructionSelector::VisitInt32Mod(Node* node) {
VisitMod(this, node, kIA32Idiv); VisitMod(this, node, kIA32Idiv);
} }
......
...@@ -738,6 +738,8 @@ void InstructionSelector::VisitNode(Node* node) { ...@@ -738,6 +738,8 @@ void InstructionSelector::VisitNode(Node* node) {
return VisitUint32LessThanOrEqual(node); return VisitUint32LessThanOrEqual(node);
case IrOpcode::kUint32Mod: case IrOpcode::kUint32Mod:
return VisitUint32Mod(node); return VisitUint32Mod(node);
case IrOpcode::kUint32MulHigh:
return VisitUint32MulHigh(node);
case IrOpcode::kInt64Add: case IrOpcode::kInt64Add:
return VisitInt64Add(node); return VisitInt64Add(node);
case IrOpcode::kInt64Sub: case IrOpcode::kInt64Sub:
......
...@@ -49,11 +49,13 @@ Node* MachineOperatorReducer::Word32And(Node* lhs, uint32_t rhs) { ...@@ -49,11 +49,13 @@ Node* MachineOperatorReducer::Word32And(Node* lhs, uint32_t rhs) {
Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) { Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
if (rhs == 0) return lhs;
return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs)); return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
} }
Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) { Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
if (rhs == 0) return lhs;
return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs)); return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
} }
...@@ -78,7 +80,8 @@ Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) { ...@@ -78,7 +80,8 @@ Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
} }
Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) { Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
DCHECK_NE(0, divisor);
DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor); DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
base::MagicNumbersForDivision<uint32_t> const mag = base::MagicNumbersForDivision<uint32_t> const mag =
base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor)); base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
...@@ -89,10 +92,25 @@ Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) { ...@@ -89,10 +92,25 @@ Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) {
} else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) { } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
quotient = Int32Sub(quotient, dividend); quotient = Int32Sub(quotient, dividend);
} }
if (mag.shift) { return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
quotient = Word32Sar(quotient, mag.shift); }
Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
DCHECK_LT(0, divisor);
base::MagicNumbersForDivision<uint32_t> const mag =
base::UnsignedDivisionByConstant(bit_cast<uint32_t>(divisor));
Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
Uint32Constant(mag.multiplier));
if (mag.add) {
DCHECK_LE(1, mag.shift);
quotient = Word32Shr(
Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
mag.shift - 1);
} else {
quotient = Word32Shr(quotient, mag.shift);
} }
return Int32Add(quotient, Word32Shr(dividend, 31)); return quotient;
} }
...@@ -572,7 +590,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { ...@@ -572,7 +590,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend); quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
quotient = Word32Sar(quotient, shift); quotient = Word32Sar(quotient, shift);
} else { } else {
quotient = TruncatingDiv(quotient, Abs(divisor)); quotient = Int32Div(quotient, Abs(divisor));
} }
if (divisor < 0) { if (divisor < 0) {
node->set_op(machine()->Int32Sub()); node->set_op(machine()->Int32Sub());
...@@ -600,11 +618,17 @@ Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) { ...@@ -600,11 +618,17 @@ Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
Node* const zero = Int32Constant(0); Node* const zero = Int32Constant(0);
return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero)); return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
} }
if (m.right().IsPowerOf2()) { // x / 2^n => x >> n if (m.right().HasValue()) {
node->TrimInputCount(2); Node* const dividend = m.left().node();
node->set_op(machine()->Word32Shr()); uint32_t const divisor = m.right().Value();
node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value()))); if (base::bits::IsPowerOfTwo32(divisor)) { // x / 2^n => x >> n
return Changed(node); node->set_op(machine()->Word32Shr());
node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
node->TrimInputCount(2);
return Changed(node);
} else {
return Replace(Uint32Div(dividend, divisor));
}
} }
return NoChange(); return NoChange();
} }
...@@ -640,17 +664,20 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) { ...@@ -640,17 +664,20 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
Node* pos = Word32And(dividend, mask); Node* pos = Word32And(dividend, mask);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* phi =
graph()->NewNode(common()->Phi(kMachInt32, 2), neg, pos, merge); DCHECK_EQ(3, node->InputCount());
return Replace(phi); node->set_op(common()->Phi(kMachInt32, 2));
node->ReplaceInput(0, neg);
node->ReplaceInput(1, pos);
node->ReplaceInput(2, merge);
} else { } else {
Node* quotient = TruncatingDiv(dividend, divisor); Node* quotient = Int32Div(dividend, divisor);
node->set_op(machine()->Int32Sub()); node->set_op(machine()->Int32Sub());
DCHECK_EQ(dividend, node->InputAt(0)); DCHECK_EQ(dividend, node->InputAt(0));
node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor))); node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
node->TrimInputCount(2); node->TrimInputCount(2);
return Changed(node);
} }
return Changed(node);
} }
return NoChange(); return NoChange();
} }
...@@ -666,10 +693,19 @@ Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) { ...@@ -666,10 +693,19 @@ Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
return ReplaceUint32( return ReplaceUint32(
base::bits::UnsignedMod32(m.left().Value(), m.right().Value())); base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
} }
if (m.right().IsPowerOf2()) { // x % 2^n => x & 2^n-1 if (m.right().HasValue()) {
Node* const dividend = m.left().node();
uint32_t const divisor = m.right().Value();
if (base::bits::IsPowerOfTwo32(divisor)) { // x % 2^n => x & 2^n-1
node->set_op(machine()->Word32And());
node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
} else {
Node* quotient = Uint32Div(dividend, divisor);
node->set_op(machine()->Int32Sub());
DCHECK_EQ(dividend, node->InputAt(0));
node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
}
node->TrimInputCount(2); node->TrimInputCount(2);
node->set_op(machine()->Word32And());
node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
return Changed(node); return Changed(node);
} }
return NoChange(); return NoChange();
......
...@@ -41,8 +41,8 @@ class MachineOperatorReducer FINAL : public Reducer { ...@@ -41,8 +41,8 @@ class MachineOperatorReducer FINAL : public Reducer {
Node* Int32Add(Node* lhs, Node* rhs); Node* Int32Add(Node* lhs, Node* rhs);
Node* Int32Sub(Node* lhs, Node* rhs); Node* Int32Sub(Node* lhs, Node* rhs);
Node* Int32Mul(Node* lhs, Node* rhs); Node* Int32Mul(Node* lhs, Node* rhs);
Node* Int32Div(Node* dividend, int32_t divisor);
Node* TruncatingDiv(Node* dividend, int32_t divisor); Node* Uint32Div(Node* dividend, uint32_t divisor);
Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); } Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); }
Reduction ReplaceFloat32(volatile float value) { Reduction ReplaceFloat32(volatile float value) {
......
...@@ -84,6 +84,7 @@ StoreRepresentation const& StoreRepresentationOf(Operator const* op) { ...@@ -84,6 +84,7 @@ StoreRepresentation const& StoreRepresentationOf(Operator const* op) {
V(Uint32LessThan, Operator::kNoProperties, 2, 0, 1) \ V(Uint32LessThan, Operator::kNoProperties, 2, 0, 1) \
V(Uint32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \ V(Uint32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1) \
V(Uint32Mod, Operator::kNoProperties, 2, 1, 1) \ V(Uint32Mod, Operator::kNoProperties, 2, 1, 1) \
V(Uint32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
V(Int64Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ V(Int64Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
V(Int64Sub, Operator::kNoProperties, 2, 0, 1) \ V(Int64Sub, Operator::kNoProperties, 2, 0, 1) \
V(Int64Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \ V(Int64Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
......
...@@ -108,6 +108,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject { ...@@ -108,6 +108,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
const Operator* Uint32LessThan(); const Operator* Uint32LessThan();
const Operator* Uint32LessThanOrEqual(); const Operator* Uint32LessThanOrEqual();
const Operator* Uint32Mod(); const Operator* Uint32Mod();
const Operator* Uint32MulHigh();
bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; } bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; }
bool Int32ModIsSafe() const { return flags_ & kInt32ModIsSafe; } bool Int32ModIsSafe() const { return flags_ & kInt32ModIsSafe; }
bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; } bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; }
......
...@@ -198,6 +198,7 @@ ...@@ -198,6 +198,7 @@
V(Uint32LessThan) \ V(Uint32LessThan) \
V(Uint32LessThanOrEqual) \ V(Uint32LessThanOrEqual) \
V(Uint32Mod) \ V(Uint32Mod) \
V(Uint32MulHigh) \
V(Int64Add) \ V(Int64Add) \
V(Int64Sub) \ V(Int64Sub) \
V(Int64Mul) \ V(Int64Mul) \
......
...@@ -102,14 +102,15 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -102,14 +102,15 @@ class RawMachineAssembler : public GraphBuilder {
return Load(rep, base, Int32Constant(0)); return Load(rep, base, Int32Constant(0));
} }
Node* Load(MachineType rep, Node* base, Node* index) { Node* Load(MachineType rep, Node* base, Node* index) {
return NewNode(machine()->Load(rep), base, index); return NewNode(machine()->Load(rep), base, index, graph()->start(),
graph()->start());
} }
void Store(MachineType rep, Node* base, Node* value) { void Store(MachineType rep, Node* base, Node* value) {
Store(rep, base, Int32Constant(0), value); Store(rep, base, Int32Constant(0), value);
} }
void Store(MachineType rep, Node* base, Node* index, Node* value) { void Store(MachineType rep, Node* base, Node* index, Node* value) {
NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base, NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base,
index, value); index, value, graph()->start(), graph()->start());
} }
// Arithmetic Operations. // Arithmetic Operations.
Node* WordAnd(Node* a, Node* b) { Node* WordAnd(Node* a, Node* b) {
...@@ -231,10 +232,10 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -231,10 +232,10 @@ class RawMachineAssembler : public GraphBuilder {
return NewNode(machine()->Int32MulHigh(), a, b); return NewNode(machine()->Int32MulHigh(), a, b);
} }
Node* Int32Div(Node* a, Node* b) { Node* Int32Div(Node* a, Node* b) {
return NewNode(machine()->Int32Div(), a, b); return NewNode(machine()->Int32Div(), a, b, graph()->start());
} }
Node* Int32Mod(Node* a, Node* b) { Node* Int32Mod(Node* a, Node* b) {
return NewNode(machine()->Int32Mod(), a, b); return NewNode(machine()->Int32Mod(), a, b, graph()->start());
} }
Node* Int32LessThan(Node* a, Node* b) { Node* Int32LessThan(Node* a, Node* b) {
return NewNode(machine()->Int32LessThan(), a, b); return NewNode(machine()->Int32LessThan(), a, b);
...@@ -243,7 +244,7 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -243,7 +244,7 @@ class RawMachineAssembler : public GraphBuilder {
return NewNode(machine()->Int32LessThanOrEqual(), a, b); return NewNode(machine()->Int32LessThanOrEqual(), a, b);
} }
Node* Uint32Div(Node* a, Node* b) { Node* Uint32Div(Node* a, Node* b) {
return NewNode(machine()->Uint32Div(), a, b); return NewNode(machine()->Uint32Div(), a, b, graph()->start());
} }
Node* Uint32LessThan(Node* a, Node* b) { Node* Uint32LessThan(Node* a, Node* b) {
return NewNode(machine()->Uint32LessThan(), a, b); return NewNode(machine()->Uint32LessThan(), a, b);
...@@ -252,7 +253,10 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -252,7 +253,10 @@ class RawMachineAssembler : public GraphBuilder {
return NewNode(machine()->Uint32LessThanOrEqual(), a, b); return NewNode(machine()->Uint32LessThanOrEqual(), a, b);
} }
Node* Uint32Mod(Node* a, Node* b) { Node* Uint32Mod(Node* a, Node* b) {
return NewNode(machine()->Uint32Mod(), a, b); return NewNode(machine()->Uint32Mod(), a, b, graph()->start());
}
Node* Uint32MulHigh(Node* a, Node* b) {
return NewNode(machine()->Uint32MulHigh(), a, b);
} }
Node* Int32GreaterThan(Node* a, Node* b) { return Int32LessThan(b, a); } Node* Int32GreaterThan(Node* a, Node* b) { return Int32LessThan(b, a); }
Node* Int32GreaterThanOrEqual(Node* a, Node* b) { Node* Int32GreaterThanOrEqual(Node* a, Node* b) {
......
...@@ -857,11 +857,13 @@ class RepresentationSelector { ...@@ -857,11 +857,13 @@ class RepresentationSelector {
case IrOpcode::kInt32Add: case IrOpcode::kInt32Add:
case IrOpcode::kInt32Sub: case IrOpcode::kInt32Sub:
case IrOpcode::kInt32Mul: case IrOpcode::kInt32Mul:
case IrOpcode::kInt32MulHigh:
case IrOpcode::kInt32Div: case IrOpcode::kInt32Div:
case IrOpcode::kInt32Mod: case IrOpcode::kInt32Mod:
return VisitInt32Binop(node); return VisitInt32Binop(node);
case IrOpcode::kUint32Div: case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod: case IrOpcode::kUint32Mod:
case IrOpcode::kUint32MulHigh:
return VisitUint32Binop(node); return VisitUint32Binop(node);
case IrOpcode::kInt32LessThan: case IrOpcode::kInt32LessThan:
case IrOpcode::kInt32LessThanOrEqual: case IrOpcode::kInt32LessThanOrEqual:
......
...@@ -1606,7 +1606,7 @@ Bounds Typer::Visitor::TypeInt32Mul(Node* node) { ...@@ -1606,7 +1606,7 @@ Bounds Typer::Visitor::TypeInt32Mul(Node* node) {
Bounds Typer::Visitor::TypeInt32MulHigh(Node* node) { Bounds Typer::Visitor::TypeInt32MulHigh(Node* node) {
return Bounds(Type::Integral32()); return Bounds(Type::Signed32());
} }
...@@ -1650,6 +1650,11 @@ Bounds Typer::Visitor::TypeUint32Mod(Node* node) { ...@@ -1650,6 +1650,11 @@ Bounds Typer::Visitor::TypeUint32Mod(Node* node) {
} }
Bounds Typer::Visitor::TypeUint32MulHigh(Node* node) {
return Bounds(Type::Unsigned32());
}
Bounds Typer::Visitor::TypeInt64Add(Node* node) { Bounds Typer::Visitor::TypeInt64Add(Node* node) {
return Bounds(Type::Internal()); return Bounds(Type::Internal());
} }
......
...@@ -688,6 +688,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) { ...@@ -688,6 +688,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
case IrOpcode::kInt32LessThanOrEqual: case IrOpcode::kInt32LessThanOrEqual:
case IrOpcode::kUint32Div: case IrOpcode::kUint32Div:
case IrOpcode::kUint32Mod: case IrOpcode::kUint32Mod:
case IrOpcode::kUint32MulHigh:
case IrOpcode::kUint32LessThan: case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual: case IrOpcode::kUint32LessThanOrEqual:
case IrOpcode::kInt64Add: case IrOpcode::kInt64Add:
......
...@@ -289,7 +289,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -289,7 +289,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ASSEMBLE_MULT(imulq); ASSEMBLE_MULT(imulq);
break; break;
case kX64ImulHigh32: case kX64ImulHigh32:
__ imull(i.InputRegister(1)); if (instr->InputAt(1)->IsRegister()) {
__ imull(i.InputRegister(1));
} else {
__ imull(i.InputOperand(1));
}
break;
case kX64UmulHigh32:
if (instr->InputAt(1)->IsRegister()) {
__ mull(i.InputRegister(1));
} else {
__ mull(i.InputOperand(1));
}
break; break;
case kX64Idiv32: case kX64Idiv32:
__ cdq(); __ cdq();
......
...@@ -29,6 +29,7 @@ namespace compiler { ...@@ -29,6 +29,7 @@ namespace compiler {
V(X64Imul) \ V(X64Imul) \
V(X64Imul32) \ V(X64Imul32) \
V(X64ImulHigh32) \ V(X64ImulHigh32) \
V(X64UmulHigh32) \
V(X64Idiv) \ V(X64Idiv) \
V(X64Idiv32) \ V(X64Idiv32) \
V(X64Udiv) \ V(X64Udiv) \
......
...@@ -405,6 +405,36 @@ void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) { ...@@ -405,6 +405,36 @@ void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
} }
} }
void VisitMulHigh(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
X64OperandGenerator g(selector);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
if (selector->IsLive(left) && !selector->IsLive(right)) {
std::swap(left, right);
}
selector->Emit(opcode, g.DefineAsFixed(node, rdx), g.UseFixed(left, rax),
g.UseUnique(right));
}
void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
X64OperandGenerator g(selector);
InstructionOperand* temps[] = {g.TempRegister(rdx)};
selector->Emit(
opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
}
void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
X64OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsFixed(node, rdx),
g.UseFixed(node->InputAt(0), rax),
g.UseUniqueRegister(node->InputAt(1)));
}
} // namespace } // namespace
...@@ -419,20 +449,7 @@ void InstructionSelector::VisitInt64Mul(Node* node) { ...@@ -419,20 +449,7 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
void InstructionSelector::VisitInt32MulHigh(Node* node) { void InstructionSelector::VisitInt32MulHigh(Node* node) {
X64OperandGenerator g(this); VisitMulHigh(this, node, kX64ImulHigh32);
Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx),
g.UseFixed(node->InputAt(0), rax),
g.UseUniqueRegister(node->InputAt(1)));
}
static void VisitDiv(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
X64OperandGenerator g(selector);
InstructionOperand* temps[] = {g.TempRegister(rdx)};
selector->Emit(
opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
} }
...@@ -456,15 +473,6 @@ void InstructionSelector::VisitUint64Div(Node* node) { ...@@ -456,15 +473,6 @@ void InstructionSelector::VisitUint64Div(Node* node) {
} }
static void VisitMod(InstructionSelector* selector, Node* node,
ArchOpcode opcode) {
X64OperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsFixed(node, rdx),
g.UseFixed(node->InputAt(0), rax),
g.UseUniqueRegister(node->InputAt(1)));
}
void InstructionSelector::VisitInt32Mod(Node* node) { void InstructionSelector::VisitInt32Mod(Node* node) {
VisitMod(this, node, kX64Idiv32); VisitMod(this, node, kX64Idiv32);
} }
...@@ -485,6 +493,11 @@ void InstructionSelector::VisitUint64Mod(Node* node) { ...@@ -485,6 +493,11 @@ void InstructionSelector::VisitUint64Mod(Node* node) {
} }
void InstructionSelector::VisitUint32MulHigh(Node* node) {
VisitMulHigh(this, node, kX64UmulHigh32);
}
void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) { void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
X64OperandGenerator g(this); X64OperandGenerator g(this);
Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0))); Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
...@@ -544,7 +557,8 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { ...@@ -544,7 +557,8 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
case IrOpcode::kUint32Div: case IrOpcode::kUint32Div:
case IrOpcode::kUint32LessThan: case IrOpcode::kUint32LessThan:
case IrOpcode::kUint32LessThanOrEqual: case IrOpcode::kUint32LessThanOrEqual:
case IrOpcode::kUint32Mod: { case IrOpcode::kUint32Mod:
case IrOpcode::kUint32MulHigh: {
// These 32-bit operations implicitly zero-extend to 64-bit on x64, so the // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the
// zero-extension is a no-op. // zero-extension is a no-op.
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value)); Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
......
...@@ -935,6 +935,14 @@ void Assembler::emit_imul(Register src, int size) { ...@@ -935,6 +935,14 @@ void Assembler::emit_imul(Register src, int size) {
} }
void Assembler::emit_imul(const Operand& src, int size) {
EnsureSpace ensure_space(this);
emit_rex(src, size);
emit(0xF7);
emit_operand(0x5, src);
}
void Assembler::emit_imul(Register dst, Register src, int size) { void Assembler::emit_imul(Register dst, Register src, int size) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
emit_rex(dst, src, size); emit_rex(dst, src, size);
...@@ -1499,7 +1507,23 @@ void Assembler::emit_repmovs(int size) { ...@@ -1499,7 +1507,23 @@ void Assembler::emit_repmovs(int size) {
} }
void Assembler::mul(Register src) { void Assembler::mull(Register src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(src);
emit(0xF7);
emit_modrm(0x4, src);
}
void Assembler::mull(const Operand& src) {
EnsureSpace ensure_space(this);
emit_optional_rex_32(src);
emit(0xF7);
emit_operand(0x4, src);
}
void Assembler::mulq(Register src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
emit_rex_64(src); emit_rex_64(src);
emit(0xF7); emit(0xF7);
......
...@@ -810,8 +810,11 @@ class Assembler : public AssemblerBase { ...@@ -810,8 +810,11 @@ class Assembler : public AssemblerBase {
// Sign-extends eax into edx:eax. // Sign-extends eax into edx:eax.
void cdq(); void cdq();
// Multiply eax by src, put the result in edx:eax.
void mull(Register src);
void mull(const Operand& src);
// Multiply rax by src, put the result in rdx:rax. // Multiply rax by src, put the result in rdx:rax.
void mul(Register src); void mulq(Register src);
#define DECLARE_SHIFT_INSTRUCTION(instruction, subcode) \ #define DECLARE_SHIFT_INSTRUCTION(instruction, subcode) \
void instruction##p(Register dst, Immediate imm8) { \ void instruction##p(Register dst, Immediate imm8) { \
...@@ -1473,6 +1476,7 @@ class Assembler : public AssemblerBase { ...@@ -1473,6 +1476,7 @@ class Assembler : public AssemblerBase {
// Signed multiply instructions. // Signed multiply instructions.
// rdx:rax = rax * src when size is 64 or edx:eax = eax * src when size is 32. // rdx:rax = rax * src when size is 64 or edx:eax = eax * src when size is 32.
void emit_imul(Register src, int size); void emit_imul(Register src, int size);
void emit_imul(const Operand& src, int size);
void emit_imul(Register dst, Register src, int size); void emit_imul(Register dst, Register src, int size);
void emit_imul(Register dst, const Operand& src, int size); void emit_imul(Register dst, const Operand& src, int size);
void emit_imul(Register dst, Register src, Immediate imm, int size); void emit_imul(Register dst, Register src, Immediate imm, int size);
......
...@@ -61,16 +61,16 @@ TEST(CodeGenInt32Binop) { ...@@ -61,16 +61,16 @@ TEST(CodeGenInt32Binop) {
RawMachineAssemblerTester<void> m; RawMachineAssemblerTester<void> m;
const Operator* kOps[] = { const Operator* kOps[] = {
m.machine()->Word32And(), m.machine()->Word32Or(), m.machine()->Word32And(), m.machine()->Word32Or(),
m.machine()->Word32Xor(), m.machine()->Word32Shl(), m.machine()->Word32Xor(), m.machine()->Word32Shl(),
m.machine()->Word32Shr(), m.machine()->Word32Sar(), m.machine()->Word32Shr(), m.machine()->Word32Sar(),
m.machine()->Word32Equal(), m.machine()->Int32Add(), m.machine()->Word32Equal(), m.machine()->Int32Add(),
m.machine()->Int32Sub(), m.machine()->Int32Mul(), m.machine()->Int32Sub(), m.machine()->Int32Mul(),
m.machine()->Int32MulHigh(), m.machine()->Int32Div(), m.machine()->Int32MulHigh(), m.machine()->Int32Div(),
m.machine()->Uint32Div(), m.machine()->Int32Mod(), m.machine()->Uint32Div(), m.machine()->Int32Mod(),
m.machine()->Uint32Mod(), m.machine()->Int32LessThan(), m.machine()->Uint32Mod(), m.machine()->Uint32MulHigh(),
m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(), m.machine()->Int32LessThan(), m.machine()->Int32LessThanOrEqual(),
m.machine()->Uint32LessThanOrEqual()}; m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual()};
for (size_t i = 0; i < arraysize(kOps); ++i) { for (size_t i = 0; i < arraysize(kOps); ++i) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
...@@ -1500,6 +1500,20 @@ TEST(RunInt32MulAndInt32SubP) { ...@@ -1500,6 +1500,20 @@ TEST(RunInt32MulAndInt32SubP) {
} }
TEST(RunUint32MulHighP) {
RawMachineAssemblerTester<int32_t> m;
Int32BinopTester bt(&m);
bt.AddReturn(m.Uint32MulHigh(bt.param0, bt.param1));
FOR_UINT32_INPUTS(i) {
FOR_UINT32_INPUTS(j) {
int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(
(static_cast<uint64_t>(*i) * static_cast<uint64_t>(*j)) >> 32));
CHECK_EQ(expected, bt.call(bit_cast<int32_t>(*i), bit_cast<int32_t>(*j)));
}
}
}
TEST(RunInt32DivP) { TEST(RunInt32DivP) {
{ {
RawMachineAssemblerTester<int32_t> m; RawMachineAssemblerTester<int32_t> m;
...@@ -2812,16 +2826,17 @@ TEST(RunDeadInt32Binops) { ...@@ -2812,16 +2826,17 @@ TEST(RunDeadInt32Binops) {
RawMachineAssemblerTester<int32_t> m; RawMachineAssemblerTester<int32_t> m;
const Operator* kOps[] = { const Operator* kOps[] = {
m.machine()->Word32And(), m.machine()->Word32Or(), m.machine()->Word32And(), m.machine()->Word32Or(),
m.machine()->Word32Xor(), m.machine()->Word32Shl(), m.machine()->Word32Xor(), m.machine()->Word32Shl(),
m.machine()->Word32Shr(), m.machine()->Word32Sar(), m.machine()->Word32Shr(), m.machine()->Word32Sar(),
m.machine()->Word32Ror(), m.machine()->Word32Equal(), m.machine()->Word32Ror(), m.machine()->Word32Equal(),
m.machine()->Int32Add(), m.machine()->Int32Sub(), m.machine()->Int32Add(), m.machine()->Int32Sub(),
m.machine()->Int32Mul(), m.machine()->Int32MulHigh(), m.machine()->Int32Mul(), m.machine()->Int32MulHigh(),
m.machine()->Int32Div(), m.machine()->Uint32Div(), m.machine()->Int32Div(), m.machine()->Uint32Div(),
m.machine()->Int32Mod(), m.machine()->Uint32Mod(), m.machine()->Int32Mod(), m.machine()->Uint32Mod(),
m.machine()->Int32LessThan(), m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32MulHigh(), m.machine()->Int32LessThan(),
m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual()}; m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
m.machine()->Uint32LessThanOrEqual()};
for (size_t i = 0; i < arraysize(kOps); ++i) { for (size_t i = 0; i < arraysize(kOps); ++i) {
RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32); RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
......
...@@ -179,7 +179,8 @@ TEST(DisasmX64) { ...@@ -179,7 +179,8 @@ TEST(DisasmX64) {
__ nop(); __ nop();
__ idivq(rdx); __ idivq(rdx);
__ mul(rdx); __ mull(rdx);
__ mulq(rdx);
__ negq(rdx); __ negq(rdx);
__ notq(rdx); __ notq(rdx);
__ testq(Operand(rbx, rcx, times_4, 10000), rdx); __ testq(Operand(rbx, rcx, times_4, 10000), rdx);
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var stdlib = {};
var foreign = {};
var heap = new ArrayBuffer(64 * 1024);
function Uint32Div(divisor) {
var name = "div_";
name += divisor;
var m = eval("function Module(stdlib, foreign, heap) {\n"
+ " \"use asm\";\n"
+ " function " + name + "(dividend) {\n"
+ " return ((dividend >>> 0) / " + divisor + ") >>> 0;\n"
+ " }\n"
+ " return { f: " + name + "}\n"
+ "}; Module");
return m(stdlib, foreign, heap).f;
}
var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
for (var i in divisors) {
var divisor = divisors[i];
var mod = Uint32Div(divisor);
for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
assertEquals((dividend / divisor) >>> 0, mod(dividend));
}
}
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var stdlib = {};
var foreign = {};
var heap = new ArrayBuffer(64 * 1024);
function Uint32Mod(divisor) {
var name = "mod_";
name += divisor;
var m = eval("function Module(stdlib, foreign, heap) {\n"
+ " \"use asm\";\n"
+ " function " + name + "(dividend) {\n"
+ " return ((dividend >>> 0) % " + divisor + ") >>> 0;\n"
+ " }\n"
+ " return { f: " + name + "}\n"
+ "}; Module");
return m(stdlib, foreign, heap).f;
}
var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
for (var i in divisors) {
var divisor = divisors[i];
var mod = Uint32Mod(divisor);
for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
assertEquals((dividend % divisor) >>> 0, mod(dividend));
}
}
...@@ -1765,6 +1765,23 @@ TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) { ...@@ -1765,6 +1765,23 @@ TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
} }
TEST_F(InstructionSelectorTest, Uint32MulHighWithParameters) {
StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const n = m.Uint32MulHigh(p0, p1);
m.Return(n);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArmUmull, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
ASSERT_EQ(2U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->OutputAt(1)));
}
TEST_F(InstructionSelectorTest, Uint32DivWithParameters) { TEST_F(InstructionSelectorTest, Uint32DivWithParameters) {
StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1))); m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1)));
......
...@@ -456,7 +456,7 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) { ...@@ -456,7 +456,7 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
IsMerge( IsMerge(
IsIfTrue(AllOf(CaptureEq(&branch), IsIfTrue(AllOf(CaptureEq(&branch),
IsBranch(IsUint32LessThanOrEqual( IsBranch(IsUint32LessThanOrEqual(
val, IsInt64Constant(SmiMaxValue())), val, IsInt32Constant(SmiMaxValue())),
graph()->start()))), graph()->start()))),
AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
} }
......
...@@ -298,7 +298,27 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) { ...@@ -298,7 +298,27 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) {
EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax)); EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1))); EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1))); EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
ASSERT_EQ(1U, s[0]->OutputCount()); ASSERT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
}
TEST_F(InstructionSelectorTest, Uint32MulHigh) {
StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
Node* const p0 = m.Parameter(0);
Node* const p1 = m.Parameter(1);
Node* const n = m.Uint32MulHigh(p0, p1);
m.Return(n);
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
ASSERT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx)); EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment