mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 891534 - Use asm.js ops for truncated unsigned div/mod, allow div ops to be marked as truncated, r=jandem.
This commit is contained in:
parent
e5d69cbd84
commit
e1af6a5691
@ -1545,6 +1545,26 @@ MustBeUInt32(MDefinition *def, MDefinition **pwrapped)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MBinaryInstruction::tryUseUnsignedOperands()
|
||||
{
|
||||
MDefinition *newlhs, *newrhs;
|
||||
if (MustBeUInt32(getOperand(0), &newlhs) && MustBeUInt32(getOperand(1), &newrhs)) {
|
||||
if (newlhs->type() != MIRType_Int32 || newrhs->type() != MIRType_Int32)
|
||||
return false;
|
||||
if (newlhs != getOperand(0)) {
|
||||
getOperand(0)->setFoldedUnchecked();
|
||||
replaceOperand(0, newlhs);
|
||||
}
|
||||
if (newrhs != getOperand(1)) {
|
||||
getOperand(1)->setFoldedUnchecked();
|
||||
replaceOperand(1, newrhs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MCompare::infer(JSContext *cx, BaselineInspector *inspector, jsbytecode *pc)
|
||||
{
|
||||
@ -1560,19 +1580,9 @@ MCompare::infer(JSContext *cx, BaselineInspector *inspector, jsbytecode *pc)
|
||||
bool strictEq = jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE;
|
||||
bool relationalEq = !(looseEq || strictEq);
|
||||
|
||||
// Comparisons on unsigned integers may be treated as UInt32. Skip any (x >>> 0)
|
||||
// operation coercing the operands to uint32. The type policy will make sure the
|
||||
// now unwrapped operand is an int32.
|
||||
// Comparisons on unsigned integers may be treated as UInt32.
|
||||
MDefinition *newlhs, *newrhs;
|
||||
if (MustBeUInt32(getOperand(0), &newlhs) && MustBeUInt32(getOperand(1), &newrhs)) {
|
||||
if (newlhs != getOperand(0)) {
|
||||
getOperand(0)->setFoldedUnchecked();
|
||||
replaceOperand(0, newlhs);
|
||||
}
|
||||
if (newrhs != getOperand(1)) {
|
||||
getOperand(1)->setFoldedUnchecked();
|
||||
replaceOperand(1, newrhs);
|
||||
}
|
||||
if (tryUseUnsignedOperands()) {
|
||||
compareType_ = Compare_UInt32;
|
||||
return;
|
||||
}
|
||||
|
@ -1706,6 +1706,11 @@ class MBinaryInstruction : public MAryInstruction<2>
|
||||
return (left->valueNumber() == insLeft->valueNumber()) &&
|
||||
(right->valueNumber() == insRight->valueNumber());
|
||||
}
|
||||
|
||||
// Return true if the operands to this instruction are both unsigned,
|
||||
// in which case any wrapping operands were replaced with the underlying
|
||||
// int32 operands.
|
||||
bool tryUseUnsignedOperands();
|
||||
};
|
||||
|
||||
class MTernaryInstruction : public MAryInstruction<3>
|
||||
@ -3388,12 +3393,14 @@ class MDiv : public MBinaryArithInstruction
|
||||
bool canBeNegativeZero_;
|
||||
bool canBeNegativeOverflow_;
|
||||
bool canBeDivideByZero_;
|
||||
bool unsigned_;
|
||||
|
||||
MDiv(MDefinition *left, MDefinition *right, MIRType type)
|
||||
: MBinaryArithInstruction(left, right),
|
||||
canBeNegativeZero_(true),
|
||||
canBeNegativeOverflow_(true),
|
||||
canBeDivideByZero_(true)
|
||||
canBeDivideByZero_(true),
|
||||
unsigned_(false)
|
||||
{
|
||||
if (type != MIRType_Value)
|
||||
specialization_ = type;
|
||||
@ -3438,14 +3445,21 @@ class MDiv : public MBinaryArithInstruction
|
||||
return canBeDivideByZero_;
|
||||
}
|
||||
|
||||
bool isUnsigned() {
|
||||
return unsigned_;
|
||||
}
|
||||
|
||||
bool fallible();
|
||||
bool truncate();
|
||||
};
|
||||
|
||||
class MMod : public MBinaryArithInstruction
|
||||
{
|
||||
bool unsigned_;
|
||||
|
||||
MMod(MDefinition *left, MDefinition *right, MIRType type)
|
||||
: MBinaryArithInstruction(left, right)
|
||||
: MBinaryArithInstruction(left, right),
|
||||
unsigned_(false)
|
||||
{
|
||||
if (type != MIRType_Value)
|
||||
specialization_ = type;
|
||||
@ -3474,6 +3488,10 @@ class MMod : public MBinaryArithInstruction
|
||||
bool canBeDivideByZero() const;
|
||||
bool canBePowerOfTwoDivisor() const;
|
||||
|
||||
bool isUnsigned() {
|
||||
return unsigned_;
|
||||
}
|
||||
|
||||
bool fallible();
|
||||
|
||||
void computeRange();
|
||||
|
@ -1586,6 +1586,13 @@ MDiv::truncate()
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncated(true);
|
||||
|
||||
// Divisions where the lhs and rhs are unsigned and the result is
|
||||
// truncated can be lowered more efficiently.
|
||||
if (specialization() == MIRType_Int32 && tryUseUnsignedOperands()) {
|
||||
unsigned_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// No modifications.
|
||||
return false;
|
||||
}
|
||||
@ -1596,6 +1603,12 @@ MMod::truncate()
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncated(true);
|
||||
|
||||
// As for division, handle unsigned modulus with a truncated result.
|
||||
if (specialization() == MIRType_Int32 && tryUseUnsignedOperands()) {
|
||||
unsigned_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// No modifications.
|
||||
return false;
|
||||
}
|
||||
@ -1759,7 +1772,14 @@ RangeAnalysis::truncate()
|
||||
// Set truncated flag if range analysis ensure that it has no
|
||||
// rounding errors and no fractional part.
|
||||
const Range *r = iter->range();
|
||||
if (!r || r->hasRoundingErrors())
|
||||
bool hasRoundingErrors = !r || r->hasRoundingErrors();
|
||||
|
||||
// Special case integer division: the result of a/b can be infinite
|
||||
// but cannot actually have rounding errors induced by truncation.
|
||||
if (iter->isDiv() && iter->toDiv()->specialization() == MIRType_Int32)
|
||||
hasRoundingErrors = false;
|
||||
|
||||
if (hasRoundingErrors)
|
||||
continue;
|
||||
|
||||
// Ensure all observable uses are truncated.
|
||||
|
@ -1806,7 +1806,7 @@ CodeGeneratorARM::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
|
||||
|
||||
|
||||
bool
|
||||
CodeGeneratorARM::visitAsmJSDivOrMod(LAsmJSDivOrMod *ins)
|
||||
CodeGeneratorARM::visitUDivOrMod(LUDivOrMod *ins)
|
||||
{
|
||||
//Register remainder = ToRegister(ins->remainder());
|
||||
Register lhs = ToRegister(ins->lhs());
|
||||
|
@ -171,7 +171,7 @@ class CodeGeneratorARM : public CodeGeneratorShared
|
||||
}
|
||||
|
||||
bool visitEffectiveAddress(LEffectiveAddress *ins);
|
||||
bool visitAsmJSDivOrMod(LAsmJSDivOrMod *ins);
|
||||
bool visitUDivOrMod(LUDivOrMod *ins);
|
||||
};
|
||||
|
||||
typedef CodeGeneratorARM CodeGeneratorSpecific;
|
||||
|
@ -343,12 +343,12 @@ class LMulI : public LBinaryMath<0>
|
||||
|
||||
// This class performs a simple x86 'div', yielding either a quotient or remainder depending on
|
||||
// whether this instruction is defined to output eax (quotient) or edx (remainder).
|
||||
class LAsmJSDivOrMod : public LBinaryMath<2>
|
||||
class LUDivOrMod : public LBinaryMath<2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(AsmJSDivOrMod);
|
||||
LIR_HEADER(UDivOrMod);
|
||||
|
||||
LAsmJSDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp1, const LDefinition &temp2) {
|
||||
LUDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp1, const LDefinition &temp2) {
|
||||
setOperand(0, lhs);
|
||||
setOperand(1, rhs);
|
||||
setTemp(0, temp1);
|
||||
|
@ -20,7 +20,7 @@
|
||||
_(ModMaskI) \
|
||||
_(PowHalfD) \
|
||||
_(UInt32ToDouble) \
|
||||
_(AsmJSDivOrMod) \
|
||||
_(UDivOrMod) \
|
||||
_(AsmJSLoadFuncPtr)
|
||||
|
||||
|
||||
|
@ -228,6 +228,9 @@ LIRGeneratorARM::lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mi
|
||||
bool
|
||||
LIRGeneratorARM::lowerDivI(MDiv *div)
|
||||
{
|
||||
if (div->isUnsigned())
|
||||
return lowerUDiv(div);
|
||||
|
||||
// Division instructions are slow. Division by constant denominators can be
|
||||
// rewritten to use other instructions.
|
||||
if (div->rhs()->isConstant()) {
|
||||
@ -273,6 +276,9 @@ LIRGeneratorARM::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
|
||||
bool
|
||||
LIRGeneratorARM::lowerModI(MMod *mod)
|
||||
{
|
||||
if (mod->isUnsigned())
|
||||
return lowerUMod(mod);
|
||||
|
||||
if (mod->rhs()->isConstant()) {
|
||||
int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
|
||||
int32_t shift;
|
||||
@ -430,22 +436,35 @@ LIRGeneratorARM::visitAsmJSNeg(MAsmJSNeg *ins)
|
||||
JS_ASSERT(ins->type() == MIRType_Double);
|
||||
return define(new LNegD(useRegisterAtStart(ins->input())), ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorARM::lowerUDiv(MInstruction *div)
|
||||
{
|
||||
LUDivOrMod *lir = new LUDivOrMod(useFixed(div->getOperand(0), r0),
|
||||
useFixed(div->getOperand(1), r1),
|
||||
tempFixed(r2), tempFixed(r3));
|
||||
return defineFixed(lir, div, LAllocation(AnyRegister(r0)));
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorARM::visitAsmJSUDiv(MAsmJSUDiv *div)
|
||||
{
|
||||
LAsmJSDivOrMod *lir = new LAsmJSDivOrMod(useFixed(div->lhs(), r0),
|
||||
useFixed(div->rhs(), r1),
|
||||
tempFixed(r2), tempFixed(r3));
|
||||
return defineFixed(lir, div, LAllocation(AnyRegister(r0)));
|
||||
return lowerUDiv(div);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorARM::lowerUMod(MInstruction *mod)
|
||||
{
|
||||
LUDivOrMod *lir = new LUDivOrMod(useFixed(mod->getOperand(0), r0),
|
||||
useFixed(mod->getOperand(1), r1),
|
||||
tempFixed(r2), tempFixed(r3));
|
||||
return defineFixed(lir, mod, LAllocation(AnyRegister(r1)));
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorARM::visitAsmJSUMod(MAsmJSUMod *mod)
|
||||
{
|
||||
LAsmJSDivOrMod *lir = new LAsmJSDivOrMod(useFixed(mod->lhs(), r0),
|
||||
useFixed(mod->rhs(), r1),
|
||||
tempFixed(r2), tempFixed(r3));
|
||||
return defineFixed(lir, mod, LAllocation(AnyRegister(r1)));
|
||||
return lowerUMod(mod);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -52,6 +52,8 @@ class LIRGeneratorARM : public LIRGeneratorShared
|
||||
bool lowerDivI(MDiv *div);
|
||||
bool lowerModI(MMod *mod);
|
||||
bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
|
||||
bool lowerUDiv(MInstruction *div);
|
||||
bool lowerUMod(MInstruction *mod);
|
||||
bool visitPowHalf(MPowHalf *ins);
|
||||
bool visitAsmJSNeg(MAsmJSNeg *ins);
|
||||
bool visitAsmJSUDiv(MAsmJSUDiv *ins);
|
||||
|
@ -625,7 +625,7 @@ CodeGeneratorX86Shared::visitMulI(LMulI *ins)
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGeneratorX86Shared::visitAsmJSDivOrMod(LAsmJSDivOrMod *ins)
|
||||
CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins)
|
||||
{
|
||||
JS_ASSERT(ToRegister(ins->lhs()) == eax);
|
||||
Register rhs = ToRegister(ins->rhs());
|
||||
|
@ -106,7 +106,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
||||
virtual bool visitGuardObjectType(LGuardObjectType *guard);
|
||||
virtual bool visitGuardClass(LGuardClass *guard);
|
||||
virtual bool visitEffectiveAddress(LEffectiveAddress *ins);
|
||||
virtual bool visitAsmJSDivOrMod(LAsmJSDivOrMod *ins);
|
||||
virtual bool visitUDivOrMod(LUDivOrMod *ins);
|
||||
virtual bool visitAsmJSPassStackArg(LAsmJSPassStackArg *ins);
|
||||
|
||||
bool visitNegI(LNegI *lir);
|
||||
|
@ -97,12 +97,12 @@ class LModI : public LBinaryMath<1>
|
||||
|
||||
// This class performs a simple x86 'div', yielding either a quotient or remainder depending on
|
||||
// whether this instruction is defined to output eax (quotient) or edx (remainder).
|
||||
class LAsmJSDivOrMod : public LBinaryMath<1>
|
||||
class LUDivOrMod : public LBinaryMath<1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(AsmJSDivOrMod);
|
||||
LIR_HEADER(UDivOrMod);
|
||||
|
||||
LAsmJSDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
|
||||
LUDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
|
||||
setOperand(0, lhs);
|
||||
setOperand(1, rhs);
|
||||
setTemp(0, temp);
|
||||
|
@ -125,6 +125,9 @@ LIRGeneratorX86Shared::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
|
||||
bool
|
||||
LIRGeneratorX86Shared::lowerDivI(MDiv *div)
|
||||
{
|
||||
if (div->isUnsigned())
|
||||
return lowerUDiv(div);
|
||||
|
||||
// Division instructions are slow. Division by constant denominators can be
|
||||
// rewritten to use other instructions.
|
||||
if (div->rhs()->isConstant()) {
|
||||
@ -154,6 +157,9 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *div)
|
||||
bool
|
||||
LIRGeneratorX86Shared::lowerModI(MMod *mod)
|
||||
{
|
||||
if (mod->isUnsigned())
|
||||
return lowerUMod(mod);
|
||||
|
||||
if (mod->rhs()->isConstant()) {
|
||||
int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
|
||||
int32_t shift;
|
||||
@ -181,22 +187,34 @@ LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg *ins)
|
||||
return defineReuseInput(new LNegD(useRegisterAtStart(ins->input())), ins, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorX86Shared::lowerUDiv(MInstruction *div)
|
||||
{
|
||||
LUDivOrMod *lir = new LUDivOrMod(useFixed(div->getOperand(0), eax),
|
||||
useRegister(div->getOperand(1)),
|
||||
tempFixed(edx));
|
||||
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorX86Shared::visitAsmJSUDiv(MAsmJSUDiv *div)
|
||||
{
|
||||
LAsmJSDivOrMod *lir = new LAsmJSDivOrMod(useFixed(div->lhs(), eax),
|
||||
useRegister(div->rhs()),
|
||||
tempFixed(edx));
|
||||
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
|
||||
return lowerUDiv(div);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorX86Shared::lowerUMod(MInstruction *mod)
|
||||
{
|
||||
LUDivOrMod *lir = new LUDivOrMod(useFixed(mod->getOperand(0), eax),
|
||||
useRegister(mod->getOperand(1)),
|
||||
LDefinition::BogusTemp());
|
||||
return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGeneratorX86Shared::visitAsmJSUMod(MAsmJSUMod *mod)
|
||||
{
|
||||
LAsmJSDivOrMod *lir = new LAsmJSDivOrMod(useFixed(mod->lhs(), eax),
|
||||
useRegister(mod->rhs()),
|
||||
LDefinition::BogusTemp());
|
||||
return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
|
||||
return lowerUMod(mod);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -41,6 +41,8 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared
|
||||
bool lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs);
|
||||
bool lowerDivI(MDiv *div);
|
||||
bool lowerModI(MMod *mod);
|
||||
bool lowerUDiv(MInstruction *div);
|
||||
bool lowerUMod(MInstruction *mod);
|
||||
bool lowerUrshD(MUrsh *mir);
|
||||
bool lowerConstantDouble(double d, MInstruction *ins);
|
||||
bool lowerTruncateDToInt32(MTruncateToInt32 *ins);
|
||||
|
@ -18,6 +18,6 @@
|
||||
_(PowHalfD) \
|
||||
_(UInt32ToDouble) \
|
||||
_(AsmJSLoadFuncPtr) \
|
||||
_(AsmJSDivOrMod)
|
||||
_(UDivOrMod)
|
||||
|
||||
#endif /* ion_x64_LOpcodes_x64_h */
|
||||
|
@ -19,6 +19,6 @@
|
||||
_(PowHalfD) \
|
||||
_(UInt32ToDouble) \
|
||||
_(AsmJSLoadFuncPtr) \
|
||||
_(AsmJSDivOrMod)
|
||||
_(UDivOrMod)
|
||||
|
||||
#endif /* ion_x86_LOpcodes_x86_h */
|
||||
|
Loading…
Reference in New Issue
Block a user