diff options
Diffstat (limited to 'deps/v8/src/wasm/baseline/liftoff-register.h')
-rw-r--r-- | deps/v8/src/wasm/baseline/liftoff-register.h | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/deps/v8/src/wasm/baseline/liftoff-register.h b/deps/v8/src/wasm/baseline/liftoff-register.h new file mode 100644 index 0000000000..bb5ef5be4a --- /dev/null +++ b/deps/v8/src/wasm/baseline/liftoff-register.h @@ -0,0 +1,242 @@ +// Copyright 2017 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_WASM_BASELINE_LIFTOFF_REGISTER_H_ +#define V8_WASM_BASELINE_LIFTOFF_REGISTER_H_ + +#include <iosfwd> +#include <memory> + +// Clients of this interface shouldn't depend on lots of compiler internals. +// Do not include anything from src/compiler here! +#include "src/base/bits.h" +#include "src/wasm/baseline/liftoff-assembler-defs.h" +#include "src/wasm/wasm-opcodes.h" + +namespace v8 { +namespace internal { +namespace wasm { + +enum RegClass { kNoReg, kGpReg, kFpReg }; + +// TODO(clemensh): Use a switch once we require C++14 support. +static inline constexpr RegClass reg_class_for(ValueType type) { + return type == kWasmI32 || type == kWasmI64 // int types + ? kGpReg + : type == kWasmF32 || type == kWasmF64 // float types + ? kFpReg + : kNoReg; // other (unsupported) types +} + +// RegForClass<rc>: Register for rc==kGpReg, DoubleRegister for rc==kFpReg, void +// for all other values of rc. +template <RegClass rc> +using RegForClass = typename std::conditional< + rc == kGpReg, Register, + typename std::conditional<rc == kFpReg, DoubleRegister, void>::type>::type; + +// Maximum code of a gp cache register. +static constexpr int kMaxGpRegCode = + 8 * sizeof(kLiftoffAssemblerGpCacheRegs) - + base::bits::CountLeadingZeros(kLiftoffAssemblerGpCacheRegs); +// Maximum code of an fp cache register. +static constexpr int kMaxFpRegCode = + 8 * sizeof(kLiftoffAssemblerFpCacheRegs) - + base::bits::CountLeadingZeros(kLiftoffAssemblerFpCacheRegs); +// LiftoffRegister encodes both gp and fp in a unified index space. +// [0 .. kMaxGpRegCode] encodes gp registers, +// [kMaxGpRegCode+1 .. kMaxGpRegCode + kMaxFpRegCode] encodes fp registers. +static constexpr int kAfterMaxLiftoffGpRegCode = kMaxGpRegCode + 1; +static constexpr int kAfterMaxLiftoffFpRegCode = + kAfterMaxLiftoffGpRegCode + kMaxFpRegCode + 1; +static constexpr int kAfterMaxLiftoffRegCode = kAfterMaxLiftoffFpRegCode; +static_assert(kAfterMaxLiftoffRegCode < 256, + "liftoff register codes can be stored in one uint8_t"); + +class LiftoffRegister { + public: + explicit LiftoffRegister(Register reg) : LiftoffRegister(reg.code()) { + DCHECK_EQ(reg, gp()); + } + explicit LiftoffRegister(DoubleRegister reg) + : LiftoffRegister(kAfterMaxLiftoffGpRegCode + reg.code()) { + DCHECK_EQ(reg, fp()); + } + + static LiftoffRegister from_liftoff_code(int code) { + DCHECK_LE(0, code); + DCHECK_GT(kAfterMaxLiftoffRegCode, code); + return LiftoffRegister(code); + } + + static LiftoffRegister from_code(RegClass rc, int code) { + switch (rc) { + case kGpReg: + return LiftoffRegister(Register::from_code(code)); + case kFpReg: + return LiftoffRegister(DoubleRegister::from_code(code)); + default: + UNREACHABLE(); + } + } + + constexpr bool is_gp() const { return code_ < kAfterMaxLiftoffGpRegCode; } + constexpr bool is_fp() const { + return code_ >= kAfterMaxLiftoffGpRegCode && + code_ < kAfterMaxLiftoffFpRegCode; + } + + Register gp() const { + DCHECK(is_gp()); + return Register::from_code(code_); + } + + DoubleRegister fp() const { + DCHECK(is_fp()); + return DoubleRegister::from_code(code_ - kAfterMaxLiftoffGpRegCode); + } + + int liftoff_code() const { return code_; } + + RegClass reg_class() const { + DCHECK(is_gp() || is_fp()); + return is_gp() ? kGpReg : kFpReg; + } + + bool operator==(const LiftoffRegister other) const { + return code_ == other.code_; + } + bool operator!=(const LiftoffRegister other) const { + return code_ != other.code_; + } + + private: + uint8_t code_; + + explicit constexpr LiftoffRegister(uint8_t code) : code_(code) {} +}; +static_assert(IS_TRIVIALLY_COPYABLE(LiftoffRegister), + "LiftoffRegister can efficiently be passed by value"); + +inline std::ostream& operator<<(std::ostream& os, LiftoffRegister reg) { + return reg.is_gp() ? os << "gp" << reg.gp().code() + : os << "fp" << reg.fp().code(); +} + +class LiftoffRegList { + public: + static constexpr bool use_u16 = kAfterMaxLiftoffRegCode <= 16; + static constexpr bool use_u32 = !use_u16 && kAfterMaxLiftoffRegCode <= 32; + using storage_t = std::conditional< + use_u16, uint16_t, + std::conditional<use_u32, uint32_t, uint64_t>::type>::type; + + static constexpr storage_t kGpMask = storage_t{kLiftoffAssemblerGpCacheRegs}; + static constexpr storage_t kFpMask = storage_t{kLiftoffAssemblerFpCacheRegs} + << kAfterMaxLiftoffGpRegCode; + + constexpr LiftoffRegList() = default; + + Register set(Register reg) { return set(LiftoffRegister(reg)).gp(); } + DoubleRegister set(DoubleRegister reg) { + return set(LiftoffRegister(reg)).fp(); + } + + LiftoffRegister set(LiftoffRegister reg) { + regs_ |= storage_t{1} << reg.liftoff_code(); + return reg; + } + + LiftoffRegister clear(LiftoffRegister reg) { + regs_ &= ~(storage_t{1} << reg.liftoff_code()); + return reg; + } + + bool has(LiftoffRegister reg) const { + return (regs_ & (storage_t{1} << reg.liftoff_code())) != 0; + } + + constexpr bool is_empty() const { return regs_ == 0; } + + constexpr unsigned GetNumRegsSet() const { + return base::bits::CountPopulation(regs_); + } + + constexpr LiftoffRegList operator&(const LiftoffRegList other) const { + return LiftoffRegList(regs_ & other.regs_); + } + + constexpr LiftoffRegList operator~() const { + return LiftoffRegList(~regs_ & (kGpMask | kFpMask)); + } + + constexpr bool operator==(const LiftoffRegList other) const { + return regs_ == other.regs_; + } + constexpr bool operator!=(const LiftoffRegList other) const { + return regs_ != other.regs_; + } + + LiftoffRegister GetFirstRegSet() const { + DCHECK(!is_empty()); + unsigned first_code = base::bits::CountTrailingZeros(regs_); + return LiftoffRegister::from_liftoff_code(first_code); + } + + LiftoffRegister GetLastRegSet() const { + DCHECK(!is_empty()); + unsigned last_code = + 8 * sizeof(regs_) - 1 - base::bits::CountLeadingZeros(regs_); + return LiftoffRegister::from_liftoff_code(last_code); + } + + LiftoffRegList MaskOut(const LiftoffRegList mask) const { + // Masking out is guaranteed to return a correct reg list, hence no checks + // needed. + return FromBits(regs_ & ~mask.regs_); + } + + static LiftoffRegList FromBits(storage_t bits) { + DCHECK_EQ(bits, bits & (kGpMask | kFpMask)); + return LiftoffRegList(bits); + } + + template <storage_t bits> + static constexpr LiftoffRegList FromBits() { + static_assert(bits == (bits & (kGpMask | kFpMask)), "illegal reg list"); + return LiftoffRegList(bits); + } + + template <typename... Regs> + static LiftoffRegList ForRegs(Regs... regs) { + std::array<LiftoffRegister, sizeof...(regs)> regs_arr{ + LiftoffRegister(regs)...}; + LiftoffRegList list; + for (LiftoffRegister reg : regs_arr) list.set(reg); + return list; + } + + private: + storage_t regs_ = 0; + + // Unchecked constructor. Only use for valid bits. + explicit constexpr LiftoffRegList(storage_t bits) : regs_(bits) {} +}; +static_assert(IS_TRIVIALLY_COPYABLE(LiftoffRegList), + "LiftoffRegList can be passed by value"); + +static constexpr LiftoffRegList kGpCacheRegList = + LiftoffRegList::FromBits<LiftoffRegList::kGpMask>(); +static constexpr LiftoffRegList kFpCacheRegList = + LiftoffRegList::FromBits<LiftoffRegList::kFpMask>(); + +static constexpr LiftoffRegList GetCacheRegList(RegClass rc) { + return rc == kGpReg ? kGpCacheRegList : kFpCacheRegList; +} + +} // namespace wasm +} // namespace internal +} // namespace v8 + +#endif // V8_WASM_BASELINE_LIFTOFF_REGISTER_H_ |