diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 7290bd984e0..3237cf03384 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -5781,6 +5781,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode { js::Vector inputs_; + TruncateKind truncateKind_; bool hasBackedgeType_; bool triedToSpecialize_; bool isIterator_; @@ -5810,6 +5811,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode MPhi(TempAllocator &alloc, MIRType resultType) : inputs_(alloc), + truncateKind_(NoTruncate), hasBackedgeType_(false), triedToSpecialize_(false), isIterator_(false), @@ -5929,6 +5931,9 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode void setCanConsumeFloat32(bool can) { canConsumeFloat32_ = can; } + + TruncateKind operandTruncateKind(size_t index) const; + bool truncate(TruncateKind kind); }; // The goal of a Beta node is to split a def at a conditionally taken diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index d0a1924dbb7..ab69d7e9a03 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -2163,6 +2163,20 @@ MConstant::truncate(TruncateKind kind) return true; } +bool +MPhi::truncate(TruncateKind kind) +{ + if (type() == MIRType_Double || type() == MIRType_Int32) { + truncateKind_ = kind; + setResultType(MIRType_Int32); + if (kind >= IndirectTruncate && range()) + range()->wrapAroundToInt32(); + return true; + } + + return false; +} + bool MAdd::truncate(TruncateKind kind) { @@ -2302,6 +2316,14 @@ MDefinition::operandTruncateKind(size_t index) const return NoTruncate; } +MDefinition::TruncateKind +MPhi::operandTruncateKind(size_t index) const +{ + // The truncation applied to a phi is effectively applied to the phi's + // operands. + return truncateKind_; +} + MDefinition::TruncateKind MTruncateToInt32::operandTruncateKind(size_t index) const { @@ -2460,7 +2482,7 @@ TruncateTest(TempAllocator &alloc, MTest *test) // Examine all the users of |candidate| and determine the most aggressive // truncate kind that satisfies all of them. static MDefinition::TruncateKind -ComputeRequestedTruncateKind(MInstruction *candidate) +ComputeRequestedTruncateKind(MDefinition *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 @@ -2491,7 +2513,7 @@ ComputeRequestedTruncateKind(MInstruction *candidate) } static MDefinition::TruncateKind -ComputeTruncateKind(MInstruction *candidate) +ComputeTruncateKind(MDefinition *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. @@ -2518,7 +2540,7 @@ ComputeTruncateKind(MInstruction *candidate) } static void -RemoveTruncatesOnOutput(MInstruction *truncated) +RemoveTruncatesOnOutput(MDefinition *truncated) { // Compare returns a boolean so it doen't have any output truncates. if (truncated->isCompare()) @@ -2537,7 +2559,7 @@ RemoveTruncatesOnOutput(MInstruction *truncated) } static void -AdjustTruncatedInputs(TempAllocator &alloc, MInstruction *truncated) +AdjustTruncatedInputs(TempAllocator &alloc, MDefinition *truncated) { MBasicBlock *block = truncated->block(); for (size_t i = 0, e = truncated->numOperands(); i < e; i++) { @@ -2552,20 +2574,26 @@ AdjustTruncatedInputs(TempAllocator &alloc, MInstruction *truncated) if (input->isToDouble() && input->getOperand(0)->type() == MIRType_Int32) { JS_ASSERT(input->range()->isInt32()); truncated->replaceOperand(i, input->getOperand(0)); - } else if (kind == MDefinition::TruncateAfterBailouts) { - MToInt32 *op = MToInt32::New(alloc, truncated->getOperand(i)); - block->insertBefore(truncated, op); - truncated->replaceOperand(i, op); } else { - MTruncateToInt32 *op = MTruncateToInt32::New(alloc, truncated->getOperand(i)); - block->insertBefore(truncated, op); + MInstruction *op; + if (kind == MDefinition::TruncateAfterBailouts) + op = MToInt32::New(alloc, truncated->getOperand(i)); + else + op = MTruncateToInt32::New(alloc, truncated->getOperand(i)); + + if (truncated->isPhi()) { + MBasicBlock *pred = op->block()->getPredecessor(i); + pred->insertBefore(pred->lastIns(), op); + } else { + block->insertBefore(truncated->toInstruction(), op); + } truncated->replaceOperand(i, op); } } if (truncated->isToDouble()) { - truncated->replaceAllUsesWith(truncated->getOperand(0)); - block->discard(truncated); + truncated->replaceAllUsesWith(truncated->toToDouble()->getOperand(0)); + block->discard(truncated->toToDouble()); } } @@ -2591,7 +2619,7 @@ RangeAnalysis::truncate() // any automatic truncations. MOZ_ASSERT(!mir->compilingAsmJS()); - Vector worklist; + Vector worklist; Vector bitops; for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd(); block++) { @@ -2629,15 +2657,30 @@ RangeAnalysis::truncate() if (!worklist.append(*iter)) return false; } + for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ++iter) { + MDefinition::TruncateKind kind = ComputeTruncateKind(*iter); + if (kind == MDefinition::NoTruncate) + continue; + + // Truncate this phi if possible. + if (!iter->truncate(kind)) + continue; + + // Delay updates of inputs/outputs to avoid creating node which + // would be removed by the truncation of the next operations. + iter->setInWorklist(); + if (!worklist.append(*iter)) + return false; + } } // Update inputs/outputs of truncated instructions. JitSpew(JitSpew_Range, "Do graph type fixup (dequeue)"); while (!worklist.empty()) { - MInstruction *ins = worklist.popCopy(); - ins->setNotInWorklist(); - RemoveTruncatesOnOutput(ins); - AdjustTruncatedInputs(alloc(), ins); + MDefinition *def = worklist.popCopy(); + def->setNotInWorklist(); + RemoveTruncatesOnOutput(def); + AdjustTruncatedInputs(alloc(), def); } // Fold any unnecessary bitops in the graph, such as (x | 0) on an integer