text: // Copyright 2018 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_WASM_VALUE_TYPE_H_
  #define V8_WASM_VALUE_TYPE_H_
  
  #include "src/machine-type.h"
  #include "src/wasm/wasm-constants.h"
  
  namespace v8 {
  namespace internal {
  
  template <typename T>
  class Signature;
  
  namespace wasm {
  
  enum ValueType : uint8_t {
    kWasmStmt,
    kWasmI32,
    kWasmI64,
    kWasmF32,
    kWasmF64,
    kWasmS128,
    kWasmAnyRef,
    kWasmAnyFunc,
    kWasmExceptRef,
    kWasmVar,
  };
  
  using FunctionSig = Signature<ValueType>;
  
  inline size_t hash_value(ValueType type) { return static_cast<size_t>(type); }
  
  // TODO(clemensh): Compute memtype and size from ValueType once we have c++14
  // constexpr support.
  #define FOREACH_LOAD_TYPE(V) \
    V(I32, , Int32, 2)         \
    V(I32, 8S, Int8, 0)        \
    V(I32, 8U, Uint8, 0)       \
    V(I32, 16S, Int16, 1)      \
    V(I32, 16U, Uint16, 1)     \
    V(I64, , Int64, 3)         \
    V(I64, 8S, Int8, 0)        \
    V(I64, 8U, Uint8, 0)       \
    V(I64, 16S, Int16, 1)      \
    V(I64, 16U, Uint16, 1)     \
    V(I64, 32S, Int32, 2)      \
    V(I64, 32U, Uint32, 2)     \
    V(F32, , Float32, 2)       \
    V(F64, , Float64, 3)       \
    V(S128, , Simd128, 4)
  
  class LoadType {
   public:
    enum LoadTypeValue : uint8_t {
  #define DEF_ENUM(type, suffix, ...) k##type##Load##suffix,
      FOREACH_LOAD_TYPE(DEF_ENUM)
  #undef DEF_ENUM
    };
  
    // Allow implicit convertion of the enum value to this wrapper.
    constexpr LoadType(LoadTypeValue val)  // NOLINT(runtime/explicit)
        : val_(val) {}
  
    constexpr LoadTypeValue value() const { return val_; }
    constexpr unsigned size_log_2() const { return kLoadSizeLog2[val_]; }
    constexpr unsigned size() const { return 1 << size_log_2(); }
    constexpr ValueType value_type() const { return kValueType[val_]; }
    constexpr MachineType mem_type() const { return kMemType[val_]; }
  
    static LoadType ForValueType(ValueType type) {
      switch (type) {
        case kWasmI32:
          return kI32Load;
        case kWasmI64:
          return kI64Load;
        case kWasmF32:
          return kF32Load;
        case kWasmF64:
          return kF64Load;
        default:
          UNREACHABLE();
      }
    }
  
   private:
    const LoadTypeValue val_;
  
    static constexpr uint8_t kLoadSizeLog2[] = {
  #define LOAD_SIZE(_, __, ___, size) size,
        FOREACH_LOAD_TYPE(LOAD_SIZE)
  #undef LOAD_SIZE
    };
  
    static constexpr ValueType kValueType[] = {
  #define VALUE_TYPE(type, ...) kWasm##type,
        FOREACH_LOAD_TYPE(VALUE_TYPE)
  #undef VALUE_TYPE
    };
  
    static constexpr MachineType kMemType[] = {
  #define MEMTYPE(_, __, memtype, ___) MachineType::memtype(),
        FOREACH_LOAD_TYPE(MEMTYPE)
  #undef MEMTYPE
    };
  };
  
  #define FOREACH_STORE_TYPE(V) \
    V(I32, , Word32, 2)         \
    V(I32, 8, Word8, 0)         \
    V(I32, 16, Word16, 1)       \
    V(I64, , Word64, 3)         \
    V(I64, 8, Word8, 0)         \
    V(I64, 16, Word16, 1)       \
    V(I64, 32, Word32, 2)       \
    V(F32, , Float32, 2)        \
    V(F64, , Float64, 3)        \
    V(S128, , Simd128, 4)
  
  class StoreType {
   public:
    enum StoreTypeValue : uint8_t {
  #define DEF_ENUM(type, suffix, ...) k##type##Store##suffix,
      FOREACH_STORE_TYPE(DEF_ENUM)
  #undef DEF_ENUM
    };
  
    // Allow implicit convertion of the enum value to this wrapper.
    constexpr StoreType(StoreTypeValue val)  // NOLINT(runtime/explicit)
        : val_(val) {}
  
    constexpr StoreTypeValue value() const { return val_; }
    constexpr unsigned size_log_2() const { return kStoreSizeLog2[val_]; }
    constexpr unsigned size() const { return 1 << size_log_2(); }
    constexpr ValueType value_type() const { return kValueType[val_]; }
    constexpr MachineRepresentation mem_rep() const { return kMemRep[val_]; }
  
    static StoreType ForValueType(ValueType type) {
      switch (type) {
        case kWasmI32:
          return kI32Store;
        case kWasmI64:
          return kI64Store;
        case kWasmF32:
          return kF32Store;
        case kWasmF64:
          return kF64Store;
        default:
          UNREACHABLE();
      }
    }
  
   private:
    const StoreTypeValue val_;
  
    static constexpr uint8_t kStoreSizeLog2[] = {
  #define STORE_SIZE(_, __, ___, size) size,
        FOREACH_STORE_TYPE(STORE_SIZE)
  #undef STORE_SIZE
    };
  
    static constexpr ValueType kValueType[] = {
  #define VALUE_TYPE(type, ...) kWasm##type,
        FOREACH_STORE_TYPE(VALUE_TYPE)
  #undef VALUE_TYPE
    };
  
    static constexpr MachineRepresentation kMemRep[] = {
  #define MEMREP(_, __, memrep, ___) MachineRepresentation::k##memrep,
        FOREACH_STORE_TYPE(MEMREP)
  #undef MEMREP
    };
  };
  
  // A collection of ValueType-related static methods.
  class V8_EXPORT_PRIVATE ValueTypes {
   public:
    static byte MemSize(MachineType type) {
      return 1 << i::ElementSizeLog2Of(type.representation());
    }
  
    static int ElementSizeInBytes(ValueType type) {
      switch (type) {
        case kWasmI32:
        case kWasmF32:
          return 4;
        case kWasmI64:
        case kWasmF64:
          return 8;
        case kWasmS128:
          return 16;
        default:
          UNREACHABLE();
      }
    }
  
    static int ElementSizeLog2Of(ValueType type) {
      switch (type) {
        case kWasmI32:
        case kWasmF32:
          return 2;
        case kWasmI64:
        case kWasmF64:
          return 3;
        case kWasmS128:
          return 4;
        default:
          UNREACHABLE();
      }
    }
  
    static byte MemSize(ValueType type) { return 1 << ElementSizeLog2Of(type); }
  
    static ValueTypeCode ValueTypeCodeFor(ValueType type) {
      switch (type) {
        case kWasmI32:
          return kLocalI32;
        case kWasmI64:
          return kLocalI64;
        case kWasmF32:
          return kLocalF32;
        case kWasmF64:
          return kLocalF64;
        case kWasmS128:
          return kLocalS128;
        case kWasmAnyRef:
          return kLocalAnyRef;
        case kWasmExceptRef:
          return kLocalExceptRef;
        case kWasmStmt:
          return kLocalVoid;
        default:
          UNREACHABLE();
      }
    }
  
    static MachineType MachineTypeFor(ValueType type) {
      switch (type) {
        case kWasmI32:
          return MachineType::Int32();
        case kWasmI64:
          return MachineType::Int64();
        case kWasmF32:
          return MachineType::Float32();
        case kWasmF64:
          return MachineType::Float64();
        case kWasmAnyFunc:
        case kWasmAnyRef:
          return MachineType::TaggedPointer();
        case kWasmS128:
          return MachineType::Simd128();
        case kWasmStmt:
          return MachineType::None();
        default:
          UNREACHABLE();
      }
    }
  
    static MachineRepresentation MachineRepresentationFor(ValueType type) {
      switch (type) {
        case kWasmI32:
          return MachineRepresentation::kWord32;
        case kWasmI64:
          return MachineRepresentation::kWord64;
        case kWasmF32:
          return MachineRepresentation::kFloat32;
        case kWasmF64:
          return MachineRepresentation::kFloat64;
        case kWasmAnyRef:
        case kWasmExceptRef:
          return MachineRepresentation::kTaggedPointer;
        case kWasmS128:
          return MachineRepresentation::kSimd128;
        case kWasmStmt:
          return MachineRepresentation::kNone;
        default:
          UNREACHABLE();
      }
    }
  
    static ValueType ValueTypeFor(MachineType type) {
      switch (type.representation()) {
        case MachineRepresentation::kWord8:
        case MachineRepresentation::kWord16:
        case MachineRepresentation::kWord32:
          return kWasmI32;
        case MachineRepresentation::kWord64:
          return kWasmI64;
        case MachineRepresentation::kFloat32:
          return kWasmF32;
        case MachineRepresentation::kFloat64:
          return kWasmF64;
        case MachineRepresentation::kTaggedPointer:
          return kWasmAnyRef;
        case MachineRepresentation::kSimd128:
          return kWasmS128;
        default:
          UNREACHABLE();
      }
    }
  
    static char ShortNameOf(ValueType type) {
      switch (type) {
        case kWasmI32:
          return 'i';
        case kWasmI64:
          return 'l';
        case kWasmF32:
          return 'f';
        case kWasmF64:
          return 'd';
        case kWasmAnyRef:
          return 'r';
        case kWasmS128:
          return 's';
        case kWasmStmt:
          return 'v';
        case kWasmVar:
          return '*';
        default:
          return '?';
      }
    }
  
    static const char* TypeName(ValueType type) {
      switch (type) {
        case kWasmI32:
          return "i32";
        case kWasmI64:
          return "i64";
        case kWasmF32:
          return "f32";
        case kWasmF64:
          return "f64";
        case kWasmAnyRef:
          return "ref";
        case kWasmExceptRef:
          return "exn";
        case kWasmS128:
          return "s128";
        case kWasmStmt:
          return "<stmt>";
        case kWasmVar:
          return "<var>";
        default:
          return "<unknown>";
      }
    }
  
   private:
    DISALLOW_IMPLICIT_CONSTRUCTORS(ValueTypes);
  };
  
  }  // namespace wasm
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_WASM_VALUE_TYPE_H_
  