//     opcode name,             return type,    arg1 type,      arg2 type,      arg3 type,      ...

OPCODE(Void,                    T::Void,                                                        )
OPCODE(Identity,                T::Opaque,      T::Opaque                                       )
OPCODE(Breakpoint,              T::Void,                                                        )

// A32 Context getters/setters
A32OPC(GetRegister,             T::U32,         T::A32Reg                                       )
A32OPC(GetExtendedRegister32,   T::U32,         T::A32ExtReg                                    )
A32OPC(GetExtendedRegister64,   T::U64,         T::A32ExtReg                                    )
A32OPC(SetRegister,             T::Void,        T::A32Reg,      T::U32                          )
A32OPC(SetExtendedRegister32,   T::Void,        T::A32ExtReg,   T::U32                          )
A32OPC(SetExtendedRegister64,   T::Void,        T::A32ExtReg,   T::U64                          )
A32OPC(GetCpsr,                 T::U32,                                                         )
A32OPC(SetCpsr,                 T::Void,        T::U32                                          )
A32OPC(SetCpsrNZCV,             T::Void,        T::U32                                          )
A32OPC(SetCpsrNZCVQ,            T::Void,        T::U32                                          )
A32OPC(GetNFlag,                T::U1,                                                          )
A32OPC(SetNFlag,                T::Void,        T::U1                                           )
A32OPC(GetZFlag,                T::U1,                                                          )
A32OPC(SetZFlag,                T::Void,        T::U1                                           )
A32OPC(GetCFlag,                T::U1,                                                          )
A32OPC(SetCFlag,                T::Void,        T::U1                                           )
A32OPC(GetVFlag,                T::U1,                                                          )
A32OPC(SetVFlag,                T::Void,        T::U1                                           )
A32OPC(OrQFlag,                 T::Void,        T::U1                                           )
A32OPC(GetGEFlags,              T::U32,                                                         )
A32OPC(SetGEFlags,              T::Void,        T::U32                                          )
A32OPC(SetGEFlagsCompressed,    T::Void,        T::U32                                          )
A32OPC(BXWritePC,               T::Void,        T::U32                                          )
A32OPC(CallSupervisor,          T::Void,        T::U32                                          )
A32OPC(GetFpscr,                T::U32,                                                         )
A32OPC(SetFpscr,                T::Void,        T::U32,                                         )
A32OPC(GetFpscrNZCV,            T::U32,                                                         )
A32OPC(SetFpscrNZCV,            T::Void,        T::U32,                                         )

// A64 Context getters/setters
A64OPC(SetCheckBit,             T::Void,        T::U1                                           )
A64OPC(GetCFlag,                T::U1,                                                          )
A64OPC(SetNZCV,                 T::Void,        T::NZCVFlags                                    )
A64OPC(GetW,                    T::U32,         T::A64Reg                                       )
A64OPC(GetX,                    T::U64,         T::A64Reg                                       )
//A64OPC(GetB,                    T::U128,        T::A64Vec                                       )
//A64OPC(GetH,                    T::U128,        T::A64Vec                                       )
//A64OPC(GetS,                    T::U128,        T::A64Vec                                       )
A64OPC(GetD,                    T::U128,        T::A64Vec                                       )
A64OPC(GetQ,                    T::U128,        T::A64Vec                                       )
A64OPC(GetSP,                   T::U64,                                                         )
A64OPC(SetW,                    T::Void,        T::A64Reg,      T::U32                          )
A64OPC(SetX,                    T::Void,        T::A64Reg,      T::U64                          )
//A64OPC(SetB,                    T::Void,        T::A64Vec,      T::U8                           )
//A64OPC(SetH,                    T::Void,        T::A64Vec,      T::U16                          )
//A64OPC(SetS,                    T::Void,        T::A64Vec,      T::U32                          )
A64OPC(SetD,                    T::Void,        T::A64Vec,      T::U128                         )
A64OPC(SetQ,                    T::Void,        T::A64Vec,      T::U128                         )
A64OPC(SetSP,                   T::Void,        T::U64                                          )
A64OPC(SetPC,                   T::Void,        T::U64                                          )
A64OPC(CallSupervisor,          T::Void,        T::U32                                          )
A64OPC(ExceptionRaised,         T::Void,        T::U64,         T::U64                          )

