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/globals.h"
9 
10 namespace v8 {
11 namespace internal {
12 namespace interpreter {
13 
14 #define INVALID_OPERAND_TYPE_LIST(V) V(None, OperandTypeInfo::kNone)
15 
16 #define REGISTER_INPUT_OPERAND_TYPE_LIST(V)        \
17   V(Reg, OperandTypeInfo::kScalableSignedByte)     \
18   V(RegList, OperandTypeInfo::kScalableSignedByte) \
19   V(RegPair, OperandTypeInfo::kScalableSignedByte)
20 
21 #define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V)          \
22   V(RegOut, OperandTypeInfo::kScalableSignedByte)     \
23   V(RegOutPair, OperandTypeInfo::kScalableSignedByte) \
24   V(RegOutTriple, OperandTypeInfo::kScalableSignedByte)
25 
26 #define SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \
27   V(Imm, OperandTypeInfo::kScalableSignedByte)
28 
29 #define UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \
30   V(Idx, OperandTypeInfo::kScalableUnsignedByte)      \
31   V(UImm, OperandTypeInfo::kScalableUnsignedByte)     \
32   V(RegCount, OperandTypeInfo::kScalableUnsignedByte)
33 
34 #define UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V)    \
35   V(Flag8, OperandTypeInfo::kFixedUnsignedByte)       \
36   V(IntrinsicId, OperandTypeInfo::kFixedUnsignedByte) \
37   V(RuntimeId, OperandTypeInfo::kFixedUnsignedShort)
38 
39 // Carefully ordered for operand type range checks below.
40 #define NON_REGISTER_OPERAND_TYPE_LIST(V)       \
41   INVALID_OPERAND_TYPE_LIST(V)                  \
42   UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V)    \
43   UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \
44   SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V)
45 
46 // Carefully ordered for operand type range checks below.
47 #define REGISTER_OPERAND_TYPE_LIST(V) \
48   REGISTER_INPUT_OPERAND_TYPE_LIST(V) \
49   REGISTER_OUTPUT_OPERAND_TYPE_LIST(V)
50 
51 // The list of operand types used by bytecodes.
52 // Carefully ordered for operand type range checks below.
53 #define OPERAND_TYPE_LIST(V)        \
54   NON_REGISTER_OPERAND_TYPE_LIST(V) \
55   REGISTER_OPERAND_TYPE_LIST(V)
56 
57 // Enumeration of scaling factors applicable to scalable operands. Code
58 // relies on being able to cast values to integer scaling values.
59 #define OPERAND_SCALE_LIST(V) \
60   V(Single, 1)                \
61   V(Double, 2)                \
62   V(Quadruple, 4)
63 
64 enum class OperandScale : uint8_t {
65 #define DECLARE_OPERAND_SCALE(Name, Scale) k##Name = Scale,
66   OPERAND_SCALE_LIST(DECLARE_OPERAND_SCALE)
67 #undef DECLARE_OPERAND_SCALE
68       kLast = kQuadruple
69 };
70 
71 // Enumeration of the size classes of operand types used by
72 // bytecodes. Code relies on being able to cast values to integer
73 // types to get the size in bytes.
74 enum class OperandSize : uint8_t {
75   kNone = 0,
76   kByte = 1,
77   kShort = 2,
78   kQuad = 4,
79   kLast = kQuad
80 };
81 
82 // Primitive operand info used that summarize properties of operands.
83 // Columns are Name, IsScalable, IsUnsigned, UnscaledSize.
84 #define OPERAND_TYPE_INFO_LIST(V)                         \
85   V(None, false, false, OperandSize::kNone)               \
86   V(ScalableSignedByte, true, false, OperandSize::kByte)  \
87   V(ScalableUnsignedByte, true, true, OperandSize::kByte) \
88   V(FixedUnsignedByte, false, true, OperandSize::kByte)   \
89   V(FixedUnsignedShort, false, true, OperandSize::kShort)
90 
91 enum class OperandTypeInfo : uint8_t {
92 #define DECLARE_OPERAND_TYPE_INFO(Name, ...) k##Name,
93   OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO)
94 #undef DECLARE_OPERAND_TYPE_INFO
95 };
96 
97 // Enumeration of operand types used by bytecodes.
98 enum class OperandType : uint8_t {
99 #define DECLARE_OPERAND_TYPE(Name, _) k##Name,
100   OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE)
101 #undef DECLARE_OPERAND_TYPE
102 #define COUNT_OPERAND_TYPES(x, _) +1
103   // The COUNT_OPERAND macro will turn this into kLast = -1 +1 +1... which will
104   // evaluate to the same value as the last operand.
105   kLast = -1 OPERAND_TYPE_LIST(COUNT_OPERAND_TYPES)
106 #undef COUNT_OPERAND_TYPES
107 };
108 
109 enum class AccumulatorUse : uint8_t {
110   kNone = 0,
111   kRead = 1 << 0,
112   kWrite = 1 << 1,
113   kReadWrite = kRead | kWrite
114 };
115 
116 inline AccumulatorUse operator&(AccumulatorUse lhs, AccumulatorUse rhs) {
117   int result = static_cast<int>(lhs) & static_cast<int>(rhs);
118   return static_cast<AccumulatorUse>(result);
119 }
120 
121 inline AccumulatorUse operator|(AccumulatorUse lhs, AccumulatorUse rhs) {
122   int result = static_cast<int>(lhs) | static_cast<int>(rhs);
123   return static_cast<AccumulatorUse>(result);
124 }
125 
126 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
127                                            const AccumulatorUse& use);
128 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
129                                            const OperandScale& operand_scale);
130 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
131                                            const OperandSize& operand_size);
132 std::ostream& operator<<(std::ostream& os, const OperandType& operand_type);
133 
134 class BytecodeOperands {
135  public:
136   // Returns true if |accumulator_use| reads the accumulator.
ReadsAccumulator(AccumulatorUse accumulator_use)137   static constexpr bool ReadsAccumulator(AccumulatorUse accumulator_use) {
138     return accumulator_use == AccumulatorUse::kRead ||
139            accumulator_use == AccumulatorUse::kReadWrite;
140   }
141 
142   // Returns true if |accumulator_use| writes the accumulator.
WritesAccumulator(AccumulatorUse accumulator_use)143   static constexpr bool WritesAccumulator(AccumulatorUse accumulator_use) {
144     return accumulator_use == AccumulatorUse::kWrite ||
145            accumulator_use == AccumulatorUse::kReadWrite;
146   }
147 
148   // Returns true if |operand_type| is a scalable signed byte.
IsScalableSignedByte(OperandType operand_type)149   static constexpr bool IsScalableSignedByte(OperandType operand_type) {
150     return operand_type >= OperandType::kImm &&
151            operand_type <= OperandType::kRegOutTriple;
152   }
153 
154   // Returns true if |operand_type| is a scalable unsigned byte.
IsScalableUnsignedByte(OperandType operand_type)155   static constexpr bool IsScalableUnsignedByte(OperandType operand_type) {
156     return operand_type >= OperandType::kIdx &&
157            operand_type <= OperandType::kRegCount;
158   }
159 };
160 
161 }  // namespace interpreter
162 }  // namespace internal
163 }  // namespace v8
164 
165 #endif  // V8_INTERPRETER_BYTECODE_OPERANDS_H_
166