Bug 888237 - IonMonkey: (ARM) Use hardware divide instruction to calculate modulus r=mjrosenb

This commit is contained in:
Jon Coppeard 2013-07-18 14:25:06 +01:00
parent 1c760fa01e
commit 86aadbaae4
7 changed files with 132 additions and 45 deletions

View File

@ -641,37 +641,9 @@ CodeGeneratorARM::visitDivPowTwoI(LDivPowTwoI *ins)
}
bool
CodeGeneratorARM::visitModI(LModI *ins)
CodeGeneratorARM::modICommon(MMod *mir, Register lhs, Register rhs, Register output,
LSnapshot *snapshot, Label &done)
{
// Extract the registers from this instruction
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register callTemp = ToRegister(ins->getTemp(2));
MMod *mir = ins->mir();
Label done;
// save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0.
JS_ASSERT(callTemp.code() > r3.code() && callTemp.code() < r12.code());
masm.ma_mov(lhs, callTemp);
// Prevent INT_MIN % -1;
// The integer division will give INT_MIN, but we want -(double)INT_MIN.
if (mir->canBeNegativeDividend()) {
masm.ma_cmp(lhs, Imm32(INT_MIN)); // sets EQ if lhs == INT_MIN
masm.ma_cmp(rhs, Imm32(-1), Assembler::Equal); // if EQ (LHS == INT_MIN), sets EQ if rhs == -1
if (mir->isTruncated()) {
// (INT_MIN % -1)|0 == 0
Label skip;
masm.ma_b(&skip, Assembler::NotEqual);
masm.ma_mov(Imm32(0), r1);
masm.ma_b(&done);
masm.bind(&skip);
} else {
JS_ASSERT(mir->fallible());
if (!bailoutIf(Assembler::Equal, ins->snapshot()))
return false;
}
}
// 0/X (with X < 0) is bad because both of these values *should* be doubles, and
// the result should be -0.0, which cannot be represented in integers.
// X/0 is bad because it will give garbage (or abort), when it should give
@ -691,7 +663,77 @@ CodeGeneratorARM::visitModI(LModI *ins)
// NaN|0 == 0 and (0 % -X)|0 == 0
Label skip;
masm.ma_b(&skip, Assembler::NotEqual);
masm.ma_mov(Imm32(0), r1);
masm.ma_mov(Imm32(0), output);
masm.ma_b(&done);
masm.bind(&skip);
} else {
JS_ASSERT(mir->fallible());
if (!bailoutIf(Assembler::Equal, snapshot))
return false;
}
return true;
}
bool
CodeGeneratorARM::visitModI(LModI *ins)
{
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
Register callTemp = ToRegister(ins->getTemp(0));
MMod *mir = ins->mir();
// save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0.
masm.ma_mov(lhs, callTemp);
Label done;
if (!modICommon(mir, lhs, rhs, output, ins->snapshot(), done))
return false;
masm.ma_smod(lhs, rhs, output);
// If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0
if (mir->isTruncated()) {
// -0.0|0 == 0
} else {
JS_ASSERT(mir->fallible());
// See if X < 0
masm.ma_cmp(output, Imm32(0));
masm.ma_b(&done, Assembler::NotEqual);
masm.ma_cmp(callTemp, Imm32(0));
if (!bailoutIf(Assembler::Signed, ins->snapshot()))
return false;
}
masm.bind(&done);
return true;
}
bool
CodeGeneratorARM::visitSoftModI(LSoftModI *ins)
{
// Extract the registers from this instruction
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
Register callTemp = ToRegister(ins->getTemp(2));
MMod *mir = ins->mir();
Label done;
// save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0.
JS_ASSERT(callTemp.code() > r3.code() && callTemp.code() < r12.code());
masm.ma_mov(lhs, callTemp);
// Prevent INT_MIN % -1;
// The integer division will give INT_MIN, but we want -(double)INT_MIN.
if (mir->canBeNegativeDividend()) {
masm.ma_cmp(lhs, Imm32(INT_MIN)); // sets EQ if lhs == INT_MIN
masm.ma_cmp(rhs, Imm32(-1), Assembler::Equal); // if EQ (LHS == INT_MIN), sets EQ if rhs == -1
if (mir->isTruncated()) {
// (INT_MIN % -1)|0 == 0
Label skip;
masm.ma_b(&skip, Assembler::NotEqual);
masm.ma_mov(Imm32(0), output);
masm.ma_b(&done);
masm.bind(&skip);
} else {
@ -699,17 +741,23 @@ CodeGeneratorARM::visitModI(LModI *ins)
if (!bailoutIf(Assembler::Equal, ins->snapshot()))
return false;
}
}
if (!modICommon(mir, lhs, rhs, output, ins->snapshot(), done))
return false;
masm.setupAlignedABICall(2);
masm.passABIArg(lhs);
masm.passABIArg(rhs);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, __aeabi_idivmod));
// If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0
// See if X < 0
masm.ma_cmp(r1, Imm32(0));
if (mir->isTruncated()) {
// -0.0|0 == 0
} else {
JS_ASSERT(mir->fallible());
// See if X < 0
masm.ma_cmp(r1, Imm32(0));
masm.ma_b(&done, Assembler::NotEqual);
masm.ma_cmp(callTemp, Imm32(0));
if (!bailoutIf(Assembler::Signed, ins->snapshot()))

View File

@ -78,6 +78,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
virtual bool visitSoftDivI(LSoftDivI *ins);
virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
virtual bool visitModI(LModI *ins);
virtual bool visitSoftModI(LSoftModI *ins);
virtual bool visitModPowTwoI(LModPowTwoI *ins);
virtual bool visitModMaskI(LModMaskI *ins);
virtual bool visitPowHalfD(LPowHalfD *ins);
@ -120,6 +121,8 @@ class CodeGeneratorARM : public CodeGeneratorShared
bool divICommon(MDiv *mir, Register lhs, Register rhs, Register output, LSnapshot *snapshot,
Label &done);
bool modICommon(MMod *mir, Register lhs, Register rhs, Register output, LSnapshot *snapshot,
Label &done);
public:
CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);

