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

# [SMDOC] MIR Opcodes
# =======================
# This file defines all MIR opcodes. It is parsed by GenerateMIRFiles.py
# at build time to create MIROpsGenerated.h. Each opcode consists of a
# name and a set of attributes that are described below. A few of the
# attributes below allow setting the value to "custom", meaning the
# method will be declared for the MIR op, but will need to be implemented
# in C++ (typically done in MIR.cpp). Unless marked as required, attributes
# are optional.
#
# name [required]
# ====
# Opcode name.
# Possible values:
#   - opcode string: used as the name for MIR opcode.
#
# gen_boilerplate
# ===============
# Used to decide to generate MIR boilerplate.
#   - true (default): auto generate boilerplate for this MIR opcode
#   - false: do not generate boilerplate for this MIR opcode
#
# operands
# ========
# A list of operands for the MIR op class constructor. Each operand is a
# MIR node. The operand kind is specified from the one of the kinds from
# the MIRType enum in IonTypes.h or `any` if the operand has no specific type.
# The specified types for the operands will decide the type policy for the
# instruction.
#
# The naming of operands is how the NAMED_OPERANDS macro will define
# its operands.
#
# For example:
#   object: Object
#   id: Value
#   value: Object
#
# Will result in an instruction having the type policy of:
#   MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>
# and a named operands definition that looks like the following:
#   NAMED_OPERANDS((0, object), (1, idValue), (2, value))
#
#   - attribute not specified (default): no code generated
#   - operand list: MIRTypes (See MIRType in jit/IonTypes.h)
#
# arguments
# =========
# A list of non-MIR node arguments to the MIR op class constructor
# that are passed along with the operands. The arguments require
# both a name and a full type signature for each item in the list.
#
# For example:
#   templateObject: JSObject*
#   initialHeap: gc::Heap
#
# For each argument a private variable declaration will be autogenerated
# in the MIR op class, as well as simple accessor for that variable. If
# the type of the variable is a GC pointer it will by automatically
# wrapped by CompilerGCPointer. The above arguments list will result in
# the following declarations and accessors:
#
#   CompilerGCPointer<JSObject*> templateObject_;
#   gc::Heap initialHeap_;
#
#   JSObject* templateObject() const { return templateObject_; }
#   gc::Heap initialHeap() const { return initialHeap_; }
#
#   - attribute not specified (default): no code generated
#   - operand list: argument names and their full type signature
#
# type_policy
# ============
# If this attribute is present, then the type policy for that opcode will be
# NoTypePolicy. This is used for opcode that should have no type policy.
#   - attribute not specified (default): no code generated, type policy
#     is based off of operands
#   - none: defines the type policy as opcode's NoTypePolicy
#
# result_type
# ===========
# Defines the result type of the MIR opcode.
#   - attribute not specified (default): no code is generated
#   - MIRType string: Will add a call to setResultType to the opcode constructor.
#                   This will set the MIR opcodes result type to whatever the
#                   specified MIRType is (See MIRType in jit/IonTypes.h).
#
# guard
# =====
# Set if the opcode is a guard instruction and is used for checks in optimizations
# such as range analysis and value numbering.
#   - attribute not specified (default): no code generated
#   - true: adds setGuard to opcode constructor
#
# movable
# =======
# Defines the movable MIR flag for movable instructions. This is used for knowing
# whether we can hoist an instruction.
#   - attribute not specified (default): no code generated
#   - true: adds setMovable call in opcode constructor
#
# folds_to
# ========
# The foldsTo method is used for determining if an instruction can be folded into
# simpler instruction or for constant folding, depending on its operands.
#   - attribute not specified (default): no code generated, no constants to fold
#   - custom: custom C++ implementation
#
# value_hash
# ==========
# Used by ValueNumbering to determine the hash number for the instruction.
#   - attribute not specified (default): no code generated, inherit valueHash from
#     the base class
#   - custom: custom C++ implementation
#
# congruent_to
# ============
# Used by ValueNumbering to determine if two values are congruent.
#   - attribute not specified (default): no code generated, congruentTo(foo) returns
#     false
#   - if_operands_equal: congruentTo(foo) will return congruentIfOperandsEqual(foo)
#   - if_operands_equal_ignore_arguments: congruentTo(foo) will return congruentIfOperandsEqual(foo), but ignore any arguments
#   - if_operands_and_arguments_equal: congruentTo(foo) will return congruentIfOperandsEqual(foo) and all arguments are equal
#   - custom: custom C++ implementation
#
# alias_set
# =========
# Defines the getAliasSet function for a MIR op. The alias set is used for alias
# analysis. The default alias set is Any.
#   - attribute not specified (default): no code generated, alias set is Any
#   - none: this is the most common case, this is will set the alias set to None.
#   - custom: custom C++ implementation in MIR.cpp
#   - dictionary with keys "load" and "store" whose value is a single alias set flag or a list of alias set flags.
#     Valid alias set flags are the enum values of `AliasSet::Flag` defined in MIR.h.
#
#     Examples:
#       alias_set:
#         load: Any
#
#       alias_set:
#         store:
#           - ObjectFields
#           - Element
#
# possibly_calls
# ==============
# Defines if a opcode can possibly call.
#   - attribute not specified (default): no code generated, opcode does not call
#   - true: possiblyCalls returns true
#   - custom: custom C++ implementation
#
# compute_range
# =============
# Computes and sets the range value for a MIR node, which is then used in range
# analysis.
#   - attribute not specified (default): no code generated, range is not set for node
#   - custom: custom C++ implementation in RangeAnalysis.cpp
#
# can_recover
# ===========
# Indicates whether this instruction can be recovered on bailout.
# Possible values:
#   - attribute not specified (default): no code generated, canRecoverOnBailout
#     returns false
#   - true: canRecoverOnBailout returns true
#   - custom: canRecoverOnBailout has a custom C++ implementation
# If the value is either 'true' or 'custom', writeRecoverData has a custom C++
# implementation.
#
# clone
# =====
# Allows cloning for that MIR op.
#   - attribute not specified (default): no code generated
#   - true: allows cloning
#
# can_consume_float32
# ===================
# Indicates whether this instruction's operands can have MIRType::Float32.
# Possible values:
#   - attribute not specified (default): no code generated
#   - true: canConsumeFloat32 returns true
#
# generate_lir
# ===================
# Controls whether to generate direct 1-1 mapping LIR instruction for the MIR op
# Possible values:
#   - attribute not specified (default): no code generated
#   - true: generates corresponding LIR classes in LIROpsGenerated.h
#
# lir_temps, lir_temp64s, lir_temp_boxes
# ======================================
# Specifies the number of temporary virtual registers, LDefinitions, used by
# the corresponding LIR op in the case generate_lir is true. The temp can be
# either a single LDefinition, a LInt64Definition, or a LBoxDefinition
# depending on the variant used.
#
# Possible values:
#   - attribute not specified (default): number of temps is set to 0
#   - number: sets number of temps max 15
#
# lir_result_type
# ===============
# Specifies the result_type of the corresponding LIR op in case generate_lir is
# true.
# Possible values:
#   - attribute not specified (default): the LIR result type is based on the MIR
#     op's result_type
#   - none: the LIR instruction does not produce a result
#   - result type: the LIR op's result type

# TODO(no-TI): try to remove this instruction.
- name: Start

# Instruction marking on entrypoint for on-stack replacement.
# OSR may occur at loop headers (at JSOp::LoopHead).
# There is at most one MOsrEntry per MIRGraph.
- name: OsrEntry
  result_type: Pointer

- name: Nop
  alias_set: none
  clone: true

- name: LimitedTruncate
  gen_boilerplate: false

# Truncation barrier. This is intended for protecting its input against
# follow-up truncation optimizations.
- name: IntPtrLimitedTruncate
  operands:
    input: IntPtr
  result_type: IntPtr
  type_policy: none
  alias_set: none
  movable: true

# Truncation barrier. This is intended for protecting its input against
# follow-up truncation optimizations.
- name: Int64LimitedTruncate
  operands:
    input: Int64
  result_type: Int64
  type_policy: none
  alias_set: none
  movable: true

- name: Constant
  gen_boilerplate: false

- name: WasmNullConstant
  gen_boilerplate: false

- name: WasmFloatConstant
  gen_boilerplate: false

- name: Parameter
  gen_boilerplate: false

- name: Callee
  result_type: Object
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  can_recover: true
  generate_lir: true

- name: IsConstructing
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: TableSwitch
  gen_boilerplate: false

- name: Goto
  gen_boilerplate: false

- name: Test
  gen_boilerplate: false

- name: Return
  gen_boilerplate: false

- name: Throw
  operands:
    value: Value
  alias_set:
    store: ExceptionState
  possibly_calls: true
  generate_lir: true

- name: ThrowWithStack
  operands:
    value: Value
    stack: Value
  alias_set:
    store: ExceptionState
  possibly_calls: true
  generate_lir: true

- name: NewArray
  gen_boilerplate: false

- name: NewArrayDynamicLength
  operands:
    length: Int32
  arguments:
    templateObject: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  # Need to throw if length is negative.
  guard: true
  # Throws if length is negative.
  alias_set:
    store: ExceptionState
  generate_lir: true
  lir_temps: 1

- name: NewTypedArray
  gen_boilerplate: false

- name: NewTypedArrayDynamicLength
  operands:
    length: Int32
  arguments:
    templateObject: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  guard: true
  # Throws if length is negative.
  alias_set:
    store: ExceptionState
  possibly_calls: true
  generate_lir: true
  lir_temps: 3

# Create a new TypedArray from an Array (or Array-like object) or a TypedArray.
- name: NewTypedArrayFromArray
  operands:
    array: Object
  arguments:
    templateObject: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  guard: true
  possibly_calls: true
  generate_lir: true

# Create a new TypedArray from an ArrayBuffer (or SharedArrayBuffer).
- name: NewTypedArrayFromArrayBuffer
  operands:
    arrayBuffer: Object
    byteOffset: Value
    length: Value
  arguments:
    templateObject: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  guard: true
  possibly_calls: true
  generate_lir: true

- name: NewMapObject
  arguments:
    templateObject: JSObject*
  result_type: Object
  possibly_calls: true

- name: NewSetObject
  arguments:
    templateObject: JSObject*
  result_type: Object
  possibly_calls: true

- name: NewMapObjectFromIterable
  operands:
    iterable: Value
  arguments:
    templateObject: JSObject*
  result_type: Object
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

- name: NewSetObjectFromIterable
  operands:
    iterable: Value
  arguments:
    templateObject: JSObject*
  result_type: Object
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

- name: NewObject
  gen_boilerplate: false

- name: NewPlainObject
  gen_boilerplate: false

- name: NewArrayObject
  gen_boilerplate: false

- name: NewIterator
  gen_boilerplate: false

- name: ObjectState
  gen_boilerplate: false

- name: ArrayState
  gen_boilerplate: false

- name: BindFunction
  gen_boilerplate: false

- name: NewBoundFunction
  arguments:
    templateObj: JSObject*
  result_type: Object
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: BoundFunctionNumArgs
  operands:
    object: Object
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  # A bound function's state is immutable, so there is no
  # implicit dependency.
  alias_set: none
  generate_lir: true

- name: GuardBoundFunctionIsConstructor
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # The is-constructor flag is immutable for a bound function.
  alias_set: none
  generate_lir: true
  lir_result_type: none

