[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
This commit is contained in:
parent
e634bdb290
commit
498920f91c
@ -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 {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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() {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
} 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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 {
|
|||||||
// 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 {
|
|||||||
// 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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
__ 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);
|
||||||
|
29
test/mjsunit/asm/uint32div.js
Normal file
29
test/mjsunit/asm/uint32div.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
29
test/mjsunit/asm/uint32mod.js
Normal file
29
test/mjsunit/asm/uint32mod.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
|||||||
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))))));
|
||||||
}
|
}
|
||||||
|
@ -680,26 +680,26 @@ TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Shr) {
|
|||||||
TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(0)));
|
machine()->Int32Div(), p0, Int32Constant(0), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(1)));
|
machine()->Int32Div(), p0, Int32Constant(1), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_EQ(r.replacement(), p0);
|
EXPECT_EQ(r.replacement(), p0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(-1)));
|
machine()->Int32Div(), p0, Int32Constant(-1), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), p0));
|
EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), p0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(2)));
|
machine()->Int32Div(), p0, Int32Constant(2), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
r.replacement(),
|
r.replacement(),
|
||||||
@ -707,8 +707,8 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
|||||||
IsInt32Constant(1)));
|
IsInt32Constant(1)));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(-2)));
|
machine()->Int32Div(), p0, Int32Constant(-2), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
r.replacement(),
|
r.replacement(),
|
||||||
@ -718,8 +718,9 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
|||||||
IsInt32Constant(1))));
|
IsInt32Constant(1))));
|
||||||
}
|
}
|
||||||
TRACED_FORRANGE(int32_t, shift, 2, 30) {
|
TRACED_FORRANGE(int32_t, shift, 2, 30) {
|
||||||
Reduction const r = Reduce(
|
Reduction const r =
|
||||||
graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(1 << shift)));
|
Reduce(graph()->NewNode(machine()->Int32Div(), p0,
|
||||||
|
Int32Constant(1 << shift), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
r.replacement(),
|
r.replacement(),
|
||||||
@ -731,7 +732,8 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
|||||||
TRACED_FORRANGE(int32_t, shift, 2, 31) {
|
TRACED_FORRANGE(int32_t, shift, 2, 31) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
machine()->Int32Div(), p0,
|
machine()->Int32Div(), p0,
|
||||||
Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift)));
|
Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
|
||||||
|
graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
r.replacement(),
|
r.replacement(),
|
||||||
@ -746,15 +748,15 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
|||||||
TRACED_FOREACH(int32_t, divisor, kInt32Values) {
|
TRACED_FOREACH(int32_t, divisor, kInt32Values) {
|
||||||
if (divisor < 0) {
|
if (divisor < 0) {
|
||||||
if (base::bits::IsPowerOfTwo32(-divisor)) continue;
|
if (base::bits::IsPowerOfTwo32(-divisor)) continue;
|
||||||
Reduction const r = Reduce(
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(divisor)));
|
machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0),
|
EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0),
|
||||||
IsTruncatingDiv(p0, -divisor)));
|
IsTruncatingDiv(p0, -divisor)));
|
||||||
} else if (divisor > 0) {
|
} else if (divisor > 0) {
|
||||||
if (base::bits::IsPowerOfTwo32(divisor)) continue;
|
if (base::bits::IsPowerOfTwo32(divisor)) continue;
|
||||||
Reduction const r = Reduce(
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(divisor)));
|
machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsTruncatingDiv(p0, divisor));
|
EXPECT_THAT(r.replacement(), IsTruncatingDiv(p0, divisor));
|
||||||
}
|
}
|
||||||
@ -764,7 +766,8 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
|
|||||||
|
|
||||||
TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
|
TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Int32Div(), p0, p0));
|
Reduction const r =
|
||||||
|
Reduce(graph()->NewNode(machine()->Int32Div(), p0, p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
r.replacement(),
|
r.replacement(),
|
||||||
@ -779,28 +782,28 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
|
|||||||
TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
|
TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Uint32Div(), Int32Constant(0), p0));
|
machine()->Uint32Div(), Int32Constant(0), p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Uint32Div(), p0, Int32Constant(0)));
|
machine()->Uint32Div(), p0, Int32Constant(0), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Uint32Div(), p0, Int32Constant(1)));
|
machine()->Uint32Div(), p0, Int32Constant(1), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_EQ(r.replacement(), p0);
|
EXPECT_EQ(r.replacement(), p0);
|
||||||
}
|
}
|
||||||
TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
|
TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
|
||||||
TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
|
TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(),
|
Reduction const r = Reduce(
|
||||||
Uint32Constant(dividend),
|
graph()->NewNode(machine()->Uint32Div(), Uint32Constant(dividend),
|
||||||
Uint32Constant(divisor)));
|
Uint32Constant(divisor), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(),
|
EXPECT_THAT(r.replacement(),
|
||||||
IsInt32Constant(bit_cast<int32_t>(
|
IsInt32Constant(bit_cast<int32_t>(
|
||||||
@ -808,8 +811,9 @@ TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRACED_FORRANGE(uint32_t, shift, 1, 31) {
|
TRACED_FORRANGE(uint32_t, shift, 1, 31) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
|
Reduction const r =
|
||||||
Uint32Constant(1u << shift)));
|
Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
|
||||||
|
Uint32Constant(1u << shift), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(),
|
EXPECT_THAT(r.replacement(),
|
||||||
IsWord32Shr(p0, IsInt32Constant(bit_cast<int32_t>(shift))));
|
IsWord32Shr(p0, IsInt32Constant(bit_cast<int32_t>(shift))));
|
||||||
@ -819,7 +823,8 @@ TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
|
|||||||
|
|
||||||
TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
|
TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(), p0, p0));
|
Reduction const r = Reduce(
|
||||||
|
graph()->NewNode(machine()->Uint32Div(), p0, p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(
|
EXPECT_THAT(
|
||||||
r.replacement(),
|
r.replacement(),
|
||||||
@ -834,42 +839,43 @@ TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
|
|||||||
TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
|
TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Mod(), Int32Constant(0), p0));
|
machine()->Int32Mod(), Int32Constant(0), p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(0)));
|
machine()->Int32Mod(), p0, Int32Constant(0), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1)));
|
machine()->Int32Mod(), p0, Int32Constant(1), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(-1)));
|
machine()->Int32Mod(), p0, Int32Constant(-1), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
TRACED_FOREACH(int32_t, dividend, kInt32Values) {
|
TRACED_FOREACH(int32_t, dividend, kInt32Values) {
|
||||||
TRACED_FOREACH(int32_t, divisor, kInt32Values) {
|
TRACED_FOREACH(int32_t, divisor, kInt32Values) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Int32Mod(),
|
Reduction const r = Reduce(
|
||||||
Int32Constant(dividend),
|
graph()->NewNode(machine()->Int32Mod(), Int32Constant(dividend),
|
||||||
Int32Constant(divisor)));
|
Int32Constant(divisor), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(),
|
EXPECT_THAT(r.replacement(),
|
||||||
IsInt32Constant(base::bits::SignedMod32(dividend, divisor)));
|
IsInt32Constant(base::bits::SignedMod32(dividend, divisor)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRACED_FORRANGE(int32_t, shift, 1, 30) {
|
TRACED_FORRANGE(int32_t, shift, 1, 30) {
|
||||||
Reduction const r = Reduce(
|
Reduction const r =
|
||||||
graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1 << shift)));
|
Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
|
||||||
|
Int32Constant(1 << shift), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
|
|
||||||
Capture<Node*> branch;
|
Capture<Node*> branch;
|
||||||
@ -890,7 +896,8 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
|
|||||||
TRACED_FORRANGE(int32_t, shift, 1, 31) {
|
TRACED_FORRANGE(int32_t, shift, 1, 31) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
machine()->Int32Mod(), p0,
|
machine()->Int32Mod(), p0,
|
||||||
Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift)));
|
Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
|
||||||
|
graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
|
|
||||||
Capture<Node*> branch;
|
Capture<Node*> branch;
|
||||||
@ -910,8 +917,8 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
|
|||||||
}
|
}
|
||||||
TRACED_FOREACH(int32_t, divisor, kInt32Values) {
|
TRACED_FOREACH(int32_t, divisor, kInt32Values) {
|
||||||
if (divisor == 0 || base::bits::IsPowerOfTwo32(Abs(divisor))) continue;
|
if (divisor == 0 || base::bits::IsPowerOfTwo32(Abs(divisor))) continue;
|
||||||
Reduction const r = Reduce(
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(divisor)));
|
machine()->Int32Mod(), p0, Int32Constant(divisor), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(),
|
EXPECT_THAT(r.replacement(),
|
||||||
IsInt32Sub(p0, IsInt32Mul(IsTruncatingDiv(p0, Abs(divisor)),
|
IsInt32Sub(p0, IsInt32Mul(IsTruncatingDiv(p0, Abs(divisor)),
|
||||||
@ -922,7 +929,8 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
|
|||||||
|
|
||||||
TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
|
TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Int32Mod(), p0, p0));
|
Reduction const r =
|
||||||
|
Reduce(graph()->NewNode(machine()->Int32Mod(), p0, p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
@ -935,28 +943,28 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
|
|||||||
TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
|
TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Uint32Mod(), p0, Int32Constant(0)));
|
machine()->Uint32Mod(), p0, Int32Constant(0), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Uint32Mod(), Int32Constant(0), p0));
|
machine()->Uint32Mod(), Int32Constant(0), p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Reduction const r =
|
Reduction const r = Reduce(graph()->NewNode(
|
||||||
Reduce(graph()->NewNode(machine()->Uint32Mod(), p0, Int32Constant(1)));
|
machine()->Uint32Mod(), p0, Int32Constant(1), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
|
TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
|
||||||
TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
|
TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(),
|
Reduction const r = Reduce(
|
||||||
Uint32Constant(dividend),
|
graph()->NewNode(machine()->Uint32Mod(), Uint32Constant(dividend),
|
||||||
Uint32Constant(divisor)));
|
Uint32Constant(divisor), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(),
|
EXPECT_THAT(r.replacement(),
|
||||||
IsInt32Constant(bit_cast<int32_t>(
|
IsInt32Constant(bit_cast<int32_t>(
|
||||||
@ -964,8 +972,9 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRACED_FORRANGE(uint32_t, shift, 1, 31) {
|
TRACED_FORRANGE(uint32_t, shift, 1, 31) {
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
|
Reduction const r =
|
||||||
Uint32Constant(1u << shift)));
|
Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
|
||||||
|
Uint32Constant(1u << shift), graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(),
|
EXPECT_THAT(r.replacement(),
|
||||||
IsWord32And(p0, IsInt32Constant(
|
IsWord32And(p0, IsInt32Constant(
|
||||||
@ -976,7 +985,8 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
|
|||||||
|
|
||||||
TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
|
TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
|
||||||
Node* const p0 = Parameter(0);
|
Node* const p0 = Parameter(0);
|
||||||
Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(), p0, p0));
|
Reduction const r = Reduce(
|
||||||
|
graph()->NewNode(machine()->Uint32Mod(), p0, p0, graph()->start()));
|
||||||
ASSERT_TRUE(r.Changed());
|
ASSERT_TRUE(r.Changed());
|
||||||
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
EXPECT_THAT(r.replacement(), IsInt32Constant(0));
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user