// Hints
OPCODE(PushRSB,                 T::Void,        T::U64                                          )

// Pseudo-operation, handled specially at final emit
OPCODE(GetCarryFromOp,          T::U1,          T::U32                                          )
OPCODE(GetOverflowFromOp,       T::U1,          T::U32                                          )
OPCODE(GetGEFromOp,             T::U32,         T::U32                                          )
OPCODE(GetNZCVFromOp,           T::NZCVFlags,   T::Opaque                                       )

// Calculations
OPCODE(Pack2x32To1x64,          T::U64,         T::U32,         T::U32                          )
OPCODE(LeastSignificantWord,    T::U32,         T::U64                                          )
OPCODE(MostSignificantWord,     T::U32,         T::U64                                          )
OPCODE(LeastSignificantHalf,    T::U16,         T::U32                                          )
OPCODE(LeastSignificantByte,    T::U8,          T::U32                                          )
OPCODE(MostSignificantBit,      T::U1,          T::U32                                          )
OPCODE(IsZero32,                T::U1,          T::U32                                          )
OPCODE(IsZero64,                T::U1,          T::U64                                          )
OPCODE(TestBit,                 T::U1,          T::U64,         T::U8                           )
OPCODE(ConditionalSelect32,     T::U32,         T::Cond,        T::U32,         T::U32          )
OPCODE(ConditionalSelect64,     T::U64,         T::Cond,        T::U64,         T::U64          )
OPCODE(LogicalShiftLeft32,      T::U32,         T::U32,         T::U8,          T::U1           )
OPCODE(LogicalShiftLeft64,      T::U64,         T::U64,         T::U8                           )
OPCODE(LogicalShiftRight32,     T::U32,         T::U32,         T::U8,          T::U1           )
OPCODE(LogicalShiftRight64,     T::U64,         T::U64,         T::U8                           )
OPCODE(ArithmeticShiftRight32,  T::U32,         T::U32,         T::U8,          T::U1           )
OPCODE(ArithmeticShiftRight64,  T::U64,         T::U64,         T::U8                           )
OPCODE(RotateRight32,           T::U32,         T::U32,         T::U8,          T::U1           )
OPCODE(RotateRight64,           T::U64,         T::U64,         T::U8                           )
OPCODE(RotateRightExtended,     T::U32,         T::U32,         T::U1                           )
OPCODE(Add32,                   T::U32,         T::U32,         T::U32,         T::U1           )
OPCODE(Add64,                   T::U64,         T::U64,         T::U64,         T::U1           )
OPCODE(Sub32,                   T::U32,         T::U32,         T::U32,         T::U1           )
OPCODE(Sub64,                   T::U64,         T::U64,         T::U64,         T::U1           )
OPCODE(Mul32,                   T::U32,         T::U32,         T::U32                          )
OPCODE(Mul64,                   T::U64,         T::U64,         T::U64                          )
OPCODE(And32,                   T::U32,         T::U32,         T::U32                          )
OPCODE(And64,                   T::U64,         T::U64,         T::U64                          )
OPCODE(Eor32,                   T::U32,         T::U32,         T::U32                          )
OPCODE(Eor64,                   T::U64,         T::U64,         T::U64                          )
OPCODE(Or32,                    T::U32,         T::U32,         T::U32                          )
OPCODE(Or64,                    T::U64,         T::U64,         T::U64                          )
OPCODE(Not32,                   T::U32,         T::U32                                          )
OPCODE(Not64,                   T::U64,         T::U64                                          )
OPCODE(SignExtendByteToWord,    T::U32,         T::U8                                           )
OPCODE(SignExtendHalfToWord,    T::U32,         T::U16                                          )
OPCODE(SignExtendByteToLong,    T::U64,         T::U8                                           )
OPCODE(SignExtendHalfToLong,    T::U64,         T::U16                                          )
OPCODE(SignExtendWordToLong,    T::U64,         T::U32                                          )
OPCODE(ZeroExtendByteToWord,    T::U32,         T::U8                                           )
OPCODE(ZeroExtendHalfToWord,    T::U32,         T::U16                                          )
OPCODE(ZeroExtendByteToLong,    T::U64,         T::U8                                           )
OPCODE(ZeroExtendHalfToLong,    T::U64,         T::U16                                          )
OPCODE(ZeroExtendWordToLong,    T::U64,         T::U32                                          )
OPCODE(ByteReverseWord,         T::U32,         T::U32                                          )
OPCODE(ByteReverseHalf,         T::U16,         T::U16                                          )
OPCODE(ByteReverseDual,         T::U64,         T::U64                                          )
OPCODE(CountLeadingZeros,       T::U32,         T::U32                                          )

