*******************************************
* HipHop Intermediate Representation (HHIR)
*******************************************



Introduction
------------

The HipHop Intermediate Representation (IR) is a typed, in-memory,
static-single-assignment, intermediate-level representation of HHBC programs
used for just in time compilation, with these goals:

  1. Complete. The IR represents a program or program fragment entirely,
     without reference to HHBC or other upstream forms of the program.

  2. Type-Safe. Since the IR deals directly with refined types and internal VM
     types, all operations are typesafe. All instruction parameters have a
     parameter type P, and all variables have a type S. Given an instruction
     with source parameter type P and variable type S, S must be equal to or
     more refined than P (S == P or S <: P).

  3. Machine Independent. Since this IR is intended to be used in a JIT
     compiler, it will always be used in a machine specific context.
     Nevertheless, we rely on machine independence in order to separate
     concerns and increase portability of the VM. Passes which manipulate IR
     based on PHP or HHBC semantics should be portable. Passes which deal with
     machine specifics (such as register allocation) should be done in the
     lower level IR (vasm). Types are machine independent.

The unit of compilation is the IRUnit, which is a collection of Blocks
containing IRInstructions that produce and consume SSATmp values. Blocks are
single-entry, single-exit sequences of instructions (i.e. basic
blocks). Instructions may be annotated with Type parameter which modifies the
instruction's behavior, or with additional compile-time constant data (see
extra-data.h). Each SSATmp has a Type which describes the set of values it may
hold, over its entire live range. Instructions may have side effects, which
occur in execution order.

The static single assignment form guarantees the following two invariants for a
well-formed compilation unit:

  1. Each SSATmp is assigned to by exactly one IRInstruction.

  2. Definitions dominate uses. Every path to an IRInstruction using an SSATmp
     first executes the IRInstruction defining the SSATmp.

Any pass that generates or manipulates IR must preserve these invariants,
however it is possible and expected for the invariants to be temporarily broken
during IR generation or during an optimization pass.


Control Flow
------------

IRUnits have one entry block, zero or more exit blocks, and zero or more catch
blocks. Exit blocks leave the compilation unit in the middle of the same PHP
function using one of several instructions that exit a compilation unit
(e.g. ReqBindJmp). Catch blocks are blocks that are reachable from exceptional
control flow edges, and are executed during unwinding if an exception
propagates through the instruction that had it as a `taken' edge.

No SSATmps are defined on entry to the main Block.

Blocks which are join points may start with a DefLabel with destination
SSATmps. In that case, each predecessor must be a Jmp passing a matching number
of sources. In this case the Jmp acts as a tail-call, passing arguments the
same way a plain call would.

Together, the sources of the Jmp instructions and the destinations of the
DefLabel instructions act as traditional SSA Phi pseudo-functions; The type of
the DefLabel's destination is the type-union of the corresponding sources.
Because the Jmp sources are at the ends of blocks, they do not violate the SSA
dominator rule (rule 2, above).


Types
-----

For an overview of the HHIR type system, see the "Type System" section in
hackers-guide/jit-core.md.


SSATmps
-------

An SSATmp represents a virtual register. Since HHIR uses SSA, an SSATmp may
only be assigned to by one instruction. The type of an SSATmp represents the
set of values it may hold at the point it is defined, which is invariant over
the lifetime of the variable (from the definition point to the last use).


IRInstructions
--------------

An instruction is an executable operation with zero or more inputs (sources),
zero or one result (destination), and possible side effects such as accessing
memory, doing I/O, and which may branch or throw an exception. Some
instructions have a Type parameter which modifies its behavior, or other "extra
data" in an arbitrary C++ struct (see extra-data.h).

Each instruction has a signature which describes its effect, parameter types,
and return type, for example:

  IsType<T>, D(Bool), S(Cell), NF

The first column is the instruction name (and optional Type parameter in <>).

The second column describes the result (destination) using one of the D*
macros documented in hphp/runtime/vm/jit/ir-opcode.h, or ND for no destination.

The third column describes the sources, separated by whitespace, using macros
documented in hphp/runtime/vm/jit/ir-opcode.h, or NA if there are no sources.

The fourth column contains the flags, described below. The short name of the
flag (used in this file) is given first, with the long name that it expands to
in hphp/runtime/vm/jit/ir-opcode.cpp in parentheses after it.

NF

  The instruction has no flags.

PRc (ProducesRC)

  The instruction produces a value with an unconsumed reference that must be
  consumed, either by DecRefing it or storing it somewhere in memory.

CRc (ConsumesRC)

  The instruction consumes a reference to one or more of its sources, either by
  decreasing its refcount or storing the reference to memory.

T (Terminal)

  The instruction has no next instruction; it either jumps, returns, or throws.

B (Branch)

  The instruction has a (sometimes optional) taken edge. Instructions that are
  conditional branches (i.e. a Branch that is not Terminal) will also have a
  next edge.

P (Passthrough)

  The value of the instruction's dest is the same as one of its inputs; it
  differs only in the type of the variable, or some other property that doesn't
  affect the value of the variable itself.

MProp (MInstrProp)

  The instruction may affect the type and/or value of its base operand,
  operating on object properties.

MElem (MInstrElem)

  The instruction may affect the type and/or value of its base operand,
  operating on array elements.


Instruction set
---------------

1. Checks and Asserts

Note: Instructions that check boxed types only check that the operand is boxed,
and they ignore the type of the value inside the box (the inner type). The
inner type is normally checked when the value within the box is about to be
loaded, using a separate CheckRefInner instruction.

| CheckType<T>, DRefineS(0), S(Gen,Cls), B|P

  Check that the type of the src S0 is T, and if so copy it to D, and
  fallthrough. If S0 cannot be proven to be T, branch to block B. Note that
  this means S0 still /may/ be a subtype of T in block B in some circumstances.

  Specifically, subtypes of Type::Static may not be checked precisely,
  depending on the type of the source.  This means the instruction may take the
  branch in some circumstances even when S0 is a subtype of T, if T has a
  non-empty intersection with Type::Static.

  Also note that many types are not supported as the typeParam right now.

| CheckNullptr, ND, S(StaticStr,Nullptr), B

  If S0 is not a null pointer, branch to block B. This is used to check the
  return value of a native helper that returns a potentially null StringData*.

| AssertType, DRefineS(0), S(Gen,Cls,Ctx,FuncMM), P

  Assert that the type of S0 is T, copying it to D.

| CheckTypeMem<T>, ND, S(MemToGen), B

  If the value pointed to by S0 is not type T, branch to the block B.

| CheckVArray, DArrPacked, S(Arr), B|P

  Check that S0 is a varray, and if so copy it to D, and fallthrough. If S0 is
  not a varray, branch to block B.

| CheckDArray, DArrMixed, S(Arr), B|P

  Check that S0 is a darray, and if so copy it to D, and fallthrough. If S0 is
  not a darray, branch to block B.

| HintLocInner<T,localId>, ND, S(FramePtr), NF

  Hint that the inner type of a BoxedCell in localId is likely type T, where T
  is a subtype of BoxedCell. The type must be guarded on before it is known to
  be true (via CheckRefInner).

| HintStkInner<T,offset>, ND, S(StkPtr), NF

  Hint that the inner type of the BoxedInitCell on the stack pointed to by S0
  at offset (in cells) is T. The type must be guarded on before it is known to
  be true (via CheckRefInner).

| HintMBaseInner<T>, ND, NA, NF

  Hint that the inner type of the BoxedInitCell pointed to by the member base
  register is T.  The type must be guarded on before it is known to be true
  (via CheckRefInner).

| CheckLoc<T,localId>, ND, S(FramePtr), B

  Check that type of the given localId on the frame S0 is T; if not, branch to
  block B.

| CheckStk<T,offset>, ND, S(StkPtr), B

  Check that the type of the cell on the stack pointed to by S0 at offset (in
  cells) is T; if not, branch to block B.

| CheckMBase<T>, ND, S(LvalToGen), B

  Check that the value pointed to by the member base register S0 has type T; if
  not, branch to block B.  This is functionally the same as CheckTypeMem.

| AssertLoc<T,localId>, ND, S(FramePtr), NF

  Asserts that type of the supplied local on the frame S0 is T. This is used
  for local type information, and is similar to CheckLoc except it doesn't
  imply a runtime check (the assertion must've already been proven to be true)
  and cannot cause control flow.

| AssertStk<T,offset>, ND, S(StkPtr), NF

  Assert that stack element at `offset' (in cells) from S0 has type T. This is
  similar to a CheckStk except that it does not imply a runtime check and
  cannot cause control flow.

| AssertMBase<T>, ND, NA, NF

  Assert that the value pointed to by the member base register has type T.
  This is similar to a CheckMBase except that it does not imply a runtime check
  and cannot cause control flow.

  These instructions convert either a Cell or a Str to a primitive type (Bool,
  Int, Dbl) and return the resulting value. They may throw an exception upon
  failed type coercion. They are encoded along with callee Func, fn, and the
  integer position of the argument, argNum, being coerced.

| CheckInit, ND, S(Gen), B

  If S0's type is Uninit, branch to block B.

| CheckInitMem, ND, S(MemToGen), B

  If the value pointed to by S0 has type Uninit, branch to block B.

| CheckCold<TransID>, ND, NA, B

  Check if the counter associated with translation TransID is cold (i.e. within
  a fixed threshold). If it's not (i.e. such translation has reached the
  "hotness threshold"), then branch to block B.

| CheckRefs<firstBit,mask,vals>, ND, S(Func) S(Int), B

  Perform reffiness guard checks. Operands:

    S0 - function pointer for the frame
    S1 - num params expected in the func
    firstBit - first bit to check, must be a multiple of 64
    mask - mask to check (RefDeps::Record::m_mask entries)
    vals - values to check (RefDeps::Record::m_vals entries)

  If any of the checks fail, branch to block B.

| EndGuards, ND, NA, NF

  A no-op at runtime, this instruction serves to mark the end of the initial
  sequence of guards in a trace.

| CheckNonNull, DSubtract(0, Nullptr), S(Nullptr,Func,PtrToGen,TCA,Cls,Ctx,Str), B

  If the value in S0 is Nullptr, branch to block B. If S0 cannot be Nullptr, or
  always is Nullptr, this check may be optimized away.

| AssertNonNull, DSubtract(0, Nullptr), S(Nullptr,StaticStr,Func,ArrLike), P

  Returns S0, with Nullptr removed from its type. This instruction currently
  supports a very limited range of types but can be expanded if needed.

| AssertARFunc<spOff>, ND, S(StkPtr) S(Func), NF

  Asserts that the ActRec at offset spOff from S0 contains function S1.

| CheckFuncMMNonMagic, D(Func), S(FuncMM), B|P

  Check that S0 is not a func pointer with magic bit set and if so copy it
  to D, and fallthrough. If S0 has a magic bit set, branch to block B.

| CheckSmashableClass, ND, S(Smashable) S(Cls), B

  If the lower 32 bits of S0 does not match class pointer S1, branch to block B.

2. Arithmetic

| AddInt, D(Int), S(Int) S(Int), NF

| SubInt, D(Int), S(Int) S(Int), NF

| MulInt, D(Int), S(Int) S(Int), NF

| AddIntO, D(Int), S(Int) S(Int), B

| SubIntO, D(Int), S(Int) S(Int), B

| MulIntO, D(Int), S(Int) S(Int), B

| AddDbl, D(Dbl), S(Dbl) S(Dbl), NF

| SubDbl, D(Dbl), S(Dbl) S(Dbl), NF

| MulDbl, D(Dbl), S(Dbl) S(Dbl), NF

| DivDbl, D(Dbl), S(Dbl) S(Dbl), NF

| DivInt, D(Int), S(Int) S(Int), NF

| Floor, D(Dbl), S(Dbl), NF

| Ceil, D(Dbl), S(Dbl), NF

| AbsDbl, D(Dbl), S(Dbl), NF

| Sqrt, D(Dbl), S(Dbl), NF

| AndInt, D(Int), S(Int) S(Int), NF

| OrInt, D(Int), S(Int) S(Int), NF

| XorInt, D(Int), S(Int) S(Int), NF

| Shl, D(Int), S(Int) S(Int), NF

| Shr, D(Int), S(Int) S(Int), NF

| Lshr, D(Int), S(Int) S(Int), NF

  Double arithmetic, integer arithmetic, and integer bitwise operations.
  Performs the operation described by the opcode name on S0 and S1, and puts
  the result in D.

  Undefined behavior occurs if Mod is given a divisor of zero, or if the
  divisor is -1 and the dividend is the minimum representable integer.

  AbsDbl computes the absolute value of a double-precision value.

  DivDbl conforms to IEEE 754. In particular, division by zero returns +/- INF
  or NAN depending on the dividend; and should the result of a division be zero
  the sign will follow the normal sign rules for division.

  DivInt will perform integer division of S1 by S0. S0 should not be zero and
  must divide S1.

  Note that Shr is an arithmetic right shift: The MSB is sign-extended.

  Lshr is logical right shift.

  Floor and Ceil will return an integral value not greater, or not less
  than their input respectively. Their use requires SSE 4.1, availability
  should be checked before they are emitted.

  AddIntO, SubIntO, MulIntO perform integer arithmetic on S0 and S1, but will
  branch to block B on integer overflow.

| XorBool, D(Bool), S(Bool) S(Bool), NF

  Logical XOR of the two sources. (Note that && and || do not have
  corresponding opcodes because they're handled at the bytecode level, to
  implement short-circuiting.)

| Mod, D(Int), S(Int) S(Int), NF

  Compute S0 mod S1. If S1 is -1 or 0 the results are undefined.


3. Type conversions

To array conversions:

| ConvBoolToArr,                D(Arr), S(Bool),                         PRc

| ConvDblToArr,                 D(Arr), S(Dbl),                          PRc

| ConvIntToArr,                 D(Arr), S(Int),                          PRc

| ConvObjToArr,                 D(Arr), S(Obj),                   PRc|CRc

| ConvStrToArr,                 D(Arr), S(Str),                      PRc|CRc

| ConvVecToArr,                 D(Arr), S(Vec),                      PRc|CRc

| ConvDictToArr,                D(Arr), S(Dict),                  PRc|CRc

| ConvShapeToArr,               D(Arr), S(Shape),                 PRc|CRc

| ConvKeysetToArr,              D(Arr), S(Keyset),                PRc|CRc

| ConvCellToArr,                D(Arr), S(Cell),                  PRc|CRc


| ConvArrToNonDVArr,            D(Arr), S(Arr),                      PRc|CRc


To vec conversions:

| ConvArrToVec,                 D(Vec), S(Arr),                   PRc|CRc

| ConvDictToVec,                D(Vec), S(Dict),                     PRc|CRc

| ConvShapeToVec,               D(Vec), S(Shape),                    PRc|CRc

| ConvKeysetToVec,              D(Vec), S(Keyset),                   PRc|CRc

| ConvObjToVec,                 D(Vec), S(Obj),                   PRc|CRc


To dict conversions:

| ConvArrToDict,                D(Dict), S(Arr),                  PRc|CRc

| ConvShapeToDict,              D(Dict), S(Shape),                PRc|CRc

| ConvVecToDict,                D(Dict), S(Vec),                     PRc|CRc

| ConvKeysetToDict,             D(Dict), S(Keyset),                  PRc|CRc

| ConvObjToDict,                D(Dict), S(Obj),                  PRc|CRc


To keyset conversions:

| ConvArrToKeyset,              D(Keyset), S(Arr),                PRc|CRc

| ConvVecToKeyset,              D(Keyset), S(Vec),                PRc|CRc

| ConvDictToKeyset,             D(Keyset), S(Dict),               PRc|CRc

| ConvShapeToKeyset,            D(Keyset), S(Shape),              PRc|CRc

| ConvObjToKeyset,              D(Keyset), S(Obj),                PRc|CRc


To varray conversions:

| ConvArrToVArr,                DArrPacked, S(Arr),                  PRc|CRc

| ConvVecToVArr,                DArrPacked, S(Vec),                  PRc|CRc

| ConvDictToVArr,               DArrPacked, S(Dict),                 PRc|CRc

| ConvShapeToVArr,              DArrPacked, S(Shape),                PRc|CRc

| ConvKeysetToVArr,             DArrPacked, S(Keyset),               PRc|CRc

| ConvObjToVArr,                DArrPacked, S(Obj),               PRc|CRc


To darray conversion:

| ConvArrToDArr,                DArrMixed, S(Arr),                   PRc|CRc

