AirOpcode.opcodes   [plain text]


# Copyright (C) 2015-2017 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.

# Syllabus:
#
# Examples of some roles, types, and widths:
# U:G:32 => use of the low 32 bits of a general-purpose register or value
# D:G:32 => def of the low 32 bits of a general-purpose register or value
# UD:G:32 => use and def of the low 32 bits of a general-purpose register or value
# U:G:64 => use of the low 64 bits of a general-purpose register or value
# ZD:G:32 => def of all bits of a general-purpose register, where all but the low 32 bits are guaranteed to be zeroed.
# UA:G:Ptr => UseAddr (see comment in Arg.h)
# U:F:32 => use of a float register or value
# U:F:64 => use of a double register or value
# D:F:32 => def of a float register or value
# UD:F:32 => use and def of a float register or value
# S:F:32 => scratch float register.
#
# Argument kinds:
# Tmp => temporary or register
# Imm => 32-bit immediate int
# BigImm => TrustedImm64
# Addr => address as temporary/register+offset
# Index => BaseIndex address
# Abs => AbsoluteAddress
#
# The parser views these things as keywords, and understands that they fall into two distinct classes
# of things. So, although this file uses a particular indentation style, none of the whitespace or
# even newlines are meaningful to the parser. For example, you could write:
#
# Foo42 U:G:32, UD:F:32 Imm, Tmp Addr, Tmp
#
# And the parser would know that this is the same as:
#
# Foo42 U:G:32, UD:F:32
#     Imm, Tmp
#     Addr, Tmp
#
# I.e. a two-form instruction that uses a GPR or an int immediate and uses+defs a float register.
#
# Any opcode or opcode form can be preceded with an architecture list, which restricts the opcode to the
# union of those architectures. For example, if this is the only overload of the opcode, then it makes the
# opcode only available on x86_64:
#
# x86_64: Fuzz UD:G:64, D:G:64
#     Tmp, Tmp
#     Tmp, Addr
#
# But this only restricts the two-operand form, the other form is allowed on all architectures:
#
# x86_64: Fuzz UD:G:64, D:G:64
#     Tmp, Tmp
#     Tmp, Addr
# Fuzz UD:G:Ptr, D:G:Ptr, U:F:Ptr
#     Tmp, Tmp, Tmp
#     Tmp, Addr, Tmp
#
# And you can also restrict individual forms:
#
# Thingy UD:G:32, D:G:32
#     Tmp, Tmp
#     arm64: Tmp, Addr
#
# Additionally, you can have an intersection between the architectures of the opcode overload and the
# form. In this example, the version that takes an address is only available on armv7 while the other
# versions are available on armv7 or x86_64:
#
# x86_64 armv7: Buzz U:G:32, UD:F:32
#     Tmp, Tmp
#     Imm, Tmp
#     armv7: Addr, Tmp
#
# Finally, you can specify architectures using helpful architecture groups. Here are all of the
# architecture keywords that we support:
#
# x86: means x86-32 or x86-64.
# x86_32: means just x86-32.
# x86_64: means just x86-64.
# arm: means armv7 or arm64.
# armv7: means just armv7.
# arm64: means just arm64.
# 32: means x86-32 or armv7.
# 64: means x86-64 or arm64.

# Note that the opcodes here have a leading capital (Add32) but must correspond to MacroAssembler
# API that has a leading lower-case (add32).

Nop

Add32 U:G:32, U:G:32, ZD:G:32
    Imm, Tmp, Tmp
    Tmp, Tmp, Tmp

Add32 U:G:32, UZD:G:32
    Tmp, Tmp
    x86: Imm, Addr
    x86: Imm, Index
    Imm, Tmp
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index

x86: Add8 U:G:8, UD:G:8
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: Add16 U:G:16, UD:G:16
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

64: Add64 U:G:64, UD:G:64
    Tmp, Tmp
    x86: Imm, Addr
    x86: Imm, Index
    Imm, Tmp
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index

64: Add64 U:G:64, U:G:64, D:G:64
    Imm, Tmp, Tmp
    Tmp, Tmp, Tmp

AddDouble U:F:64, U:F:64, D:F:64
    Tmp, Tmp, Tmp
    x86: Addr, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Index, Tmp, Tmp

x86: AddDouble U:F:64, UD:F:64
    Tmp, Tmp
    Addr, Tmp

AddFloat U:F:32, U:F:32, D:F:32
    Tmp, Tmp, Tmp
    x86: Addr, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Index, Tmp, Tmp

x86: AddFloat U:F:32, UD:F:32
    Tmp, Tmp
    Addr, Tmp

