/*
 * Copyright (C) 2016-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 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 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.
 */

// DO NO EDIT! - This file was generated by JavaScriptCore/wasm/generateWasmOpsHeader.py

#pragma once

#if ENABLE(WEBASSEMBLY)

#include <cstdint>
#include <wtf/PrintStream.h>

namespace JSC {

enum class Width : uint8_t;

namespace Wasm {

static constexpr unsigned expectedVersionNumber = 1;

static constexpr unsigned numTypes = 24;

static constexpr int minTypeValue = -64;
#define FOR_EACH_WASM_TYPE(macro) \
    macro(I32, -0x1, B3::Int32, 0, i32, 32) \
    macro(I64, -0x2, B3::Int64, 1, i64, 64) \
    macro(F32, -0x3, B3::Float, 2, f32, 32) \
    macro(F64, -0x4, B3::Double, 3, f64, 64) \
    macro(V128, -0x5, B3::V128, 4, v128, 128) \
    macro(Funcref, -0x10, B3::Int64, 5, funcref, 64) \
    macro(Externref, -0x11, B3::Int64, 6, externref, 64) \
    macro(Anyref, -0x12, B3::Void, 7, anyref, 0) \
    macro(Eqref, -0x13, B3::Void, 8, eqref, 0) \
    macro(RefNull, -0x14, B3::Int64, 9, ref_null, 64) \
    macro(Ref, -0x15, B3::Int64, 10, ref, 64) \
    macro(I31ref, -0x16, B3::Void, 11, i31ref, 0) \
    macro(Nullfuncref, -0x17, B3::Void, 12, nullfuncref, 0) \
    macro(Nullexternref, -0x18, B3::Void, 13, nullexternref, 0) \
    macro(Structref, -0x19, B3::Int64, 14, structref, 0) \
    macro(Arrayref, -0x1a, B3::Int64, 15, arrayref, 0) \
    macro(Nullref, -0x1b, B3::Void, 16, nullref, 0) \
    macro(Func, -0x20, B3::Void, 17, func, 0) \
    macro(Struct, -0x21, B3::Void, 18, struct, 0) \
    macro(Array, -0x22, B3::Void, 19, array, 0) \
    macro(Sub, -0x30, B3::Void, 20, sub, 0) \
    macro(Rec, -0x31, B3::Void, 21, rec, 0) \
    macro(Subfinal, -0x32, B3::Void, 22, subfinal, 0) \
    macro(Void, -0x40, B3::Void, 23, void, 0)

#define FOR_EACH_WASM_PACKED_TYPE(macro) \
    macro(I8, -0x6) \
    macro(I16, -0x7)

#define FOR_EACH_WASM_TYPE_EXCEPT_FUNCREF_AND_EXTERNREF(macro) \
    macro(I32, -0x1, B3::Int32, 0, i32, 32) \
    macro(I64, -0x2, B3::Int64, 1, i64, 64) \
    macro(F32, -0x3, B3::Float, 2, f32, 32) \
    macro(F64, -0x4, B3::Double, 3, f64, 64) \
    macro(V128, -0x5, B3::V128, 4, v128, 128) \
    macro(Funcref, -0x10, B3::Int64, 5, funcref, 64) \
    macro(Externref, -0x11, B3::Int64, 6, externref, 64) \
    macro(Anyref, -0x12, B3::Void, 7, anyref, 0) \
    macro(Eqref, -0x13, B3::Void, 8, eqref, 0) \
    macro(RefNull, -0x14, B3::Int64, 9, ref_null, 64) \
    macro(Ref, -0x15, B3::Int64, 10, ref, 64) \
    macro(I31ref, -0x16, B3::Void, 11, i31ref, 0) \
    macro(Nullfuncref, -0x17, B3::Void, 12, nullfuncref, 0) \
    macro(Nullexternref, -0x18, B3::Void, 13, nullexternref, 0) \
    macro(Structref, -0x19, B3::Int64, 14, structref, 0) \
    macro(Arrayref, -0x1a, B3::Int64, 15, arrayref, 0) \
    macro(Nullref, -0x1b, B3::Void, 16, nullref, 0) \
    macro(Func, -0x20, B3::Void, 17, func, 0) \
    macro(Struct, -0x21, B3::Void, 18, struct, 0) \
    macro(Array, -0x22, B3::Void, 19, array, 0) \
    macro(Sub, -0x30, B3::Void, 20, sub, 0) \
    macro(Rec, -0x31, B3::Void, 21, rec, 0) \
    macro(Subfinal, -0x32, B3::Void, 22, subfinal, 0) \
    macro(Void, -0x40, B3::Void, 23, void, 0)
#define CREATE_ENUM_VALUE(name, id, ...) name = id,
enum class TypeKind : int8_t {
    FOR_EACH_WASM_TYPE(CREATE_ENUM_VALUE)
};
#undef CREATE_ENUM_VALUE

#define CREATE_ENUM_VALUE(name, id) name = id,
enum class PackedType: int8_t {
    FOR_EACH_WASM_PACKED_TYPE(CREATE_ENUM_VALUE)
};
#undef CREATE_ENUM_VALUE

using TypeIndex = uintptr_t;

inline bool typeIndexIsType(TypeIndex index)
{
    auto signedIndex = static_cast<std::make_signed<TypeIndex>::type>(index);
    return (signedIndex < 0) && (signedIndex > minTypeValue);
}

struct Type {
    TypeKind kind;
    TypeIndex index;

