1 // Copyright 2015 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_TRAITS_H_ 6 #define V8_INTERPRETER_BYTECODE_TRAITS_H_ 7 8 #include "src/interpreter/bytecodes.h" 9 10 namespace v8 { 11 namespace internal { 12 namespace interpreter { 13 14 template <OperandTypeInfo> 15 struct OperandTypeInfoTraits { 16 static const bool kIsScalable = false; 17 static const bool kIsUnsigned = false; 18 static const OperandSize kUnscaledSize = OperandSize::kNone; 19 }; 20 21 #define DECLARE_OPERAND_TYPE_INFO(Name, Scalable, Unsigned, BaseSize) \ 22 template <> \ 23 struct OperandTypeInfoTraits<OperandTypeInfo::k##Name> { \ 24 static const bool kIsScalable = Scalable; \ 25 static const bool kIsUnsigned = Unsigned; \ 26 static const OperandSize kUnscaledSize = BaseSize; \ 27 }; 28 OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO) 29 #undef DECLARE_OPERAND_TYPE_INFO 30 31 template <OperandType> 32 struct OperandTraits { 33 typedef OperandTypeInfoTraits<OperandTypeInfo::kNone> TypeInfoTraits; 34 static const OperandTypeInfo kOperandTypeInfo = OperandTypeInfo::kNone; 35 }; 36 37 #define DECLARE_OPERAND_TYPE_TRAITS(Name, InfoType) \ 38 template <> \ 39 struct OperandTraits<OperandType::k##Name> { \ 40 typedef OperandTypeInfoTraits<InfoType> TypeInfoTraits; \ 41 static const OperandTypeInfo kOperandTypeInfo = InfoType; \ 42 }; 43 OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE_TRAITS) 44 #undef DECLARE_OPERAND_TYPE_TRAITS 45 46 template <OperandType operand_type, OperandScale operand_scale> 47 struct OperandScaler { 48 template <bool, OperandSize, OperandScale> 49 struct Helper { 50 static const int kSize = 0; 51 }; 52 template <OperandSize size, OperandScale scale> 53 struct Helper<false, size, scale> { 54 static const int kSize = static_cast<int>(size); 55 }; 56 template <OperandSize size, OperandScale scale> 57 struct Helper<true, size, scale> { 58 static const int kSize = static_cast<int>(size) * static_cast<int>(scale); 59 }; 60 61 static const int kSize = 62 Helper<OperandTraits<operand_type>::TypeInfoTraits::kIsScalable, 63 OperandTraits<operand_type>::TypeInfoTraits::kUnscaledSize, 64 operand_scale>::kSize; 65 static const OperandSize kOperandSize = static_cast<OperandSize>(kSize); 66 }; 67 68 template <OperandType> 69 struct RegisterOperandTraits { 70 static const int kIsRegisterOperand = 0; 71 }; 72 73 #define DECLARE_REGISTER_OPERAND(Name, _) \ 74 template <> \ 75 struct RegisterOperandTraits<OperandType::k##Name> { \ 76 static const int kIsRegisterOperand = 1; \ 77 }; 78 REGISTER_OPERAND_TYPE_LIST(DECLARE_REGISTER_OPERAND) 79 #undef DECLARE_REGISTER_OPERAND 80 81 template <AccumulatorUse, OperandType...> 82 struct BytecodeTraits {}; 83 84 template <AccumulatorUse accumulator_use, OperandType operand_0, 85 OperandType operand_1, OperandType operand_2, OperandType operand_3> 86 struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2, 87 operand_3> { 88 static const OperandType* GetOperandTypes() { 89 static const OperandType operand_types[] = {operand_0, operand_1, operand_2, 90 operand_3, OperandType::kNone}; 91 return operand_types; 92 } 93 94 static const OperandTypeInfo* GetOperandTypeInfos() { 95 static const OperandTypeInfo operand_type_infos[] = { 96 OperandTraits<operand_0>::kOperandTypeInfo, 97 OperandTraits<operand_1>::kOperandTypeInfo, 98 OperandTraits<operand_2>::kOperandTypeInfo, 99 OperandTraits<operand_3>::kOperandTypeInfo, OperandTypeInfo::kNone}; 100 return operand_type_infos; 101 } 102 103 static const OperandSize* GetOperandSizes(OperandScale operand_scale) { 104 switch (operand_scale) { 105 #define CASE(Name, _) \ 106 case OperandScale::k##Name: { \ 107 static const OperandSize kOperandSizes[] = { \ 108 OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ 109 OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \ 110 OperandScaler<operand_2, OperandScale::k##Name>::kOperandSize, \ 111 OperandScaler<operand_3, OperandScale::k##Name>::kOperandSize, \ 112 }; \ 113 return kOperandSizes; \ 114 } 115 OPERAND_SCALE_LIST(CASE) 116 #undef CASE 117 } 118 UNREACHABLE(); 119 return nullptr; 120 } 121 122 template <OperandType ot> 123 static inline bool HasAnyOperandsOfType() { 124 return operand_0 == ot || operand_1 == ot || operand_2 == ot || 125 operand_3 == ot; 126 } 127 128 static inline bool IsScalable() { 129 return (OperandTraits<operand_0>::TypeInfoTraits::kIsScalable | 130 OperandTraits<operand_1>::TypeInfoTraits::kIsScalable | 131 OperandTraits<operand_2>::TypeInfoTraits::kIsScalable | 132 OperandTraits<operand_3>::TypeInfoTraits::kIsScalable); 133 } 134 135 static const AccumulatorUse kAccumulatorUse = accumulator_use; 136 static const int kOperandCount = 4; 137 static const int kRegisterOperandCount = 138 RegisterOperandTraits<operand_0>::kIsRegisterOperand + 139 RegisterOperandTraits<operand_1>::kIsRegisterOperand + 140 RegisterOperandTraits<operand_2>::kIsRegisterOperand + 141 RegisterOperandTraits<operand_3>::kIsRegisterOperand; 142 static const int kRegisterOperandBitmap = 143 RegisterOperandTraits<operand_0>::kIsRegisterOperand + 144 (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1) + 145 (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2) + 146 (RegisterOperandTraits<operand_3>::kIsRegisterOperand << 3); 147 }; 148 149 template <AccumulatorUse accumulator_use, OperandType operand_0, 150 OperandType operand_1, OperandType operand_2> 151 struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2> { 152 static const OperandType* GetOperandTypes() { 153 static const OperandType operand_types[] = {operand_0, operand_1, operand_2, 154 OperandType::kNone}; 155 return operand_types; 156 } 157 158 static const OperandTypeInfo* GetOperandTypeInfos() { 159 static const OperandTypeInfo operand_type_infos[] = { 160 OperandTraits<operand_0>::kOperandTypeInfo, 161 OperandTraits<operand_1>::kOperandTypeInfo, 162 OperandTraits<operand_2>::kOperandTypeInfo, OperandTypeInfo::kNone}; 163 return operand_type_infos; 164 } 165 166 static const OperandSize* GetOperandSizes(OperandScale operand_scale) { 167 switch (operand_scale) { 168 #define CASE(Name, _) \ 169 case OperandScale::k##Name: { \ 170 static const OperandSize kOperandSizes[] = { \ 171 OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ 172 OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \ 173 OperandScaler<operand_2, OperandScale::k##Name>::kOperandSize, \ 174 }; \ 175 return kOperandSizes; \ 176 } 177 OPERAND_SCALE_LIST(CASE) 178 #undef CASE 179 } 180 UNREACHABLE(); 181 return nullptr; 182 } 183 184 template <OperandType ot> 185 static inline bool HasAnyOperandsOfType() { 186 return operand_0 == ot || operand_1 == ot || operand_2 == ot; 187 } 188 189 static inline bool IsScalable() { 190 return (OperandTraits<operand_0>::TypeInfoTraits::kIsScalable | 191 OperandTraits<operand_1>::TypeInfoTraits::kIsScalable | 192 OperandTraits<operand_2>::TypeInfoTraits::kIsScalable); 193 } 194 195 static const AccumulatorUse kAccumulatorUse = accumulator_use; 196 static const int kOperandCount = 3; 197 static const int kRegisterOperandCount = 198 RegisterOperandTraits<operand_0>::kIsRegisterOperand + 199 RegisterOperandTraits<operand_1>::kIsRegisterOperand + 200 RegisterOperandTraits<operand_2>::kIsRegisterOperand; 201 static const int kRegisterOperandBitmap = 202 RegisterOperandTraits<operand_0>::kIsRegisterOperand + 203 (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1) + 204 (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2); 205 }; 206 207 template <AccumulatorUse accumulator_use, OperandType operand_0, 208 OperandType operand_1> 209 struct BytecodeTraits<accumulator_use, operand_0, operand_1> { 210 static const OperandType* GetOperandTypes() { 211 static const OperandType operand_types[] = {operand_0, operand_1, 212 OperandType::kNone}; 213 return operand_types; 214 } 215 216 static const OperandTypeInfo* GetOperandTypeInfos() { 217 static const OperandTypeInfo operand_type_infos[] = { 218 OperandTraits<operand_0>::kOperandTypeInfo, 219 OperandTraits<operand_1>::kOperandTypeInfo, OperandTypeInfo::kNone}; 220 return operand_type_infos; 221 } 222 223 static const OperandSize* GetOperandSizes(OperandScale operand_scale) { 224 switch (operand_scale) { 225 #define CASE(Name, _) \ 226 case OperandScale::k##Name: { \ 227 static const OperandSize kOperandSizes[] = { \ 228 OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ 229 OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \ 230 }; \ 231 return kOperandSizes; \ 232 } 233 OPERAND_SCALE_LIST(CASE) 234 #undef CASE 235 } 236 UNREACHABLE(); 237 return nullptr; 238 } 239 240 template <OperandType ot> 241 static inline bool HasAnyOperandsOfType() { 242 return operand_0 == ot || operand_1 == ot; 243 } 244 245 static inline bool IsScalable() { 246 return (OperandTraits<operand_0>::TypeInfoTraits::kIsScalable | 247 OperandTraits<operand_1>::TypeInfoTraits::kIsScalable); 248 } 249 250 static const AccumulatorUse kAccumulatorUse = accumulator_use; 251 static const int kOperandCount = 2; 252 static const int kRegisterOperandCount = 253 RegisterOperandTraits<operand_0>::kIsRegisterOperand + 254 RegisterOperandTraits<operand_1>::kIsRegisterOperand; 255 static const int kRegisterOperandBitmap = 256 RegisterOperandTraits<operand_0>::kIsRegisterOperand + 257 (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1); 258 }; 259 260 template <AccumulatorUse accumulator_use, OperandType operand_0> 261 struct BytecodeTraits<accumulator_use, operand_0> { 262 static const OperandType* GetOperandTypes() { 263 static const OperandType operand_types[] = {operand_0, OperandType::kNone}; 264 return operand_types; 265 } 266 267 static const OperandTypeInfo* GetOperandTypeInfos() { 268 static const OperandTypeInfo operand_type_infos[] = { 269 OperandTraits<operand_0>::kOperandTypeInfo, OperandTypeInfo::kNone}; 270 return operand_type_infos; 271 } 272 273 static const OperandSize* GetOperandSizes(OperandScale operand_scale) { 274 switch (operand_scale) { 275 #define CASE(Name, _) \ 276 case OperandScale::k##Name: { \ 277 static const OperandSize kOperandSizes[] = { \ 278 OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \ 279 }; \ 280 return kOperandSizes; \ 281 } 282 OPERAND_SCALE_LIST(CASE) 283 #undef CASE 284 } 285 UNREACHABLE(); 286 return nullptr; 287 } 288 289 template <OperandType ot> 290 static inline bool HasAnyOperandsOfType() { 291 return operand_0 == ot; 292 } 293 294 static inline bool IsScalable() { 295 return OperandTraits<operand_0>::TypeInfoTraits::kIsScalable; 296 } 297 298 static const AccumulatorUse kAccumulatorUse = accumulator_use; 299 static const int kOperandCount = 1; 300 static const int kRegisterOperandCount = 301 RegisterOperandTraits<operand_0>::kIsRegisterOperand; 302 static const int kRegisterOperandBitmap = 303 RegisterOperandTraits<operand_0>::kIsRegisterOperand; 304 }; 305 306 template <AccumulatorUse accumulator_use> 307 struct BytecodeTraits<accumulator_use> { 308 static const OperandType* GetOperandTypes() { 309 static const OperandType operand_types[] = {OperandType::kNone}; 310 return operand_types; 311 } 312 313 static const OperandTypeInfo* GetOperandTypeInfos() { 314 static const OperandTypeInfo operand_type_infos[] = { 315 OperandTypeInfo::kNone}; 316 return operand_type_infos; 317 } 318 319 static const OperandSize* GetOperandSizes(OperandScale operand_scale) { 320 return nullptr; 321 } 322 323 template <OperandType ot> 324 static inline bool HasAnyOperandsOfType() { 325 return false; 326 } 327 328 static inline bool IsScalable() { return false; } 329 330 static const AccumulatorUse kAccumulatorUse = accumulator_use; 331 static const int kOperandCount = 0; 332 static const int kRegisterOperandCount = 0; 333 static const int kRegisterOperandBitmap = 0; 334 }; 335 336 static OperandSize ScaledOperandSize(OperandType operand_type, 337 OperandScale operand_scale) { 338 STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 && 339 OperandScale::kLast == OperandScale::kQuadruple); 340 int index = static_cast<int>(operand_scale) >> 1; 341 switch (operand_type) { 342 #define CASE(Name, TypeInfo) \ 343 case OperandType::k##Name: { \ 344 static const OperandSize kOperandSizes[] = { \ 345 OperandScaler<OperandType::k##Name, \ 346 OperandScale::kSingle>::kOperandSize, \ 347 OperandScaler<OperandType::k##Name, \ 348 OperandScale::kDouble>::kOperandSize, \ 349 OperandScaler<OperandType::k##Name, \ 350 OperandScale::kQuadruple>::kOperandSize}; \ 351 return kOperandSizes[index]; \ 352 } 353 OPERAND_TYPE_LIST(CASE) 354 #undef CASE 355 } 356 UNREACHABLE(); 357 return OperandSize::kNone; 358 } 359 360 } // namespace interpreter 361 } // namespace internal 362 } // namespace v8 363 364 #endif // V8_INTERPRETER_BYTECODE_TRAITS_H_ 365