11cb0ef41Sopenharmony_ci// Copyright 2017 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_WASM_BASELINE_LIFTOFF_REGISTER_H_
61cb0ef41Sopenharmony_ci#define V8_WASM_BASELINE_LIFTOFF_REGISTER_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <iosfwd>
91cb0ef41Sopenharmony_ci#include <memory>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "src/base/bits.h"
121cb0ef41Sopenharmony_ci#include "src/wasm/baseline/liftoff-assembler-defs.h"
131cb0ef41Sopenharmony_ci#include "src/wasm/wasm-opcodes.h"
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cinamespace v8 {
161cb0ef41Sopenharmony_cinamespace internal {
171cb0ef41Sopenharmony_cinamespace wasm {
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cistatic constexpr bool kNeedI64RegPair = kSystemPointerSize == 4;
201cb0ef41Sopenharmony_cistatic constexpr bool kNeedS128RegPair = kFPAliasing == AliasingKind::kCombine;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_cienum RegClass : uint8_t {
231cb0ef41Sopenharmony_ci  kGpReg,
241cb0ef41Sopenharmony_ci  kFpReg,
251cb0ef41Sopenharmony_ci  kGpRegPair = kFpReg + 1 + (kNeedS128RegPair && !kNeedI64RegPair),
261cb0ef41Sopenharmony_ci  kFpRegPair = kFpReg + 1 + kNeedI64RegPair,
271cb0ef41Sopenharmony_ci  kNoReg = kFpRegPair + kNeedS128RegPair,
281cb0ef41Sopenharmony_ci  // +------------------+-------------------------------+
291cb0ef41Sopenharmony_ci  // |                  |        kNeedI64RegPair        |
301cb0ef41Sopenharmony_ci  // +------------------+---------------+---------------+
311cb0ef41Sopenharmony_ci  // | kNeedS128RegPair |     true      |    false      |
321cb0ef41Sopenharmony_ci  // +------------------+---------------+---------------+
331cb0ef41Sopenharmony_ci  // |             true | 0,1,2,3,4 (a) | 0,1,3,2,3     |
341cb0ef41Sopenharmony_ci  // |            false | 0,1,2,3,3 (b) | 0,1,2,2,2 (c) |
351cb0ef41Sopenharmony_ci  // +------------------+---------------+---------------+
361cb0ef41Sopenharmony_ci  // (a) arm
371cb0ef41Sopenharmony_ci  // (b) ia32
381cb0ef41Sopenharmony_ci  // (c) x64, arm64
391cb0ef41Sopenharmony_ci};
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cistatic_assert(kNeedI64RegPair == (kGpRegPair != kNoReg),
421cb0ef41Sopenharmony_ci              "kGpRegPair equals kNoReg if unused");
431cb0ef41Sopenharmony_cistatic_assert(kNeedS128RegPair == (kFpRegPair != kNoReg),
441cb0ef41Sopenharmony_ci              "kFpRegPair equals kNoReg if unused");
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_cienum RegPairHalf : uint8_t { kLowWord = 0, kHighWord = 1 };
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cistatic inline constexpr bool needs_gp_reg_pair(ValueKind kind) {
491cb0ef41Sopenharmony_ci  return kNeedI64RegPair && kind == kI64;
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_cistatic inline constexpr bool needs_fp_reg_pair(ValueKind kind) {
531cb0ef41Sopenharmony_ci  return kNeedS128RegPair && kind == kS128;
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cistatic inline constexpr RegClass reg_class_for(ValueKind kind) {
571cb0ef41Sopenharmony_ci  switch (kind) {
581cb0ef41Sopenharmony_ci    case kF32:
591cb0ef41Sopenharmony_ci    case kF64:
601cb0ef41Sopenharmony_ci      return kFpReg;
611cb0ef41Sopenharmony_ci    case kI8:
621cb0ef41Sopenharmony_ci    case kI16:
631cb0ef41Sopenharmony_ci    case kI32:
641cb0ef41Sopenharmony_ci      return kGpReg;
651cb0ef41Sopenharmony_ci    case kI64:
661cb0ef41Sopenharmony_ci      return kNeedI64RegPair ? kGpRegPair : kGpReg;
671cb0ef41Sopenharmony_ci    case kS128:
681cb0ef41Sopenharmony_ci      return kNeedS128RegPair ? kFpRegPair : kFpReg;
691cb0ef41Sopenharmony_ci    case kRef:
701cb0ef41Sopenharmony_ci    case kOptRef:
711cb0ef41Sopenharmony_ci    case kRtt:
721cb0ef41Sopenharmony_ci      return kGpReg;
731cb0ef41Sopenharmony_ci    default:
741cb0ef41Sopenharmony_ci      return kNoReg;  // unsupported kind
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci}
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci// Description of LiftoffRegister code encoding.
791cb0ef41Sopenharmony_ci// This example uses the ARM architecture, which as of writing has:
801cb0ef41Sopenharmony_ci// - 9 GP registers, requiring 4 bits
811cb0ef41Sopenharmony_ci// - 13 FP regitsters, requiring 5 bits
821cb0ef41Sopenharmony_ci// - kNeedI64RegPair is true
831cb0ef41Sopenharmony_ci// - kNeedS128RegPair is true
841cb0ef41Sopenharmony_ci// - thus, kBitsPerRegPair is 2 + 2 * 4 = 10
851cb0ef41Sopenharmony_ci// - storage_t is uint16_t
861cb0ef41Sopenharmony_ci// The table below illustrates how each RegClass is encoded, with brackets
871cb0ef41Sopenharmony_ci// surrounding the bits which encode the register number.
881cb0ef41Sopenharmony_ci//
891cb0ef41Sopenharmony_ci// +----------------+------------------+
901cb0ef41Sopenharmony_ci// | RegClass       | Example          |
911cb0ef41Sopenharmony_ci// +----------------+------------------+
921cb0ef41Sopenharmony_ci// | kGpReg (1)     | [00 0000   0000] |
931cb0ef41Sopenharmony_ci// | kFpReg (2)     | [00 0000   1001] |
941cb0ef41Sopenharmony_ci// | kGpRegPair (3) | 01 [0000] [0001] |
951cb0ef41Sopenharmony_ci// | kFpRegPair (4) | 10  000[0  0010] |
961cb0ef41Sopenharmony_ci// +----------------+------------------+
971cb0ef41Sopenharmony_ci//
981cb0ef41Sopenharmony_ci// gp and fp registers are encoded in the same index space, which means that
991cb0ef41Sopenharmony_ci// code has to check for kGpRegPair and kFpRegPair before it can treat the code
1001cb0ef41Sopenharmony_ci// as a register code.
1011cb0ef41Sopenharmony_ci// (1) [0 .. kMaxGpRegCode] encodes gp registers
1021cb0ef41Sopenharmony_ci// (2) [kMaxGpRegCode + 1 .. kMaxGpRegCode + kMaxFpRegCode] encodes fp
1031cb0ef41Sopenharmony_ci// registers, so in this example, 1001 is really fp register 0.
1041cb0ef41Sopenharmony_ci// (3) The second top bit is set for kGpRegPair, and the two gp registers are
1051cb0ef41Sopenharmony_ci// stuffed side by side in code. Note that this is not the second top bit of
1061cb0ef41Sopenharmony_ci// storage_t, since storage_t is larger than the number of meaningful bits we
1071cb0ef41Sopenharmony_ci// need for the encoding.
1081cb0ef41Sopenharmony_ci// (4) The top bit is set for kFpRegPair, and the fp register is stuffed into
1091cb0ef41Sopenharmony_ci// the bottom part of the code. Unlike (2), this is the fp register code itself
1101cb0ef41Sopenharmony_ci// (not sharing index space with gp), so in this example, it is fp register 2.
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci// Maximum code of a gp cache register.
1131cb0ef41Sopenharmony_cistatic constexpr int kMaxGpRegCode = kLiftoffAssemblerGpCacheRegs.last().code();
1141cb0ef41Sopenharmony_ci// Maximum code of an fp cache register.
1151cb0ef41Sopenharmony_cistatic constexpr int kMaxFpRegCode = kLiftoffAssemblerFpCacheRegs.last().code();
1161cb0ef41Sopenharmony_cistatic constexpr int kAfterMaxLiftoffGpRegCode = kMaxGpRegCode + 1;
1171cb0ef41Sopenharmony_cistatic constexpr int kAfterMaxLiftoffFpRegCode =
1181cb0ef41Sopenharmony_ci    kAfterMaxLiftoffGpRegCode + kMaxFpRegCode + 1;
1191cb0ef41Sopenharmony_cistatic constexpr int kAfterMaxLiftoffRegCode = kAfterMaxLiftoffFpRegCode;
1201cb0ef41Sopenharmony_cistatic constexpr int kBitsPerLiftoffRegCode =
1211cb0ef41Sopenharmony_ci    32 - base::bits::CountLeadingZeros<uint32_t>(kAfterMaxLiftoffRegCode - 1);
1221cb0ef41Sopenharmony_cistatic constexpr int kBitsPerGpRegCode =
1231cb0ef41Sopenharmony_ci    32 - base::bits::CountLeadingZeros<uint32_t>(kMaxGpRegCode);
1241cb0ef41Sopenharmony_cistatic constexpr int kBitsPerFpRegCode =
1251cb0ef41Sopenharmony_ci    32 - base::bits::CountLeadingZeros<uint32_t>(kMaxFpRegCode);
1261cb0ef41Sopenharmony_ci// GpRegPair requires 1 extra bit, S128RegPair also needs an extra bit.
1271cb0ef41Sopenharmony_cistatic constexpr int kBitsPerRegPair =
1281cb0ef41Sopenharmony_ci    (kNeedS128RegPair ? 2 : 1) + 2 * kBitsPerGpRegCode;
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_cistatic_assert(2 * kBitsPerGpRegCode >= kBitsPerFpRegCode,
1311cb0ef41Sopenharmony_ci              "encoding for gp pair and fp pair collides");
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ciclass LiftoffRegister {
1341cb0ef41Sopenharmony_ci  static constexpr int needed_bits =
1351cb0ef41Sopenharmony_ci      std::max(kNeedI64RegPair || kNeedS128RegPair ? kBitsPerRegPair : 0,
1361cb0ef41Sopenharmony_ci               kBitsPerLiftoffRegCode);
1371cb0ef41Sopenharmony_ci  using storage_t = std::conditional<
1381cb0ef41Sopenharmony_ci      needed_bits <= 8, uint8_t,
1391cb0ef41Sopenharmony_ci      std::conditional<needed_bits <= 16, uint16_t, uint32_t>::type>::type;
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  static_assert(8 * sizeof(storage_t) >= needed_bits,
1421cb0ef41Sopenharmony_ci                "chosen type is big enough");
1431cb0ef41Sopenharmony_ci  // Check for smallest required data type being chosen.
1441cb0ef41Sopenharmony_ci  // Special case for uint8_t as there are no smaller types.
1451cb0ef41Sopenharmony_ci  static_assert((8 * sizeof(storage_t) < 2 * needed_bits) ||
1461cb0ef41Sopenharmony_ci                    (sizeof(storage_t) == sizeof(uint8_t)),
1471cb0ef41Sopenharmony_ci                "chosen type is small enough");
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci public:
1501cb0ef41Sopenharmony_ci  constexpr explicit LiftoffRegister(Register reg)
1511cb0ef41Sopenharmony_ci      : LiftoffRegister(reg.code()) {
1521cb0ef41Sopenharmony_ci    DCHECK(kLiftoffAssemblerGpCacheRegs.has(reg));
1531cb0ef41Sopenharmony_ci    DCHECK_EQ(reg, gp());
1541cb0ef41Sopenharmony_ci  }
1551cb0ef41Sopenharmony_ci  constexpr explicit LiftoffRegister(DoubleRegister reg)
1561cb0ef41Sopenharmony_ci      : LiftoffRegister(kAfterMaxLiftoffGpRegCode + reg.code()) {
1571cb0ef41Sopenharmony_ci    DCHECK(kLiftoffAssemblerFpCacheRegs.has(reg));
1581cb0ef41Sopenharmony_ci    DCHECK_EQ(reg, fp());
1591cb0ef41Sopenharmony_ci  }
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  static LiftoffRegister from_liftoff_code(int code) {
1621cb0ef41Sopenharmony_ci    LiftoffRegister reg{static_cast<storage_t>(code)};
1631cb0ef41Sopenharmony_ci    // Check that the code is correct by round-tripping through the
1641cb0ef41Sopenharmony_ci    // reg-class-specific constructor.
1651cb0ef41Sopenharmony_ci    DCHECK(
1661cb0ef41Sopenharmony_ci        (reg.is_gp() && code == LiftoffRegister{reg.gp()}.liftoff_code()) ||
1671cb0ef41Sopenharmony_ci        (reg.is_fp() && code == LiftoffRegister{reg.fp()}.liftoff_code()) ||
1681cb0ef41Sopenharmony_ci        (reg.is_gp_pair() &&
1691cb0ef41Sopenharmony_ci         code == ForPair(reg.low_gp(), reg.high_gp()).liftoff_code()) ||
1701cb0ef41Sopenharmony_ci        (reg.is_fp_pair() && code == ForFpPair(reg.low_fp()).liftoff_code()));
1711cb0ef41Sopenharmony_ci    return reg;
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  static LiftoffRegister from_code(RegClass rc, int code) {
1751cb0ef41Sopenharmony_ci    switch (rc) {
1761cb0ef41Sopenharmony_ci      case kGpReg:
1771cb0ef41Sopenharmony_ci        return LiftoffRegister(Register::from_code(code));
1781cb0ef41Sopenharmony_ci      case kFpReg:
1791cb0ef41Sopenharmony_ci        return LiftoffRegister(DoubleRegister::from_code(code));
1801cb0ef41Sopenharmony_ci      default:
1811cb0ef41Sopenharmony_ci        UNREACHABLE();
1821cb0ef41Sopenharmony_ci    }
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  // Shifts the register code depending on the type before converting to a
1861cb0ef41Sopenharmony_ci  // LiftoffRegister.
1871cb0ef41Sopenharmony_ci  static LiftoffRegister from_external_code(RegClass rc, ValueKind kind,
1881cb0ef41Sopenharmony_ci                                            int code) {
1891cb0ef41Sopenharmony_ci    if (kFPAliasing == AliasingKind::kCombine && kind == kF32) {
1901cb0ef41Sopenharmony_ci      // Liftoff assumes a one-to-one mapping between float registers and
1911cb0ef41Sopenharmony_ci      // double registers, and so does not distinguish between f32 and f64
1921cb0ef41Sopenharmony_ci      // registers. The f32 register code must therefore be halved in order
1931cb0ef41Sopenharmony_ci      // to pass the f64 code to Liftoff.
1941cb0ef41Sopenharmony_ci      DCHECK_EQ(0, code % 2);
1951cb0ef41Sopenharmony_ci      return LiftoffRegister::from_code(rc, code >> 1);
1961cb0ef41Sopenharmony_ci    }
1971cb0ef41Sopenharmony_ci    if (kNeedS128RegPair && kind == kS128) {
1981cb0ef41Sopenharmony_ci      // Similarly for double registers and SIMD registers, the SIMD code
1991cb0ef41Sopenharmony_ci      // needs to be doubled to pass the f64 code to Liftoff.
2001cb0ef41Sopenharmony_ci      return LiftoffRegister::ForFpPair(DoubleRegister::from_code(code << 1));
2011cb0ef41Sopenharmony_ci    }
2021cb0ef41Sopenharmony_ci    return LiftoffRegister::from_code(rc, code);
2031cb0ef41Sopenharmony_ci  }
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci  static LiftoffRegister ForPair(Register low, Register high) {
2061cb0ef41Sopenharmony_ci    DCHECK(kNeedI64RegPair);
2071cb0ef41Sopenharmony_ci    DCHECK_NE(low, high);
2081cb0ef41Sopenharmony_ci    storage_t combined_code = low.code() | high.code() << kBitsPerGpRegCode |
2091cb0ef41Sopenharmony_ci                              1 << (2 * kBitsPerGpRegCode);
2101cb0ef41Sopenharmony_ci    return LiftoffRegister(combined_code);
2111cb0ef41Sopenharmony_ci  }
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  static LiftoffRegister ForFpPair(DoubleRegister low) {
2141cb0ef41Sopenharmony_ci    DCHECK(kNeedS128RegPair);
2151cb0ef41Sopenharmony_ci    DCHECK_EQ(0, low.code() % 2);
2161cb0ef41Sopenharmony_ci    storage_t combined_code = low.code() | 2 << (2 * kBitsPerGpRegCode);
2171cb0ef41Sopenharmony_ci    return LiftoffRegister(combined_code);
2181cb0ef41Sopenharmony_ci  }
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci  constexpr bool is_pair() const {
2211cb0ef41Sopenharmony_ci    return (kNeedI64RegPair || kNeedS128RegPair) &&
2221cb0ef41Sopenharmony_ci           (code_ & (3 << (2 * kBitsPerGpRegCode)));
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  constexpr bool is_gp_pair() const {
2261cb0ef41Sopenharmony_ci    return kNeedI64RegPair && (code_ & (1 << (2 * kBitsPerGpRegCode))) != 0;
2271cb0ef41Sopenharmony_ci  }
2281cb0ef41Sopenharmony_ci  constexpr bool is_fp_pair() const {
2291cb0ef41Sopenharmony_ci    return kNeedS128RegPair && (code_ & (2 << (2 * kBitsPerGpRegCode))) != 0;
2301cb0ef41Sopenharmony_ci  }
2311cb0ef41Sopenharmony_ci  constexpr bool is_gp() const { return code_ < kAfterMaxLiftoffGpRegCode; }
2321cb0ef41Sopenharmony_ci  constexpr bool is_fp() const {
2331cb0ef41Sopenharmony_ci    return code_ >= kAfterMaxLiftoffGpRegCode &&
2341cb0ef41Sopenharmony_ci           code_ < kAfterMaxLiftoffFpRegCode;
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  LiftoffRegister low() const {
2381cb0ef41Sopenharmony_ci    // Common case for most archs where only gp pair supported.
2391cb0ef41Sopenharmony_ci    if (!kNeedS128RegPair) return LiftoffRegister(low_gp());
2401cb0ef41Sopenharmony_ci    return is_gp_pair() ? LiftoffRegister(low_gp()) : LiftoffRegister(low_fp());
2411cb0ef41Sopenharmony_ci  }
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci  LiftoffRegister high() const {
2441cb0ef41Sopenharmony_ci    // Common case for most archs where only gp pair supported.
2451cb0ef41Sopenharmony_ci    if (!kNeedS128RegPair) return LiftoffRegister(high_gp());
2461cb0ef41Sopenharmony_ci    return is_gp_pair() ? LiftoffRegister(high_gp())
2471cb0ef41Sopenharmony_ci                        : LiftoffRegister(high_fp());
2481cb0ef41Sopenharmony_ci  }
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  Register low_gp() const {
2511cb0ef41Sopenharmony_ci    DCHECK(is_gp_pair());
2521cb0ef41Sopenharmony_ci    static constexpr storage_t kCodeMask = (1 << kBitsPerGpRegCode) - 1;
2531cb0ef41Sopenharmony_ci    return Register::from_code(code_ & kCodeMask);
2541cb0ef41Sopenharmony_ci  }
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci  Register high_gp() const {
2571cb0ef41Sopenharmony_ci    DCHECK(is_gp_pair());
2581cb0ef41Sopenharmony_ci    static constexpr storage_t kCodeMask = (1 << kBitsPerGpRegCode) - 1;
2591cb0ef41Sopenharmony_ci    return Register::from_code((code_ >> kBitsPerGpRegCode) & kCodeMask);
2601cb0ef41Sopenharmony_ci  }
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci  DoubleRegister low_fp() const {
2631cb0ef41Sopenharmony_ci    DCHECK(is_fp_pair());
2641cb0ef41Sopenharmony_ci    static constexpr storage_t kCodeMask = (1 << kBitsPerFpRegCode) - 1;
2651cb0ef41Sopenharmony_ci    return DoubleRegister::from_code(code_ & kCodeMask);
2661cb0ef41Sopenharmony_ci  }
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci  DoubleRegister high_fp() const {
2691cb0ef41Sopenharmony_ci    DCHECK(is_fp_pair());
2701cb0ef41Sopenharmony_ci    static constexpr storage_t kCodeMask = (1 << kBitsPerFpRegCode) - 1;
2711cb0ef41Sopenharmony_ci    return DoubleRegister::from_code((code_ & kCodeMask) + 1);
2721cb0ef41Sopenharmony_ci  }
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci  constexpr Register gp() const {
2751cb0ef41Sopenharmony_ci    DCHECK(is_gp());
2761cb0ef41Sopenharmony_ci    return Register::from_code(code_);
2771cb0ef41Sopenharmony_ci  }
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci  constexpr DoubleRegister fp() const {
2801cb0ef41Sopenharmony_ci    DCHECK(is_fp());
2811cb0ef41Sopenharmony_ci    return DoubleRegister::from_code(code_ - kAfterMaxLiftoffGpRegCode);
2821cb0ef41Sopenharmony_ci  }
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  constexpr int liftoff_code() const {
2851cb0ef41Sopenharmony_ci    STATIC_ASSERT(sizeof(int) >= sizeof(storage_t));
2861cb0ef41Sopenharmony_ci    return static_cast<int>(code_);
2871cb0ef41Sopenharmony_ci  }
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  constexpr RegClass reg_class() const {
2901cb0ef41Sopenharmony_ci    return is_fp_pair() ? kFpRegPair
2911cb0ef41Sopenharmony_ci                        : is_gp_pair() ? kGpRegPair : is_gp() ? kGpReg : kFpReg;
2921cb0ef41Sopenharmony_ci  }
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci  bool operator==(const LiftoffRegister other) const {
2951cb0ef41Sopenharmony_ci    DCHECK_EQ(is_gp_pair(), other.is_gp_pair());
2961cb0ef41Sopenharmony_ci    DCHECK_EQ(is_fp_pair(), other.is_fp_pair());
2971cb0ef41Sopenharmony_ci    return code_ == other.code_;
2981cb0ef41Sopenharmony_ci  }
2991cb0ef41Sopenharmony_ci  bool operator!=(const LiftoffRegister other) const {
3001cb0ef41Sopenharmony_ci    DCHECK_EQ(is_gp_pair(), other.is_gp_pair());
3011cb0ef41Sopenharmony_ci    DCHECK_EQ(is_fp_pair(), other.is_fp_pair());
3021cb0ef41Sopenharmony_ci    return code_ != other.code_;
3031cb0ef41Sopenharmony_ci  }
3041cb0ef41Sopenharmony_ci  bool overlaps(const LiftoffRegister other) const {
3051cb0ef41Sopenharmony_ci    if (is_pair()) return low().overlaps(other) || high().overlaps(other);
3061cb0ef41Sopenharmony_ci    if (other.is_pair()) return *this == other.low() || *this == other.high();
3071cb0ef41Sopenharmony_ci    return *this == other;
3081cb0ef41Sopenharmony_ci  }
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci private:
3111cb0ef41Sopenharmony_ci  explicit constexpr LiftoffRegister(storage_t code) : code_(code) {}
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci  storage_t code_;
3141cb0ef41Sopenharmony_ci};
3151cb0ef41Sopenharmony_ciASSERT_TRIVIALLY_COPYABLE(LiftoffRegister);
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ciinline std::ostream& operator<<(std::ostream& os, LiftoffRegister reg) {
3181cb0ef41Sopenharmony_ci  if (reg.is_gp_pair()) {
3191cb0ef41Sopenharmony_ci    return os << "<" << reg.low_gp() << "+" << reg.high_gp() << ">";
3201cb0ef41Sopenharmony_ci  } else if (reg.is_fp_pair()) {
3211cb0ef41Sopenharmony_ci    return os << "<" << reg.low_fp() << "+" << reg.high_fp() << ">";
3221cb0ef41Sopenharmony_ci  } else if (reg.is_gp()) {
3231cb0ef41Sopenharmony_ci    return os << reg.gp();
3241cb0ef41Sopenharmony_ci  } else {
3251cb0ef41Sopenharmony_ci    return os << reg.fp();
3261cb0ef41Sopenharmony_ci  }
3271cb0ef41Sopenharmony_ci}
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ciclass LiftoffRegList {
3301cb0ef41Sopenharmony_ci public:
3311cb0ef41Sopenharmony_ci  class Iterator;
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci  static constexpr bool use_u16 = kAfterMaxLiftoffRegCode <= 16;
3341cb0ef41Sopenharmony_ci  static constexpr bool use_u32 = !use_u16 && kAfterMaxLiftoffRegCode <= 32;
3351cb0ef41Sopenharmony_ci  using storage_t = std::conditional<
3361cb0ef41Sopenharmony_ci      use_u16, uint16_t,
3371cb0ef41Sopenharmony_ci      std::conditional<use_u32, uint32_t, uint64_t>::type>::type;
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci  static constexpr storage_t kGpMask =
3401cb0ef41Sopenharmony_ci      storage_t{kLiftoffAssemblerGpCacheRegs.bits()};
3411cb0ef41Sopenharmony_ci  static constexpr storage_t kFpMask =
3421cb0ef41Sopenharmony_ci      storage_t{kLiftoffAssemblerFpCacheRegs.bits()}
3431cb0ef41Sopenharmony_ci      << kAfterMaxLiftoffGpRegCode;
3441cb0ef41Sopenharmony_ci  // Sets all even numbered fp registers.
3451cb0ef41Sopenharmony_ci  static constexpr uint64_t kEvenFpSetMask = uint64_t{0x5555555555555555}
3461cb0ef41Sopenharmony_ci                                             << kAfterMaxLiftoffGpRegCode;
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  constexpr LiftoffRegList() = default;
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci  // Allow to construct LiftoffRegList from a number of
3511cb0ef41Sopenharmony_ci  // {Register|DoubleRegister|LiftoffRegister}.
3521cb0ef41Sopenharmony_ci  template <
3531cb0ef41Sopenharmony_ci      typename... Regs,
3541cb0ef41Sopenharmony_ci      typename = std::enable_if_t<std::conjunction_v<std::disjunction<
3551cb0ef41Sopenharmony_ci          std::is_same<Register, Regs>, std::is_same<DoubleRegister, Regs>,
3561cb0ef41Sopenharmony_ci          std::is_same<LiftoffRegister, Regs>>...>>>
3571cb0ef41Sopenharmony_ci  constexpr LiftoffRegList(Regs... regs) {
3581cb0ef41Sopenharmony_ci    (..., set(regs));
3591cb0ef41Sopenharmony_ci  }
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  constexpr Register set(Register reg) {
3621cb0ef41Sopenharmony_ci    return set(LiftoffRegister(reg)).gp();
3631cb0ef41Sopenharmony_ci  }
3641cb0ef41Sopenharmony_ci  constexpr DoubleRegister set(DoubleRegister reg) {
3651cb0ef41Sopenharmony_ci    return set(LiftoffRegister(reg)).fp();
3661cb0ef41Sopenharmony_ci  }
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  constexpr LiftoffRegister set(LiftoffRegister reg) {
3691cb0ef41Sopenharmony_ci    if (reg.is_pair()) {
3701cb0ef41Sopenharmony_ci      regs_ |= storage_t{1} << reg.low().liftoff_code();
3711cb0ef41Sopenharmony_ci      regs_ |= storage_t{1} << reg.high().liftoff_code();
3721cb0ef41Sopenharmony_ci    } else {
3731cb0ef41Sopenharmony_ci      regs_ |= storage_t{1} << reg.liftoff_code();
3741cb0ef41Sopenharmony_ci    }
3751cb0ef41Sopenharmony_ci    return reg;
3761cb0ef41Sopenharmony_ci  }
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci  constexpr LiftoffRegister clear(LiftoffRegister reg) {
3791cb0ef41Sopenharmony_ci    if (reg.is_pair()) {
3801cb0ef41Sopenharmony_ci      regs_ &= ~(storage_t{1} << reg.low().liftoff_code());
3811cb0ef41Sopenharmony_ci      regs_ &= ~(storage_t{1} << reg.high().liftoff_code());
3821cb0ef41Sopenharmony_ci    } else {
3831cb0ef41Sopenharmony_ci      regs_ &= ~(storage_t{1} << reg.liftoff_code());
3841cb0ef41Sopenharmony_ci    }
3851cb0ef41Sopenharmony_ci    return reg;
3861cb0ef41Sopenharmony_ci  }
3871cb0ef41Sopenharmony_ci  constexpr Register clear(Register reg) {
3881cb0ef41Sopenharmony_ci    return clear(LiftoffRegister{reg}).gp();
3891cb0ef41Sopenharmony_ci  }
3901cb0ef41Sopenharmony_ci  constexpr DoubleRegister clear(DoubleRegister reg) {
3911cb0ef41Sopenharmony_ci    return clear(LiftoffRegister{reg}).fp();
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci  bool has(LiftoffRegister reg) const {
3951cb0ef41Sopenharmony_ci    if (reg.is_pair()) {
3961cb0ef41Sopenharmony_ci      DCHECK_EQ(has(reg.low()), has(reg.high()));
3971cb0ef41Sopenharmony_ci      reg = reg.low();
3981cb0ef41Sopenharmony_ci    }
3991cb0ef41Sopenharmony_ci    return (regs_ & (storage_t{1} << reg.liftoff_code())) != 0;
4001cb0ef41Sopenharmony_ci  }
4011cb0ef41Sopenharmony_ci  bool has(Register reg) const { return has(LiftoffRegister{reg}); }
4021cb0ef41Sopenharmony_ci  bool has(DoubleRegister reg) const { return has(LiftoffRegister{reg}); }
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  constexpr bool is_empty() const { return regs_ == 0; }
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ci  constexpr unsigned GetNumRegsSet() const {
4071cb0ef41Sopenharmony_ci    return base::bits::CountPopulation(regs_);
4081cb0ef41Sopenharmony_ci  }
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ci  constexpr LiftoffRegList operator&(const LiftoffRegList other) const {
4111cb0ef41Sopenharmony_ci    return LiftoffRegList(regs_ & other.regs_);
4121cb0ef41Sopenharmony_ci  }
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci  constexpr LiftoffRegList operator|(const LiftoffRegList other) const {
4151cb0ef41Sopenharmony_ci    return LiftoffRegList(regs_ | other.regs_);
4161cb0ef41Sopenharmony_ci  }
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci  constexpr LiftoffRegList GetAdjacentFpRegsSet() const {
4191cb0ef41Sopenharmony_ci    // And regs_ with a right shifted version of itself, so reg[i] is set only
4201cb0ef41Sopenharmony_ci    // if reg[i+1] is set. We only care about the even fp registers.
4211cb0ef41Sopenharmony_ci    storage_t available = (regs_ >> 1) & regs_ & kEvenFpSetMask;
4221cb0ef41Sopenharmony_ci    return LiftoffRegList(available);
4231cb0ef41Sopenharmony_ci  }
4241cb0ef41Sopenharmony_ci
4251cb0ef41Sopenharmony_ci  constexpr bool HasAdjacentFpRegsSet() const {
4261cb0ef41Sopenharmony_ci    return !GetAdjacentFpRegsSet().is_empty();
4271cb0ef41Sopenharmony_ci  }
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci  constexpr bool operator==(const LiftoffRegList other) const {
4301cb0ef41Sopenharmony_ci    return regs_ == other.regs_;
4311cb0ef41Sopenharmony_ci  }
4321cb0ef41Sopenharmony_ci  constexpr bool operator!=(const LiftoffRegList other) const {
4331cb0ef41Sopenharmony_ci    return regs_ != other.regs_;
4341cb0ef41Sopenharmony_ci  }
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci  LiftoffRegister GetFirstRegSet() const {
4371cb0ef41Sopenharmony_ci    DCHECK(!is_empty());
4381cb0ef41Sopenharmony_ci    int first_code = base::bits::CountTrailingZeros(regs_);
4391cb0ef41Sopenharmony_ci    return LiftoffRegister::from_liftoff_code(first_code);
4401cb0ef41Sopenharmony_ci  }
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci  LiftoffRegister GetLastRegSet() const {
4431cb0ef41Sopenharmony_ci    DCHECK(!is_empty());
4441cb0ef41Sopenharmony_ci    int last_code =
4451cb0ef41Sopenharmony_ci        8 * sizeof(regs_) - 1 - base::bits::CountLeadingZeros(regs_);
4461cb0ef41Sopenharmony_ci    return LiftoffRegister::from_liftoff_code(last_code);
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  LiftoffRegList MaskOut(const LiftoffRegList mask) const {
4501cb0ef41Sopenharmony_ci    // Masking out is guaranteed to return a correct reg list, hence no checks
4511cb0ef41Sopenharmony_ci    // needed.
4521cb0ef41Sopenharmony_ci    return FromBits(regs_ & ~mask.regs_);
4531cb0ef41Sopenharmony_ci  }
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci  RegList GetGpList() { return RegList::FromBits(regs_ & kGpMask); }
4561cb0ef41Sopenharmony_ci  DoubleRegList GetFpList() {
4571cb0ef41Sopenharmony_ci    return DoubleRegList::FromBits((regs_ & kFpMask) >>
4581cb0ef41Sopenharmony_ci                                   kAfterMaxLiftoffGpRegCode);
4591cb0ef41Sopenharmony_ci  }
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ci  inline Iterator begin() const;
4621cb0ef41Sopenharmony_ci  inline Iterator end() const;
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  static LiftoffRegList FromBits(storage_t bits) {
4651cb0ef41Sopenharmony_ci    DCHECK_EQ(bits, bits & (kGpMask | kFpMask));
4661cb0ef41Sopenharmony_ci    return LiftoffRegList(bits);
4671cb0ef41Sopenharmony_ci  }
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci  template <storage_t bits>
4701cb0ef41Sopenharmony_ci  static constexpr LiftoffRegList FromBits() {
4711cb0ef41Sopenharmony_ci    static_assert(bits == (bits & (kGpMask | kFpMask)), "illegal reg list");
4721cb0ef41Sopenharmony_ci    return LiftoffRegList(bits);
4731cb0ef41Sopenharmony_ci  }
4741cb0ef41Sopenharmony_ci
4751cb0ef41Sopenharmony_ci private:
4761cb0ef41Sopenharmony_ci  // Unchecked constructor. Only use for valid bits.
4771cb0ef41Sopenharmony_ci  explicit constexpr LiftoffRegList(storage_t bits) : regs_(bits) {}
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci  storage_t regs_ = 0;
4801cb0ef41Sopenharmony_ci};
4811cb0ef41Sopenharmony_ciASSERT_TRIVIALLY_COPYABLE(LiftoffRegList);
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_cistatic constexpr LiftoffRegList kGpCacheRegList =
4841cb0ef41Sopenharmony_ci    LiftoffRegList::FromBits<LiftoffRegList::kGpMask>();
4851cb0ef41Sopenharmony_cistatic constexpr LiftoffRegList kFpCacheRegList =
4861cb0ef41Sopenharmony_ci    LiftoffRegList::FromBits<LiftoffRegList::kFpMask>();
4871cb0ef41Sopenharmony_ci
4881cb0ef41Sopenharmony_ciclass LiftoffRegList::Iterator {
4891cb0ef41Sopenharmony_ci public:
4901cb0ef41Sopenharmony_ci  LiftoffRegister operator*() { return remaining_.GetFirstRegSet(); }
4911cb0ef41Sopenharmony_ci  Iterator& operator++() {
4921cb0ef41Sopenharmony_ci    remaining_.clear(remaining_.GetFirstRegSet());
4931cb0ef41Sopenharmony_ci    return *this;
4941cb0ef41Sopenharmony_ci  }
4951cb0ef41Sopenharmony_ci  bool operator==(Iterator other) { return remaining_ == other.remaining_; }
4961cb0ef41Sopenharmony_ci  bool operator!=(Iterator other) { return remaining_ != other.remaining_; }
4971cb0ef41Sopenharmony_ci
4981cb0ef41Sopenharmony_ci private:
4991cb0ef41Sopenharmony_ci  explicit Iterator(LiftoffRegList remaining) : remaining_(remaining) {}
5001cb0ef41Sopenharmony_ci  friend class LiftoffRegList;
5011cb0ef41Sopenharmony_ci
5021cb0ef41Sopenharmony_ci  LiftoffRegList remaining_;
5031cb0ef41Sopenharmony_ci};
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_ciLiftoffRegList::Iterator LiftoffRegList::begin() const {
5061cb0ef41Sopenharmony_ci  return Iterator{*this};
5071cb0ef41Sopenharmony_ci}
5081cb0ef41Sopenharmony_ciLiftoffRegList::Iterator LiftoffRegList::end() const {
5091cb0ef41Sopenharmony_ci  return Iterator{LiftoffRegList{}};
5101cb0ef41Sopenharmony_ci}
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_cistatic constexpr LiftoffRegList GetCacheRegList(RegClass rc) {
5131cb0ef41Sopenharmony_ci  return rc == kFpReg ? kFpCacheRegList : kGpCacheRegList;
5141cb0ef41Sopenharmony_ci}
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ciinline std::ostream& operator<<(std::ostream& os, LiftoffRegList reglist) {
5171cb0ef41Sopenharmony_ci  os << "{";
5181cb0ef41Sopenharmony_ci  for (bool first = true; !reglist.is_empty(); first = false) {
5191cb0ef41Sopenharmony_ci    LiftoffRegister reg = reglist.GetFirstRegSet();
5201cb0ef41Sopenharmony_ci    reglist.clear(reg);
5211cb0ef41Sopenharmony_ci    os << (first ? "" : ", ") << reg;
5221cb0ef41Sopenharmony_ci  }
5231cb0ef41Sopenharmony_ci  return os << "}";
5241cb0ef41Sopenharmony_ci}
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci}  // namespace wasm
5271cb0ef41Sopenharmony_ci}  // namespace internal
5281cb0ef41Sopenharmony_ci}  // namespace v8
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci#endif  // V8_WASM_BASELINE_LIFTOFF_REGISTER_H_
531