// Saturated instructions
OPCODE(SignedSaturatedAdd,      T::U32,         T::U32,         T::U32                          )
OPCODE(SignedSaturatedSub,      T::U32,         T::U32,         T::U32                          )
OPCODE(UnsignedSaturation,      T::U32,         T::U32,         T::U8                           )
OPCODE(SignedSaturation,        T::U32,         T::U32,         T::U8                           )

// Packed instructions
OPCODE(PackedAddU8,             T::U32,         T::U32,         T::U32                          )
OPCODE(PackedAddS8,             T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSubU8,             T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSubS8,             T::U32,         T::U32,         T::U32                          )
OPCODE(PackedAddU16,            T::U32,         T::U32,         T::U32                          )
OPCODE(PackedAddS16,            T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSubU16,            T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSubS16,            T::U32,         T::U32,         T::U32                          )
OPCODE(PackedAddSubU16,         T::U32,         T::U32,         T::U32                          )
OPCODE(PackedAddSubS16,         T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSubAddU16,         T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSubAddS16,         T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingAddU8,      T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingAddS8,      T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingSubU8,      T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingSubS8,      T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingAddU16,     T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingAddS16,     T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingSubU16,     T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingSubS16,     T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingAddSubU16,  T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingAddSubS16,  T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingSubAddU16,  T::U32,         T::U32,         T::U32                          )
OPCODE(PackedHalvingSubAddS16,  T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedAddU8,    T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedAddS8,    T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedSubU8,    T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedSubS8,    T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedAddU16,   T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedAddS16,   T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedSubU16,   T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSaturatedSubS16,   T::U32,         T::U32,         T::U32                          )
OPCODE(PackedAbsDiffSumS8,      T::U32,         T::U32,         T::U32                          )
OPCODE(PackedSelect,            T::U32,         T::U32,         T::U32,         T::U32          )

// Vector instructions
OPCODE(VectorAdd8,              T::U128,        T::U128,        T::U128                         )
OPCODE(VectorAdd16,             T::U128,        T::U128,        T::U128                         )
OPCODE(VectorAdd32,             T::U128,        T::U128,        T::U128                         )
OPCODE(VectorAdd64,             T::U128,        T::U128,        T::U128                         )
OPCODE(VectorAnd,               T::U128,        T::U128,        T::U128                         )

// Floating-point operations
OPCODE(FPAbs32,                 T::U32,         T::U32                                          )
OPCODE(FPAbs64,                 T::U64,         T::U64                                          )
OPCODE(FPAdd32,                 T::U32,         T::U32,         T::U32                          )
OPCODE(FPAdd64,                 T::U64,         T::U64,         T::U64                          )
OPCODE(FPCompare32,             T::Void,        T::U32,         T::U32,         T::U1           )
OPCODE(FPCompare64,             T::Void,        T::U64,         T::U64,         T::U1           )
OPCODE(FPDiv32,                 T::U32,         T::U32,         T::U32                          )
OPCODE(FPDiv64,                 T::U64,         T::U64,         T::U64                          )
OPCODE(FPMul32,                 T::U32,         T::U32,         T::U32                          )
OPCODE(FPMul64,                 T::U64,         T::U64,         T::U64                          )
OPCODE(FPNeg32,                 T::U32,         T::U32                                          )
OPCODE(FPNeg64,                 T::U64,         T::U64                                          )
OPCODE(FPSqrt32,                T::U32,         T::U32                                          )
OPCODE(FPSqrt64,                T::U64,         T::U64                                          )
OPCODE(FPSub32,                 T::U32,         T::U32,         T::U32                          )
OPCODE(FPSub64,                 T::U64,         T::U64,         T::U64                          )

