/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Documentation.  Code starts about 670 lines down from here.               //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// [SMDOC] An overview of Ion's register allocator
//
// The intent of this documentation is to give maintainers a map with which to
// navigate the allocator.  As further understanding is obtained, it should be
// added to this overview.
//
// Where possible, invariants are stated and are marked "(INVAR)".  Many
// details are omitted because their workings are currently unknown.  In
// particular, this overview doesn't explain how Intel-style "modify" (tied)
// operands are handled.  Facts or invariants that are speculative -- believed
// to be true, but not verified at the time of writing -- are marked "(SPEC)".
//
// The various concepts are interdependent, so a single forwards reading of the
// following won't make much sense.  Many concepts are explained only after
// they are mentioned.
//
// Where possible examples are shown.  Without those the description is
// excessively abstract.
//
// Names of the form ::name mean BacktrackingAllocator::name.
//
// The description falls into two sections:
//
// * Section 1: A tour of the data structures
// * Section 2: The core allocation loop, and bundle splitting
//
// The allocator sometimes produces poor allocations, with excessive spilling
// and register-to-register moves (bugs 1752520, bug 1714280 bug 1746596).
// Work in bug 1752582 shows we can get better quality allocations from this
// framework without having to make any large (conceptual) changes, by having
// better splitting heuristics.
//
// At https://bugzilla.mozilla.org/show_bug.cgi?id=1758274#c17
// (https://bugzilla.mozilla.org/attachment.cgi?id=9288467) is a document
// written at the same time as these comments.  It describes some improvements
// we could make to our splitting heuristics, particularly in the presence of
// loops and calls, and shows why the current implementation sometimes produces
// excessive spilling.  It builds on the commentary in this SMDOC.
//
//
// Top level pipeline
// ~~~~~~~~~~~~~~~~~~
// There are three major phases in allocation.  They run sequentially, at a
// per-function granularity.
//
// (1) Liveness analysis and bundle formation
// (2) Bundle allocation and last-chance allocation
// (3) Rewriting the function to create MoveGroups and to "install"
//     the allocation
//
// The input language (LIR) is in SSA form, and phases (1) and (3) depend on
// that SSAness.  Without it the allocator wouldn't work.
//
// The top level function is ::go.  The phases are divided into functions as
// follows:
//
// (1) ::buildLivenessInfo, ::mergeAndQueueRegisters
// (2) ::processBundle, ::tryAllocatingRegistersForSpillBundles,
//     ::pickStackSlots
// (3) ::createMoveGroupsFromLiveRangeTransitions, ::installAllocationsInLIR,
//     ::populateSafepoints, ::annotateMoveGroups
//
// The code in this file is structured as much as possible in the same sequence
// as flow through the pipeline.  Hence, top level function ::go is right at
// the end.  Where a function depends on helper function(s), the helpers appear
// first.
//
//
// ========================================================================
// ====                                                                ====
// ==== Section 1: A tour of the data structures                       ====
// ====                                                                ====
// ========================================================================
//
// Here are the key data structures necessary for understanding what follows.
//
// Some basic data structures
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// CodePosition
// ------------
// A CodePosition is an unsigned 32-bit int that indicates an instruction index
// in the incoming LIR.  Each LIR actually has two code positions, one to
// denote the "input" point (where, one might imagine, the operands are read,
// at least useAtStart ones) and the "output" point, where operands are
// written.  Eg:
//
//    Block 0 [successor 2] [successor 1]
//      2-3 WasmParameter [def v1<g>:r14]
//      4-5 WasmCall [use v1:F:r14]
//      6-7 WasmLoadTls [def v2<o>] [use v1:R]
//      8-9 WasmNullConstant [def v3<o>]
//      10-11 Compare [def v4<i>] [use v2:R] [use v3:A]
//      12-13 TestIAndBranch [use v4:R]
//
// So for example the WasmLoadTls insn has its input CodePosition as 6 and
// output point as 7.  Input points are even numbered, output points are odd
// numbered.  CodePositions 0 and 1 never appear, because LIR instruction IDs
// start at 1.  Indeed, CodePosition 0 is assumed to be invalid and hence is
// used as a marker for "unusual conditions" in various places.
//
// Phi nodes exist in the instruction stream too.  They always appear at the
// start of blocks (of course) (SPEC), but their start and end points are
// printed for the group as a whole.  This is to emphasise that they are really
// parallel assignments and that printing them sequentially would misleadingly
// imply that they are executed sequentially.  Example:
//
//    Block 6 [successor 7] [successor 8]
//      56-59 Phi [def v19<o>] [use v2:A] [use v5:A] [use v13:A]
//      56-59 Phi [def v20<o>] [use v7:A] [use v14:A] [use v12:A]
//      60-61 WasmLoadSlot [def v21<o>] [use v1:R]
//      62-63 Compare [def v22<i>] [use v20:R] [use v21:A]
//      64-65 TestIAndBranch [use v22:R]
//
// See that both Phis are printed with limits 56-59, even though they are
// stored in the LIR array like regular LIRs and so have code points 56-57 and
// 58-59 in reality.
//
// The process of allocation adds MoveGroup LIRs to the function.  Each
// incoming LIR has its own private list of MoveGroups (actually, 3 lists; two
// for moves that conceptually take place before the instruction, and one for
// moves after it).  Hence the CodePositions for LIRs (the "62-63", etc, above)
// do not change as a result of allocation.
//
// Virtual registers (vregs) in LIR
// --------------------------------
// The MIR from which the LIR is derived, is standard SSA.  That SSAness is
// carried through into the LIR (SPEC).  In the examples here, LIR SSA names
// (virtual registers, a.k.a. vregs) are printed as "v<number>".  v0 never
// appears and is presumed to be a special value, perhaps "invalid" (SPEC).
//
// The allocator core has a type VirtualRegister, but this is private to the
// allocator and not part of the LIR.  It carries far more information than
// merely the name of the vreg.  The allocator creates one VirtualRegister
// structure for each vreg in the LIR.
//
// LDefinition and LUse
// --------------------
// These are part of the incoming LIR.  Each LIR instruction defines zero or
// more values, and contains one LDefinition for each defined value (SPEC).
// Each instruction has zero or more input operands, each of which has its own
// LUse (SPEC).
//
// Both LDefinition and LUse hold both a virtual register name and, in general,
// a real (physical) register identity.  The incoming LIR has the real register
// fields unset, except in places where the incoming LIR has fixed register
// constraints (SPEC).  Phase 3 of allocation will visit all of the
// LDefinitions and LUses so as to write into the real register fields the
// decisions made by the allocator.  For LUses, this is done by overwriting the
// complete LUse with a different LAllocation, for example LStackSlot.  That's
// possible because LUse is a child class of LAllocation.
//
// This action of reading and then later updating LDefinition/LUses is the core
// of the allocator's interface to the outside world.
//
// To make visiting of LDefinitions/LUses possible, the allocator doesn't work
// with LDefinition and LUse directly.  Rather it has pointers to them
// (VirtualRegister::def_, UsePosition::use_).  Hence Phase 3 can modify the
// LIR in-place.
//
// (INVARs, all SPEC):
//
// - The collective VirtualRegister::def_ values should be unique, and there
//   should be a 1:1 mapping between the VirtualRegister::def_ values and the
//   LDefinitions in the LIR.  (So that the LIR LDefinition has exactly one
//   VirtualRegister::def_ to track it).  But only for the valid LDefinitions.
//   If isBogusTemp() is true, the definition is invalid and doesn't have a
//   vreg.
//
// - The same for uses: there must be a 1:1 correspondence between the
//   CodePosition::use_ values and the LIR LUses.
//
// - The allocation process must preserve these 1:1 mappings.  That implies
//   (weaker) that the number of VirtualRegisters and of UsePositions must
//   remain constant through allocation.  (Eg: losing them would mean that some
//   LIR def or use would necessarily not get annotated with its final
//   allocation decision.  Duplicating them would lead to the possibility of
//   conflicting allocation decisions.)
//
// Other comments regarding LIR
// ----------------------------
// The incoming LIR is structured into basic blocks and a CFG, as one would
// expect.  These (insns, block boundaries, block edges etc) are available
// through the BacktrackingAllocator object.  They are important for Phases 1
// and 3 but not for Phase 2.
//
// Phase 3 "rewrites" the input LIR so as to "install" the final allocation.
// It has to insert MoveGroup instructions, but that isn't done by pushing them
// into the instruction array.  Rather, each LIR has 3 auxiliary sets of
// MoveGroups (SPEC): two that "happen" conceptually before the LIR, and one
// that happens after it.  The rewriter inserts MoveGroups into one of these 3
// sets, and later code generation phases presumably insert the sets (suitably
// translated) into the final machine code (SPEC).
//
//
// Key data structures: LiveRange, VirtualRegister and LiveBundle
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// These three have central roles in allocation.  Of them, LiveRange is the
// most central.  VirtualRegister is conceptually important throughout, but
// appears less frequently in the allocator code.  LiveBundle is important only
// in Phase 2 (where it is central) and at the end of Phase 1, but plays no
// role in Phase 3.
//
// It's important to understand that LiveRange and VirtualRegister correspond
// to concepts visible in the incoming LIR, which is in SSA form.  LiveBundle
// by comparison is related to neither the structure of LIR nor its SSA
// properties.  Instead, LiveBundle is an essentially adminstrative structure
// used to accelerate allocation and to implement a crude form of
// move-coalescing.
//
// VirtualRegisters and LiveRanges are (almost) static throughout the process,
// because they reflect aspects of the incoming LIR, which does not change.
// LiveBundles by contrast come and go; they are created, but may be split up
// into new bundles, and old ones abandoned.
//
// Each LiveRange is a member of two different lists.
//
// A VirtualRegister (described in detail below) has a vector of LiveRanges that
// it "owns".
//
// A LiveBundle (also described below) has a linked list of LiveRanges that it
// "owns".
//
// Hence each LiveRange is "owned" by one VirtualRegister and one LiveBundle.
// LiveRanges may have their owning LiveBundle changed as a result of
// splitting.  By contrast a LiveRange stays with its "owning" VirtualRegister
// for ever.
//
// A few LiveRanges have no VirtualRegister.  This is used to implement
// register spilling for calls.  Each physical register that's not preserved
// across a call has a small range that covers the call.  It is
// ::buildLivenessInfo that adds these small ranges.
//
// Iterating over every VirtualRegister in the system is a common operation and
// is straightforward because (somewhat redundantly?) the LIRGraph knows the
// number of vregs, and more importantly because BacktrackingAllocator::vregs
// is a vector of all VirtualRegisters.  By contrast iterating over every
// LiveBundle in the system is more complex because there is no top-level
// registry of them.  It is still possible though.  See ::dumpLiveRangesByVReg
// and ::dumpLiveRangesByBundle for example code.
//
// LiveRange
// ---------
// Fundamentally, a LiveRange (often written just "range") is a request for
// storage of a LIR vreg for some contiguous sequence of LIRs.  A LiveRange
// generally covers only a fraction of a vreg's overall lifetime, so multiple
// LiveRanges are generally needed to cover the whole lifetime.
//
// A LiveRange contains (amongst other things):
//
// * the vreg for which it is for, as a VirtualRegister*
//
// * the range of CodePositions for which it is for, as a LiveRange::Range
//
// * auxiliary information:
//
//   - a boolean that indicates whether this LiveRange defines a value for the
//     vreg.  If so, that definition is regarded as taking place at the first
//     CodePoint of the range.
//
//   - a linked list of uses of the vreg within this range.  Each use is a pair
//     of a CodePosition and an LUse*.  (INVAR): the uses are maintained in
//     increasing order of CodePosition.  Multiple uses at the same
//     CodePosition are permitted, since that is necessary to represent an LIR
//     that uses the same vreg in more than one of its operand slots.
//
// Some important facts about LiveRanges are best illustrated with examples:
//
//   v25 75-82 { 75_def:R 78_v25:A 82_v25:A }
//
// This LiveRange is for vreg v25.  The value is defined at CodePosition 75,
// with the LIR requiring that it be in a register.  It is used twice at
// positions 78 and 82, both with no constraints (A meaning "any").  The range
// runs from position 75 to 82 inclusive.  Note however that LiveRange::Range
// uses non-inclusive range ends; hence its .to field would be 83, not 82.
//
//   v26 84-85 { 85_v26:R }
//
// This LiveRange is for vreg v26.  Here, there's only a single use of it at
// position 85.  Presumably it is defined in some other LiveRange.
//
//   v19 74-79 { }
//
// This LiveRange is for vreg v19.  There is no def and no uses, so at first
// glance this seems redundant.  But it isn't: it still expresses a request for
// storage for v19 across 74-79, because Phase 1 regards v19 as being live in
// this range (meaning: having a value that, if changed in this range, would
// cause the program to fail).
//
// Other points:
//
// * (INVAR) Each vreg/VirtualRegister has at least one LiveRange.
//
// * (INVAR) Exactly one LiveRange of a vreg gives a definition for the value.
//   All other LiveRanges must consist only of uses (including zero uses, for a
//   "flow-though" range as mentioned above).  This requirement follows from
//   the fact that LIR is in SSA form.
//
// * It follows from this, that the LiveRanges for a VirtualRegister must form
//   a tree, where the parent-child relationship is "control flows directly
//   from a parent LiveRange (anywhere in the LiveRange) to a child LiveRange
//   (start)".  The entire tree carries only one value.  This is a use of
//   SSAness in the allocator which is fundamental: without SSA input, this
//   design would not work.
//
//   The root node (LiveRange) in the tree must be one that defines the value,
//   and all other nodes must only use or be flow-throughs for the value.  It's
//   OK for LiveRanges in the tree to overlap, providing that there is a unique
//   root node -- otherwise it would be unclear which LiveRange provides the
//   value.
//
//   The function ::createMoveGroupsFromLiveRangeTransitions runs after all
//   LiveBundles have been allocated.  It visits each VirtualRegister tree in
//   turn.  For every parent->child edge in a tree, it creates a MoveGroup that
//   copies the value from the parent into the child -- this is how the
//   allocator decides where to put MoveGroups.  There are various other
//   details not described here.
//
// * It's important to understand that a LiveRange carries no meaning about
//   control flow beyond that implied by the SSA (hence, dominance)
//   relationship between a def and its uses.  In particular, there's no
//   implication that execution "flowing into" the start of the range implies
//   that it will "flow out" of the end.  Or that any particular use will or
//   will not be executed.
//
// * (very SPEC) Indeed, even if a range has a def, there's no implication that
//   a use later in the range will have been immediately preceded by execution
//   of the def.  It could be that the def is executed, flow jumps somewhere
//   else, and later jumps back into the middle of the range, where there are
//   then some uses.
//
// * Uses of a vreg by a phi node are not mentioned in the use list of a
//   LiveRange.  The reasons for this are unknown, but it is speculated that
//   this is because we don't need to know about phi uses where we use the list
//   of positions.  See comments on VirtualRegister::usedByPhi_.
//
// * Similarly, a definition of a vreg by a phi node is not regarded as being a
//   definition point (why not?), at least as the view of
//   LiveRange::hasDefinition_.
//
// * LiveRanges that nevertheless include a phi-defined value have their first
//   point set to the first of the block of phis, even if the var isn't defined
//   by that specific phi.  Eg:
//
//    Block 6 [successor 7] [successor 8]
//      56-59 Phi [def v19<o>] [use v2:A] [use v5:A] [use v13:A]
//      56-59 Phi [def v20<o>] [use v7:A] [use v14:A] [use v12:A]
//      60-61 WasmLoadSlot [def v21<o>] [use v1:R]
//      62-63 Compare [def v22<i>] [use v20:R] [use v21:A]
//
//   The relevant live range for v20 is
//
//    v20 56-65 { 63_v20:R }
//
//   Observe that it starts at 56, not 58.
//
// VirtualRegister
// ---------------
// Each VirtualRegister is associated with an SSA value created by the LIR.
// Fundamentally it is a container to hold all of the LiveRanges that together
// indicate where the value must be kept live.  The live ranges are stored in a
// vector, VirtualRegister::ranges_.  The set of LiveRanges must logically form
// a tree, rooted at the LiveRange which defines the value.
//
// The live ranges are sorted in order of decreasing start point by construction
// after buildLivenessInfo until the main register allocation loops.  At that
// point they can become unsorted and this is important for performance because
// it allows the core allocation code to add/remove ranges more efficiently.
// After all bundles are allocated, sortVirtualRegisterRanges is called to
// ensure the ranges are sorted again.
//
// There are various auxiliary fields, most importantly the LIR node and the
// associated LDefinition that define the value.
//
// It is OK, and quite common, for LiveRanges of a VirtualRegister to overlap.
// The effect will be that, in an overlapped area, there are two storage
// locations holding the value.  This is OK -- although wasteful of storage
// resources -- because the SSAness means the value must be the same in both
// locations.  Hence there's no questions like "which LiveRange holds the most
// up-to-date value?", since it's all just one value anyway.
//
// Note by contrast, it is *not* OK for the LiveRanges of a LiveBundle to
// overlap.
//
// LiveBundle
// ----------
// Similar to VirtualRegister, a LiveBundle is also, fundamentally, a container
// for a set of LiveRanges.  The set is stored as a linked list, rooted at
// LiveBundle::ranges_.
//
// However, the similarity ends there:
//
// * The LiveRanges in a LiveBundle absolutely must not overlap.  They must
//   indicate disjoint sets of CodePositions, and must be stored in the list in
//   order of increasing CodePosition.  Because of the no-overlap requirement,
//   these ranges form a total ordering regardless of whether one uses the
//   LiveRange::Range::from_ or ::to_ fields for comparison.
//
// * The LiveRanges in a LiveBundle can otherwise be entirely arbitrary and
//   unrelated.  They can be from different VirtualRegisters and can have no
//   particular mutual significance w.r.t. the SSAness or structure of the
//   input LIR.
//
// LiveBundles are the fundamental unit of allocation.  The allocator attempts
// to find a single storage location that will work for all LiveRanges in the
// bundle.  That's why the ranges must not overlap.  If no such location can be
// found, the allocator may decide to split the bundle into multiple smaller
// bundles.  Each of those may be allocated independently.
//
// The other really important field is LiveBundle::alloc_, indicating the
// chosen storage location.
//
// Here's an example, for a LiveBundle before it has been allocated:
//
//   LB2(parent=none v3 8-21 { 16_v3:A } ## v3 24-25 { 25_v3:F:xmm0 })
//
// LB merely indicates "LiveBundle", and the 2 is the id_ value (see
// below).  This bundle has two LiveRanges
//
//   v3 8-21 { 16_v3:A }
//   v3 24-25 { 25_v3:F:xmm0 }
//
// both of which (coincidentally) are for the same VirtualRegister, v3.The
// second LiveRange has a fixed use in `xmm0`, whilst the first one doesn't
// care (A meaning "any location") so the allocator *could* choose `xmm0` for
// the bundle as a whole.
//
// One might ask: why bother with LiveBundle at all?  After all, it would be
// possible to get correct allocations by allocating each LiveRange
// individually, then leaving ::createMoveGroupsFromLiveRangeTransitions to add
// MoveGroups to join up LiveRanges that form each SSA value tree (that is,
// LiveRanges belonging to each VirtualRegister).
//
// There are two reasons:
//
// (1) By putting multiple LiveRanges into each LiveBundle, we can end up with
//     many fewer LiveBundles than LiveRanges.  Since the cost of allocating a
//     LiveBundle is substantially less than the cost of allocating each of its
//     LiveRanges individually, the allocator will run faster.
//
// (2) It provides a crude form of move-coalescing.  There are situations where
//     it would be beneficial, although not mandatory, to have two LiveRanges
//     assigned to the same storage unit.  Most importantly: (a) LiveRanges
//     that form all of the inputs, and the output, of a phi node.  (b)
//     LiveRanges for the output and first-operand values in the case where we
//     are targetting Intel-style instructions.
//
//     In such cases, if the bundle can be allocated as-is, then no extra moves
//     are necessary.  If not (and the bundle is split), then
//     ::createMoveGroupsFromLiveRangeTransitions will later fix things up by
//     inserting MoveGroups in the right places.
//
// Merging of LiveRanges into LiveBundles is done in Phase 1, by
// ::mergeAndQueueRegisters, after liveness analysis (which generates only
// LiveRanges).
//
// For the bundle mentioned above, viz
//
//   LB2(parent=none v3 8-21 { 16_v3:A } ## v3 24-25 { 25_v3:F:xmm0 })
//
// the allocator did not in the end choose to allocate it to `xmm0`.  Instead
// it was split into two bundles, LB6 (a "spill parent", or root node in the
// trees described above), and LB9, a leaf node, that points to its parent LB6:
//
//   LB6(parent=none v3 8-21 %xmm1.s { 16_v3:A } ## v3 24-25 %xmm1.s { })
//   LB9(parent=LB6 v3 24-25 %xmm0.s { 25_v3:F:rax })
//
// Note that both bundles now have an allocation, and that is printed,
// redundantly, for each LiveRange in the bundle -- hence the repeated
// `%xmm1.s` in the lines above.  Since all LiveRanges in a LiveBundle must be
// allocated to the same storage location, we never expect to see output like
// this
//
//   LB6(parent=none v3 8-21 %xmm1.s { 16_v3:A } ## v3 24-25 %xmm2.s { })
//
// and that is in any case impossible, since a LiveRange doesn't have an
// LAllocation field.  Instead it has a pointer to its LiveBundle, and the
// LAllocation lives in the LiveBundle.
//
// For the resulting allocation (LB6 and LB9), all the LiveRanges are use-only
// or flow-through.  There are no definitions.  But they are all for the same
// VirtualReg, v3, so they all have the same value.  An important question is
// where they "get their value from".  The answer is that
// ::createMoveGroupsFromLiveRangeTransitions will have to insert suitable
// MoveGroups so that each LiveRange for v3 can "acquire" the value from a
// previously-executed LiveRange, except for the range that defines it.  The
// defining LiveRange is not visible here; either it is in some other
// LiveBundle, not shown, or (more likely) the value is defined by a phi-node,
// in which case, as mentioned previously, it is not shown as having an
// explicit definition in any LiveRange.
//
// LiveBundles also have a `SpillSet* spill_` field (see below) and a
// `LiveBundle* spillParent_`.  The latter is used to ensure that all bundles
// originating from an "original" bundle share the same spill slot.  The
// `spillParent_` pointers can be thought of creating a 1-level tree, where
// each node points at its parent.  Since the tree can be only 1-level, the
// following invariant (INVAR) must be maintained:
//
// * if a LiveBundle has a non-null spillParent_ field, then it is a leaf node,
//   and no other LiveBundle can point at this one.
//
// * else (it has a null spillParent_ field) it is a root node, and so other
//   LiveBundles may point at it.
//
// LiveBundle has a 32-bit `id_` field. This is used for debug printing, and
// makes it easier to see parent-child relationships induced by the
// `spillParent_` pointers. It's also used for sorting live ranges in
// VirtualRegister::sortRanges.
//
// The "life cycle" of LiveBundles is described in Section 2 below.
//
//
// Secondary data structures: SpillSet, Requirement
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// SpillSet
// --------
// A SpillSet is a container for a set of LiveBundles that have been spilled,
// all of which are assigned the same spill slot.  The set is represented as a
// vector of points to LiveBundles.  SpillSet also contains the identity of the
// spill slot (its LAllocation).
//
// A LiveBundle, if it is to be spilled, has a pointer to the relevant
// SpillSet, and the SpillSet in turn has a pointer back to the LiveBundle in
// its vector thereof.  So LiveBundles (that are to be spilled) and SpillSets
// point at each other.
//
// (SPEC) LiveBundles that are not to be spilled (or for which the decision has
// yet to be made, have their SpillSet pointers as null.  (/SPEC)
//
// Requirement
// -----------
// Requirements are used transiently during the main allocation loop.  It
// summarises the set of constraints on storage location (must be any register,
// must be this specific register, must be stack, etc) for a LiveBundle.  This
// is so that the main allocation loop knows what kind of storage location it
// must choose in order to satisfy all of the defs and uses within the bundle.
//
// What Requirement provides is (a) a partially ordered set of locations, and
// (b) a constraint-merging method `merge`.
//
// Requirement needs a rewrite (and, in fact, that has already happened in
// un-landed code in bug 1758274) for the following reasons:
//
// * it's potentially buggy (bug 1761654), although that doesn't currently
//   affect us, for reasons which are unclear.
//
// * the partially ordered set has a top point, meaning "no constraint", but it
//   doesn't have a corresponding bottom point, meaning "impossible
//   constraints".  (So it's a partially ordered set, but not a lattice).  This
//   leads to awkward coding in some places, which would be simplified if there
//   were an explicit way to indicate "impossible constraint".
//
//
// Some ASCII art
// ~~~~~~~~~~~~~~
//
// Here's some not-very-good ASCII art that tries to summarise the data
// structures that persist for the entire allocation of a function:
//
//     BacktrackingAllocator
//        |
//      (vregs)
//        |
//        v
//        |
//     VirtualRegister -->--(ins)--> LNode
//     |            |  `->--(def)--> LDefinition
//     v            ^
//     |            |
// (ranges vector)  |
//     |            |
//     |          (vreg)
//     `--v->--.    |
//              \   |
//               LiveRange -->--b-->-- LiveRange -->--b-->-- NULL
//              /    |
//     ,--b->--'    /
//     |         (bundle)
//     ^          /
//     |         v
//  (ranges)    /
//     |       /
//     LiveBundle --s-->- LiveBundle
//       |      \           /    |
//       |       \         /     |
//      (spill)   ^       ^     (spill)
//       |         \     /       |
//       v          \   /        ^
//       |          (list)       |
//       \            |          /
//        `--->---> SpillSet <--'
//
// --b-- LiveRange::next_: links in the list of LiveRanges that belong to
//       a LiveBundle
//
// --v-- VirtualRegister::ranges_: vector of LiveRanges that belong to a
//       VirtualRegister
//
// --s-- LiveBundle::spillParent: a possible link to my "spill parent bundle"
//
//
// * LiveRange is in the center.  Each LiveRange is a member of a linked list,
//   the --b-- list, and is also stored in VirtualRegister's `ranges` vector.
//
// * VirtualRegister has a `ranges` vector that contains its LiveRanges.
//
// * LiveBundle has a pointer `ranges` that points to the start of its --b--
//   list of LiveRanges.
//
// * LiveRange points back at both its owning VirtualRegister (`vreg`) and its
//   owning LiveBundle (`bundle`).
//
// * LiveBundle has a pointer --s-- `spillParent`, which may be null, to its
//   conceptual "spill parent bundle", as discussed in detail above.
//
// * LiveBundle has a pointer `spill` to its SpillSet.
//
// * SpillSet has a vector `list` of pointers back to the LiveBundles that
//   point at it.
//
// * VirtualRegister has pointers `ins` to the LNode that defines the value and
//   `def` to the LDefinition within that LNode.
//
// * BacktrackingAllocator has a vector `vregs` of pointers to all the
//   VirtualRegisters for the function.  There is no equivalent top-level table
//   of all the LiveBundles for the function.
//
// Note that none of these pointers are "owning" in the C++-storage-management
// sense.  Rather, everything is stored in single arena which is freed when
// compilation of the function is complete.  For this reason,
// BacktrackingAllocator.{h,cpp} is almost completely free of the usual C++
// storage-management artefacts one would normally expect to see.
//
//
// ========================================================================
// ====                                                                ====
// ==== Section 2: The core allocation loop, and bundle splitting      ====
// ====                                                                ====
// ========================================================================
//
// Phase 1 of the allocator (described at the start of this SMDOC) computes
// live ranges, merges them into bundles, and places the bundles in a priority
// queue ::allocationQueue, ordered by what ::computePriority computes.
//
//
// The allocation loops
// ~~~~~~~~~~~~~~~~~~~~
// The core of the allocation machinery consists of two loops followed by a
// call to ::pickStackSlots.  The latter is uninteresting.  The two loops live
// in ::go and are documented in detail there.
//
//
// Bundle splitting
// ~~~~~~~~~~~~~~~~
// If the first of the two abovementioned loops cannot find a register for a
// bundle, either directly or as a result of evicting conflicting bundles, then
// it will have to either split or spill the bundle.  The entry point to the
// split/spill subsystem is ::chooseBundleSplit.  See comments there.

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// End of documentation                                                      //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "jit/BacktrackingAllocator.h"