Sub32 U:G:32, UZD:G:32
    Tmp, Tmp
    x86: Imm, Addr
    x86: Imm, Index
    Imm, Tmp
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index

arm64: Sub32 U:G:32, U:G:32, D:G:32
    Tmp, Tmp, Tmp

64: Sub64 U:G:64, UD:G:64
    Tmp, Tmp
    x86: Imm, Addr
    x86: Imm, Index
    Imm, Tmp
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index

arm64: Sub64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp

SubDouble U:F:64, U:F:64, D:F:64
    arm64: Tmp, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Tmp, Index, Tmp

x86: SubDouble U:F:64, UD:F:64
    Tmp, Tmp
    Addr, Tmp

SubFloat U:F:32, U:F:32, D:F:32
    arm64: Tmp, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Tmp, Index, Tmp

x86: SubFloat U:F:32, UD:F:32
    Tmp, Tmp
    Addr, Tmp

Neg32 UZD:G:32
    Tmp
    x86: Addr
    x86: Index

64: Neg64 UD:G:64
    Tmp
    x86: Addr
    x86: Index

arm64: NegateDouble U:F:64, D:F:64
    Tmp, Tmp

arm64: NegateFloat U:F:32, D:F:32
    Tmp, Tmp

Mul32 U:G:32, UZD:G:32
    Tmp, Tmp
    x86: Addr, Tmp

Mul32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    x86: Addr, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Imm, Tmp, Tmp

64: Mul64 U:G:64, UD:G:64
    Tmp, Tmp

Mul64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp

arm64: MultiplyAdd32 U:G:32, U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp, Tmp

arm64: MultiplyAdd64 U:G:64, U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp, Tmp

arm64: MultiplySub32 U:G:32, U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp, Tmp

arm64: MultiplySub64 U:G:64, U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp, Tmp

arm64: MultiplyNeg32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp

arm64: MultiplyNeg64 U:G:64, U:G:64, ZD:G:64
    Tmp, Tmp, Tmp

arm64: Div32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp

arm64: UDiv32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp

arm64: Div64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp

arm64: UDiv64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp

MulDouble U:F:64, U:F:64, D:F:64
    Tmp, Tmp, Tmp
    x86: Addr, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Index, Tmp, Tmp

x86: MulDouble U:F:64, UD:F:64
    Tmp, Tmp
    Addr, Tmp

MulFloat U:F:32, U:F:32, D:F:32
    Tmp, Tmp, Tmp
    x86: Addr, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Index, Tmp, Tmp

x86: MulFloat U:F:32, UD:F:32
    Tmp, Tmp
    Addr, Tmp

arm64: DivDouble U:F:64, U:F:32, D:F:64
    Tmp, Tmp, Tmp

x86: DivDouble U:F:64, UD:F:64
    Tmp, Tmp
    Addr, Tmp

arm64: DivFloat U:F:32, U:F:32, D:F:32
    Tmp, Tmp, Tmp

x86: DivFloat U:F:32, UD:F:32
    Tmp, Tmp
    Addr, Tmp

x86: X86ConvertToDoubleWord32 U:G:32, ZD:G:32
    Tmp*, Tmp*

x86_64: X86ConvertToQuadWord64 U:G:64, D:G:64
    Tmp*, Tmp*

x86: X86Div32 UZD:G:32, UZD:G:32, U:G:32
    Tmp*, Tmp*, Tmp

x86: X86UDiv32 UZD:G:32, UZD:G:32, U:G:32
    Tmp*, Tmp*, Tmp

x86_64: X86Div64 UZD:G:64, UZD:G:64, U:G:64
    Tmp*, Tmp*, Tmp

x86_64: X86UDiv64 UZD:G:64, UZD:G:64, U:G:64
    Tmp*, Tmp*, Tmp

Lea32 UA:G:32, D:G:32
    Addr, Tmp
    x86: Index, Tmp as x86Lea32

Lea64 UA:G:64, D:G:64
    Addr, Tmp
    x86: Index, Tmp as x86Lea64

And32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    arm64: BitImm, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Addr, Tmp, Tmp

And32 U:G:32, UZD:G:32
    Tmp, Tmp
    x86: Imm, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Imm, Addr
    x86: Imm, Index

64: And64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    arm64: BitImm64, Tmp, Tmp

x86_64: And64 U:G:64, UD:G:64
    Tmp, Tmp
    Imm, Tmp
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index
    Addr, Tmp
    Index, Tmp

AndDouble U:F:64, U:F:64, D:F:64
    Tmp, Tmp, Tmp

x86: AndDouble U:F:64, UD:F:64
    Tmp, Tmp

AndFloat U:F:32, U:F:32, D:F:32
    Tmp, Tmp, Tmp

