blob: ea3d5d4e441078350761bb3c98a0ae5f4e9abb05 [file] [log] [blame]
// 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_