1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_INTERPRETER_BYTECODE_OPERANDS_H_ 6 #define V8_INTERPRETER_BYTECODE_OPERANDS_H_ 7 8 #include "src/base/bounds.h" 9 #include "src/common/globals.h" 10 11 namespace v8 { 12 namespace internal { 13 namespace interpreter { 14 15 #define INVALID_OPERAND_TYPE_LIST(V) V(None, OperandTypeInfo::kNone) 16 17 #define REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ 18 V(Reg, OperandTypeInfo::kScalableSignedByte) \ 19 V(RegList, OperandTypeInfo::kScalableSignedByte) \ 20 V(RegPair, OperandTypeInfo::kScalableSignedByte) 21 22 #define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V) \ 23 V(RegOut, OperandTypeInfo::kScalableSignedByte) \ 24 V(RegOutList, OperandTypeInfo::kScalableSignedByte) \ 25 V(RegOutPair, OperandTypeInfo::kScalableSignedByte) \ 26 V(RegOutTriple, OperandTypeInfo::kScalableSignedByte) 27 28 #define SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \ 29 V(Imm, OperandTypeInfo::kScalableSignedByte) 30 31 #define UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \ 32 V(Idx, OperandTypeInfo::kScalableUnsignedByte) \ 33 V(UImm, OperandTypeInfo::kScalableUnsignedByte) \ 34 V(RegCount, OperandTypeInfo::kScalableUnsignedByte) 35 36 #define UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V) \ 37 V(Flag8, OperandTypeInfo::kFixedUnsignedByte) \ 38 V(IntrinsicId, OperandTypeInfo::kFixedUnsignedByte) \ 39 V(RuntimeId, OperandTypeInfo::kFixedUnsignedShort) \ 40 V(NativeContextIndex, OperandTypeInfo::kFixedUnsignedByte) 41 42 // Carefully ordered for operand type range checks below. 43 #define NON_REGISTER_OPERAND_TYPE_LIST(V) \ 44 INVALID_OPERAND_TYPE_LIST(V) \ 45 UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V) \ 46 UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \ 47 SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) 48 49 // Carefully ordered for operand type range checks below. 50 #define REGISTER_OPERAND_TYPE_LIST(V) \ 51 REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ 52 REGISTER_OUTPUT_OPERAND_TYPE_LIST(V) 53 54 // The list of operand types used by bytecodes. 55 // Carefully ordered for operand type range checks below. 56 #define OPERAND_TYPE_LIST(V) \ 57 NON_REGISTER_OPERAND_TYPE_LIST(V) \ 58 REGISTER_OPERAND_TYPE_LIST(V) 59 60 // Enumeration of scaling factors applicable to scalable operands. Code 61 // relies on being able to cast values to integer scaling values. 62 #define OPERAND_SCALE_LIST(V) \ 63 V(Single, 1) \ 64 V(Double, 2) \ 65 V(Quadruple, 4) 66 67 enum class OperandScale : uint8_t { 68 #define DECLARE_OPERAND_SCALE(Name, Scale) k##Name = Scale, 69 OPERAND_SCALE_LIST(DECLARE_OPERAND_SCALE) 70 #undef DECLARE_OPERAND_SCALE 71 kLast = kQuadruple 72 }; 73 74 // Enumeration of the size classes of operand types used by 75 // bytecodes. Code relies on being able to cast values to integer 76 // types to get the size in bytes. 77 enum class OperandSize : uint8_t { 78 kNone = 0, 79 kByte = 1, 80 kShort = 2, 81 kQuad = 4, 82 kLast = kQuad 83 }; 84 85 // Primitive operand info used that summarize properties of operands. 86 // Columns are Name, IsScalable, IsUnsigned, UnscaledSize. 87 #define OPERAND_TYPE_INFO_LIST(V) \ 88 V(None, false, false, OperandSize::kNone) \ 89 V(ScalableSignedByte, true, false, OperandSize::kByte) \ 90 V(ScalableUnsignedByte, true, true, OperandSize::kByte) \ 91 V(FixedUnsignedByte, false, true, OperandSize::kByte) \ 92 V(FixedUnsignedShort, false, true, OperandSize::kShort) 93 94 enum class OperandTypeInfo : uint8_t { 95 #define DECLARE_OPERAND_TYPE_INFO(Name, ...) k##Name, 96 OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO) 97 #undef DECLARE_OPERAND_TYPE_INFO 98 }; 99 100 // Enumeration of operand types used by bytecodes. 101 enum class OperandType : uint8_t { 102 #define DECLARE_OPERAND_TYPE(Name, _) k##Name, 103 OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE) 104 #undef DECLARE_OPERAND_TYPE 105 #define COUNT_OPERAND_TYPES(x, _) +1 106 // The COUNT_OPERAND macro will turn this into kLast = -1 +1 +1... which will 107 // evaluate to the same value as the last operand. 108 kLast = -1 OPERAND_TYPE_LIST(COUNT_OPERAND_TYPES) 109 #undef COUNT_OPERAND_TYPES 110 }; 111 112 enum class AccumulatorUse : uint8_t { 113 kNone = 0, 114 kRead = 1 << 0, 115 kWrite = 1 << 1, 116 kReadWrite = kRead | kWrite 117 }; 118 119 constexpr inline AccumulatorUse operator&(AccumulatorUse lhs, 120 AccumulatorUse rhs) { 121 return static_cast<AccumulatorUse>(static_cast<int>(lhs) & 122 static_cast<int>(rhs)); 123 } 124 125 constexpr inline AccumulatorUse operator|(AccumulatorUse lhs, 126 AccumulatorUse rhs) { 127 return static_cast<AccumulatorUse>(static_cast<int>(lhs) | 128 static_cast<int>(rhs)); 129 } 130 131 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 132 const AccumulatorUse& use); 133 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 134 const OperandScale& operand_scale); 135 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 136 const OperandSize& operand_size); 137 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 138 const OperandType& operand_type); 139 140 class BytecodeOperands : public AllStatic { 141 public: 142 // The total number of bytecode operand types used. 143 static const int kOperandTypeCount = static_cast<int>(OperandType::kLast) + 1; 144 145 // The total number of bytecode operand scales used. 146 #define OPERAND_SCALE_COUNT(...) +1 147 static const int kOperandScaleCount = 148 0 OPERAND_SCALE_LIST(OPERAND_SCALE_COUNT); 149 #undef OPERAND_SCALE_COUNT 150 OperandScaleAsIndex(OperandScale operand_scale)151 static constexpr int OperandScaleAsIndex(OperandScale operand_scale) { 152 #if V8_HAS_CXX14_CONSTEXPR 153 #ifdef DEBUG 154 int result = static_cast<int>(operand_scale) >> 1; 155 switch (operand_scale) { 156 case OperandScale::kSingle: 157 DCHECK_EQ(0, result); 158 break; 159 case OperandScale::kDouble: 160 DCHECK_EQ(1, result); 161 break; 162 case OperandScale::kQuadruple: 163 DCHECK_EQ(2, result); 164 break; 165 default: 166 UNREACHABLE(); 167 } 168 #endif 169 #endif 170 return static_cast<int>(operand_scale) >> 1; 171 } 172 173 // Returns true if |accumulator_use| reads the accumulator. ReadsAccumulator(AccumulatorUse accumulator_use)174 static constexpr bool ReadsAccumulator(AccumulatorUse accumulator_use) { 175 return (accumulator_use & AccumulatorUse::kRead) == AccumulatorUse::kRead; 176 } 177 178 // Returns true if |accumulator_use| writes the accumulator. WritesAccumulator(AccumulatorUse accumulator_use)179 static constexpr bool WritesAccumulator(AccumulatorUse accumulator_use) { 180 return (accumulator_use & AccumulatorUse::kWrite) == AccumulatorUse::kWrite; 181 } 182 183 // Returns true if |operand_type| is a scalable signed byte. IsScalableSignedByte(OperandType operand_type)184 static constexpr bool IsScalableSignedByte(OperandType operand_type) { 185 return base::IsInRange(operand_type, OperandType::kImm, 186 OperandType::kRegOutTriple); 187 } 188 189 // Returns true if |operand_type| is a scalable unsigned byte. IsScalableUnsignedByte(OperandType operand_type)190 static constexpr bool IsScalableUnsignedByte(OperandType operand_type) { 191 return base::IsInRange(operand_type, OperandType::kIdx, 192 OperandType::kRegCount); 193 } 194 }; 195 196 } // namespace interpreter 197 } // namespace internal 198 } // namespace v8 199 200 #endif // V8_INTERPRETER_BYTECODE_OPERANDS_H_ 201