# Setting __proto__ in an object literal.
- name: MutateProto
  operands:
    object: Object
    value: Value
  result_type: None
  possibly_calls: true
  generate_lir: true

- name: InitPropGetterSetter
  operands:
    object: Object
    value: Object
  arguments:
    name: PropertyName*
  possibly_calls: true
  generate_lir: true

- name: InitElemGetterSetter
  operands:
    object: Object
    id: Value
    value: Object
  possibly_calls: true
  generate_lir: true

- name: Call
  gen_boilerplate: false

- name: CallClassHook
  gen_boilerplate: false

- name: ApplyArgs
  gen_boilerplate: false

- name: ApplyArgsObj
  gen_boilerplate: false

- name: ApplyArray
  gen_boilerplate: false

- name: ConstructArgs
  gen_boilerplate: false

- name: ConstructArray
  gen_boilerplate: false

- name: Bail
  gen_boilerplate: false
  generate_lir: true

- name: Unreachable
  gen_boilerplate: false

# This op serves as a way to force the encoding of a snapshot, even if there
# is no resume point using it.  This is useful to run MAssertRecoveredOnBailout
# assertions.
- name: EncodeSnapshot
  guard: true
  generate_lir: true

- name: AssertRecoveredOnBailout
  gen_boilerplate: false

- name: AssertFloat32
  operands:
    value: any
  arguments:
    mustBeFloat32: bool
  result_type: None
  type_policy: none
  can_consume_float32: true

- name: Compare
  gen_boilerplate: false

- name: StrictConstantCompareInt32
  operands:
    value: Value
  arguments:
    constant: int32_t
    jsop: JSOp
  can_recover: true
  movable: true
  alias_set: none
  folds_to: custom
  result_type: Boolean
  generate_lir: true
  lir_temps: 1

- name: StrictConstantCompareBoolean
  operands:
    value: Value
  arguments:
    constant: bool
    jsop: JSOp
  can_recover: true
  movable: true
  alias_set: none
  folds_to: custom
  result_type: Boolean
  generate_lir: true

- name: SameValueDouble
  operands:
    left: Double
    right: Double
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  clone: true
  generate_lir: true
  lir_temps: 1

- name: SameValue
  operands:
    left: Value
    right: Value
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  clone: true
  generate_lir: true

- name: Box
  gen_boilerplate: false

- name: Unbox
  gen_boilerplate: false

- name: AssertRange
  gen_boilerplate: false

- name: AssertClass
  gen_boilerplate: false

- name: AssertShape
  operands:
    object: Object
  arguments:
    shape: Shape*
  type_policy: none
  alias_set: none
  guard: true
  generate_lir: true

# Caller-side allocation of |this| for |new|:
# Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
- name: CreateThis
  operands:
    callee: Object
    newTarget: Object
  result_type: Value
  # Performs a property read from |newTarget| iff |newTarget| is a JSFunction
  # with an own |.prototype| property.
  alias_set:
    load: Any
  possibly_calls: true
  generate_lir: true

# Eager initialization of arguments object.
- name: CreateArgumentsObject
  operands:
    callObject: Object
  arguments:
    templateObject: ArgumentsObject*
  result_type: Object
  alias_set: none
  possibly_calls: true
  can_recover: true
  generate_lir: true
  lir_temps: 3

- name: CreateInlinedArgumentsObject
  gen_boilerplate: false

- name: GetInlinedArgument
  gen_boilerplate: false

- name: GetInlinedArgumentHole
  gen_boilerplate: false

# Get argument from arguments object.
- name: GetArgumentsObjectArg
  operands:
    argsObject: Object
  arguments:
    argno: size_t
  result_type: Value
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load: Any
  generate_lir: true
  lir_temps: 1

# Set argument on arguments object.
- name: SetArgumentsObjectArg
  operands:
    argsObject: Object
    value: Value
  arguments:
    argno: size_t
  alias_set:
    store: Any
  generate_lir: true
  lir_temps: 1

# Load |arguments[index]| from a mapped or unmapped arguments object. Bails out
# when any elements were overridden or deleted. Also bails out if the index is
# out of bounds.
- name: LoadArgumentsObjectArg
  operands:
    argsObject: Object
    index: Int32
  result_type: Value
  guard: true
  congruent_to: if_operands_equal
  alias_set:
    load: Any
  generate_lir: true
  lir_temps: 1

# Load |arguments[index]| from a mapped or unmapped arguments object. Bails out
# when any elements were overridden or deleted. Returns undefined if the index is
# out of bounds.
- name: LoadArgumentsObjectArgHole
  operands:
    argsObject: Object
    index: Int32
  result_type: Value
  guard: true
  congruent_to: if_operands_equal
  alias_set:
    load: Any
  generate_lir: true
  lir_temps: 1

- name: InArgumentsObjectArg
  operands:
    argsObject: Object
    index: Int32
  result_type: Boolean
  guard: true
  congruent_to: if_operands_equal
  # Loads |arguments.length|, but not the actual element, so we can use the
  # same alias-set as ArgumentsObjectLength.
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true
  lir_temps: 1

# Load |arguments.length|. Bails out if the length has been overriden.
- name: ArgumentsObjectLength
  operands:
    argsObject: Object
  result_type: Int32
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # Even though the "length" property is lazily resolved, it acts similar to
  # a normal property load, so we can treat this operation like any other
  # property read.
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true

# Create an array from an arguments object.
- name: ArrayFromArgumentsObject
  operands:
    argsObject: Object
  arguments:
    shape: Shape*
  result_type: Object
  possibly_calls: true
  generate_lir: true

# Guard that the given flags are not set on the arguments object.
- name: GuardArgumentsObjectFlags
  operands:
    argsObject: Object
  arguments:
    flags: uint32_t
  result_type: Object
  movable: true
  guard: true
  congruent_to: if_operands_and_arguments_equal
  # The flags are packed with the length in a fixed private slot.
  alias_set:
    load: FixedSlot
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

# Guard cx->realm() == obj->realm().
- name: GuardObjectHasSameRealm
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # The object's realm is immutable. The context's realm must always be the same
  # realm for this compilation.
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: LoadScriptedProxyHandler
  operands:
    object: Object
  result_type: Object
  guard: true
  congruent_to: if_operands_equal
  # The handler slot is cleared when the proxy is revoked.
  alias_set:
    load: ObjectFields
  generate_lir: true

#ifdef JS_PUNBOX64
- name: CheckScriptedProxyGetResult
  operands:
    target: Value
    id: Value
    value: Value
  guard: true
  alias_set:
    store: ExceptionState
  generate_lir: true
  lir_temps: 2
#endif

- name: IdToStringOrSymbol
  operands:
    idVal: Value
  result_type: Value
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  generate_lir: true
  lir_temps: 1

# Given a MIRType::Value A and a MIRType::Object B:
# If the Value may be safely unboxed to an Object, return Object(A).
# Otherwise, return B.
# Used to implement return behavior for inlined constructors.
- name: ReturnFromCtor
  operands:
    value: Value
    object: Object
  result_type: Object
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: ToDouble
  gen_boilerplate: false

- name: ToFloat32
  gen_boilerplate: false

- name: ToFloat16
  gen_boilerplate: false

# Converts a uint32 to a double (coming from wasm).
- name: WasmUnsignedToDouble
  operands:
    def: Int32
  type_policy: none
  result_type: Double
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  clone: true

- name: WasmUnsignedToFloat32
  gen_boilerplate: false

- name: WrapInt64ToInt32
  operands:
    input: Int64
  arguments:
    bottomHalf: bool
  result_type: Int32
  type_policy: none
  alias_set: none
  movable: true
  clone: true
  congruent_to: if_operands_and_arguments_equal
  folds_to: custom
  generate_lir: true

- name: ExtendInt32ToInt64
  operands:
    input: Int32
  arguments:
    isUnsigned: bool
  result_type: Int64
  type_policy: none
  alias_set: none
  movable: true
  clone: true
  congruent_to: if_operands_and_arguments_equal
  folds_to: custom
  generate_lir: true

- name: WasmBuiltinTruncateToInt64
  gen_boilerplate: false

- name: WasmTruncateToInt64
  gen_boilerplate: false

- name: WasmTruncateToInt32
  gen_boilerplate: false

- name: WasmAnyRefFromJSValue
  operands:
    def: Value
  result_type: WasmAnyRef
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1
  lir_temp_boxes: 1

- name: WasmAnyRefFromJSObject
  operands:
    def: Object
  type_policy: none
  result_type: WasmAnyRef
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  generate_lir: true

- name: WasmAnyRefFromJSString
  operands:
    def: String
  type_policy: none
  result_type: WasmAnyRef
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: WasmAnyRefIsJSString
  operands:
    input: WasmAnyRef
  type_policy: none
  result_type: Int32
  congruent_to: if_operands_equal
  alias_set: none
  movable: true
  clone: true
  generate_lir: true
  lir_temps: 1

- name: WasmTrapIfAnyRefIsNotJSString
  operands:
    input: WasmAnyRef
  arguments:
    trap: wasm::Trap
    trapSiteDesc: wasm::TrapSiteDesc
  type_policy: none
  congruent_to: if_operands_equal_ignore_arguments
  alias_set: none
  guard: true
  clone: true
  generate_lir: true
  lir_temps: 1

- name: WasmAnyRefJSStringLength
  operands:
    input: WasmAnyRef
  arguments:
    trap: wasm::Trap
    trapSiteDesc: wasm::TrapSiteDesc
  type_policy: none
  result_type: Int32
  congruent_to: if_operands_equal_ignore_arguments
  alias_set: none
  guard: true
  clone: true
  generate_lir: true
  lir_temps: 1

- name: WasmNewI31Ref
  gen_boilerplate: false

- name: WasmI31RefGet
  operands:
    input: WasmAnyRef
  arguments:
    wideningOp: wasm::FieldWideningOp
  type_policy: none
  result_type: Int32
  congruent_to: if_operands_and_arguments_equal
  alias_set: none
  generate_lir: true

- name: Int32ToIntPtr
  gen_boilerplate: false

# Converts an IntPtr value >= 0 to Int32. Bails out if the value > INT32_MAX.
- name: NonNegativeIntPtrToInt32
  operands:
    input: IntPtr
  result_type: Int32
  type_policy: none
  alias_set: none
  movable: true
  congruent_to: if_operands_equal
  compute_range: custom
  generate_lir: true

# Converts an IntPtr value to Double.
- name: IntPtrToDouble
  operands:
    input: IntPtr
  result_type: Double
  type_policy: none
  alias_set: none
  movable: true
  congruent_to: if_operands_equal
  generate_lir: true

- name: AdjustDataViewLength
  gen_boilerplate: false

- name: Int64ToFloatingPoint
  gen_boilerplate: false

- name: BuiltinInt64ToFloatingPoint
  gen_boilerplate: false

- name: ToNumberInt32
  gen_boilerplate: false

- name: BooleanToInt32
  operands:
    input: Boolean
  result_type: Int32
  movable: true
  compute_range: custom
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none

- name: TruncateToInt32
  gen_boilerplate: false

- name: WasmBuiltinTruncateToInt32
  gen_boilerplate: false

- name: ToBigInt
  gen_boilerplate: false

- name: ToInt64
  gen_boilerplate: false

# Takes a BigInt pointer and returns its toInt64 value.
- name: TruncateBigIntToInt64
  operands:
    input: BigInt
  result_type: Int64
  type_policy: none
  alias_set: none
  movable: true
  clone: true
  congruent_to: if_operands_equal
  folds_to: custom
  generate_lir: true

# Takes an Int64 and returns a fresh BigInt pointer.
- name: Int64ToBigInt
  operands:
    input: Int64
  arguments:
    isSigned: bool
  result_type: BigInt
  type_policy: none
  alias_set: none
  movable: true
  clone: true
  can_recover: true
  congruent_to: if_operands_and_arguments_equal
  generate_lir: true
  lir_temps64: 1

# Takes an Int64 and returns a IntPtr.
- name: Int64ToIntPtr
  operands:
    input: Int64
  arguments:
    isSigned: bool
  result_type: IntPtr
  type_policy: none
  alias_set: none
  movable: true
  clone: true
  congruent_to: if_operands_and_arguments_equal
  generate_lir: true

# Takes a IntPtr and returns an Int64.
- name: IntPtrToInt64
  operands:
    input: IntPtr
  result_type: Int64
  type_policy: none
  alias_set: none
  movable: true
  clone: true
  congruent_to: if_operands_and_arguments_equal
  generate_lir: true

- name: ToString
  gen_boilerplate: false

- name: BitNot
  gen_boilerplate: false

- name: TypeOf
  gen_boilerplate: false

- name: TypeOfName
  operands:
    input: Int32
  result_type: String
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  can_recover: true
  generate_lir: true

- name: TypeOfIs
  gen_boilerplate: false

- name: ToAsyncIter
  operands:
    iterator: Object
    nextMethod: Value
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: ToPropertyKeyCache
  operands:
    input: Value
  result_type: Value
  generate_lir: true

- name: BitAnd
  gen_boilerplate: false

- name: BitOr
  gen_boilerplate: false

- name: BitXor
  gen_boilerplate: false

- name: Lsh
  gen_boilerplate: false

- name: Rsh
  gen_boilerplate: false

- name: Ursh
  gen_boilerplate: false

- name: SignExtendInt32
  gen_boilerplate: false

- name: SignExtendInt64
  gen_boilerplate: false

- name: SignExtendIntPtr
  gen_boilerplate: false

- name: MinMax
  gen_boilerplate: false

- name: MinMaxArray
  gen_boilerplate: false

- name: Abs
  gen_boilerplate: false

- name: Clz
  gen_boilerplate: false

- name: Ctz
  gen_boilerplate: false

- name: Popcnt
  gen_boilerplate: false

- name: Sqrt
  gen_boilerplate: false

- name: CopySign
  gen_boilerplate: false

# Inline implementation of atan2 (arctangent of y/x).
- name: Atan2
  operands:
    y: Double
    x: Double
  result_type: Double
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  can_recover: true
  clone: true

- name: Hypot
  gen_boilerplate: false

- name: Pow
  gen_boilerplate: false

- name: PowHalf
  gen_boilerplate: false

- name: Random
  result_type: Double
  alias_set:
    store: RNG
  compute_range: custom
  can_recover: custom
  clone: true
  generate_lir: true
  lir_temps: 1
  lir_temps64: 2

- name: Sign
  gen_boilerplate: false

- name: MathFunction
  gen_boilerplate: false

- name: Add
  gen_boilerplate: false

- name: Sub
  gen_boilerplate: false

- name: Mul
  gen_boilerplate: false

- name: Div
  gen_boilerplate: false

- name: WasmBuiltinDivI64
  gen_boilerplate: false

- name: Mod
  gen_boilerplate: false

- name: WasmBuiltinModD
  gen_boilerplate: false

- name: WasmBuiltinModI64
  gen_boilerplate: false

- name: BigIntAdd
  gen_boilerplate: false

- name: BigIntSub
  gen_boilerplate: false

- name: BigIntMul
  gen_boilerplate: false

- name: BigIntDiv
  gen_boilerplate: false

- name: BigIntMod
  gen_boilerplate: false

- name: BigIntPow
  gen_boilerplate: false

- name: BigIntBitAnd
  gen_boilerplate: false

- name: BigIntBitOr
  gen_boilerplate: false

- name: BigIntBitXor
  gen_boilerplate: false

- name: BigIntLsh
  gen_boilerplate: false

- name: BigIntRsh
  gen_boilerplate: false

- name: BigIntIncrement
  gen_boilerplate: false

- name: BigIntDecrement
  gen_boilerplate: false

- name: BigIntNegate
  gen_boilerplate: false

- name: BigIntBitNot
  gen_boilerplate: false

- name: BigIntToIntPtr
  operands:
    input: BigInt
  result_type: IntPtr
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  can_recover: true
  clone: true
  generate_lir: true

- name: IntPtrToBigInt
  operands:
    input: IntPtr
  result_type: BigInt
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  can_recover: true
  clone: true
  generate_lir: true
  lir_temps: 1

- name: BigIntPtrAdd
  gen_boilerplate: false

- name: BigIntPtrSub
  gen_boilerplate: false

- name: BigIntPtrMul
  gen_boilerplate: false

- name: BigIntPtrDiv
  gen_boilerplate: false

- name: BigIntPtrMod
  gen_boilerplate: false

- name: BigIntPtrPow
  gen_boilerplate: false

- name: BigIntPtrBitAnd
  gen_boilerplate: false

- name: BigIntPtrBitOr
  gen_boilerplate: false

- name: BigIntPtrBitXor
  gen_boilerplate: false

- name: BigIntPtrLsh
  gen_boilerplate: false

- name: BigIntPtrRsh
  gen_boilerplate: false

- name: BigIntPtrBitNot
  gen_boilerplate: false

- name: Int32ToStringWithBase
  operands:
    input: Int32
    base: Int32
  arguments:
    stringCase: StringCase
  result_type: String
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set: none
  generate_lir: true
  lir_temps: 2

- name: NumberParseInt
  operands:
    string: String
    radix: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 1

- name: DoubleParseInt
  operands:
    number: Double
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: Concat
  gen_boilerplate: false

- name: LinearizeString
  operands:
    string: String
  result_type: String
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  generate_lir: true

- name: LinearizeForCharAccess
  operands:
    string: String
    index: Int32
  result_type: String
  movable: true
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  generate_lir: true

- name: LinearizeForCodePointAccess
  operands:
    string: String
    index: Int32
  result_type: String
  movable: true
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: ToRelativeStringIndex
  operands:
    index: Int32
    length: Int32
  result_type: Int32
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: CharCodeAt
  operands:
    string: String
    index: Int32
  result_type: Int32
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  compute_range: custom
  can_recover: true
  clone: true
  generate_lir: true
  lir_temps: 2

# Similar to CharCodeAt, but returns a negative value on out-of-bounds access.
- name: CharCodeAtOrNegative
  operands:
    string: String
    index: Int32
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  generate_lir: true
  lir_temps: 2

- name: CodePointAt
  operands:
    string: String
    index: Int32
  result_type: Int32
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  compute_range: custom
  clone: true
  generate_lir: true
  lir_temps: 2

# Similar to CodePointAt, but returns a negative value on out-of-bounds access.
- name: CodePointAtOrNegative
  operands:
    string: String
    index: Int32
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  # Strings are immutable, so there is no implicit dependency.
  alias_set: none
  generate_lir: true
  lir_temps: 2

# Return the input if non-negative, otherwise return NaN.
- name: NegativeToNaN
  operands:
    input: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

# Return the input if non-negative, otherwise return undefined.
- name: NegativeToUndefined
  operands:
    input: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

# Convert uint16 character code to a string.
- name: FromCharCode
  operands:
    code: Int32
  result_type: String
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  can_recover: true
  clone: true
  generate_lir: true

# Similar to FromCharCode, but returns the empty string if the input is negative.
- name: FromCharCodeEmptyIfNegative
  operands:
    code: Int32
  result_type: String
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  can_recover: true
  clone: true
  generate_lir: true

# Similar to FromCharCode, but returns the |undefined| if the input is negative.
- name: FromCharCodeUndefinedIfNegative
  operands:
    code: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

# Convert uint32 code point to a string.
- name: FromCodePoint
  operands:
    codePoint: Int32
  result_type: String
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  clone: true
  generate_lir: true
  lir_temps: 2

# Test if a string includes the search string.
- name: StringIncludes
  operands:
    string: String
    searchString: String
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

# Search for the first index of the search string.
- name: StringIndexOf
  operands:
    string: String
    searchString: String
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

# Search for the last index of the search string.
- name: StringLastIndexOf
  operands:
    string: String
    searchString: String
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

# Test if a string starts with the search string.
- name: StringStartsWith
  operands:
    string: String
    searchString: String
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

# Test if a string ends with the search string.
- name: StringEndsWith
  operands:
    string: String
    searchString: String
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

- name: StringConvertCase
  operands:
    string: String
  arguments:
    stringCase: StringCase
  result_type: String
  movable: true
  possibly_calls: true
  alias_set: none
  congruent_to: if_operands_and_arguments_equal
  folds_to: custom

- name: CharCodeConvertCase
  operands:
    code: Int32
  arguments:
    stringCase: StringCase
  result_type: String
  movable: true
  alias_set: none
  congruent_to: if_operands_and_arguments_equal

# Index of first non-whitespace character.
- name: StringTrimStartIndex
  operands:
    string: String
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

# Index of last non-whitespace character.
- name: StringTrimEndIndex
  operands:
    string: String
    start: Int32
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  possibly_calls: true
  generate_lir: true

- name: StringSplit
  operands:
    string: String
    separator: String
  result_type: Object
  possibly_calls: true
  # Although this instruction returns a new array, we don't have to mark
  # it as store instruction, see also MNewArray.
  alias_set: none
  can_recover: true
  generate_lir: true

- name: BoxNonStrictThis
  operands:
    def: ValueOrObject
  arguments:
    globalThis: JSObject*
  result_type: Object
  folds_to: custom
  possibly_calls: true
  # This instruction can allocate a new object for wrapped primitives, but
  # has no effect on existing objects.
  alias_set: none

- name: ImplicitThis
  operands:
    env: Object
  result_type: Value
  generate_lir: true

- name: Phi
  gen_boilerplate: false

- name: Beta
  gen_boilerplate: false

- name: NaNToZero
  gen_boilerplate: false

- name: OsrValue
  gen_boilerplate: false

- name: OsrEnvironmentChain
  gen_boilerplate: false

- name: OsrArgumentsObject
  gen_boilerplate: false

- name: OsrReturnValue
  gen_boilerplate: false

- name: BinaryCache
  gen_boilerplate: false

- name: UnaryCache
  operands:
    input: Value
  result_type: Value
  generate_lir: true

# Checks whether we need to fire the interrupt handler.
- name: CheckOverRecursed
  guard: true
  alias_set: none
  generate_lir: true

# Check whether we need to fire the interrupt handler.
- name: InterruptCheck
  guard: true
  alias_set: none
  generate_lir: true

- name: WasmInterruptCheck
  gen_boilerplate: false

- name: WasmTrap
  gen_boilerplate: false
  generate_lir: true

- name: LexicalCheck
  gen_boilerplate: false

# Unconditionally throw an uninitialized let error.
- name: ThrowRuntimeLexicalError
  arguments:
    errorNumber: unsigned
  result_type: None
  guard: true
  alias_set:
    store: ExceptionState
  possibly_calls: true
  generate_lir: true

