// Copyright 2015 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_INTERPRETER_BYTECODE_TRAITS_H_ #define V8_INTERPRETER_BYTECODE_TRAITS_H_ #include "src/interpreter/bytecodes.h" namespace v8 { namespace internal { namespace interpreter { template <OperandTypeInfo> struct OperandTypeInfoTraits { static const bool kIsScalable = false; static const bool kIsUnsigned = false; static const OperandSize kUnscaledSize = OperandSize::kNone; }; #define DECLARE_OPERAND_TYPE_INFO(Name, Scalable, Unsigned, BaseSize) \ template <> \ struct OperandTypeInfoTraits<OperandTypeInfo::k##Name> { \ static const bool kIsScalable = Scalable; \ static const bool kIsUnsigned = Unsigned; \ static const OperandSize kUnscaledSize = BaseSize; \ }; OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO) #undef DECLARE_OPERAND_TYPE_INFO template <OperandType> struct OperandTraits { typedef OperandTypeInfoTraits<OperandTypeInfo::kNone> TypeInfoTraits; static const OperandTypeInfo kOperandTypeInfo = OperandTypeInfo::kNone; }; #define DECLARE_OPERAND_TYPE_TRAITS(Name, InfoType) \ template <> \ struct OperandTraits<OperandType::k##Name> { \ typedef OperandTypeInfoTraits<InfoType> TypeInfoTraits; \ static const OperandTypeInfo kOperandTypeInfo = InfoType; \ }; OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE_TRAITS) #undef DECLARE_OPERAND_TYPE_TRAITS template <OperandType operand_type, OperandScale operand_scale> struct OperandScaler { template <bool, OperandSize, OperandScale> struct Helper { static const int kSize = 0; }; template <OperandSize size, OperandScale scale> struct Helper<false, size, scale> { static const int kSize = static_cast<int>(size); }; template <OperandSize size, OperandScale scale> struct Helper<true, size, scale> { static const int kSize = static_cast<int>(size) * static_cast<int>(scale); }; static const int kSize = Helper<OperandTraits<operand_type>::TypeInfoTraits::kIsScalable, OperandTraits<operand_type>::TypeInfoTraits::kUnscaledSize, operand_scale>::kSize; static const OperandSize kOperandSize = static_cast<OperandSize>(kSize); }; template <OperandType> struct RegisterOperandTraits { static const int kIsRegisterOperand = 0; }; #define DECLARE_REGISTER_OPERAND(Name, _) \ template <> \ struct RegisterOperandTraits<OperandType::k##Name> { \ static const int kIsRegisterOperand = 1; \ }; REGISTER_OPERAND_TYPE_LIST(DECLARE_REGISTER_OPERAND) #undef DECLARE_REGISTER_OPERAND template <AccumulatorUse, OperandType...> struct BytecodeTraits {}; template <AccumulatorUse accumulator_use, OperandType operand_0, OperandType operand_1, OperandType operand_2, OperandType operand_3> struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2, operand_3> { static const OperandType* GetOperandTypes() { static const OperandType operand_types[] = {operand_0, operand_1, operand_2, operand_3, OperandType::kNone}; return operand_types; } static const OperandTypeInfo* GetOperandTypeInfos() { static const OperandTypeInfo operand_type_infos[] = { OperandTraits<operand_0>::kOperandTypeInfo, OperandTraits<operand_1>::kOperandTypeInfo, OperandTraits<operand_2>::kOperandTypeInfo, OperandTraits<operand_3>::kOperandTypeInfo, OperandTypeInfo::kNone}; return operand_type_infos; } static const OperandSize* GetOperandSizes(OperandScale operand_scale) { switch (operand_scale) { #define CASE(Name, _) \ case OperandScale::k##Name: { \ static const OperandSize kOperandSizes[] = { \ OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \ OperandScaler<operand_2, OperandScale::k##Name>::kOperandSize, \ OperandScaler<operand_3, OperandScale::k##Name>::kOperandSize, \ }; \ return kOperandSizes; \ } OPERAND_SCALE_LIST(CASE) #undef CASE } UNREACHABLE(); return nullptr; } template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot || operand_1 == ot || operand_2 == ot || operand_3 == ot; } static inline bool IsScalable() { return (OperandTraits<operand_0>::TypeInfoTraits::kIsScalable | OperandTraits<operand_1>::TypeInfoTraits::kIsScalable | OperandTraits<operand_2>::TypeInfoTraits::kIsScalable | OperandTraits<operand_3>::TypeInfoTraits::kIsScalable); } static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 4; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand + RegisterOperandTraits<operand_1>::kIsRegisterOperand + RegisterOperandTraits<operand_2>::kIsRegisterOperand + RegisterOperandTraits<operand_3>::kIsRegisterOperand; static const int kRegisterOperandBitmap = RegisterOperandTraits<operand_0>::kIsRegisterOperand + (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1) + (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2) + (RegisterOperandTraits<operand_3>::kIsRegisterOperand << 3); }; template <AccumulatorUse accumulator_use, OperandType operand_0, OperandType operand_1, OperandType operand_2> struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2> { static const OperandType* GetOperandTypes() { static const OperandType operand_types[] = {operand_0, operand_1, operand_2, OperandType::kNone}; return operand_types; } static const OperandTypeInfo* GetOperandTypeInfos() { static const OperandTypeInfo operand_type_infos[] = { OperandTraits<operand_0>::kOperandTypeInfo, OperandTraits<operand_1>::kOperandTypeInfo, OperandTraits<operand_2>::kOperandTypeInfo, OperandTypeInfo::kNone}; return operand_type_infos; } static const OperandSize* GetOperandSizes(OperandScale operand_scale) { switch (operand_scale) { #define CASE(Name, _) \ case OperandScale::k##Name: { \ static const OperandSize kOperandSizes[] = { \ OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \ OperandScaler<operand_2, OperandScale::k##Name>::kOperandSize, \ }; \ return kOperandSizes; \ } OPERAND_SCALE_LIST(CASE) #undef CASE } UNREACHABLE(); return nullptr; } template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot || operand_1 == ot || operand_2 == ot; } static inline bool IsScalable() { return (OperandTraits<operand_0>::TypeInfoTraits::kIsScalable | OperandTraits<operand_1>::TypeInfoTraits::kIsScalable | OperandTraits<operand_2>::TypeInfoTraits::kIsScalable); } static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 3; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand + RegisterOperandTraits<operand_1>::kIsRegisterOperand + RegisterOperandTraits<operand_2>::kIsRegisterOperand; static const int kRegisterOperandBitmap = RegisterOperandTraits<operand_0>::kIsRegisterOperand + (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1) + (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2); }; template <AccumulatorUse accumulator_use, OperandType operand_0, OperandType operand_1> struct BytecodeTraits<accumulator_use, operand_0, operand_1> { static const OperandType* GetOperandTypes() { static const OperandType operand_types[] = {operand_0, operand_1, OperandType::kNone}; return operand_types; } static const OperandTypeInfo* GetOperandTypeInfos() { static const OperandTypeInfo operand_type_infos[] = { OperandTraits<operand_0>::kOperandTypeInfo, OperandTraits<operand_1>::kOperandTypeInfo, OperandTypeInfo::kNone}; return operand_type_infos; } static const OperandSize* GetOperandSizes(OperandScale operand_scale) { switch (operand_scale) { #define CASE(Name, _) \ case OperandScale::k##Name: { \ static const OperandSize kOperandSizes[] = { \ OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \ }; \ return kOperandSizes; \ } OPERAND_SCALE_LIST(CASE) #undef CASE } UNREACHABLE(); return nullptr; } template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot || operand_1 == ot; } static inline bool IsScalable() { return (OperandTraits<operand_0>::TypeInfoTraits::kIsScalable | OperandTraits<operand_1>::TypeInfoTraits::kIsScalable); } static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 2; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand + RegisterOperandTraits<operand_1>::kIsRegisterOperand; static const int kRegisterOperandBitmap = RegisterOperandTraits<operand_0>::kIsRegisterOperand + (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1); }; template <AccumulatorUse accumulator_use, OperandType operand_0> struct BytecodeTraits<accumulator_use, operand_0> { static const OperandType* GetOperandTypes() { static const OperandType operand_types[] = {operand_0, OperandType::kNone}; return operand_types; } static const OperandTypeInfo* GetOperandTypeInfos() { static const OperandTypeInfo operand_type_infos[] = { OperandTraits<operand_0>::kOperandTypeInfo, OperandTypeInfo::kNone}; return operand_type_infos; } static const OperandSize* GetOperandSizes(OperandScale operand_scale) { switch (operand_scale) { #define CASE(Name, _) \ case OperandScale::k##Name: { \ static const OperandSize kOperandSizes[] = { \ OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ }; \ return kOperandSizes; \ } OPERAND_SCALE_LIST(CASE) #undef CASE } UNREACHABLE(); return nullptr; } template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot; } static inline bool IsScalable() { return OperandTraits<operand_0>::TypeInfoTraits::kIsScalable; } static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 1; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand; static const int kRegisterOperandBitmap = RegisterOperandTraits<operand_0>::kIsRegisterOperand; }; template <AccumulatorUse accumulator_use> struct BytecodeTraits<accumulator_use> { static const OperandType* GetOperandTypes() { static const OperandType operand_types[] = {OperandType::kNone}; return operand_types; } static const OperandTypeInfo* GetOperandTypeInfos() { static const OperandTypeInfo operand_type_infos[] = { OperandTypeInfo::kNone}; return operand_type_infos; } static const OperandSize* GetOperandSizes(OperandScale operand_scale) { return nullptr; } template <OperandType ot> static inline bool HasAnyOperandsOfType() { return false; } static inline bool IsScalable() { return false; } static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 0; static const int kRegisterOperandCount = 0; static const int kRegisterOperandBitmap = 0; }; static OperandSize ScaledOperandSize(OperandType operand_type, OperandScale operand_scale) { STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 && OperandScale::kLast == OperandScale::kQuadruple); int index = static_cast<int>(operand_scale) >> 1; switch (operand_type) { #define CASE(Name, TypeInfo) \ case OperandType::k##Name: { \ static const OperandSize kOperandSizes[] = { \ OperandScaler<OperandType::k##Name, \ OperandScale::kSingle>::kOperandSize, \ OperandScaler<OperandType::k##Name, \ OperandScale::kDouble>::kOperandSize, \ OperandScaler<OperandType::k##Name, \ OperandScale::kQuadruple>::kOperandSize}; \ return kOperandSizes[index]; \ } OPERAND_TYPE_LIST(CASE) #undef CASE } UNREACHABLE(); return OperandSize::kNone; } } // namespace interpreter } // namespace internal } // namespace v8 #endif // V8_INTERPRETER_BYTECODE_TRAITS_H_