x86: AndFloat U:F:32, UD:F:32
    Tmp, Tmp

OrDouble U:F:64, U:F:64, D:F:64
    Tmp, Tmp, Tmp

x86: OrDouble U:F:64, UD:F:64
    Tmp, Tmp

OrFloat U:F:32, U:F:32, D:F:32
    Tmp, Tmp, Tmp

x86: OrFloat U:F:32, UD:F:32
    Tmp, Tmp

x86: XorDouble U:F:64, U:F:64, D:F:64
    Tmp, Tmp, Tmp

x86: XorDouble U:F:64, UD:F:64
    Tmp, Tmp

x86: XorFloat U:F:32, U:F:32, D:F:32
    Tmp, Tmp, Tmp

x86: XorFloat U:F:32, UD:F:32
    Tmp, Tmp

arm64: Lshift32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86:Lshift32 U:G:32, UZD:G:32
    Tmp*, Tmp
    Imm, Tmp

arm64: Lshift64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86_64: Lshift64 U:G:64, UD:G:64
    Tmp*, Tmp
    Imm, Tmp

arm64: Rshift32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86: Rshift32 U:G:32, UZD:G:32
    Tmp*, Tmp
    Imm, Tmp

arm64: Rshift64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86_64: Rshift64 U:G:64, UD:G:64
    Tmp*, Tmp
    Imm, Tmp

arm64: Urshift32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86: Urshift32 U:G:32, UZD:G:32
    Tmp*, Tmp
    Imm, Tmp

arm64: Urshift64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86_64: Urshift64 U:G:64, UD:G:64
    Tmp*, Tmp
    Imm, Tmp

x86_64: RotateRight32 U:G:32, UZD:G:32
    Tmp*, Tmp
    Imm, Tmp

arm64: RotateRight32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86_64: RotateRight64 U:G:64, UD:G:64
    Tmp*, Tmp
    Imm, Tmp

arm64: RotateRight64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    Tmp, Imm, Tmp

x86_64: RotateLeft32 U:G:32, UZD:G:32
    Tmp*, Tmp
    Imm, Tmp

x86_64: RotateLeft64 U:G:64, UD:G:64
    Tmp*, Tmp
    Imm, Tmp

Or32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    arm64: BitImm, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Addr, Tmp, Tmp

Or32 U:G:32, UZD:G:32
    Tmp, Tmp
    x86: Imm, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Imm, Addr
    x86: Imm, Index

64: Or64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    arm64: BitImm64, Tmp, Tmp

64: Or64 U:G:64, UD:G:64
    Tmp, Tmp
    x86: Imm, Tmp
    x86: Imm, Addr
    x86: Imm, Index
    x86: Tmp, Addr
    x86: Tmp, Index
    x86: Addr, Tmp
    x86: Index, Tmp

Xor32 U:G:32, U:G:32, ZD:G:32
    Tmp, Tmp, Tmp
    arm64: BitImm, Tmp, Tmp
    x86: Tmp, Addr, Tmp
    x86: Addr, Tmp, Tmp

Xor32 U:G:32, UZD:G:32
    Tmp, Tmp
    x86: Imm, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Imm, Addr
    x86: Imm, Index

64: Xor64 U:G:64, U:G:64, D:G:64
    Tmp, Tmp, Tmp
    arm64: BitImm64, Tmp, Tmp

64: Xor64 U:G:64, UD:G:64
    Tmp, Tmp
    x86: Tmp, Addr
    x86: Tmp, Index
    x86: Addr, Tmp
    x86: Index, Tmp
    x86: Imm, Addr
    x86: Imm, Index
    x86: Imm, Tmp

arm64: Not32 U:G:32, ZD:G:32
    Tmp, Tmp

x86: Not32 UZD:G:32
    Tmp
    Addr
    Index

arm64: Not64 U:G:64, D:G:64
    Tmp, Tmp

x86_64: Not64 UD:G:64
    Tmp
    Addr
    Index

arm64: AbsDouble U:F:64, D:F:64
    Tmp, Tmp

arm64: AbsFloat U:F:32, D:F:32
    Tmp, Tmp

CeilDouble U:F:64, D:F:64
    Tmp, Tmp
    x86: Addr, Tmp

CeilFloat U:F:32, D:F:32
    Tmp, Tmp
    x86: Addr, Tmp

FloorDouble U:F:64, D:F:64
    Tmp, Tmp
    x86: Addr, Tmp

FloorFloat U:F:32, D:F:32
    Tmp, Tmp
    x86: Addr, Tmp

SqrtDouble U:F:64, D:F:64
    Tmp, Tmp
    x86: Addr, Tmp