// Floating-point conversions
OPCODE(FPSingleToDouble,        T::U64,         T::U32                                          )
OPCODE(FPDoubleToSingle,        T::U32,         T::U64                                          )
OPCODE(FPSingleToU32,           T::U32,         T::U32,         T::U1                           )
OPCODE(FPSingleToS32,           T::U32,         T::U32,         T::U1                           )
OPCODE(FPDoubleToU32,           T::U32,         T::U64,         T::U1                           )
OPCODE(FPDoubleToS32,           T::U32,         T::U64,         T::U1                           )
OPCODE(FPU32ToSingle,           T::U32,         T::U32,         T::U1                           )
OPCODE(FPS32ToSingle,           T::U32,         T::U32,         T::U1                           )
OPCODE(FPU32ToDouble,           T::U64,         T::U32,         T::U1                           )
OPCODE(FPS32ToDouble,           T::U64,         T::U32,         T::U1                           )

// A32 Memory access
A32OPC(ClearExclusive,          T::Void,                                                        )
A32OPC(SetExclusive,            T::Void,        T::U32,         T::U8                           )
A32OPC(ReadMemory8,             T::U8,          T::U32                                          )
A32OPC(ReadMemory16,            T::U16,         T::U32                                          )
A32OPC(ReadMemory32,            T::U32,         T::U32                                          )
A32OPC(ReadMemory64,            T::U64,         T::U32                                          )
A32OPC(WriteMemory8,            T::Void,        T::U32,         T::U8                           )
A32OPC(WriteMemory16,           T::Void,        T::U32,         T::U16                          )
A32OPC(WriteMemory32,           T::Void,        T::U32,         T::U32                          )
A32OPC(WriteMemory64,           T::Void,        T::U32,         T::U64                          )
A32OPC(ExclusiveWriteMemory8,   T::U32,         T::U32,         T::U8                           )
A32OPC(ExclusiveWriteMemory16,  T::U32,         T::U32,         T::U16                          )
A32OPC(ExclusiveWriteMemory32,  T::U32,         T::U32,         T::U32                          )
A32OPC(ExclusiveWriteMemory64,  T::U32,         T::U32,         T::U32,         T::U32          )

// A64 Memory access
A64OPC(ReadMemory8,             T::U8,          T::U64                                          )
A64OPC(ReadMemory16,            T::U16,         T::U64                                          )
A64OPC(ReadMemory32,            T::U32,         T::U64                                          )
A64OPC(ReadMemory64,            T::U64,         T::U64                                          )
A64OPC(WriteMemory8,            T::Void,        T::U64,         T::U8                           )
A64OPC(WriteMemory16,           T::Void,        T::U64,         T::U16                          )
A64OPC(WriteMemory32,           T::Void,        T::U64,         T::U32                          )
A64OPC(WriteMemory64,           T::Void,        T::U64,         T::U64                          )

// Coprocessor
A32OPC(CoprocInternalOperation, T::Void,        T::CoprocInfo                                   )
A32OPC(CoprocSendOneWord,       T::Void,        T::CoprocInfo,  T::U32                          )
A32OPC(CoprocSendTwoWords,      T::Void,        T::CoprocInfo,  T::U32,         T::U32          )
A32OPC(CoprocGetOneWord,        T::U32,         T::CoprocInfo                                   )
A32OPC(CoprocGetTwoWords,       T::U64,         T::CoprocInfo                                   )
A32OPC(CoprocLoadWords,         T::Void,        T::CoprocInfo,  T::U32                          )
A32OPC(CoprocStoreWords,        T::Void,        T::CoprocInfo,  T::U32                          )
