| // Copyright 2016 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_OPERANDS_H_ |
| #define V8_INTERPRETER_BYTECODE_OPERANDS_H_ |
| |
| #include "src/base/bounds.h" |
| #include "src/common/globals.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace interpreter { |
| |
| #define INVALID_OPERAND_TYPE_LIST(V) V(None, OperandTypeInfo::kNone) |
| |
| #define REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ |
| V(Reg, OperandTypeInfo::kScalableSignedByte) \ |
| V(RegList, OperandTypeInfo::kScalableSignedByte) \ |
| V(RegPair, OperandTypeInfo::kScalableSignedByte) |
| |
| #define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V) \ |
| V(RegOut, OperandTypeInfo::kScalableSignedByte) \ |
| V(RegOutList, OperandTypeInfo::kScalableSignedByte) \ |
| V(RegOutPair, OperandTypeInfo::kScalableSignedByte) \ |
| V(RegOutTriple, OperandTypeInfo::kScalableSignedByte) |
| |
| #define SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \ |
| V(Imm, OperandTypeInfo::kScalableSignedByte) |
| |
| #define UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \ |
| V(Idx, OperandTypeInfo::kScalableUnsignedByte) \ |
| V(UImm, OperandTypeInfo::kScalableUnsignedByte) \ |
| V(RegCount, OperandTypeInfo::kScalableUnsignedByte) |
| |
| #define UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V) \ |
| V(Flag8, OperandTypeInfo::kFixedUnsignedByte) \ |
| V(IntrinsicId, OperandTypeInfo::kFixedUnsignedByte) \ |
| V(RuntimeId, OperandTypeInfo::kFixedUnsignedShort) \ |
| V(NativeContextIndex, OperandTypeInfo::kFixedUnsignedByte) |
| |
| // Carefully ordered for operand type range checks below. |
| #define NON_REGISTER_OPERAND_TYPE_LIST(V) \ |
| INVALID_OPERAND_TYPE_LIST(V) \ |
| UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V) \ |
| UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \ |
| SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) |
| |
| // Carefully ordered for operand type range checks below. |
| #define REGISTER_OPERAND_TYPE_LIST(V) \ |
| REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ |
| REGISTER_OUTPUT_OPERAND_TYPE_LIST(V) |
| |
| // The list of operand types used by bytecodes. |
| // Carefully ordered for operand type range checks below. |
| #define OPERAND_TYPE_LIST(V) \ |
| NON_REGISTER_OPERAND_TYPE_LIST(V) \ |
| REGISTER_OPERAND_TYPE_LIST(V) |
| |
| // Enumeration of scaling factors applicable to scalable operands. Code |
| // relies on being able to cast values to integer scaling values. |
| #define OPERAND_SCALE_LIST(V) \ |
| V(Single, 1) \ |
| V(Double, 2) \ |
| V(Quadruple, 4) |
| |
| enum class OperandScale : uint8_t { |
| #define DECLARE_OPERAND_SCALE(Name, Scale) k##Name = Scale, |
| OPERAND_SCALE_LIST(DECLARE_OPERAND_SCALE) |
| #undef DECLARE_OPERAND_SCALE |
| kLast = kQuadruple |
| }; |
| |
| // Enumeration of the size classes of operand types used by |
| // bytecodes. Code relies on being able to cast values to integer |
| // types to get the size in bytes. |
| enum class OperandSize : uint8_t { |
| kNone = 0, |
| kByte = 1, |
| kShort = 2, |
| kQuad = 4, |
| kLast = kQuad |
| }; |
| |
| // Primitive operand info used that summarize properties of operands. |
| // Columns are Name, IsScalable, IsUnsigned, UnscaledSize. |
| #define OPERAND_TYPE_INFO_LIST(V) \ |
| V(None, false, false, OperandSize::kNone) \ |
| V(ScalableSignedByte, true, false, OperandSize::kByte) \ |
| V(ScalableUnsignedByte, true, true, OperandSize::kByte) \ |
| V(FixedUnsignedByte, false, true, OperandSize::kByte) \ |
| V(FixedUnsignedShort, false, true, OperandSize::kShort) |
| |
| enum class OperandTypeInfo : uint8_t { |
| #define DECLARE_OPERAND_TYPE_INFO(Name, ...) k##Name, |
| OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO) |
| #undef DECLARE_OPERAND_TYPE_INFO |
| }; |
| |
| // Enumeration of operand types used by bytecodes. |
| enum class OperandType : uint8_t { |
| #define DECLARE_OPERAND_TYPE(Name, _) k##Name, |
| OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE) |
| #undef DECLARE_OPERAND_TYPE |
| #define COUNT_OPERAND_TYPES(x, _) +1 |
| // The COUNT_OPERAND macro will turn this into kLast = -1 +1 +1... which will |
| // evaluate to the same value as the last operand. |
| kLast = -1 OPERAND_TYPE_LIST(COUNT_OPERAND_TYPES) |
| #undef COUNT_OPERAND_TYPES |
| }; |
| |
| enum class AccumulatorUse : uint8_t { |
| kNone = 0, |
| kRead = 1 << 0, |
| kWrite = 1 << 1, |
| kReadWrite = kRead | kWrite |
| }; |
| |
| constexpr inline AccumulatorUse operator&(AccumulatorUse lhs, |
| AccumulatorUse rhs) { |
| return static_cast<AccumulatorUse>(static_cast<int>(lhs) & |
| static_cast<int>(rhs)); |
| } |
| |
| constexpr inline AccumulatorUse operator|(AccumulatorUse lhs, |
| AccumulatorUse rhs) { |
| return static_cast<AccumulatorUse>(static_cast<int>(lhs) | |
| static_cast<int>(rhs)); |
| } |
| |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| const AccumulatorUse& use); |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| const OperandScale& operand_scale); |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| const OperandSize& operand_size); |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| const OperandType& operand_type); |
| |
| class BytecodeOperands : public AllStatic { |
| public: |
| // The total number of bytecode operand types used. |
| static const int kOperandTypeCount = static_cast<int>(OperandType::kLast) + 1; |
| |
| // The total number of bytecode operand scales used. |
| #define OPERAND_SCALE_COUNT(...) +1 |
| static const int kOperandScaleCount = |
| 0 OPERAND_SCALE_LIST(OPERAND_SCALE_COUNT); |
| #undef OPERAND_SCALE_COUNT |
| |
| static constexpr int OperandScaleAsIndex(OperandScale operand_scale) { |
| #if V8_HAS_CXX14_CONSTEXPR |
| #ifdef DEBUG |
| int result = static_cast<int>(operand_scale) >> 1; |
| switch (operand_scale) { |
| case OperandScale::kSingle: |
| DCHECK_EQ(0, result); |
| break; |
| case OperandScale::kDouble: |
| DCHECK_EQ(1, result); |
| break; |
| case OperandScale::kQuadruple: |
| DCHECK_EQ(2, result); |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| #endif |
| #endif |
| return static_cast<int>(operand_scale) >> 1; |
| } |
| |
| // Returns true if |accumulator_use| reads the accumulator. |
| static constexpr bool ReadsAccumulator(AccumulatorUse accumulator_use) { |
| return (accumulator_use & AccumulatorUse::kRead) == AccumulatorUse::kRead; |
| } |
| |
| // Returns true if |accumulator_use| writes the accumulator. |
| static constexpr bool WritesAccumulator(AccumulatorUse accumulator_use) { |
| return (accumulator_use & AccumulatorUse::kWrite) == AccumulatorUse::kWrite; |
| } |
| |
| // Returns true if |operand_type| is a scalable signed byte. |
| static constexpr bool IsScalableSignedByte(OperandType operand_type) { |
| return base::IsInRange(operand_type, OperandType::kImm, |
| OperandType::kRegOutTriple); |
| } |
| |
| // Returns true if |operand_type| is a scalable unsigned byte. |
| static constexpr bool IsScalableUnsignedByte(OperandType operand_type) { |
| return base::IsInRange(operand_type, OperandType::kIdx, |
| OperandType::kRegCount); |
| } |
| }; |
| |
| } // namespace interpreter |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_INTERPRETER_BYTECODE_OPERANDS_H_ |