зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1176230 - Try to fold ternary's with double-argument to NaNToZero. r=nbp
This commit is contained in:
Родитель
41dba26ec2
Коммит
3f3c70ceb2
|
@ -11990,5 +11990,48 @@ CodeGenerator::visitRotate(LRotate* ins)
|
|||
}
|
||||
}
|
||||
|
||||
class OutOfLineNaNToZero : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LNaNToZero* lir_;
|
||||
|
||||
public:
|
||||
explicit OutOfLineNaNToZero(LNaNToZero* lir)
|
||||
: lir_(lir)
|
||||
{}
|
||||
|
||||
void accept(CodeGenerator* codegen) {
|
||||
codegen->visitOutOfLineNaNToZero(this);
|
||||
}
|
||||
LNaNToZero* lir() const {
|
||||
return lir_;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
CodeGenerator::visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool)
|
||||
{
|
||||
FloatRegister output = ToFloatRegister(ool->lir()->output());
|
||||
masm.loadConstantDouble(0.0, output);
|
||||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitNaNToZero(LNaNToZero* lir)
|
||||
{
|
||||
FloatRegister input = ToFloatRegister(lir->input());
|
||||
|
||||
OutOfLineNaNToZero* ool = new(alloc()) OutOfLineNaNToZero(lir);
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
if (lir->mir()->operandIsNeverNegativeZero()){
|
||||
masm.branchDouble(Assembler::DoubleUnordered, input, input, ool->entry());
|
||||
} else {
|
||||
FloatRegister scratch = ToFloatRegister(lir->tempDouble());
|
||||
masm.loadConstantDouble(0.0, scratch);
|
||||
masm.branchDouble(Assembler::DoubleEqualOrUnordered, input, scratch, ool->entry());
|
||||
}
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
@ -52,6 +52,7 @@ class OutOfLineRegExpTester;
|
|||
class OutOfLineRegExpPrototypeOptimizable;
|
||||
class OutOfLineRegExpInstanceOptimizable;
|
||||
class OutOfLineLambdaArrow;
|
||||
class OutOfLineNaNToZero;
|
||||
|
||||
class CodeGenerator final : public CodeGeneratorSpecific
|
||||
{
|
||||
|
@ -383,6 +384,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitCheckIsObj(LCheckIsObj* ins);
|
||||
void visitCheckObjCoercible(LCheckObjCoercible* ins);
|
||||
void visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins);
|
||||
void visitNaNToZero(LNaNToZero* ins);
|
||||
void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool);
|
||||
|
||||
void visitCheckOverRecursed(LCheckOverRecursed* lir);
|
||||
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
|
||||
|
|
|
@ -4841,6 +4841,19 @@ LIRGenerator::visitBlock(MBasicBlock* block)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitNaNToZero(MNaNToZero *ins)
|
||||
{
|
||||
MDefinition* input = ins->input();
|
||||
|
||||
if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
|
||||
redefine(ins, input);
|
||||
return;
|
||||
}
|
||||
LNaNToZero* lir = new(alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
|
||||
defineReuseInput(lir, ins, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::generate()
|
||||
{
|
||||
|
|
|
@ -322,6 +322,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitDebugger(MDebugger* ins);
|
||||
void visitNewTarget(MNewTarget* ins);
|
||||
void visitArrowNewTarget(MArrowNewTarget* ins);
|
||||
void visitNaNToZero(MNaNToZero *ins);
|
||||
void visitAtomicIsLockFree(MAtomicIsLockFree* ins);
|
||||
void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins);
|
||||
void visitCheckReturn(MCheckReturn* ins);
|
||||
|
|
|
@ -2326,7 +2326,7 @@ MPhi::removeAllOperands()
|
|||
}
|
||||
|
||||
MDefinition*
|
||||
MPhi::foldsTernary()
|
||||
MPhi::foldsTernary(TempAllocator& alloc)
|
||||
{
|
||||
/* Look if this MPhi is a ternary construct.
|
||||
* This is a very loose term as it actually only checks for
|
||||
|
@ -2416,6 +2416,14 @@ MPhi::foldsTernary()
|
|||
return trueDef;
|
||||
}
|
||||
|
||||
// If testArg is an double type we can:
|
||||
// - fold testArg ? testArg : 0.0 to MNaNToZero(testArg)
|
||||
if (testArg->type() == MIRType::Double && c->numberToDouble() == 0 && c != trueDef) {
|
||||
MNaNToZero* replace = MNaNToZero::New(alloc, testArg);
|
||||
test->block()->insertBefore(test, replace);
|
||||
return replace;
|
||||
}
|
||||
|
||||
// If testArg is a string type we can:
|
||||
// - fold testArg ? testArg : "" to testArg
|
||||
// - fold testArg ? "" : testArg to ""
|
||||
|
@ -2495,7 +2503,7 @@ MPhi::foldsTo(TempAllocator& alloc)
|
|||
if (MDefinition* def = operandIfRedundant())
|
||||
return def;
|
||||
|
||||
if (MDefinition* def = foldsTernary())
|
||||
if (MDefinition* def = foldsTernary(alloc))
|
||||
return def;
|
||||
|
||||
if (MDefinition* def = foldsFilterTypeSet())
|
||||
|
|
|
@ -7656,7 +7656,7 @@ class MPhi final
|
|||
bool checkForTypeChange(TempAllocator& alloc, MDefinition* ins, bool* ptypeChange);
|
||||
|
||||
MDefinition* foldsTo(TempAllocator& alloc) override;
|
||||
MDefinition* foldsTernary();
|
||||
MDefinition* foldsTernary(TempAllocator& alloc);
|
||||
MDefinition* foldsFilterTypeSet();
|
||||
|
||||
bool congruentTo(const MDefinition* ins) const override;
|
||||
|
@ -7730,6 +7730,47 @@ class MBeta
|
|||
void computeRange(TempAllocator& alloc) override;
|
||||
};
|
||||
|
||||
// If input evaluates to false (i.e. it's NaN, 0 or -0), 0 is returned, else the input is returned
|
||||
class MNaNToZero
|
||||
: public MUnaryInstruction,
|
||||
public DoublePolicy<0>::Data
|
||||
{
|
||||
bool operandIsNeverNaN_;
|
||||
bool operandIsNeverNegativeZero_;
|
||||
explicit MNaNToZero(MDefinition* input)
|
||||
: MUnaryInstruction(input), operandIsNeverNaN_(false), operandIsNeverNegativeZero_(false)
|
||||
{
|
||||
setResultType(MIRType::Double);
|
||||
setMovable();
|
||||
}
|
||||
public:
|
||||
INSTRUCTION_HEADER(NaNToZero)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
|
||||
bool operandIsNeverNaN() const {
|
||||
return operandIsNeverNaN_;
|
||||
}
|
||||
|
||||
bool operandIsNeverNegativeZero() const {
|
||||
return operandIsNeverNegativeZero_;
|
||||
}
|
||||
|
||||
void collectRangeInfoPreTrunc() override;
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator& alloc) override;
|
||||
|
||||
bool writeRecoverData(CompactBufferWriter& writer) const override;
|
||||
bool canRecoverOnBailout() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MNaNToZero)
|
||||
};
|
||||
|
||||
// MIR representation of a Value on the OSR BaselineFrame.
|
||||
// The Value is indexed off of OsrFrameReg.
|
||||
class MOsrValue
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace jit {
|
|||
_(Compare) \
|
||||
_(Phi) \
|
||||
_(Beta) \
|
||||
_(NaNToZero) \
|
||||
_(OsrValue) \
|
||||
_(OsrEnvironmentChain) \
|
||||
_(OsrReturnValue) \
|
||||
|
|
|
@ -1217,6 +1217,16 @@ Range::sign(TempAllocator& alloc, const Range* op)
|
|||
0);
|
||||
}
|
||||
|
||||
Range*
|
||||
Range::NaNToZero(TempAllocator& alloc, const Range *op)
|
||||
{
|
||||
Range* copy = new(alloc) Range(*op);
|
||||
if (copy->canBeNaN())
|
||||
copy->max_exponent_ = Range::IncludesInfinity;
|
||||
copy->refineToExcludeNegativeZero();
|
||||
return copy;
|
||||
}
|
||||
|
||||
bool
|
||||
Range::negativeZeroMul(const Range* lhs, const Range* rhs)
|
||||
{
|
||||
|
@ -1874,6 +1884,13 @@ MRandom::computeRange(TempAllocator& alloc)
|
|||
setRange(r);
|
||||
}
|
||||
|
||||
void
|
||||
MNaNToZero::computeRange(TempAllocator& alloc)
|
||||
{
|
||||
Range other(input());
|
||||
setRange(Range::NaNToZero(alloc, &other));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Range Analysis
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -3466,6 +3483,17 @@ MBinaryBitwiseInstruction::collectRangeInfoPreTrunc()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MNaNToZero::collectRangeInfoPreTrunc()
|
||||
{
|
||||
Range inputRange(input());
|
||||
|
||||
if (!inputRange.canBeNaN())
|
||||
operandIsNeverNaN_ = true;
|
||||
if (!inputRange.canBeNegativeZero())
|
||||
operandIsNeverNegativeZero_ = true;
|
||||
}
|
||||
|
||||
bool
|
||||
RangeAnalysis::prepareForUCE(bool* shouldRemoveDeadCode)
|
||||
{
|
||||
|
|
|
@ -482,6 +482,7 @@ class Range : public TempObject {
|
|||
static Range* floor(TempAllocator& alloc, const Range* op);
|
||||
static Range* ceil(TempAllocator& alloc, const Range* op);
|
||||
static Range* sign(TempAllocator& alloc, const Range* op);
|
||||
static Range* NaNToZero(TempAllocator& alloc, const Range* op);
|
||||
|
||||
static MOZ_MUST_USE bool negativeZeroMul(const Range* lhs, const Range* rhs);
|
||||
|
||||
|
|
|
@ -1051,6 +1051,31 @@ RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const
|
||||
{
|
||||
MOZ_ASSERT(canRecoverOnBailout());
|
||||
writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero));
|
||||
return true;
|
||||
}
|
||||
|
||||
RNaNToZero::RNaNToZero(CompactBufferReader& reader)
|
||||
{ }
|
||||
|
||||
|
||||
bool
|
||||
RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||
{
|
||||
RootedValue v(cx, iter.read());
|
||||
RootedValue result(cx);
|
||||
|
||||
MOZ_ASSERT(v.isDouble());
|
||||
result.setDouble((mozilla::IsNaN(v.toDouble()) || mozilla::IsNegativeZero(v.toDouble())) ? 0.0 : v.toDouble());
|
||||
|
||||
iter.storeInstructionResult(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MRegExpMatcher::writeRecoverData(CompactBufferWriter& writer) const
|
||||
{
|
||||
|
|
|
@ -90,6 +90,7 @@ namespace jit {
|
|||
_(MathFunction) \
|
||||
_(Random) \
|
||||
_(StringSplit) \
|
||||
_(NaNToZero) \
|
||||
_(RegExpMatcher) \
|
||||
_(RegExpSearcher) \
|
||||
_(RegExpTester) \
|
||||
|
@ -478,6 +479,14 @@ class RStringSplit final : public RInstruction
|
|||
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const;
|
||||
};
|
||||
|
||||
class RNaNToZero final : public RInstruction
|
||||
{
|
||||
public:
|
||||
RINSTRUCTION_HEADER_NUM_OP_(NaNToZero, 1);
|
||||
|
||||
bool recover(JSContext* cx, SnapshotIterator& iter) const;
|
||||
};
|
||||
|
||||
class RRegExpMatcher final : public RInstruction
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -4566,6 +4566,30 @@ class LStart : public LInstructionHelper<0, 0, 0>
|
|||
LIR_HEADER(Start)
|
||||
};
|
||||
|
||||
class LNaNToZero : public LInstructionHelper<1, 1, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(NaNToZero)
|
||||
|
||||
explicit LNaNToZero(const LAllocation& input, const LDefinition& tempDouble) {
|
||||
setOperand(0, input);
|
||||
setTemp(0, tempDouble);
|
||||
}
|
||||
|
||||
const MNaNToZero* mir() {
|
||||
return mir_->toNaNToZero();
|
||||
}
|
||||
const LAllocation* input() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LDefinition* output() {
|
||||
return getDef(0);
|
||||
}
|
||||
const LDefinition* tempDouble() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Passed the BaselineFrame address in the OsrFrameReg by SideCannon().
|
||||
// Forwards this object to the LOsrValues for Value materialization.
|
||||
class LOsrEntry : public LInstructionHelper<1, 0, 1>
|
||||
|
|
|
@ -222,6 +222,7 @@
|
|||
_(Float32x4ToInt32x4) \
|
||||
_(Float32x4ToUint32x4) \
|
||||
_(Start) \
|
||||
_(NaNToZero) \
|
||||
_(OsrEntry) \
|
||||
_(OsrValue) \
|
||||
_(OsrEnvironmentChain) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче