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
11namespace v8 {
12namespace internal {
13namespace 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
67enum 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.
77enum 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
94enum 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.
101enum 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
112enum 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
121constexpr inline ImplicitRegisterUse operator&(ImplicitRegisterUse lhs,
122                                               ImplicitRegisterUse rhs) {
123  return static_cast<ImplicitRegisterUse>(static_cast<int>(lhs) &
124                                          static_cast<int>(rhs));
125}
126
127constexpr inline ImplicitRegisterUse operator|(ImplicitRegisterUse lhs,
128                                               ImplicitRegisterUse rhs) {
129  return static_cast<ImplicitRegisterUse>(static_cast<int>(lhs) |
130                                          static_cast<int>(rhs));
131}
132
133V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
134                                           const ImplicitRegisterUse& use);
135V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
136                                           const OperandScale& operand_scale);
137V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
138                                           const OperandSize& operand_size);
139V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
140                                           const OperandType& operand_type);
141
142class 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
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.
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.
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.
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.
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.
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