#include "mozilla/BinarySearch.h"
#include "mozilla/Maybe.h"

#include <algorithm>

#include "jit/BitSet.h"
#include "jit/CompileInfo.h"
#include "js/Printf.h"

using namespace js;
using namespace js::jit;

using mozilla::DebugOnly;
using mozilla::Maybe;

// This is a big, complex file.  Code is grouped into various sections, each
// preceded by a box comment.  Sections not marked as "Misc helpers" are
// pretty much the top level flow, and are presented roughly in the same order
// in which the allocation pipeline operates.  BacktrackingAllocator::go,
// right at the end of the file, is a good starting point.

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: linked-list management                                      //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

static inline bool SortBefore(UsePosition* a, UsePosition* b) {
  return a->pos <= b->pos;
}

static inline bool SortBefore(LiveRange* a, LiveRange* b) {
  MOZ_ASSERT(!a->intersects(b));
  return a->from() < b->from();
}

template <typename T>
static void InsertSortedList(InlineForwardList<T>& list, T* value,
                             T* startAt = nullptr) {
  if (list.empty()) {
    MOZ_ASSERT(!startAt);
    list.pushFront(value);
    return;
  }

#ifdef DEBUG
  if (startAt) {
    // `startAt` must be an element in `list` that sorts before `value`.
    MOZ_ASSERT(SortBefore(startAt, value));
    MOZ_ASSERT_IF(*list.begin() == list.back(), list.back() == startAt);
    MOZ_ASSERT_IF(startAt != *list.begin(), SortBefore(*list.begin(), startAt));
    MOZ_ASSERT_IF(startAt != list.back(), SortBefore(startAt, list.back()));
  }
#endif

  if (SortBefore(list.back(), value)) {
    list.pushBack(value);
    return;
  }

  // If `startAt` is non-nullptr, we can start iterating there.
  T* prev = nullptr;
  InlineForwardListIterator<T> iter =
      startAt ? list.begin(startAt) : list.begin();
  if (startAt) {
    // `value` must sort after `startAt` so skip to the next element.
    MOZ_ASSERT(!SortBefore(value, *iter));
    ++iter;
    prev = startAt;
  }
  for (; iter; iter++) {
    if (SortBefore(value, *iter)) {
      break;
    }
    prev = *iter;
  }

  if (prev) {
    list.insertAfter(prev, value);
  } else {
    list.pushFront(value);
  }
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: methods for class SpillSet                                  //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

void SpillSet::setAllocation(LAllocation alloc) {
  for (size_t i = 0; i < numSpilledBundles(); i++) {
    spilledBundle(i)->setAllocation(alloc);
  }
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: methods for class LiveRange                                 //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

static size_t SpillWeightFromUsePolicy(LUse::Policy policy) {
  switch (policy) {
    case LUse::ANY:
      return 1000;

    case LUse::REGISTER:
    case LUse::FIXED:
      return 2000;

    default:
      return 0;
  }
}

inline void LiveRange::noteAddedUse(UsePosition* use) {
  LUse::Policy policy = use->usePolicy();
  usesSpillWeight_ += SpillWeightFromUsePolicy(policy);
  if (policy == LUse::FIXED) {
    ++numFixedUses_;
  }
}

inline void LiveRange::noteRemovedUse(UsePosition* use) {
  LUse::Policy policy = use->usePolicy();
  usesSpillWeight_ -= SpillWeightFromUsePolicy(policy);
  if (policy == LUse::FIXED) {
    --numFixedUses_;
  }
  MOZ_ASSERT_IF(!hasUses(), !usesSpillWeight_ && !numFixedUses_);
}

void LiveRange::addUse(UsePosition* use) {
  MOZ_ASSERT(covers(use->pos));
  InsertSortedList(uses_, use);
  noteAddedUse(use);
}

UsePosition* LiveRange::popUse() {
  UsePosition* ret = uses_.popFront();
  noteRemovedUse(ret);
  return ret;
}

void LiveRange::tryToMoveDefAndUsesInto(LiveRange* other) {
  MOZ_ASSERT(&other->vreg() == &vreg());
  MOZ_ASSERT(this != other);

  // This method shouldn't be called for two non-intersecting live ranges
  // because it's a no-op in that case.
  MOZ_ASSERT(intersects(other));

  CodePosition otherFrom = other->from();
  CodePosition otherTo = other->to();

  // Copy the has-definition flag to |other|, if possible.
  if (hasDefinition() && from() == otherFrom) {
    other->setHasDefinition();
  }

  // If we have no uses, we're done.
  if (!hasUses()) {
    return;
  }

  // Fast path for when we can use |moveAllUsesToTheEndOf|. This is very common
  // for the non-Wasm code path in |trySplitAcrossHotcode|. This fast path had a
  // hit rate of 75% when running Octane in the JS shell.
  //
  // Note: the |!other->hasUses()| check could be more precise, but this didn't
  // improve the hit rate at all.
  if (!other->hasUses() && usesBegin()->pos >= otherFrom &&
      lastUse()->pos < otherTo) {
    moveAllUsesToTheEndOf(other);
    return;
  }

  // The uses are sorted by position, so first skip all uses before |other|
  // starts.
  UsePositionIterator iter = usesBegin();
  while (iter && iter->pos < otherFrom) {
    iter++;
  }

  // Move over all uses which fit in |other|'s boundaries.
  while (iter && iter->pos < otherTo) {
    UsePosition* use = *iter;
    MOZ_ASSERT(other->covers(use->pos));
    uses_.removeAndIncrement(iter);
    noteRemovedUse(use);
    other->addUse(use);
  }

  MOZ_ASSERT_IF(iter, !other->covers(iter->pos));
}

void LiveRange::moveAllUsesToTheEndOf(LiveRange* other) {
  MOZ_ASSERT(&other->vreg() == &vreg());
  MOZ_ASSERT(this != other);
  MOZ_ASSERT(intersects(other));

  if (uses_.empty()) {
    return;
  }

  // Assert |other| covers all of our uses.
  MOZ_ASSERT(other->covers(uses_.begin()->pos));
  MOZ_ASSERT(other->covers(uses_.back()->pos));

  // Assert |other->uses_| remains sorted after adding our uses at the end.
  MOZ_ASSERT_IF(!other->uses_.empty(),
                SortBefore(other->uses_.back(), *uses_.begin()));

  other->uses_.extendBack(std::move(uses_));
  MOZ_ASSERT(!hasUses());

  other->usesSpillWeight_ += usesSpillWeight_;
  other->numFixedUses_ += numFixedUses_;
  usesSpillWeight_ = 0;
  numFixedUses_ = 0;
}

bool LiveRange::contains(LiveRange* other) const {
  return from() <= other->from() && to() >= other->to();
}

void LiveRange::intersect(LiveRange* other, Range* pre, Range* inside,
                          Range* post) const {
  MOZ_ASSERT(pre->empty() && inside->empty() && post->empty());

  CodePosition innerFrom = from();
  if (from() < other->from()) {
    if (to() < other->from()) {
      *pre = range_;
      return;
    }
    *pre = Range(from(), other->from());
    innerFrom = other->from();
  }

  CodePosition innerTo = to();
  if (to() > other->to()) {
    if (from() >= other->to()) {
      *post = range_;
      return;
    }
    *post = Range(other->to(), to());
    innerTo = other->to();
  }

  if (innerFrom != innerTo) {
    *inside = Range(innerFrom, innerTo);
  }
}

bool LiveRange::intersects(LiveRange* other) const {
  Range pre, inside, post;
  intersect(other, &pre, &inside, &post);
  return !inside.empty();
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: methods for class LiveBundle                                //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#ifdef DEBUG
size_t LiveBundle::numRanges() const {
  size_t count = 0;
  for (RangeIterator iter = rangesBegin(); iter; iter++) {
    count++;
  }
  return count;
}
#endif

LiveRange* LiveBundle::rangeFor(CodePosition pos) const {
  for (RangeIterator iter = rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    if (range->covers(pos)) {
      return range;
    }
  }
  return nullptr;
}

void LiveBundle::addRange(LiveRange* range,
                          LiveRange* startAt /* = nullptr */) {
  MOZ_ASSERT(!range->bundle());
  MOZ_ASSERT(range->hasVreg());
  MOZ_ASSERT_IF(startAt, startAt->bundle() == this);
  range->setBundle(this);
  InsertSortedList(ranges_, range, startAt);
}

void LiveBundle::addRangeAtEnd(LiveRange* range) {
  // Note: this method is functionally equivalent to `addRange`, but can be used
  // when we know `range` must be added after all existing ranges in the bundle.
  MOZ_ASSERT(!range->bundle());
  MOZ_ASSERT(range->hasVreg());
  MOZ_ASSERT_IF(!ranges_.empty(), SortBefore(ranges_.back(), range));
  range->setBundle(this);
  ranges_.pushBack(range);
}

bool LiveBundle::addRangeAtEnd(TempAllocator& alloc, VirtualRegister* vreg,
                               CodePosition from, CodePosition to) {
  LiveRange* range = LiveRange::FallibleNew(alloc, vreg, from, to);
  if (!range) {
    return false;
  }
  addRangeAtEnd(range);
  return true;
}

bool LiveBundle::addRangeAndDistributeUses(TempAllocator& alloc,
                                           LiveRange* oldRange,
                                           CodePosition from, CodePosition to) {
  LiveRange* range = LiveRange::FallibleNew(alloc, &oldRange->vreg(), from, to);
  if (!range) {
    return false;
  }
  addRange(range);
  oldRange->tryToMoveDefAndUsesInto(range);
  return true;
}

LiveRange* LiveBundle::popFirstRange() {
  RangeIterator iter = rangesBegin();
  if (!iter) {
    return nullptr;
  }

  LiveRange* range = *iter;
  ranges_.removeAt(iter);

  range->setBundle(nullptr);
  return range;
}

void LiveBundle::removeRange(LiveRange* range) {
  for (RangeIterator iter = rangesBegin(); iter; iter++) {
    LiveRange* existing = *iter;
    if (existing == range) {
      ranges_.removeAt(iter);
      return;
    }
  }
  MOZ_CRASH();
}

void LiveBundle::removeAllRangesFromVirtualRegisters() {
  VirtualRegister* prevVreg = nullptr;
  for (RangeIterator iter = rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    MOZ_ASSERT(!range->hasUses());
    if (&range->vreg() != prevVreg) {
      // As an optimization, remove all ranges owned by this bundle from the
      // register's list, instead of a single range at a time.
      range->vreg().removeRangesForBundle(this);
      prevVreg = &range->vreg();
    }
  }
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: methods for class VirtualRegister                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

bool VirtualRegister::addInitialRange(TempAllocator& alloc, CodePosition from,
                                      CodePosition to) {
  MOZ_ASSERT(rangesSorted_, "ranges stay sorted during live range building");

  MOZ_ASSERT(from < to);
  MOZ_ASSERT_IF(hasRanges(), from < ranges_.back()->to());

  // Mark [from,to) as a live range for this register during the initial
  // liveness analysis, coalescing with any existing overlapping ranges.

  LiveRange* merged = nullptr;
  for (RangeIterator iter(*this); iter; iter++) {
    LiveRange* existing = *iter;

    MOZ_ASSERT(from < existing->to());

    if (to < existing->from()) {
      // All other ranges start after |to| so can't overlap.
      break;
    }

    if (!merged) {
      // This is the first old range we've found that overlaps the new
      // range. Extend this one to cover its union with the new range.
      merged = existing;

      if (from < existing->from()) {
        existing->setFrom(from);
      }
      if (to > existing->to()) {
        existing->setTo(to);
      }

      // Continue searching to see if any other old ranges can be
      // coalesced with the new merged range.
    } else {
      // Coalesce this range into the previous range we merged into.
      MOZ_ASSERT(existing->from() >= merged->from());
      if (existing->to() > merged->to()) {
        merged->setTo(existing->to());
      }

      MOZ_ASSERT(!existing->hasDefinition());
      existing->moveAllUsesToTheEndOf(merged);
      MOZ_ASSERT(!existing->hasUses());
    }

    removeFirstRange(iter);
  }

  if (merged) {
    // Re-append the merged range.
    if (!ranges_.append(merged)) {
      return false;
    }
  } else {
    // The new range does not overlap any existing range for the vreg.
    MOZ_ASSERT_IF(hasRanges(), to < ranges_.back()->from());

    LiveRange* range = LiveRange::FallibleNew(alloc, this, from, to);
    if (!range) {
      return false;
    }

    if (!ranges_.append(range)) {
      return false;
    }
  }

  MOZ_ASSERT(rangesSorted_, "ranges are still sorted");

#ifdef DEBUG
  // Check the last few ranges don't overlap and are in the correct order.
  size_t len = ranges_.length();
  static constexpr size_t MaxIterations = 4;
  size_t start = len > MaxIterations ? (len - MaxIterations) : 1;

  for (size_t i = start; i < len; i++) {
    LiveRange* range = ranges_[i];
    LiveRange* prev = ranges_[i - 1];
    MOZ_ASSERT(range->from() < range->to());
    MOZ_ASSERT(range->to() < prev->from());
  }
#endif

  return true;
}

void VirtualRegister::addInitialUse(UsePosition* use) {
  MOZ_ASSERT(rangesSorted_, "ranges stay sorted during live range building");
  ranges_.back()->addUse(use);
}

void VirtualRegister::setInitialDefinition(CodePosition from) {
  MOZ_ASSERT(rangesSorted_, "ranges stay sorted during live range building");
  LiveRange* first = ranges_.back();
  MOZ_ASSERT(from >= first->from());
  first->setFrom(from);
  first->setHasDefinition();
}

LiveRange* VirtualRegister::rangeFor(CodePosition pos,
                                     bool preferRegister /* = false */) const {
  assertRangesSorted();

  size_t len = ranges_.length();

  // Because the ranges are sorted in order of descending start position, we use
  // binary search to find the first range where |range->from <= pos|. All
  // ranges before that definitely don't cover |pos|.
  auto compare = [pos](LiveRange* other) {
    if (pos < other->from()) {
      return 1;
    }
    if (pos > other->from()) {
      return -1;
    }
    return 0;
  };
  size_t index;
  mozilla::BinarySearchIf(ranges_, 0, len, compare, &index);

  if (index == len) {
    // None of the ranges overlap.
    MOZ_ASSERT(ranges_.back()->from() > pos);
    return nullptr;
  }

  // There can be multiple ranges with |range->from == pos|. We want to start at
  // the first one.
  while (index > 0 && ranges_[index - 1]->from() == pos) {
    index--;
  }

  // Verify the above code is correct:
  // * The range at |index| starts before or at |pos| and needs to be searched.
  // * All ranges before |index| start after |pos| and can be ignored.
  MOZ_ASSERT(ranges_[index]->from() <= pos);
  MOZ_ASSERT_IF(index > 0, ranges_[index - 1]->from() > pos);

  LiveRange* found = nullptr;
  do {
    LiveRange* range = ranges_[index];
    if (range->covers(pos)) {
      if (!preferRegister || range->bundle()->allocation().isAnyRegister()) {
        return range;
      }
      if (!found) {
        found = range;
      }
    }
    index++;
  } while (index < len);

  return found;
}

void VirtualRegister::sortRanges() {
  if (rangesSorted_) {
    assertRangesSorted();
    return;
  }

  // Sort ranges by start position in descending order.
  //
  // It would be correct to only compare the start position, but std::sort is
  // not a stable sort and we don't want the order of ranges with the same start
  // position to depend on the sort implementation. Use the end position and the
  // bundle's id to ensure ranges are always sorted the same way.
  auto compareRanges = [](LiveRange* a, LiveRange* b) -> bool {
    if (a->from() != b->from()) {
      return a->from() > b->from();
    }
    if (a->to() != b->to()) {
      return a->to() > b->to();
    }
    // Overlapping live ranges must belong to different bundles.
    MOZ_ASSERT_IF(a != b, a->bundle()->id() != b->bundle()->id());
    return a->bundle()->id() > b->bundle()->id();
  };
  std::sort(ranges_.begin(), ranges_.end(), compareRanges);

  rangesSorted_ = true;
}

#ifdef DEBUG
void VirtualRegister::assertRangesSorted() const {
  MOZ_ASSERT(rangesSorted_);

  // Assert the last N ranges in the vector are sorted correctly. We don't check
  // the whole vector to not slow down debug builds too much.

  size_t len = ranges_.length();
  static constexpr size_t MaxIterations = 4;
  size_t start = len > MaxIterations ? (len - MaxIterations) : 1;

  for (size_t i = start; i < len; i++) {
    LiveRange* prev = ranges_[i - 1];
    LiveRange* range = ranges_[i];
    MOZ_ASSERT(range->from() <= prev->from());

    // If two ranges have the same |from| position, neither must be defining.
    // This ensures the defining range, if any, always comes first after
    // sorting.
    MOZ_ASSERT_IF(range->from() == prev->from(),
                  !range->hasDefinition() && !prev->hasDefinition());
  }
}
#endif

bool VirtualRegister::addRange(LiveRange* range) {
  bool sorted = ranges_.empty() ||
                (rangesSorted_ && ranges_.back()->from() >= range->from());
  if (!ranges_.append(range)) {
    return false;
  }
  rangesSorted_ = sorted;
  return true;
}

void VirtualRegister::removeFirstRange(RangeIterator& iter) {
  MOZ_ASSERT(iter.index() == ranges_.length() - 1);
  ranges_.popBack();
}

void VirtualRegister::removeRangesForBundle(LiveBundle* bundle) {
  auto bundleMatches = [bundle](LiveRange* range) {
    return range->bundle() == bundle;
  };
  ranges_.eraseIf(bundleMatches);
}

template <typename Pred>
void VirtualRegister::removeRangesIf(Pred&& pred) {
  assertRangesSorted();
  ranges_.eraseIf([&](LiveRange* range) { return pred(ranges_, range); });
}

// Helper for ::tryMergeReusedRegister.
bool VirtualRegister::replaceLastRangeLinear(LiveRange* old, LiveRange* newPre,
                                             LiveRange* newPost) {
  assertRangesSorted();

  // |old| is currently the first range in the Vector (the range with the
  // highest start position). This range is being replaced with two new ranges,
  // |newPre| and |newPost|. The relative order of these ranges by start
  // position is:
  //
  //   old <= newPre <= newPost
  //
  // To keep the vector sorted by descending start position, |newPost| must
  // become the new last range and |newPre| must be inserted after it.

  MOZ_ASSERT(ranges_[0] == old);
  MOZ_ASSERT(old->from() <= newPre->from());
  MOZ_ASSERT(newPre->from() <= newPost->from());

  ranges_[0] = newPost;

  if (!ranges_.insert(ranges_.begin() + 1, newPre)) {
    return false;
  }

  assertRangesSorted();
  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: queries about uses                                          //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

static inline LDefinition* FindReusingDefOrTemp(LNode* node,
                                                LAllocation* alloc) {
  if (node->isPhi()) {
    MOZ_ASSERT(node->toPhi()->numDefs() == 1);
    MOZ_ASSERT(node->toPhi()->getDef(0)->policy() !=
               LDefinition::MUST_REUSE_INPUT);
    return nullptr;
  }

  LInstruction* ins = node->toInstruction();

  for (size_t i = 0; i < ins->numDefs(); i++) {
    LDefinition* def = ins->getDef(i);
    if (def->policy() == LDefinition::MUST_REUSE_INPUT &&
        ins->getOperand(def->getReusedInput()) == alloc) {
      return def;
    }
  }
  for (size_t i = 0; i < ins->numTemps(); i++) {
    LDefinition* def = ins->getTemp(i);
    if (def->policy() == LDefinition::MUST_REUSE_INPUT &&
        ins->getOperand(def->getReusedInput()) == alloc) {
      return def;
    }
  }
  return nullptr;
}

bool BacktrackingAllocator::isReusedInput(LUse* use, LNode* ins,
                                          bool considerCopy) {
  if (LDefinition* def = FindReusingDefOrTemp(ins, use)) {
    return considerCopy || !vregs[def->virtualRegister()].mustCopyInput();
  }
  return false;
}

bool BacktrackingAllocator::isRegisterUse(UsePosition* use, LNode* ins,
                                          bool considerCopy) {
  switch (use->usePolicy()) {
    case LUse::ANY:
      return isReusedInput(use->use(), ins, considerCopy);

    case LUse::REGISTER:
    case LUse::FIXED:
      return true;

    default:
      return false;
  }
}

bool BacktrackingAllocator::isRegisterDefinition(LiveRange* range) {
  if (!range->hasDefinition()) {
    return false;
  }

  VirtualRegister& reg = range->vreg();
  if (reg.ins()->isPhi()) {
    return false;
  }

  if (reg.def()->policy() == LDefinition::FIXED &&
      !reg.def()->output()->isAnyRegister()) {
    return false;
  }

  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: atomic LIR groups                                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// The following groupings contain implicit (invisible to ::buildLivenessInfo)
// value flows, and therefore no split points may be requested inside them.
// This is an otherwise unstated part of the contract between LIR generation
// and the allocator.
//
// (1) (any insn) ; OsiPoint
//
// [Further group definitions and supporting code to come, pending rework
//  of the wasm atomic-group situation.]

CodePosition BacktrackingAllocator::minimalDefEnd(LNode* ins) const {
  // Compute the shortest interval that captures vregs defined by ins.
  // Watch for instructions that are followed by an OSI point.
  // If moves are introduced between the instruction and the OSI point then
  // safepoint information for the instruction may be incorrect.
  while (true) {
    LNode* next = insData[ins->id() + 1];
    if (!next->isOsiPoint()) {
      break;
    }
    ins = next;
  }

  return outputOf(ins);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Misc helpers: computation of bundle priorities and spill weights          //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

size_t BacktrackingAllocator::computePriority(LiveBundle* bundle) {
  // The priority of a bundle is its total length, so that longer lived
  // bundles will be processed before shorter ones (even if the longer ones
  // have a low spill weight). See processBundle().
  size_t lifetimeTotal = 0;

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    lifetimeTotal += range->to() - range->from();
  }

  return lifetimeTotal;
}

bool BacktrackingAllocator::minimalDef(LiveRange* range, LNode* ins) {
  // Whether this is a minimal range capturing a definition at ins.
  return (range->to() <= minimalDefEnd(ins).next()) &&
         ((!ins->isPhi() && range->from() == inputOf(ins)) ||
          range->from() == outputOf(ins));
}

bool BacktrackingAllocator::minimalUse(LiveRange* range, UsePosition* use) {
  // Whether this is a minimal range capturing |use|.
  LNode* ins = insData[use->pos];
  return (range->from() == inputOf(ins)) &&
         (range->to() ==
          (use->use()->usedAtStart() ? outputOf(ins) : outputOf(ins).next()));
}

bool BacktrackingAllocator::minimalBundle(LiveBundle* bundle, bool* pfixed) {
  // Return true iff |bundle| is a minimal bundle. A minimal bundle is a bundle
  // that can't be split further. Minimal bundles have a single (very short)
  // range.
  //
  // If the bundle is minimal we also set the |*pfixed| outparam to indicate
  // whether the bundle must be allocated to a fixed register. The value of
  // |*pfixed| is undefined if this function returns false.

  LiveBundle::RangeIterator iter = bundle->rangesBegin();
  LiveRange* range = *iter;

  MOZ_ASSERT(range->hasVreg(), "Call ranges are not added to LiveBundles");

  // If a bundle contains multiple ranges, splitAtAllRegisterUses will split
  // each range into a separate bundle.
  if (++iter) {
    return false;
  }

  if (range->hasDefinition()) {
    VirtualRegister& reg = range->vreg();
    if (!minimalDef(range, reg.ins())) {
      return false;
    }
    if (pfixed) {
      *pfixed = reg.def()->policy() == LDefinition::FIXED &&
                reg.def()->output()->isAnyRegister();
    }
    return true;
  }

  // Performance optimization: |minimalUse| will only return true for length-1
  // or length-2 ranges so if this is a longer range it can't be minimal.
  if (range->to() - range->from() > 2) {
#ifdef DEBUG
    for (UsePositionIterator iter = range->usesBegin(); iter; iter++) {
      MOZ_ASSERT(!minimalUse(range, *iter));
    }
#endif
    return false;
  }

  bool fixed = false, minimal = false, multiple = false;

  for (UsePositionIterator iter = range->usesBegin(); iter; iter++) {
    if (iter != range->usesBegin()) {
      multiple = true;
    }

    switch (iter->usePolicy()) {
      case LUse::FIXED:
        if (fixed) {
          return false;
        }
        fixed = true;
        if (minimalUse(range, *iter)) {
          minimal = true;
        }
        break;

      case LUse::REGISTER:
        if (minimalUse(range, *iter)) {
          minimal = true;
        }
        break;

      default:
        break;
    }
  }

  // If a range contains a fixed use and at least one other use,
  // splitAtAllRegisterUses will split each use into a different bundle.
  if (multiple && fixed) {
    return false;
  }

  if (!minimal) {
    return false;
  }
  if (pfixed) {
    *pfixed = fixed;
  }
  return true;
}

size_t BacktrackingAllocator::computeSpillWeight(LiveBundle* bundle) {
  // Minimal bundles have an extremely high spill weight, to ensure they
  // can evict any other bundles and be allocated to a register.
  bool fixed;
  if (minimalBundle(bundle, &fixed)) {
    return fixed ? 2000000 : 1000000;
  }

  size_t usesTotal = 0;
  fixed = false;

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;

    if (range->hasDefinition()) {
      VirtualRegister& reg = range->vreg();
      if (reg.def()->policy() == LDefinition::FIXED &&
          reg.def()->output()->isAnyRegister()) {
        usesTotal += 2000;
        fixed = true;
      } else if (!reg.ins()->isPhi()) {
        usesTotal += 2000;
      }
    }

    usesTotal += range->usesSpillWeight();
    if (range->numFixedUses() > 0) {
      fixed = true;
    }
  }

  // Compute spill weight as a use density, lowering the weight for long
  // lived bundles with relatively few uses.
  size_t lifetimeTotal = computePriority(bundle);
  return lifetimeTotal ? usesTotal / lifetimeTotal : 0;
}

size_t BacktrackingAllocator::maximumSpillWeight(
    const LiveBundleVector& bundles) {
  size_t maxWeight = 0;
  for (size_t i = 0; i < bundles.length(); i++) {
    maxWeight = std::max(maxWeight, computeSpillWeight(bundles[i]));
  }
  return maxWeight;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Initialization of the allocator                                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// This function pre-allocates and initializes as much global state as possible
// to avoid littering the algorithms with memory management cruft.
bool BacktrackingAllocator::init() {
  if (!insData.init(mir, graph.numInstructions())) {
    return false;
  }

  if (!entryPositions.reserve(graph.numBlocks()) ||
      !exitPositions.reserve(graph.numBlocks())) {
    return false;
  }

  for (size_t i = 0; i < graph.numBlocks(); i++) {
    LBlock* block = graph.getBlock(i);
    for (LInstructionIterator ins = block->begin(); ins != block->end();
         ins++) {
      insData[ins->id()] = *ins;
    }
    for (size_t j = 0; j < block->numPhis(); j++) {
      LPhi* phi = block->getPhi(j);
      insData[phi->id()] = phi;
    }

    CodePosition entry =
        block->numPhis() != 0
            ? CodePosition(block->getPhi(0)->id(), CodePosition::INPUT)
            : inputOf(block->firstInstructionWithId());
    CodePosition exit = outputOf(block->lastInstructionWithId());

    MOZ_ASSERT(block->mir()->id() == i);
    entryPositions.infallibleAppend(entry);
    exitPositions.infallibleAppend(exit);
  }

  uint32_t numBlocks = graph.numBlockIds();
  MOZ_ASSERT(liveIn.empty());
  if (!liveIn.growBy(numBlocks)) {
    return false;
  }

  size_t numVregs = graph.numVirtualRegisters();
  if (!vregs.initCapacity(numVregs)) {
    return false;
  }
  for (uint32_t i = 0; i < numVregs; i++) {
    vregs.infallibleEmplaceBack();
  }

  // Build virtual register objects.
  for (size_t i = 0; i < graph.numBlocks(); i++) {
    if (mir->shouldCancel("Create data structures (main loop)")) {
      return false;
    }

    LBlock* block = graph.getBlock(i);
    for (LInstructionIterator ins = block->begin(); ins != block->end();
         ins++) {
      if (mir->shouldCancel("Create data structures (inner loop 1)")) {
        return false;
      }

      for (LInstruction::OutputIter output(*ins); !output.done(); output++) {
        vreg(*output).init(*ins, *output, /* isTemp = */ false);
      }
      for (LInstruction::TempIter temp(*ins); !temp.done(); temp++) {
        vreg(*temp).init(*ins, *temp, /* isTemp = */ true);
      }
    }
    for (size_t j = 0; j < block->numPhis(); j++) {
      LPhi* phi = block->getPhi(j);
      LDefinition* def = phi->getDef(0);
      vreg(def).init(phi, def, /* isTemp = */ false);
    }
  }

  LiveRegisterSet remainingRegisters(allRegisters_.asLiveSet());
  while (!remainingRegisters.emptyGeneral()) {
    AnyRegister reg = AnyRegister(remainingRegisters.takeAnyGeneral());
    registers[reg.code()].allocatable = true;
  }
  while (!remainingRegisters.emptyFloat()) {
    AnyRegister reg =
        AnyRegister(remainingRegisters.takeAnyFloat<RegTypeName::Any>());
    registers[reg.code()].allocatable = true;
  }

  LifoAlloc* lifoAlloc = mir->alloc().lifoAlloc();
  for (size_t i = 0; i < AnyRegister::Total; i++) {
    registers[i].reg = AnyRegister::FromCode(i);
    registers[i].allocations.setAllocator(lifoAlloc);
  }

  hotcode.setAllocator(lifoAlloc);

  // Partition the graph into hot and cold sections, for helping to make
  // splitting decisions. Since we don't have any profiling data this is a
  // crapshoot, so just mark the bodies of inner loops as hot and everything
  // else as cold.

  LBlock* backedge = nullptr;
  for (size_t i = 0; i < graph.numBlocks(); i++) {
    LBlock* block = graph.getBlock(i);

    // If we see a loop header, mark the backedge so we know when we have
    // hit the end of the loop. Don't process the loop immediately, so that
    // if there is an inner loop we will ignore the outer backedge.
    if (block->mir()->isLoopHeader()) {
      backedge = block->mir()->backedge()->lir();
    }

    if (block == backedge) {
      LBlock* header = block->mir()->loopHeaderOfBackedge()->lir();
      LiveRange* range = LiveRange::FallibleNew(
          alloc(), nullptr, entryOf(header), exitOf(block).next());
      if (!range || !hotcode.insert(range)) {
        return false;
      }
    }
  }

  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Liveness analysis                                                         //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// Helper for ::buildLivenessInfo
bool BacktrackingAllocator::addInitialFixedRange(AnyRegister reg,
                                                 CodePosition from,
                                                 CodePosition to) {
  LiveRange* range = LiveRange::FallibleNew(alloc(), nullptr, from, to);
  if (!range) {
    return false;
  }
  LiveRangePlus rangePlus(range);
  return registers[reg.code()].allocations.insert(rangePlus);
}

// Helper for ::buildLivenessInfo
#ifdef DEBUG
// Returns true iff ins has a def/temp reusing the input allocation.
static bool IsInputReused(LInstruction* ins, LUse* use) {
  for (size_t i = 0; i < ins->numDefs(); i++) {
    if (ins->getDef(i)->policy() == LDefinition::MUST_REUSE_INPUT &&
        ins->getOperand(ins->getDef(i)->getReusedInput())->toUse() == use) {
      return true;
    }
  }

  for (size_t i = 0; i < ins->numTemps(); i++) {
    if (ins->getTemp(i)->policy() == LDefinition::MUST_REUSE_INPUT &&
        ins->getOperand(ins->getTemp(i)->getReusedInput())->toUse() == use) {
      return true;
    }
  }

  return false;
}
#endif

/*
 * This function builds up liveness ranges for all virtual registers
 * defined in the function.
 *
 * The algorithm is based on the one published in:
 *
 * Wimmer, Christian, and Michael Franz. "Linear Scan Register Allocation on
 *     SSA Form." Proceedings of the International Symposium on Code Generation
 *     and Optimization. Toronto, Ontario, Canada, ACM. 2010. 170-79. PDF.
 *
 * The algorithm operates on blocks ordered such that dominators of a block
 * are before the block itself, and such that all blocks of a loop are
 * contiguous. It proceeds backwards over the instructions in this order,
 * marking registers live at their uses, ending their live ranges at
 * definitions, and recording which registers are live at the top of every
 * block. To deal with loop backedges, registers live at the beginning of
 * a loop gain a range covering the entire loop.
 */
bool BacktrackingAllocator::buildLivenessInfo() {
  JitSpew(JitSpew_RegAlloc, "Beginning liveness analysis");

  // The callPositions vector and the safepoint vectors are initialized from
  // index |length - 1| to 0, to ensure they are sorted.
  if (!callPositions.growByUninitialized(graph.numCallInstructions()) ||
      !safepoints_.growByUninitialized(graph.numSafepoints()) ||
      !nonCallSafepoints_.growByUninitialized(graph.numNonCallSafepoints())) {
    return false;
  }
  size_t prevCallPositionIndex = callPositions.length();
  size_t prevSafepointIndex = safepoints_.length();
  size_t prevNonCallSafepointIndex = nonCallSafepoints_.length();

  for (size_t i = graph.numBlocks(); i > 0; i--) {
    if (mir->shouldCancel("Build Liveness Info (main loop)")) {
      return false;
    }

    LBlock* block = graph.getBlock(i - 1);
    MBasicBlock* mblock = block->mir();

    VirtualRegBitSet& live = liveIn[mblock->id()];

    // Propagate liveIn from our successors to us.
    for (size_t i = 0; i < mblock->lastIns()->numSuccessors(); i++) {
      MBasicBlock* successor = mblock->lastIns()->getSuccessor(i);
      // Skip backedges, as we fix them up at the loop header.
      if (mblock->id() < successor->id()) {
        if (!live.insertAll(liveIn[successor->id()])) {
          return false;
        }
      }
    }

    // Add successor phis.
    if (mblock->successorWithPhis()) {
      LBlock* phiSuccessor = mblock->successorWithPhis()->lir();
      for (unsigned int j = 0; j < phiSuccessor->numPhis(); j++) {
        LPhi* phi = phiSuccessor->getPhi(j);
        LAllocation* use = phi->getOperand(mblock->positionInPhiSuccessor());
        uint32_t reg = use->toUse()->virtualRegister();
        if (!live.insert(reg)) {
          return false;
        }
        vreg(use).setUsedByPhi();
      }
    }

    // Registers are assumed alive for the entire block, a define shortens
    // the range to the point of definition.
    for (VirtualRegBitSet::Iterator liveRegId(live); liveRegId; ++liveRegId) {
      if (!vregs[*liveRegId].addInitialRange(alloc(), entryOf(block),
                                             exitOf(block).next())) {
        return false;
      }
    }

    // Shorten the front end of ranges for live variables to their point of
    // definition, if found.
    for (LInstructionReverseIterator ins = block->rbegin();
         ins != block->rend(); ins++) {
      // Calls may clobber registers, so force a spill and reload around the
      // callsite.
      if (ins->isCall()) {
        for (AnyRegisterIterator iter(allRegisters_.asLiveSet()); iter.more();
             ++iter) {
          bool found = false;
          for (size_t i = 0; i < ins->numDefs(); i++) {
            if (ins->getDef(i)->isFixed() &&
                ins->getDef(i)->output()->aliases(LAllocation(*iter))) {
              found = true;
              break;
            }
          }
          // If this register doesn't have an explicit def above, mark
          // it as clobbered by the call unless it is actually
          // call-preserved.
          if (!found && !ins->isCallPreserved(*iter)) {
            if (!addInitialFixedRange(*iter, outputOf(*ins),
                                      outputOf(*ins).next())) {
              return false;
            }
          }
        }

        // Add the call position before the previous one to ensure the vector is
        // sorted.
        MOZ_ASSERT(prevCallPositionIndex > 0);
        MOZ_ASSERT_IF(prevCallPositionIndex < callPositions.length(),
                      outputOf(*ins) < callPositions[prevCallPositionIndex]);
        prevCallPositionIndex--;
        callPositions[prevCallPositionIndex] = outputOf(*ins);
      }

      for (LInstruction::OutputIter output(*ins); !output.done(); output++) {
        LDefinition* def = *output;
        CodePosition from = outputOf(*ins);

        if (def->policy() == LDefinition::MUST_REUSE_INPUT) {
          ins->changePolicyOfReusedInputToAny(def);
        }

        if (!vreg(def).addInitialRange(alloc(), from, from.next())) {
          return false;
        }
        vreg(def).setInitialDefinition(from);
        live.remove(def->virtualRegister());
      }

      for (LInstruction::TempIter tempIter(*ins); !tempIter.done();
           tempIter++) {
        LDefinition* temp = *tempIter;

        // Normally temps are considered to cover both the input
        // and output of the associated instruction. In some cases
        // though we want to use a fixed register as both an input
        // and clobbered register in the instruction, so watch for
        // this and shorten the temp to cover only the output.
        CodePosition from = inputOf(*ins);
        if (temp->policy() == LDefinition::FIXED) {
          AnyRegister reg = temp->output()->toAnyRegister();
          for (LInstruction::NonSnapshotInputIter alloc(**ins); alloc.more();
               alloc.next()) {
            if (alloc->isUse()) {
              LUse* use = alloc->toUse();
              if (use->isFixedRegister()) {
                if (GetFixedRegister(vreg(use).def(), use) == reg) {
                  from = outputOf(*ins);
                }
              }
            }
          }
        }

        // * For non-call instructions, temps cover both the input and output,
        //   so temps never alias uses (even at-start uses) or defs.
        // * For call instructions, temps only cover the input (the output is
        //   used for the force-spill ranges added above). This means temps
        //   still don't alias uses but they can alias the (fixed) defs. For now
        //   we conservatively require temps to have a fixed register for call
        //   instructions to prevent a footgun.
        MOZ_ASSERT_IF(ins->isCall(), temp->policy() == LDefinition::FIXED);
        CodePosition to =
            ins->isCall() ? outputOf(*ins) : outputOf(*ins).next();

        if (!vreg(temp).addInitialRange(alloc(), from, to)) {
          return false;
        }
        vreg(temp).setInitialDefinition(from);
      }

      DebugOnly<bool> hasUseRegister = false;
      DebugOnly<bool> hasUseRegisterAtStart = false;

      for (LInstruction::InputIter inputAlloc(**ins); inputAlloc.more();
           inputAlloc.next()) {
        if (inputAlloc->isUse()) {
          LUse* use = inputAlloc->toUse();

          // Call uses should always be at-start, since calls use all
          // registers.
          MOZ_ASSERT_IF(ins->isCall() && !inputAlloc.isSnapshotInput(),
                        use->usedAtStart());

#ifdef DEBUG
          // If there are both useRegisterAtStart(x) and useRegister(y)
          // uses, we may assign the same register to both operands
          // (bug 772830). Don't allow this for now.
          if (use->policy() == LUse::REGISTER) {
            if (use->usedAtStart()) {
              if (!IsInputReused(*ins, use)) {
                hasUseRegisterAtStart = true;
              }
            } else {
              hasUseRegister = true;
            }
          }
          MOZ_ASSERT(!(hasUseRegister && hasUseRegisterAtStart));
#endif

          // Don't treat RECOVERED_INPUT uses as keeping the vreg alive.
          if (use->policy() == LUse::RECOVERED_INPUT) {
            continue;
          }

          CodePosition to = use->usedAtStart() ? inputOf(*ins) : outputOf(*ins);
          if (use->isFixedRegister()) {
            LAllocation reg(AnyRegister::FromCode(use->registerCode()));
            for (size_t i = 0; i < ins->numDefs(); i++) {
              LDefinition* def = ins->getDef(i);
              if (def->policy() == LDefinition::FIXED &&
                  *def->output() == reg) {
                to = inputOf(*ins);
              }
            }
          }

          if (!vreg(use).addInitialRange(alloc(), entryOf(block), to.next())) {
            return false;
          }
          UsePosition* usePosition =
              new (alloc().fallible()) UsePosition(use, to);
          if (!usePosition) {
            return false;
          }
          vreg(use).addInitialUse(usePosition);
          if (!live.insert(use->virtualRegister())) {
            return false;
          }
        }
      }

      if (ins->safepoint()) {
        MOZ_ASSERT(prevSafepointIndex > 0);
        prevSafepointIndex--;
        safepoints_[prevSafepointIndex] = *ins;
        if (!ins->isCall()) {
          MOZ_ASSERT(prevNonCallSafepointIndex > 0);
          prevNonCallSafepointIndex--;
          nonCallSafepoints_[prevNonCallSafepointIndex] = *ins;
        }
      }
    }

    // Phis have simultaneous assignment semantics at block begin, so at
    // the beginning of the block we can be sure that liveIn does not
    // contain any phi outputs.
    for (unsigned int i = 0; i < block->numPhis(); i++) {
      LDefinition* def = block->getPhi(i)->getDef(0);
      if (live.contains(def->virtualRegister())) {
        live.remove(def->virtualRegister());
      } else {
        // This is a dead phi, so add a dummy range over all phis. This
        // can go away if we have an earlier dead code elimination pass.
        CodePosition entryPos = entryOf(block);
        if (!vreg(def).addInitialRange(alloc(), entryPos, entryPos.next())) {
          return false;
        }
      }
    }

    if (mblock->isLoopHeader()) {
      // MakeLoopsContiguous ensures blocks of a loop are contiguous, so add a
      // single live range spanning the loop. Because we require liveIn in a
      // later pass for resolution, we also have to fix that up for all loop
      // blocks.

      MBasicBlock* backedge = mblock->backedge();

      // Add a range for this entire loop
      CodePosition from = entryOf(mblock->lir());
      CodePosition to = exitOf(backedge->lir()).next();

      for (VirtualRegBitSet::Iterator liveRegId(live); liveRegId; ++liveRegId) {
        if (!vregs[*liveRegId].addInitialRange(alloc(), from, to)) {
          return false;
        }
      }

      if (mblock != backedge) {
        // Start at the block after |mblock|.
        MOZ_ASSERT(graph.getBlock(i - 1) == mblock->lir());
        size_t j = i;
        while (true) {
          MBasicBlock* loopBlock = graph.getBlock(j)->mir();

          // Fix up the liveIn set.
          if (!liveIn[loopBlock->id()].insertAll(live)) {
            return false;
          }

          if (loopBlock == backedge) {
            break;
          }
          j++;
        }
      }
    }

    MOZ_ASSERT_IF(!mblock->numPredecessors(), live.empty());
  }

  MOZ_RELEASE_ASSERT(prevCallPositionIndex == 0,
                     "Must have initialized all call positions");
  MOZ_RELEASE_ASSERT(prevSafepointIndex == 0,
                     "Must have initialized all safepoints");
  MOZ_RELEASE_ASSERT(prevNonCallSafepointIndex == 0,
                     "Must have initialized all safepoints");

  JitSpew(JitSpew_RegAlloc, "Completed liveness analysis");
  return true;
}

Maybe<size_t> BacktrackingAllocator::lookupFirstCallPositionInRange(
    CodePosition from, CodePosition to) {
  MOZ_ASSERT(from < to);

  // Use binary search to find the first call position in range [from, to).
  size_t len = callPositions.length();
  size_t index;
  mozilla::BinarySearch(callPositions, 0, len, from, &index);
  MOZ_ASSERT(index <= len);

  if (index == len) {
    // Last call position in the vector is before this range.
    MOZ_ASSERT_IF(len > 0, callPositions.back() < from);
    return {};
  }

  if (callPositions[index] >= to) {
    // The next call position comes after this range.
    return {};
  }

  MOZ_ASSERT(callPositions[index] >= from && callPositions[index] < to);
  return mozilla::Some(index);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Merging and queueing of LiveRange groups                                  //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// Helper for ::tryMergeBundles
static bool IsArgumentSlotDefinition(LDefinition* def) {
  return def->policy() == LDefinition::FIXED && def->output()->isArgument();
}

// Helper for ::tryMergeBundles
static bool IsThisSlotDefinition(LDefinition* def) {
  return IsArgumentSlotDefinition(def) &&
         def->output()->toArgument()->index() <
             THIS_FRAME_ARGSLOT + sizeof(Value);
}

// Helper for ::tryMergeBundles
static bool HasStackPolicy(LDefinition* def) {
  return def->policy() == LDefinition::STACK;
}

// Helper for ::tryMergeBundles
static bool CanMergeTypesInBundle(LDefinition::Type a, LDefinition::Type b) {
  // Fast path for the common case.
  if (a == b) {
    return true;
  }

  // Only merge if the sizes match, so that we don't get confused about the
  // width of spill slots.
  return LStackSlot::width(a) == LStackSlot::width(b);
}

// Helper for ::tryMergeReusedRegister
void BacktrackingAllocator::tryMergeBundles(LiveBundle* bundle0,
                                            LiveBundle* bundle1) {
  // See if bundle0 and bundle1 can be merged together.
  if (bundle0 == bundle1) {
    return;
  }

  // Get a representative virtual register from each bundle.
  VirtualRegister& reg0 = bundle0->firstRange()->vreg();
  VirtualRegister& reg1 = bundle1->firstRange()->vreg();

  MOZ_ASSERT(CanMergeTypesInBundle(reg0.type(), reg1.type()));
  MOZ_ASSERT(reg0.isCompatible(reg1));

  if (!compilingWasm()) {
    // Registers which might spill to the frame's |this| slot can only be
    // grouped with other such registers. The frame's |this| slot must always
    // hold the |this| value, as required by JitFrame tracing and by the Ion
    // constructor calling convention.
    if (IsThisSlotDefinition(reg0.def()) || IsThisSlotDefinition(reg1.def())) {
      if (*reg0.def()->output() != *reg1.def()->output()) {
        return;
      }
    }

    // Registers which might spill to the frame's argument slots can only be
    // grouped with other such registers in the following cases:
    //
    // * If the frame might access those arguments through a lazy arguments
    //   object or rest parameter.
    //
    // * On 32-bit platforms, to prevent creating garbage Values in the formal
    //   argument slots when spilling just the type or payload of a different
    //   Value. GC tracing of ArraySortData relies on the argument slots holding
    //   valid JS values. See bug 1911858.
    if (IsArgumentSlotDefinition(reg0.def()) ||
        IsArgumentSlotDefinition(reg1.def())) {
#ifdef JS_PUNBOX64
      MOZ_ASSERT(reg0.type() == LDefinition::Type::BOX);
      MOZ_ASSERT(reg1.type() == LDefinition::Type::BOX);
      bool canSpillToArgSlots =
          !graph.mir().entryBlock()->info().mayReadFrameArgsDirectly();
#else
      bool canSpillToArgSlots = false;
#endif
      if (!canSpillToArgSlots) {
        if (*reg0.def()->output() != *reg1.def()->output()) {
          return;
        }
      }
    }
  }

  // When we make a call to a WebAssembly function that returns multiple
  // results, some of those results can go on the stack.  The callee is passed a
  // pointer to this stack area, which is represented as having policy
  // LDefinition::STACK (with type LDefinition::STACKRESULTS).  Individual
  // results alias parts of the stack area with a value-appropriate type, but
  // policy LDefinition::STACK.  This aliasing between allocations makes it
  // unsound to merge anything with a LDefinition::STACK policy.
  if (HasStackPolicy(reg0.def()) || HasStackPolicy(reg1.def())) {
    return;
  }

  // Limit the number of times we compare ranges if there are many ranges in
  // one of the bundles, to avoid quadratic behavior.
  static const size_t MAX_RANGES = 200;

  // Make sure that ranges in the bundles do not overlap.
  LiveBundle::RangeIterator iter0 = bundle0->rangesBegin(),
                            iter1 = bundle1->rangesBegin();
  size_t count = 0;
  while (iter0 && iter1) {
    if (++count >= MAX_RANGES) {
      return;
    }

    LiveRange* range0 = *iter0;
    LiveRange* range1 = *iter1;

    if (range0->from() >= range1->to()) {
      iter1++;
    } else if (range1->from() >= range0->to()) {
      iter0++;
    } else {
      return;
    }
  }

  // Move all ranges from bundle1 into bundle0. Use a fast path for the case
  // where we can add all ranges from bundle1 at the end of bundle0.
  if (SortBefore(bundle0->lastRange(), bundle1->firstRange())) {
    while (LiveRange* range = bundle1->popFirstRange()) {
      bundle0->addRangeAtEnd(range);
    }
  } else {
    LiveRange* prevRange = nullptr;
    while (LiveRange* range = bundle1->popFirstRange()) {
      bundle0->addRange(range, prevRange);
      prevRange = range;
    }
  }
}

// Helper for ::mergeAndQueueRegisters
bool BacktrackingAllocator::allocateStackDefinition(VirtualRegister& reg) {
  LInstruction* ins = reg.ins()->toInstruction();
  if (reg.def()->type() == LDefinition::STACKRESULTS) {
    LStackArea alloc(ins->toInstruction());
    if (!stackSlotAllocator.allocateStackArea(&alloc)) {
      return false;
    }
    reg.def()->setOutput(alloc);
  } else {
    // Because the definitions are visited in order, the area has been allocated
    // before we reach this result, so we know the operand is an LStackArea.
    const LUse* use = ins->getOperand(0)->toUse();
    VirtualRegister& area = vregs[use->virtualRegister()];
    const LStackArea* areaAlloc = area.def()->output()->toStackArea();
    reg.def()->setOutput(areaAlloc->resultAlloc(ins, reg.def()));
  }
  return true;
}

// Helper for ::mergeAndQueueRegisters
bool BacktrackingAllocator::tryMergeReusedRegister(VirtualRegister& def,
                                                   VirtualRegister& input) {
  // def is a vreg which reuses input for its output physical register. Try
  // to merge ranges for def with those of input if possible, as avoiding
  // copies before def's instruction is crucial for generated code quality
  // (MUST_REUSE_INPUT is used for all arithmetic on x86/x64).

  // Don't try to merge if the definition starts at the input point of the
  // instruction.
  if (def.firstRange()->from() == inputOf(def.ins())) {
    MOZ_ASSERT(def.isTemp());
    def.setMustCopyInput();
    return true;
  }
  MOZ_ASSERT(def.firstRange()->from() == outputOf(def.ins()));

  if (!CanMergeTypesInBundle(def.type(), input.type())) {
    def.setMustCopyInput();
    return true;
  }

  LiveRange* inputRange = input.rangeFor(outputOf(def.ins()));
  if (!inputRange) {
    // The input is not live after the instruction, either in a safepoint
    // for the instruction or in subsequent code. The input and output
    // can thus be in the same group.
    tryMergeBundles(def.firstBundle(), input.firstBundle());
    return true;
  }

  // Avoid merging in very large live ranges as merging has non-linear
  // complexity.  The cutoff value is hard to gauge.  1M was chosen because it
  // is "large" and yet usefully caps compile time on AutoCad-for-the-web to
  // something reasonable on a 2017-era desktop system.  See bug 1728781.
  //
  // Subsequently -- bug 1897427 comment 9 -- even this threshold seems too
  // high, resulting in delays of around 10 seconds.  Setting it to 500000
  // "fixes" that one, but it seems prudent to reduce it to 250000 so as to
  // avoid having to change it yet again at some future point.
  const uint32_t RANGE_SIZE_CUTOFF = 250000;
  if (inputRange->to() - inputRange->from() > RANGE_SIZE_CUTOFF) {
    def.setMustCopyInput();
    return true;
  }

  // The input is live afterwards, either in future instructions or in a
  // safepoint for the reusing instruction. This is impossible to satisfy
  // without copying the input.
  //
  // It may or may not be better to split the input into two bundles at the
  // point of the definition, which may permit merging. One case where it is
  // definitely better to split is if the input never has any register uses
  // after the instruction. Handle this splitting eagerly.

  LBlock* block = def.ins()->block();

  // The input's lifetime must end within the same block as the definition,
  // otherwise it could live on in phis elsewhere.
  if (inputRange != input.lastRange() || inputRange->to() > exitOf(block)) {
    def.setMustCopyInput();
    return true;
  }

  // If we already split the input for some other register, don't make a
  // third bundle.
  if (inputRange->bundle() != input.firstRange()->bundle()) {
    def.setMustCopyInput();
    return true;
  }

  // If the input will start out in memory then adding a separate bundle for
  // memory uses after the def won't help.
  if (input.def()->isFixed() && !input.def()->output()->isAnyRegister()) {
    def.setMustCopyInput();
    return true;
  }

  // The input cannot have register or reused uses after the definition.
  for (UsePositionIterator iter = inputRange->usesBegin(); iter; iter++) {
    if (iter->pos <= inputOf(def.ins())) {
      continue;
    }

    LUse* use = iter->use();
    if (FindReusingDefOrTemp(insData[iter->pos], use)) {
      def.setMustCopyInput();
      return true;
    }
    if (iter->usePolicy() != LUse::ANY &&
        iter->usePolicy() != LUse::KEEPALIVE) {
      def.setMustCopyInput();
      return true;
    }
  }

  LiveRange* preRange = LiveRange::FallibleNew(
      alloc(), &input, inputRange->from(), outputOf(def.ins()));
  if (!preRange) {
    return false;
  }

  // The new range starts at reg's input position, which means it overlaps
  // with the old range at one position. This is what we want, because we
  // need to copy the input before the instruction.
  LiveRange* postRange = LiveRange::FallibleNew(
      alloc(), &input, inputOf(def.ins()), inputRange->to());
  if (!postRange) {
    return false;
  }

  inputRange->tryToMoveDefAndUsesInto(preRange);
  inputRange->tryToMoveDefAndUsesInto(postRange);
  MOZ_ASSERT(!inputRange->hasUses());

  JitSpewIfEnabled(JitSpew_RegAlloc,
                   "  splitting reused input at %u to try to help grouping",
                   inputOf(def.ins()).bits());

  LiveBundle* firstBundle = inputRange->bundle();

  // Note: this inserts an item at the beginning of the ranges vector. That's
  // okay in this case because the checks above ensure this happens at most once
  // for the |input| virtual register.
  if (!input.replaceLastRangeLinear(inputRange, preRange, postRange)) {
    return false;
  }

  firstBundle->removeRange(inputRange);
  firstBundle->addRange(preRange);

  // The new range goes in a separate bundle, where it will be spilled during
  // allocation.
  LiveBundle* secondBundle =
      LiveBundle::FallibleNew(alloc(), nullptr, nullptr, getNextBundleId());
  if (!secondBundle) {
    return false;
  }
  secondBundle->addRangeAtEnd(postRange);

  tryMergeBundles(def.firstBundle(), input.firstBundle());
  return true;
}

bool BacktrackingAllocator::mergeAndQueueRegisters() {
  MOZ_ASSERT(!vregs[0u].hasRanges());

  // Create a bundle for each register containing all its ranges.
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];
    if (!reg.hasRanges()) {
      continue;
    }

    LiveBundle* bundle =
        LiveBundle::FallibleNew(alloc(), nullptr, nullptr, getNextBundleId());
    if (!bundle) {
      return false;
    }
    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      bundle->addRangeAtEnd(*iter);
    }
  }

  // If there is an OSR block, merge parameters in that block with the
  // corresponding parameters in the initial block.
  if (MBasicBlock* osr = graph.mir().osrBlock()) {
    size_t original = 1;
    for (LInstructionIterator iter = osr->lir()->begin();
         iter != osr->lir()->end(); iter++) {
      if (iter->isParameter()) {
        for (size_t i = 0; i < iter->numDefs(); i++) {
          DebugOnly<bool> found = false;
          VirtualRegister& paramVreg = vreg(iter->getDef(i));
          for (; original < paramVreg.vreg(); original++) {
            VirtualRegister& originalVreg = vregs[original];
            if (*originalVreg.def()->output() == *iter->getDef(i)->output()) {
              MOZ_ASSERT(originalVreg.ins()->isParameter());
              tryMergeBundles(originalVreg.firstBundle(),
                              paramVreg.firstBundle());
              found = true;
              break;
            }
          }
          MOZ_ASSERT(found);
        }
      }
    }
  }

  // Try to merge registers with their reused inputs.
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];
    if (!reg.hasRanges()) {
      continue;
    }

    if (reg.def()->policy() == LDefinition::MUST_REUSE_INPUT) {
      LUse* use = reg.ins()
                      ->toInstruction()
                      ->getOperand(reg.def()->getReusedInput())
                      ->toUse();
      if (!tryMergeReusedRegister(reg, vreg(use))) {
        return false;
      }
    }
  }

  // Try to merge phis with their inputs.
  for (size_t i = 0; i < graph.numBlocks(); i++) {
    LBlock* block = graph.getBlock(i);
    for (size_t j = 0; j < block->numPhis(); j++) {
      LPhi* phi = block->getPhi(j);
      VirtualRegister& outputVreg = vreg(phi->getDef(0));
      for (size_t k = 0, kend = phi->numOperands(); k < kend; k++) {
        VirtualRegister& inputVreg = vreg(phi->getOperand(k)->toUse());
        tryMergeBundles(inputVreg.firstBundle(), outputVreg.firstBundle());
      }
    }
  }

  // Add all bundles to the allocation queue, and create spill sets for them.
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];

    // Eagerly allocate stack result areas and their component stack results.
    if (reg.def() && reg.def()->policy() == LDefinition::STACK &&
        !allocateStackDefinition(reg)) {
      return false;
    }

    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      LiveRange* range = *iter;
      LiveBundle* bundle = range->bundle();
      if (range == bundle->firstRange()) {
        if (!alloc().ensureBallast()) {
          return false;
        }

        SpillSet* spill = SpillSet::New(alloc());
        if (!spill) {
          return false;
        }
        bundle->setSpillSet(spill);

        size_t priority = computePriority(bundle);
        if (!allocationQueue.insert(QueueItem(bundle, priority))) {
          return false;
        }
      }
    }
  }

  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Code for the splitting/spilling subsystem begins here.                    //
//                                                                           //
// The code that follows is structured in the following sequence:            //
//                                                                           //
// (1) Routines that are helpers for ::splitAt.                              //
// (2) ::splitAt itself, which implements splitting decisions.               //
// (3) heuristic routines (eg ::splitAcrossCalls), which decide where        //
//     splits should be made.  They then call ::splitAt to perform the       //
//     chosen split.                                                         //
// (4) The top level driver, ::chooseBundleSplit.                            //
//                                                                           //
// There are further comments on ::splitAt and ::chooseBundleSplit below.    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Implementation of splitting decisions, but not the making of those        //
// decisions: various helper functions                                       //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

bool BacktrackingAllocator::updateVirtualRegisterListsThenRequeueBundles(
    LiveBundle* bundle, const LiveBundleVector& newBundles) {
#ifdef DEBUG
  if (newBundles.length() == 1) {
    LiveBundle* newBundle = newBundles[0];
    if (newBundle->numRanges() == bundle->numRanges() &&
        computePriority(newBundle) == computePriority(bundle)) {
      bool different = false;
      LiveBundle::RangeIterator oldRanges = bundle->rangesBegin();
      LiveBundle::RangeIterator newRanges = newBundle->rangesBegin();
      while (oldRanges) {
        LiveRange* oldRange = *oldRanges;
        LiveRange* newRange = *newRanges;
        if (oldRange->from() != newRange->from() ||
            oldRange->to() != newRange->to()) {
          different = true;
          break;
        }
        oldRanges++;
        newRanges++;
      }

      // This is likely to trigger an infinite loop in register allocation. This
      // can be the result of invalid register constraints, making regalloc
      // impossible; consider relaxing those.
      MOZ_ASSERT(different,
                 "Split results in the same bundle with the same priority");
    }
  }
#endif

  if (JitSpewEnabled(JitSpew_RegAlloc)) {
    JitSpew(JitSpew_RegAlloc, "  .. into:");
    for (size_t i = 0; i < newBundles.length(); i++) {
      JitSpew(JitSpew_RegAlloc, "    %s", newBundles[i]->toString().get());
    }
  }

  // Remove all ranges in the old bundle from their register's list.
  bundle->removeAllRangesFromVirtualRegisters();

  // Add all ranges in the new bundles to their register's list.
  for (size_t i = 0; i < newBundles.length(); i++) {
    LiveBundle* newBundle = newBundles[i];
    for (LiveBundle::RangeIterator iter = newBundle->rangesBegin(); iter;
         iter++) {
      LiveRange* range = *iter;
      if (!range->vreg().addRange(range)) {
        return false;
      }
    }
  }

  // Queue the new bundles for register assignment.
  for (size_t i = 0; i < newBundles.length(); i++) {
    LiveBundle* newBundle = newBundles[i];
    size_t priority = computePriority(newBundle);
    if (!allocationQueue.insert(QueueItem(newBundle, priority))) {
      return false;
    }
  }

  return true;
}

// Helper for ::splitAt
// When splitting a bundle according to a list of split positions, return
// whether a use or range at |pos| should use a different bundle than the last
// position this was called for.
static bool UseNewBundle(const SplitPositionVector& splitPositions,
                         CodePosition pos, size_t* activeSplitPosition) {
  if (splitPositions.empty()) {
    // When the split positions are empty we are splitting at all uses.
    return true;
  }

  if (*activeSplitPosition == splitPositions.length()) {
    // We've advanced past all split positions.
    return false;
  }

  if (splitPositions[*activeSplitPosition] > pos) {
    // We haven't gotten to the next split position yet.
    return false;
  }

  // We've advanced past the next split position, find the next one which we
  // should split at.
  while (*activeSplitPosition < splitPositions.length() &&
         splitPositions[*activeSplitPosition] <= pos) {
    (*activeSplitPosition)++;
  }
  return true;
}

// Helper for ::splitAt
static bool HasPrecedingRangeSharingVreg(LiveBundle* bundle, LiveRange* range) {
  MOZ_ASSERT(range->bundle() == bundle);

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* prevRange = *iter;
    if (prevRange == range) {
      return false;
    }
    if (&prevRange->vreg() == &range->vreg()) {
      return true;
    }
  }

  MOZ_CRASH();
}

