blob: 6fc67cd30464f280293056e255429f81e02e62dd [file] [log] [blame]
// Copyright 2022 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_CODEGEN_REGLIST_BASE_H_
#define V8_CODEGEN_REGLIST_BASE_H_
#include <cstdint>
#include <initializer_list>
#include "src/base/bits.h"
#include "src/base/iterator.h"
#include "src/base/template-utils.h"
namespace v8 {
namespace internal {
class Register;
template <typename RegisterT>
class RegListBase {
using num_registers_sized_storage_t = typename std::conditional<
RegisterT::kNumRegisters <= 16, uint16_t,
typename std::conditional<RegisterT::kNumRegisters <= 32, uint32_t,
uint64_t>::type>::type;
STATIC_ASSERT(RegisterT::kNumRegisters <= 64);
public:
class Iterator;
class ReverseIterator;
#ifdef V8_TARGET_ARCH_ARM64
// On ARM64 the sp register has the special value 63 (kSPRegInternalCode)
using storage_t = typename std::conditional<
std::is_same<RegisterT, v8::internal::Register>::value, uint64_t,
num_registers_sized_storage_t>::type;
#else
using storage_t = num_registers_sized_storage_t;
#endif
constexpr RegListBase() = default;
constexpr RegListBase(std::initializer_list<RegisterT> regs) {
for (RegisterT reg : regs) {
set(reg);
}
}
constexpr void set(RegisterT reg) {
if (!reg.is_valid()) return;
regs_ |= storage_t{1} << reg.code();
}
constexpr void clear(RegisterT reg) {
if (!reg.is_valid()) return;
regs_ &= ~(storage_t{1} << reg.code());
}
constexpr bool has(RegisterT reg) const {
if (!reg.is_valid()) return false;
return (regs_ & (storage_t{1} << reg.code())) != 0;
}
constexpr void clear(RegListBase other) { regs_ &= ~other.regs_; }
constexpr bool is_empty() const { return regs_ == 0; }
constexpr unsigned Count() const {
return base::bits::CountPopulation(regs_);
}
constexpr RegListBase operator&(const RegListBase other) const {
return RegListBase(regs_ & other.regs_);
}
constexpr RegListBase operator|(const RegListBase other) const {
return RegListBase(regs_ | other.regs_);
}
constexpr RegListBase operator^(const RegListBase other) const {
return RegListBase(regs_ ^ other.regs_);
}
constexpr RegListBase operator-(const RegListBase other) const {
return RegListBase(regs_ & ~other.regs_);
}
constexpr RegListBase operator|(const RegisterT reg) const {
return *this | RegListBase{reg};
}
constexpr RegListBase operator-(const RegisterT reg) const {
return *this - RegListBase{reg};
}
constexpr RegListBase& operator&=(const RegListBase other) {
regs_ &= other.regs_;
return *this;
}
constexpr RegListBase& operator|=(const RegListBase other) {
regs_ |= other.regs_;
return *this;
}
constexpr bool operator==(const RegListBase other) const {
return regs_ == other.regs_;
}
constexpr bool operator!=(const RegListBase other) const {
return regs_ != other.regs_;
}
constexpr RegisterT first() const {
DCHECK(!is_empty());
int first_code = base::bits::CountTrailingZerosNonZero(regs_);
return RegisterT::from_code(first_code);
}
constexpr RegisterT last() const {
DCHECK(!is_empty());
int last_code =
8 * sizeof(regs_) - 1 - base::bits::CountLeadingZeros(regs_);
return RegisterT::from_code(last_code);
}
constexpr RegisterT PopFirst() {
RegisterT reg = first();
clear(reg);
return reg;
}
constexpr storage_t bits() const { return regs_; }
inline Iterator begin() const;
inline Iterator end() const;
inline ReverseIterator rbegin() const;
inline ReverseIterator rend() const;
static RegListBase FromBits(storage_t bits) { return RegListBase(bits); }
template <storage_t bits>
static constexpr RegListBase FromBits() {
return RegListBase{bits};
}
private:
// Unchecked constructor. Only use for valid bits.
explicit constexpr RegListBase(storage_t bits) : regs_(bits) {}
storage_t regs_ = 0;
};
template <typename RegisterT>
class RegListBase<RegisterT>::Iterator
: public base::iterator<std::forward_iterator_tag, RegisterT> {
public:
RegisterT operator*() { return remaining_.first(); }
Iterator& operator++() {
remaining_.clear(remaining_.first());
return *this;
}
bool operator==(Iterator other) { return remaining_ == other.remaining_; }
bool operator!=(Iterator other) { return remaining_ != other.remaining_; }
private:
explicit Iterator(RegListBase<RegisterT> remaining) : remaining_(remaining) {}
friend class RegListBase;
RegListBase<RegisterT> remaining_;
};
template <typename RegisterT>
class RegListBase<RegisterT>::ReverseIterator
: public base::iterator<std::forward_iterator_tag, RegisterT> {
public:
RegisterT operator*() { return remaining_.last(); }
ReverseIterator& operator++() {
remaining_.clear(remaining_.last());
return *this;
}
bool operator==(ReverseIterator other) {
return remaining_ == other.remaining_;
}
bool operator!=(ReverseIterator other) {
return remaining_ != other.remaining_;
}
private:
explicit ReverseIterator(RegListBase<RegisterT> remaining)
: remaining_(remaining) {}
friend class RegListBase;
RegListBase<RegisterT> remaining_;
};
template <typename RegisterT>
typename RegListBase<RegisterT>::Iterator RegListBase<RegisterT>::begin()
const {
return Iterator{*this};
}
template <typename RegisterT>
typename RegListBase<RegisterT>::Iterator RegListBase<RegisterT>::end() const {
return Iterator{RegListBase<RegisterT>{}};
}
template <typename RegisterT>
typename RegListBase<RegisterT>::ReverseIterator
RegListBase<RegisterT>::rbegin() const {
return ReverseIterator{*this};
}
template <typename RegisterT>
typename RegListBase<RegisterT>::ReverseIterator RegListBase<RegisterT>::rend()
const {
return ReverseIterator{RegListBase<RegisterT>{}};
}
template <typename RegisterT>
inline std::ostream& operator<<(std::ostream& os,
RegListBase<RegisterT> reglist) {
os << "{";
for (bool first = true; !reglist.is_empty(); first = false) {
RegisterT reg = reglist.first();
reglist.clear(reg);
os << (first ? "" : ", ") << reg;
}
return os << "}";
}
} // namespace internal
} // namespace v8
#endif // V8_CODEGEN_REGLIST_BASE_H_