/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef jit_mips32_Architecture_mips32_h #define jit_mips32_Architecture_mips32_h #include "mozilla/EndianUtils.h" #include "mozilla/MathAlgorithms.h" #include #include #include "jit/mips-shared/Architecture-mips-shared.h" #include "js/Utility.h" namespace js { namespace jit { static constexpr uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t); // These offsets are specific to nunboxing, and capture offsets into the // components of a js::Value. // Size of MIPS32 general purpose registers is 32 bits. #if MOZ_LITTLE_ENDIAN() static const int32_t NUNBOX32_TYPE_OFFSET = 4; static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0; #else static const int32_t NUNBOX32_TYPE_OFFSET = 0; static const int32_t NUNBOX32_PAYLOAD_OFFSET = 4; #endif // MIPS32 can have two types of floating-point coprocessors modes: // - FR=0 mode/ 32-bit FPRs - Historical default, there are 32 single // precision registers and pairs of even and odd float registers are used as // double precision registers. Example: f0 (double) is composed of // f0 and f1 (single). Loongson3A FPU running in this mode doesn't allow // use of odd registers for single precision arithmetic. // - FR=1 mode/ 64-bit FPRs - In this case, there are 32 double precision // register which can also be used as single precision registers. More info // https://dmz-portal.imgtec.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking // Currently we enable 16 even single precision registers which can be also can // be used as double precision registers. It enables jit code to run even on // Loongson3A. It does not support FR=1 mode because MacroAssembler threats odd // single precision registers as high parts of even double precision registers. #ifdef __mips_fpr static_assert(__mips_fpr == 32, "MIPS32 jit only supports FR=0 fpu mode."); #endif class FloatRegisters : public FloatRegistersMIPSShared { public: static const char* GetName(uint32_t i) { MOZ_ASSERT(i < RegisterIdLimit); return FloatRegistersMIPSShared::GetName(Encoding(i % 32)); } static Encoding FromName(const char* name); static const uint32_t Total = 32; static const uint32_t TotalDouble = 16; static const uint32_t TotalSingle = 16; static const uint32_t Allocatable = 30; static const SetType AllSingleMask = (1ULL << TotalSingle) - 1; static const SetType AllDoubleMask = ((1ULL << TotalDouble) - 1) << TotalSingle; static const SetType AllMask = AllDoubleMask | AllSingleMask; // When saving all registers we only need to do is save double registers. static const uint32_t TotalPhys = 16; static const uint32_t RegisterIdLimit = 32; static_assert(sizeof(SetType) * 8 >= Total, "SetType should be large enough to enumerate all registers."); static const SetType NonVolatileMask = ((SetType(1) << (FloatRegisters::f20 >> 1)) | (SetType(1) << (FloatRegisters::f22 >> 1)) | (SetType(1) << (FloatRegisters::f24 >> 1)) | (SetType(1) << (FloatRegisters::f26 >> 1)) | (SetType(1) << (FloatRegisters::f28 >> 1)) | (SetType(1) << (FloatRegisters::f30 >> 1))) * ((1 << TotalSingle) + 1); static const SetType VolatileMask = AllMask & ~NonVolatileMask; static const SetType WrapperMask = VolatileMask; static const SetType NonAllocatableMask = (SetType(1) << (FloatRegisters::f18 >> 1)) * ((1 << TotalSingle) + 1); static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; }; class FloatRegister : public FloatRegisterMIPSShared { public: enum RegType { Single = 0x0, Double = 0x1, }; typedef FloatRegisters Codes; typedef Codes::Code Code; typedef Codes::Encoding Encoding; Encoding code_ : 6; protected: RegType kind_ : 1; public: constexpr FloatRegister(uint32_t code, RegType kind = Double) : code_(Encoding(code)), kind_(kind) {} constexpr FloatRegister() : code_(FloatRegisters::invalid_freg), kind_(Double) {} bool operator==(const FloatRegister& other) const { MOZ_ASSERT(!isInvalid()); MOZ_ASSERT(!other.isInvalid()); return kind_ == other.kind_ && code_ == other.code_; } bool equiv(const FloatRegister& other) const { return other.kind_ == kind_; } size_t size() const { return (kind_ == Double) ? 8 : 4; } size_t pushSize() const { return size(); } bool isNotOdd() const { return !isInvalid() && ((code_ & 1) == 0); } bool isSingle() const { return kind_ == Single; } bool isDouble() const { return kind_ == Double; } bool isInvalid() const { return code_ == FloatRegisters::invalid_freg; } bool isSimd128() const { return false; } FloatRegister doubleOverlay() const; FloatRegister singleOverlay() const; FloatRegister asSingle() const { return singleOverlay(); } FloatRegister asDouble() const { return doubleOverlay(); } FloatRegister asSimd128() const { MOZ_CRASH("NYI"); } Code code() const { MOZ_ASSERT(isNotOdd()); return Code((code_ >> 1) | (kind_ << 4)); } Encoding encoding() const { MOZ_ASSERT(!isInvalid()); return code_; } uint32_t id() const { MOZ_ASSERT(!isInvalid()); return code_; } static FloatRegister FromCode(uint32_t i) { uint32_t code = i & 15; uint32_t kind = i >> 4; return FloatRegister(Encoding(code << 1), RegType(kind)); } static FloatRegister FromIndex(uint32_t index, RegType kind) { MOZ_ASSERT(index < 16); return FloatRegister(Encoding(index << 1), kind); } bool volatile_() const { return !!((SetType(1) << code()) & FloatRegisters::VolatileMask); } const char* name() const { return FloatRegisters::GetName(code_); } bool operator!=(const FloatRegister& other) const { return other.kind_ != kind_ || code_ != other.code_; } bool aliases(const FloatRegister& other) { MOZ_ASSERT(isNotOdd()); return code_ == other.code_; } uint32_t numAliased() const { MOZ_ASSERT(isNotOdd()); return 2; } FloatRegister aliased(uint32_t aliasIdx) { MOZ_ASSERT(isNotOdd()); if (aliasIdx == 0) { return *this; } MOZ_ASSERT(aliasIdx == 1); if (isDouble()) { return singleOverlay(); } return doubleOverlay(); } uint32_t numAlignedAliased() const { MOZ_ASSERT(isNotOdd()); return 2; } FloatRegister alignedAliased(uint32_t aliasIdx) { MOZ_ASSERT(isNotOdd()); if (aliasIdx == 0) { return *this; } MOZ_ASSERT(aliasIdx == 1); if (isDouble()) { return singleOverlay(); } return doubleOverlay(); } SetType alignedOrDominatedAliasedSet() const { MOZ_ASSERT(isNotOdd()); return (SetType(1) << (code_ >> 1)) * ((1 << FloatRegisters::TotalSingle) + 1); } static constexpr RegTypeName DefaultType = RegTypeName::Float64; template static SetType LiveAsIndexableSet(SetType s) { return SetType(0); } template static SetType AllocatableAsIndexableSet(SetType s) { static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable"); return LiveAsIndexableSet(s); } static Code FromName(const char* name) { return FloatRegisters::FromName(name); } static TypedRegisterSet ReduceSetForPush( const TypedRegisterSet& s); static uint32_t GetPushSizeInBytes(const TypedRegisterSet& s); uint32_t getRegisterDumpOffsetInBytes(); }; template <> inline FloatRegister::SetType FloatRegister::LiveAsIndexableSet(SetType set) { return set & FloatRegisters::AllSingleMask; } template <> inline FloatRegister::SetType FloatRegister::LiveAsIndexableSet(SetType set) { return set & FloatRegisters::AllDoubleMask; } template <> inline FloatRegister::SetType FloatRegister::LiveAsIndexableSet(SetType set) { return set; } template <> inline FloatRegister::SetType FloatRegister::AllocatableAsIndexableSet(SetType set) { // Single registers are not dominating any smaller registers, thus masking // is enough to convert an allocatable set into a set of register list all // single register available. return set & FloatRegisters::AllSingleMask; } template <> inline FloatRegister::SetType FloatRegister::AllocatableAsIndexableSet(SetType set) { return set & FloatRegisters::AllDoubleMask; } // In order to handle functions such as int(*)(int, double) where the first // argument is a general purpose register, and the second argument is a floating // point register, we have to store the double content into 2 general purpose // registers, namely a2 and a3. #define JS_CODEGEN_REGISTER_PAIR 1 } // namespace jit } // namespace js #endif /* jit_mips32_Architecture_mips32_h */