SqrtFloat U:F:32, D:F:32
    Tmp, Tmp
    x86: Addr, Tmp

ConvertInt32ToDouble U:G:32, D:F:64
    Tmp, Tmp
    x86: Addr, Tmp

64: ConvertInt64ToDouble U:G:64, D:F:64
    Tmp, Tmp
    x86_64: Addr, Tmp

ConvertInt32ToFloat U:G:32, D:F:32
    Tmp, Tmp
    x86: Addr, Tmp

64: ConvertInt64ToFloat U:G:64, D:F:32
    Tmp, Tmp
    x86_64: Addr, Tmp

CountLeadingZeros32 U:G:32, ZD:G:32
    Tmp, Tmp
    x86: Addr, Tmp

64: CountLeadingZeros64 U:G:64, D:G:64
    Tmp, Tmp
    x86: Addr, Tmp

ConvertDoubleToFloat U:F:64, D:F:32
    Tmp, Tmp
    x86: Addr, Tmp

ConvertFloatToDouble U:F:32, D:F:64
    Tmp, Tmp
    x86: Addr, Tmp

# Note that Move operates over the full register size, which is either 32-bit or 64-bit depending on
# the platform. I'm not entirely sure that this is a good thing; it might be better to just have a
# Move64 instruction. OTOH, our MacroAssemblers already have this notion of "move()" that basically
# means movePtr.
Move U:G:Ptr, D:G:Ptr
    Tmp, Tmp
    Imm, Tmp as signExtend32ToPtr
    BigImm, Tmp
    Addr, Tmp as loadPtr # This means that "Move Addr, Tmp" is code-generated as "load" not "move".
    Index, Tmp as loadPtr
    Tmp, Addr as storePtr
    Tmp, Index as storePtr
    x86: Imm, Addr as storePtr

# This is for moving between spill slots.
Move U:G:Ptr, D:G:Ptr, S:G:Ptr
    Addr, Addr, Tmp

x86: Swap32 UD:G:32, UD:G:32
    Tmp, Tmp
    Tmp, Addr

x86_64: Swap64 UD:G:64, UD:G:64
    Tmp, Tmp
    Tmp, Addr

Move32 U:G:32, ZD:G:32
    Tmp, Tmp as zeroExtend32ToPtr
    Addr, Tmp as load32
    Index, Tmp as load32
    Tmp, Addr as store32
    Tmp, Index as store32
    x86: Imm, Tmp as zeroExtend32ToPtr
    x86: Imm, Addr as store32
    x86: Imm, Index as store32

# This is for moving between spill slots.
Move32 U:G:32, ZD:G:32, S:G:32
    Addr, Addr, Tmp

# FIXME: StoreZero32 and StoreZero64 are hacks on ARM64, we can do better: https://bugs.webkit.org/show_bug.cgi?id=174821
StoreZero32 D:G:32
    Addr
    Index

64: StoreZero64 D:G:64
    Addr
    Index

SignExtend32ToPtr U:G:32, D:G:Ptr
    Tmp, Tmp

ZeroExtend8To32 U:G:8, ZD:G:32
    Tmp, Tmp
    x86: Addr, Tmp as load8
    x86: Index, Tmp as load8

SignExtend8To32 U:G:8, ZD:G:32
    Tmp, Tmp
    x86: Addr, Tmp as load8SignedExtendTo32
    x86: Index, Tmp as load8SignedExtendTo32

ZeroExtend16To32 U:G:16, ZD:G:32
    Tmp, Tmp
    x86: Addr, Tmp as load16
    x86: Index, Tmp as load16

SignExtend16To32 U:G:16, ZD:G:32
    Tmp, Tmp
    x86: Addr, Tmp as load16SignedExtendTo32
    x86: Index, Tmp as load16SignedExtendTo32

MoveFloat U:F:32, D:F:32
    Tmp, Tmp as moveDouble
    Addr, Tmp as loadFloat
    Index, Tmp as loadFloat
    Tmp, Addr as storeFloat
    Tmp, Index as storeFloat

MoveFloat U:F:32, D:F:32, S:F:32
    Addr, Addr, Tmp

MoveDouble U:F:64, D:F:64
    Tmp, Tmp
    Addr, Tmp as loadDouble
    Index, Tmp as loadDouble
    Tmp, Addr as storeDouble
    Tmp, Index as storeDouble

MoveDouble U:F:64, D:F:64, S:F:64
    Addr, Addr, Tmp

MoveZeroToDouble D:F:64
    Tmp

64: Move64ToDouble U:G:64, D:F:64
    Tmp, Tmp
    x86: Addr, Tmp as loadDouble
    Index, Tmp as loadDouble

Move32ToFloat U:G:32, D:F:32
    Tmp, Tmp
    x86: Addr, Tmp as loadFloat
    Index, Tmp as loadFloat

64: MoveDoubleTo64 U:F:64, D:G:64
    Tmp, Tmp
    Addr, Tmp as load64
    Index, Tmp as load64

MoveFloatTo32 U:F:32, D:G:32
    Tmp, Tmp
    Addr, Tmp as load32
    Index, Tmp as load32

Load8 U:G:8, ZD:G:32
    Addr, Tmp
    Index, Tmp

arm: LoadAcq8 U:G:8, ZD:G:32 /effects
    SimpleAddr, Tmp

Store8 U:G:8, D:G:8
    Tmp, Index
    Tmp, Addr
    x86: Imm, Index
    x86: Imm, Addr

arm: StoreRel8 U:G:8, D:G:8 /effects
    Tmp, SimpleAddr

Load8SignedExtendTo32 U:G:8, ZD:G:32
    Addr, Tmp
    Index, Tmp

arm: LoadAcq8SignedExtendTo32 U:G:8, ZD:G:32 /effects
    SimpleAddr, Tmp

Load16 U:G:16, ZD:G:32
    Addr, Tmp
    Index, Tmp

arm: LoadAcq16 U:G:16, ZD:G:32 /effects
    SimpleAddr, Tmp

Load16SignedExtendTo32 U:G:16, ZD:G:32
    Addr, Tmp
    Index, Tmp

arm: LoadAcq16SignedExtendTo32 U:G:16, ZD:G:32 /effects
    SimpleAddr, Tmp

Store16 U:G:16, D:G:16
    Tmp, Index
    Tmp, Addr
    x86: Imm, Index
    x86: Imm, Addr

arm: StoreRel16 U:G:16, D:G:16 /effects
    Tmp, SimpleAddr

arm: LoadAcq32 U:G:32, ZD:G:32 /effects
    SimpleAddr, Tmp

arm: StoreRel32 U:G:32, ZD:G:32 /effects
    Tmp, SimpleAddr

arm64: LoadAcq64 U:G:64, ZD:G:64 /effects
    SimpleAddr, Tmp

arm64: StoreRel64 U:G:64, ZD:G:64 /effects
    Tmp, SimpleAddr

x86: Xchg8 UD:G:8, UD:G:8 /effects
    Tmp, Addr
    Tmp, Index

x86: Xchg16 UD:G:16, UD:G:16 /effects
    Tmp, Addr
    Tmp, Index

x86: Xchg32 UD:G:32, UD:G:32 /effects
    Tmp, Addr
    Tmp, Index

x86_64: Xchg64 UD:G:64, UD:G:64 /effects
    Tmp, Addr
    Tmp, Index

# The first operand is rax.
# FIXME: This formulation means that the boolean result cannot be put in eax, even though all users
# of this would be OK with that.
# https://bugs.webkit.org/show_bug.cgi?id=169254
x86: AtomicStrongCAS8 U:G:32, UD:G:8, U:G:8, UD:G:8, ZD:G:8 /effects
    StatusCond, Tmp*, Tmp, Addr, Tmp
    StatusCond, Tmp*, Tmp, Index, Tmp

x86: AtomicStrongCAS16 U:G:32, UD:G:16, U:G:32, UD:G:16, ZD:G:8 /effects
    StatusCond, Tmp*, Tmp, Addr, Tmp
    StatusCond, Tmp*, Tmp, Index, Tmp

x86: AtomicStrongCAS32 U:G:32, UD:G:32, U:G:32, UD:G:32, ZD:G:8 /effects
    StatusCond, Tmp*, Tmp, Addr, Tmp
    StatusCond, Tmp*, Tmp, Index, Tmp

x86_64: AtomicStrongCAS64 U:G:32, UD:G:64, U:G:64, UD:G:64, ZD:G:8 /effects
    StatusCond, Tmp*, Tmp, Addr, Tmp
    StatusCond, Tmp*, Tmp, Index, Tmp

x86: AtomicStrongCAS8 UD:G:8, U:G:8, UD:G:8 /effects
    Tmp*, Tmp, Addr
    Tmp*, Tmp, Index

x86: AtomicStrongCAS16 UD:G:16, U:G:32, UD:G:16 /effects
    Tmp*, Tmp, Addr
    Tmp*, Tmp, Index

x86: AtomicStrongCAS32 UD:G:32, U:G:32, UD:G:32 /effects
    Tmp*, Tmp, Addr
    Tmp*, Tmp, Index

x86_64: AtomicStrongCAS64 UD:G:64, U:G:64, UD:G:64 /effects
    Tmp*, Tmp, Addr
    Tmp*, Tmp, Index

x86: BranchAtomicStrongCAS8 U:G:32, UD:G:8, U:G:8, UD:G:8 /branch /effects
    StatusCond, Tmp*, Tmp, Addr
    StatusCond, Tmp*, Tmp, Index

x86: BranchAtomicStrongCAS16 U:G:32, UD:G:16, U:G:32, UD:G:16 /branch /effects
    StatusCond, Tmp*, Tmp, Addr
    StatusCond, Tmp*, Tmp, Index

x86: BranchAtomicStrongCAS32 U:G:32, UD:G:32, U:G:32, UD:G:32 /branch /effects
    StatusCond, Tmp*, Tmp, Addr
    StatusCond, Tmp*, Tmp, Index

x86_64: BranchAtomicStrongCAS64 U:G:32, UD:G:64, U:G:64, UD:G:64 /branch /effects
    StatusCond, Tmp*, Tmp, Addr
    StatusCond, Tmp*, Tmp, Index

x86: AtomicAdd8 U:G:8, UD:G:8 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicAdd16 U:G:16, UD:G:16 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicAdd32 U:G:32, UD:G:32 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86_64: AtomicAdd64 U:G:64, UD:G:64 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicSub8 U:G:8, UD:G:8 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicSub16 U:G:16, UD:G:16 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicSub32 U:G:32, UD:G:32 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86_64: AtomicSub64 U:G:64, UD:G:64 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicAnd8 U:G:8, UD:G:8 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicAnd16 U:G:16, UD:G:16 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicAnd32 U:G:32, UD:G:32 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86_64: AtomicAnd64 U:G:64, UD:G:64 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicOr8 U:G:8, UD:G:8 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicOr16 U:G:16, UD:G:16 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicOr32 U:G:32, UD:G:32 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86_64: AtomicOr64 U:G:64, UD:G:64 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicXor8 U:G:8, UD:G:8 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicXor16 U:G:16, UD:G:16 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicXor32 U:G:32, UD:G:32 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86_64: AtomicXor64 U:G:64, UD:G:64 /effects
    Imm, Addr
    Imm, Index
    Tmp, Addr
    Tmp, Index

x86: AtomicNeg8 UD:G:8 /effects
    Addr
    Index

x86: AtomicNeg16 UD:G:16 /effects
    Addr
    Index

x86: AtomicNeg32 UD:G:32 /effects
    Addr
    Index

x86_64: AtomicNeg64 UD:G:64 /effects
    Addr
    Index

x86: AtomicNot8 UD:G:8 /effects
    Addr
    Index

x86: AtomicNot16 UD:G:16 /effects
    Addr
    Index

x86: AtomicNot32 UD:G:32 /effects
    Addr
    Index

x86_64: AtomicNot64 UD:G:64 /effects
    Addr
    Index

x86: AtomicXchgAdd8 UD:G:8, UD:G:8 /effects
    Tmp, Addr
    Tmp, Index

x86: AtomicXchgAdd16 UD:G:16, UD:G:16 /effects
    Tmp, Addr
    Tmp, Index

x86: AtomicXchgAdd32 UD:G:32, UD:G:32 /effects
    Tmp, Addr
    Tmp, Index

x86_64: AtomicXchgAdd64 UD:G:64, UD:G:64 /effects
    Tmp, Addr
    Tmp, Index

x86: AtomicXchg8 UD:G:8, UD:G:8 /effects
    Tmp, Addr
    Tmp, Index

x86: AtomicXchg16 UD:G:16, UD:G:16 /effects
    Tmp, Addr
    Tmp, Index

x86: AtomicXchg32 UD:G:32, UD:G:32 /effects
    Tmp, Addr
    Tmp, Index

x86_64: AtomicXchg64 UD:G:64, UD:G:64 /effects
    Tmp, Addr
    Tmp, Index

arm64: LoadLink8 U:G:8, ZD:G:8 /effects
    SimpleAddr, Tmp

arm64: LoadLinkAcq8 U:G:8, ZD:G:8 /effects
    SimpleAddr, Tmp

# Super confusing fact: this returns 0 to mean success, 1 to mean failure.
arm64: StoreCond8 U:G:8, D:G:8, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: StoreCondRel8 U:G:8, D:G:8, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: LoadLink16 U:G:16, ZD:G:16 /effects
    SimpleAddr, Tmp

arm64: LoadLinkAcq16 U:G:16, ZD:G:16 /effects
    SimpleAddr, Tmp

arm64: StoreCond16 U:G:16, D:G:16, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: StoreCondRel16 U:G:16, D:G:16, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: LoadLink32 U:G:32, ZD:G:32 /effects
    SimpleAddr, Tmp

arm64: LoadLinkAcq32 U:G:32, ZD:G:32 /effects
    SimpleAddr, Tmp

arm64: StoreCond32 U:G:32, D:G:32, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: StoreCondRel32 U:G:32, D:G:32, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: LoadLink64 U:G:64, ZD:G:64 /effects
    SimpleAddr, Tmp

arm64: LoadLinkAcq64 U:G:64, ZD:G:64 /effects
    SimpleAddr, Tmp

arm64: StoreCond64 U:G:64, D:G:64, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: StoreCondRel64 U:G:64, D:G:64, EZD:G:8 /effects
    Tmp, SimpleAddr, Tmp

arm64: Depend32 U:G:32, ZD:G:32
    Tmp, Tmp

arm64: Depend64 U:G:64, ZD:G:64
    Tmp, Tmp

Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32
    RelCond, Tmp, Tmp, Tmp
    RelCond, Tmp, Imm, Tmp

64: Compare64 U:G:32, U:G:64, U:G:64, ZD:G:32
    RelCond, Tmp, Tmp, Tmp
    x86: RelCond, Tmp, Imm, Tmp

Test32 U:G:32, U:G:32, U:G:32, ZD:G:32
    x86: ResCond, Addr, Imm, Tmp
    ResCond, Tmp, Tmp, Tmp
    ResCond, Tmp, BitImm, Tmp

64: Test64 U:G:32, U:G:64, U:G:64, ZD:G:32
    x86: ResCond, Tmp, Imm, Tmp
    ResCond, Tmp, Tmp, Tmp

CompareDouble U:G:32, U:F:64, U:F:64, ZD:G:32
    DoubleCond, Tmp, Tmp, Tmp

CompareFloat U:G:32, U:F:32, U:F:32, ZD:G:32
    DoubleCond, Tmp, Tmp, Tmp

# Note that branches have some logic in AirOptimizeBlockOrder.cpp. If you add new branches, please make sure
# you opt them into the block order optimizations.

Branch8 U:G:32, U:G:8, U:G:8 /branch
    x86: RelCond, Addr, Imm
    x86: RelCond, Index, Imm

Branch32 U:G:32, U:G:32, U:G:32 /branch
    x86: RelCond, Addr, Imm
    RelCond, Tmp, Tmp
    RelCond, Tmp, Imm
    x86: RelCond, Tmp, Addr
    x86: RelCond, Addr, Tmp
    x86: RelCond, Index, Imm

64: Branch64 U:G:32, U:G:64, U:G:64 /branch
    RelCond, Tmp, Tmp
    RelCond, Tmp, Imm
    x86: RelCond, Tmp, Addr
    x86: RelCond, Addr, Tmp
    x86: RelCond, Addr, Imm
    x86: RelCond, Index, Tmp

BranchTest8 U:G:32, U:G:8, U:G:8 /branch
    x86: ResCond, Addr, BitImm
    x86: ResCond, Index, BitImm

BranchTest32 U:G:32, U:G:32, U:G:32 /branch
    ResCond, Tmp, Tmp
    ResCond, Tmp, BitImm
    x86: ResCond, Addr, BitImm
    x86: ResCond, Index, BitImm

# Warning: forms that take an immediate will sign-extend their immediate. You probably want
# BranchTest32 in most cases where you use an immediate.
64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
    ResCond, Tmp, Tmp
    arm64: ResCond, Tmp, BitImm64
    x86: ResCond, Tmp, BitImm
    x86: ResCond, Addr, BitImm
    x86: ResCond, Addr, Tmp
    x86: ResCond, Index, BitImm

BranchDouble U:G:32, U:F:64, U:F:64 /branch
    DoubleCond, Tmp, Tmp

BranchFloat U:G:32, U:F:32, U:F:32 /branch
    DoubleCond, Tmp, Tmp

BranchAdd32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
    ResCond, Tmp, Tmp, Tmp
    x86:ResCond, Tmp, Addr, Tmp
    x86:ResCond, Addr, Tmp, Tmp

BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch
    ResCond, Tmp, Tmp
    ResCond, Imm, Tmp
    x86: ResCond, Imm, Addr
    x86: ResCond, Tmp, Addr
    x86: ResCond, Addr, Tmp

BranchAdd64 U:G:32, U:G:64, U:G:64, ZD:G:64 /branch
    ResCond, Tmp, Tmp, Tmp
    x86:ResCond, Tmp, Addr, Tmp
    x86:ResCond, Addr, Tmp, Tmp