# Unconditionally throw a known error number.
- name: ThrowMsg
  arguments:
    throwMsgKind: ThrowMsgKind
  result_type: None
  guard: true
  alias_set:
    store: ExceptionState
  possibly_calls: true
  generate_lir: true

# In the prologues of global and eval scripts, check for redeclarations and
# initialize bindings.
- name: GlobalDeclInstantiation
  guard: true
  generate_lir: true

- name: RegExp
  arguments:
    source: RegExpObject*
    hasShared: bool
  result_type: Object
  possibly_calls: true
  alias_set: none

- name: RegExpMatcher
  operands:
    regexp: Object
    string: String
    lastIndex: Int32
  result_type: Value
  possibly_calls: true
  generate_lir: true

# Note: this instruction writes to cx->regExpSearcherLastLimit.
# See also MRegExpSearcherLastLimit.
- name: RegExpSearcher
  operands:
    regexp: Object
    string: String
    lastIndex: Int32
  result_type: Int32
  possibly_calls: true
  generate_lir: true

# This instruction loads cx->regExpSearcherLastLimit. We don't have a
# specialized alias set for this so just use the default alias set similar to
# the MRegExpSearcher instruction that precedes it.
- name: RegExpSearcherLastLimit
  result_type: Int32
  generate_lir: true
  lir_temps: 1

- name: RegExpExecMatch
  operands:
    regexp: Object
    string: String
  result_type: Value
  possibly_calls: true
  generate_lir: true

- name: RegExpExecTest
  operands:
    regexp: Object
    string: String
  result_type: Boolean
  possibly_calls: true
  generate_lir: true

- name: RegExpHasCaptureGroups
  operands:
    regexp: Object
    input: String
  result_type: Boolean
  possibly_calls: true

- name: GetFirstDollarIndex
  gen_boilerplate: false

- name: StringReplace
  gen_boilerplate: false

- name: Substr
  operands:
    string: String
    begin: Int32
    length: Int32
  result_type: String
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  can_recover: true
  generate_lir: true
  lir_temps: 3

- name: ModuleMetadata
  arguments:
    module: JSObject*
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: DynamicImport
  operands:
    specifier: Value
    options: Value
  arguments:
    phase: ImportPhase
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: Lambda
  gen_boilerplate: false

- name: FunctionWithProto
  gen_boilerplate: false

- name: SetFunName
  operands:
    fun: Object
    name: Value
  arguments:
    prefixKind: uint8_t
  result_type: None
  possibly_calls: true
  generate_lir: true

# Returns obj->slots.
- name: Slots
  operands:
    object: Object
  result_type: Slots
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  might_alias: custom
  clone: true
  generate_lir: true

# Returns obj->elements.
- name: Elements
  operands:
    object: Object
  result_type: Elements
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  clone: true
  generate_lir: true

# Load the initialized length from an elements header.
- name: InitializedLength
  operands:
    elements: Elements
  type_policy: none
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  compute_range: custom
  clone: true
  generate_lir: true

# Store to the initialized length in an elements header. Note the input is an
# *index*, one less than the desired initialized length.
- name: SetInitializedLength
  operands:
    elements: Elements
    index: Int32
  type_policy: none
  alias_set:
    store: ObjectFields
  clone: true
  generate_lir: true

# Load the array length from an elements header.
- name: ArrayLength
  operands:
    elements: Elements
  type_policy: none
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  compute_range: custom
  clone: true
  generate_lir: true

# Store to the length in an elements header. Note the input is an *index*, one
# less than the desired length.
- name: SetArrayLength
  operands:
    elements: Elements
    index: Int32
  type_policy: none
  alias_set:
    store: ObjectFields
  generate_lir: true

# Load the function length. Bails for functions with lazy scripts or a
# resolved "length" property.
- name: FunctionLength
  operands:
    function: Object
  result_type: Int32
  guard: true
  congruent_to: if_operands_equal
  # Even though the "length" property is lazily resolved, it acts similar to
  # a normal property load, so we can treat this operation like any other
  # property read.
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true

# Load the function name. Bails for bound functions when the bound function
# name prefix isn't present or functions with a resolved "name" property.
- name: FunctionName
  operands:
    function: Object
  result_type: String
  guard: true
  congruent_to: if_operands_equal
  # Even though the "name" property is lazily resolved, it acts similar to
  # a normal property load, so we can treat this operation like any other
  # property read.
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true

- name: GetNextEntryForIterator
  gen_boilerplate: false

# Read the byte length of an array buffer as IntPtr.
- name: ArrayBufferByteLength
  operands:
    object: Object
  result_type: IntPtr
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: FixedSlot
  generate_lir: true

# Read the length of an array buffer view.
- name: ArrayBufferViewLength
  operands:
    object: Object
  result_type: IntPtr
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ArrayBufferViewLengthOrOffset
  compute_range: custom
  generate_lir: true

# Read the byteOffset of an array buffer view.
- name: ArrayBufferViewByteOffset
  operands:
    object: Object
  result_type: IntPtr
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ArrayBufferViewLengthOrOffset
  compute_range: custom
  generate_lir: true

# Read the elements of an array buffer view.
- name: ArrayBufferViewElements
  operands:
    object: Object
  result_type: Elements
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  clone: true
  generate_lir: true

# Read the length of a resizable typed array.
- name: ResizableTypedArrayLength
  operands:
    object: Object
  arguments:
    requiresMemoryBarrier: MemoryBarrierRequirement
  result_type: IntPtr
  # Not removable or movable when a barrier is needed.
  guard: true
  movable: false
  congruent_to: custom
  alias_set: custom
  compute_range: custom
  generate_lir: true
  lir_temps: 1

# Read the byteLength of a resizable dataview.
- name: ResizableDataViewByteLength
  operands:
    object: Object
  arguments:
    requiresMemoryBarrier: MemoryBarrierRequirement
  result_type: IntPtr
  # Not removable or movable when a barrier is needed.
  guard: true
  movable: false
  congruent_to: custom
  alias_set: custom
  compute_range: custom
  generate_lir: true
  lir_temps: 1

# Read the byte length of a growable shared array buffer as IntPtr.
- name: GrowableSharedArrayBufferByteLength
  operands:
    object: Object
  result_type: IntPtr
  guard: true
  movable: false
  # Requires a barrier, so make the instruction effectful by giving it a
  # "store" effect. Also prevent reordering LoadUnboxedScalar before this
  # instruction by including |UnboxedElement| in the alias set.
  alias_set:
    store:
      - FixedSlot
      - SharedArrayRawBufferLength
      - UnboxedElement
  generate_lir: true

# Return the element size of a typed array.
- name: TypedArrayElementSize
  operands:
    object: Object
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  # Class is immutable. See also MHasClass.
  alias_set: none
  compute_range: custom
  generate_lir: true

# Guard an ArrayBufferView has an attached ArrayBuffer.
- name: GuardHasAttachedArrayBuffer
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

# Guard a resizable typed array is in-bounds.
- name: GuardResizableArrayBufferViewInBounds
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # Additionally reads the |initialLength| and |initialByteOffset| slots, but
  # since these can't change after construction, we don't need to track them.
  alias_set:
    load: ArrayBufferViewLengthOrOffset
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

# Guard a resizable typed array is in-bounds or detached.
- name: GuardResizableArrayBufferViewInBoundsOrDetached
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # Loads the byteOffset and additionally checks for detached buffers, so the
  # alias set also has to include |ObjectFields| and |FixedSlot|.
  alias_set:
    load:
      - ArrayBufferViewLengthOrOffset
      - ObjectFields
      - FixedSlot
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

# Inline TypedArray.prototype.fill
- name: TypedArrayFill
  gen_boilerplate: false

# Inlined TypedArray.prototype.set
- name: TypedArraySet
  operands:
    target: Object
    source: Object
    offset: IntPtr
  arguments:
    canUseBitwiseCopy: bool
  # Loads typed array length and elements.
  # Stores into typed array elements.
  alias_set:
    load:
      - ArrayBufferViewLengthOrOffset
      - ObjectFields
      - UnboxedElement
    store:
      - UnboxedElement
  possibly_calls: true
  generate_lir: true

- name: TypedArraySetFromSubarray
  operands:
    target: Object
    source: Object
    offset: IntPtr
    sourceOffset: IntPtr
    sourceLength: IntPtr
  arguments:
    canUseBitwiseCopy: bool
  # Loads typed array length and elements.
  # Stores into typed array elements.
  alias_set:
    load:
      - ArrayBufferViewLengthOrOffset
      - ObjectFields
      - UnboxedElement
    store:
      - UnboxedElement
  possibly_calls: true
  generate_lir: true

- name: GuardTypedArraySetOffset
  operands:
    offset: IntPtr
    targetLength: IntPtr
    sourceLength: IntPtr
  result_type: IntPtr
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

# Inlined TypedArray.prototype.subarray
- name: TypedArraySubarray
  gen_boilerplate: false

- name: ToIntegerIndex
  operands:
    index: IntPtr
    length: IntPtr
  result_type: IntPtr
  alias_set: none
  folds_to: custom
  generate_lir: true

- name: GuardNumberToIntPtrIndex
  gen_boilerplate: false

- name: KeepAliveObject
  operands:
    object: Object
  result_type: None
  guard: true
  generate_lir: true

- name: DebugEnterGCUnsafeRegion
  result_type: None
  guard: true
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: DebugLeaveGCUnsafeRegion
  result_type: None
  guard: true
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: Not
  gen_boilerplate: false

- name: BoundsCheck
  gen_boilerplate: false

- name: BoundsCheckLower
  gen_boilerplate: false

- name: SpectreMaskIndex
  gen_boilerplate: false

- name: LoadElement
  gen_boilerplate: false

- name: LoadElementAndUnbox
  gen_boilerplate: false

- name: LoadElementHole
  gen_boilerplate: false

- name: StoreElement
  gen_boilerplate: false

- name: StoreHoleValueElement
  gen_boilerplate: false

- name: StoreElementHole
  gen_boilerplate: false

- name: ArrayPopShift
  gen_boilerplate: false

# Array.prototype.push on a dense array. Returns the new array length.
- name: ArrayPush
  operands:
    object: Object
    value: Value
  result_type: Int32
  alias_set:
    store:
      - ObjectFields
      - Element
  compute_range: custom
  clone: true
  generate_lir: true
  lir_temps: 2

# Array.prototype.slice on a dense array.
- name: ArraySlice
  operands:
    object: Object
    begin: Int32
    end: Int32
  arguments:
    templateObj: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

# Array.prototype.slice on an arguments object.
- name: ArgumentsSlice
  operands:
    object: Object
    begin: Int32
    end: Int32
  arguments:
    templateObj: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

# Array.prototype.slice on an arguments object.
- name: FrameArgumentsSlice
  operands:
    begin: Int32
    count: Int32
  arguments:
    templateObj: JSObject*
    initialHeap: gc::Heap
  result_type: Object
  alias_set: none
  possibly_calls: true

# Array.prototype.slice on an inlined arguments object.
- name: InlineArgumentsSlice
  gen_boilerplate: false

- name: NormalizeSliceTerm
  operands:
    value: Int32
    length: Int32
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  generate_lir: true

