bytecode-operands.h 7.13 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_INTERPRETER_BYTECODE_OPERANDS_H_
#define V8_INTERPRETER_BYTECODE_OPERANDS_H_

8
#include "src/base/bounds.h"
9
#include "src/common/globals.h"
10 11 12 13 14 15 16

namespace v8 {
namespace internal {
namespace interpreter {

#define INVALID_OPERAND_TYPE_LIST(V) V(None, OperandTypeInfo::kNone)

17 18
#define REGISTER_INPUT_OPERAND_TYPE_LIST(V)        \
  V(Reg, OperandTypeInfo::kScalableSignedByte)     \
19
  V(RegList, OperandTypeInfo::kScalableSignedByte) \
20 21 22 23
  V(RegPair, OperandTypeInfo::kScalableSignedByte)

#define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V)          \
  V(RegOut, OperandTypeInfo::kScalableSignedByte)     \
24
  V(RegOutList, OperandTypeInfo::kScalableSignedByte) \
25 26 27
  V(RegOutPair, OperandTypeInfo::kScalableSignedByte) \
  V(RegOutTriple, OperandTypeInfo::kScalableSignedByte)

28 29 30 31
#define SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \
  V(Imm, OperandTypeInfo::kScalableSignedByte)

#define UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \
32 33
  V(Idx, OperandTypeInfo::kScalableUnsignedByte)      \
  V(UImm, OperandTypeInfo::kScalableUnsignedByte)     \
34 35 36 37 38
  V(RegCount, OperandTypeInfo::kScalableUnsignedByte)

#define UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V)    \
  V(Flag8, OperandTypeInfo::kFixedUnsignedByte)       \
  V(IntrinsicId, OperandTypeInfo::kFixedUnsignedByte) \
39
  V(RuntimeId, OperandTypeInfo::kFixedUnsignedShort)  \
40
  V(NativeContextIndex, OperandTypeInfo::kFixedUnsignedByte)
41

42 43 44 45 46 47
// Carefully ordered for operand type range checks below.
#define NON_REGISTER_OPERAND_TYPE_LIST(V)       \
  INVALID_OPERAND_TYPE_LIST(V)                  \
  UNSIGNED_FIXED_SCALAR_OPERAND_TYPE_LIST(V)    \
  UNSIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V) \
  SIGNED_SCALABLE_SCALAR_OPERAND_TYPE_LIST(V)
48

49
// Carefully ordered for operand type range checks below.
50 51 52 53 54
#define REGISTER_OPERAND_TYPE_LIST(V) \
  REGISTER_INPUT_OPERAND_TYPE_LIST(V) \
  REGISTER_OUTPUT_OPERAND_TYPE_LIST(V)

// The list of operand types used by bytecodes.
55
// Carefully ordered for operand type range checks below.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#define OPERAND_TYPE_LIST(V)        \
  NON_REGISTER_OPERAND_TYPE_LIST(V) \
  REGISTER_OPERAND_TYPE_LIST(V)

// Enumeration of scaling factors applicable to scalable operands. Code
// relies on being able to cast values to integer scaling values.
#define OPERAND_SCALE_LIST(V) \
  V(Single, 1)                \
  V(Double, 2)                \
  V(Quadruple, 4)

enum class OperandScale : uint8_t {
#define DECLARE_OPERAND_SCALE(Name, Scale) k##Name = Scale,
  OPERAND_SCALE_LIST(DECLARE_OPERAND_SCALE)
#undef DECLARE_OPERAND_SCALE
      kLast = kQuadruple
};

// Enumeration of the size classes of operand types used by
// bytecodes. Code relies on being able to cast values to integer
// types to get the size in bytes.
enum class OperandSize : uint8_t {
  kNone = 0,
  kByte = 1,
  kShort = 2,
  kQuad = 4,
  kLast = kQuad
};

// Primitive operand info used that summarize properties of operands.
// Columns are Name, IsScalable, IsUnsigned, UnscaledSize.
#define OPERAND_TYPE_INFO_LIST(V)                         \
  V(None, false, false, OperandSize::kNone)               \
  V(ScalableSignedByte, true, false, OperandSize::kByte)  \
  V(ScalableUnsignedByte, true, true, OperandSize::kByte) \
  V(FixedUnsignedByte, false, true, OperandSize::kByte)   \
  V(FixedUnsignedShort, false, true, OperandSize::kShort)

enum class OperandTypeInfo : uint8_t {
#define DECLARE_OPERAND_TYPE_INFO(Name, ...) k##Name,
  OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO)
#undef DECLARE_OPERAND_TYPE_INFO
};

// Enumeration of operand types used by bytecodes.
enum class OperandType : uint8_t {
#define DECLARE_OPERAND_TYPE(Name, _) k##Name,
  OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE)
#undef DECLARE_OPERAND_TYPE
#define COUNT_OPERAND_TYPES(x, _) +1
  // The COUNT_OPERAND macro will turn this into kLast = -1 +1 +1... which will
  // evaluate to the same value as the last operand.
  kLast = -1 OPERAND_TYPE_LIST(COUNT_OPERAND_TYPES)
#undef COUNT_OPERAND_TYPES
};