// Helper for ::splitAt
static bool HasFollowingRangeSharingVreg(LiveBundle* bundle, LiveRange* range) {
  MOZ_ASSERT(range->bundle() == bundle);

  LiveBundle::RangeIterator iter = bundle->rangesBegin(range);
  MOZ_ASSERT(*iter == range);
  iter++;

  for (; iter; iter++) {
    LiveRange* nextRange = *iter;
    if (&nextRange->vreg() == &range->vreg()) {
      return true;
    }
  }

  return false;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Implementation of splitting decisions, but not the making of those        //
// decisions:                                                                //
//   ::splitAt                                                               //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// ::splitAt
// ---------
// It would be nice to be able to interpret ::splitAt as simply performing
// whatever split the heuristic routines decide on.  Unfortunately it
// tries to "improve" on the initial locations, which as
// https://bugzilla.mozilla.org/show_bug.cgi?id=1758274#c17 shows, often
// leads to excessive spilling.  So there is no clean distinction between
// policy (where to split, computed by the heuristic routines) and
// implementation (done by ::splitAt).
//
// ::splitAt -- creation of spill parent bundles
// ---------------------------------------------
// To understand what ::splitAt does, we must refer back to Section 1's
// description of LiveBundle::spillParent_.
//
// Initially (as created by Phase 1), all bundles have `spillParent_` being
// NULL.  If ::splitAt is asked to split such a bundle, it will first create a
// "spill bundle" or "spill parent" bundle.  This is a copy of the original,
// with two changes:
//
// * all register uses have been removed, so that only stack-compatible uses
//   remain.
//
// * for all LiveRanges in the bundle that define a register, the start point
//   of the range is moved one CodePosition forwards, thusly:
//
//   from = minimalDefEnd(insData[from]).next();
//
// The reason for the latter relates to the idea described in Section 1, that
// all LiveRanges for any given VirtualRegister must form a tree rooted at the
// defining LiveRange.  If the spill-bundle definition range start points are
// the same as those in the original bundle, then we will end up with two roots
// for the tree, and it is then unclear which one should supply "the value".
//
// Putting the spill-bundle start point one CodePosition further along causes
// the range containing the register def (after splitting) to still be the
// defining point.  ::createMoveGroupsFromLiveRangeTransitions will observe the
// equivalent spill-bundle range starting one point later and add a MoveGroup
// to move the value into it.  Since the spill bundle is intended to be stack
// resident, the effect is to force creation of the MoveGroup that will
// actually spill this value onto the stack.
//
// If the bundle provided to ::splitAt already has a spill parent, then
// ::splitAt doesn't create a new spill parent.  This situation will happen
// when the bundle to be split was itself created by splitting.  The effect is
// that *all* bundles created from an "original bundle" share the same spill
// parent, and hence they will share the same spill slot, which guarantees that
// all the spilled fragments of a VirtualRegister share the same spill slot,
// which means we'll never have to move a VirtualRegister between different
// spill slots during its lifetime.
//
// ::splitAt -- creation of other bundles
// --------------------------------------
// With the spill parent bundle question out of the way, ::splitAt then goes on
// to create the remaining new bundles, using near-incomprehensible logic
// steered by `UseNewBundle`.
//
// This supposedly splits the bundle at the positions given by the
// `SplitPositionVector` parameter to ::splitAt, putting them in a temporary
// vector `newBundles`.  Whether it really splits at the requested positions or
// not is hard to say; more important is what happens next.
//
// ::splitAt -- "improvement" ("filtering") of the split bundles
// -------------------------------------------------------------
// ::splitAt now tries to reduce the length of the LiveRanges that make up the
// new bundles (not including the "spill parent").  I assume this is to remove
// sections of the bundles that carry no useful value (eg, extending after the
// last using a range), thereby removing the demand for registers in those
// parts.  This does however mean that ::splitAt is no longer really splitting
// where the heuristic routines wanted, and that can lead to a big increase in
// spilling in loops, as
// https://bugzilla.mozilla.org/show_bug.cgi?id=1758274#c17 describes.
//
// ::splitAt -- meaning of the incoming `SplitPositionVector`
// ----------------------------------------------------------
// ::splitAt has one last mystery which is important to document.  The split
// positions are specified as CodePositions, but this leads to ambiguity
// because, in a sequence of N (LIR) instructions, there are 2N valid
// CodePositions.  For example:
//
//    6-7 WasmLoadTls [def v2<o>] [use v1:R]
//    8-9 WasmNullConstant [def v3<o>]
//
// Consider splitting the range for `v2`, which starts at CodePosition 7.
// What's the difference between saying "split it at 7" and "split it at 8" ?
// Not much really, since in both cases what we intend is for the range to be
// split in between the two instructions.
//
// Hence I believe the semantics is:
//
// * splitting at an even numbered CodePosition (eg, 8), which is an input-side
//   position, means "split before the instruction containing this position".
//
// * splitting at an odd numbered CodePositin (eg, 7), which is an output-side
//   position, means "split after the instruction containing this position".
//
// Hence in the example, we could specify either 7 or 8 to mean the same
// placement of the split.  Well, almost true, but actually:
//
// (SPEC) specifying 8 means
//
//   "split between these two insns, and any resulting MoveGroup goes in the
//    list to be emitted before the start of the second insn"
//
// (SPEC) specifying 7 means
//
//   "split between these two insns, and any resulting MoveGroup goes in the
//    list to be emitted after the end of the first insn"
//
// In most cases we don't care on which "side of the valley" the MoveGroup ends
// up, in which case we can use either convention.
//
// (SPEC) I believe these semantics are implied by the logic in
// ::createMoveGroupsFromLiveRangeTransitions.  They are certainly not
// documented anywhere in the code.

bool BacktrackingAllocator::splitAt(LiveBundle* bundle,
                                    const SplitPositionVector& splitPositions) {
  // Split the bundle at the given split points. Register uses which have no
  // intervening split points are consolidated into the same bundle. If the
  // list of split points is empty, then all register uses are placed in
  // minimal bundles.

  // splitPositions should be sorted.
  for (size_t i = 1; i < splitPositions.length(); ++i) {
    MOZ_ASSERT(splitPositions[i - 1] < splitPositions[i]);
  }

  // We don't need to create a new spill bundle if there already is one.
  bool spillBundleIsNew = false;
  LiveBundle* spillBundle = bundle->spillParent();
  if (!spillBundle) {
    spillBundle = LiveBundle::FallibleNew(alloc(), bundle->spillSet(), nullptr,
                                          getNextBundleId());
    if (!spillBundle) {
      return false;
    }
    spillBundleIsNew = true;

    for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
      LiveRange* range = *iter;

      CodePosition from = range->from();
      if (isRegisterDefinition(range)) {
        from = minimalDefEnd(insData[from]).next();
      }

      if (from < range->to()) {
        if (!spillBundle->addRangeAtEnd(alloc(), &range->vreg(), from,
                                        range->to())) {
          return false;
        }

        if (range->hasDefinition() && !isRegisterDefinition(range)) {
          spillBundle->lastRange()->setHasDefinition();
        }
      }
    }
  }

  LiveBundleVector newBundles;

  // The bundle which ranges are currently being added to.
  LiveBundle* activeBundle = LiveBundle::FallibleNew(
      alloc(), bundle->spillSet(), spillBundle, getNextBundleId());
  if (!activeBundle || !newBundles.append(activeBundle)) {
    return false;
  }

  // State for use by UseNewBundle.
  size_t activeSplitPosition = 0;

  // Make new bundles according to the split positions, and distribute ranges
  // and uses to them.
  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;

    if (UseNewBundle(splitPositions, range->from(), &activeSplitPosition)) {
      activeBundle = LiveBundle::FallibleNew(alloc(), bundle->spillSet(),
                                             spillBundle, getNextBundleId());
      if (!activeBundle || !newBundles.append(activeBundle)) {
        return false;
      }
    }

    LiveRange* activeRange = LiveRange::FallibleNew(alloc(), &range->vreg(),
                                                    range->from(), range->to());
    if (!activeRange) {
      return false;
    }
    activeBundle->addRangeAtEnd(activeRange);

    if (isRegisterDefinition(range)) {
      activeRange->setHasDefinition();
    }

    while (range->hasUses()) {
      UsePosition* use = range->popUse();
      LNode* ins = insData[use->pos];

      // Any uses of a register that appear before its definition has
      // finished must be associated with the range for that definition.
      if (isRegisterDefinition(range) &&
          use->pos <= minimalDefEnd(insData[range->from()])) {
        activeRange->addUse(use);
      } else if (isRegisterUse(use, ins)) {
        // Place this register use into a different bundle from the
        // last one if there are any split points between the two uses.
        // UseNewBundle always returns true if we are splitting at all
        // register uses, but we can still reuse the last range and
        // bundle if they have uses at the same position, except when
        // either use is fixed (the two uses might require incompatible
        // registers.)
        if (UseNewBundle(splitPositions, use->pos, &activeSplitPosition) &&
            (!activeRange->hasUses() ||
             activeRange->usesBegin()->pos != use->pos ||
             activeRange->usesBegin()->usePolicy() == LUse::FIXED ||
             use->usePolicy() == LUse::FIXED)) {
          activeBundle = LiveBundle::FallibleNew(
              alloc(), bundle->spillSet(), spillBundle, getNextBundleId());
          if (!activeBundle || !newBundles.append(activeBundle)) {
            return false;
          }
          activeRange = LiveRange::FallibleNew(alloc(), &range->vreg(),
                                               range->from(), range->to());
          if (!activeRange) {
            return false;
          }
          activeBundle->addRangeAtEnd(activeRange);
        }

        activeRange->addUse(use);
      } else {
        MOZ_ASSERT(spillBundleIsNew);
        spillBundle->rangeFor(use->pos)->addUse(use);
      }
    }
  }

  LiveBundleVector filteredBundles;

  // Trim the ends of ranges in each new bundle when there are no other
  // earlier or later ranges in the same bundle with the same vreg.
  for (size_t i = 0; i < newBundles.length(); i++) {
    LiveBundle* bundle = newBundles[i];

    for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter;) {
      LiveRange* range = *iter;

      if (!range->hasDefinition()) {
        if (!HasPrecedingRangeSharingVreg(bundle, range)) {
          if (range->hasUses()) {
            UsePosition* use = *range->usesBegin();
            range->setFrom(inputOf(insData[use->pos]));
          } else {
            bundle->removeRangeAndIncrementIterator(iter);
            continue;
          }
        }
      }

      if (!HasFollowingRangeSharingVreg(bundle, range)) {
        if (range->hasUses()) {
          UsePosition* use = range->lastUse();
          range->setTo(use->pos.next());
        } else if (range->hasDefinition()) {
          range->setTo(minimalDefEnd(insData[range->from()]).next());
        } else {
          bundle->removeRangeAndIncrementIterator(iter);
          continue;
        }
      }

      iter++;
    }

    if (bundle->hasRanges() && !filteredBundles.append(bundle)) {
      return false;
    }
  }

  if (spillBundleIsNew && !filteredBundles.append(spillBundle)) {
    return false;
  }

  return updateVirtualRegisterListsThenRequeueBundles(bundle, filteredBundles);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Creation of splitting decisions, but not their implementation:            //
