mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
Bug 999580 - IonMonkey: Generalize RangeAnalysis truncation to handle other kinds of paths to integer types. r=nbp
This commit is contained in:
parent
3afa6d1ec8
commit
4caac74d72
@ -1621,7 +1621,7 @@ MAdd::fallible() const
|
||||
{
|
||||
// the add is fallible if range analysis does not say that it is finite, AND
|
||||
// either the truncation analysis shows that there are non-truncated uses.
|
||||
if (isTruncated())
|
||||
if (truncateKind() >= IndirectTruncate)
|
||||
return false;
|
||||
if (range() && range()->hasInt32Bounds())
|
||||
return false;
|
||||
@ -1632,7 +1632,7 @@ bool
|
||||
MSub::fallible() const
|
||||
{
|
||||
// see comment in MAdd::fallible()
|
||||
if (isTruncated())
|
||||
if (truncateKind() >= IndirectTruncate)
|
||||
return false;
|
||||
if (range() && range()->hasInt32Bounds())
|
||||
return false;
|
||||
|
136
js/src/jit/MIR.h
136
js/src/jit/MIR.h
@ -412,8 +412,44 @@ class MDefinition : public MNode
|
||||
virtual void analyzeEdgeCasesForward();
|
||||
virtual void analyzeEdgeCasesBackward();
|
||||
|
||||
virtual bool truncate();
|
||||
virtual bool isOperandTruncated(size_t index) const;
|
||||
// When a floating-point value is used by nodes which would prefer to
|
||||
// recieve integer inputs, we may be able to help by computing our result
|
||||
// into an integer directly.
|
||||
//
|
||||
// A value can be truncated in 4 differents ways:
|
||||
// 1. Ignore Infinities (x / 0 --> 0).
|
||||
// 2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
|
||||
// 3. Ignore negative zeros. (-0 --> 0)
|
||||
// 4. Ignore remainder. (3 / 4 --> 0)
|
||||
//
|
||||
// Indirect truncation is used to represent that we are interested in the
|
||||
// truncated result, but only if it can safely flow into operations which
|
||||
// are computed modulo 2^32, such as (2) and (3). Infinities are not safe,
|
||||
// as they would have absorbed other math operations. Remainders are not
|
||||
// safe, as fractions can be scaled up by multiplication.
|
||||
//
|
||||
// Division is a particularly interesting node here because it covers all 4
|
||||
// cases even when its own operands are integers.
|
||||
//
|
||||
// Note that these enum values are ordered from least value-modifying to
|
||||
// most value-modifying, and code relies on this ordering.
|
||||
enum TruncateKind {
|
||||
// No correction.
|
||||
NoTruncate = 0,
|
||||
// An integer is desired, but we can't skip bailout checks.
|
||||
TruncateAfterBailouts = 1,
|
||||
// The value will be truncated after some arithmetic (see above).
|
||||
IndirectTruncate = 2,
|
||||
// Direct and infallible truncation to int32.
|
||||
Truncate = 3
|
||||
};
|
||||
|
||||
// Apply the given truncate to this node itself.
|
||||
virtual bool truncate(TruncateKind kind);
|
||||
|
||||
// Determine what kind of truncate this node prefers for the operand at the
|
||||
// given index.
|
||||
virtual TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
// Compute an absolute or symbolic range for the value of this node.
|
||||
virtual void computeRange(TempAllocator &alloc) {
|
||||
@ -977,7 +1013,7 @@ class MConstant : public MNullaryInstruction
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool truncate(TruncateKind kind);
|
||||
|
||||
bool canProduceFloat32() const;
|
||||
};
|
||||
@ -2375,8 +2411,8 @@ class MCompare
|
||||
|
||||
void trySpecializeFloat32(TempAllocator &alloc);
|
||||
bool isFloat32Commutative() const { return true; }
|
||||
bool truncate();
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
bool truncate(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
# ifdef DEBUG
|
||||
bool isConsistentFloat32Use(MUse *use) const {
|
||||
@ -2905,8 +2941,10 @@ class MToDouble
|
||||
private:
|
||||
ConversionKind conversion_;
|
||||
|
||||
TruncateKind implicitTruncate_;
|
||||
|
||||
MToDouble(MDefinition *def, ConversionKind conversion = NonStringPrimitives)
|
||||
: MUnaryInstruction(def), conversion_(conversion)
|
||||
: MUnaryInstruction(def), conversion_(conversion), implicitTruncate_(NoTruncate)
|
||||
{
|
||||
setResultType(MIRType_Double);
|
||||
setMovable();
|
||||
@ -2946,12 +2984,19 @@ class MToDouble
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
bool truncate(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isConsistentFloat32Use(MUse *use) const { return true; }
|
||||
#endif
|
||||
|
||||
TruncateKind truncateKind() const {
|
||||
return implicitTruncate_;
|
||||
}
|
||||
void setTruncateKind(TruncateKind kind) {
|
||||
implicitTruncate_ = Max(implicitTruncate_, kind);
|
||||
}
|
||||
};
|
||||
|
||||
// Converts a primitive (either typed or untyped) to a float32. If the input is
|
||||
@ -3171,7 +3216,7 @@ class MTruncateToInt32 : public MUnaryInstruction
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
# ifdef DEBUG
|
||||
bool isConsistentFloat32Use(MUse *use) const {
|
||||
return true;
|
||||
@ -3349,7 +3394,7 @@ class MBinaryBitwiseInstruction
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
};
|
||||
|
||||
class MBitAnd : public MBinaryBitwiseInstruction
|
||||
@ -3524,14 +3569,14 @@ class MBinaryArithInstruction
|
||||
// This optimization happens when the multiplication cannot be truncated
|
||||
// even if all uses are truncating its result, such as when the range
|
||||
// analysis detect a precision loss in the multiplication.
|
||||
bool implicitTruncate_;
|
||||
TruncateKind implicitTruncate_;
|
||||
|
||||
void inferFallback(BaselineInspector *inspector, jsbytecode *pc);
|
||||
|
||||
public:
|
||||
MBinaryArithInstruction(MDefinition *left, MDefinition *right)
|
||||
: MBinaryInstruction(left, right),
|
||||
implicitTruncate_(false)
|
||||
implicitTruncate_(NoTruncate)
|
||||
{
|
||||
setMovable();
|
||||
}
|
||||
@ -3566,10 +3611,13 @@ class MBinaryArithInstruction
|
||||
}
|
||||
|
||||
bool isTruncated() const {
|
||||
return implicitTruncate_ == Truncate;
|
||||
}
|
||||
TruncateKind truncateKind() const {
|
||||
return implicitTruncate_;
|
||||
}
|
||||
void setTruncated(bool truncate) {
|
||||
implicitTruncate_ = truncate;
|
||||
void setTruncateKind(TruncateKind kind) {
|
||||
implicitTruncate_ = Max(implicitTruncate_, kind);
|
||||
}
|
||||
};
|
||||
|
||||
@ -4017,7 +4065,7 @@ class MAdd : public MBinaryArithInstruction
|
||||
add->specialization_ = type;
|
||||
add->setResultType(type);
|
||||
if (type == MIRType_Int32) {
|
||||
add->setTruncated(true);
|
||||
add->setTruncateKind(Truncate);
|
||||
add->setCommutative();
|
||||
}
|
||||
return add;
|
||||
@ -4031,8 +4079,8 @@ class MAdd : public MBinaryArithInstruction
|
||||
|
||||
bool fallible() const;
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
bool truncate(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
bool writeRecoverData(CompactBufferWriter &writer) const;
|
||||
bool canRecoverOnBailout() const {
|
||||
@ -4060,7 +4108,7 @@ class MSub : public MBinaryArithInstruction
|
||||
sub->specialization_ = type;
|
||||
sub->setResultType(type);
|
||||
if (type == MIRType_Int32)
|
||||
sub->setTruncated(true);
|
||||
sub->setTruncateKind(Truncate);
|
||||
return sub;
|
||||
}
|
||||
|
||||
@ -4072,8 +4120,8 @@ class MSub : public MBinaryArithInstruction
|
||||
|
||||
bool fallible() const;
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
bool truncate(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
};
|
||||
|
||||
class MMul : public MBinaryArithInstruction
|
||||
@ -4100,7 +4148,7 @@ class MMul : public MBinaryArithInstruction
|
||||
// This implements the required behavior for Math.imul, which
|
||||
// can never fail and always truncates its output to int32.
|
||||
canBeNegativeZero_ = false;
|
||||
setTruncated(true);
|
||||
setTruncateKind(Truncate);
|
||||
setCommutative();
|
||||
}
|
||||
JS_ASSERT_IF(mode != Integer, mode == Normal);
|
||||
@ -4165,8 +4213,8 @@ class MMul : public MBinaryArithInstruction
|
||||
bool isFloat32Commutative() const { return true; }
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
bool truncate(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
Mode mode() const { return mode_; }
|
||||
};
|
||||
@ -4179,32 +4227,13 @@ class MDiv : public MBinaryArithInstruction
|
||||
bool canBeNegativeDividend_;
|
||||
bool unsigned_;
|
||||
|
||||
// A Division can be truncated in 4 differents ways:
|
||||
// 1. Ignore Infinities (x / 0 --> 0).
|
||||
// 2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
|
||||
// 3. Ignore negative zeros. (-0 --> 0)
|
||||
// 4. Ignore remainder. (3 / 4 --> 0)
|
||||
//
|
||||
// isTruncatedIndirectly is used to represent that we are interested in the
|
||||
// truncated result, but only if they it can safely flow in operations which
|
||||
// are computed modulo 2^32, such as (2) and (3).
|
||||
//
|
||||
// A division can return either Infinities (1) or a remainder (4) when both
|
||||
// operands are integers. Infinities are not safe, as they would have
|
||||
// absorbed other math operations. Remainders are not safe, as multiple can
|
||||
// add up to integers. This implies that we need to distinguish between a
|
||||
// division which is truncated directly (isTruncated) or which flow into
|
||||
// truncated operations (isTruncatedIndirectly).
|
||||
bool isTruncatedIndirectly_;
|
||||
|
||||
MDiv(MDefinition *left, MDefinition *right, MIRType type)
|
||||
: MBinaryArithInstruction(left, right),
|
||||
canBeNegativeZero_(true),
|
||||
canBeNegativeOverflow_(true),
|
||||
canBeDivideByZero_(true),
|
||||
canBeNegativeDividend_(true),
|
||||
unsigned_(false),
|
||||
isTruncatedIndirectly_(false)
|
||||
unsigned_(false)
|
||||
{
|
||||
if (type != MIRType_Value)
|
||||
specialization_ = type;
|
||||
@ -4225,7 +4254,7 @@ class MDiv : public MBinaryArithInstruction
|
||||
MDiv *div = new(alloc) MDiv(left, right, type);
|
||||
div->unsigned_ = unsignd;
|
||||
if (type == MIRType_Int32)
|
||||
div->setTruncated(true);
|
||||
div->setTruncateKind(Truncate);
|
||||
return div;
|
||||
}
|
||||
|
||||
@ -4261,10 +4290,7 @@ class MDiv : public MBinaryArithInstruction
|
||||
}
|
||||
|
||||
bool isTruncatedIndirectly() const {
|
||||
return isTruncatedIndirectly_;
|
||||
}
|
||||
void setTruncatedIndirectly(bool truncate) {
|
||||
isTruncatedIndirectly_ = truncate;
|
||||
return truncateKind() >= IndirectTruncate;
|
||||
}
|
||||
|
||||
bool canTruncateInfinities() const {
|
||||
@ -4284,7 +4310,7 @@ class MDiv : public MBinaryArithInstruction
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool fallible() const;
|
||||
bool truncate();
|
||||
bool truncate(TruncateKind kind);
|
||||
void collectRangeInfoPreTrunc();
|
||||
};
|
||||
|
||||
@ -4314,7 +4340,7 @@ class MMod : public MBinaryArithInstruction
|
||||
MMod *mod = new(alloc) MMod(left, right, type);
|
||||
mod->unsigned_ = unsignd;
|
||||
if (type == MIRType_Int32)
|
||||
mod->setTruncated(true);
|
||||
mod->setTruncateKind(Truncate);
|
||||
return mod;
|
||||
}
|
||||
|
||||
@ -4338,7 +4364,7 @@ class MMod : public MBinaryArithInstruction
|
||||
bool fallible() const;
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool truncate(TruncateKind kind);
|
||||
void collectRangeInfoPreTrunc();
|
||||
};
|
||||
|
||||
@ -6543,7 +6569,7 @@ class MLoadTypedArrayElementStatic
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate();
|
||||
bool truncate(TruncateKind kind);
|
||||
bool canProduceFloat32() const { return typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32; }
|
||||
};
|
||||
|
||||
@ -6608,7 +6634,7 @@ class MStoreTypedArrayElement
|
||||
void setRacy() {
|
||||
racy_ = true;
|
||||
}
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
bool canConsumeFloat32(MUse *use) const {
|
||||
return use->index() == 2 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
|
||||
@ -6676,7 +6702,7 @@ class MStoreTypedArrayElementHole
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::Store(AliasSet::TypedArrayElement);
|
||||
}
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
bool canConsumeFloat32(MUse *use) const {
|
||||
return use->index() == 3 && arrayType_ == ScalarTypeDescr::TYPE_FLOAT32;
|
||||
@ -6723,7 +6749,7 @@ class MStoreTypedArrayElementStatic :
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::Store(AliasSet::TypedArrayElement);
|
||||
}
|
||||
bool isOperandTruncated(size_t index) const;
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
|
||||
bool canConsumeFloat32(MUse *use) const {
|
||||
return use->index() == 1 && typedArray_->type() == ScalarTypeDescr::TYPE_FLOAT32;
|
||||
|
@ -2136,14 +2136,14 @@ Range::wrapAroundToBoolean()
|
||||
}
|
||||
|
||||
bool
|
||||
MDefinition::truncate()
|
||||
MDefinition::truncate(TruncateKind kind)
|
||||
{
|
||||
// No procedure defined for truncating this instruction.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MConstant::truncate()
|
||||
MConstant::truncate(TruncateKind kind)
|
||||
{
|
||||
if (!value_.isDouble())
|
||||
return false;
|
||||
@ -2158,15 +2158,15 @@ MConstant::truncate()
|
||||
}
|
||||
|
||||
bool
|
||||
MAdd::truncate()
|
||||
MAdd::truncate(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncated(true);
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (range())
|
||||
if (kind >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
return true;
|
||||
}
|
||||
@ -2175,15 +2175,15 @@ MAdd::truncate()
|
||||
}
|
||||
|
||||
bool
|
||||
MSub::truncate()
|
||||
MSub::truncate(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed for fallible checks.
|
||||
setTruncated(true);
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
if (range())
|
||||
if (kind >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
return true;
|
||||
}
|
||||
@ -2192,54 +2192,39 @@ MSub::truncate()
|
||||
}
|
||||
|
||||
bool
|
||||
MMul::truncate()
|
||||
MMul::truncate(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncated(true);
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
setCanBeNegativeZero(false);
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MDiv::truncate()
|
||||
{
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncatedIndirectly(true);
|
||||
|
||||
// Check if this division only flows in bitwise instructions.
|
||||
if (!isTruncated()) {
|
||||
bool allUsesExplictlyTruncate = true;
|
||||
for (MUseDefIterator use(this); allUsesExplictlyTruncate && use; use++) {
|
||||
switch (use.def()->op()) {
|
||||
case MDefinition::Op_BitAnd:
|
||||
case MDefinition::Op_BitOr:
|
||||
case MDefinition::Op_BitXor:
|
||||
case MDefinition::Op_Lsh:
|
||||
case MDefinition::Op_Rsh:
|
||||
case MDefinition::Op_Ursh:
|
||||
break;
|
||||
default:
|
||||
allUsesExplictlyTruncate = false;
|
||||
}
|
||||
if (kind >= IndirectTruncate) {
|
||||
setCanBeNegativeZero(false);
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
|
||||
if (allUsesExplictlyTruncate)
|
||||
setTruncated(true);
|
||||
return 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 false;
|
||||
}
|
||||
|
||||
bool
|
||||
MDiv::truncate(TruncateKind kind)
|
||||
{
|
||||
setTruncateKind(kind);
|
||||
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
|
||||
// Divisions where the lhs and rhs are unsigned and the result is
|
||||
// truncated can be lowered more efficiently.
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2248,14 +2233,19 @@ MDiv::truncate()
|
||||
}
|
||||
|
||||
bool
|
||||
MMod::truncate()
|
||||
MMod::truncate(TruncateKind kind)
|
||||
{
|
||||
// Remember analysis, needed to remove negative zero checks.
|
||||
setTruncated(true);
|
||||
setTruncateKind(kind);
|
||||
|
||||
// As for division, handle unsigned modulus with a truncated result.
|
||||
if (specialization() == MIRType_Int32 && tryUseUnsignedOperands()) {
|
||||
unsigned_ = true;
|
||||
if (type() == MIRType_Double || type() == MIRType_Int32) {
|
||||
specialization_ = MIRType_Int32;
|
||||
setResultType(MIRType_Int32);
|
||||
|
||||
if (tryUseUnsignedOperands())
|
||||
unsigned_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2264,90 +2254,103 @@ MMod::truncate()
|
||||
}
|
||||
|
||||
bool
|
||||
MToDouble::truncate()
|
||||
MToDouble::truncate(TruncateKind kind)
|
||||
{
|
||||
JS_ASSERT(type() == MIRType_Double);
|
||||
|
||||
setTruncateKind(kind);
|
||||
|
||||
// We use the return type to flag that this MToDouble should be replaced by
|
||||
// a MTruncateToInt32 when modifying the graph.
|
||||
setResultType(MIRType_Int32);
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
if (kind >= IndirectTruncate) {
|
||||
if (range())
|
||||
range()->wrapAroundToInt32();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MLoadTypedArrayElementStatic::truncate()
|
||||
MLoadTypedArrayElementStatic::truncate(TruncateKind kind)
|
||||
{
|
||||
setInfallible();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MDefinition::isOperandTruncated(size_t index) const
|
||||
MDefinition::TruncateKind
|
||||
MDefinition::operandTruncateKind(size_t index) const
|
||||
{
|
||||
return false;
|
||||
// Generic routine: We don't know anything.
|
||||
return NoTruncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MTruncateToInt32::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// This operator is an explicit truncate to int32.
|
||||
return Truncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MBinaryBitwiseInstruction::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// The bitwise operators truncate to int32.
|
||||
return Truncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MAdd::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// This operator is doing some arithmetic. If its result is truncated,
|
||||
// it's an indirect truncate for its operands.
|
||||
return Min(truncateKind(), IndirectTruncate);
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MSub::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// See the comment in MAdd::operandTruncateKind.
|
||||
return Min(truncateKind(), IndirectTruncate);
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MMul::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// See the comment in MAdd::operandTruncateKind.
|
||||
return Min(truncateKind(), IndirectTruncate);
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MToDouble::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// MToDouble propagates its truncate kind to its operand.
|
||||
return truncateKind();
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MStoreTypedArrayElement::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// An integer store truncates the stored value.
|
||||
return index == 2 && !isFloatArray() ? Truncate : NoTruncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MStoreTypedArrayElementHole::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// An integer store truncates the stored value.
|
||||
return index == 3 && !isFloatArray() ? Truncate : NoTruncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MStoreTypedArrayElementStatic::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// An integer store truncates the stored value.
|
||||
return index == 1 && !isFloatArray() ? Truncate : NoTruncate;
|
||||
}
|
||||
|
||||
bool
|
||||
MTruncateToInt32::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MBinaryBitwiseInstruction::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MAdd::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return isTruncated();
|
||||
}
|
||||
|
||||
bool
|
||||
MSub::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return isTruncated();
|
||||
}
|
||||
|
||||
bool
|
||||
MMul::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return isTruncated();
|
||||
}
|
||||
|
||||
bool
|
||||
MToDouble::isOperandTruncated(size_t index) const
|
||||
{
|
||||
// The return type is used to flag that we are replacing this Double by a
|
||||
// Truncate of its operand if needed.
|
||||
return type() == MIRType_Int32;
|
||||
}
|
||||
|
||||
bool
|
||||
MStoreTypedArrayElement::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return index == 2 && !isFloatArray();
|
||||
}
|
||||
|
||||
bool
|
||||
MStoreTypedArrayElementHole::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return index == 3 && !isFloatArray();
|
||||
}
|
||||
|
||||
bool
|
||||
MStoreTypedArrayElementStatic::isOperandTruncated(size_t index) const
|
||||
{
|
||||
return index == 1 && !isFloatArray();
|
||||
}
|
||||
|
||||
bool
|
||||
MCompare::truncate()
|
||||
MCompare::truncate(TruncateKind kind)
|
||||
{
|
||||
if (!isDoubleComparison())
|
||||
return false;
|
||||
@ -2359,32 +2362,34 @@ MCompare::truncate()
|
||||
|
||||
compareType_ = Compare_Int32;
|
||||
|
||||
// Truncating the operands won't change their value, but it will change
|
||||
// their type, which we need because we now expect integer inputs.
|
||||
// Truncating the operands won't change their value because we don't force a
|
||||
// truncation, but it will change their type, which we need because we
|
||||
// now expect integer inputs.
|
||||
truncateOperands_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MCompare::isOperandTruncated(size_t index) const
|
||||
MDefinition::TruncateKind
|
||||
MCompare::operandTruncateKind(size_t index) const
|
||||
{
|
||||
// If we're doing an int32 comparison on operands which were previously
|
||||
// floating-point, convert them!
|
||||
JS_ASSERT_IF(truncateOperands_, isInt32Comparison());
|
||||
return truncateOperands_;
|
||||
return truncateOperands_ ? TruncateAfterBailouts : NoTruncate;
|
||||
}
|
||||
|
||||
// Ensure that all observables uses can work with a truncated
|
||||
// version of the |candidate|'s result.
|
||||
static bool
|
||||
AllUsesTruncate(MInstruction *candidate)
|
||||
// Examine all the users of |candidate| and determine the most aggressive
|
||||
// truncate kind that satisfies all of them.
|
||||
static MDefinition::TruncateKind
|
||||
ComputeRequestedTruncateKind(MInstruction *candidate)
|
||||
{
|
||||
// If the value naturally produces an int32 value (before bailout checks)
|
||||
// that needs no conversion, we don't have to worry about resume points
|
||||
// seeing truncated values.
|
||||
bool needsConversion = !candidate->range() || !candidate->range()->isInt32();
|
||||
|
||||
MDefinition::TruncateKind kind = MDefinition::Truncate;
|
||||
for (MUseIterator use(candidate->usesBegin()); use != candidate->usesEnd(); use++) {
|
||||
if (!use->consumer()->isDefinition()) {
|
||||
// We can only skip testing resume points, if all original uses are
|
||||
@ -2393,24 +2398,27 @@ AllUsesTruncate(MInstruction *candidate)
|
||||
// value, and any bailout with a truncated value might lead an
|
||||
// incorrect value.
|
||||
if (candidate->isUseRemoved() && needsConversion)
|
||||
return false;
|
||||
kind = Min(kind, MDefinition::TruncateAfterBailouts);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!use->consumer()->toDefinition()->isOperandTruncated(use->index()))
|
||||
return false;
|
||||
MDefinition *consumer = use->consumer()->toDefinition();
|
||||
MDefinition::TruncateKind consumerKind = consumer->operandTruncateKind(use->index());
|
||||
kind = Min(kind, consumerKind);
|
||||
if (kind == MDefinition::NoTruncate)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
return kind;
|
||||
}
|
||||
|
||||
static bool
|
||||
CanTruncate(MInstruction *candidate)
|
||||
static MDefinition::TruncateKind
|
||||
ComputeTruncateKind(MInstruction *candidate)
|
||||
{
|
||||
// Compare operations might coerce its inputs to int32 if the ranges are
|
||||
// correct. So we do not need to check if all uses are coerced.
|
||||
if (candidate->isCompare())
|
||||
return true;
|
||||
return MDefinition::TruncateAfterBailouts;
|
||||
|
||||
// Set truncated flag if range analysis ensure that it has no
|
||||
// rounding errors and no fractional part. Note that we can't use
|
||||
@ -2425,10 +2433,10 @@ CanTruncate(MInstruction *candidate)
|
||||
canHaveRoundingErrors = false;
|
||||
|
||||
if (canHaveRoundingErrors)
|
||||
return false;
|
||||
return MDefinition::NoTruncate;
|
||||
|
||||
// Ensure all observable uses are truncated.
|
||||
return AllUsesTruncate(candidate);
|
||||
return ComputeRequestedTruncateKind(candidate);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2455,7 +2463,7 @@ AdjustTruncatedInputs(TempAllocator &alloc, MInstruction *truncated)
|
||||
{
|
||||
MBasicBlock *block = truncated->block();
|
||||
for (size_t i = 0, e = truncated->numOperands(); i < e; i++) {
|
||||
if (!truncated->isOperandTruncated(i))
|
||||
if (truncated->operandTruncateKind(i) == MDefinition::NoTruncate)
|
||||
continue;
|
||||
|
||||
MDefinition *input = truncated->getOperand(i);
|
||||
@ -2515,11 +2523,12 @@ RangeAnalysis::truncate()
|
||||
default:;
|
||||
}
|
||||
|
||||
if (!CanTruncate(*iter))
|
||||
MDefinition::TruncateKind kind = ComputeTruncateKind(*iter);
|
||||
if (kind == MDefinition::NoTruncate)
|
||||
continue;
|
||||
|
||||
// Truncate this instruction if possible.
|
||||
if (!iter->truncate())
|
||||
if (!iter->truncate(kind))
|
||||
continue;
|
||||
|
||||
// Delay updates of inputs/outputs to avoid creating node which
|
||||
|
Loading…
Reference in New Issue
Block a user