| ConvVecToDArr,                DArrMixed, S(Vec),                   PRc|CRc

| ConvDictToDArr,               DArrMixed, S(Dict),               PRc|CRc

| ConvShapeToDArr,              DArrMixed, S(Shape),              PRc|CRc

| ConvKeysetToDArr,             DArrMixed, S(Keyset),             PRc|CRc

| ConvObjToDArr,                DArrMixed, S(Obj),                PRc|CRc


To bool conversions:

| ConvArrToBool,               D(Bool), S(Arr),                           NF

| ConvDblToBool,               D(Bool), S(Dbl),                           NF

| ConvIntToBool,               D(Bool), S(Int),                           NF

| ConvStrToBool,               D(Bool), S(Str),                           NF

| ConvObjToBool,               D(Bool), S(Obj),                           NF

| ConvCellToBool,              D(Bool), S(Cell),                          NF


To double conversions:

| ConvArrToDbl,                 D(Dbl), S(Arr),                           NF

| ConvBoolToDbl,                D(Dbl), S(Bool),                          NF

| ConvIntToDbl,                 D(Dbl), S(Int),                           NF

| ConvObjToDbl,                 D(Dbl), S(Obj),                           NF

| ConvStrToDbl,                 D(Dbl), S(Str),                           NF

| ConvResToDbl,                 D(Dbl), S(Res),                           NF

| ConvCellToDbl,                D(Dbl), S(Cell),                          NF


To int conversions:

| ConvBoolToInt,                D(Int), S(Bool),                          NF

| ConvDblToInt,                 D(Int), S(Dbl),                           NF

| ConvObjToInt,                 D(Int), S(Obj),                           NF

| ConvStrToInt,                 D(Int), S(Str),                           NF

| ConvResToInt,                 D(Int), S(Res),                           NF

| ConvCellToInt,                D(Int), S(Cell),                          NF


To object conversions:

| ConvCellToObj, D(Obj), S(Cell), CRc|PRc


To string conversions:

| ConvDblToStr,                 D(Str), S(Dbl),                          PRc

| ConvIntToStr,                 D(Str), S(Int),                          PRc

| ConvObjToStr,                 D(Str), S(Obj),                          PRc

| ConvResToStr,                 D(Str), S(Res),                          PRc

| ConvCellToStr,                D(Str), S(Cell),                         PRc


  All the above opcodes convert S0 from its current type to the destination
  type, according to the PHP semantics of such a conversion.

| DblAsBits,                    D(Int), S(Dbl),                           NF

  Reinterpret a double as an integer with the same bit pattern.

| ConvClsToCctx, D(Cctx), S(Cls), NF

  Convert a class to a class context (i.e. the class with a 1 or'd into the low
  bit).

| OrdStr,                       D(Int), S(Str),                           NF

  Convert the first byte in a string to an unsigned integer.
  Intended as an optimization for ord($str)

| OrdStrIdx,                    D(Int), S(Str) S(Int),                    NF

  Convert the character at position S1 in base string S0 to an unsigned
  integer.  Raises a notice if the position is out of bounds.
  Intended as an optimization for ord($str[$idx]).

| ChrInt,                      D(StaticStr), S(Int),                      NF

  Convert the integer S0 to a the one character string with ascii code
  S0 & 255.

| StrictlyIntegerConv,         D(Str|Int), S(Str),                        PRc

  If S0 is a string representing an integer value (same criteria as array key
  conversion), return that value as an integer. Otherwise return S0.

| ConvPtrToLval,               DLvalOfPtr, S(PtrToGen),                   NF

  Convert S0 to an equivalent lval.


4. Boolean predicates

| GtInt,                       D(Bool), S(Int) S(Int),                    NF

| GteInt,                      D(Bool), S(Int) S(Int),                    NF

| LtInt,                       D(Bool), S(Int) S(Int),                    NF

| LteInt,                      D(Bool), S(Int) S(Int),                    NF

| EqInt,                       D(Bool), S(Int) S(Int),                    NF

| NeqInt,                      D(Bool), S(Int) S(Int),                    NF

| CmpInt,                      D(Int),  S(Int) S(Int),                    NF

  Perform 64-bit integer comparisons.

| GtDbl,                       D(Bool), S(Dbl) S(Dbl),                    NF

| GteDbl,                      D(Bool), S(Dbl) S(Dbl),                    NF

| LtDbl,                       D(Bool), S(Dbl) S(Dbl),                    NF

| LteDbl,                      D(Bool), S(Dbl) S(Dbl),                    NF

| EqDbl,                       D(Bool), S(Dbl) S(Dbl),                    NF

| NeqDbl,                      D(Bool), S(Dbl) S(Dbl),                    NF

| CmpDbl,                      D(Int),  S(Dbl) S(Dbl),                    NF

  Perform comparisons of doubles. Comparisons that are unordered according to
  IEEE 754 (such as when at least one operand is NaN) result in false.

| GtStr,                       D(Bool), S(Str) S(Str),                    NF

| GteStr,                      D(Bool), S(Str) S(Str),                    NF

| LtStr,                       D(Bool), S(Str) S(Str),                    NF

| LteStr,                      D(Bool), S(Str) S(Str),                    NF

| EqStr,                       D(Bool), S(Str) S(Str),                    NF

| NeqStr,                      D(Bool), S(Str) S(Str),                    NF

| SameStr,                     D(Bool), S(Str) S(Str),                    NF

| NSameStr,                    D(Bool), S(Str) S(Str),                    NF

| CmpStr,                      D(Int),  S(Str) S(Str),                    NF

  Performs comparison of strings using PHP semantics.

| GtStrInt,                    D(Bool), S(Str) S(Int),                    NF

| GteStrInt,                   D(Bool), S(Str) S(Int),                    NF

| LtStrInt,                    D(Bool), S(Str) S(Int),                    NF

| LteStrInt,                   D(Bool), S(Str) S(Int),                    NF

| EqStrInt,                    D(Bool), S(Str) S(Int),                    NF

| NeqStrInt,                   D(Bool), S(Str) S(Int),                    NF

| CmpStrInt,                   D(Int),  S(Str) S(Int),                    NF

  Performs comparison of strings with integers using PHP semantics.

| GtBool,                      D(Bool), S(Bool) S(Bool),                  NF

| GteBool,                     D(Bool), S(Bool) S(Bool),                  NF

| LtBool,                      D(Bool), S(Bool) S(Bool),                  NF

| LteBool,                     D(Bool), S(Bool) S(Bool),                  NF

| EqBool,                      D(Bool), S(Bool) S(Bool),                  NF

| NeqBool,                     D(Bool), S(Bool) S(Bool),                  NF

| CmpBool,                     D(Int),  S(Bool) S(Bool),                  NF

  Performs comparison of booleans.

| GtObj,                       D(Bool), S(Obj) S(Obj),                    NF

| GteObj,                      D(Bool), S(Obj) S(Obj),                    NF

| LtObj,                       D(Bool), S(Obj) S(Obj),                    NF

| LteObj,                      D(Bool), S(Obj) S(Obj),                    NF

| EqObj,                       D(Bool), S(Obj) S(Obj),                    NF

| NeqObj,                      D(Bool), S(Obj) S(Obj),                    NF

| SameObj,                     D(Bool), S(Obj) S(Obj),                    NF

| NSameObj,                    D(Bool), S(Obj) S(Obj),                    NF

| CmpObj,                      D(Int),  S(Obj) S(Obj),                    NF

  Perform comparison of objects using PHP semantics. All versions except for
  SameObj and NSameObj may re-enter the VM and therefore may throw
  exceptions. SameObj and NSameObj never re-enter or throw.

| GtArr,                       D(Bool), S(Arr) S(Arr),                    NF

| GteArr,                      D(Bool), S(Arr) S(Arr),                    NF

| LtArr,                       D(Bool), S(Arr) S(Arr),                    NF

| LteArr,                      D(Bool), S(Arr) S(Arr),                    NF

| EqArr,                       D(Bool), S(Arr) S(Arr),                    NF

| NeqArr,                      D(Bool), S(Arr) S(Arr),                    NF

| SameArr,                     D(Bool), S(Arr) S(Arr),                    NF

| NSameArr,                    D(Bool), S(Arr) S(Arr),                    NF

| CmpArr,                      D(Int),  S(Arr) S(Arr),                    NF

  Perform comparison of arrays using PHP semantics. All versions except for
  SameArr and NSameArr may re-enter the VM and therefore may throw
  exceptions. SameArr and NSameArr never re-enter or throw.

| GtShape,                     D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| GteShape,                    D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| LtShape,                     D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| LteShape,                    D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| EqShape,                     D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| NeqShape,                    D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| SameShape,                   D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| NSameShape,                  D(Bool), S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

| CmpShape,                    D(Int),  S(Shape,Arr,Dict) S(Shape,Arr,Dict), NF

  Perform comparison of Shapes using PHP semantics. All versions except for
  SameShape and NSameShape may re-enter the VM and therefore may throw
  exceptions. SameShape and NSameShape never re-enter or throw.

| GtVec,                       D(Bool), S(Vec) S(Vec),                    NF

| GteVec,                      D(Bool), S(Vec) S(Vec),                    NF

| LtVec,                       D(Bool), S(Vec) S(Vec),                    NF

| LteVec,                      D(Bool), S(Vec) S(Vec),                    NF

| EqVec,                       D(Bool), S(Vec) S(Vec),                    NF

| NeqVec,                      D(Bool), S(Vec) S(Vec),                    NF

| SameVec,                     D(Bool), S(Vec) S(Vec),                    NF

| NSameVec,                    D(Bool), S(Vec) S(Vec),                    NF

| CmpVec,                      D(Int),  S(Vec) S(Vec),                    NF

  Perform comparison of vecs. All versions except for SameVec and NSameVec may
  re-enter the VM and therefore may throw exceptions. SameVec and NSameVec
  never re-enter or throw.

| EqDict,                      D(Bool), S(Dict) S(Dict),                  NF

| NeqDict,                     D(Bool), S(Dict) S(Dict),                  NF

| SameDict,                    D(Bool), S(Dict) S(Dict),                  NF

| NSameDict,                   D(Bool), S(Dict) S(Dict),                  NF

  Perform comparison of dicts. EqDict and NeqDict may re-enter the VM and
  therefore may throw exceptions. SameDict and NSameDict never re-enter or
  throw. Relational comparisons for dicts are not supported.

| EqKeyset,                    D(Bool), S(Keyset) S(Keyset),              NF

| NeqKeyset,                   D(Bool), S(Keyset) S(Keyset),              NF

| SameKeyset,                  D(Bool), S(Keyset) S(Keyset),              NF

| NSameKeyset,                 D(Bool), S(Keyset) S(Keyset),              NF

  Perform comparison of keysets. As keysets can only contain ints and strings,
  comparisons never re-enter or throw. Relational comparisons for keysets are
  not supported.

| GtRes,                       D(Bool), S(Res) S(Res),                    NF

| GteRes,                      D(Bool), S(Res) S(Res),                    NF

| LtRes,                       D(Bool), S(Res) S(Res),                    NF

| LteRes,                      D(Bool), S(Res) S(Res),                    NF

| EqRes,                       D(Bool), S(Res) S(Res),                    NF

| NeqRes,                      D(Bool), S(Res) S(Res),                    NF

| CmpRes,                      D(Int),  S(Res) S(Res),                    NF

  Perform comparison of resources using PHP semantics. Resource comparisons
  never re-enter or throw.

| EqCls,                       D(Bool), S(Cls) S(Cls),                    NF

  Checks if two Class values are equal.

| EqFunc,                      D(Bool), S(Func) S(Func),                  NF

  Checks if two Func values are equal.

| EqStrPtr,                    D(Bool), S(Str) S(Str),                    NF

  Checks if two string values represent the same underlying string. That is,
  that they point at the same underlying storage.

| EqArrayDataPtr,              D(Bool), S(ArrLike) S(ArrLike),            NF

  Checks if the two arguments represent the same underlying ArrayData. That is,
  that they point at the same underlying storage.

| ProfileInstanceCheck, ND, C(StaticStr), NF

  Profile that S0 has been used as the RHS of an instance check.

| InstanceOf, D(Bool), S(Cls) S(Cls|Nullptr), NF

  Sets D based on whether S0 is a descendant of the class, interface, or trait
  in S1. (Note that this is always false for a trait). S1 may be null at
  runtime if the class is not defined.

| InstanceOfIface, D(Bool), S(Cls) CStr, NF

  Fast path for interface checks. Sets D based on whether S0 implements S1, but
  S1 must be a unique interface. This should only be used in repo-authoritative
  mode.

| InstanceOfIfaceVtable<iface>, D(Bool), S(Cls), NF

  Faster path for interface checks. Sets D based on whether S0 implements
  iface, which must be a unique interface with an assigned vtable slot.

| ExtendsClass<cls,strictLikely>, D(Bool), S(Cls), NF

  A fast-path for instanceof checks. Sets D based on whether S0 is a descendant
  of cls, where cls must be a unique class that is not an interface or a trait.

  If strictLikely is true, optimize for the case where S0 is not equal to S1.

| InstanceOfBitmask,           D(Bool), S(Cls) CStr,                      NF

| NInstanceOfBitmask,          D(Bool), S(Cls) CStr,                      NF

  A fast-path for instanceof checks. Sets D based on whether S0 is a descendant
  of the class named by S1, where S1 must have a bit allocated for it in the
  fast instance check bitvector (see class.h).

| InterfaceSupportsArr,        D(Bool), S(Str), NF

| InterfaceSupportsVec,        D(Bool), S(Str), NF

| InterfaceSupportsDict,       D(Bool), S(Str), NF

| InterfaceSupportsKeyset,     D(Bool), S(Str), NF

| InterfaceSupportsStr,        D(Bool), S(Str), NF

| InterfaceSupportsInt,        D(Bool), S(Str), NF

| InterfaceSupportsDbl,        D(Bool), S(Str), NF

  Returns whether t instanceof S0 returns true when t is of the given type.

| ResolveTypeStruct<class,suppress,offset,size,isOrAsOp>,
|   DDArr, S(StkPtr) S(Cls|Nullptr), NF

  Applies class/alias resolution on the type structure that is at the stack
  offset given by S0 and offset. If size > 1, combine the type structures on
  the stack into the first one's denoted holes. Returns a copy.
  S1 is the calling class, used to resolve the this typehint.
  If isOrAsOp is set, raises an error if S0 contains traits, function types or
  typevars.
  If there is an error during type structure resolution, this instruction raises
  an error. If suppress is set, this error is demoted to a warning.

| IsTypeStruct, D(Bool), SDArr S(Cell), NF

  Returns whether S1 matches the type structure of a defined type in S0 and S1
  is a subtype of S0. The input type structure (S0) must be resolved.

| ThrowAsTypeStructException, ND, SDArr S(Cell), T

  Throws an exception indicating why S1 does not match the type structure of a
  defined type in S0 or why S1 is not a subtype of S0. The input type structure
  (S0) must be resolved.

| RaiseErrorOnInvalidIsAsExpressionType, DDArr, SDArr, NF

  Raises an error if the type hint for is/as expression contains an invalid
  type such as callables, erased type variables and trait type hints.
  The input type structure (S0) must be resolved.

| HasToString, D(Bool), S(Obj), NF

  Returns whether the object S0 has a toString method.

| IsType<T>, D(Bool), S(Gen), NF

  Sets D to true iff S0 holds a value that is of type T. T must not be a
  specialized type.

| IsNType<T>, D(Bool), S(Gen), NF

  Sets D to true iff S0 holds a value that is not of type T. T must not be a
  specialized type.

| IsTypeMem<T>, D(Bool), S(PtrToGen), NF

  Sets D to true iff the value referenced by S0 is of type T. T must not be a
  specialized type.

  The value in S0 must not be a pointer into the evaluation stack or frame
  locals.

| IsNTypeMem<T>, D(Bool), S(PtrToGen), NF

  Sets D to true iff the value referenced by S0 is not of type T. T must not be
  a specialized type.

| IsWaitHandle, D(Bool), S(Obj), NF

  Sets D to true iff S0 is a subclass of WaitHandle.

| IsCol, D(Bool), S(Obj), NF

  Sets D to true iff S0 is a collection.

| IsDVArray, D(Bool), S(Arr), NF

  Sets D to true iff S0 is a darray or varray.

5. Branches

| JmpZero,                          ND, S(Int,Bool),                     B

| JmpNZero,                         ND, S(Int,Bool),                     B

  Conditionally jump to based on S0.