//   ::splitAcrossCalls                                                      //
//   ::trySplitAcrossHotcode                                                 //
//   ::trySplitAfterLastRegisterUse                                          //
//   ::trySplitBeforeFirstRegisterUse                                        //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

bool BacktrackingAllocator::splitAcrossCalls(LiveBundle* bundle) {
  // Split the bundle to separate register uses and non-register uses and
  // allow the vreg to be spilled across its range.

  // Locations of all calls in the bundle's range. This vector is sorted in
  // ascending order because ranges in the bundle are sorted by start position
  // and don't overlap
  SplitPositionVector bundleCallPositions;

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;

    // Append call positions in range [from+1, to) to bundleCallPositions.
    // Calls at the beginning of the range are ignored because there is no
    // splitting to do in this case.

    CodePosition from = range->from().next();
    if (from == range->to()) {
      // Empty range can't contain any calls.
      continue;
    }

    // Use binary search to find the first call position.
    Maybe<size_t> index = lookupFirstCallPositionInRange(from, range->to());
    if (!index.isSome()) {
      // There are no calls inside this range.
      continue;
    }

    // Find the index of the last call within this range.
    size_t startIndex = *index;
    size_t endIndex = startIndex;
    while (endIndex < callPositions.length() - 1) {
      if (callPositions[endIndex + 1] >= range->to()) {
        break;
      }
      endIndex++;
    }

    MOZ_ASSERT(startIndex <= endIndex);

#ifdef DEBUG
    auto inRange = [range](CodePosition pos) {
      return range->covers(pos) && pos != range->from();
    };

    // Assert startIndex is the first call position in this range.
    MOZ_ASSERT(inRange(callPositions[startIndex]));
    MOZ_ASSERT_IF(startIndex > 0, !inRange(callPositions[startIndex - 1]));

    // Assert endIndex is the last call position in this range.
    MOZ_ASSERT(inRange(callPositions[endIndex]));
    MOZ_ASSERT_IF(endIndex + 1 < callPositions.length(),
                  !inRange(callPositions[endIndex + 1]));

    // Assert bundleCallPositions stays sorted.
    MOZ_ASSERT_IF(!bundleCallPositions.empty(),
                  bundleCallPositions.back() < callPositions[startIndex]);
#endif

    const CodePosition* start = &callPositions[startIndex];
    size_t count = endIndex - startIndex + 1;
    if (!bundleCallPositions.append(start, start + count)) {
      return false;
    }
  }

  MOZ_ASSERT(!bundleCallPositions.empty());

