mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 888237 - IonMonkey: (ARM) Use hardware divide instruction to calculate modulus r=mjrosenb
This commit is contained in:
parent
1c760fa01e
commit
86aadbaae4
@ -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()))
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -16,6 +16,7 @@
|
||||
_(SoftDivI) \
|
||||
_(DivPowTwoI) \
|
||||
_(ModI) \
|
||||
_(SoftModI) \
|
||||
_(ModPowTwoI) \
|
||||
_(ModMaskI) \
|
||||
_(PowHalfD) \
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user