• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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