enum class AccumulatorUse : uint8_t {
  kNone = 0,
  kRead = 1 << 0,
  kWrite = 1 << 1,
  kReadWrite = kRead | kWrite
};

119 120 121 122
constexpr inline AccumulatorUse operator&(AccumulatorUse lhs,
                                          AccumulatorUse rhs) {
  return static_cast<AccumulatorUse>(static_cast<int>(lhs) &
                                     static_cast<int>(rhs));
123 124
}

125 126 127 128
constexpr inline AccumulatorUse operator|(AccumulatorUse lhs,
                                          AccumulatorUse rhs) {
  return static_cast<AccumulatorUse>(static_cast<int>(lhs) |
                                     static_cast<int>(rhs));
129 130
}

131 132
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const AccumulatorUse& use);
133 134
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const OperandScale& operand_scale);
135 136
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const OperandSize& operand_size);
137 138
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const OperandType& operand_type);
139

140
class BytecodeOperands : public AllStatic {
141
 public:
142
  // The total number of bytecode operand types used.
143 144
  static const int kOperandTypeCount = static_cast<int>(OperandType::kLast) + 1;

145 146 147 148 149 150
// The total number of bytecode operand scales used.
#define OPERAND_SCALE_COUNT(...) +1
  static const int kOperandScaleCount =
      0 OPERAND_SCALE_LIST(OPERAND_SCALE_COUNT);
#undef OPERAND_SCALE_COUNT

151
  static constexpr int OperandScaleAsIndex(OperandScale operand_scale) {
152
#if V8_HAS_CXX14_CONSTEXPR
153 154
#ifdef DEBUG
    int result = static_cast<int>(operand_scale) >> 1;
155 156
    switch (operand_scale) {
      case OperandScale::kSingle:
157 158
        DCHECK_EQ(0, result);
        break;
159
      case OperandScale::kDouble:
160 161
        DCHECK_EQ(1, result);
        break;
162
      case OperandScale::kQuadruple:
163 164
        DCHECK_EQ(2, result);
        break;
165 166 167
      default:
        UNREACHABLE();
    }
168 169 170
#endif
#endif
    return static_cast<int>(operand_scale) >> 1;
171 172
  }

173 174
  // Returns true if |accumulator_use| reads the accumulator.
  static constexpr bool ReadsAccumulator(AccumulatorUse accumulator_use) {
175
    return (accumulator_use & AccumulatorUse::kRead) == AccumulatorUse::kRead;
176 177 178 179
  }

  // Returns true if |accumulator_use| writes the accumulator.
  static constexpr bool WritesAccumulator(AccumulatorUse accumulator_use) {
180
    return (accumulator_use & AccumulatorUse::kWrite) == AccumulatorUse::kWrite;
181 182 183 184
  }

  // Returns true if |operand_type| is a scalable signed byte.
  static constexpr bool IsScalableSignedByte(OperandType operand_type) {
185 186
    return base::IsInRange(operand_type, OperandType::kImm,
                           OperandType::kRegOutTriple);
187 188 189 190
  }

  // Returns true if |operand_type| is a scalable unsigned byte.
  static constexpr bool IsScalableUnsignedByte(OperandType operand_type) {
191 192
    return base::IsInRange(operand_type, OperandType::kIdx,
                           OperandType::kRegCount);
193 194 195
  }
};

196 197 198 199 200
}  // namespace interpreter
}  // namespace internal
}  // namespace v8

#endif  // V8_INTERPRETER_BYTECODE_OPERANDS_H_