# MArrayJoin doesn't override |getAliasSet()|, because Array.prototype.join
# might coerce the elements of the Array to strings. This coercion might
# cause the evaluation of JavaScript code.
- name: ArrayJoin
  operands:
    array: Object
    separator: String
  result_type: String
  possibly_calls: true
  folds_to: custom
  generate_lir: true
  lir_temps: 1
  # MArrayJoin doesn't override |getAliasSet()|, because Array.prototype.join
  # might coerce the elements of the Array to strings. This coercion might
  # cause the evaluation of JavaScript code.

# Object.prototype.keys. Used to elide it when possible.
- name: ObjectKeys
  operands:
    object: Object
  arguments:
    resultShape: Shape*
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: ObjectKeysFromIterator
  operands:
    iterator: Object
  result_type: Object
  alias_set: none
  can_recover: true

- name: LoadUnboxedScalar
  gen_boilerplate: false

- name: LoadDataViewElement
  gen_boilerplate: false

- name: LoadTypedArrayElementHole
  gen_boilerplate: false

- name: StoreUnboxedScalar
  gen_boilerplate: false

- name: StoreDataViewElement
  gen_boilerplate: false

- name: StoreTypedArrayElementHole
  gen_boilerplate: false

- name: EffectiveAddress3
  gen_boilerplate: false

- name: EffectiveAddress2
  gen_boilerplate: false

- name: ClampToUint8
  gen_boilerplate: false

- name: LoadFixedSlot
  gen_boilerplate: false

- name: LoadFixedSlotFromOffset
  operands:
    object: Object
    offset: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: FixedSlot
  generate_lir: true

- name: LoadFixedSlotAndUnbox
  gen_boilerplate: false

- name: LoadDynamicSlotAndUnbox
  gen_boilerplate: false

- name: StoreFixedSlot
  gen_boilerplate: false

- name: StoreFixedSlotFromOffset
  gen_boilerplate: false

- name: StoreDynamicSlotFromOffset
  gen_boilerplate: false

- name: GetPropertyCache
  gen_boilerplate: false

- name: HomeObjectSuperBase
  operands:
    homeObject: Object
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true

- name: GetPropSuperCache
  gen_boilerplate: false

- name: BindNameCache
  operands:
    environmentChain: Object
  result_type: Object
  generate_lir: true
  lir_temps: 1

- name: GuardShape
  operands:
    object: Object
  arguments:
    shape: Shape*
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load: ObjectFields
  might_alias: custom
  folds_to: custom
  generate_lir: true
  lir_temps: 1

- name: HasShape
  operands:
    object: Object
  arguments:
    shape: Shape*
  result_type: Boolean
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load: ObjectFields
  generate_lir: true

- name: GuardFuse
  arguments:
    fuseIndex: RealmFuses::FuseIndex
  result_type: None
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  # The alias set below reflects the set of operations which could cause a fuse
  # to be popped, and therefore MGuardFuse aliases with.
  alias_set:
    load:
      - ObjectFields
      - DynamicSlot
      - FixedSlot
      - GlobalGenerationCounter
  generate_lir: true

# This is the equivalent of the GuardMultipleShapes CacheIR op. Because it
# stores a pointer to the ShapeListObject, we don't need to recompile Ion code
# when a new shape is added to the list.
- name: GuardMultipleShapes
  operands:
    object: Object
    shapeList: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # Note: This instruction loads the elements of the ListObject used to
  # store the list of shapes, but that object is internal and not exposed
  # to script, so it doesn't have to be in the alias set.
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_temps: 4

# Similar to GuardMultipleShapes but used when the list had a small number of
# shapes. These shapes have been copied to the ShapeListSnapshot and are
# available at compile-time. This lets us perform more MIR optimizations, but
# we need to recompile when a new shape is added to the list.
- name: GuardShapeList
  operands:
    object: Object
  arguments:
    shapeList: const ShapeListSnapshot*
  result_type: Object
  guard: true
  movable: true
  congruent_to: custom
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_temps: 2

- name: GuardShapeListToOffset
  operands:
    object: Object
  arguments:
    shapeList: const ShapeListWithOffsetsSnapshot*
  result_type: Int32
  guard: true
  movable: true
  congruent_to: custom
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_temps: 2

- name: GuardMultipleShapesToOffset
  operands:
    object: Object
    shapeList: Object
  result_type: Int32
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields

- name: GuardProto
  gen_boilerplate: false

- name: GuardNullProto
  gen_boilerplate: false

# Guard the object is a native object.
- name: GuardIsNativeObject
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # A native object can never become a non-native object and vice versa.
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardGlobalGeneration
  arguments:
   expected: uint32_t
   generationAddr: const void*
  result_type: None
  guard: true
  movable: true
  alias_set:
    load: GlobalGenerationCounter
  congruent_to: if_operands_and_arguments_equal
  generate_lir: true
  lir_temps: 1

- name: GuardIsProxy
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # A proxy object can never become a non-proxy object and vice versa.
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardIsNotDOMProxy
  operands:
    proxy: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardIsNotProxy
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  # A proxy object can never become a non-proxy object and vice versa.
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: ProxyGet
  operands:
    proxy: Object
  arguments:
    id: jsid
  result_type: Value
  possibly_calls: true
  generate_lir: true
  lir_temps: 1

- name: ProxyGetByValue
  operands:
    proxy: Object
    idVal: Value
  result_type: Value
  possibly_calls: true
  generate_lir: true

- name: ProxyHasProp
  operands:
    proxy: Object
    idVal: Value
  arguments:
    hasOwn: bool
  result_type: Boolean
  possibly_calls: true

- name: ProxySet
  operands:
    proxy: Object
    rhs: Value
  arguments:
    id: jsid
    strict: bool
  possibly_calls: true
  generate_lir: true
  lir_temps: 1

- name: ProxySetByValue
  operands:
    proxy: Object
    idVal: Value
    rhs: Value
  arguments:
    strict: bool
  possibly_calls: true
  generate_lir: true

- name: CallSetArrayLength
  operands:
    obj: Object
    rhs: Value
  arguments:
    strict: bool
  possibly_calls: true
  generate_lir: true

- name: MegamorphicLoadSlot
  operands:
    object: Object
  arguments:
    name: PropertyKey
  result_type: Value
  # Bails when non-native or accessor properties are encountered, so we can't
  # DCE this instruction.
  guard: true
  possibly_calls: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true
  lir_temps: 4

- name: MegamorphicLoadSlotPermissive
  operands:
    object: Object
  arguments:
    name: PropertyKey
  result_type: Value
  guard: true
  possibly_calls: true
  generate_lir: true
  lir_temps: 4

- name: MegamorphicLoadSlotByValue
  operands:
    object: Object
    idVal: Value
  result_type: Value
  # Bails when non-native or accessor properties are encountered, so we can't
  # DCE this instruction.
  guard: true
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  possibly_calls: true
  generate_lir: true
  lir_temps: 3

- name: MegamorphicLoadSlotByValuePermissive
  operands:
    object: Object
    idVal: Value
  result_type: Value
  guard: true
  folds_to: custom
  possibly_calls: true
  generate_lir: true
#ifdef JS_CODEGEN_X86
  lir_temps: 3
#else
  lir_temps: 4
#endif

- name: MegamorphicStoreSlot
  operands:
    object: Object
    rhs: Value
  arguments:
    name: PropertyKey
    strict: bool
  possibly_calls: true
  generate_lir: true
#ifdef JS_CODEGEN_X86
  lir_temps: 1
#else
  lir_temps: 3
#endif

- name: MegamorphicHasProp
  operands:
    object: Object
    idVal: Value
  arguments:
    hasOwn: bool
  result_type: Boolean
  # Bails when non-native or accessor properties are encountered, so we can't
  # DCE this instruction.
  guard: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  possibly_calls: true
  generate_lir: true
  lir_temps: 3

- name: SmallObjectVariableKeyHasProp
  operands:
    idStr: String
  arguments:
    shape: Shape*
  congruent_to: if_operands_and_arguments_equal
  result_type: Boolean
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true

- name: GuardToArrayBuffer
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: GuardToSharedArrayBuffer
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: GuardIsNotArrayBufferMaybeShared
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardIsNonResizableTypedArray
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardIsResizableTypedArray
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardHasProxyHandler
  operands:
    object: Object
  arguments:
    handler: const void*
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  # The proxy handler can change when a proxy is swapped with another object or
  # when nuking a cross-compartment wrapper.
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none

# Loads a specific JSObject* that was originally nursery-allocated.
# See also WarpObjectField.
- name: NurseryObject
  arguments:
    # Index in the Vector of objects stored in the WarpSnapshot.
    nurseryObjectIndex: uint32_t
  result_type: Object
  movable: true
  value_hash: custom
  congruent_to: if_operands_and_arguments_equal
  alias_set: none
  generate_lir: true

- name: GuardValue
  gen_boilerplate: false

- name: GuardNullOrUndefined
  operands:
    value: Value
  result_type: Value
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

- name: GuardIsNotObject
  operands:
    value: Value
  result_type: Value
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

- name: GuardFunctionFlags
  gen_boilerplate: false

- name: GuardFunctionIsNonBuiltinCtor
  operands:
    function: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardFunctionKind
  operands:
    function: Object
  arguments:
    expected: FunctionFlags::FunctionKind
    bailOnEquality: bool
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardFunctionScript
  operands:
    function: Object
  arguments:
    expected: BaseScript*
    nargs: uint16_t
    flags: FunctionFlags
  result_type: Object
  guard: true
  movable: true
  folds_to: custom
  congruent_to: custom
  # A JSFunction's BaseScript pointer is immutable. Relazification of
  # self-hosted functions is an exception to this, but we don't use this
  # guard for self-hosted functions.
  alias_set: custom
  generate_lir: true
  lir_result_type: none

- name: GuardObjectIdentity
  gen_boilerplate: false

- name: GuardSpecificFunction
  gen_boilerplate: false

- name: GuardSpecificAtom
  operands:
    str: String
  arguments:
    atom: JSOffThreadAtom*
  result_type: String
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardSpecificSymbol
  gen_boilerplate: false

- name: GuardSpecificInt32
  operands:
    num: Int32
  arguments:
    expected: int32_t
  result_type: Int32
  guard: true
  movable: true
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

- name: GuardStringToIndex
  operands:
    string: String
  result_type: Int32
  # Mark as guard because this instruction must not be eliminated. For
  # example, if the string is not an index the operation could change from a
  # typed array load to a getter call.
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true

- name: GuardStringToInt32
  operands:
    string: String
  result_type: Int32
  # Mark as guard to prevent the issue described in MGuardStringToIndex's
  # constructor.
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: GuardStringToDouble
  operands:
    string: String
  result_type: Double
  # Mark as guard to prevent the issue described in MGuardStringToIndex's
  # constructor.
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_temps: 2

- name: GuardNoDenseElements
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardTagNotEqual
  gen_boilerplate: false

- name: LoadDynamicSlot
  gen_boilerplate: false

- name: LoadDynamicSlotFromOffset
  operands:
    slots: Slots
    offset: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: DynamicSlot
  generate_lir: true

# Inline call to access a function's environment (scope chain).
- name: FunctionEnvironment
  operands:
    function: Object
  result_type: Object
  movable: true
  folds_to: custom
  # A function's environment is fixed.
  alias_set: none
  can_recover: true
  generate_lir: true

# Allocate a new BlockLexicalEnvironmentObject.
- name: NewLexicalEnvironmentObject
  operands:
    templateObj: Object
  result_type: Object
  alias_set: none

