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 ImplicitRegisterUse : uint8_t { 113 kNone = 0, 114 kReadAccumulator = 1 << 0, 115 kWriteAccumulator = 1 << 1, 116 kWriteShortStar = 1 << 2, 117 kReadWriteAccumulator = kReadAccumulator | kWriteAccumulator, 118 kReadAccumulatorWriteShortStar = kReadAccumulator | kWriteShortStar 119 }; 120 121 constexpr inline ImplicitRegisterUse operator&(ImplicitRegisterUse lhs, 122 ImplicitRegisterUse rhs) { 123 return static_cast<ImplicitRegisterUse>(static_cast<int>(lhs) & 124 static_cast<int>(rhs)); 125 } 126 127 constexpr inline ImplicitRegisterUse operator|(ImplicitRegisterUse lhs, 128 ImplicitRegisterUse rhs) { 129 return static_cast<ImplicitRegisterUse>(static_cast<int>(lhs) | 130 static_cast<int>(rhs)); 131 } 132 133 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 134 const ImplicitRegisterUse& use); 135 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 136 const OperandScale& operand_scale); 137 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 138 const OperandSize& operand_size); 139 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, 140 const OperandType& operand_type); 141 142 class BytecodeOperands : public AllStatic { 143 public: 144 // The total number of bytecode operand types used. 145 static const int kOperandTypeCount = static_cast<int>(OperandType::kLast) + 1; 146 147 // The total number of bytecode operand scales used. 148 #define OPERAND_SCALE_COUNT(...) +1 149 static const int kOperandScaleCount = 150 0 OPERAND_SCALE_LIST(OPERAND_SCALE_COUNT); 151 #undef OPERAND_SCALE_COUNT 152 OperandScaleAsIndex(OperandScale operand_scale)153 static constexpr int OperandScaleAsIndex(OperandScale operand_scale) { 154 #ifdef DEBUG 155 int result = static_cast<int>(operand_scale) >> 1; 156 switch (operand_scale) { 157 case OperandScale::kSingle: 158 DCHECK_EQ(0, result); 159 break; 160 case OperandScale::kDouble: 161 DCHECK_EQ(1, result); 162 break; 163 case OperandScale::kQuadruple: 164 DCHECK_EQ(2, result); 165 break; 166 default: 167 UNREACHABLE(); 168 } 169 #endif 170 return static_cast<int>(operand_scale) >> 1; 171 } 172 173 // Returns true if |implicit_register_use| reads the 174 // accumulator. ReadsAccumulator(ImplicitRegisterUse implicit_register_use)175 static constexpr bool ReadsAccumulator( 176 ImplicitRegisterUse implicit_register_use) { 177 return (implicit_register_use & ImplicitRegisterUse::kReadAccumulator) == 178 ImplicitRegisterUse::kReadAccumulator; 179 } 180 181 // Returns true if |implicit_register_use| writes the 182 // accumulator. WritesAccumulator(ImplicitRegisterUse implicit_register_use)183 static constexpr bool WritesAccumulator( 184 ImplicitRegisterUse implicit_register_use) { 185 return (implicit_register_use & ImplicitRegisterUse::kWriteAccumulator) == 186 ImplicitRegisterUse::kWriteAccumulator; 187 } 188 189 // Returns true if |implicit_register_use| writes to a 190 // register not specified by an operand. WritesImplicitRegister(ImplicitRegisterUse implicit_register_use)191 static constexpr bool WritesImplicitRegister( 192 ImplicitRegisterUse implicit_register_use) { 193 return (implicit_register_use & ImplicitRegisterUse::kWriteShortStar) == 194 ImplicitRegisterUse::kWriteShortStar; 195 } 196 197 // Returns true if |operand_type| is a scalable signed byte. IsScalableSignedByte(OperandType operand_type)198 static constexpr bool IsScalableSignedByte(OperandType operand_type) { 199 return base::IsInRange(operand_type, OperandType::kImm, 200 OperandType::kRegOutTriple); 201 } 202 203 // Returns true if |operand_type| is a scalable unsigned byte. IsScalableUnsignedByte(OperandType operand_type)204 static constexpr bool IsScalableUnsignedByte(OperandType operand_type) { 205 return base::IsInRange(operand_type, OperandType::kIdx, 206 OperandType::kRegCount); 207 } 208 }; 209 210 } // namespace interpreter 211 } // namespace internal 212 } // namespace v8 213 214 #endif // V8_INTERPRETER_BYTECODE_OPERANDS_H_ 215