#ifdef JS_JITSPEW
  {
    AutoJitSpewMessage msg(JitSpew_RegAlloc, "  .. split across calls at ");
    for (size_t i = 0; i < bundleCallPositions.length(); ++i) {
      msg.append("%s%u", i != 0 ? ", " : "", bundleCallPositions[i].bits());
    }
  }
#endif

  return splitAt(bundle, bundleCallPositions);
}

bool BacktrackingAllocator::trySplitAcrossHotcode(LiveBundle* bundle,
                                                  bool* success) {
  // If this bundle has portions that are hot and portions that are cold,
  // split it at the boundaries between hot and cold code.

  LiveRange* hotRange = nullptr;

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    if (hotcode.contains(range, &hotRange)) {
      break;
    }
  }

  // Don't split if there is no hot code in the bundle.
  if (!hotRange) {
    JitSpew(JitSpew_RegAlloc, "  .. bundle does not contain hot code");
    return true;
  }

  // Don't split if there is no cold code in the bundle.
  bool coldCode = false;
  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    if (!hotRange->contains(range)) {
      coldCode = true;
      break;
    }
  }
  if (!coldCode) {
    JitSpew(JitSpew_RegAlloc, "  .. bundle does not contain cold code");
    return true;
  }

  JitSpewIfEnabled(JitSpew_RegAlloc, "  .. split across hot range %s",
                   hotRange->toString().get());

  // Tweak the splitting method when compiling wasm code to look at actual
  // uses within the hot/cold code. This heuristic is in place as the below
  // mechanism regressed several asm.js tests. Hopefully this will be fixed
  // soon and this special case removed. See bug 948838.
  if (compilingWasm()) {
    SplitPositionVector splitPositions;
    if (!splitPositions.append(hotRange->from()) ||
        !splitPositions.append(hotRange->to())) {
      return false;
    }
    *success = true;
    return splitAt(bundle, splitPositions);
  }

  LiveBundle* hotBundle = LiveBundle::FallibleNew(
      alloc(), bundle->spillSet(), bundle->spillParent(), getNextBundleId());
  if (!hotBundle) {
    return false;
  }
  LiveBundle* preBundle = nullptr;
  LiveBundle* postBundle = nullptr;

  // Accumulate the ranges of hot and cold code in the bundle. Note that
  // we are only comparing with the single hot range found, so the cold code
  // may contain separate hot ranges.
  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    LiveRange::Range hot, coldPre, coldPost;
    range->intersect(hotRange, &coldPre, &hot, &coldPost);

    if (!hot.empty()) {
      if (!hotBundle->addRangeAndDistributeUses(alloc(), range, hot.from,
                                                hot.to)) {
        return false;
      }
    }

    if (!coldPre.empty()) {
      if (!preBundle) {
        preBundle =
            LiveBundle::FallibleNew(alloc(), bundle->spillSet(),
                                    bundle->spillParent(), getNextBundleId());
        if (!preBundle) {
          return false;
        }
      }
      if (!preBundle->addRangeAndDistributeUses(alloc(), range, coldPre.from,
                                                coldPre.to)) {
        return false;
      }
    }

    if (!coldPost.empty()) {
      if (!postBundle) {
        postBundle =
            LiveBundle::FallibleNew(alloc(), bundle->spillSet(),
                                    bundle->spillParent(), getNextBundleId());
        if (!postBundle) {
          return false;
        }
      }
      if (!postBundle->addRangeAndDistributeUses(alloc(), range, coldPost.from,
                                                 coldPost.to)) {
        return false;
      }
    }
  }

  MOZ_ASSERT(hotBundle->numRanges() != 0);

  LiveBundleVector newBundles;
  if (!newBundles.append(hotBundle)) {
    return false;
  }

  MOZ_ASSERT(preBundle || postBundle);
  if (preBundle && !newBundles.append(preBundle)) {
    return false;
  }
  if (postBundle && !newBundles.append(postBundle)) {
    return false;
  }

  *success = true;
  return updateVirtualRegisterListsThenRequeueBundles(bundle, newBundles);
}