| JmpSSwitchDest, ND, S(TCA) S(StkPtr) S(FramePtr), T

  Jump to the target of a sswitch statement, leaving the region, where the
  target TCA is S0.

| JmpSwitchDest, ND, S(Int) S(StkPtr) S(FramePtr), T

  Jump to the target of a switch statement, leaving the region, using table
  metadata <JmpSwitchData> and index S0, which must be a valid index in the
  jump table.

| ProfileSwitchDest<handle,nCases>, ND, S(Int), NF

  Profile a switch statement target.

| CheckSurpriseFlags, ND, S(FramePtr,StkPtr), B

  Tests the implementation-specific surprise flags. If they're true, branches
  to block B. This is done by comparing an evaluation stack pointer to the RDS
  stackLimitAndSurprise word. Note that in a resumed, the frame pointer is not
  pointing into the eval stack, so S0 should be a StkPtr in that case.

| HandleRequestSurprise, ND, NA, NF

  Generate exceptions based on surprise flags on a per request basis.
  Make sure CheckSurpriseFlags is true before calling HandleRequestSurprise.

| ReturnHook, ND, S(FramePtr) S(Gen), NF

  Surprise flag hook for function returns.

| SuspendHookAwaitEF, ND, S(FramePtr) S(FramePtr) S(Obj), NF

  Surprise flag hook for suspending eagerly executing async functions. The S0
  frame was already teleported into S1. Decrefs S2 if it throws an exception.

| SuspendHookAwaitEG, ND, S(FramePtr) S(Obj), NF

  Surprise flag hook for suspending eagerly executing async generators. The S0
  frame has an associated AG, which is already linked to the newly constructed
  AGWH in the blocked state. Decrefs S1 if it throws an exception.

| SuspendHookAwaitR, ND, S(FramePtr) S(Obj), NF

  Surprise flag hook for suspending async functions and async generators resumed
  at Await. The S0 frame has an associated AFWH/AGWH still in the running state,
  S1 points to the child WH we are going to block on.

| SuspendHookCreateCont, ND, S(FramePtr) S(FramePtr) S(Obj), NF

  Surprise flag hook for suspending generators and async generators during their
  invocation. The S0 frame was already teleported into S1. Decrefs S2 if it
  throws an exception.

| SuspendHookYield, ND, S(FramePtr), NF

  Surprise flag hook for suspending generators and async generators at Yield.

| Unreachable<AssertReason>, ND, NA, T

  Indicates an unreachable code path. Any instructions that are post-dominated
  by an Unreachable may be treated as unreachable by the optimizer, and the
  behavior of a program that attempts to execute an Unreachable is undefined.

| EndBlock<AssertReason>, ND, NA, T

  Halt execution, without implying anything about the reachability of
  instructions preceding this. Intended for use in internal tests or other code
  not meant to be executed.

| Jmp, ND, SVar(Top), B|T

  Unconditional jump to block B. In the second form, the target block must
  start with a DefLabel with the same number of destinations as Jmp's number of
  sources. Jmp parallel-copies its sources to the DefLabel destinations.

| DefLabel, DMulti, NA, NF

  DefLabel defines variables received from a previous Jmp. A DefLabel with zero
  destinations is a no-op, and the predecessor blocks may not necessarily end
  in Jmp. A DefLabel with one or more destinations may only be reached by a Jmp
  instruction with the same number of sources. Ordinary branch instructions may
  not pass values to a DefLabel.

| Select, DUnion(1,2), S(Bool,Int) S(Top) S(Top), NF

  If S0 is true/non-zero, return S1, otherwise return S2.


6. Reference manipulation

| Box, D(BoxedInitCell), S(Cell), CRc|PRc

  Box S0 and put the resulting BoxedInitCell in D. If S0 is Uninit, then
  InitNull will be boxed instead.

| UnboxPtr, DUnboxPtr, S(MemToGen), NF

  If S0 points to a cell that is KindOfRef, dereference the pointer in the
  TypedValue and return a pointer to the inner-cell in D.

| BoxPtr, DBoxPtr, S(MemToGen), NF

  Boxes the TypeValue that S0 points to if it is not boxed. The result D points
  to the same TypedValue as S0 but has a more refined type.

  S0 may not already point into a RefData (due to VM invariants), although the
  IR type system does not enforce it.


7. Loads

| LdStk<T,offset>, DParamMayRelax(Gen), S(StkPtr), NF

  Loads from S0 at offset (in cells), and puts the value in D as type T.

| LdLoc<T,localId>, DParamMayRelax(Gen), S(FramePtr), NF

  Loads local slot localId from the frame S0 and puts the value in D as type T.

| LdLocPseudoMain<T,localId>, DParam(Gen), S(FramePtr), B

  Loads local number localId from frame S0 and puts the value in D if the
  local's type is a subtype of T. If the local's type is not a subtype of T,
  then the load does not happen, and this instruction branches to B. This
  instruction is used for loading locals in pseudo-mains, where they can alias
  globals.

| LdClsRefCls<T,slot>, DParamMayRelax(Cls), S(FramePtr), NF

  Loads class-ref's cls from slot `slot` in frame S0 and puts the value in D
  as type T. T must be a sub-type of TCls.

| LdClsRefTS<slot>, DVArrOrNull, S(FramePtr), NF

  Loads class-ref's reified generics from slot `slot` in frame S0 and puts the
  value in D.

| LdStkAddr<T,offset>, D(PtrToStkGen), S(StkPtr), NF

  Loads the address of the stack slot given by the pointer in S0 at the offset
  (in cells). T must be a subtype of PtrToStkGen.

| LdLocAddr<localId>, D(PtrToFrameGen), S(FramePtr), NF

  Loads the address of the local slot localId from the frame S0 into D.

| LdRDSAddr<T,RDSHandle>, DParam(PtrToGen), NA, NF

  Load the address of a Gen that lives at the specified RDS handle. The type
  param must be a subtype of PtrToGen.

| LdInitRDSAddr<T,RDSHandle>, DParam(PtrToInitGen), NA, B

  Load the address of a Gen that lives at the specified RDS handle. Branch if
  the value at that address is Uninit. The type param must be a subtype of
  PtrToInitGen.

| LdVectorBase, D(PtrToMembCell), S(Obj), NF

| LdPairBase, D(PtrToMembCell), S(Obj), NF

  Loads the base pointer to an array of Cells from the given collection
  instance in S0.

| LdMem<T>, DParam(Gen), S(MemToGen), NF

  Loads from S0 and puts the value in D.

| LdContField<T>, DParam(Gen), S(Obj) C(Int), NF

  Loads a property from the object referenced by S0 at the offset given by S1
  and puts the value in D. S0 must be a Generator.

| LdElem, D(Cell), S(PtrToCell) S(Int), NF

  Loads the element at index S1 from the base pointer in S0. The index in S1 is
  the number of bytes from the base in S0.

| LdColVec, D(Vec), S(Obj), NF

  Load the vec array backing a collection instance in S0, which must be a
  Vector or ImmVector, and that specific object type must be known at compile
  time.

| LdColDict, D(Dict), S(Obj), NF

  Load the dict array backing a collection instance in S0, which must be a
  Map, Set, ImmMap, or ImmSet, and that specific object type must be known at
  compile time.