# Allocate a new ClassBodyEnvironmentObject.
- name: NewClassBodyEnvironmentObject
  operands:
    templateObj: Object
  result_type: Object
  alias_set: none

- name: NewVarEnvironmentObject
  operands:
    templateObj: Object
  result_type: Object
  alias_set: none

- name: HomeObject
  operands:
    function: Object
  result_type: Object
  movable: true
  # A function's [[HomeObject]] is fixed.
  alias_set: none
  generate_lir: true

- name: AddAndStoreSlot
  gen_boilerplate: false

- name: AllocateAndStoreSlot
  operands:
    object: Object
    value: Value
  arguments:
    slotOffset: uint32_t
    shape: Shape*
    numNewSlots: uint32_t
    preserveWrapper: bool
  possibly_calls: true
  alias_set:
    store:
      - ObjectFields
      - DynamicSlot
  generate_lir: true
  lir_temps: 2

- name: StoreDynamicSlot
  gen_boilerplate: false

# Note, Name ICs always return a Value. There are no V/T variants.
- name: GetNameCache
  operands:
    envObj: Object
  result_type: Value
  generate_lir: true
  lir_temps: 1

- name: CallGetIntrinsicValue
  arguments:
    name: PropertyName*
  result_type: Value
  possibly_calls: true
  generate_lir: true

- name: DeleteProperty
  operands:
    value: Value
  arguments:
    name: PropertyName*
    strict: bool
  result_type: Boolean
  possibly_calls: true
  generate_lir: true

- name: DeleteElement
  operands:
    value: Value
    index: Value
  arguments:
    strict: bool
  result_type: Boolean
  possibly_calls: true
  generate_lir: true

- name: SetPropertyCache
  gen_boilerplate: false

- name: MegamorphicSetElement
  gen_boilerplate: false

- name: SetDOMProperty
  gen_boilerplate: false

- name: GetDOMProperty
  gen_boilerplate: false

- name: GetDOMMember
  gen_boilerplate: false

- name: ObjectToIterator
  gen_boilerplate: false

- name: IteratorLength
  operands:
    iter: Object
  result_type: Int32
  generate_lir: true

- name: LoadIteratorElement
  operands:
    iter: Object
    index: Int32
  result_type: String
  alias_set: none
  generate_lir: true

- name: ValueToIterator
  operands:
    value: Value
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: IteratorHasIndices
  operands:
    object: Object
    iterator: Object
  result_type: Boolean
  alias_set:
    load: ObjectFields

- name: IteratorsMatchAndHaveIndices
  operands:
    object: Object
    iterator: Object
    otherIterator: Object
  result_type: Boolean
  alias_set:
    load: ObjectFields

- name: LoadSlotByIteratorIndex
  operands:
    object: Object
    iterator: Object # TODO: add MIRType::NativeIterator?
  result_type: Value
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
      - Element
  generate_lir: true
  lir_temps: 2

- name: StoreSlotByIteratorIndex
  operands:
    object: Object
    iterator: Object
    value: Value
  alias_set:
    store:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
      - Element
  generate_lir: true
  lir_temps: 2

# Okay this is a confusing name, but essentially, the above ops load/store a
# slot of an object using the PropertyIndex associated with the *current* key
# for the iterator. The below op uses the PropertyIndex associated with the
# key indexed by `index`, rather than the current one.
- name: LoadSlotByIteratorIndexIndexed
  operands:
    object: Object
    iterator: Object
    index: Int32
  result_type: Value
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
      - Element
  generate_lir: true
  lir_temps: 2

- name: StoreSlotByIteratorIndexIndexed
  operands:
    object: Object
    iterator: Object
    index: Int32
    value: Value
  alias_set:
    store:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
      - Element
  generate_lir: true
  lir_temps: 2

# Load the private value expando from a DOM proxy. The target is stored in the
# proxy object's private slot.
# This is either an UndefinedValue (no expando), ObjectValue (the expando
# object), or PrivateValue(ExpandoAndGeneration*).
- name: LoadDOMExpandoValue
  operands:
    proxy: Object
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: DOMProxyExpando
  generate_lir: true

- name: LoadDOMExpandoValueGuardGeneration
  gen_boilerplate: false

- name: LoadDOMExpandoValueIgnoreGeneration
  operands:
    proxy: Object
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: DOMProxyExpando
  generate_lir: true

# Takes an expando Value as input, then guards it's either UndefinedValue or
# an object with the expected shape.
- name: GuardDOMExpandoMissingOrGuardShape
  operands:
    expando: Value
  arguments:
    shape: Shape*
  result_type: Value
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

# Read length field of a JSString*.
- name: StringLength
  operands:
    string: String
  result_type: Int32
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  # The string |length| property is immutable, so there is no
  # implicit dependency.
  alias_set: none
  compute_range: custom
  can_recover: true
  clone: true
  generate_lir: true

- name: Floor
  gen_boilerplate: false

- name: Ceil
  gen_boilerplate: false

- name: Round
  gen_boilerplate: false

- name: Trunc
  gen_boilerplate: false

- name: NearbyInt
  gen_boilerplate: false

- name: RoundToDouble
  gen_boilerplate: false

- name: GetIteratorCache
  operands:
    value: ValueOrObject
  result_type: Object

- name: OptimizeSpreadCallCache
  operands:
    value: Value
  result_type: Value
  generate_lir: true
  lir_temps: 1

- name: IteratorMore
  operands:
    iterator: Object
  result_type: Value
  generate_lir: true
  lir_temps: 1

- name: IsNoIter
  operands:
    def: Value
  result_type: Boolean
  type_policy: none
  movable : true
  alias_set: none

- name: IteratorEnd
  operands:
    iterator: Object
  generate_lir: true
  lir_temps: 3

- name: CloseIterCache
  operands:
    iter: Object
  arguments:
    completionKind: uint8_t
  possibly_calls: true

- name: OptimizeGetIteratorCache
  operands:
    value: Value
  result_type: Boolean
  generate_lir: true
  lir_temps: 1

- name: InCache
  gen_boilerplate: false

- name: InArray
  gen_boilerplate: false

# Bail when the element is a hole.
- name: GuardElementNotHole
  operands:
    elements: Elements
    index: Int32
  type_policy: none
  movable: true
  guard: true
  alias_set:
    load: Element
  congruent_to: if_operands_equal
  generate_lir: true

- name: NewPrivateName
  arguments:
    name: JSOffThreadAtom*
  result_type: Symbol
  possibly_calls: true
  generate_lir: true

- name: CheckPrivateFieldCache
  gen_boilerplate: false

- name: HasOwnCache
  gen_boilerplate: false

# Implementation for instanceof operator with specific rhs.
- name: InstanceOf
  operands:
    obj: ValueOrObject
    proto: Object
  result_type: Boolean

# Implementation for instanceof operator with unknown rhs.
- name: InstanceOfCache
  operands:
    obj: Value
    proto: Object
  result_type: Boolean
  generate_lir: true

# Read the number of actual arguments.
- name: ArgumentsLength
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  # Arguments |length| cannot be mutated by Ion Code.
  alias_set: none
  compute_range: custom
  can_recover: true
  generate_lir: true

# This MIR instruction is used to get an argument from the actual arguments.
- name: GetFrameArgument
  operands:
    index: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  # This instruction is never aliased, because ops like JSOp::SetArg don't
  # write to the argument frames. We create an arguments object in that case.
  alias_set: none
  generate_lir: true

# This MIR instruction is used to get an argument from the actual arguments.
# Returns undefined if |index| is larger-or-equals to |length|. Bails out if
# |index| is negative.
- name: GetFrameArgumentHole
  operands:
    index: Int32
    length: Int32
  result_type: Value
  guard: true
  movable: true
  congruent_to: if_operands_equal
  # This instruction is never aliased, because ops like JSOp::SetArg don't
  # write to the argument frames. We create an arguments object in that case.
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: NewTarget
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

# Create the rest parameter.
- name: Rest
  operands:
    numActuals: Int32
  arguments:
    numFormals: unsigned
    shape: Shape*
  result_type: Object
  possibly_calls: true
  alias_set: none
  can_recover: true
  generate_lir: true
  lir_temps: 4

- name: PostWriteBarrier
  gen_boilerplate: false

- name: PostWriteElementBarrier
  gen_boilerplate: false

- name: AssertCanElidePostWriteBarrier
  operands:
    object: Object
    value: Value
  result_type: None
  guard: true
  alias_set: none
  generate_lir: true
  lir_temps: 1

# Allocates a new NamedLambdaObject.
#
# This instruction generates two possible instruction sets:
#   (1) An inline allocation of the call object is attempted.
#   (2) Otherwise, a callVM create a new object.
- name: NewNamedLambdaObject
  arguments:
    templateObj: NamedLambdaObject*
    initialHeap: gc::Heap
  result_type: Object
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: NewCallObject
  gen_boilerplate: false

- name: NewStringObject
  gen_boilerplate: false

- name: IsCallable
  operands:
    object: ValueOrObject
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set:
    load: ObjectFields

- name: IsConstructor
  operands:
    object: Object
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true

- name: IsCrossRealmArrayConstructor
  operands:
    object: Object
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: IsObject
  operands:
    object: Value
  result_type: Boolean
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: IsNullOrUndefined
  operands:
    value: any
  result_type: Boolean
  movable: true
  folds_to: custom
  congruent_to: if_operands_equal
  alias_set: none
  type_policy: none
  can_consume_float32: true
  generate_lir: true

- name: HasClass
  gen_boilerplate: false

- name: GuardToClass
  gen_boilerplate: false

- name: GuardToFunction
  gen_boilerplate: false

# Note: we might call a proxy trap, so this instruction is effectful.
- name: IsArray
  operands:
    value: ValueOrObject
  result_type: Boolean
  folds_to: custom

- name: IsTypedArray
  gen_boilerplate: false

- name: ObjectClassToString
  operands:
    object: Object
  result_type: String
  guard: true
  movable: true
  congruent_to: if_operands_equal
  possibly_calls: true
  # Tests @@toStringTag is neither present on this object nor on any object
  # of the prototype chain.
  alias_set:
    load:
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true
  lir_temps: 1

- name: CheckReturn
  operands:
    returnValue: Value
    thisValue: Value
  result_type: Value
  guard: true
  folds_to: custom
  alias_set:
    store: ExceptionState
  generate_lir: true

- name: CheckThis
  operands:
    thisValue: Value
  result_type: Value
  guard: true
  folds_to: custom
  alias_set:
    store: ExceptionState
  generate_lir: true
  lir_result_type: none

- name: AsyncResolve
  operands:
    generator: Object
    value: Value
  result_type: Object
  possibly_calls: true
  generate_lir: true

# Returns from this function to the previous caller; this looks like a regular
# Unary instruction and is used to lie to the MIR generator about suspending
# ops like Yield/Await, which are emitted like returns, but MIR-Build like
# regular instructions.
- name: GeneratorReturn
  operands:
    input: Value
  guard: true
  alias_set: none

- name: AsyncAwait
  operands:
    value: Value
    generator: Object
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: CheckThisReinit
  operands:
    thisValue: Value
  result_type: Value
  guard: true
  folds_to: custom
  alias_set:
    store: ExceptionState
  generate_lir: true
  lir_result_type: none

- name: Generator
  gen_boilerplate: false