64: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch
    ResCond, Imm, Tmp
    ResCond, Tmp, Tmp
    x86:ResCond, Addr, Tmp

x86: BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch
    ResCond, Tmp, Tmp
    ResCond, Addr, Tmp

x86: BranchMul32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
    ResCond, Tmp, Imm, Tmp

arm64: BranchMul32 U:G:32, U:G:32, U:G:32, S:G:32, S:G:32, ZD:G:32 /branch
    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp

x86_64: BranchMul64 U:G:32, U:G:64, UZD:G:64 /branch
    ResCond, Tmp, Tmp

arm64: BranchMul64 U:G:32, U:G:64, U:G:64, S:G:64, S:G:64, ZD:G:64 /branch
    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp

BranchSub32 U:G:32, U:G:32, UZD:G:32 /branch
    ResCond, Tmp, Tmp
    ResCond, Imm, Tmp
    x86: ResCond, Imm, Addr
    x86: ResCond, Tmp, Addr
    x86: ResCond, Addr, Tmp

64: BranchSub64 U:G:32, U:G:64, UD:G:64 /branch
    ResCond, Imm, Tmp
    ResCond, Tmp, Tmp

BranchNeg32 U:G:32, UZD:G:32 /branch
    ResCond, Tmp

64: BranchNeg64 U:G:32, UZD:G:64 /branch
    ResCond, Tmp

MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
    RelCond, Tmp, Tmp, Tmp, Tmp

MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
    RelCond, Tmp, Imm, Tmp, Tmp, Tmp

64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
    RelCond, Tmp, Tmp, Tmp, Tmp

64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
    RelCond, Tmp, Imm, Tmp, Tmp, Tmp

MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
    ResCond, Tmp, Tmp, Tmp, Tmp
    x86: ResCond, Tmp, Imm, Tmp, Tmp

MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
    ResCond, Tmp, BitImm, Tmp, Tmp, Tmp

64: MoveConditionallyTest64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
    ResCond, Tmp, Tmp, Tmp, Tmp
    x86: ResCond, Tmp, Imm, Tmp, Tmp

64: MoveConditionallyTest64 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
    x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp

MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp

MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, UD:G:Ptr
    DoubleCond, Tmp, Tmp, Tmp, Tmp

MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp

MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
    DoubleCond, Tmp, Tmp, Tmp, Tmp

MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
    x86: RelCond, Addr, Imm, Tmp, Tmp, Tmp
    x86: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
    x86: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
    x86: RelCond, Index, Imm, Tmp, Tmp, Tmp

64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
    x86_64: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
    x86_64: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
    x86_64: RelCond, Addr, Imm, Tmp, Tmp, Tmp
    x86_64: RelCond, Index, Tmp, Tmp, Tmp, Tmp

MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
    ResCond, Tmp, BitImm, Tmp, Tmp, Tmp
    x86: ResCond, Addr, Imm, Tmp, Tmp, Tmp
    x86: ResCond, Index, Imm, Tmp, Tmp, Tmp

# Warning: forms that take an immediate will sign-extend their immediate. You probably want
# MoveDoubleConditionallyTest32 in most cases where you use an immediate.
64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
    x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
    x86_64: ResCond, Addr, Imm, Tmp, Tmp, Tmp
    x86_64: ResCond, Addr, Tmp, Tmp, Tmp, Tmp
    x86_64: ResCond, Index, Imm, Tmp, Tmp, Tmp

MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, U:F:64, D:F:64
    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp

MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, U:F:64, D:F:64
    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp

MemoryFence /effects
StoreFence /effects
LoadFence /effects

Jump /branch

RetVoid /return

Ret32 U:G:32 /return
    Tmp

64: Ret64 U:G:64 /return
    Tmp

RetFloat U:F:32 /return
    Tmp

RetDouble U:F:64 /return
    Tmp

Oops /terminal

# This is a terminal but we express it as a Custom because we don't want it to have a code
# generator.
custom EntrySwitch

# A Shuffle is a multi-source, multi-destination move. It simultaneously does multiple moves at once.
# The moves are specified as triplets of src, dst, and width. For example you can request a swap this
# way:
#     Shuffle %tmp1, %tmp2, 64, %tmp2, %tmp1, 64
custom Shuffle

# Air allows for exotic behavior. A Patch's behavior is determined entirely by the Special operand,
# which must be the first operand.
custom Patch

# Instructions used for lowering C calls. These don't make it to Air generation. They get lowered to
# something else first. The origin Value must be a CCallValue.
custom CCall
custom ColdCCall

# This is a special wasm opcode that branches to a trap handler. This uses the generator located to Air::Code
# to produce the side-exit code.
custom WasmBoundsCheck