View File

@ -150,12 +150,30 @@ class LDivPowTwoI : public LInstructionHelper<1, 1, 0>
}
};
class LModI : public LBinaryMath<3>
class LModI : public LBinaryMath<1>
{
public:
LIR_HEADER(ModI);
LModI(const LAllocation &lhs, const LAllocation &rhs,
const LDefinition &callTemp)
{
setOperand(0, lhs);
setOperand(1, rhs);
setTemp(0, callTemp);
}
MMod *mir() const {
return mir_->toMod();
}
};
class LSoftModI : public LBinaryMath<3>
{
public:
LIR_HEADER(SoftModI);
LSoftModI(const LAllocation &lhs, const LAllocation &rhs,
const LDefinition &temp1, const LDefinition &temp2,
const LDefinition &callTemp)
{

View File

@ -16,6 +16,7 @@
_(SoftDivI) \
_(DivPowTwoI) \
_(ModI) \
_(SoftModI) \
_(ModPowTwoI) \
_(ModMaskI) \
_(PowHalfD) \

View File

@ -297,13 +297,20 @@ LIRGeneratorARM::lowerModI(MMod *mod)
return define(lir, mod);
}
}
LModI *lir = new LModI(useFixed(mod->lhs(), r0), use(mod->rhs(), r1),
tempFixed(r2), tempFixed(r3), temp(LDefinition::GENERAL));
if (hasIDIV()) {
LModI *lir = new LModI(useRegister(mod->lhs()), useRegister(mod->rhs()), temp());
if (mod->fallible() && !assignSnapshot(lir))
return false;
return define(lir, mod);
} else {
LSoftModI *lir = new LSoftModI(useFixed(mod->lhs(), r0), use(mod->rhs(), r1),
tempFixed(r2), tempFixed(r3), temp(LDefinition::GENERAL));
if (mod->fallible() && !assignSnapshot(lir))
return false;
return defineFixed(lir, mod, LAllocation(AnyRegister(r1)));
}
}
bool
LIRGeneratorARM::visitPowHalf(MPowHalf *ins)

View File

@ -882,6 +882,13 @@ MacroAssemblerARM::ma_mod_mask(Register src, Register dest, Register hold, int32
}
void
MacroAssemblerARM::ma_smod(Register num, Register div, Register dest)
{
as_sdiv(ScratchRegister, num, div);
as_mls(dest, num, ScratchRegister, div);
}
// division
void
MacroAssemblerARM::ma_sdiv(Register num, Register div, Register dest, Condition cond)

View File

@ -238,6 +238,9 @@ class MacroAssemblerARM : public Assembler
// implicitly assumes that we can overwrite dest at the beginning of the sequence
void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift);
// mod, depends on sdiv being supported
void ma_smod(Register num, Register div, Register dest);
// division
void ma_sdiv(Register num, Register div, Register dest, Condition cond = Always);