- name: CanSkipAwait
  operands:
    value: Value
  result_type: Boolean
  possibly_calls: true
  generate_lir: true

- name: MaybeExtractAwaitValue
  gen_boilerplate: false

- name: IncrementWarmUpCounter
  arguments:
    script: JSScript*
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: AtomicIsLockFree
  gen_boilerplate: false

- name: AtomicPause
  guard: true
  movable: false
  alias_set: none
  generate_lir: true

- name: CompareExchangeTypedArrayElement
  gen_boilerplate: false

- name: AtomicExchangeTypedArrayElement
  gen_boilerplate: false

- name: AtomicTypedArrayElementBinop
  gen_boilerplate: false

- name: Debugger
  gen_boilerplate: false

- name: CheckIsObj
  operands:
    value: Value
  arguments:
    checkKind: uint8_t
  result_type: Object
  guard: true
  folds_to: custom
  alias_set:
    store: ExceptionState
  generate_lir: true

- name: CheckObjCoercible
  operands:
    checkValue: Value
  result_type: Value
  guard: true
  folds_to: custom
  # Throws on null or undefined.
  alias_set:
    store: ExceptionState
  generate_lir: true
  lir_result_type: none

- name: CheckClassHeritage
  operands:
    heritage: Value
  result_type: Value
  guard: true
  generate_lir: true
  lir_result_type: none
  lir_temps: 2

- name: DebugCheckSelfHosted
  operands:
    checkValue: Value
  result_type: Value
  guard: true
  possibly_calls: true
  generate_lir: true
  lir_result_type: none

- name: IsPackedArray
  operands:
    object: Object
  result_type: Boolean
  movable: true
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_temps: 1

- name: GuardArrayIsPacked
  operands:
    array: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 2

- name: GuardElementsArePacked
  operands:
    elements: Elements
  type_policy: none
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true

- name: GetPrototypeOf
  operands:
    target: Object
  result_type: Value
  # May throw if target is a proxy.
  guard: true
  generate_lir: true

- name: ObjectWithProto
  operands:
    prototype: Value
  result_type: Object
  # May throw if prototype is neither an object nor null.
  guard: true
  possibly_calls: true
  generate_lir: true

- name: ObjectStaticProto
  gen_boilerplate: false

# This is basically just a limited case of Constant, for objects which are
# the prototype of another object and will be used for a GuardShape. It
# includes a reference to the receiver object so we can eliminate redundant
# shape guards.
- name: ConstantProto
  gen_boilerplate: false

- name: BuiltinObject
  arguments:
    builtinObjectKind: BuiltinObjectKind
  result_type: Object
  possibly_calls: true
  generate_lir: true

- name: SuperFunction
  operands:
    callee: Object
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true

- name: SuperFunctionAndUnbox
  operands:
    callee: Object
  result_type: Object
  movable: true
  guard: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true

- name: InitHomeObject
  operands:
    function: Object
    homeObject: Value
  result_type: Object
  alias_set:
    store: ObjectFields
  generate_lir: true
  lir_result_type: none

# Return true if the object is definitely a TypedArray constructor, but not
# necessarily from the currently active realm. Return false if the object is
# not a TypedArray constructor or if it's a wrapper.
- name: IsTypedArrayConstructor
  operands:
    object: Object
  result_type: Boolean
  alias_set: none
  generate_lir: true

# Load the JSValueTag on all platforms except ARM64 and RISCV64.
#
# See the comments in MacroAssembler-arm64.h for the |cmpTag(Register, ImmTag)|
# method for why ARM64 doesn't use the raw JSValueTag, but instead a modified
# tag value. That modified tag value can't be directly compared against
# JSValueTag constants.
#
# RISCV64 uses a similar scheme, see comments in MacroAssembler-riscv64.h for
# the |splitSignExtTag(...)| method.
- name: LoadValueTag
  operands:
    value: Value
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

# Load the target object from a proxy wrapper. The target is stored in the
# proxy object's private slot. This operation is fallible if the proxy can
# be revoked.
- name: LoadWrapperTarget
  operands:
    object: Object
  arguments:
    fallible: bool
  result_type: Object
  movable: true
  congruent_to: if_operands_and_arguments_equal
  # Can't use |AliasSet::None| because the target changes on navigation.
  # TODO: Investigate using a narrower or a custom alias set.
  alias_set:
    load: Any
  generate_lir: true

- name: LoadGetterSetterFunction
  operands:
    getterSetter: Value
  arguments:
    isGetter: bool
    needsClassGuard: bool
  result_type: Object
  generate_lir: true
  lir_temps: 1
  alias_set: none

# Guard the accessor shape is present on the object or its prototype chain.
- name: GuardHasGetterSetter
  operands:
    object: Object
  arguments:
    propId: jsid
    getterSetterValue: ValueOrNurseryValueIndex
  result_type: Object
  guard: true
  movable: true
  possibly_calls: true
  congruent_to: if_operands_and_arguments_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 3

- name: GuardIsExtensible
  operands:
    object: Object
  result_type: Object
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 1

- name: GuardInt32IsNonNegative
  operands:
    index: Int32
  result_type: Int32
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

- name: GuardIntPtrIsNonNegative
  operands:
    index: IntPtr
  result_type: IntPtr
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

- name: GuardInt32Range
  operands:
    input: Int32
  arguments:
    minimum: int32_t
    maximum: int32_t
  result_type: Int32
  guard: true
  movable: true
  congruent_to: if_operands_and_arguments_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

# Guard the input index is either greater than the dense initialized length of
# an object, or a hole element.
- name: GuardIndexIsNotDenseElement
  operands:
    object: Object
    index: Int32
  result_type: Int32
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load:
      - ObjectFields
      - Element
  generate_lir: true
  lir_result_type: none
  lir_temps: 2

# Guard an array object's length can be updated successfully when adding an
# element at the input index.
- name: GuardIndexIsValidUpdateOrAdd
  operands:
    object: Object
    index: Int32
  result_type: Int32
  guard: true
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: ObjectFields
  generate_lir: true
  lir_result_type: none
  lir_temps: 2

# Add or update a sparse element of an ArrayObject or PlainObject. It's allowed
# for the sparse element to be already present on the object. It may also be an
# accessor property, so this instruction is always marked as effectful.
- name: CallAddOrUpdateSparseElement
  operands:
    object: Object
    index: Int32
    value: Value
  arguments:
    strict: bool
  possibly_calls: true
  generate_lir: true

# Get a sparse element from an ArrayObject or PlainObject, possibly by calling
# an accessor property.
- name: CallGetSparseElement
  operands:
    object: Object
    index: Int32
  result_type: Value
  possibly_calls: true
  generate_lir: true

- name: CallNativeGetElement
  operands:
    object: Object
    index: Int32
  result_type: Value
  possibly_calls: true
  generate_lir: true

- name: CallNativeGetElementSuper
  operands:
    object: Object
    index: Int32
    receiver: Value
  result_type: Value
  possibly_calls: true
  generate_lir: true

# Test if a native object has an own element (sparse or dense) at an index.
- name: CallObjectHasSparseElement
  operands:
    object: Object
    index: Int32
  result_type: Boolean
  guard: true
  congruent_to: if_operands_equal
  possibly_calls: true
  alias_set:
    load:
      - Element
      - ObjectFields
      - FixedSlot
      - DynamicSlot
  generate_lir: true
  lir_temps: 2

- name: BigIntAsIntN
  operands:
    bits: Int32
    input: BigInt
  result_type: BigInt
  movable: true
  congruent_to: if_operands_equal
  possibly_calls: true
  folds_to: custom
  alias_set: none
  can_recover: true
  clone: true
  generate_lir: true

- name: BigIntAsUintN
  operands:
    bits: Int32
    input: BigInt
  result_type: BigInt
  movable: true
  congruent_to: if_operands_equal
  possibly_calls: true
  folds_to: custom
  alias_set: none
  can_recover: true
  clone: true
  generate_lir: true

- name: GuardNonGCThing
  operands:
    input: Value
  result_type: Value
  guard: true
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  alias_set: none
  generate_lir: true
  lir_result_type: none

- name: ToHashableNonGCThing
  operands:
    input: Value
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: ToHashableString
  operands:
    input: String
  result_type: String
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: ToHashableValue
  operands:
    input: Value
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: HashNonGCThing
  operands:
    input: Value
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: HashString
  operands:
    input: String
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 1

- name: HashSymbol
  operands:
    input: Symbol
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true

- name: HashBigInt
  operands:
    input: BigInt
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 3

- name: HashObject
  operands:
    setObject: Object
    input: Value
  result_type: Int32
  # In contrast to the previous hash operations, we can't move this
  # instruction, because the hashcode is computed from the object's address,
  # which can change when the object is moved by the GC.
  movable: false
  alias_set: none
  generate_lir: true
  lir_temps: 4

- name: HashValue
  operands:
    setObject: Object
    input: Value
  result_type: Int32
  movable: false
  alias_set: none
  generate_lir: true
  lir_temps: 4

- name: SetObjectHasNonBigInt
  operands:
    setObject: Object
    value: Value
    hash: Int32
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 2

- name: SetObjectHasBigInt
  operands:
    setObject: Object
    value: Value
    hash: Int32
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 4

- name: SetObjectHasValue
  operands:
    setObject: Object
    value: Value
    hash: Int32
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 4

- name: SetObjectHasValueVMCall
  operands:
    setObject: Object
    value: Value
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  possibly_calls: true
  generate_lir: true

- name: SetObjectDelete
  operands:
    setObject: Object
    key: Value
  result_type: Boolean
  possibly_calls: true
  generate_lir: true

- name: SetObjectAdd
  operands:
    setObject: Object
    key: Value
  possibly_calls: true
  generate_lir: true

- name: SetObjectSize
  operands:
    setObject: Object
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true

- name: MapObjectHasNonBigInt
  operands:
    mapObject: Object
    value: Value
    hash: Int32
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 2

- name: MapObjectHasBigInt
  operands:
    mapObject: Object
    value: Value
    hash: Int32
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 4

- name: MapObjectHasValue
  operands:
    mapObject: Object
    value: Value
    hash: Int32
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 4

- name: MapObjectHasValueVMCall
  operands:
    mapObject: Object
    value: Value
  result_type: Boolean
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  possibly_calls: true
  generate_lir: true

- name: MapObjectGetNonBigInt
  operands:
    mapObject: Object
    value: Value
    hash: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 2

- name: MapObjectGetBigInt
  operands:
    mapObject: Object
    value: Value
    hash: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 4

- name: MapObjectGetValue
  operands:
    mapObject: Object
    value: Value
    hash: Int32
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true
  lir_temps: 4

- name: MapObjectGetValueVMCall
  operands:
    mapObject: Object
    value: Value
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  possibly_calls: true
  generate_lir: true

- name: MapObjectDelete
  operands:
    mapObject: Object
    key: Value
  result_type: Boolean
  possibly_calls: true
  generate_lir: true

- name: MapObjectSet
  operands:
    mapObject: Object
    key: Value
    value: Value
  possibly_calls: true
  generate_lir: true

- name: MapObjectSize
  operands:
    mapObject: Object
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  alias_set:
    load: MapOrSetHashTable
  generate_lir: true

# Note: for now these WeakMap/WeakSet instructions are non-movable and don't
# override congruentTo, but it'd probably be fine to change this in the future.
- name: WeakMapGetObject
  operands:
    weakMap: Object
    object: Object
  result_type: Value
  alias_set:
    load: MapOrSetHashTable
  movable: false
  generate_lir: true
