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