| CheckRefInner<T>, ND, S(BoxedCell), B

  TODO(#2939547): this should take BoxedInitCell

  Check that the inner type of the boxed cell in S0 is T, and if not take the
  branch to B.

| LdRef<T>, DParam(Cell), S(BoxedCell), NF

  TODO(#2939547): this should take BoxedInitCell

  Loads the value held in the box referenced by S0 and puts the value in D. The
  inner type of S0 must be a subtype of T (usually ensured with a previous
  CheckRefInner).

| LdCtx, DCtx, S(FramePtr), NF

  Loads into D the value of the m_this/m_cls field out of the frame pointer S0,
  which must be a frame for the function in the LdCtx's marker. The result
  could be either an object representing the this pointer or a class context.

| LdCctx, DCtx, S(FramePtr), NF

  Loads into D the value of the m_cls field out of the frame pointer S0. The
  compiler should generate this only if it can prove that the frame does not
  contain a nullptr or $this pointer.

| LdClosure<T>, DParam(Ctx), S(FramePtr), NF

  Loads into D the value of the m_this/m_cls field out of the frame pointer S0.
  The compiler should generate this only if it can prove that the frame context
  is a closure object of type T.  Unlike LdCtx and LdCctx, there are no special
  rules about the relative positions of LdClosure and InitCtx instructions.

| CheckCtxThis, ND, S(Ctx), B

  Check that the context (m_this or m_cls) in S0 is a non-null $this
  pointer. If not, branch to B.

| LdClsCtx, DCtxCls, S(Ctx), NF

  Loads into D the class representing the context in S0, which can be either
  the this pointer or the context class.

| LdClsCctx, DCtxCls, S(Cctx), NF

  Loads into D the class representing the context in S0, which is a context
  class.

| LdClsCtor, D(Func), S(Cls) S(FramePtr), NF

  Loads into D the constructor of class S0. If the constructor cannot be called
  from the context in S1, raise an error.

| LdFuncMFunc, D(Func), S(FuncM), NF

  Loads into D the func pointer for the func pointer with magic bit set in S0.

| LdSmashable, D(Smashable), NA, NF

  Loads a smashable value. The initial value is set to (1 << addr) + 1, where
  addr is a pointer pointing to the value in TC. The lowest bit is set for
  convenience of checking whether the value was already smashed.

| LdSmashableFunc, D(Func), S(Smashable), NF

  Loads into D the func pointer stored in the higher 32 bits of S0.

| LdRecCached, D(RecType), CStr, NF

  Loads the record named S0 via the RDS. Invokes autoload and may raise an error
  if the record is not defined.

| DefCls, D(Cls), S(Int), NF

  Define the class corresponding to PreClass S0 in the current unit.

| DefConst<T>, DParam(Top), NA, NF

  Define a constant value of type T. D is presumed to be globally available and
  the DefConst instruction will not actually appear in the IR instruction
  stream.

| Conjure<T>, DParam(Top), NA, NF

  Define a value of type T. This instruction aborts at runtime; it is meant to
  be used in tests or code that is known to be unreachable.

| ConjureUse, ND, S(Gen), NF

  Define a "use" of S0 effectively keeping the value alive. As with Conjure it
  should not appear in reachable code.

| LdCls, D(Cls), S(Str) C(Cls), NF

  Loads the class named S0 in the context of the class S1. Invokes autoload and
  may raise an error if the class is not defined. The explicit context
  parameter allows the compiler to simplify this instruction to a DefConst in
  some cases. If S0 is constant, this instruction may be simplified to a
  LdClsCached.

| LdClsCached, D(Cls), CStr, NF

  Loads the class named S0 via the RDS. Invokes autoload and may raise an error
  if the class is not defined.

| LdClsCachedSafe, D(Cls), CStr, B

  Loads the class whose name is S0 out of the RDS. If the class is not defined,
  branch to B.

| LdClsInitData, D(PtrToClsInitCell), S(Cls), NF

  Loads the pointer to the property initializer array for class S0.

| LookupClsRDS, D(Cls|Nullptr), S(Str), NF

  Lookup the cached-class RDS handle for a given class name. Dereference that
  handle and return the associated Class, or null if not present.

| LdCns, DCns, CStr, B

  Load the constant named S0, branching to B if isn't present.

| LookupCnsE<T,constName>,  DCns, CStr, PRc

  Load a constant via the RDS. Raises a fatal error if it cannot define the
  constant.  This should only be executed if LdCns on the same constant has
  failed.

| LdClsCns<className,constantName>, D(PtrToGen), NA, B

  Load the address of the constant 'constantName' for the class 'className' in
  RDS. If not initialized, branch to B.

| LdSubClsCns<constantName,slot>, D(PtrToGen), S(Cls), NF

  Load the address of the constant 'constantName' for the class S0. The
  constant is known to be in the given slot. If the returned TypedValue is not
  UncountedInit, its value should not be used, and a fallback method should be
  called.

| LdSubClsCnsClsName<constantName,slot>, D(StaticStr|Nullptr), S(Cls), NF

  Loads the name of the class pointed by the constant 'constantName' for the
  class S0. The constant is known to be in the given slot. Returns nullptr if
  constant is abstract, not type constant or does not point to a class.

| CheckSubClsCns<constantName,slot>, ND, S(Cls), B

  Check that the constant 'constantName' lives in the given slot for the class
  S0, and branch if not. S0 must have at least slot+1 constants.

| LdClsCnsVecLen, D(Int), S(Cls), NF

  Load the size of S0's constant table.

| LdTypeCns, DStaticDArr, S(InitCell), B

  Loads the resolved type constant S0 or branches to B if S0 is not resolved or
  not a type constant.

| LdClsTypeCns, DStaticDArr, S(Cls) S(Str), NF

  Loads type constant S1 of class S0 or raises an error if no such constant
  could be found, or if S0::S1 is not a type constant.

| LdClsTypeCnsClsName, D(StaticStr), S(Cls) S(Str), NF

  Loads the name of the class pointed by the type constant S1 of class S0 or
  raises an error if no such constant could be found, or if S0::S1 is not a
  type constant.

| ProfileSubClsCns<constantName,handle>, D(PtrToGen), S(Cls), NF

  Load the address of the constant 'constantName' for the class S0, profiling
  the observed slots. If the returned TypedValue is not UncountedInit, its
  value should not be used, and a fallback method should be called.

| LdClsMethodFCacheFunc<clsName,methodName>, D(Func), NA, B

  Loads the target cache entry for a forwarding call to clsName::methodName.
  If the method does not exist, or the cache hasn't been filled yet, branch to
  B.

| LookupClsMethodFCache<clsName,methodName>,
|    D(Func|Nullptr), C(Cls) S(FramePtr),
|    NF

  Lookup clsName::methodName in the forwarding class method cache. S0 should be
  the Class named by clsName and S1 should be the current vm frame pointer. May
  return Nullptr if lookup fails using a subset of the required lookup paths,
  indicating that a more complete lookup path should be taken. May throw if the
  method does not exist.

| FwdCtxStaticCall, D(Cctx), S(Ctx), NF

  If S0 is an object, this opcode returns S0's class with the low bit set
  (i.e., as a Cctx). Otherwise this instruction returns S0.

| LdClsMethodCacheFunc<clsName,methodName>, D(Func), NA, B

  Loads the target cache entry for the method clsName::methodName. If the
  method does not exist or the cache hasn't been filled yet, branch to B.

| LdClsMethodCacheCls<clsName,methodName>, D(Cctx), NA, NF

  Loads the target cache class context entry for a call to clsName::methodName
  from the current context. This instruction must only be used when the value
  is known to not be empty (i.e., LdClsMethodCacheFunc must have succeeded, or
  LookupClsMethodCache returned a non-null value).

| LookupClsMethodCache<clsName,methodName>, D(Func|Nullptr),
|                                           S(FramePtr),
|                                           NF

  Lookup a function in the class method targetcache. The class name and method
  name are clsName and methodName, respectively. S0 is the current vm frame
  pointer. Returns Nullptr if the method cannot be found using a subset of the
  required lookup paths, indicating that a more complete lookup path should be
  taken. May throw if the method does not exist.

| LdIfaceMethod<vtableIdx,methodIdx>, D(Func), S(Cls), NF

  Load the Func* at methodIdx from the vtable at vtableIdx in S0.

| LdFuncVecLen, D(Int), S(Cls,Cctx), NF

  Load the funcVecLen field from S0.

| LdClsMethod, D(Func), S(Cls,Cctx) C(Int), NF

  Load a Func* off of the class method table for S0, at offset S1 (in method
  slots).

| LookupClsMethod<calleeAROffset,forward,dynamic>,
|   D(Func),
|   S(Cls) S(Str) S(StkPtr) S(FramePtr),
|   NF

  Store a pointer to a class method into an activation record. S0 points to the
  class, S1 is the method name, S2 is a stack pointer that has an activation
  record to modify at `spToActRecOffset', and S3 is a pointer to the current
  frame (used to get the context). `forward` indicates if we should forward the
  current context. `dynamic` indicates if the method is called dynamically.
  Also perform caller checks (dynamic call, rx). May throw or fatal if method
  is not accessible or caller checks have failed.

| LdPropAddr<T,offset>, DParam(LvalToPropGen), S(Obj), NF

  Load the address of the object property for S0 + `offset' (in bytes).  T must
  be a subtype of PtrToPropGen.

| LdInitPropAddr<T,offset>, DParam(LvalToPropGen), S(Obj), B

  Load the address of the object property for S0 + `offset' (in bytes). Branch
  if the value at that address is Uninit.  T must be a subtype of
  PtrToPropInitGen.

| LdGblAddr, D(PtrToGblGen), S(Str), B

  Loads a pointer to a global. S0 is the global's name. Branches to B if the
  global is not defined.

| LdGblAddrDef, D(PtrToGblGen), S(Str), NF

  Loads a pointer to a global. S0 is the global's name. Defines the global if
  it is not already defined.

| LdClsPropAddrOrNull, D(PtrToSPropGen|Nullptr),
|                      S(Cls) S(Str) C(Cls) C(Bool),
|                      NF

  Loads a pointer to a static class property. S0 points to the class, S1 is the
  property name, and S2 is the class representing the context of the code
  accessing the property. If class S0 does not have a visible and accessible
  static property named S1, then nullptr is returned. An exception
  will be thrown if the property is marked LateInit and its value is
  Uninit, unless S3 is true.

| LdClsPropAddrOrRaise, D(PtrToSPropGen), S(Cls) S(Str) C(Cls) C(Bool), NF

  Loads a pointer to a static class property. S0 points to the class, S1 is the
  property name, and S2 is the class representing the context of the code
  accessing the property. If class S0 does not have a visible and accessible
  static property named S1, then nullptr is returned. An exception
  will be thrown if the property is marked LateInit and its value is
  Uninit, unless S3 is true.

| LookupSPropSlot, D(Int), S(Cls) S(Str), NF

  Lookup the slot index of the static property with the name S1 on the class
  S0, returning -1 if not found.

| LdObjMethod<methodName>, D(FuncMM), S(Cls) S(Smashable), NF

  Loads a func pointer, maybe with a magic bit set, pointing to the instance
  method that would be called if a `methodName` is invoked on an instance of S0.
  Caches the mapping in the TC cache (using S1) and target cache. Raises a fatal
  if the class does not have an accessible method with the given name and does
  not have a __call method.

| LdObjInvoke, D(Func), S(Cls), B

  Try to load a cached non-static __invoke Func from the Class in S0, or branch
  to block B if it is not present.

| LdArrFuncCtx<offset>, D(Func), S(Arr,Vec) S(StkPtr) S(FramePtr), NF

  Try to load an array as a function context. This is for use translating
  FPushFunc when the callee is an array. This instruction attempts to populate
  a partially created ActRec pointed to by S1 + `offset' (in cells). It is also
  responsible for performing caller checks (dynamic call, rx).

| LdObjClass, DLdObjCls, S(Obj), NF

  Load the class out of the object in S0 and put it in D.

| LdClsName, D(StaticStr), S(Cls), NF

  Load the name of the Class* in S0.

| LdFunc<offset>, D(Func), S(Str) S(StkPtr) S(FramePtr), NF

  Resolve the Func whose name is S0. Perform caller checks (dynamic call, rx).
  Then store the Func into the partially constructed ActRec pointed to by
  S1 + `offset` (in cells). Also populate the m_this/m_cls field if necessary.
  Fatal if the named function is not defined, and the autoloader fails to
  define it.

| LdFuncCached<funcName>, D(Func), NA, NF

  Loads the Func whose name is funcName from the RDS, invoking autoload if it
  not defined yet. Fatal if function autoloader fails to define it.

| LookupFuncCached<funcName>, D(Func), NA, NF

  Loads the Func whose name is given from %1, invoking autoload if it is not
  defined yet. Fatal if the function autoload fails to define it. This
  instruction does not assume the loaded function will be called immediately,
  so it will raise a resolution failure error instead of a call failure error.

| LdARFuncPtr<offset>, DParam(Func), S(StkPtr), NF

  Loads the m_func member of a pre-live ActRec. S0 is the base address, with
  `offset' cells to the ActRec.

| LdARCtx<T,offset>, DParam(Ctx), S(StkPtr), NF

  Loads the m_this/m_cls member of an ActRec. S0 is the base address, with
  `offset' cells to the ActRec.

| LdARNumParams, D(Int), S(FramePtr), NF

  Loads the number of params from an ActRec. S0 is the address of the ActRec

| LdFuncNumParams, D(Int), S(Func), NF

  Returns the value of func->numParams().

| LdFuncName, D(StaticStr), S(Func), NF

  Loads the full name of S0.

| LdStrLen, D(Int), S(Str), NF

  Load the length of the string in S0.

| FuncSupportsAsyncEagerReturn, D(Bool), S(Func), NF

  Tests for Func::m_attrs & AttrSupportsAsyncEagerReturn.

| IsFuncDynCallable, D(Bool), S(Func), NF

  Tests for Func::m_attrs & AttrDynamicallyCallable.

| IsClsDynConstructible, D(Bool), S(Cls), NF

  Tests for Class::m_attrCopy & AttrDynamicallyConstructible.

| LdFuncRxLevel, D(Int), S(Func), NF

  Returns the value of func->rxLevel().

| IsReifiedName, D(Bool), S(Str), NF

  Tests whether the name in S0 is name of a reified class or function.

| LdReifiedGeneric, DVArr, S(Str), NF

  Loads the reified generics associated with the name at S0. This name can be a
  class name or a function name. Raises an error if this name does not have
  any associated reified generics.

| LdClsFromClsMeth, D(Cls), S(ClsMeth), NF

  Load the Class* of the ClsMethDataRef in S0.

| LdFuncFromClsMeth, D(Func), S(ClsMeth), NF

  Load the Func* of the ClsMethDataRef in S0.

8. Allocation

| AllocObj, DAllocObj, S(Cls), PRc

  Allocates a new object of class S1.

| AllocObjReified, DAllocObj, S(Cls) SVArr, PRc

  Allocates a new object of class S1 and sets S2 as the reified generics of this
  class. If this class is not reified, this instruction raises an error.

| InitProps<class>, ND, NA, NF

  Calls the property initializer function (86pinit) for class.  May throw.

| InitSProps<class>, ND, NA, NF

  Calls the static property initializer functions (86sinit and/or 86linit)
  for class. May throw.

| CheckRDSInitialized<RDSHandle>, ND, NA, B

  Check if the RDS entry at the specified handle is initialized, and branches
  if not.

| MarkRDSInitialized<RDSHandle>, ND, NA, NF

  Mark the given RDS entry as being initialized.

| PropTypeRedefineCheck, ND, C(Cls) C(Int), NF

  Check that the specified property at the slot S1 on S0, which redeclares a
  property in the parent, has a declared type equivalent to the parent
  declaration.

| DebugBacktrace, DVArr, S(Int), PRc

  Obtain stack trace by calling the debug_backtrace() method.

| DebugBacktraceFast, D(Res), NA, PRc

  Obtain compact stack trace resource that can be expanded lazily.

| InitThrowableFileAndLine, ND, S(Obj), NF

  Initialize Throwable's file name and line number assuming the stack trace
  was already initialized and the current vmfp() is a built-in.

| NewInstanceRaw<class>, DAllocObj, NA, PRc

  Allocates an instance of class.

| InitObjProps<class>, ND, S(Obj), NF

  Initializes properties of object S0.

| ConstructInstance<class>, DAllocObj, NA, PRc

  Call the custom instance constructor of an extension class.

| ConstructClosure<class>, DAllocObj, NA, PRc

  Call the custom instance constructor of a Closure.

| NewArray, D(Arr), C(Int), PRc

  Allocate a new array with the expected capacity S0.

| NewMixedArray, DArrMixed, C(Int), PRc

  Allocate a new array in mixed mode with the expected capacity S0.

| NewDArray, DArrMixed, C(Int), PRc

  Allocate a new dict-like array with the expected capacity S0.

| NewDictArray, D(Dict), C(Int), PRc

  Allocate a new dict with the expected capacity S0.

| NewKeysetArray<offset,keys>, D(Keyset), S(StkPtr), PRc|CRc

  Allocate a new keyset containing N elements off the stack given by S0, at
  `offset'. This instruction moves the elements off the stack without
  manipulating their reference counts.

| NewLikeArray, D(Arr), S(Arr) C(Int), PRc

  Allocate a new array in the same mode as S0 and with expected capacity S1,
  unless S1 == 0, in which case the capacity is set to S0's size.

| AllocPackedArray<size>, DArrPacked, NA, PRc

  Allocate a new uninitialized packed array with space for size elements in it.
  The array will be initialized with values using either InitPackedLayoutArray
  or InitPackedLayoutArrayLoop.

| AllocVArray<size>, DArrPacked, NA, PRc

  Allocate a new uninitialized vec-like array with space for size elements in
  it.  The array will be initialized with values using either
  InitPackedLayoutArray or InitPackedLayoutArrayLoop.

| AllocVecArray<size>, D(Vec), NA, PRc

  Allocate a new uninitialized vector array with space for size elements in it.
  The array will be initialized with values using either InitPackedLayoutArray
  or InitPackedLayoutArrayLoop.

| InitPackedLayoutArray<index>, ND, S(Arr,Vec) S(Cell), NF

  Store the S1 into the slot at index in array S0. This instruction assumes
  that it doesn't have to incref the value being stored. Used to initialize an
  array allocated with AllocPackedArray or AllocVecArray.

| InitPackedLayoutArrayLoop<offset,size>, ND, S(Arr,Vec) S(StkPtr), CRc

  Move `size' elements from the stack given by S1, at `offset', into the array
  S0.  Assumes that the first element on the stack is the last element in the
  array.  Used to initialize an array allocated with AllocPackedArray or
  AllocVecArray that was too big to use a series of InitPackedLayoutArray
  instructions.

| NewRecord<offset,keys...>, D(Record), S(RecType) S(StkPtr), PRc|CRc

  Allocate a new record, given the type S0 and N immediate keys
  and taking N elements off the stack given by S1, at `offset'.
  This instruction assumes it can take the values from the stack
  without increfing them.

| NewStructArray<offset,keys...>, DArrMixed, S(StkPtr), PRc|CRc

  Allocate a new key/value array, given N immediate keys and taking N elements
  off the stack given by S0, at `offset'. This instruction assumes it can take
  the values from the stack without increfing them.

| NewStructDArray<offset,keys...>, DArrMixed, S(StkPtr), PRc|CRc

  Allocate a new key/value dict-like array, given N immediate keys and taking N
  elements off the stack given by S0, at `offset'. This instruction assumes it
  can take the values from the stack without increfing them.

| NewStructDict<offset,keys...>, D(Dict), S(StkPtr), PRc|CRc

  Allocate a new key/value dict array, given N immediate keys and taking N
  elements off the stack given by S0, at `offset'. This instruction assumes it
  can take the values from the stack without increfing them.

| NewCol<type>, DCol, NA, PRc

  Create an empty new collection of `type'. `type' cannot be Pair.

| NewPair<offset>, DCol, S(Cell) S(Cell), PRc|CRc

  Allocate a new Pair and fill it with the given cells. Ownership of the cells
  is transferred from $1 and $2 to the pair without manipulating the refcounts.

| NewColFromArray<type>, DCol, S(Vec|Dict), PRc|CRc

  Create a collection of `type` from a Vec or Dict kind. `type` cannot be
  Pair. S0 must be vec kind when `type` is Vector or ImmVector, and must be
  dict kind otherwise. Ownership of S0 is transferred from $1 to the
  collection, without manipulating the refcount.

| Clone, DofS(0), S(Obj), PRc

  Allocate an object by cloning S0.

| NewClsMeth, D(ClsMeth), S(Cls) S(Func), NF

  Allocate a new ClsMethDataRef.

9. Call & Return

| SpillFrame<offset,numArgs>,
|   ND,
|   S(StkPtr) S(Func,Nullptr) S(Ctx,Cls,Nullptr) S(Str,Nullptr) S(Bool)
|   S(Arr|Vec,Nullptr),
|   NF

  Operands:

     S0 - caller stack pointer
     S1 - callee Func or nullptr
     S2 - object (for FPushObjMethod*), class (for FPushClsMethod*), context
          (for FPushClsMethodF), or nullptr (for FPushFunc*).
     S3 - invoke name for magic dispatch
     S4 - whether this is a "dynamic" call
     S5 - reified generics type structure list

  Defines the fields for an activation record and writes them to the stack
  pointed to by S0, at `offset'.

| BeginInlining<offset>, ND, S(StkPtr), NF

  Marks the start of an inlined function whose stack resides offset cells below
  the SP. It has no effect other than to hint to optimization passes that at the
  start of the inlined function its stack is dead.

| DefInlineFP<func,callBCOff,retSPOff>, D(FramePtr),
|                                       S(StkPtr) S(FramePtr),
|                                       NF

  Defines a frame pointer for an inlined function.

  `func' is the function being inlined. `callBCOff' points to the caller's
  FCall instruction, `retSPOff' represents what the stack offset should be
  after the FCall instruction in the caller.

  This instruction is primarily used to represent a frame in the IR in a way
  that allows us to eliminate it entirely. When it cannot be eliminated (or if
  it is pushed into an unlikely path) it performs callee-side responsibilities
  for setting up an activation record (i.e. setting the return ip and m_callOff,
  storing the frame pointer into D).

  The caller frame pointer is passed as S1. This is used to keep track of the
  call chain of inlined functions for simplification and dead code elimination.

| InlineReturn<callerFPOff>, ND, S(FramePtr), NF

  Unlinks a frame constructed by DefInlineFP.  `callerFPOff' is the offset of
  the caller's frame pointer relative to S0. Every inline region must contain
  exactly one InlineReturn or InlineReturnNoFrame. Optimization passes which
  attempt to elide DefInlineFP detect "main" blocks within an inlined region as
  those which are dominated by BeginInlining and post-dominated by InlineReturn.

| InlineSuspend<callerFPOff>, ND, S(FramePtr), NF

  Identical to an InlineReturn, but for use when the frame is being suspended in
  a side exit and will be torn down via an InlineReturn in the main trace. The
  behavior of InlineSuspend is identical to inline return, but it allows us to
  preserve the invariant that an inline region has a single InlineReturn for
  every DefInlineFP (while still allowing InlineSuspend in the case of a side
  exit).

| InlineReturnNoFrame<InlineFrameStart>, ND, NA, NF

  Mark the end of an inlined function for which no DefInlineFP was required. The
  primary purpose of this instruction is to mark the result of a SpillFrame as
  dead. InlineFrameStart is the caller FP-relative offset of the start of the
  callee frame. Everything below InlineFrameStart is dead.

| CallUnpack<spOffset,numParams,callOff,funcd,destroyLocals>,
|                       DCall,
|                       S(StkPtr) S(FramePtr),
|                       NF

  Invoke function corresponding to the current FPI with numParams arguments,
  the last of which is an array of the remaining args. Used for FCall with
  unpack. S0+spOffset points to the stack resulting after the ActRec for the
  function and numParams arguments have been pushed. CallUnpack pops the array
  off the stack, pushes the elements of the array as arguments, and invokes the
  function in the ActRec.

| SyncReturnBC<spOffset,callBCOffset>, ND, S(StkPtr) S(FramePtr), NF

  Stores callBCOffset into the frame at spOffset from S0 as the call bytecode
  address and the frame S1 as the return frame.

| Call<offset,numParams,callOff,funcd,destroyLocals>, DCall,
|                                                     S(StkPtr) S(FramePtr),
|                                                     NF

  Transfer control to a callee, based on the pre-live activation record and set
  of args on the stack pointed to by S0 at `offset'. S1 is the current caller
  frame pointer. The `funcd' in the extra data is a Func* for the callee if we
  know the callee statically.

| NativeImpl<func>, ND, S(FramePtr) S(StkPtr), NF

  Execute a call to the native builtin specified by the current function. S0
  and S1 should be the current vmfp and vmsp, respectively.

| CallBuiltin, DBuiltin, S(FramePtr) S(StkPtr) SVar(PtrToGen,Gen,Cls,Nullptr), PRc

  Call builtin function with N arguments. S0 and S1 should be the current vmfp
  and vmsp, respectively.

  The source and destination types correspond to C++ parameter and return types
  as follows:

    C++ type            HHIR type         Position
    -----------------   ---------         --------
    bool                Bool              source, destination
    int64_t             Int               source, destination
    double              Dbl               source, destination
    const String&       PtrToStr          source
    const Array&        PtrToArr          source
    const Object&       PtrToObj          source
    const Variant&      PtrToGen          source
    Variant&            PtrToGen          source (ref param)
    String              {Str|InitNull}    destination
    Array               {Arr|InitNull}    destination
    Object              {Obj|InitNull}    destination
    Variant             {Gen-UninitNull}  destination

| RetCtrl<spOff,suspendingResumed>, ND, S(StkPtr) S(FramePtr) S(Gen), T

  Ensure that S0 + `spOff' (in cells) is stored in rvmsp and that S1's saved
  frame pointer is stored in rvmfp, then return to the saved return address in
  S1.  The return value is S2, which is passed via the rret_*() registers to
  the caller.  The `suspendingResumed' flag indicates when this instruction is
  suspending a resumable rather than performing a normal function return.

| AsyncFuncRet<spOff>, ND, S(StkPtr) S(FramePtr) S(Cell), T

  Return from a resumed async function, assuming no surprise. Ensures that
  S0 + `spOff` (in cells) is stored in rvmsp and that S1 is stored in rvmfp,
  packs return value S2 into registers and calls the `asyncFuncRet` unique
  stub. The stub stores the result into the wait handle associated with the
  frame pointer, marks it as finished, unblocks its parents and if possible,
  directly resumes the first parent (fast path), or a pending fast runnable
  ResumableWaitHandle (slower path). Otherwise, it will exit VM and return
  control to the asio scheduler (slow path). The stack must contain exactly one
  cell containing uninitialized garbage, which will be populated by the stub
  either to pass the return value to the resumed function, or to return null
  to the scheduler.

| AsyncFuncRetSlow<spOff>, ND, S(StkPtr) S(FramePtr) S(Cell), T

  Return from a resumed async function, assuming unknown surprise flag state
  after the previous surprise was handled by executing "return" event hook.
  Calls the `asyncFuncRetSlow` stub, which re-checks the surprise flag and
  transfers control to the AsyncFuncRet if it was clear, or performs the slow
  path of AsyncFuncRet if it was not, without resuming another function, as
  we are not able to call a potential "resume await" event hook from the stub.

| AsyncSwitchFast<spOff>, ND, S(StkPtr) S(FramePtr), T

  Switch control to another ResumableWaitHandle. Ensures that S0 + `spOff`
  (in cells) is stored in rvmsp and that S1 is stored in rvmfp and calls the
  `asyncSwitchCtrl` unique stub, which tries to resume a pending fast runnable
  ResumableWaitHandle (fast path) if possible, otherwise it will exit VM and
  return control to the asio scheduler (slow path). As with AsyncRetFast, the
  stack must contain exactly one cell containing uninitialied garbage.

| LdRetVal<T>, DParam(Gen), S(FramePtr), NF

  Load the return value from the already-returned-from ActRec pointed to by S0
  into the dest.  This is used by NativeImpl.  TODO(#7150575): We want to make
  NativeImpl return a TypedValue in the C++ ABI registers.

| DbgTrashRetVal, ND, S(FramePtr), NF

  For debugging purposes.  Store kTVTrashJITRetVal to the return value slot on
  the activation record pointed to by S0.

| ReleaseVVAndSkip, ND, S(FramePtr), B

  Loads the VarEnv slot off the ActRec pointed to by S0. If it is null, does
  nothing. If it is an ExtraArgs, deallocates the ExtraArgs structure.
  Otherwise it frees the VarEnv and jumps to block B. This instruction may not
  occur in an inlined call.

| GenericRetDecRefs, ND, S(FramePtr), NF

  Does decrefs of all the current function's locals, where S0 is a pointer to
  the relevant activation record. This instruction may not occur in an inlined
  call.


10. Stores

| StMem, ND, S(MemToGen) S(Gen), NF

  Store S1 into the location pointed to by S0.

| StElem, ND, S(PtrToCell) S(Int) S(Cell), NF

  Store S2 into the location given by the index S1 from base pointer S0. The
  index in S1 is the number of bytes from the base in S0.

| StLoc<localId>, ND, S(FramePtr) S(Gen), NF

  Store S1 to local number localId on the frame pointed to by S0.

| StLocPseudoMain<localId>, ND, S(FramePtr) S(Gen), NF

  Behaves just like StLoc, except the hard requirement that it is only emitted
  for pseudo-mains. We don't optimize StGbl the same way as StLoc, as we need
  intraprocedural analysis to know whether the store is truly dead.

| StLocRange<localIds>, ND, S(FramePtr) S(Gen), NF

  Store S1 to the local variables corresponding to localIds, on the frame
  pointed to by S0.

| StClsRefCls<slot>, ND, S(FramePtr) S(Cls), NF

  Store S1 to class-ref's cls slot `slot` on the frame pointed to by S0.

| StClsRefTS<slot>, ND, S(FramePtr) SVArr, NF

  Store S1 to class-ref's reified generic slot `slot` on the frame pointed to
  by S0.

| StRef, ND, S(BoxedCell) S(Cell), NF

  Store the value in S1 into the RefData pointed to by S0. Stores the
  RefData::m_type also.

| StStk<offset>, ND, S(StkPtr) S(Gen), NF

  Store S1 to the stack pointed to by S0, at a given offset (in cells).

| StOutValue<index>, ND, S(FramePtr) S(Gen), NF

  Store S1 in a caller allocated out-value vm stack cell index cells above
  S0 on the stack.

| DbgTrashStk<offset>, ND, S(StkPtr), NF

  For debugging purposes.  Store kTVTrashJITStk to the stack slot pointed to
  by S0, at a given offset (in cells).

| DbgTrashFrame<offset>, ND, S(StkPtr), NF

  For debugging purposes.  Store kTVTrashJITFrame to kNumActRecCells stack
  slots starting at the offset (in cells), and going toward higher memory
  addresses.

| DbgTrashMem, ND, S(MemToGen), NF

  For debugging purposes.  Store kTVTrashJITHeap to a heap slot pointed to by
  S0.

| RecordReifiedGenericsAndGetName, D(StaticStr), SVArr, CRc

  Takes a varray of reified generics from the stack, adds them to the reified
  generics table and returns mangled name used as the key

| RecordReifiedGenericsAndGetTSList, DVArr, SVArr, CRc

  Takes a varray of reified generics from the stack and adds them to the reified
  generics table and returns the input varray of reified generics, possibly
  static

| MangleReifiedName, D(StaticStr), S(StaticStr) S(StaticStr), NF

  Mangles the name from S0 with the mangled type structure string from S1


11. Trace exits

| EagerSyncVMRegs, ND, S(FramePtr) S(StkPtr), NF

  Sync the given vmfp and vmsp to their in-memory locations.

| ReqBindJmp<bcOff,transFlags>, ND, S(StkPtr) S(FramePtr), T

  Emit a jump to a REQ_BIND_JMP service request to the target offset bcOff.

| ReqRetranslate<transFlags>, ND, S(StkPtr) S(FramePtr), T

  Emit a jump to a service request that will chain to a retranslation of this
  tracelet.

  This instruction is used in exit traces for a type prediction that occurs at
  the first bytecode offset of a tracelet.

| ReqRetranslateOpt<transId,bcOff>, ND, S(StkPtr) S(FramePtr), T

  Emit a service request to retranslate, with a higher optimization gear,
  translation transID, which starts at bcOff. This instruction is used in exit
  traces that trigger profile-guided optimizations.


12. Refcounting and copies

| Mov, DofS(0), S(Top), P

  Defines D as S0. May imply register-to-register moves at code generation
  time. Does not imply an incref or any other manipulation of S0.

| IncRef, ND, S(Gen,Ctx), NF

  If S0 is a refcounted type, increment its refcount.

| DecRef<locId>, ND, S(Gen,Ctx), CRc

  Decrease the reference count of S0 by one, and call a destructor for types
  that require it if it goes to zero.

  Note that although DecRef takes a Gen, we don't allow it to use information
  about the inner types of a BoxedCell. This is because we don't guard on the
  inner types of a BoxedCell except when doing LdRef. For any S0 that is a
  strict subtype of BoxedCell, the DecRef must just decref it as if it were a
  BoxedCell.

  The locId is just a hint to the runtime indicating which local variable is
  being DecRef'd, if any.

| DecRefNZ, ND, S(Gen,Ctx), CRc

  Decrease the reference count of S0 by one, do not check if it goes to zero.
  This instruction can be used for more efficient code when it is provable that
  the reference count cannot go to zero.


13. Misc

| DefFP, D(FramePtr), NA, NF

  Creates a temporary D representing the current vm frame pointer.

| DefSP<stackOff>, D(StkPtr), S(FramePtr), NF

  Creates a temporary D representing the current vm stack pointer. S0 is a
  pointer to the current frame. The 'stackOff' is the logical offset between S0
  and the stack pointer, but in the case of generators this is not the
  physical offset at runtime.

  This instruction is used at the beginning of tracelets to represent the state
  of the stack on entry and does not emit code.

| FuncGuard<func,prologueAddrPtr>, ND, NA, NF

  Emits a function guard for func, and arranges to write the address of the
  following instruction to prologueAddrPtr.

| Count, D(Int), S(Cell), NF

  Computes the number of elements in S0. The count of an array is the number of
  elements it contains, without recursing into containers in the array.
  Subtypes of Bool|Int|Dbl|Str|Res have a count of 1, subtypes of Null have a
  count of 0. The count of objects that implement the Countable interface is
  computed by returning the value of their count method. Objects that do not
  implement Countable have a count of 1.

| CountArray,      D(Int), S(Arr),    NF

| CountArrayFast,  D(Int), S(Arr),    NF

| CountVec,        D(Int), S(Vec),    NF

| CountDict,       D(Int), S(Dict),   NF

| CountShape,      D(Int), S(Shape),  NF

| CountKeyset,     D(Int), S(Keyset), NF

| CountCollection, D(Int), S(Obj),    NF

  Computes the number of elements in S0 using the same definition as Count, but
  with a restriction on the input type.

  CountArray expects any array. CountArrayFast expects an array whose kind is
  not kGlobalsKind. CountCollection expects a collection object.

| Nop, ND, NA, NF

  Does nothing. It's sometimes useful for the simplifier to insert one of these
  in the instruction stream.

| ExitPlaceholder, ND, NA, B

  Does nothing if executed. Semantically, this instruction carries a taken edge
  to a block that was a pure side-exit during initial IR generation.  This
  allows later passes to test conditions and create new exits from the region
  at this point in the program.

14. Runtime helpers

| VerifyParamCls, ND, S(Cls) S(Cls|Nullptr) C(Int) C(Int), NF

  Verify parameter type for classes or traits. If S0 does not extend (if S1 is
  a class) or implement (if S1 is an interface) S1, this instruction will raise
  a recoverable fatal error describing the type mismatch.

| VerifyParamCallable, ND, S(Gen) C(Int), NF

  If S0 is not callable, as defined by the php function is_callable, this
  instruction will raise a recoverable fatal error describing the type
  mismatch.

| VerifyParamFail, ND, C(Int), NF

  Assumes that parameter number S0 in the current function has failed a its
  type check. Depending on the typehint being verified and a number of runtime
  options, may coerce the parameter to the correct type or raise a recoverable
  fatal error describing the type mismatch.

| VerifyParamFailHard, ND, C(Int), T

  A terminal version of VerifyParamFail, to be used when the compiler can
  statically prove that this failure will result in a fatal error rather than a
  type coercion.

| VerifyRetCallable, ND, S(Gen), NF

  Verify a return type hint.

| VerifyRetCls, ND, S(Cls) S(Cls|Nullptr) C(Int) S(Cell), NF

  Verify a return type hint.

| VerifyRetFail, ND, S(PtrToGen), NF

  Failure to verify a return type hint.

| VerifyRetFailHard, ND, S(PtrToGen), T

  Terminal version of VerifyRetFail, to be used when the compiler can prove
  that this failure will result in a fatal error.

| VerifyPropCls, ND, S(Cls) S(Int) S(Cls|Nullptr) S(Obj) C(Bool), NF

  Verify a property type hint with AnnotType::Object against an object
  value. S0 is the class of the object containing the property. S1 is the slot
  of the property on the class. S3 is the object which is being set in the
  property. If S2 is not nullptr, than the type-hint refers to that Class, and
  S3 will be checked to see if its an instance of S2. Otherwise, the type-hint
  refers to a type-alias, and the alias will be resolved and checked against
  S3. S4 is true if this is a static property, false otherwise.

| VerifyPropFail, ND, S(Cls) S(Int) S(Cell) C(Bool), NF

  Failure to verify a property type hint. S0 is the class of the object
  containing the property. S1 is the slot of the property on the class. S2 is
  the value which was being set in the property. S3 is true if this is a static
  property, false otherwise.

| VerifyPropFailHard, ND, S(Cls) S(Int) S(Cell) C(Bool), T

  Terminal version of VerifyPropFail, to be used when the compiler can prove
  that this failure will result in a fatal error.

| VerifyProp, ND, S(Cls) S(Int) S(Cell) C(Bool), NF

  Verify that S2 is compatible with the type hint for the property at slot S1
  on S0. S3 is true if this is a static property, false otherwise.

| VerifyReifiedLocalType<id>, ND, SDArr, NF

  Raises a catchable type hint error if the reified generics of function
  parameter id does not match the type structure given on S0.

| VerifyReifiedReturnType, ND, S(Cell) SDArr, NF

  Raises a catchable type hint error if the reified generics of S0 does not
  match the type structure given on S1.

| RaiseHackArrParamNotice<type,id,isReturn>, ND, S(Arr) S(Func), NF

  Raise a HackArrCompatNotice corresponding to a parameter or return type-hint
  d/varray mismatch. S0 is the array being passed in. S1 is the function being
  called.

| RaiseHackArrPropNotice<type>, ND, S(Cls) S(Arr) S(Int) C(Bool), NF

  Raise a HackArrCompatNotice corresponding to a property type-hint d/varray
  mismatch.

| RaiseUninitLoc<localId>, ND, S(Str), NF

  Raise a notice for an uninitialized local variable.

| RaiseUndefProp, ND, S(Obj) CStr, NF

  Raise a notice for an undefined property named S1 on the class of S0.

| RaiseMissingArg<func,argc>, ND, NA, NF

  Raise a missing argument warning because only argc arguments were passed to
  function func.

| RaiseTooManyArg<func,argc>, ND, NA, NF

  Raise a too many argument warning because argc arguments were passed to
  function func.

| RaiseError, ND, S(Str), T

  Raises a fatal error with the text in S0 as its message.

| RaiseWarning, ND, S(Str), NF

  Raises a warning with the text in S0 as its message.

| RaiseNotice, ND, S(Str), NF

  Raises a notice with the text in S0 as its message.

| RaiseArrayIndexNotice<isInOut>, ND, S(Int), NF

  Raises a notice that S0 is an undefined index for an array. The isInOut option
  indicates that the access was for an inout parameter.

| RaiseArrayKeyNotice<isInOut>, ND, S(StaticStr), NF

  Raises a notice that S0 is an undefined key for an array. The isInOut option
  indicates that the access was for an inout parameter.

| ThrowHasThisNeedStatic, ND, S(Func), T

  Throws a BadMethodCallException to indicate that func was called on an object
  but is a static method.

| ThrowMissingThis, ND, S(Func), T

  Throws a BadMethodCallException to indicate that an instance method was called
  with null $this.

| RaiseHackArrCompatNotice, ND, S(Str), NF

  Raises a Hack array compat notice with the text in S0 as its message.

| ThrowParamRefMismatch<paramIndex>, ND, S(Func), T

  Throw an exception indicating that the reffiness of a parameter was
  incorrectly annotated at the callsite.

| ThrowParamRefMismatchRange<firstBit,mask,vals>, ND, S(Func), T

  Throw an exception indicating that the reffiness of at least one parameter
  within a given range was incorrectly annotated at the callsite.

  See CheckRefs for meaning of firstBit, mask and vals.

| RaiseForbiddenDynCall, ND, S(Func), NF

  Depending on the setting of the `ForbidDynamicCalls` runtime option, either
  raise a warning or throw an exception indicating that the func specified in
  S0 was called dynamically (and should not be).

| RaiseForbiddenDynConstruct, ND, S(Cls), NF

  Depending on the setting of the `ForbidDynamicCalls` runtime option, either
  raise a warning or throw an exception indicating that the class specified in
  S0 was constructed dynamically (and should not be).

| RaiseRxCallViolation, ND, S(FramePtr) S(Func), NF

  Depending on the setting of the `RxEnforceCalls` runtime option, either raise
  a warning or throw an exception indicating that the caller specified by S0
  was violating reactivity constraints when calling the callee specified by S1.

| RaiseStrToClassNotice, ND, S(Str), NF

  Raise a notice if a string is implicitly converted to a class.

| CheckClsReifiedGenericMismatch<cls>, ND, SVArr, NF

  Raises a runtime error unless whether each generic in S0 is reified or erased
  matches exactly to the expectations of the cls.

| CheckFunReifiedGenericMismatch<func>, ND, SVArr, NF

  Raises a runtime error unless whether each generic in S0 is reified or erased
  matches exactly to the expectations of the func.

| IsFunReifiedGenericsMatched<func>, D(Bool), S(FramePtr), NF

  Load the value of m_reifiedGenerics on the ActRec pointed to by the frame
  pointer S0 and does the fast path for checking whether the number of generics
  and whether erased versus reified parity match.
  If the function has soft generics or the number of generics is greater than
  ReifiedGenericsPtr::kMaxTagSize, returns false.

| InitClsCns<className,constName>, DCns, NA, PRc

  Initialize the RDS entry for a constant for a class, invoking autoload if it
  is not defined. The initialized value is returned. This instruction may raise
  an undefined constant error if autoload cannot define the constant.

| PrintStr,  ND, S(Str),  CRc

| PrintInt,  ND, S(Int),  CRc

| PrintBool, ND, S(Bool), CRc

  Print for various types.

| ConcatIntStr, D(Str), S(Int) S(Str), PRc

  Concatenate S0 and S1 after converting S0 to String.

| ConcatStrInt, D(Str), S(Str) S(Int), CRc|PRc

  Concatenate S0 and S1 after converting S1 to String.

| ConcatStrStr, D(Str), S(Str) S(Str), CRc|PRc

  Concatenate S0 and S1.

| ConcatStr3, D(Str), S(Str) S(Str) S(Str), CRc|PRc

  Concatenate S0, S1, and S2.

| ConcatStr4, D(Str), S(Str) S(Str) S(Str) S(Str), CRc|PRc

  Concatenate S0, S1, S2, and S3.

| AddElemStrKey, D(Arr), S(Arr) S(Str) S(Cell), CRc|PRc

  Add S2 to the array S0 for the key S1, and return the resulting array.

| AddElemIntKey, D(Arr), S(Arr) S(Int) S(Cell), CRc|PRc

  Add S2 to the array S0 for the key S1, and return the resulting array.

| AddNewElem, D(Arr), S(Arr) S(Cell), CRc|PRc

| AddNewElemKeyset, D(Keyset), S(Keyset) S(Cell), CRc|PRc

| AddNewElemVec, D(Vec), S(Vec) S(Cell), CRc|PRc

  Add S1 as a new element to the array/keyset/vec S0.  (Note: S1 must actually
  be a subtype of InitCell for array invariants, but we can't assert this yet
  in the IR because many eval stack slots are not entirely typed wrt initness
  right now.)

| DictAddElemStrKey, D(Dict), S(Dict) S(Str) S(Cell), CRc|PRc

  Add S2 to the dict S0 for the key S1, and return the resulting dict.

| DictAddElemIntKey, D(Dict), S(Dict) S(Int) S(Cell), CRc|PRc

  Add S2 to the dict S0 for the key S1, and return the resulting dict.

| ArrayAdd, D(Arr), S(Arr) S(Arr), CRc|PRc

  Has the effects of the php + operator on the two source arrays.

| AKExistsArr, D(Bool), S(Arr) S(Int,Str), NF

  Has the effects of array_key_exists(S0, S1).

| AKExistsDict, D(Bool), S(Dict) S(Int,Str), NF

  Has the effects of array_key_exists(S0, S1).

| AKExistsKeyset, D(Bool), S(Keyset) S(Int,Str), NF

  Has the effects of array_key_exists(S0, S1).

| AKExistsObj, D(Bool), S(Obj) S(Int,Str), NF

  Has the effects of array_key_exists(S0, S1) on an object S0. This either does
  collection accesses, or uses the ArrayAccess API.

| GetMemoKey, DMemoKey, S(Cell), PRc

  Given a cell, produces a string or an int that can be used as a memoize cache
  key. Valid values for the input include all basic types, arrays and
  collections, and objects that implement IMemoizeParam. Any other type will
  cause GetMemoKey to throw. This op can only be used within functions marked
  as memoize wrappers.

| GetMemoKeyScalar, DMemoKey, S(Uncounted,Str), PRc

  Identical to GetMemoKey but only accepts scalar types and cannot produce
  errors.

| ArrayIdx, DArrElem, S(Arr) S(Int,Str) S(Cell), NF

  Checks if S0 contains the key S1, and returns the result if found. Otherwise
  S2 is returned.

| DictIdx, DDictElem, S(Dict) S(Int,Str) S(Cell), NF

  Checks if S0 contains the key S1 and returns the result if found. Otherwise
  S2 is returned.

| KeysetIdx, DKeysetElem, S(Keyset) S(Int,Str) S(Cell), NF

  Checks if S0 contains the key S1 and returns the result if found. Otherwise
  S2 is returned.

| MethodExists, D(Bool), S(Cls) S(Str), NF

  Checks if the method named S1 exists on class S0.  S0 must be a normal class
  that is not abstract.

| LdBindAddr<SrcKey,spOff>, D(TCA), NA, NF

  Creates a service request to bind the given target address. Returns a TCA
  pointing either to the service request (before the service request is
  satisfied) or to the native code for the given target address (once the
  service request is satisfied).

| LdSwitchDblIndex, D(Int), S(Dbl) S(Int) S(Int), NF

| LdSwitchStrIndex, D(Int), S(Str) S(Int) S(Int), CRc

| LdSwitchObjIndex, D(Int), S(Obj) S(Int) S(Int), CRc

  These instructions are used to determine the target of a switch statement
  with target range [S1:S1 + S2), when invoked with the value S0. They call
  helper functions to check whether S0 is an numeric integer in the range
  [S1:S1 + S2), and if so return the value S1 - (Int)S0. Else, they return the
  target of the default target, S2 + 1.

| LdSSwitchDestFast, D(TCA), S(Gen), NF

| LdSSwitchDestSlow, D(TCA), S(Gen), NF

  Load string switch destinations (two different compilation strategies).

| InterpOne<T,spOff,bcOff,numPopped,numPushed>, ND,
|                                               S(StkPtr) S(FramePtr),
|                                               NF

  Call the interpreter implementation function for one opcode. S0 + `spOff' (in
  cells) and S1 are, respectively, the VM stack and frame pointers before this
  instruction. T is only present if the instruction pushes to the stack, in
  which case it is the type of the top stack element after the call. `bcOff' is
  the bytecode offset. `numPopped' is the number of stack cells consumed by the
  instruction, and `numPushed' is the number of stack cells produced by the
  instruction.

| InterpOneCF<T,bcOff,numPopped,numPushed>, ND,
|                                           S(StkPtr) S(FramePtr),
|                                           T

  Similar to InterpOne, but for instructions that may modify vmpc. This is
  implemented as a tail call to a stub, so any exceptions thrown will be thrown
  in the context of the stub, not the InterpOneCF instruction.

| OODeclExists<kind>, D(Bool), S(Str) S(Bool), NF

  Returns a bool indicating whether the class, interface, or trait named by S0
  exists. Invokes autoload if S1 is true.

| SetOpCell<op>, ND, S(LvalToCell) S(Cell), NF

  Performs S0 <op>= S1.

| SetOpCellVerify<op>, ND, S(LvalToCell) S(Cell) S(Cls) S(Int), NF

  Similar to SetOpCell, but does a type-hint check of the result (before
  assigning to S0) using the type-hint of the property in class S2 at slot S3.

| GetTime, D(Dbl), NA, NF

  Returns a double of the current time in seconds.

| GetTimeNs, D(Int), C(Int), NF

  Returns the current time of the given clock id specified as clockid_t in
  nanoseconds as integer. This will call kernel's clock_gettime_ns() API. Note
  that this cannot be used for CLOCK_THREAD_CPUTIME_ID, as HHVM provides
  different semantics for that counter.

| KillClsRefCls<slot>, ND, S(FramePtr), NF

  Mark the class-ref's cls slot `slot` in frame S0 as no longer containing a
  meaningful value. This is used to aid in memory analysis. In debugging
  builds, it may overwrite the slot with a poison value.

| KillClsRefTS<slot>, ND, S(FramePtr), NF

  Mark the class-ref's reified generic slot `slot` in frame S0 as no longer
  containing a meaningful value. This is used to aid in memory analysis.
  In debugging builds, it may overwrite the slot with a poison value.

15. Generators & Closures

| LdClosureCtx, DCtx, S(Obj), NF

  Load the context from the closure object S0 into D.
  May only be used in S0's closure Func.

| StClosureCtx, ND, S(Obj) S(Ctx,Nullptr), CRc

  Store the context represented by S1 into the closure object S0. S1 may be a
  Nullptr when there is no context (i.e. the closure is being used in a
  non-method).

| StClosureArg<offsetBytes>, ND, S(Obj) S(Cell), CRc

  Store one of the closure environment arguments (i.e. from the closure's use
  clause) from S1 into the closure object S0.

| CreateGen, DAllocObj, S(FramePtr) C(Int) S(TCA,Nullptr) C(Int), PRc

  Create a Generator object and suspend the ActRec provided by S0 into its
  embedded ActRec, allocating S1 slots for locals/iterators. Set the native
  resume address to S2 and resume offset to S3.

| CreateAGen, DAllocObj, S(FramePtr) C(Int) S(TCA,Nullptr) C(Int), PRc

  Create an AsyncGenerator object and suspend the ActRec provided by S0 into its
  embedded ActRec, allocating S1 slots for locals/iterators. Set the native
  resume address to S2 and resume offset to S3.

| CreateAFWH, DAllocObj,
|             S(FramePtr) C(Int) S(TCA,Nullptr) C(Int) S(Obj),
|             CRc|PRc

  Create an AsyncFunctionWaitHandle object and suspend the ActRec provided by
  S0 into its embedded ActRec, allocating S1 slots for locals/iterators.  Set
  the native resume address to S2, resume offset to S3, and mark it blocked on
  non-finished child S4.

| CreateAFWHNoVV, DAllocObj,
|                 S(FramePtr) C(Int) S(TCA,Nullptr) C(Int) S(Obj),
|                 CRc|PRc

  Create an AsyncFunctionWaitHandle object and suspend the ActRec provided by
  S0 into its embedded ActRec, allocating S1 slots for locals/iterators.  Set
  the native resume address to S2, resume offset to S3, and mark it blocked on
  non-finished child S4.  This version of the instruction guarantees that the
  VarEnv is unused.

| CreateAGWH, DAllocObj,
|             S(FramePtr) S(TCA,Nullptr) C(Int) S(Obj),
|             CRc|PRc

  Create an AsyncGeneratorWaitHandle object and link it to the AsyncGenerator
  associated with the ActRec provided by S0.  Set the native resume address
  to S1, resume offset to S2, and mark it blocked on non-finished child S3.

| CreateAAWH<local,count>, DAllocObj, S(FramePtr) S(Int), PRc

  Create an AwaitAllWaitHandle and add the count elements from frame contiguous
  frame locals beginning at local and extending count locals. S1 denotes the
  total number of non-completed waithandles. All locals must be subclasses of
  WaitHandle.

| CreateSSWH, DAllocObj, S(Cell), CRc|PRc

  Call c_StaticWaitHandle::CreateSucceeded.

| AFWHPrepareChild, ND, S(FramePtr) S(Obj), NF

  Prepare unfinished WaitableWaitHandle object specified by S1 for getting
  awaited by an AsyncFunctionWaitHandle object specified by its ActRec
  provided by S0.

  Injects S1 into the currently running scheduler instance and performs
  cross-scheduler and intra-scheduler cycle detection. Throws if the
  dependency cannot be established.

| StArResumeAddr<offset>, ND, S(FramePtr) S(TCA), NF

  Store the resume address S1 into the Resumable whose ActRec is given by S0,
  marking the offset to resume at as `offset'.

| ContEnter<spOffset,callBCOffset>, DGenIter,
|                                   S(StkPtr) S(FramePtr) S(FramePtr) S(TCA),
|                                   NF

  Enters a generator body. S0 + `spOffset' (in cells) is a pointer to the
  stack, S1 is the current frame pointer, S2 is the generator frame pointer
  embedded in the Generator object, and S3 is the address to jump to. The
  `callBCOffset' will be stored to the m_callOff field of the ActRec in
  the generator.

| ContPreNext, ND, S(Obj) C(Bool), B

  Performs operations needed for the next() method of Generator object S0.
  If the generator is already running or finished, or it was not started yet
  and the S1 check-started flag is set, the branch B is taken. Otherwise,
  the generator is marked as running.

| ContStartedCheck, ND, S(Obj), B

  Checks if the Generator object S0 has started, and if not branches to
  block B.

| ContValid, D(Bool), S(Obj), NF

  Return true if a generator is not done, false otherwise.

| ContStarted, D(Bool), S(Obj), NF

  Return true if a generator has been run at least once, i.e. is not in the
  Created state, false otherwise.

| ContArIncKey, ND, S(FramePtr), NF

  Special-case key update for generator, ActRec of which is S0, which
  increments the key of a generator if that generator's key is an Int.
  This will cause undefined behavior if the generator's key is not an Int.

| ContArIncIdx, D(Int), S(FramePtr), NF

  Increment the internal index in the Generator in S0, and return the new index
  value.

| ContArUpdateIdx, ND, S(FramePtr) S(Int), NF

  Updates the internal index of generator with S1 if necessary, i.e. if S1
  is larger than the index. S0 is the pointer to the embedded ActRec.

| LdContActRec, D(FramePtr), S(Obj), NF

  Loads the Generator object's ActRec, given a pointer to the generator
  object in S0.

| LdContResumeAddr, D(TCA|Nullptr), S(Obj), NF

  Load the resume addr from the Generator in S0.

| StContArState<state>, ND, S(FramePtr), NF

  Change the state of the Generator object which has frame pointer S0.

| LdContArValue, DParam(Cell), S(FramePtr), PRc

  Loads 'value' from the Generator object ActRec of which is S0.

| StContArValue, ND, S(FramePtr) S(Cell), CRc

  Stores 'value' into the Generator object ActRec of which is S0. S1 is the
  new value.

| LdContArKey, DParam(Cell), S(FramePtr), PRc

  Loads 'key' from the Generator object ActRec of which is S0.

| StContArKey, ND, S(FramePtr) S(Gen), CRc

  Stores 'key' into the Generator object ActRec of which is S0. S1 is the
  new value.

| AFWHBlockOn, ND, S(FramePtr) S(Obj), CRc

  Establish dependency between parent AsyncFunctionWaitHandle object, whose
  ActRec is given by S0, and child WaitableWaitHandle object referenced by S1.

| LdWHState, D(Int), S(Obj), NF

  Loads the state of the WaitHandle in S0, which is a value from the wait
  handle states in ext_asio.h. This instruction has undefined behavior if S0 is
  not a WaitHandle.

| LdWHResult, DParam(Gen), S(Obj), NF

  Loads the result of the WaitHandle in S0. This instruction has undefined
  behavior if S0 is not a WaitHandle, or if S0 is not finished.

| LdWHNotDone, D(Int), S(Obj), NF

  Returns 1 if S0 is not finished, and 0 if S0 is finished.

| CountWHNotDone<local,count>, D(Int), S(FramePtr), B

  Returns the number of unfinished awaitables contained in the contiguous
  locals beginning at local and extending count, skipping all nulls. A branch
  is taken if a non-Awaitable non-null value is encountered.

| LdAFWHActRec, D(FramePtr), S(Obj), NF

  Loads the AsyncFunctionWaitHandle object's ActRec, given a pointer to the
  AsyncFunctionWaitHandle object in S0.


16. Debugging, instrumentation, and profiling

| IncStat, ND, C(Int), NF

  Increment stat counter. S0 is the implementation defined stat counter index.

| IncProfCounter<TransID>, ND, NA, NF

  Increment the profiling counter associated with translation TransID.

| DbgAssertRefCount<AssertReason>, ND, S(Gen,TCtx), NF

  Assert that S0 has a valid refcount. If S0 has a reference counted type and
  its count is implausible then execute a hardware trap instruction.

| DbgTraceCall<spOffset>, ND, S(FramePtr) S(StkPtr), NF

  When EvalHHIRGenerateAsserts is on, this instruction is inserted at the
  start of each region, to emit some sanity checking code.

| DbgAssertARFunc<offset>, ND, S(StkPtr) S(Func), NF

  Assert that S1 is the function in the ActRec given by s0+offset. If the
  assertion fails, execution is aborted via a hardware exception.

| DbgAssertFunc, ND, S(FramePtr) S(Func), NF

  Assert that S1 is the current function in Frame S0. If the assertion fails,
  execution is aborted via a hardware exception.

| RBTraceEntry, ND, NA, NF

| RBTraceMsg, ND, NA, NF

  Ring buffer tracing.

| ZeroErrorLevel, D(Int), NA, NF

| RestoreErrorLevel, ND, S(Int), NF

  Helper instructions for fast implementation of the PHP error silencing
  operator (@foo()).


17. Iterators

| IterInit<IterData>,   D(Bool), S(ArrLike,Obj) S(FramePtr), CRc

| IterInitK<IterData>,  D(Bool), S(ArrLike,Obj) S(FramePtr), CRc

| LIterInit<IterData>,  D(Bool), S(ArrLike) S(FramePtr), NF

| LIterInitK<IterData>, D(Bool), S(ArrLike) S(FramePtr), NF

  <IterData> consists of three indices, iterId, keyId and valId. iterId is
  the index of the iterator variable, keyId and valId are indices of local
  variables.

  Initializes the iterator variable whose index is given by iterId.
  This instruction creates the appropriate iterator for the array or object that
  S0 references, and rewinds the new iterator to its start. S0 points to the
  stack frame containing the iterator and local variables with the indices
  iterId, keyId and valId.

  If the new iterator is at its end (i.e., has no elements to iterate over),
  this instruction decrements the refcount of S0 and returns false; otheriwse,
  it stores a reference to S0 in the new iterator and returns true. If the
  iterator is not at its end, then this instruction stores the iterator's first
  value (and key) into the local variable with index valId (and keyId,
  respectively).

  The IterInit and IterInitK instructions always copy the array element by
  value.

  The LIter variations only accept arrays and do not take ownership of their
  base. Instead the base is provided on each operation on the iterator. This
  avoids having to raise the ref-count of the base (in situations where this is
  safe).

  This instruction has the ConsumesRC property because it either decrements the
  reference count of S0 or stores a reference to S0 into the new iterator.

| IterNext<IterData>,   D(Bool), S(FramePtr), NF

| IterNextK<IterData>,  D(Bool), S(FramePtr), NF

| LIterNext<IterData>,  D(Bool), S(ArrLike) S(FramePtr), NF

| LIterNextK<IterData>, D(Bool), S(ArrLike) S(FramePtr), NF

  <IterData> consists of three indices, iterId, keyId and valId. iterId is
  the index of the iterator variable, keyId and valId are indices of local
  variables.  S0 points to the stack frame containing the iterator and local
  variables with the indices iterId, keyId and valId.

  Advances the iterator variable whose index is given by iterId.

  If the iterator has reached the end, this instruction frees the iterator
  variable and returns false; otherwise, it returns true. If the iterator has
  not reached its end, then this instruction stores the iterator's next value
  (and key) into the local variable with index valId (and keyId, respectively).

  The IterInit and IterInitK instructions always copy the array element by
  value.

| IterFree,  ND, S(FramePtr), NF

  Free the iterator variable whose index is given by S1 in the stack frame
  pointed to by S0.


18. Member instruction support

| LdMIStateAddr, D(PtrToMISGen), C(Int), NF

  Load an MInstrState address. Returns a pointer to offset S0 within the
  current MInstrState.

| LdMBase, DParam(LvalToGen), NA, NF

  Load the current value of the member base register.

| StMBase, ND, S(LvalToGen), NF

  Store a new value to the member base register. It is illegal for any
  instruction other than StMBase or InterpOne (when interpreting a member
  instruction) to modify the member base register.

| LdMIPropStateAddr, D(MIPropSPtr), NA, NF

  Load an address to the current MInstrPropState.

| StMIPropState, ND, S(Cls|Nullptr) S(Int) C(Bool), NF

  Write to the current MInstrPropState.

| FinishMemberOp, ND, NA, NF

  Mark the end of a member operation. This has no effect at runtime but exists
  to provide information for certain optimizations.

All of the remaining opcodes in this section are simple wrappers around helper
functions (specified in S0) to perform the corresponding vector operation. If
S1 is a ConstCls it represents the context class for the operation.

SetElem, SetProp, and SetNewElem are used to implement part of the SetM hhbc
opcode, which almost always pushes its first stack input or a StaticStr as its
stack result. The combinations of input types that cause SetM to push anything
other than those two values are vanishingly rare in correct PHP programs, so
these three instructions have been optimized for the common cases. SetNewElem
and SetProp have no destination, allowing the compiler to predict that the
SetM's output will be the same as its input (and optimize accordingly). If that
turns out to not be the case at runtime, the instruction will throw an
InvalidSetMException. The exception will hold a Cell containing the value the
SetM should push on the stack instead of its input value. The runtime is
responsible for catching this exception, finishing execution of the SetM
instruction, pushing the value from the exception on the stack, and proceeding
as appropriate (most likely with a side exit to the next bytecode instruction,
since it has pushed an unexpected type onto the stack).

SetElem is similar to SetProp and SetNewElem but can also be used for setting
characters within strings. When given a string base and a valid offset, SetElem
returns a string representation of the newly inserted character. In all other
cases it returns nullptr or throws an InvalidSetMException. It will throw this
exception when it detects invalid input types, or when trying to set a string
offset that would grow the string beyond the maximum supported size.

The input types that will cause the errors described above are listed here:

SetNewElem will fail if the base is not a subtype of {Null|Str|Arr|Obj} and not
           Bool<false>.
SetElem has the same base constraint as SetNewElem. In addition, the key must
        not be a subtype of {Arr|Obj}.
SetProp will fail if the base is not a subtype of {Obj|Null}.

Any instructions that take a pointer to an MInstrState struct use the various
fields of that struct for holding intermediate values.

| BaseG, D(LvalToRMembCell), S(Str), NF

  Get a base from global named S0.

  NB: BaseG returns either a PtrToGblGen, OR a pointer to a ref that is rooted
  in a GblGen.  (I.e. the unbox happens in the C++ helper that this instruction
  calls.)  If it is not a defining BaseG it can also return the
  init_null_variant, so for now it returns a PtrToRMembCell.

| PropX, D(LvalToMembGen), S(Obj,LvalToGen) S(Cell) S(PtrToMISGen), NF

  Lookup intermediate property in S0, with key S1.

| PropQ, D(LvalToMembGen), S(Obj,LvalToGen) S(StaticStr) S(PtrToMISGen), NF

  A nullsafe version of PropX, returns null if the base S0 is null.

| PropDX, D(LvalToMembGen), S(Obj,LvalToGen) S(Cell) S(PtrToMISGen) S(MIPropSPtr,Nullptr), MProp

  Like PropX, but used for intermediate element lookups that may modify the
  base.

| CGetProp, D(Cell), S(Obj,LvalToGen) S(Cell), PRc

  Get property with key S1 from S0.

| CGetPropQ, D(Cell), S(Obj,LvalToGen) S(StaticStr), PRc

  A nullsafe version of CGetProp, returns null if the base S0 is null.

| VGetProp, D(BoxedInitCell), S(Obj,LvalToGen) S(Cell) S(MIPropSPtr,Nullptr), MProp|PRc

  Get property with key S1 from base S0 as a reference.

| SetProp, ND, S(Obj,LvalToGen) S(Cell) S(Cell) S(MIPropSPtr,Nullptr), MProp

  Set property with key S1 in S0 to S2.

| UnsetProp, ND, S(Obj,LvalToGen) S(Cell), NF

  Unset an object property.

| SetOpProp<op>, D(Cell),
|                S(Obj,LvalToGen) S(Cell) S(Cell) S(MIPropSPtr,Nullptr),
|                MProp|PRc

  Set op propery with key S1 in base S0, using S2 as the right hand side.

| IncDecProp<op>, D(Cell),
|                 S(Obj,LvalToGen) S(Cell) S(MIPropSPtr,Nullptr),
|                 MProp|PRc

  Increment/decrement property with key S1 in base S0.

| EmptyProp, D(Bool), S(Obj,LvalToGen) S(Cell), NF

  Returns true iff the property with key S1 in base S0 is empty.

| IssetProp, D(Bool), S(Obj,LvalToGen) S(Cell), NF

  Returns true iff the property with key S1 in base S0 is set.

| ElemX, D(LvalToMembGen), S(LvalToGen) S(Cell) S(PtrToMISGen), NF

  Get intermediate element with key S1 from base S0. The base will not be
  modified.

| ProfileMixedArrayOffset, ND, S(Arr) S(Int,Str), NF

  Profile the offset of the element keyed by S1 in S0.

| CheckMixedArrayOffset<pos>, ND, S(AK(Mixed)) S(Int,Str), B

  Check that `pos' is within the usage bounds of S0 (including tombstones), and
  that S1 exactly matches the element key of S0 at `pos'.  If any of the checks
  fail, branch to B.  This check is allowed to have false negatives, in the
  case of int-like strings.

| CheckArrayCOW, ND, S(ArrLike), B

  Check that S0 has a refcount of exactly 1; if not, branch to B.

| ProfileDictOffset, ND, S(Dict) S(Int,Str), NF

  Profile the offset of the element keyed by S1 in S0.

| CheckDictOffset<pos>, ND, S(Dict) S(Int,Str), B

  Check that `pos' is within the usage bounds of S0 (including tombstones), and
  that S1 exactly matches the element key of S0 at `pos'.  If any of the checks
  fail, branch to B.  This check is allowed to have false negatives.

| ProfileKeysetOffset, ND, S(Keyset) S(Int,Str), NF

  Profile the offset of the element keyed by S1 in S0.

| CheckKeysetOffset<pos>, ND, S(Keyset) S(Int,Str), B

  Check that `pos' is within the usage bounds of S0 (including tombstones), and
  that S1 exactly matches the element key of S0 at `pos'.  If any of the checks
  fail, branch to B.  This check is allowed to have false negatives.

| ElemArrayX<M>, D(LvalToMembGen), S(Arr) S(Int,Str), NF

| ElemArrayD<T>, D(LvalToElemGen), S(LvalToGen) S(Int,Str), MElem

| ElemArrayU<T>, D(LvalToMembGen), S(LvalToGen) S(Int,Str), MElem

  Similar to ElemX, but the base S0 is an array and the key S1 is an int/str.
  ElemArrayD is for Define member instrs, ElemArrayU is for Unset, and
  ElemArrayX is for InOut, Warn, and None instrs (where the mode is M).

  ElemArray{D,U} both take a LvalToGen for the base operand, but expect it to be
  a LvalToArr or LvalToBoxedArr.  T is the type of the base array.

| ElemMixedArrayK<pos>, D(LvalToElemGen), S(AK(Mixed)) S(Int,Str), NF

  Like ElemArray, but the element for S1 is at a known position `pos' in S0.

| ElemVecD<T>, D(LvalToElemCell), S(LvalToGen) S(Int), MElem

| ElemVecU<T>, D(LvalToMembCell), S(LvalToGen) S(Int), MElem

  Similar to ElemX, but the base S0 is a vec and the key S1 is an int. ElemVecD
  is for Define member instrs and ElemVecU is for Unset. (Other variations can
  be implemented without special IR instructions).

  ElemVec{D,U} both take a LvalToGen for the base operand, but expect it to be a
  LvalToVec or LvalToBoxedVec. T is the type of the base vec.

| ElemDictX<M>, D(LvalToMembCell), S(Dict) S(Int,Str), NF

| ElemDictD<T>, D(LvalToElemCell), S(LvalToGen) S(Int,Str), MElem

| ElemDictU<T>, D(LvalToMembCell), S(LvalToGen) S(Int,Str), MElem

  Similar to ElemX, but the base S0 is a dict and the key S1 is an int/str.
  ElemDictD is for Define member instrs, ElemDictU is for Unset, and
  ElemDictX is for InOut, Warn, and None instrs (where the mode is M).

  ElemDict{D,U} both take a LvalToGen for the base operand, but expect it to be
  a LvalToDict or LvalToBoxedDict.  T is the type of the base array.

| ElemDictK<pos>, D(LvalToElemCell), S(Dict) S(Int,Str), NF

  Like ElemDict, but the element for S1 is at a known position `pos' in S0.

| ElemKeysetX<M>, D(LvalToMembCell), S(Keyset) S(Int,Str), NF

| ElemKeysetU<T>, D(LvalToMembCell), S(LvalToGen) S(Int,Str), MElem

  Similar to ElemX, but the base S0 is a keyset and the key S1 is an int/str.
  ElemKeysetU is for Unset instrs and ElemKeysetX is for InOut, Warn and None
  instrs (where the mode is M).

  ElemKeysetU both take a LvalToGen for the base operand, but expect it to be
  a LvalToKeyset or LvalToBoxedKeyset.  T is the type of the base array.

| ElemKeysetK<pos>, D(LvalToElemCell), S(Keyset) S(Int,Str), NF

  Like ElemKeyset, but the element for S1 is at a known position `pos' in S0.

| ElemDX, D(LvalToMembGen), S(LvalToGen) S(Cell) S(PtrToMISGen) S(MIPropSPtr,Nullptr), MElem

  Like ElemX, but used for intermediate element lookups that may modify the
  base.

| ElemUX, D(LvalToMembGen), S(LvalToGen) S(Cell) S(PtrToMISGen), MElem

  Like ElemX, but used for intermediate element lookups that may modify the
  base as part of an unset operation.

| ArrayGet, DArrElem, S(Arr) S(Int,Str), NF

  Get element with key S1 from base S0.

| MixedArrayGetK<pos>, DArrElem, S(AK(Mixed)) S(Int,Str), NF

  Like ArrayGet, but the element for S1 is at a known position `pos' in S0.

| DictGet, DDictElem, S(Dict) S(Int,Str), NF

  Get element with key S1 from base S0, throwing if the element is not present.

| DictGetQuiet, DDictElem, S(Dict) S(Int,Str), NF

  Get element with key S1 from base S0, returning null if the element is not
  present.

| DictGetK<pos>, DDictElem, S(Dict) S(Int,Str), NF

  Like DictGet, but the element for S1 is at a known position `pos' in S0.

| KeysetGet, DKeysetElem, S(Keyset) S(Int,Str), NF

  Get element with key S1 from base S0, throwing if the element is not present.

| KeysetGetQuiet, DKeysetElem, S(Keyset) S(Int,Str), NF

  Get element with key S1 from base S0, returning null if the element is not
  present.

| KeysetGetK<pos>, DKeysetElem, S(Keyset) S(Int,Str), NF

  Like KeysetGet, but the element for S1 is at a known position `pos' in S0.

| StringGet, D(StaticStr), S(Str) S(Int), PRc

  Get string representing character at position S1 from base string S0.  Raises
  a notice if the position is out of bounds.

| MapGet, D(Cell), S(Obj) S(Int,Str), PRc

  Get element with key S1 from base S0.

| CGetElem, D(Cell), S(LvalToGen) S(Cell), PRc

  Get element with key S1 from S0.

| MemoGetStaticValue<func,T>, DParam(InitCell), NA, B

  Get the memo value associated with the static function "func". If the value
  is not present, branch. The returned value is not inc-reffed. This op can
  only be used inside a memoize wrapper.

| MemoGetStaticCache<func,keys,T>, DParam(InitCell), S(FramePtr,StkPtr), B

  Perform a lookup on the memo cache associated with the static function
  "func". The keys for the lookup are read from the locals on the frame pointed
  to by S0 (which must be ints or strings). If the lookup fails, branch. The
  returned value is not inc-reffed. This op can only be used inside a memoize
  wrapper.

| MemoGetLSBValue<func,T>, DParam(InitCell), S(Cls), B

  Get the memo value associated with the static function "func" and late static
  bound class S0. If the value is not present, branch. The returned value is not
  inc-reffed. This op can only be used inside a memoize wrapper.

| MemoGetLSBCache<func,keys,T>, DParam(InitCell), S(FramePtr,StkPtr) S(Cls), B

  Perform a lookup on the memo cache associated with the static function
  "func" and late static bound class S1. The keys for the lookup are read from
  the locals on the frame pointed to by S0 (which must be ints or strings). If
  the lookup fails, branch. The returned value is not inc-reffed. This op can
  only be used inside a memoize wrapper.

| MemoGetInstanceValue<slot,func,T>, DParam(InitCell), S(Obj), B

  Get the memo value at the specified memo slot on S0. If the value is not
  present, branch. The returned value is not inc-reffed. This op can only be
  used inside a memoize wrapper.

| MemoGetInstanceCache<func,keys,T>, DParam(InitCell), S(FramePtr,StkPtr) S(Obj), B

  Perform a lookup on the memo cache at the specified memo slot on S1. The keys
  for the lookup are read from the locals on the frame pointed to by S0 (which
  must be ints or strings). If the lookup fails, branch. The returned value is
  not inc-reffed. This op can only be used inside a memoize wrapper.

| MemoSetStaticValue<func>, ND, S(InitCell), NF

  Set S0 as the memo value associated with the static function "func". Store
  the value, overwriting any previous value, with appropriate ref-count
  manipulations. This op can only be used inside a memoize wrapper.

| MemoSetStaticCache<func,keys>, ND, S(FramePtr,StkPtr) S(InitCell), NF

  Store S1 in the memo cache associated with the static function "func". The
  keys for the lookup are read from the locals on the frame pointed to be S0
  (which must be ints or strings). Store the value, overwriting any previous
  value, with appropriate ref-count manipulations. This op can only be used
  inside a memoize wrapper.

| MemoSetLSBValue<func>, ND, S(InitCell) S(Cls), NF

  Set S0 as the memo value associated with the static function "func" and
  late static bound class S1. Store the value, overwriting any previous
  value, with appropriate ref-count manipulations. This op can only be used
  inside a memoize wrapper.

| MemoSetLSBCache<func,keys>, ND, S(FramePtr,StkPtr) S(Cls) S(InitCell), NF

  Store S2 in the memo cache associated with the static function "func" and
  late static bound class S1. The keys for the lookup are read from the
  locals on the frame pointed to be S0 (which must be ints or strings).
  Store the value, overwriting any previous value, with appropriate
  ref-count manipulations. This op can only be used inside a memoize wrapper.

| MemoSetInstanceValue<slot,func>, ND, S(Obj) S(InitCell), NF

  Set S2 as the memo value at the specified memo slot on S1. Store the value,
  overwriting any previous value, with appropriate ref-count
  manipulations. This op can only be used inside a memoize wrapper.

| MemoSetInstanceCache<slot,func,keys>, ND, S(FramePtr,StkPtr) S(Obj) S(InitCell), NF

  Store S2 in the memo cache at the specified memo slot on S1. Store the value,
  overwriting any previous value, with appropriate ref-count
  manipulations. This op can only be used inside a memoize wrapper.

| InitObjMemoSlots<class>, ND, S(Obj), NF

  Initialize the memoization instance slots for object S0 of the given class.

| ArraySet, D(Arr), S(Arr) S(Int,Str) S(Cell), PRc|CRc

  Set element with key S1 in S0 to S2. The dest will be a new Array that should
  replace S0.

| ArraySetRef, ND, S(Arr) S(Int,Str) S(Cell) S(BoxedCell), CRc

  Like ArraySet, but for binding operations on the array. S3 must point to a
  RefData with an array type when this instruction is executed, and it must be
  the same array that is in S0.

| VecSet, D(Vec), S(Vec) S(Int) S(Cell), PRc|CRc

  Set element with key S1 in S0 to S2. The dest will be a new Vec that should
  replace S0.

| VecSetRef, ND, S(Vec) S(Int) S(Cell) S(BoxedCell), CRc

  Like VecSet, but for binding operations on the vec. S3 must point to a
  RefData with a vec type when this instruction is executed, and it must be the
  same vec that is in S0.

| DictSet, D(Dict), S(Dict) S(Int,Str) S(Cell), PRc|CRc

  Set element with key S1 in S0 to S2. The dest will be a new Dict that should
  replace S0.

| DictSetRef, ND, S(Dict) S(Int,Str) S(Cell) S(BoxedCell), CRc

  Like DictSet, but for binding operations on the dict. S3 must point to a
  RefData with a vec type when this instruction is executed, and it must be the
  same dict that is in S0.

| MapSet, ND, S(Obj) S(Int,Str) S(Cell), NF

  Set element with key S1 in S0 to S2.

| VectorSet, ND, S(Obj) S(Int,Str) S(Cell), NF

  Set element with key S1 in S0 to S2.

| SetElem, DSetElem, S(LvalToGen) S(Cell) S(Cell) S(MIPropSPtr,Nullptr), MElem

  Set element with key S1 in S0 to S2. SetElem returns a Nullptr in the common
  case, where the logical result of the hhbc SetM is its right hand side. In
  the case of string bases, the SetM returns a new string containing the newly
  inserted character. So the return value of this instruction is Nullptr unless
  SetM needed to return a static string.

  Furthermore, in the case of "invalid offsets", SetElem may throw an
  InvalidSetMException (see discussion above).

| SetRange, ND, S(LvalToGen) S(Int) S(Cell) S(Int) S(Int), MElem

| SetRangeRev, ND, S(LvalToGen) S(Int) S(Cell) S(Int) S(Int), MElem

  Perform a range set or reverse range set operation, with the same arguments
  and semantics as the RangeSet bytecode instruction.

| UnsetElem, ND, S(LvalToGen) S(Cell), MElem

  Unsets the element at key S1 in the base S0.

| SetOpElem<op>, D(Cell),
|                S(LvalToGen) S(Cell) S(Cell) S(MIPropSPtr,Nullptr),
|                MElem|PRc

  Set op elem with key S1 in base S0, using S2 as the right hand side.

| IncDecElem, D(Cell), S(LvalToGen) S(Cell) S(MIPropSPtr,Nullptr), MElem|PRc

  Increment/decrement element with key S1 in base S0.

| SetNewElem, ND, S(LvalToGen) S(Cell) S(MIPropSPtr,Nullptr), MElem

  Append the value in S1 to S0.

| SetNewElemArray, ND, S(LvalToGen) S(Cell), MElem

  Append the value in S1 to S0, where S0 must be a pointer to a array.

| SetNewElemVec, ND, S(LvalToGen) S(Cell), MElem

  Append the value in S1 to S0, where S0 must be a pointer to a vec.

| SetNewElemKeyset, ND, S(LvalToGen) S(Int,Str), MElem

  Append the value in S1 to S0, where S0 must be a pointer to a keyset.

| ArrayIsset, D(Bool), S(Arr) S(Int,Str), NF

  Returns true iff the element at key S1 in the base S0 is set.

| DictIsset, D(Bool), S(Dict) S(Int,Str), NF

  Returns true iff the element at key S1 in the base S0 is set.

| KeysetIsset, D(Bool), S(Keyset) S(Int,Str), NF

  Returns true iff the element at key S1 in the base S0 is set.

| StringIsset, D(Bool), S(Str) S(Int), NF

  Returns true iff the string S0 has a character at position S1.

| VectorIsset, D(Bool), S(Obj) S(Int), NF

  Returns true iff the element at key S1 in the base S0 is set.

| PairIsset, D(Bool), S(Obj) S(Int), NF

  Returns true iff the element at key S1 in the base S0 is set.

| MapIsset, D(Bool), S(Obj) S(Int,Str), NF

  Returns true iff the element at key S1 in the base S0 is set.

| IssetElem, D(Bool), S(LvalToGen) S(Cell), NF

  Returns true iff the element at key S1 in S0 is set.

| EmptyElem, D(Bool), S(LvalToGen) S(Cell), NF

  Returns true iff the element at key S1 in S0 is set and not equal (as defined
  by the hhbc Eq instruction) to false.

| DictEmptyElem, D(Bool), S(Dict) S(Int,Str), NF

  Like EmptyElem, but specialized for dicts.

| KeysetEmptyElem, D(Bool), S(Keyset) S(Int,Str), NF

  Like EmptyElem, but specialized for dicts.

| CheckRange, D(Bool), S(Int) S(Int), NF

  Returns true iff S0 is in the range [0, S1).

| ThrowOutOfBounds, ND, S(ArrLike|Obj) S(Gen), T

  Throws an OutOfBoundsException corresponding to an access of S0 with the key
  S1.

| ThrowInvalidArrayKey, ND, S(ArrLike) S(Gen), T

  Throws an InvalidArgumentException corresponding to an access of S0 with the
  key S1, which has a type invalid for that array.

| ThrowInvalidOperation, ND, S(Str), T

  Throws an InvalidOperationException with a message indicating S0.

| ThrowArithmeticError, ND, S(Str), T

  Throws an ArithmeticError with a message indicating S0.

| ThrowDivisionByZeroError, ND, S(Str), T

  Throws a DivisionByZeroError with a message indicating S0.

| ThrowDivisionByZeroException, ND, NA, T

  Throws a DivisionByZeroException.

| ThrowLateInitPropError, ND, S(Cls) S(Str) S(Bool), T

  Throws an InvalidOperationException indicating an access of a unset LateInit
  property. S0 is the class the property was declared on. S1 is the property
  name. S2 is true if its a static property, false otherwise.

| ThrowParameterWrongType<expectedType, func, argNum>, ND, S(Gen), T

  Throws a RuntimeException if calling a function with an argument that has the
  wrong type

| ProfileArrayKind, ND, S(Arr), NF

  Profile the array kind of S0.

| ProfileType, ND, S(Gen), NF

  Profile the type of S0.

| ProfileMethod<rdsHandle>, ND, S(Cls) S(Func), NF

  Profile the method S1 called with class context S0.

| CheckPackedArrayDataBounds, ND, S(AK(Packed),Vec) S(Int), B

  Checks that the index in S1 is within the bounds of the packed array or
  vector array in S0. Branches to B if the index is out of bounds.

| LdPackedArrayDataElemAddr<T>, DParam(LvalToElemGen), S(AK(Packed),Vec) S(Int), NF

  Loads the address of the element at index S1 of the packed array or vec array
  in S0. This instruction assumes the array actually contains an element at
  that offset (IE, the array has the proper length).

| ReservePackedArrayDataNewElem, D(Int), S(AK(Packed),Vec), B

  If there is room in the packed or vec array (which is assumed to be mutable),
  increments the array size and returns the index of the new last element
  (which you must initialize); else jumps to the taken branch.

| LdPackedElem, DArrElem, S(AK(Packed)) S(Int), NF

  Loads the element of the packed array in S0 at offset S1. This instruction
  assumes that the vec actually contains an element at that offset (IE, the
  array has the proper length).

| LdVecElem, DVecElem, S(Vec) S(Int), NF

  Loads the element of the vec array in S0 at offset S1. This instruction
  assumes that the vec actually contains an element at that offset (IE, the vec
  has the proper length).

| LdVectorSize, D(Int), S(Obj), NF

  Returns the size of the given Vector collection in S0.

| ColIsEmpty, D(Bool), S(Obj), NF

| ColIsNEmpty, D(Bool), S(Obj), NF

  Returns whether a collection instance is empty or not.  S0 must be known to
  be an instance of a collection class at compile time.


| VecFirst, DVecFirstElem, S(Vec,AK(Packed)), NF

  Returns the first value from the packed or vec array in S0.
  If the array is empty, it will return NULL.

| VecLast, DVecLastElem, S(Vec,AK(Packed)), NF

  Returns the last value from the packed or vec array in S0.
  If the array is empty, it will return NULL.

| DictFirst, DDictFirstElem, S(Dict,AK(Mixed)), NF

  Returns the first value from the mixed or dict array in S0.
  If the array is empty, it will return NULL.

| DictLast, DDictLastElem, S(Dict,AK(Mixed)), NF

  Returns the last value from the mixed or dict array in S0.
  If the array is empty, it will return NULL.

| DictFirstKey, DDictFirstKey, S(Dict,AK(Mixed)), NF

  Returns the first key from the mixed or dict array in S0.
  If the array is empty, it will return NULL.

| DictLastKey, DDictLastKey, S(Dict,AK(Mixed)), NF

  Returns the last key from the mixed or dict array in S0.
  If the array is empty, it will return NULL.

| KeysetFirst, DKeysetFirstElem, S(Keyset), NF

  Returns the first value(key) from the keyset in S0.
  If the array is empty, it will return NULL.

| KeysetLast, DKeysetLastElem, S(Keyset), NF

  Returns the first value(key) from the keyset in S0.
  If the array is empty, it will return NULL.


19. Exception/unwinding support

| BeginCatch, ND, NA, NF

  Marks the beginning of a catch region. Exact behavior is implementation and
  architecture specific.

| EndCatch<spOffset>, ND, S(FramePtr) S(StkPtr), T

  Marks the end of a catch region and returns control to the unwinder.  The
  `spOffset' field represents a logical adjustment to S1 (in cells) to yield
  the vm stack pointer, however the stack pointer is not actually adjusted
  before this instruction returns control to the unwinder.  The unwinder
  instead relies on fixup map information to find the appropriate stack
  pointers.  Instead it's part of this instruction to facilitate assertions and
  memory effect analysis.

| UnwindCheckSideExit, ND, S(FramePtr) S(StkPtr), B

  Branches to B if the currently executing catch region should return control
  to the unwinder rather than side exiting.  Used to control behavior in catch
  traces for the InvalidSetMException and TVCoercionException situations.

| LdUnwinderValue<T>, DParam(Cell), NA, PRc

  Loads the value contained by the current unwinder exception.


20. Function prologues

| EnterFrame, ND, S(FramePtr), NF

  Stash the return address of the call in m_savedRip.

| CheckStackOverflow, ND, S(FramePtr), NF

  Check if the stack depth has exceeded its limit.  If it has, jump to the
  stack overflow helper stub, which will throw.

| InitExtraArgs<func,argc>, ND, S(FramePtr), NF

  Set up the ExtraArgs struct on the live ActRec.  If extra args are present
  and need to be discarded, they will be decref'd and may re-enter to run
  destructors.

| InitCtx, ND, S(FramePtr) S(Ctx,Nullptr), CRc

  Store S1 to the m_this/m_cls field in the frame pointer S0.

  If InitCtx appears in an IR unit, it must dominate all occurrences of LdCtx
  and LdCctx with the same FramePtr.

| CheckSurpriseFlagsEnter<func,argc>, ND, S(FramePtr), NF

  Test the implementation-specific surprise flags.  If they're nonzero, call
  the function enter helper.

| CheckSurpriseAndStack<func,args>, ND, S(FramePtr), NF

  Test surprise flags and stack overflow at the same time.

| CheckARMagicFlag, ND, S(FramePtr), B

  If the MagicDispatch flags on the ActRec pointed to by the frame pointer S0
  are not set, branch to block B.

| LdARNumArgsAndFlags, D(Int), S(FramePtr), NF

  Load the value of m_numArgsAndFlags on the ActRec pointed to by the frame
  pointer S0.

| StARNumArgsAndFlags, ND, S(FramePtr) S(Int), NF

  Store S1 to m_numArgsAndFlags on the ActRec pointed to by the frame pointer
  S0.

| LdARInvName, D(Str), S(FramePtr), NF

  Load the value of m_invName off the ActRec pointed to by the frame pointer S0.
  The compiler should generate this only if it knows that m_invName is a
  StringData* (rather than, e.g., a VarEnv*).

| StARInvName, ND, S(FramePtr) S(Str,Nullptr), CRc

  Store S1 to m_invName on the ActRec pointed to by the frame pointer S0.

| PackMagicArgs, DVArr, S(FramePtr), PRc

  Call PackedArray::MakeVArray() with the value of numArgs() on the ActRec
  pointed to by the frame pointer S0 as the first argument, and the pointer to
  the first parameter in the frame as the second argument.

| LdTVAux<ValidBits>, D(Int), S(Gen), NF

  Load the value of m_aux from the TypedValue S0.  ValidBits is a mask
  specifying which bits are allowed to be set.  The runtime may ignore it.

  Note that when we pass TypedValues around in registers, we usually use a byte
  register for the m_type member, and thus ignore m_aux.  LdTVAux is only valid
  when we know that S0's m_type and m_aux were both materialized into the same
  64-bit register.

| LdARReifiedGenerics, DVArr, S(FramePtr), NF

  Load the value of m_reifiedGenerics on the ActRec pointed to by the frame
  pointer S0.

| KillARReifiedGenerics, ND, S(FramePtr), NF

  Mark the ActRec's m_reifiedGenerics pointer in frame S0 as no longer
  containing a meaningful value. This can used to aid in memory analysis.
  In debugging builds, it may overwrite the pointer with a poison value.

/* Local Variables: */
/* fill-column: 79 */
/* End: */
vim:textwidth=80