bool BacktrackingAllocator::trySplitAfterLastRegisterUse(LiveBundle* bundle,
                                                         LiveBundle* conflict,
                                                         bool* success) {
  // If this bundle's later uses do not require it to be in a register,
  // split it after the last use which does require a register. If conflict
  // is specified, only consider register uses before the conflict starts.

  CodePosition lastRegisterFrom, lastRegisterTo, lastUse;

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;

    // If the range defines a register, consider that a register use for
    // our purposes here.
    if (isRegisterDefinition(range)) {
      CodePosition spillStart = minimalDefEnd(insData[range->from()]).next();
      if (!conflict || spillStart < conflict->firstRange()->from()) {
        lastUse = lastRegisterFrom = range->from();
        lastRegisterTo = spillStart;
      }
    }

    for (UsePositionIterator iter(range->usesBegin()); iter; iter++) {
      LNode* ins = insData[iter->pos];

      // Uses in the bundle should be sorted.
      MOZ_ASSERT(iter->pos >= lastUse);
      lastUse = inputOf(ins);

      if (!conflict || outputOf(ins) < conflict->firstRange()->from()) {
        if (isRegisterUse(*iter, ins, /* considerCopy = */ true)) {
          lastRegisterFrom = inputOf(ins);
          lastRegisterTo = iter->pos.next();
        }
      }
    }
  }

  // Can't trim non-register uses off the end by splitting.
  if (!lastRegisterFrom.bits()) {
    JitSpew(JitSpew_RegAlloc, "  .. bundle has no register uses");
    return true;
  }
  if (lastUse < lastRegisterTo) {
    JitSpew(JitSpew_RegAlloc, "  .. bundle's last use is a register use");
    return true;
  }

  JitSpewIfEnabled(JitSpew_RegAlloc, "  .. split after last register use at %u",
                   lastRegisterTo.bits());

  SplitPositionVector splitPositions;
  if (!splitPositions.append(lastRegisterTo)) {
    return false;
  }
  *success = true;
  return splitAt(bundle, splitPositions);
}

bool BacktrackingAllocator::trySplitBeforeFirstRegisterUse(LiveBundle* bundle,
                                                           LiveBundle* conflict,
                                                           bool* success) {
  // If this bundle's earlier uses do not require it to be in a register,
  // split it before the first use which does require a register. If conflict
  // is specified, only consider register uses after the conflict ends.

  if (isRegisterDefinition(bundle->firstRange())) {
    JitSpew(JitSpew_RegAlloc, "  .. bundle is defined by a register");
    return true;
  }
  if (!bundle->firstRange()->hasDefinition()) {
    JitSpew(JitSpew_RegAlloc, "  .. bundle does not have definition");
    return true;
  }

  CodePosition firstRegisterFrom;

  CodePosition conflictEnd;
  if (conflict) {
    for (LiveBundle::RangeIterator iter = conflict->rangesBegin(); iter;
         iter++) {
      LiveRange* range = *iter;
      if (range->to() > conflictEnd) {
        conflictEnd = range->to();
      }
    }
  }

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;

    if (!conflict || range->from() > conflictEnd) {
      if (range->hasDefinition() && isRegisterDefinition(range)) {
        firstRegisterFrom = range->from();
        break;
      }
    }

    for (UsePositionIterator iter(range->usesBegin()); iter; iter++) {
      LNode* ins = insData[iter->pos];

      if (!conflict || outputOf(ins) >= conflictEnd) {
        if (isRegisterUse(*iter, ins, /* considerCopy = */ true)) {
          firstRegisterFrom = inputOf(ins);
          break;
        }
      }
    }
    if (firstRegisterFrom.bits()) {
      break;
    }
  }

  if (!firstRegisterFrom.bits()) {
    // Can't trim non-register uses off the beginning by splitting.
    JitSpew(JitSpew_RegAlloc, "  bundle has no register uses");
    return true;
  }

  JitSpewIfEnabled(JitSpew_RegAlloc,
                   "  .. split before first register use at %u",
                   firstRegisterFrom.bits());

  SplitPositionVector splitPositions;
  if (!splitPositions.append(firstRegisterFrom)) {
    return false;
  }
  *success = true;
  return splitAt(bundle, splitPositions);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// The top level driver for the splitting machinery                          //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// ::chooseBundleSplit
// -------------------
// If the first allocation loop (in ::go) can't allocate a bundle, it hands it
// off to ::chooseBundleSplit, which is the "entry point" of the bundle-split
// machinery.  This tries four heuristics in turn, to see if any can split the
// bundle:
//
// * ::trySplitAcrossHotcode
// * ::splitAcrossCalls (in some cases)
// * ::trySplitBeforeFirstRegisterUse
// * ::trySplitAfterLastRegisterUse
//
// These routines have similar structure: they try to decide on one or more
// CodePositions at which to split the bundle, using whatever heuristics they
// have to hand.  If suitable CodePosition(s) are found, they are put into a
// `SplitPositionVector`, and the bundle and the vector are handed off to
// ::splitAt, which performs the split (at least in theory) at the chosen
// positions.  It also arranges for the new bundles to be added to
// ::allocationQueue.
//
// ::trySplitAcrossHotcode has a special case for JS -- it modifies the
// bundle(s) itself, rather than using ::splitAt.
//
// If none of the heuristic routines apply, then ::splitAt is called with an
// empty vector of split points.  This is interpreted to mean "split at all
// register uses".  When combined with how ::splitAt works, the effect is to
// spill the bundle.

bool BacktrackingAllocator::chooseBundleSplit(LiveBundle* bundle, bool hasCall,
                                              LiveBundle* conflict) {
  bool success = false;

  JitSpewIfEnabled(JitSpew_RegAlloc, "  Splitting %s ..",
                   bundle->toString().get());

  if (!trySplitAcrossHotcode(bundle, &success)) {
    return false;
  }
  if (success) {
    return true;
  }

  if (hasCall) {
    return splitAcrossCalls(bundle);
  }

  if (!trySplitBeforeFirstRegisterUse(bundle, conflict, &success)) {
    return false;
  }
  if (success) {
    return true;
  }

  if (!trySplitAfterLastRegisterUse(bundle, conflict, &success)) {
    return false;
  }
  if (success) {
    return true;
  }

  // Split at all register uses.
  SplitPositionVector emptyPositions;
  return splitAt(bundle, emptyPositions);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Bundle allocation                                                         //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

static const size_t MAX_ATTEMPTS = 2;

bool BacktrackingAllocator::computeRequirement(LiveBundle* bundle,
                                               Requirement* requirement,
                                               Requirement* hint) {
  // Set any requirement or hint on bundle according to its definition and
  // uses. Return false if there are conflicting requirements which will
  // require the bundle to be split.

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    VirtualRegister& reg = range->vreg();

    if (range->hasDefinition()) {
      // Deal with any definition constraints/hints.
      LDefinition::Policy policy = reg.def()->policy();
      if (policy == LDefinition::FIXED || policy == LDefinition::STACK) {
        // Fixed and stack policies get a FIXED requirement.  (In the stack
        // case, the allocation should have been performed already by
        // mergeAndQueueRegisters.)
        JitSpewIfEnabled(JitSpew_RegAlloc,
                         "  Requirement %s, fixed by definition",
                         reg.def()->output()->toString().get());
        if (!requirement->merge(Requirement(*reg.def()->output()))) {
          return false;
        }
      } else if (reg.ins()->isPhi()) {
        // Phis don't have any requirements, but they should prefer their
        // input allocations. This is captured by the group hints above.
      } else {
        // Non-phis get a REGISTER requirement.
        if (!requirement->merge(Requirement(Requirement::REGISTER))) {
          return false;
        }
      }
    }

    // Search uses for requirements.
    for (UsePositionIterator iter = range->usesBegin(); iter; iter++) {
      LUse::Policy policy = iter->usePolicy();
      if (policy == LUse::FIXED) {
        AnyRegister required = GetFixedRegister(reg.def(), iter->use());

        JitSpewIfEnabled(JitSpew_RegAlloc, "  Requirement %s, due to use at %u",
                         required.name(), iter->pos.bits());

        // If there are multiple fixed registers which the bundle is
        // required to use, fail. The bundle will need to be split before
        // it can be allocated.
        if (!requirement->merge(Requirement(LAllocation(required)))) {
          return false;
        }
      } else if (policy == LUse::REGISTER) {
        if (!requirement->merge(Requirement(Requirement::REGISTER))) {
          return false;
        }
      } else if (policy == LUse::ANY) {
        // ANY differs from KEEPALIVE by actively preferring a register.
        if (!hint->merge(Requirement(Requirement::REGISTER))) {
          return false;
        }
      }

      // The only case of STACK use policies is individual stack results using
      // their containing stack result area, which is given a fixed allocation
      // above.
      MOZ_ASSERT_IF(policy == LUse::STACK,
                    requirement->kind() == Requirement::FIXED);
      MOZ_ASSERT_IF(policy == LUse::STACK,
                    requirement->allocation().isStackArea());
    }
  }

  return true;
}

bool BacktrackingAllocator::tryAllocateRegister(PhysicalRegister& r,
                                                LiveBundle* bundle,
                                                bool* success, bool* hasCall,
                                                LiveBundleVector& conflicting) {
  *success = false;

  // If we know this bundle contains a call (where all registers are spilled) we
  // shouldn't try again to allocate a register.
  MOZ_ASSERT(!*hasCall);

  if (!r.allocatable) {
    return true;
  }

  LiveBundleVector aliasedConflicting;

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    LiveRangePlus rangePlus(range);

    // All ranges in the bundle must be compatible with the physical register.
    MOZ_ASSERT(range->vreg().isCompatible(r.reg));

    const size_t numAliased = r.reg.numAliased();
    for (size_t a = 0; a < numAliased; a++) {
      PhysicalRegister& rAlias = registers[r.reg.aliased(a).code()];
      LiveRangePlus existingPlus;
      if (!rAlias.allocations.contains(rangePlus, &existingPlus)) {
        continue;
      }
      const LiveRange* existing = existingPlus.liveRange();
      if (existing->hasVreg()) {
        MOZ_ASSERT(existing->bundle()->allocation().toAnyRegister() ==
                   rAlias.reg);
        bool duplicate = false;
        for (size_t i = 0; i < aliasedConflicting.length(); i++) {
          if (aliasedConflicting[i] == existing->bundle()) {
            duplicate = true;
            break;
          }
        }
        if (!duplicate && !aliasedConflicting.append(existing->bundle())) {
          return false;
        }
      } else {
        // This bundle contains a call instruction.
        MOZ_ASSERT(lookupFirstCallPositionInRange(range->from(), range->to()));
        JitSpewIfEnabled(JitSpew_RegAlloc, "  %s collides with fixed use %s",
                         rAlias.reg.name(), existing->toString().get());
        *hasCall = true;
        return true;
      }
      MOZ_ASSERT(r.reg.numAliased() == numAliased);
    }
  }

  if (!aliasedConflicting.empty()) {
    // One or more aliased registers is allocated to another bundle
    // overlapping this one. Keep track of the conflicting set, and in the
    // case of multiple conflicting sets keep track of the set with the
    // lowest maximum spill weight.

    // The #ifdef guards against "unused variable 'existing'" bustage.
#ifdef JS_JITSPEW
    if (JitSpewEnabled(JitSpew_RegAlloc)) {
      if (aliasedConflicting.length() == 1) {
        LiveBundle* existing = aliasedConflicting[0];
        JitSpew(JitSpew_RegAlloc, "  %s collides with %s [weight %zu]",
                r.reg.name(), existing->toString().get(),
                computeSpillWeight(existing));
      } else {
        JitSpew(JitSpew_RegAlloc, "  %s collides with the following",
                r.reg.name());
        for (size_t i = 0; i < aliasedConflicting.length(); i++) {
          LiveBundle* existing = aliasedConflicting[i];
          JitSpew(JitSpew_RegAlloc, "    %s [weight %zu]",
                  existing->toString().get(), computeSpillWeight(existing));
        }
      }
    }
#endif

    if (conflicting.empty()) {
      conflicting = std::move(aliasedConflicting);
    } else {
      if (maximumSpillWeight(aliasedConflicting) <
          maximumSpillWeight(conflicting)) {
        conflicting = std::move(aliasedConflicting);
      }
    }
    return true;
  }

  JitSpewIfEnabled(JitSpew_RegAlloc, "  allocated to %s", r.reg.name());

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    if (!alloc().ensureBallast()) {
      return false;
    }
    LiveRangePlus rangePlus(range);
    if (!r.allocations.insert(rangePlus)) {
      return false;
    }
  }

  bundle->setAllocation(LAllocation(r.reg));
  *success = true;
  return true;
}

bool BacktrackingAllocator::tryAllocateAnyRegister(
    LiveBundle* bundle, bool* success, bool* hasCall,
    LiveBundleVector& conflicting) {
  // Search for any available register which the bundle can be allocated to.

  LDefinition::Type type = bundle->firstRange()->vreg().type();

  if (LDefinition::isFloatReg(type)) {
    for (size_t i = AnyRegister::FirstFloatReg; i < AnyRegister::Total; i++) {
      if (!LDefinition::isFloatRegCompatible(type, registers[i].reg.fpu())) {
        continue;
      }
      if (!tryAllocateRegister(registers[i], bundle, success, hasCall,
                               conflicting)) {
        return false;
      }
      if (*success) {
        break;
      }
      if (*hasCall) {
        // This bundle contains a call instruction. Calls require spilling all
        // registers, so we have to split or spill this bundle.
        break;
      }
    }
    return true;
  }

  for (size_t i = 0; i < AnyRegister::FirstFloatReg; i++) {
    if (!tryAllocateRegister(registers[i], bundle, success, hasCall,
                             conflicting)) {
      return false;
    }
    if (*success) {
      break;
    }
    if (*hasCall) {
      // This bundle contains a call instruction. Calls require spilling all
      // registers, so we have to split or spill this bundle.
      break;
    }
  }
  return true;
}

bool BacktrackingAllocator::evictBundle(LiveBundle* bundle) {
  JitSpewIfEnabled(JitSpew_RegAlloc,
                   "  Evicting %s [priority %zu] [weight %zu]",
                   bundle->toString().get(), computePriority(bundle),
                   computeSpillWeight(bundle));

  AnyRegister reg(bundle->allocation().toAnyRegister());
  PhysicalRegister& physical = registers[reg.code()];
  MOZ_ASSERT(physical.reg == reg && physical.allocatable);

  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    LiveRangePlus rangePlus(range);
    physical.allocations.remove(rangePlus);
  }

  bundle->setAllocation(LAllocation());

  size_t priority = computePriority(bundle);
  return allocationQueue.insert(QueueItem(bundle, priority));
}

bool BacktrackingAllocator::tryAllocateFixed(LiveBundle* bundle,
                                             Requirement requirement,
                                             bool* success, bool* hasCall,
                                             LiveBundleVector& conflicting) {
  // Spill bundles which are required to be in a certain stack slot.
  if (!requirement.allocation().isAnyRegister()) {
    JitSpew(JitSpew_RegAlloc, "  stack allocation requirement");
    bundle->setAllocation(requirement.allocation());
    *success = true;
    return true;
  }

  AnyRegister reg = requirement.allocation().toAnyRegister();
  return tryAllocateRegister(registers[reg.code()], bundle, success, hasCall,
                             conflicting);
}

bool BacktrackingAllocator::tryAllocateNonFixed(LiveBundle* bundle,
                                                Requirement requirement,
                                                Requirement hint, bool* success,
                                                bool* hasCall,
                                                LiveBundleVector& conflicting) {
  MOZ_ASSERT(hint.kind() != Requirement::FIXED);
  MOZ_ASSERT(conflicting.empty());

  // Spill bundles which have no hint or register requirement.
  if (requirement.kind() == Requirement::NONE &&
      hint.kind() == Requirement::NONE) {
    JitSpew(JitSpew_RegAlloc,
            "  postponed spill (no hint or register requirement)");
    if (!spilledBundles.append(bundle)) {
      return false;
    }
    *success = true;
    return true;
  }

  if (!tryAllocateAnyRegister(bundle, success, hasCall, conflicting)) {
    return false;
  }
  if (*success) {
    return true;
  }

  // Spill bundles which have no register requirement if they didn't get
  // allocated.
  if (requirement.kind() == Requirement::NONE) {
    JitSpew(JitSpew_RegAlloc, "  postponed spill (no register requirement)");
    if (!spilledBundles.append(bundle)) {
      return false;
    }
    *success = true;
    return true;
  }

  // We failed to allocate this bundle.
  MOZ_ASSERT(!*success);
  return true;
}

