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