#ifdef JS_CODEGEN_X86
  possibly_calls: true
  lir_temps: 1
#else
  lir_temps: 7
#endif

- name: WeakMapHasObject
  operands:
    weakMap: Object
    object: Object
  result_type: Boolean
  alias_set:
    load: MapOrSetHashTable
  movable: false
  generate_lir: true
#ifdef JS_CODEGEN_X86
  possibly_calls: true
#else
  lir_temps: 7
#endif

- name: WeakSetHasObject
  operands:
    weakSet: Object
    object: Object
  result_type: Boolean
  alias_set:
    load: MapOrSetHashTable
  movable: false
  possibly_calls: true
  generate_lir: true

- name: DateFillLocalTimeSlots
  operands:
    date: Object
  congruent_to: if_operands_equal
  # Reads and stores fixed slots. Additional reads from DateTimeInfo don't need
  # to be tracked, because they don't interact with other alias set states.
  alias_set:
    store: FixedSlot
  generate_lir: true
  lir_temps: 1

- name: DateHoursFromSecondsIntoYear
  operands:
    secondsIntoYear: Value
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 2

- name: DateMinutesFromSecondsIntoYear
  operands:
    secondsIntoYear: Value
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 2

- name: DateSecondsFromSecondsIntoYear
  operands:
    secondsIntoYear: Value
  result_type: Value
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  generate_lir: true
  lir_temps: 2

- name: DateNow
  result_type: Double
  alias_set: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 1

- name: DateParse
  operands:
    string: String
  result_type: Double
  # Date.parse reads the current time zone, so there's actually load-dependency
  # on the time zone. AliasSet doesn't have a flag to model this dependency and
  # because it seems wasteful to use one of the few remaining bits for it, this
  # instruction can neither be marked as movable nor implement congruentTo.
  alias_set: none
  folds_to: custom
  possibly_calls: true
  generate_lir: true
  lir_temps: 1

- name: TimeClip
  operands:
    time: Double
  result_type: Double
  movable: true
  congruent_to: if_operands_equal
  alias_set: none
  folds_to: custom
  generate_lir: true

- name: LocalTimeToUTC
  operands:
    localTime: Int64
  result_type: Double
  type_policy: none
  # Neither movable nor implements congruentTo, see DateParse.
  alias_set: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 1

- name: YearFromTime
  operands:
    utcTime: Double
  result_type: Value
  # Neither movable nor implements congruentTo, see DateParse.
  alias_set: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

- name: MonthFromTime
  operands:
    utcTime: Double
  result_type: Value
  # Neither movable nor implements congruentTo, see DateParse.
  alias_set: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

- name: DateFromTime
  operands:
    utcTime: Double
  result_type: Value
  # Neither movable nor implements congruentTo, see DateParse.
  alias_set: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 2

- name: NewDateObject
  operands:
    utcTime: Double
  arguments:
    templateObject: JSObject*
  result_type: Object
  alias_set: none
  can_recover: true
  generate_lir: true
  lir_temps: 1

- name: PostIntPtrConversion
  gen_boilerplate: false

- name: CanonicalizeNaN
  gen_boilerplate: false

- name: WasmNeg
  gen_boilerplate: false

- name: WasmBinaryBitwise
  gen_boilerplate: false

- name: WasmLoadInstance
  gen_boilerplate: false

- name: WasmHeapReg
  gen_boilerplate: false

- name: WasmBoundsCheck
  gen_boilerplate: false

- name: WasmBoundsCheckRange32
  operands:
    index: Int32
    length: Int32
    limit: Int32
  arguments:
    trapSiteDesc: wasm::TrapSiteDesc
  result_type: Int32
  congruent_to: if_operands_equal_ignore_arguments
  type_policy: none
  generate_lir: true
  lir_result_type: none
  lir_temps: 1
  alias_set: none
  guard: true

- name: WasmExtendU32Index
  operands:
    input: Int32
  result_type: Int64
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  type_policy: none
  alias_set: none

- name: WasmWrapU32Index
  operands:
    input: Int64
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  folds_to: custom
  type_policy: none
  alias_set: none

- name: WasmClampTable64Address
  operands:
    address: Int64
  result_type: Int32
  movable: true
  congruent_to: if_operands_equal
  type_policy: none
  alias_set: none
  generate_lir: true

- name: WasmAddOffset
  gen_boilerplate: false

- name: WasmAlignmentCheck
  gen_boilerplate: false

- name: WasmLoad
  gen_boilerplate: false

- name: WasmStore
  gen_boilerplate: false

- name: WasmFence
  guard: true
  alias_set: none
  clone: true
  generate_lir: true

- name: WasmCompareExchangeHeap
  gen_boilerplate: false

- name: WasmAtomicExchangeHeap
  gen_boilerplate: false

- name: WasmAtomicBinopHeap
  gen_boilerplate: false

- name: WasmLoadInstanceDataField
  gen_boilerplate: false

- name: WasmLoadInstanceScratch2xI32
  gen_boilerplate: false

- name: WasmLoadGlobalCell
  gen_boilerplate: false

- name: WasmLoadTableElement
  gen_boilerplate: false

- name: WasmStoreInstanceDataField
  gen_boilerplate: false

- name: WasmStoreInstanceScratch2xI32
  gen_boilerplate: false

- name: WasmStoreGlobalCell
  gen_boilerplate: false

- name: WasmStoreStackResult
  gen_boilerplate: false

- name: WasmDerivedPointer
  gen_boilerplate: false

- name: WasmDerivedIndexPointer
  gen_boilerplate: false

- name: WasmStoreRef
  gen_boilerplate: false

- name: WasmPostWriteBarrierWholeCell
  gen_boilerplate: false

- name: WasmPostWriteBarrierEdgeAtIndex
  gen_boilerplate: false

- name: WasmParameter
  gen_boilerplate: false

- name: WasmReturn
  gen_boilerplate: false

- name: WasmReturnVoid
  gen_boilerplate: false

- name: WasmStackArg
  gen_boilerplate: false

- name: WasmRegisterResult
  gen_boilerplate: false

- name: WasmFloatRegisterResult
  gen_boilerplate: false

- name: WasmSystemFloatRegisterResult
  gen_boilerplate: false

- name: WasmRegister64Result
  gen_boilerplate: false

- name: WasmStackResultArea
  gen_boilerplate: false

- name: WasmStackResult
  gen_boilerplate: false

- name: WasmCallCatchable
  gen_boilerplate: false

- name: WasmCallUncatchable
  gen_boilerplate: false

- name: WasmCallLandingPrePad
  gen_boilerplate: false
  generate_lir: true

- name: WasmReturnCall
  gen_boilerplate: false

#ifdef ENABLE_WASM_JSPI
- name: WasmFindHandler
  operands:
    instance: Pointer
    tag: WasmAnyRef
  arguments:
    trap: wasm::Trap
    trapSiteDesc: wasm::TrapSiteDesc
  result_type: Pointer
  movable: false
  guard: true
  type_policy: none
  generate_lir: true
  lir_temps: 4

- name: WasmSuspend
  operands:
    instance: Pointer
    suspendedCont: WasmAnyRef
    handler: Pointer
  arguments:
    callSiteDesc: wasm::CallSiteDesc
  type_policy: none
  possibly_calls: true
  generate_lir: true
  lir_temps: 3

- name: WasmResumeBarrier
  operands:
    instance: Pointer
    cont: WasmAnyRef
  movable: false
  guard: true
  type_policy: none
  generate_lir: true
  lir_temps: 1

- name: WasmResume
  gen_boilerplate: false
#endif

- name: WasmSelect
  gen_boilerplate: false

- name: ReinterpretCast
  gen_boilerplate: false

- name: Rotate
  gen_boilerplate: false

- name: WasmBinarySimd128
  gen_boilerplate: false

- name: WasmBinarySimd128WithConstant
  gen_boilerplate: false

# (v128, i32) -> v128 effect-free shift operations.
- name: WasmShiftSimd128
  operands:
    lhs: Simd128
    rhs: Int32
  arguments:
    simdOp: wasm::SimdOp
  type_policy: none
  result_type: Simd128
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set: none
  clone: true

# (v128, v128, mask) -> v128 effect-free operation.
- name: WasmShuffleSimd128
  operands:
    lhs: Simd128
    rhs: Simd128
  arguments:
    shuffle: SimdShuffle
  type_policy: none
  result_type: Simd128
  movable: true
  congruent_to: custom
  alias_set: none
  clone: true

- name: WasmReplaceLaneSimd128
  gen_boilerplate: false

- name: WasmUnarySimd128
  operands:
    src: Simd128
  arguments:
    simdOp: wasm::SimdOp
  type_policy: none
  result_type: Simd128
  movable: true
  congruent_to: if_operands_and_arguments_equal
  alias_set: none
  clone: true
  generate_lir: true
  # temp is FPR (if in use).
  lir_temps: 1

- name: WasmTernarySimd128
  gen_boilerplate: false

- name: WasmScalarToSimd128
  gen_boilerplate: false

- name: WasmReduceSimd128
  gen_boilerplate: false

- name: WasmLoadLaneSimd128
  gen_boilerplate: false

- name: WasmStoreLaneSimd128
  gen_boilerplate: false

- name: UnreachableResult
  gen_boilerplate: false

- name: IonToWasmCall
  gen_boilerplate: false

- name: WasmLoadField
  gen_boilerplate: false

- name: WasmLoadElement
  gen_boilerplate: false

- name: WasmStoreField
  gen_boilerplate: false

- name: WasmStoreFieldRef
  gen_boilerplate: false

- name: WasmStoreElement
  gen_boilerplate: false

- name: WasmStoreElementRef
  gen_boilerplate: false

- name: WasmRefAsNonNull
  gen_boilerplate: false

- name: WasmRefTestConcrete
  gen_boilerplate: false

- name: WasmRefTestAbstract
  gen_boilerplate: false

- name: WasmRefCastConcrete
  gen_boilerplate: false

- name: WasmRefCastAbstract
  gen_boilerplate: false

# Produced by OptimizeWasmCasts when a cast is known to always succeed.
- name: WasmRefCastInfallible
  operands:
    ref: WasmAnyRef
  arguments:
    destType: wasm::RefType
  result_type: WasmAnyRef
  type_policy: none
  wasm_ref_type: wasm::MaybeRefType(destType)
  guard: true
  alias_set: none
  congruent_to: if_operands_and_arguments_equal

- name: WasmRefConvertAnyExtern
  gen_boilerplate: false

- name: WasmNewStructObject
  gen_boilerplate: false

- name: WasmNewArrayObject
  gen_boilerplate: false

- name: WasmAddSubI128HI64
  gen_boilerplate: false

- name: WasmMulI64WideHI64
  gen_boilerplate: false

#ifdef FUZZING_JS_FUZZILLI
- name: FuzzilliHash
  gen_boilerplate: false

- name: FuzzilliHashStore
  gen_boilerplate: false
#endif

#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
- name: AddDisposableResource
  operands:
    environment: Object
    resource: Value
    method: Value
    needsClosure: Boolean
  arguments:
    hint: uint8_t
  possibly_calls: true
  generate_lir: true

- name: TakeDisposeCapability
  operands:
    environment: Object
  result_type: Value
  generate_lir: true
#endif