bool BacktrackingAllocator::processBundle(const MIRGenerator* mir,
                                          LiveBundle* bundle) {
  JitSpewIfEnabled(JitSpew_RegAlloc,
                   "Allocating %s [priority %zu] [weight %zu]",
                   bundle->toString().get(), computePriority(bundle),
                   computeSpillWeight(bundle));

  // A bundle can be processed by doing any of the following:
  //
  // - Assigning the bundle a register. The bundle cannot overlap any other
  //   bundle allocated for that physical register.
  //
  // - Spilling the bundle, provided it has no register uses.
  //
  // - Splitting the bundle into two or more bundles which cover the original
  //   one. The new bundles are placed back onto the priority queue for later
  //   processing.
  //
  // - Evicting one or more existing allocated bundles, and then doing one
  //   of the above operations. Evicted bundles are placed back on the
  //   priority queue. Any evicted bundles must have a lower spill weight
  //   than the bundle being processed.
  //
  // As long as this structure is followed, termination is guaranteed.
  // In general, we want to minimize the amount of bundle splitting (which
  // generally necessitates spills), so allocate longer lived, lower weight
  // bundles first and evict and split them later if they prevent allocation
  // for higher weight bundles.

  Requirement requirement, hint;
  bool doesNotHaveFixedConflict =
      computeRequirement(bundle, &requirement, &hint);

  bool hasCall = false;
  LiveBundleVector conflicting;

  if (doesNotHaveFixedConflict) {
    for (size_t attempt = 0;; attempt++) {
      if (mir->shouldCancel("Backtracking Allocation (processBundle loop)")) {
        return false;
      }

      bool success = false;
      hasCall = false;
      conflicting.clear();

      // Ok, let's try allocating for this bundle.
      if (requirement.kind() == Requirement::FIXED) {
        if (!tryAllocateFixed(bundle, requirement, &success, &hasCall,
                              conflicting)) {
          return false;
        }
      } else {
        if (!tryAllocateNonFixed(bundle, requirement, hint, &success, &hasCall,
                                 conflicting)) {
          return false;
        }
      }

      // If that worked, we're done!
      if (success) {
        return true;
      }

      // If that didn't work, but we have one or more non-call bundles known to
      // be conflicting, maybe we can evict them and try again.
      if ((attempt < MAX_ATTEMPTS || minimalBundle(bundle)) && !hasCall &&
          !conflicting.empty() &&
          maximumSpillWeight(conflicting) < computeSpillWeight(bundle)) {
        for (size_t i = 0; i < conflicting.length(); i++) {
          if (!evictBundle(conflicting[i])) {
            return false;
          }
        }
        continue;
      }

      // We have to split this bundle.
      break;
    }
  }

  // A minimal bundle cannot be split any further. If we try to split it
  // it at this point we will just end up with the same bundle and will
  // enter an infinite loop. Weights and the initial live ranges must
  // be constructed so that any minimal bundle is allocatable.
  MOZ_ASSERT(!minimalBundle(bundle));

  LiveBundle* conflict = conflicting.empty() ? nullptr : conflicting[0];
  return chooseBundleSplit(bundle, hasCall, conflict);
}

// Helper for ::tryAllocatingRegistersForSpillBundles
bool BacktrackingAllocator::spill(LiveBundle* bundle) {
  JitSpew(JitSpew_RegAlloc, "  Spilling bundle");
  MOZ_ASSERT(bundle->allocation().isBogus());

  if (LiveBundle* spillParent = bundle->spillParent()) {
    JitSpew(JitSpew_RegAlloc, "    Using existing spill bundle");
    for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
      LiveRange* range = *iter;
      LiveRange* parentRange = spillParent->rangeFor(range->from());
      MOZ_ASSERT(parentRange->contains(range));
      MOZ_ASSERT(&range->vreg() == &parentRange->vreg());
      range->tryToMoveDefAndUsesInto(parentRange);
    }
    bundle->removeAllRangesFromVirtualRegisters();
    return true;
  }

  return bundle->spillSet()->addSpilledBundle(bundle);
}

bool BacktrackingAllocator::tryAllocatingRegistersForSpillBundles() {
  for (auto it = spilledBundles.begin(); it != spilledBundles.end(); it++) {
    LiveBundle* bundle = *it;
    LiveBundleVector conflicting;
    bool hasCall = false;
    bool success = false;

    if (mir->shouldCancel("Backtracking Try Allocating Spilled Bundles")) {
      return false;
    }

    JitSpewIfEnabled(JitSpew_RegAlloc, "Spill or allocate %s",
                     bundle->toString().get());

    if (!tryAllocateAnyRegister(bundle, &success, &hasCall, conflicting)) {
      return false;
    }

    // If the bundle still has no register, spill the bundle.
    if (!success && !spill(bundle)) {
      return false;
    }
  }

  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Rewriting of the LIR after bundle processing is done:                     //
//   ::pickStackSlots                                                        //
//   ::createMoveGroupsFromLiveRangeTransitions                              //
//   ::installAllocationsInLIR                                               //
//   ::populateSafepoints                                                    //
//   ::annotateMoveGroups                                                    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// Helper for ::pickStackSlot
bool BacktrackingAllocator::insertAllRanges(LiveRangePlusSet& set,
                                            LiveBundle* bundle) {
  for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
    LiveRange* range = *iter;
    if (!alloc().ensureBallast()) {
      return false;
    }
    LiveRangePlus rangePlus(range);
    if (!set.insert(rangePlus)) {
      return false;
    }
  }
  return true;
}

void BacktrackingAllocator::sortVirtualRegisterRanges() {
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];
    reg.sortRanges();
  }
}

// Helper for ::pickStackSlots
bool BacktrackingAllocator::pickStackSlot(SpillSet* spillSet) {
  // Look through all ranges that have been spilled in this set for a
  // register definition which is fixed to a stack or argument slot. If we
  // find one, use it for all bundles that have been spilled. tryMergeBundles
  // makes sure this reuse is possible when an initial bundle contains ranges
  // from multiple virtual registers.
  for (size_t i = 0; i < spillSet->numSpilledBundles(); i++) {
    LiveBundle* bundle = spillSet->spilledBundle(i);
    for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter; iter++) {
      LiveRange* range = *iter;
      if (range->hasDefinition()) {
        LDefinition* def = range->vreg().def();
        if (def->policy() == LDefinition::FIXED) {
          MOZ_ASSERT(!def->output()->isAnyRegister());
          MOZ_ASSERT(!def->output()->isStackSlot());
          spillSet->setAllocation(*def->output());
          return true;
        }
      }
    }
  }

  LDefinition::Type type =
      spillSet->spilledBundle(0)->firstRange()->vreg().type();

  SpillSlotList* slotList;
  switch (LStackSlot::width(type)) {
    case LStackSlot::Word:
      slotList = &normalSlots;
      break;
    case LStackSlot::DoubleWord:
      slotList = &doubleSlots;
      break;
    case LStackSlot::QuadWord:
      slotList = &quadSlots;
      break;
    default:
      MOZ_CRASH("Bad width");
  }

  // Maximum number of existing spill slots we will look at before giving up
  // and allocating a new slot.
  static const size_t MAX_SEARCH_COUNT = 10;

  size_t searches = 0;
  SpillSlot* stop = nullptr;
  while (!slotList->empty()) {
    SpillSlot* spillSlot = *slotList->begin();
    if (!stop) {
      stop = spillSlot;
    } else if (stop == spillSlot) {
      // We looked through every slot in the list.
      break;
    }

    bool success = true;
    for (size_t i = 0; i < spillSet->numSpilledBundles(); i++) {
      LiveBundle* bundle = spillSet->spilledBundle(i);
      for (LiveBundle::RangeIterator iter = bundle->rangesBegin(); iter;
           iter++) {
        LiveRange* range = *iter;
        LiveRangePlus rangePlus(range);
        LiveRangePlus existingPlus;
        if (spillSlot->allocated.contains(rangePlus, &existingPlus)) {
          success = false;
          break;
        }
      }
      if (!success) {
        break;
      }
    }
    if (success) {
      // We can reuse this physical stack slot for the new bundles.
      // Update the allocated ranges for the slot.
      for (size_t i = 0; i < spillSet->numSpilledBundles(); i++) {
        LiveBundle* bundle = spillSet->spilledBundle(i);
        if (!insertAllRanges(spillSlot->allocated, bundle)) {
          return false;
        }
      }
      spillSet->setAllocation(spillSlot->alloc);
      return true;
    }

    // On a miss, move the spill to the end of the list. This will cause us
    // to make fewer attempts to allocate from slots with a large and
    // highly contended range.
    slotList->popFront();
    slotList->pushBack(spillSlot);

    if (++searches == MAX_SEARCH_COUNT) {
      break;
    }
  }

  // We need a new physical stack slot.
  LStackSlot::Width width = LStackSlot::width(type);
  uint32_t stackSlot;
  if (!stackSlotAllocator.allocateSlot(width, &stackSlot)) {
    return false;
  }

  SpillSlot* spillSlot =
      new (alloc().fallible()) SpillSlot(stackSlot, width, alloc().lifoAlloc());
  if (!spillSlot) {
    return false;
  }

  for (size_t i = 0; i < spillSet->numSpilledBundles(); i++) {
    LiveBundle* bundle = spillSet->spilledBundle(i);
    if (!insertAllRanges(spillSlot->allocated, bundle)) {
      return false;
    }
  }

  spillSet->setAllocation(spillSlot->alloc);

  slotList->pushFront(spillSlot);
  return true;
}

bool BacktrackingAllocator::pickStackSlots() {
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];

    if (mir->shouldCancel("Backtracking Pick Stack Slots")) {
      return false;
    }

    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      LiveBundle* bundle = iter->bundle();

      if (bundle->allocation().isBogus()) {
        if (!pickStackSlot(bundle->spillSet())) {
          return false;
        }
        MOZ_ASSERT(!bundle->allocation().isBogus());
      }
    }
  }

  return true;
}

// Helper for ::createMoveGroupsFromLiveRangeTransitions
bool BacktrackingAllocator::moveAtEdge(LBlock* predecessor, LBlock* successor,
                                       LiveRange* from, LiveRange* to,
                                       LDefinition::Type type) {
  if (successor->mir()->numPredecessors() > 1) {
    MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
    return moveAtExit(predecessor, from, to, type);
  }

  return moveAtEntry(successor, from, to, type);
}

// Helper for ::createMoveGroupsFromLiveRangeTransitions
void BacktrackingAllocator::removeDeadRanges(VirtualRegister& reg) {
  auto isDeadRange = [&](VirtualRegister::RangeVector& ranges,
                         LiveRange* range) {
    // Check for direct uses of this range.
    if (range->hasUses() || range->hasDefinition()) {
      return false;
    }

    // Check if there are later ranges for this vreg. The first item in the list
    // must have the highest start position so we compare against that one.
    CodePosition start = range->from();
    CodePosition maxFrom = ranges[0]->from();
    if (maxFrom > start) {
      return false;
    }

    LNode* ins = insData[start];
    if (start == entryOf(ins->block())) {
      return false;
    }

    // Check if this range ends at a loop backedge.
    LNode* last = insData[range->to().previous()];
    if (last->isGoto() &&
        last->toGoto()->target()->id() < last->block()->mir()->id()) {
      return false;
    }

    // Check if there are phis which this vreg flows to.
    if (reg.usedByPhi()) {
      return false;
    }

    return true;
  };

  reg.removeRangesIf(isDeadRange);
}

static void AssertCorrectRangeForPosition(const VirtualRegister& reg,
                                          CodePosition pos,
                                          const LiveRange* range) {
  MOZ_ASSERT(range->covers(pos));
#ifdef DEBUG
  // Assert the result is consistent with rangeFor. The ranges can be different
  // but must be equivalent (both register or both non-register ranges).
  LiveRange* expected = reg.rangeFor(pos, /* preferRegister = */ true);
  MOZ_ASSERT(range->bundle()->allocation().isAnyRegister() ==
             expected->bundle()->allocation().isAnyRegister());
#endif
}

// Helper for ::createMoveGroupsFromLiveRangeTransitions
bool BacktrackingAllocator::createMoveGroupsForControlFlowEdges(
    const VirtualRegister& reg, const ControlFlowEdgeVector& edges) {
  // Iterate over both the virtual register ranges (sorted by start position)
  // and the control flow edges (sorted by predecessorExit). When we find the
  // predecessor range for the next edge, add a move from predecessor range to
  // successor range.

  VirtualRegister::RangeIterator iter(reg);
  LiveRange* nonRegisterRange = nullptr;

  for (const ControlFlowEdge& edge : edges) {
    CodePosition pos = edge.predecessorExit;
    LAllocation successorAllocation =
        edge.successorRange->bundle()->allocation();

    // We don't need to insert a move if nonRegisterRange covers the predecessor
    // block exit and has the same allocation as the successor block. This check
    // is not required for correctness but it reduces the number of generated
    // moves.
    if (nonRegisterRange && pos < nonRegisterRange->to() &&
        nonRegisterRange->bundle()->allocation() == successorAllocation) {
      MOZ_ASSERT(nonRegisterRange->covers(pos));
      continue;
    }

    // Search for a matching range. Prefer a register range.
    LiveRange* predecessorRange = nullptr;
    bool foundSameAllocation = false;
    while (true) {
      if (iter.done() || iter->from() > pos) {
        // No register range covers this edge.
        predecessorRange = nonRegisterRange;
        break;
      }
      if (iter->to() <= pos) {
        // Skip ranges that end before this edge (and later edges).
        iter++;
        continue;
      }
      MOZ_ASSERT(iter->covers(pos));
      if (iter->bundle()->allocation() == successorAllocation) {
        // There's a range covering the predecessor block exit that has the same
        // allocation, so we don't need to insert a move. This check is not
        // required for correctness but it reduces the number of generated
        // moves.
        foundSameAllocation = true;
        break;
      }
      if (iter->bundle()->allocation().isAnyRegister()) {
        predecessorRange = *iter;
        break;
      }
      if (!nonRegisterRange || iter->to() > nonRegisterRange->to()) {
        nonRegisterRange = *iter;
      }
      iter++;
    }

    if (foundSameAllocation) {
      continue;
    }

    MOZ_ASSERT(predecessorRange);
    AssertCorrectRangeForPosition(reg, pos, predecessorRange);

    if (!alloc().ensureBallast()) {
      return false;
    }
    JitSpew(JitSpew_RegAlloc, "    (moveAtEdge#2)");
    if (!moveAtEdge(edge.predecessor, edge.successor, predecessorRange,
                    edge.successorRange, reg.type())) {
      return false;
    }
  }

  return true;
}

bool BacktrackingAllocator::createMoveGroupsFromLiveRangeTransitions() {
  // Add moves to handle changing assignments for vregs over their lifetime.
  JitSpew(JitSpew_RegAlloc, "ResolveControlFlow: begin");

  JitSpew(JitSpew_RegAlloc,
          "  ResolveControlFlow: adding MoveGroups within blocks");

  // Look for places where a register's assignment changes in the middle of a
  // basic block.
  MOZ_ASSERT(!vregs[0u].hasRanges());
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];

    if (mir->shouldCancel(
            "Backtracking Resolve Control Flow (vreg outer loop)")) {
      return false;
    }

    // Remove ranges which will never be used.
    removeDeadRanges(reg);

    LiveRange* registerRange = nullptr;
    LiveRange* nonRegisterRange = nullptr;
    VirtualRegister::RangeIterator iter(reg);

    // Keep track of the register and non-register ranges with the highest end
    // position before advancing the iterator. These are predecessor ranges for
    // later ranges.
    auto moveToNextRange = [&](LiveRange* range) {
      MOZ_ASSERT(*iter == range);
      if (range->bundle()->allocation().isAnyRegister()) {
        if (!registerRange || range->to() > registerRange->to()) {
          registerRange = range;
        }
      } else {
        if (!nonRegisterRange || range->to() > nonRegisterRange->to()) {
          nonRegisterRange = range;
        }
      }
      iter++;
    };

    // Iterate over all ranges.
    while (!iter.done()) {
      LiveRange* range = *iter;

      if (mir->shouldCancel(
              "Backtracking Resolve Control Flow (vreg inner loop)")) {
        return false;
      }

      // The range which defines the register does not have a predecessor
      // to add moves from.
      if (range->hasDefinition()) {
        moveToNextRange(range);
        continue;
      }

      // Ignore ranges that start at block boundaries. We will handle
      // these in the next phase.
      CodePosition start = range->from();
      LNode* ins = insData[start];
      if (start == entryOf(ins->block())) {
        moveToNextRange(range);
        continue;
      }

      // Determine the predecessor range to use for this range and other ranges
      // starting at the same position. Prefer a register range.
      LiveRange* predecessorRange = nullptr;
      if (registerRange && start.previous() < registerRange->to()) {
        predecessorRange = registerRange;
      } else {
        MOZ_ASSERT(nonRegisterRange);
        MOZ_ASSERT(start.previous() < nonRegisterRange->to());
        predecessorRange = nonRegisterRange;
      }
      AssertCorrectRangeForPosition(reg, start.previous(), predecessorRange);

      // Add moves from predecessorRange to all ranges that start here.
      do {
        range = *iter;
        MOZ_ASSERT(!range->hasDefinition());

        if (!alloc().ensureBallast()) {
          return false;
        }

#ifdef DEBUG
        // If we already saw a range which covers the start of this range, it
        // must have a different allocation.
        for (VirtualRegister::RangeIterator prevIter(reg); *prevIter != range;
             prevIter++) {
          MOZ_ASSERT_IF(prevIter->covers(start),
                        prevIter->bundle()->allocation() !=
                            range->bundle()->allocation());
        }
#endif

        if (start.subpos() == CodePosition::INPUT) {
          JitSpewIfEnabled(JitSpew_RegAlloc, "    moveInput (%s) <- (%s)",
                           range->toString().get(),
                           predecessorRange->toString().get());
          if (!moveInput(ins->toInstruction(), predecessorRange, range,
                         reg.type())) {
            return false;
          }
        } else {
          JitSpew(JitSpew_RegAlloc, "    (moveAfter)");
          if (!moveAfter(ins->toInstruction(), predecessorRange, range,
                         reg.type())) {
            return false;
          }
        }

        moveToNextRange(range);
      } while (!iter.done() && iter->from() == start);
    }
  }

  JitSpew(JitSpew_RegAlloc,
          "  ResolveControlFlow: adding MoveGroups for phi nodes");

  for (size_t i = 0; i < graph.numBlocks(); i++) {
    if (mir->shouldCancel("Backtracking Resolve Control Flow (block loop)")) {
      return false;
    }

    LBlock* successor = graph.getBlock(i);
    MBasicBlock* mSuccessor = successor->mir();
    if (mSuccessor->numPredecessors() < 1) {
      continue;
    }

    // Resolve phis to moves.
    for (size_t j = 0; j < successor->numPhis(); j++) {
      LPhi* phi = successor->getPhi(j);
      MOZ_ASSERT(phi->numDefs() == 1);
      LDefinition* def = phi->getDef(0);
      VirtualRegister& reg = vreg(def);
      LiveRange* to = reg.firstRange();
      MOZ_ASSERT(to->from() == entryOf(successor));

      for (size_t k = 0; k < mSuccessor->numPredecessors(); k++) {
        LBlock* predecessor = mSuccessor->getPredecessor(k)->lir();
        MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);

        LAllocation* input = phi->getOperand(k);
        LiveRange* from = vreg(input).rangeFor(exitOf(predecessor),
                                               /* preferRegister = */ true);
        MOZ_ASSERT(from);

        if (!alloc().ensureBallast()) {
          return false;
        }

        // Note: we have to use moveAtEdge both here and below (for edge
        // resolution) to avoid conflicting moves. See bug 1493900.
        JitSpew(JitSpew_RegAlloc, "    (moveAtEdge#1)");
        if (!moveAtEdge(predecessor, successor, from, to, def->type())) {
          return false;
        }
      }
    }
  }

  JitSpew(JitSpew_RegAlloc,
          "  ResolveControlFlow: adding MoveGroups to fix conflicted edges");

  // Add moves to resolve graph edges with different allocations at their
  // source and target.
  ControlFlowEdgeVector edges;
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];

    // First collect all control flow edges we need to resolve. This loop knows
    // the range on the successor side, but looking up the corresponding
    // predecessor range with rangeFor is quadratic so we handle that
    // differently.
    edges.clear();
    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      LiveRange* targetRange = *iter;

      size_t firstBlockId = insData[targetRange->from()]->block()->mir()->id();
      if (!targetRange->covers(entryOf(graph.getBlock(firstBlockId)))) {
        firstBlockId++;
      }
      for (size_t id = firstBlockId; id < graph.numBlocks(); id++) {
        LBlock* successor = graph.getBlock(id);
        if (!targetRange->covers(entryOf(successor))) {
          break;
        }

        VirtualRegBitSet& live = liveIn[id];
        if (!live.contains(i)) {
          continue;
        }

        for (size_t j = 0; j < successor->mir()->numPredecessors(); j++) {
          LBlock* predecessor = successor->mir()->getPredecessor(j)->lir();
          CodePosition predecessorExit = exitOf(predecessor);
          if (targetRange->covers(predecessorExit)) {
            continue;
          }
          if (!edges.emplaceBack(predecessor, successor, targetRange,
                                 predecessorExit)) {
            return false;
          }
        }
      }
    }

    if (edges.empty()) {
      continue;
    }

    // Sort edges by predecessor position. This doesn't need to be a stable sort
    // because createMoveGroupsForControlFlowEdges will use the same predecessor
    // range if there are multiple edges with the same predecessor position.
    auto compareEdges = [](const ControlFlowEdge& a, const ControlFlowEdge& b) {
      return a.predecessorExit < b.predecessorExit;
    };
    std::sort(edges.begin(), edges.end(), compareEdges);

    // Resolve edges and add move groups.
    if (!createMoveGroupsForControlFlowEdges(reg, edges)) {
      return false;
    }
  }

  JitSpew(JitSpew_RegAlloc, "ResolveControlFlow: end");
  return true;
}

