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