    bool operator==(const Type& other) const
    {
        return other.kind == kind && other.isNullable() == isNullable() && other.index == index;
    }

    bool operator!=(const Type& other) const
    {
        return !(other == *this);
    }

    bool isNullable() const
    {
        return kind == TypeKind::RefNull || kind == TypeKind::Externref || kind == TypeKind::Funcref;
    }

    void dump(PrintStream& out) const;
    Width width() const;

    // Use Wasm::isFuncref and Wasm::isExternref instead because they check againts all kind of representations of function referenes and external references.

    #define CREATE_PREDICATE(name, ...) bool is ## name() const { return kind == TypeKind::name; }
    FOR_EACH_WASM_TYPE_EXCEPT_FUNCREF_AND_EXTERNREF(CREATE_PREDICATE)
    #undef CREATE_PREDICATE

    bool isGP64() const
    {
        switch(kind) {
        case TypeKind::I64:
        case TypeKind::Funcref:
        case TypeKind::Externref:
        case TypeKind::RefNull:
        case TypeKind::Ref:
            return true;
        default:
            return false;
        }
    }
};

namespace Types
{
#define CREATE_CONSTANT(name, id, ...) constexpr Type name = Type{TypeKind::name, 0u};
FOR_EACH_WASM_TYPE(CREATE_CONSTANT)
#undef CREATE_CONSTANT
#if USE(JSVALUE64)
constexpr Type IPtr = I64;
#elif USE(JSVALUE32_64)
constexpr Type IPtr = I32;
#endif
} // namespace Types

#define CREATE_CASE(name, id, ...) case id: return true;
template <typename Int>
inline bool isValidTypeKind(Int i)
{
    switch (i) {
    default: return false;
    FOR_EACH_WASM_TYPE(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return false;
}
#undef CREATE_CASE

#define CREATE_CASE(name, id, ...) case id: return true;
template <typename Int>
inline bool isValidPackedType(Int i)
{
    switch (i) {
    default: return false;
    FOR_EACH_WASM_PACKED_TYPE(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return false;
}
#undef CREATE_CASE

#define CREATE_CASE(name, ...) case TypeKind::name: return #name;
inline const char* makeString(TypeKind kind)
{
    switch (kind) {
    FOR_EACH_WASM_TYPE(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return nullptr;
}
#undef CREATE_CASE

#define CREATE_CASE(name, ...) case PackedType::name: return #name;
inline const char* makeString(PackedType packedType)
{
    switch (packedType) {
    FOR_EACH_WASM_PACKED_TYPE(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return nullptr;
}
#undef CREATE_CASE

#define CREATE_CASE(name, id, b3type, inc, ...) case TypeKind::name: return inc;
inline int linearizeType(TypeKind kind)
{
    switch (kind) {
    FOR_EACH_WASM_TYPE(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return 0;
}
#undef CREATE_CASE

#define CREATE_CASE(name, id, b3type, inc, ...) case inc: return TypeKind::name;
inline TypeKind linearizedToType(int i)
{
    switch (i) {
    FOR_EACH_WASM_TYPE(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return TypeKind::Void;
}
#undef CREATE_CASE


#define FOR_EACH_WASM_SPECIAL_OP(macro) \
    macro(I32Const, 0x41, Oops, 0) \
    macro(I64Const, 0x42, Oops, 1) \
    macro(F64Const, 0x44, Oops, 2) \
    macro(F32Const, 0x43, Oops, 3) \
    macro(RefNull, 0xd0, Oops, 4) \
    macro(RefIsNull, 0xd1, Oops, 5) \
    macro(RefFunc, 0xd2, Oops, 6) \
    macro(RefAsNonNull, 0xd3, Oops, 7) \
    macro(RefEq, 0xd5, Oops, 8) \
    macro(GetLocal, 0x20, Oops, 9) \
    macro(SetLocal, 0x21, Oops, 10) \
    macro(TeeLocal, 0x22, Oops, 11) \
    macro(GetGlobal, 0x23, Oops, 12) \
    macro(SetGlobal, 0x24, Oops, 13) \
    macro(TableGet, 0x25, Oops, 14) \
    macro(TableSet, 0x26, Oops, 15) \
    macro(Call, 0x10, Oops, 16) \
    macro(CallIndirect, 0x11, Oops, 17) \
    macro(TailCall, 0x12, Oops, 18) \
    macro(TailCallIndirect, 0x13, Oops, 19) \
    macro(CallRef, 0x14, Oops, 20) \
    macro(CurrentMemory, 0x3f, Oops, 21) \
    macro(GrowMemory, 0x40, Oops, 22)

#define FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
    macro(Unreachable, 0x0, Oops, 0) \
    macro(Nop, 0x1, Oops, 1) \
    macro(Block, 0x2, Oops, 2) \
    macro(Loop, 0x3, Oops, 3) \
    macro(If, 0x4, Oops, 4) \
    macro(Else, 0x5, Oops, 5) \
    macro(Try, 0x6, Oops, 6) \
    macro(Catch, 0x7, Oops, 7) \
    macro(Throw, 0x8, Oops, 8) \
    macro(Rethrow, 0x9, Oops, 9) \
    macro(Br, 0xc, Oops, 10) \
    macro(BrIf, 0xd, Oops, 11) \
    macro(BrTable, 0xe, Oops, 12) \
    macro(Return, 0xf, Oops, 13) \
    macro(Delegate, 0x18, Oops, 14) \
    macro(CatchAll, 0x19, Oops, 15) \
    macro(Drop, 0x1a, Oops, 16) \
    macro(Select, 0x1b, Oops, 17) \
    macro(AnnotatedSelect, 0x1c, Oops, 18) \
    macro(End, 0xb, Oops, 19)

#define FOR_EACH_WASM_SIMPLE_UNARY_OP(macro) \
    macro(I32Clz, 0x67, Clz, 0, I32, I32) \
    macro(I32Eqz, 0x45, Equal(i32(0), @0), 1, I32, I32) \
    macro(I64Clz, 0x79, Clz, 2, I64, I64) \
    macro(I64Eqz, 0x50, Equal(i64(0), @0), 3, I64, I32) \
    macro(F32Abs, 0x8b, Abs, 4, F32, F32) \
    macro(F32Neg, 0x8c, Neg, 5, F32, F32) \
    macro(F32Ceil, 0x8d, Ceil, 6, F32, F32) \
    macro(F32Floor, 0x8e, Floor, 7, F32, F32) \
    macro(F32Sqrt, 0x91, Sqrt, 8, F32, F32) \
    macro(F64Abs, 0x99, Abs, 9, F64, F64) \
    macro(F64Neg, 0x9a, Neg, 10, F64, F64) \
    macro(F64Ceil, 0x9b, Ceil, 11, F64, F64) \
    macro(F64Floor, 0x9c, Floor, 12, F64, F64) \
    macro(F64Sqrt, 0x9f, Sqrt, 13, F64, F64) \
    macro(I32WrapI64, 0xa7, Trunc, 14, I64, I32) \
    macro(I64ExtendSI32, 0xac, SExt32, 15, I32, I64) \
    macro(I64ExtendUI32, 0xad, ZExt32, 16, I32, I64) \
    macro(F32ConvertSI32, 0xb2, IToF, 17, I32, F32) \
    macro(F32ConvertUI32, 0xb3, IToF(ZExt32(@0)), 18, I32, F32) \
    macro(F32ConvertSI64, 0xb4, IToF, 19, I64, F32) \
    macro(F32DemoteF64, 0xb6, DoubleToFloat, 20, F64, F32) \
    macro(F32ReinterpretI32, 0xbe, BitwiseCast, 21, I32, F32) \
    macro(F64ConvertSI32, 0xb7, IToD, 22, I32, F64) \
    macro(F64ConvertUI32, 0xb8, IToD(ZExt32(@0)), 23, I32, F64) \
    macro(F64ConvertSI64, 0xb9, IToD, 24, I64, F64) \
    macro(F64PromoteF32, 0xbb, FloatToDouble, 25, F32, F64) \
    macro(F64ReinterpretI64, 0xbf, BitwiseCast, 26, I64, F64) \
    macro(I32ReinterpretF32, 0xbc, BitwiseCast, 27, F32, I32) \
    macro(I64ReinterpretF64, 0xbd, BitwiseCast, 28, F64, I64) \
    macro(I32Extend8S, 0xc0, SExt8, 29, I32, I32) \
    macro(I32Extend16S, 0xc1, SExt16, 30, I32, I32) \
    macro(I64Extend8S, 0xc2, SExt32(SExt8(Trunc(@0))), 31, I64, I64) \
    macro(I64Extend16S, 0xc3, SExt32(SExt16(Trunc(@0))), 32, I64, I64) \
    macro(I64Extend32S, 0xc4, SExt32(Trunc(@0)), 33, I64, I64)

#define FOR_EACH_WASM_UNARY_OP(macro) \
    FOR_EACH_WASM_SIMPLE_UNARY_OP(macro) \
    macro(I32Ctz, 0x68, Oops, 0, I32, I32) \
    macro(I32Popcnt, 0x69, Oops, 1, I32, I32) \
    macro(I64Ctz, 0x7a, Oops, 2, I64, I64) \
    macro(I64Popcnt, 0x7b, Oops, 3, I64, I64) \
    macro(F32Trunc, 0x8f, Oops, 4, F32, F32) \
    macro(F32Nearest, 0x90, Oops, 5, F32, F32) \
    macro(F64Trunc, 0x9d, Oops, 6, F64, F64) \
    macro(F64Nearest, 0x9e, Oops, 7, F64, F64) \
    macro(I32TruncSF32, 0xa8, Oops, 8, F32, I32) \
    macro(I32TruncSF64, 0xaa, Oops, 9, F64, I32) \
    macro(I32TruncUF32, 0xa9, Oops, 10, F32, I32) \
    macro(I32TruncUF64, 0xab, Oops, 11, F64, I32) \
    macro(I64TruncSF32, 0xae, Oops, 12, F32, I64) \
    macro(I64TruncSF64, 0xb0, Oops, 13, F64, I64) \
    macro(I64TruncUF32, 0xaf, Oops, 14, F32, I64) \
    macro(I64TruncUF64, 0xb1, Oops, 15, F64, I64) \
    macro(F32ConvertUI64, 0xb5, Oops, 16, I64, F32) \
    macro(F64ConvertUI64, 0xba, Oops, 17, I64, F64)

#define FOR_EACH_WASM_SIMPLE_BINARY_OP(macro) \
    macro(I32Add, 0x6a, Add, 0, I32, I32, I32) \
    macro(I32Sub, 0x6b, Sub, 1, I32, I32, I32) \
    macro(I32Mul, 0x6c, Mul, 2, I32, I32, I32) \
    macro(I32And, 0x71, BitAnd, 3, I32, I32, I32) \
    macro(I32Or, 0x72, BitOr, 4, I32, I32, I32) \
    macro(I32Xor, 0x73, BitXor, 5, I32, I32, I32) \
    macro(I32Shl, 0x74, Shl, 6, I32, I32, I32) \
    macro(I32ShrU, 0x76, ZShr, 7, I32, I32, I32) \
    macro(I32ShrS, 0x75, SShr, 8, I32, I32, I32) \
    macro(I32Rotr, 0x78, RotR, 9, I32, I32, I32) \
    macro(I32Rotl, 0x77, RotL, 10, I32, I32, I32) \
    macro(I32Eq, 0x46, Equal, 11, I32, I32, I32) \
    macro(I32Ne, 0x47, NotEqual, 12, I32, I32, I32) \
    macro(I32LtS, 0x48, LessThan, 13, I32, I32, I32) \
    macro(I32LeS, 0x4c, LessEqual, 14, I32, I32, I32) \
    macro(I32LtU, 0x49, Below, 15, I32, I32, I32) \
    macro(I32LeU, 0x4d, BelowEqual, 16, I32, I32, I32) \
    macro(I32GtS, 0x4a, GreaterThan, 17, I32, I32, I32) \
    macro(I32GeS, 0x4e, GreaterEqual, 18, I32, I32, I32) \
    macro(I32GtU, 0x4b, Above, 19, I32, I32, I32) \
    macro(I32GeU, 0x4f, AboveEqual, 20, I32, I32, I32) \
    macro(I64Add, 0x7c, Add, 21, I64, I64, I64) \
    macro(I64Sub, 0x7d, Sub, 22, I64, I64, I64) \
    macro(I64Mul, 0x7e, Mul, 23, I64, I64, I64) \
    macro(I64And, 0x83, BitAnd, 24, I64, I64, I64) \
    macro(I64Or, 0x84, BitOr, 25, I64, I64, I64) \
    macro(I64Xor, 0x85, BitXor, 26, I64, I64, I64) \
    macro(I64Shl, 0x86, Shl(@0, Trunc(@1)), 27, I64, I64, I64) \
    macro(I64ShrU, 0x88, ZShr(@0, Trunc(@1)), 28, I64, I64, I64) \
    macro(I64ShrS, 0x87, SShr(@0, Trunc(@1)), 29, I64, I64, I64) \
    macro(I64Rotr, 0x8a, RotR(@0, Trunc(@1)), 30, I64, I64, I64) \
    macro(I64Rotl, 0x89, RotL(@0, Trunc(@1)), 31, I64, I64, I64) \
    macro(I64Eq, 0x51, Equal, 32, I64, I64, I32) \
    macro(I64Ne, 0x52, NotEqual, 33, I64, I64, I32) \
    macro(I64LtS, 0x53, LessThan, 34, I64, I64, I32) \
    macro(I64LeS, 0x57, LessEqual, 35, I64, I64, I32) \
    macro(I64LtU, 0x54, Below, 36, I64, I64, I32) \
    macro(I64LeU, 0x58, BelowEqual, 37, I64, I64, I32) \
    macro(I64GtS, 0x55, GreaterThan, 38, I64, I64, I32) \
    macro(I64GeS, 0x59, GreaterEqual, 39, I64, I64, I32) \
    macro(I64GtU, 0x56, Above, 40, I64, I64, I32) \
    macro(I64GeU, 0x5a, AboveEqual, 41, I64, I64, I32) \
    macro(F32Add, 0x92, Add, 42, F32, F32, F32) \
    macro(F32Sub, 0x93, Sub, 43, F32, F32, F32) \
    macro(F32Mul, 0x94, Mul, 44, F32, F32, F32) \
    macro(F32Div, 0x95, Div, 45, F32, F32, F32) \
    macro(F32Min, 0x96, FMin, 46, F32, F32, F32) \
    macro(F32Max, 0x97, FMax, 47, F32, F32, F32) \
    macro(F32Copysign, 0x98, BitwiseCast(BitOr(BitAnd(BitwiseCast(@1), i32(0x80000000)), BitAnd(BitwiseCast(@0), i32(0x7fffffff)))), 48, F32, F32, F32) \
    macro(F32Eq, 0x5b, Equal, 49, F32, F32, I32) \
    macro(F32Ne, 0x5c, NotEqual, 50, F32, F32, I32) \
    macro(F32Lt, 0x5d, LessThan, 51, F32, F32, I32) \
    macro(F32Le, 0x5f, LessEqual, 52, F32, F32, I32) \
    macro(F32Gt, 0x5e, GreaterThan, 53, F32, F32, I32) \
    macro(F32Ge, 0x60, GreaterEqual, 54, F32, F32, I32) \
    macro(F64Add, 0xa0, Add, 55, F64, F64, F64) \
    macro(F64Sub, 0xa1, Sub, 56, F64, F64, F64) \
    macro(F64Mul, 0xa2, Mul, 57, F64, F64, F64) \
    macro(F64Div, 0xa3, Div, 58, F64, F64, F64) \
    macro(F64Min, 0xa4, FMin, 59, F64, F64, F64) \
    macro(F64Max, 0xa5, FMax, 60, F64, F64, F64) \
    macro(F64Copysign, 0xa6, BitwiseCast(BitOr(BitAnd(BitwiseCast(@1), i64(0x8000000000000000)), BitAnd(BitwiseCast(@0), i64(0x7fffffffffffffff)))), 61, F64, F64, F64) \
    macro(F64Eq, 0x61, Equal, 62, F64, F64, I32) \
    macro(F64Ne, 0x62, NotEqual, 63, F64, F64, I32) \
    macro(F64Lt, 0x63, LessThan, 64, F64, F64, I32) \
    macro(F64Le, 0x65, LessEqual, 65, F64, F64, I32) \
    macro(F64Gt, 0x64, GreaterThan, 66, F64, F64, I32) \
    macro(F64Ge, 0x66, GreaterEqual, 67, F64, F64, I32)

#define FOR_EACH_WASM_BINARY_OP(macro) \
    FOR_EACH_WASM_SIMPLE_BINARY_OP(macro) \
    macro(I32DivS, 0x6d, Oops, 0, I32, I32, I32) \
    macro(I32DivU, 0x6e, Oops, 1, I32, I32, I32) \
    macro(I32RemS, 0x6f, Oops, 2, I32, I32, I32) \
    macro(I32RemU, 0x70, Oops, 3, I32, I32, I32) \
    macro(I64DivS, 0x7f, Oops, 4, I64, I64, I64) \
    macro(I64DivU, 0x80, Oops, 5, I64, I64, I64) \
    macro(I64RemS, 0x81, Oops, 6, I64, I64, I64) \
    macro(I64RemU, 0x82, Oops, 7, I64, I64, I64)

#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
    macro(I32Load8S, 0x2c, Oops, 0, I32) \
    macro(I32Load8U, 0x2d, Oops, 1, I32) \
    macro(I32Load16S, 0x2e, Oops, 2, I32) \
    macro(I32Load16U, 0x2f, Oops, 3, I32) \
    macro(I64Load8S, 0x30, Oops, 4, I64) \
    macro(I64Load8U, 0x31, Oops, 5, I64) \
    macro(I64Load16S, 0x32, Oops, 6, I64) \
    macro(I64Load16U, 0x33, Oops, 7, I64) \
    macro(I64Load32S, 0x34, Oops, 8, I64) \
    macro(I64Load32U, 0x35, Oops, 9, I64) \
    macro(I32Load, 0x28, Oops, 10, I32) \
    macro(I64Load, 0x29, Oops, 11, I64) \
    macro(F32Load, 0x2a, Oops, 12, F32) \
    macro(F64Load, 0x2b, Oops, 13, F64)

#define FOR_EACH_WASM_MEMORY_STORE_OP(macro) \
    macro(I32Store8, 0x3a, Oops, 0, I32) \
    macro(I32Store16, 0x3b, Oops, 1, I32) \
    macro(I64Store8, 0x3c, Oops, 2, I64) \
    macro(I64Store16, 0x3d, Oops, 3, I64) \
    macro(I64Store32, 0x3e, Oops, 4, I64) \
    macro(I32Store, 0x36, Oops, 5, I32) \
    macro(I64Store, 0x37, Oops, 6, I64) \
    macro(F32Store, 0x38, Oops, 7, F32) \
    macro(F64Store, 0x39, Oops, 8, F64)

#define FOR_EACH_WASM_TABLE_OP(macro) \
    macro(TableInit, 0xc, Oops, 0) \
    macro(ElemDrop, 0xd, Oops, 1) \
    macro(TableGrow, 0xf, Oops, 2) \
    macro(TableSize, 0x10, Oops, 3) \
    macro(TableFill, 0x11, Oops, 4) \
    macro(TableCopy, 0xe, Oops, 5) \
    macro(MemoryFill, 0xb, Oops, 6) \
    macro(MemoryCopy, 0xa, Oops, 7) \
    macro(MemoryInit, 0x8, Oops, 8) \
    macro(DataDrop, 0x9, Oops, 9)

#define FOR_EACH_WASM_TRUNC_SATURATED_OP(macro) \
    macro(I32TruncSatF32S, 0x0, Oops, 0, F32, I32) \
    macro(I32TruncSatF32U, 0x1, Oops, 1, F32, I32) \
    macro(I32TruncSatF64S, 0x2, Oops, 2, F64, I32) \
    macro(I32TruncSatF64U, 0x3, Oops, 3, F64, I32) \
    macro(I64TruncSatF32S, 0x4, Oops, 4, F32, I64) \
    macro(I64TruncSatF32U, 0x5, Oops, 5, F32, I64) \
    macro(I64TruncSatF64S, 0x6, Oops, 6, F64, I64) \
    macro(I64TruncSatF64U, 0x7, Oops, 7, F64, I64)

#define FOR_EACH_WASM_EXT_ATOMIC_LOAD_OP(macro) \
    macro(I32AtomicLoad, 0x10, Oops, 0, I32) \
    macro(I64AtomicLoad, 0x11, Oops, 1, I64) \
    macro(I32AtomicLoad8U, 0x12, Oops, 2, I32) \
    macro(I32AtomicLoad16U, 0x13, Oops, 3, I32) \
    macro(I64AtomicLoad8U, 0x14, Oops, 4, I64) \
    macro(I64AtomicLoad16U, 0x15, Oops, 5, I64) \
    macro(I64AtomicLoad32U, 0x16, Oops, 6, I64)

#define FOR_EACH_WASM_EXT_ATOMIC_STORE_OP(macro) \
    macro(I32AtomicStore, 0x17, Oops, 0, I32) \
    macro(I64AtomicStore, 0x18, Oops, 1, I64) \
    macro(I32AtomicStore8U, 0x19, Oops, 2, I32) \
    macro(I32AtomicStore16U, 0x1a, Oops, 3, I32) \
    macro(I64AtomicStore8U, 0x1b, Oops, 4, I64) \
    macro(I64AtomicStore16U, 0x1c, Oops, 5, I64) \
    macro(I64AtomicStore32U, 0x1d, Oops, 6, I64)

#define FOR_EACH_WASM_EXT_ATOMIC_BINARY_RMW_OP(macro) \
    macro(I32AtomicRmwAdd, 0x1e, Oops, 0, I32) \
    macro(I64AtomicRmwAdd, 0x1f, Oops, 1, I64) \
    macro(I32AtomicRmw8AddU, 0x20, Oops, 2, I32) \
    macro(I32AtomicRmw16AddU, 0x21, Oops, 3, I32) \
    macro(I64AtomicRmw8AddU, 0x22, Oops, 4, I64) \
    macro(I64AtomicRmw16AddU, 0x23, Oops, 5, I64) \
    macro(I64AtomicRmw32AddU, 0x24, Oops, 6, I64) \
    macro(I32AtomicRmwSub, 0x25, Oops, 7, I32) \
    macro(I64AtomicRmwSub, 0x26, Oops, 8, I64) \
    macro(I32AtomicRmw8SubU, 0x27, Oops, 9, I32) \
    macro(I32AtomicRmw16SubU, 0x28, Oops, 10, I32) \
    macro(I64AtomicRmw8SubU, 0x29, Oops, 11, I64) \
    macro(I64AtomicRmw16SubU, 0x2a, Oops, 12, I64) \
    macro(I64AtomicRmw32SubU, 0x2b, Oops, 13, I64) \
    macro(I32AtomicRmwAnd, 0x2c, Oops, 14, I32) \
    macro(I64AtomicRmwAnd, 0x2d, Oops, 15, I64) \
    macro(I32AtomicRmw8AndU, 0x2e, Oops, 16, I32) \
    macro(I32AtomicRmw16AndU, 0x2f, Oops, 17, I32) \
    macro(I64AtomicRmw8AndU, 0x30, Oops, 18, I64) \
    macro(I64AtomicRmw16AndU, 0x31, Oops, 19, I64) \
    macro(I64AtomicRmw32AndU, 0x32, Oops, 20, I64) \
    macro(I32AtomicRmwOr, 0x33, Oops, 21, I32) \
    macro(I64AtomicRmwOr, 0x34, Oops, 22, I64) \
    macro(I32AtomicRmw8OrU, 0x35, Oops, 23, I32) \
    macro(I32AtomicRmw16OrU, 0x36, Oops, 24, I32) \
    macro(I64AtomicRmw8OrU, 0x37, Oops, 25, I64) \
    macro(I64AtomicRmw16OrU, 0x38, Oops, 26, I64) \
    macro(I64AtomicRmw32OrU, 0x39, Oops, 27, I64) \
    macro(I32AtomicRmwXor, 0x3a, Oops, 28, I32) \
    macro(I64AtomicRmwXor, 0x3b, Oops, 29, I64) \
    macro(I32AtomicRmw8XorU, 0x3c, Oops, 30, I32) \
    macro(I32AtomicRmw16XorU, 0x3d, Oops, 31, I32) \
    macro(I64AtomicRmw8XorU, 0x3e, Oops, 32, I64) \
    macro(I64AtomicRmw16XorU, 0x3f, Oops, 33, I64) \
    macro(I64AtomicRmw32XorU, 0x40, Oops, 34, I64) \
    macro(I32AtomicRmwXchg, 0x41, Oops, 35, I32) \
    macro(I64AtomicRmwXchg, 0x42, Oops, 36, I64) \
    macro(I32AtomicRmw8XchgU, 0x43, Oops, 37, I32) \
    macro(I32AtomicRmw16XchgU, 0x44, Oops, 38, I32) \
    macro(I64AtomicRmw8XchgU, 0x45, Oops, 39, I64) \
    macro(I64AtomicRmw16XchgU, 0x46, Oops, 40, I64) \
    macro(I64AtomicRmw32XchgU, 0x47, Oops, 41, I64)

#define FOR_EACH_WASM_EXT_ATOMIC_OTHER_OP(macro) \
    macro(MemoryAtomicNotify, 0x0, Oops, 0) \
    macro(MemoryAtomicWait32, 0x1, Oops, 1) \
    macro(MemoryAtomicWait64, 0x2, Oops, 2) \
    macro(AtomicFence, 0x3, Oops, 3) \
    macro(I32AtomicRmwCmpxchg, 0x48, Oops, 4) \
    macro(I64AtomicRmwCmpxchg, 0x49, Oops, 5) \
    macro(I32AtomicRmw8CmpxchgU, 0x4a, Oops, 6) \
    macro(I32AtomicRmw16CmpxchgU, 0x4b, Oops, 7) \
    macro(I64AtomicRmw8CmpxchgU, 0x4c, Oops, 8) \
    macro(I64AtomicRmw16CmpxchgU, 0x4d, Oops, 9) \
    macro(I64AtomicRmw32CmpxchgU, 0x4e, Oops, 10)

#define FOR_EACH_WASM_GC_OP(macro) \
    macro(StructNewCanon, 0x1, Oops, 0) \
    macro(StructNewCanonDefault, 0x2, Oops, 1) \
    macro(StructGet, 0x3, Oops, 2) \
    macro(StructSet, 0x6, Oops, 3) \
    macro(StructNew, 0x7, Oops, 4) \
    macro(StructNewDefault, 0x8, Oops, 5) \
    macro(ArrayNew, 0x11, Oops, 6) \
    macro(ArrayNewDefault, 0x12, Oops, 7) \
    macro(ArrayNewFixed, 0x19, Oops, 8) \
    macro(ArrayGet, 0x13, Oops, 9) \
    macro(ArraySet, 0x16, Oops, 10) \
    macro(ArrayGetS, 0x14, Oops, 11) \
    macro(ArrayGetU, 0x15, Oops, 12) \
    macro(ArrayLen, 0x17, Oops, 13) \
    macro(ArrayNewData, 0x1b, Oops, 14) \
    macro(ArrayNewElem, 0x1c, Oops, 15) \
    macro(I31New, 0x20, Oops, 16) \
    macro(I31GetS, 0x21, Oops, 17) \
    macro(I31GetU, 0x22, Oops, 18) \
    macro(RefTest, 0x40, Oops, 19) \
    macro(RefCast, 0x41, Oops, 20) \
    macro(RefTestNull, 0x48, Oops, 21) \
    macro(RefCastNull, 0x49, Oops, 22) \
    macro(ExternInternalize, 0x70, Oops, 23) \
    macro(ExternExternalize, 0x71, Oops, 24)


#define FOR_EACH_WASM_OP(macro) \
    FOR_EACH_WASM_SPECIAL_OP(macro) \
    FOR_EACH_WASM_CONTROL_FLOW_OP(macro) \
    FOR_EACH_WASM_UNARY_OP(macro) \
    FOR_EACH_WASM_BINARY_OP(macro) \
    FOR_EACH_WASM_MEMORY_LOAD_OP(macro) \
    FOR_EACH_WASM_MEMORY_STORE_OP(macro) \
    macro(ExtGC,  0xFB, Oops, 0) \
    macro(Ext1,  0xFC, Oops, 0) \
    macro(ExtSIMD, 0xFD, Oops, 0) \
    macro(ExtAtomic, 0xFE, Oops, 0)

#define CREATE_ENUM_VALUE(name, id, ...) name = id,

enum OpType : uint8_t {
    FOR_EACH_WASM_OP(CREATE_ENUM_VALUE)
};

template<typename Int>
inline bool isValidOpType(Int i)
{
    // Bitset of valid ops.
    static const uint8_t valid[] = { 0xff, 0xfb, 0x1f, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x0, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x78 };
    return 0 <= i && i <= 254 && (valid[i / 8] & (1 << (i % 8)));
}

enum class BinaryOpType : uint8_t {
    FOR_EACH_WASM_BINARY_OP(CREATE_ENUM_VALUE)
};

enum class UnaryOpType : uint8_t {
    FOR_EACH_WASM_UNARY_OP(CREATE_ENUM_VALUE)
};

enum class LoadOpType : uint8_t {
    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_ENUM_VALUE)
};

enum class StoreOpType : uint8_t {
    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_ENUM_VALUE)
};

enum class Ext1OpType : uint32_t {
    FOR_EACH_WASM_TABLE_OP(CREATE_ENUM_VALUE)
    FOR_EACH_WASM_TRUNC_SATURATED_OP(CREATE_ENUM_VALUE)
};

enum class ExtSIMDOpType : uint32_t;

enum class ExtGCOpType : uint32_t {
    FOR_EACH_WASM_GC_OP(CREATE_ENUM_VALUE)
};

enum class ExtAtomicOpType : uint32_t {
    FOR_EACH_WASM_EXT_ATOMIC_LOAD_OP(CREATE_ENUM_VALUE)
    FOR_EACH_WASM_EXT_ATOMIC_STORE_OP(CREATE_ENUM_VALUE)
    FOR_EACH_WASM_EXT_ATOMIC_BINARY_RMW_OP(CREATE_ENUM_VALUE)
    FOR_EACH_WASM_EXT_ATOMIC_OTHER_OP(CREATE_ENUM_VALUE)
};

#undef CREATE_ENUM_VALUE

inline bool isControlOp(OpType op)
{
    switch (op) {
#define CREATE_CASE(name, ...) case OpType::name:
    FOR_EACH_WASM_CONTROL_FLOW_OP(CREATE_CASE)
        return true;
#undef CREATE_CASE
    default:
        break;
    }
    return false;
}

inline bool isSimple(UnaryOpType op)
{
    switch (op) {
#define CREATE_CASE(name, ...) case UnaryOpType::name:
    FOR_EACH_WASM_SIMPLE_UNARY_OP(CREATE_CASE)
        return true;
#undef CREATE_CASE
    default:
        break;
    }
    return false;
}

inline bool isSimple(BinaryOpType op)
{
    switch (op) {
#define CREATE_CASE(name, ...) case BinaryOpType::name:
    FOR_EACH_WASM_SIMPLE_BINARY_OP(CREATE_CASE)
        return true;
#undef CREATE_CASE
    default:
        break;
    }
    return false;
}

inline uint32_t memoryLog2Alignment(OpType op)
{
    switch (op) {
    case I32Load8S: return 0;
    case I32Load8U: return 0;
    case I32Load16S: return 1;
    case I32Load16U: return 1;
    case I64Load8S: return 0;
    case I64Load8U: return 0;
    case I64Load16S: return 1;
    case I64Load16U: return 1;
    case I64Load32S: return 2;
    case I64Load32U: return 2;
    case I32Load: return 2;
    case I64Load: return 3;
    case F32Load: return 2;
    case F64Load: return 3;
    case I32Store8: return 0;
    case I32Store16: return 1;
    case I64Store8: return 0;
    case I64Store16: return 1;
    case I64Store32: return 2;
    case I32Store: return 2;
    case I64Store: return 3;
    case F32Store: return 2;
    case F64Store: return 3;
    default:
        break;
    }
    RELEASE_ASSERT_NOT_REACHED();
    return 0;
}

inline uint32_t memoryLog2Alignment(ExtAtomicOpType op)
{
    switch (op) {
    case ExtAtomicOpType::MemoryAtomicNotify: return 2;
    case ExtAtomicOpType::MemoryAtomicWait32: return 2;
    case ExtAtomicOpType::MemoryAtomicWait64: return 3;
    case ExtAtomicOpType::AtomicFence: return 0;
    case ExtAtomicOpType::I32AtomicLoad: return 2;
    case ExtAtomicOpType::I64AtomicLoad: return 3;
    case ExtAtomicOpType::I32AtomicLoad8U: return 0;
    case ExtAtomicOpType::I32AtomicLoad16U: return 1;
    case ExtAtomicOpType::I64AtomicLoad8U: return 0;
    case ExtAtomicOpType::I64AtomicLoad16U: return 1;
    case ExtAtomicOpType::I64AtomicLoad32U: return 2;
    case ExtAtomicOpType::I32AtomicStore: return 2;
    case ExtAtomicOpType::I64AtomicStore: return 3;
    case ExtAtomicOpType::I32AtomicStore8U: return 0;
    case ExtAtomicOpType::I32AtomicStore16U: return 1;
    case ExtAtomicOpType::I64AtomicStore8U: return 0;
    case ExtAtomicOpType::I64AtomicStore16U: return 1;
    case ExtAtomicOpType::I64AtomicStore32U: return 2;
    case ExtAtomicOpType::I32AtomicRmwAdd: return 2;
    case ExtAtomicOpType::I64AtomicRmwAdd: return 3;
    case ExtAtomicOpType::I32AtomicRmw8AddU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16AddU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8AddU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16AddU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32AddU: return 2;
    case ExtAtomicOpType::I32AtomicRmwSub: return 2;
    case ExtAtomicOpType::I64AtomicRmwSub: return 3;
    case ExtAtomicOpType::I32AtomicRmw8SubU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16SubU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8SubU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16SubU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32SubU: return 2;
    case ExtAtomicOpType::I32AtomicRmwAnd: return 2;
    case ExtAtomicOpType::I64AtomicRmwAnd: return 3;
    case ExtAtomicOpType::I32AtomicRmw8AndU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16AndU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8AndU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16AndU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32AndU: return 2;
    case ExtAtomicOpType::I32AtomicRmwOr: return 2;
    case ExtAtomicOpType::I64AtomicRmwOr: return 3;
    case ExtAtomicOpType::I32AtomicRmw8OrU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16OrU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8OrU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16OrU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32OrU: return 2;
    case ExtAtomicOpType::I32AtomicRmwXor: return 2;
    case ExtAtomicOpType::I64AtomicRmwXor: return 3;
    case ExtAtomicOpType::I32AtomicRmw8XorU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16XorU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8XorU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16XorU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32XorU: return 2;
    case ExtAtomicOpType::I32AtomicRmwXchg: return 2;
    case ExtAtomicOpType::I64AtomicRmwXchg: return 3;
    case ExtAtomicOpType::I32AtomicRmw8XchgU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16XchgU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8XchgU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16XchgU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32XchgU: return 2;
    case ExtAtomicOpType::I32AtomicRmwCmpxchg: return 2;
    case ExtAtomicOpType::I64AtomicRmwCmpxchg: return 3;
    case ExtAtomicOpType::I32AtomicRmw8CmpxchgU: return 0;
    case ExtAtomicOpType::I32AtomicRmw16CmpxchgU: return 1;
    case ExtAtomicOpType::I64AtomicRmw8CmpxchgU: return 0;
    case ExtAtomicOpType::I64AtomicRmw16CmpxchgU: return 1;
    case ExtAtomicOpType::I64AtomicRmw32CmpxchgU: return 2;
    default:
        break;
    }
    RELEASE_ASSERT_NOT_REACHED();
    return 0;
}

#define CREATE_CASE(name, ...) case name: return #name;
inline const char* makeString(OpType op)
{
    switch (op) {
    FOR_EACH_WASM_OP(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return nullptr;
}
#undef CREATE_CASE

#define CREATE_CASE(name, ...) case ExtAtomicOpType::name: return #name;
inline const char* makeString(ExtAtomicOpType op)
{
    switch (op) {
    FOR_EACH_WASM_EXT_ATOMIC_LOAD_OP(CREATE_CASE)
    FOR_EACH_WASM_EXT_ATOMIC_STORE_OP(CREATE_CASE)
    FOR_EACH_WASM_EXT_ATOMIC_BINARY_RMW_OP(CREATE_CASE)
    FOR_EACH_WASM_EXT_ATOMIC_OTHER_OP(CREATE_CASE)
    }
    RELEASE_ASSERT_NOT_REACHED();
    return nullptr;
}
#undef CREATE_CASE

} } // namespace JSC::Wasm

namespace WTF {

inline void printInternal(PrintStream& out, JSC::Wasm::TypeKind kind)
{
    out.print(JSC::Wasm::makeString(kind));
}

inline void printInternal(PrintStream& out, JSC::Wasm::OpType op)
{
    out.print(JSC::Wasm::makeString(op));
}

inline void printInternal(PrintStream& out, JSC::Wasm::ExtAtomicOpType op)
{
    out.print(JSC::Wasm::makeString(op));
}

} // namespace WTF

#endif // ENABLE(WEBASSEMBLY)