// Helper for ::addLiveRegistersForRange
size_t BacktrackingAllocator::findFirstNonCallSafepoint(CodePosition pos,
                                                        size_t startFrom) {
  // Assert startFrom is valid.
  MOZ_ASSERT_IF(startFrom > 0,
                inputOf(nonCallSafepoints_[startFrom - 1]) < pos);

  size_t i = startFrom;
  for (; i < nonCallSafepoints_.length(); i++) {
    const LInstruction* ins = nonCallSafepoints_[i];
    if (pos <= inputOf(ins)) {
      break;
    }
  }
  return i;
}

// Helper for ::installAllocationsInLIR
void BacktrackingAllocator::addLiveRegistersForRange(
    VirtualRegister& reg, LiveRange* range, size_t* firstNonCallSafepoint) {
  // Fill in the live register sets for all non-call safepoints.
  LAllocation a = range->bundle()->allocation();
  if (!a.isAnyRegister()) {
    return;
  }

  // Don't add output registers to the safepoint.
  CodePosition start = range->from();
  if (range->hasDefinition()) {
#ifdef CHECK_OSIPOINT_REGISTERS
    // Add output and temp registers to the safepoint's clobberedRegs.
    // Note: the outputs aren't added to the safepoint's liveRegs here, but the
    // same register might still be added to liveRegs for one of the inputs, so
    // we have to add outputs to clobberedRegs here.
    if (reg.ins()->isInstruction() && !reg.ins()->isCall()) {
      if (LSafepoint* safepoint = reg.ins()->toInstruction()->safepoint()) {
        safepoint->addClobberedRegister(a.toAnyRegister());
      }
    }
#endif
    if (!reg.isTemp()) {
      start = start.next();
    }
  }

  *firstNonCallSafepoint =
      findFirstNonCallSafepoint(start, *firstNonCallSafepoint);

  for (size_t i = *firstNonCallSafepoint; i < nonCallSafepoints_.length();
       i++) {
    LInstruction* ins = nonCallSafepoints_[i];
    CodePosition pos = inputOf(ins);

    // Safepoints are sorted, so we can shortcut out of this loop
    // if we go out of range.
    if (range->to() <= pos) {
      break;
    }

    MOZ_ASSERT(range->covers(pos));

    LSafepoint* safepoint = ins->safepoint();
    safepoint->addLiveRegister(a.toAnyRegister());
  }
}

// Helper for ::installAllocationsInLIR
static inline size_t NumReusingDefs(LInstruction* ins) {
  size_t num = 0;
  for (size_t i = 0; i < ins->numDefs(); i++) {
    LDefinition* def = ins->getDef(i);
    if (def->policy() == LDefinition::MUST_REUSE_INPUT) {
      num++;
    }
  }
  return num;
}

bool BacktrackingAllocator::installAllocationsInLIR() {
  JitSpew(JitSpew_RegAlloc, "Installing Allocations");

  // The virtual registers and safepoints are both ordered by position. To avoid
  // quadratic behavior in findFirstNonCallSafepoint, we use
  // firstNonCallSafepoint as cursor to start the search at the safepoint
  // returned by the previous call.
  size_t firstNonCallSafepoint = 0;

  MOZ_ASSERT(!vregs[0u].hasRanges());
  for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];

    if (mir->shouldCancel("Backtracking Install Allocations (main loop)")) {
      return false;
    }

    firstNonCallSafepoint =
        findFirstNonCallSafepoint(inputOf(reg.ins()), firstNonCallSafepoint);

    // The ranges are sorted by start position, so we can use the same
    // findFirstNonCallSafepoint optimization here.
    size_t firstNonCallSafepointForRange = firstNonCallSafepoint;

    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      LiveRange* range = *iter;

      if (range->hasDefinition()) {
        reg.def()->setOutput(range->bundle()->allocation());
        if (reg.ins()->recoversInput()) {
          LSnapshot* snapshot = reg.ins()->toInstruction()->snapshot();
          for (size_t i = 0; i < snapshot->numEntries(); i++) {
            LAllocation* entry = snapshot->getEntry(i);
            if (entry->isUse() &&
                entry->toUse()->policy() == LUse::RECOVERED_INPUT) {
              *entry = *reg.def()->output();
            }
          }
        }
      }

      for (UsePositionIterator iter(range->usesBegin()); iter; iter++) {
        LAllocation* alloc = iter->use();
        *alloc = range->bundle()->allocation();

        // For any uses which feed into MUST_REUSE_INPUT definitions,
        // add copies if the use and def have different allocations.
        LNode* ins = insData[iter->pos];
        if (LDefinition* def = FindReusingDefOrTemp(ins, alloc)) {
          LiveRange* outputRange = vreg(def).firstRange();
          MOZ_ASSERT(outputRange->covers(outputOf(ins)));
          LAllocation res = outputRange->bundle()->allocation();
          LAllocation sourceAlloc = range->bundle()->allocation();

          if (res != *alloc) {
            if (!this->alloc().ensureBallast()) {
              return false;
            }
            if (NumReusingDefs(ins->toInstruction()) <= 1) {
              LMoveGroup* group = getInputMoveGroup(ins->toInstruction());
              if (!group->addAfter(sourceAlloc, res, reg.type())) {
                return false;
              }
            } else {
              LMoveGroup* group = getFixReuseMoveGroup(ins->toInstruction());
              if (!group->add(sourceAlloc, res, reg.type())) {
                return false;
              }
            }
            *alloc = res;
          }
        }
      }

      addLiveRegistersForRange(reg, range, &firstNonCallSafepointForRange);
    }
  }

  graph.setLocalSlotsSize(stackSlotAllocator.stackHeight());
  return true;
}

// Helper for ::populateSafepoints
size_t BacktrackingAllocator::findFirstSafepoint(CodePosition pos,
                                                 size_t startFrom) {
  // Assert startFrom is valid.
  MOZ_ASSERT_IF(startFrom > 0, inputOf(safepoints_[startFrom - 1]) < pos);

  size_t i = startFrom;
  for (; i < safepoints_.length(); i++) {
    LInstruction* ins = safepoints_[i];
    if (pos <= inputOf(ins)) {
      break;
    }
  }
  return i;
}

bool BacktrackingAllocator::populateSafepoints() {
  JitSpew(JitSpew_RegAlloc, "Populating Safepoints");

  // The virtual registers and safepoints are both ordered by position. To avoid
  // quadratic behavior in findFirstSafepoint, we use firstSafepoint as cursor
  // to start the search at the safepoint returned by the previous call.
  size_t firstSafepoint = 0;

  MOZ_ASSERT(!vregs[0u].def());
  for (uint32_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];

    if (!reg.def() || !reg.def()->isSafepointGCType(reg.ins())) {
      continue;
    }

    firstSafepoint = findFirstSafepoint(inputOf(reg.ins()), firstSafepoint);
    if (firstSafepoint >= graph.numSafepoints()) {
      break;
    }

    // The ranges are sorted by start position, so we can use the same
    // findFirstSafepoint optimization here.
    size_t firstSafepointForRange = firstSafepoint;

    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      LiveRange* range = *iter;

      firstSafepointForRange =
          findFirstSafepoint(range->from(), firstSafepointForRange);

      for (size_t j = firstSafepointForRange; j < graph.numSafepoints(); j++) {
        LInstruction* ins = safepoints_[j];

        if (inputOf(ins) >= range->to()) {
          break;
        }

        MOZ_ASSERT(range->covers(inputOf(ins)));

        // Include temps but not instruction outputs. Also make sure
        // MUST_REUSE_INPUT is not used with gcthings or nunboxes, or
        // we would have to add the input reg to this safepoint.
        if (ins == reg.ins() && !reg.isTemp()) {
          DebugOnly<LDefinition*> def = reg.def();
          MOZ_ASSERT_IF(def->policy() == LDefinition::MUST_REUSE_INPUT,
                        def->type() == LDefinition::GENERAL ||
                            def->type() == LDefinition::INT32 ||
                            def->type() == LDefinition::FLOAT32 ||
                            def->type() == LDefinition::DOUBLE ||
                            def->type() == LDefinition::SIMD128);
          continue;
        }

        LSafepoint* safepoint = ins->safepoint();

        LAllocation a = range->bundle()->allocation();
        if (a.isGeneralReg() && ins->isCall()) {
          continue;
        }

        if (!safepoint->addGCAllocation(i, reg.def(), a)) {
          return false;
        }
      }
    }
  }

  return true;
}

bool BacktrackingAllocator::annotateMoveGroups() {
  // Annotate move groups in the LIR graph with any register that is not
  // allocated at that point and can be used as a scratch register. This is
  // only required for x86, as other platforms always have scratch registers
  // available for use.
#ifdef JS_CODEGEN_X86
  LiveRange* range = LiveRange::FallibleNew(alloc(), nullptr, CodePosition(),
                                            CodePosition().next());
  if (!range) {
    return false;
  }

  for (size_t i = 0; i < graph.numBlocks(); i++) {
    if (mir->shouldCancel("Backtracking Annotate Move Groups")) {
      return false;
    }

    LBlock* block = graph.getBlock(i);
    LInstruction* last = nullptr;
    for (LInstructionIterator iter = block->begin(); iter != block->end();
         ++iter) {
      if (iter->isMoveGroup()) {
        CodePosition from = last ? outputOf(last) : entryOf(block);
        range->setTo(from.next());
        range->setFrom(from);

        for (size_t i = 0; i < AnyRegister::Total; i++) {
          PhysicalRegister& reg = registers[i];
          if (reg.reg.isFloat() || !reg.allocatable) {
            continue;
          }

          // This register is unavailable for use if (a) it is in use
          // by some live range immediately before the move group,
          // or (b) it is an operand in one of the group's moves. The
          // latter case handles live ranges which end immediately
          // before the move group or start immediately after.
          // For (b) we need to consider move groups immediately
          // preceding or following this one.

          if (iter->toMoveGroup()->uses(reg.reg.gpr())) {
            continue;
          }
          bool found = false;
          LInstructionIterator niter(iter);
          for (niter++; niter != block->end(); niter++) {
            if (niter->isMoveGroup()) {
              if (niter->toMoveGroup()->uses(reg.reg.gpr())) {
                found = true;
                break;
              }
            } else {
              break;
            }
          }
          if (iter != block->begin()) {
            LInstructionIterator riter(iter);
            do {
              riter--;
              if (riter->isMoveGroup()) {
                if (riter->toMoveGroup()->uses(reg.reg.gpr())) {
                  found = true;
                  break;
                }
              } else {
                break;
              }
            } while (riter != block->begin());
          }

          if (found) {
            continue;
          }
          LiveRangePlus existingPlus;
          LiveRangePlus rangePlus(range);
          if (reg.allocations.contains(rangePlus, &existingPlus)) {
            continue;
          }

          iter->toMoveGroup()->setScratchRegister(reg.reg.gpr());
          break;
        }
      } else {
        last = *iter;
      }
    }
  }
#endif

  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Debug-printing support                                                    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#ifdef JS_JITSPEW

UniqueChars LiveRange::toString() const {
  AutoEnterOOMUnsafeRegion oomUnsafe;

  UniqueChars buf = JS_smprintf("v%u %u-%u", hasVreg() ? vreg().vreg() : 0,
                                from().bits(), to().bits() - 1);

  if (buf && bundle() && !bundle()->allocation().isBogus()) {
    buf = JS_sprintf_append(std::move(buf), " %s",
                            bundle()->allocation().toString().get());
  }

  buf = JS_sprintf_append(std::move(buf), " {");

  if (buf && hasDefinition()) {
    buf = JS_sprintf_append(std::move(buf), " %u_def", from().bits());
    if (hasVreg()) {
      // If the definition has a fixed requirement, print it too.
      const LDefinition* def = vreg().def();
      LDefinition::Policy policy = def->policy();
      if (policy == LDefinition::FIXED || policy == LDefinition::STACK) {
        if (buf) {
          buf = JS_sprintf_append(std::move(buf), ":F:%s",
                                  def->output()->toString().get());
        }
      }
    }
  }

  for (UsePositionIterator iter = usesBegin(); buf && iter; iter++) {
    buf = JS_sprintf_append(std::move(buf), " %u_%s", iter->pos.bits(),
                            iter->use()->toString().get());
  }

  buf = JS_sprintf_append(std::move(buf), " }");

  if (!buf) {
    oomUnsafe.crash("LiveRange::toString()");
  }

  return buf;
}

UniqueChars LiveBundle::toString() const {
  AutoEnterOOMUnsafeRegion oomUnsafe;

  UniqueChars buf = JS_smprintf("LB%u(", id());

  if (buf) {
    if (spillParent()) {
      buf =
          JS_sprintf_append(std::move(buf), "parent=LB%u", spillParent()->id());
    } else {
      buf = JS_sprintf_append(std::move(buf), "parent=none");
    }
  }

  for (LiveBundle::RangeIterator iter = rangesBegin(); buf && iter; iter++) {
    if (buf) {
      buf = JS_sprintf_append(std::move(buf), "%s %s",
                              (iter == rangesBegin()) ? "" : " ##",
                              iter->toString().get());
    }
  }

  if (buf) {
    buf = JS_sprintf_append(std::move(buf), ")");
  }

  if (!buf) {
    oomUnsafe.crash("LiveBundle::toString()");
  }

  return buf;
}

void BacktrackingAllocator::dumpLiveRangesByVReg(const char* who) {
  MOZ_ASSERT(!vregs[0u].hasRanges());

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Live ranges by virtual register (%s):", who);

  for (uint32_t i = 1; i < graph.numVirtualRegisters(); i++) {
    AutoJitSpewMessage msg(JitSpew_RegAlloc, "  ");
    VirtualRegister& reg = vregs[i];
    for (VirtualRegister::RangeIterator iter(reg); iter; iter++) {
      if (*iter != reg.firstRange()) {
        msg.append(" ## ");
      }
      msg.append("%s", iter->toString().get());
    }
  }
}

void BacktrackingAllocator::dumpLiveRangesByBundle(const char* who) {
  MOZ_ASSERT(!vregs[0u].hasRanges());

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Live ranges by bundle (%s):", who);

  for (uint32_t i = 1; i < graph.numVirtualRegisters(); i++) {
    VirtualRegister& reg = vregs[i];
    for (VirtualRegister::RangeIterator baseIter(reg); baseIter; baseIter++) {
      LiveRange* range = *baseIter;
      LiveBundle* bundle = range->bundle();
      if (range == bundle->firstRange()) {
        JitSpew(JitSpew_RegAlloc, "  %s", bundle->toString().get());
      }
    }
  }
}

void BacktrackingAllocator::dumpAllocations() {
  JitSpew(JitSpew_RegAlloc, "Allocations:");

  dumpLiveRangesByBundle("in dumpAllocations()");

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Allocations by physical register:");

  for (size_t i = 0; i < AnyRegister::Total; i++) {
    if (registers[i].allocatable && !registers[i].allocations.empty()) {
      AutoJitSpewMessage msg(JitSpew_RegAlloc,
                             "  %s:", AnyRegister::FromCode(i).name());
      bool first = true;
      LiveRangePlusSet::Iter lrpIter(&registers[i].allocations);
      while (lrpIter.hasMore()) {
        LiveRange* range = lrpIter.next().liveRange();
        if (first) {
          first = false;
        } else {
          msg.append(" /");
        }
        msg.append(" %s", range->toString().get());
      }
    }
  }

  JitSpew(JitSpew_RegAlloc, "\n");
}

#endif  // JS_JITSPEW

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Top level of the register allocation machinery                            //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

bool BacktrackingAllocator::go() {
  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Beginning register allocation");

  JitSpew(JitSpew_RegAlloc, "\n");
  if (JitSpewEnabled(JitSpew_RegAlloc)) {
    dumpInstructions("(Pre-allocation LIR)");
  }

  if (!init()) {
    return false;
  }

  if (!buildLivenessInfo()) {
    return false;
  }

#ifdef JS_JITSPEW
  if (JitSpewEnabled(JitSpew_RegAlloc)) {
    dumpLiveRangesByVReg("after liveness analysis");
  }
#endif

  if (!allocationQueue.reserve(graph.numVirtualRegisters() * 3 / 2)) {
    return false;
  }

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Beginning grouping and queueing registers");
  if (!mergeAndQueueRegisters()) {
    return false;
  }
  JitSpew(JitSpew_RegAlloc, "Completed grouping and queueing registers");

#ifdef JS_JITSPEW
  if (JitSpewEnabled(JitSpew_RegAlloc)) {
    dumpLiveRangesByBundle("after grouping/queueing regs");
  }
#endif

  // There now follow two allocation loops, which are really the heart of the
  // allocator.  First, the "main" allocation loop.  This does almost all of
  // the allocation work, by repeatedly pulling bundles out of
  // ::allocationQueue and calling ::processBundle on it, until there are no
  // bundles left in the queue.  Note that ::processBundle can add new smaller
  // bundles to the queue if it needs to split or spill a bundle.
  //
  // For each bundle in turn pulled out of ::allocationQueue, ::processBundle:
  //
  // * calls ::computeRequirement to discover the overall constraint for the
  //   bundle.
  //
  // * tries to find a register for it, by calling either ::tryAllocateFixed or
  //   ::tryAllocateNonFixed.
  //
  // * if that fails, but ::tryAllocateFixed / ::tryAllocateNonFixed indicate
  //   that there is some other bundle with lower spill weight that can be
  //   evicted, then that bundle is evicted (hence, put back into
  //   ::allocationQueue), and we try again.
  //
  // * at most MAX_ATTEMPTS may be made.
  //
  // * If that still fails to find a register, then the bundle is handed off to
  //   ::chooseBundleSplit.  That will choose to either split the bundle,
  //   yielding multiple pieces which are put back into ::allocationQueue, or
  //   it will spill the bundle.  Note that the same mechanism applies to both;
  //   there's no clear boundary between splitting and spilling, because
  //   spilling can be interpreted as an extreme form of splitting.
  //
  // ::processBundle and its callees contains much gnarly and logic which isn't
  // easy to understand, particularly in the area of how eviction candidates
  // are chosen.  But it works well enough, and tinkering doesn't seem to
  // improve the resulting allocations.  More important is the splitting logic,
  // because that controls where spill/reload instructions are placed.
  //
  // Eventually ::allocationQueue becomes empty, and each LiveBundle has either
  // been allocated a register or is marked for spilling.  In the latter case
  // it will have been added to ::spilledBundles.

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Beginning main allocation loop");
  JitSpew(JitSpew_RegAlloc, "\n");

  // Allocate, spill and split bundles until finished.
  while (!allocationQueue.empty()) {
    if (mir->shouldCancel("Backtracking Allocation")) {
      return false;
    }

    LiveBundle* bundle = allocationQueue.highest().bundle;
    allocationQueue.popHighest();
    if (!processBundle(mir, bundle)) {
      return false;
    }
  }

  // And here's the second allocation loop (hidden inside
  // ::tryAllocatingRegistersForSpillBundles).  It makes one last attempt to
  // find a register for each spill bundle.  There's no attempt to free up
  // registers by eviction.  In at least 99% of cases this attempt fails, in
  // which case the bundle is handed off to ::spill.  The lucky remaining 1%
  // get a register.  Unfortunately this scheme interacts badly with the
  // splitting strategy, leading to excessive register-to-register copying in
  // some very simple cases.  See bug 1752520.
  //
  // A modest but probably worthwhile amount of allocation time can be saved by
  // making ::tryAllocatingRegistersForSpillBundles use specialised versions of
  // ::tryAllocateAnyRegister and its callees, that don't bother to create sets
  // of conflicting bundles.  Creating those sets is expensive and, here,
  // pointless, since we're not going to do any eviction based on them.  This
  // refinement is implemented in the un-landed patch at bug 1758274 comment
  // 15.

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc,
          "Main allocation loop complete; "
          "beginning spill-bundle allocation loop");
  JitSpew(JitSpew_RegAlloc, "\n");

  if (!tryAllocatingRegistersForSpillBundles()) {
    return false;
  }

  JitSpew(JitSpew_RegAlloc, "\n");
  JitSpew(JitSpew_RegAlloc, "Spill-bundle allocation loop complete");
  JitSpew(JitSpew_RegAlloc, "\n");

  // After this point, the VirtualRegister ranges are sorted and must stay
  // sorted.
  sortVirtualRegisterRanges();

  if (!pickStackSlots()) {
    return false;
  }

#ifdef JS_JITSPEW
  if (JitSpewEnabled(JitSpew_RegAlloc)) {
    dumpAllocations();
  }
#endif

  if (!createMoveGroupsFromLiveRangeTransitions()) {
    return false;
  }

  if (!installAllocationsInLIR()) {
    return false;
  }

  if (!populateSafepoints()) {
    return false;
  }

  if (!annotateMoveGroups()) {
    return false;
  }

  JitSpew(JitSpew_RegAlloc, "\n");
  if (JitSpewEnabled(JitSpew_RegAlloc)) {
    dumpInstructions("(Post-allocation LIR)");
  }

  JitSpew(JitSpew_RegAlloc, "Finished register allocation");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
