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