mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1000605 - Prevent division's truncation after removal of Math functions. r=sunfish,bbouvier
This commit is contained in:
parent
4a35fe6ead
commit
4a8cc281cc
43
js/src/jit-test/tests/ion/bug1000605.js
Normal file
43
js/src/jit-test/tests/ion/bug1000605.js
Normal file
@ -0,0 +1,43 @@
|
||||
setJitCompilerOption("baseline.usecount.trigger", 0);
|
||||
setJitCompilerOption("ion.usecount.trigger", 0);
|
||||
|
||||
function ceil(a, b) {
|
||||
return Math.ceil((a | 0) / (b | 0)) | 0;
|
||||
}
|
||||
function floor(a, b) {
|
||||
return Math.floor((a | 0) / (b | 0)) | 0;
|
||||
}
|
||||
function round(a, b) {
|
||||
return Math.round((a | 0) / (b | 0)) | 0;
|
||||
}
|
||||
function intdiv(a, b) {
|
||||
return ((a | 0) / (b | 0)) | 0;
|
||||
}
|
||||
|
||||
// Always rounds up.
|
||||
assertEq(ceil(5, 5), 1);
|
||||
assertEq(ceil(4, 3), 2);
|
||||
assertEq(ceil(5, 3), 2);
|
||||
assertEq(ceil(-4, 3), -1);
|
||||
assertEq(ceil(-5, 3), -1);
|
||||
|
||||
// Always rounds down.
|
||||
assertEq(floor(5, 5), 1);
|
||||
assertEq(floor(4, 3), 1);
|
||||
assertEq(floor(5, 3), 1);
|
||||
assertEq(floor(-4, 3), -2);
|
||||
assertEq(floor(-5, 3), -2);
|
||||
|
||||
// Always rounds towards the nearest.
|
||||
assertEq(round(5, 5), 1);
|
||||
assertEq(round(4, 3), 1);
|
||||
assertEq(round(5, 3), 2);
|
||||
assertEq(round(-4, 3), -1);
|
||||
assertEq(round(-5, 3), -2);
|
||||
|
||||
// Always rounds towards zero.
|
||||
assertEq(intdiv(5, 5), 1);
|
||||
assertEq(intdiv(4, 3), 1);
|
||||
assertEq(intdiv(5, 3), 1);
|
||||
assertEq(intdiv(-4, 3), -1);
|
||||
assertEq(intdiv(-5, 3), -1);
|
@ -1638,6 +1638,12 @@ LIRGenerator::visitNop(MNop *nop)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitLimitedTruncate(MLimitedTruncate *nop)
|
||||
{
|
||||
return redefine(nop, nop->input());
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitOsrEntry(MOsrEntry *entry)
|
||||
{
|
||||
|
@ -141,6 +141,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
bool visitStart(MStart *start);
|
||||
bool visitOsrEntry(MOsrEntry *entry);
|
||||
bool visitNop(MNop *nop);
|
||||
bool visitLimitedTruncate(MLimitedTruncate *nop);
|
||||
bool visitOsrValue(MOsrValue *value);
|
||||
bool visitOsrScopeChain(MOsrScopeChain *object);
|
||||
bool visitOsrReturnValue(MOsrReturnValue *value);
|
||||
|
@ -651,7 +651,14 @@ IonBuilder::inlineMathFloor(CallInfo &callInfo)
|
||||
// Math.floor(int(x)) == int(x)
|
||||
if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
current->push(callInfo.getArg(0));
|
||||
// The int operand may be something which bails out if the actual value
|
||||
// is not in the range of the result type of the MIR. We need to tell
|
||||
// the optimizer to preserve this bailout even if the final result is
|
||||
// fully truncated.
|
||||
MLimitedTruncate *ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
|
||||
MDefinition::IndirectTruncate);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
@ -689,7 +696,14 @@ IonBuilder::inlineMathCeil(CallInfo &callInfo)
|
||||
// Math.ceil(int(x)) == int(x)
|
||||
if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
current->push(callInfo.getArg(0));
|
||||
// The int operand may be something which bails out if the actual value
|
||||
// is not in the range of the result type of the MIR. We need to tell
|
||||
// the optimizer to preserve this bailout even if the final result is
|
||||
// fully truncated.
|
||||
MLimitedTruncate *ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
|
||||
MDefinition::IndirectTruncate);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
@ -719,7 +733,14 @@ IonBuilder::inlineMathRound(CallInfo &callInfo)
|
||||
// Math.round(int(x)) == int(x)
|
||||
if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
current->push(callInfo.getArg(0));
|
||||
// The int operand may be something which bails out if the actual value
|
||||
// is not in the range of the result type of the MIR. We need to tell
|
||||
// the optimizer to preserve this bailout even if the final result is
|
||||
// fully truncated.
|
||||
MLimitedTruncate *ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
|
||||
MDefinition::IndirectTruncate);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
|
@ -1013,6 +1013,45 @@ class MNop : public MNullaryInstruction
|
||||
}
|
||||
};
|
||||
|
||||
// No-op instruction. This cannot be moved or eliminated, and is intended for
|
||||
// protecting the input against follow-up optimization.
|
||||
class MLimitedTruncate : public MUnaryInstruction
|
||||
{
|
||||
public:
|
||||
TruncateKind truncate_;
|
||||
TruncateKind truncateLimit_;
|
||||
|
||||
protected:
|
||||
MLimitedTruncate(MDefinition *input, TruncateKind limit)
|
||||
: MUnaryInstruction(input),
|
||||
truncate_(NoTruncate),
|
||||
truncateLimit_(limit)
|
||||
{
|
||||
setResultType(input->type());
|
||||
setResultTypeSet(input->resultTypeSet());
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(LimitedTruncate)
|
||||
static MLimitedTruncate *New(TempAllocator &alloc, MDefinition *input, TruncateKind kind) {
|
||||
return new(alloc) MLimitedTruncate(input, kind);
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
||||
void computeRange(TempAllocator &alloc);
|
||||
bool truncate(TruncateKind kind);
|
||||
TruncateKind operandTruncateKind(size_t index) const;
|
||||
TruncateKind truncateKind() const {
|
||||
return truncate_;
|
||||
}
|
||||
void setTruncateKind(TruncateKind kind) {
|
||||
truncate_ = kind;
|
||||
}
|
||||
};
|
||||
|
||||
// A constant js::Value.
|
||||
class MConstant : public MNullaryInstruction
|
||||
{
|
||||
|
@ -101,6 +101,7 @@ namespace jit {
|
||||
_(Start) \
|
||||
_(OsrEntry) \
|
||||
_(Nop) \
|
||||
_(LimitedTruncate) \
|
||||
_(RegExp) \
|
||||
_(RegExpExec) \
|
||||
_(RegExpTest) \
|
||||
|
@ -194,6 +194,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
SAFE_OP(Start)
|
||||
UNSAFE_OP(OsrEntry)
|
||||
SAFE_OP(Nop)
|
||||
SAFE_OP(LimitedTruncate)
|
||||
UNSAFE_OP(RegExp)
|
||||
CUSTOM_OP(Lambda)
|
||||
UNSAFE_OP(LambdaArrow)
|
||||
|
@ -1384,6 +1384,13 @@ MToInt32::computeRange(TempAllocator &alloc)
|
||||
setRange(output);
|
||||
}
|
||||
|
||||
void
|
||||
MLimitedTruncate::computeRange(TempAllocator &alloc)
|
||||
{
|
||||
Range *output = new(alloc) Range(input());
|
||||
setRange(output);
|
||||
}
|
||||
|
||||
static Range *GetTypedArrayRange(TempAllocator &alloc, int type)
|
||||
{
|
||||
switch (type) {
|
||||
@ -2283,6 +2290,16 @@ MLoadTypedArrayElementStatic::truncate(TruncateKind kind)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MLimitedTruncate::truncate(TruncateKind kind)
|
||||
{
|
||||
setTruncateKind(kind);
|
||||
setResultType(MIRType_Int32);
|
||||
if (kind >= IndirectTruncate && range())
|
||||
range()->wrapAroundToInt32();
|
||||
return false;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MDefinition::operandTruncateKind(size_t index) const
|
||||
{
|
||||
@ -2304,6 +2321,12 @@ MBinaryBitwiseInstruction::operandTruncateKind(size_t index) const
|
||||
return Truncate;
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MLimitedTruncate::operandTruncateKind(size_t index) const
|
||||
{
|
||||
return Min(truncateKind(), truncateLimit_);
|
||||
}
|
||||
|
||||
MDefinition::TruncateKind
|
||||
MAdd::operandTruncateKind(size_t index) const
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user