Architecture-mips64.h (7667B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_mips64_Architecture_mips64_h 8 #define jit_mips64_Architecture_mips64_h 9 10 #include "mozilla/MathAlgorithms.h" 11 12 #include <limits.h> 13 #include <stdint.h> 14 15 #include "jit/mips-shared/Architecture-mips-shared.h" 16 17 #include "js/Utility.h" 18 19 namespace js { 20 namespace jit { 21 22 // Shadow stack space is not required on MIPS64. 23 static constexpr uint32_t ShadowStackSpace = 0; 24 25 // MIPS64 have 64 bit floating-point coprocessor. There are 32 double 26 // precision register which can also be used as single precision registers. 27 class FloatRegisters : public FloatRegistersMIPSShared { 28 public: 29 enum ContentType { Single, Double, NumTypes }; 30 31 static const char* GetName(uint32_t i) { 32 MOZ_ASSERT(i < TotalPhys); 33 return FloatRegistersMIPSShared::GetName(Encoding(i)); 34 } 35 36 static Encoding FromName(const char* name); 37 38 static const uint32_t Total = 32 * NumTypes; 39 #ifdef MIPSR6 40 static const uint32_t Allocatable = 60; 41 #else 42 static const uint32_t Allocatable = 62; 43 #endif 44 // When saving all registers we only need to do is save double registers. 45 static const uint32_t TotalPhys = 32; 46 47 static_assert(sizeof(SetType) * 8 >= Total, 48 "SetType should be large enough to enumerate all registers."); 49 50 // Magic values which are used to duplicate a mask of physical register for 51 // a specific type of register. A multiplication is used to copy and shift 52 // the bits of the physical register mask. 53 static const SetType SpreadSingle = SetType(1) 54 << (uint32_t(Single) * TotalPhys); 55 static const SetType SpreadDouble = SetType(1) 56 << (uint32_t(Double) * TotalPhys); 57 static const SetType SpreadScalar = SpreadSingle | SpreadDouble; 58 static const SetType SpreadVector = 0; 59 static const SetType Spread = SpreadScalar | SpreadVector; 60 61 static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1); 62 static const SetType AllMask = AllPhysMask * Spread; 63 static const SetType AllSingleMask = AllPhysMask * SpreadSingle; 64 static const SetType AllDoubleMask = AllPhysMask * SpreadDouble; 65 66 static const SetType NonVolatileMask = 67 ((1U << FloatRegisters::f24) | (1U << FloatRegisters::f25) | 68 (1U << FloatRegisters::f26) | (1U << FloatRegisters::f27) | 69 (1U << FloatRegisters::f28) | (1U << FloatRegisters::f29) | 70 (1U << FloatRegisters::f30) | (1U << FloatRegisters::f31)) * 71 SpreadScalar | 72 AllPhysMask * SpreadVector; 73 74 static const SetType VolatileMask = AllMask & ~NonVolatileMask; 75 76 static const SetType WrapperMask = VolatileMask; 77 78 #ifdef MIPSR6 79 static const SetType NonAllocatableMask = 80 ((1U << FloatRegisters::f23) | (1U << FloatRegisters::f24)) * Spread; 81 #else 82 static const SetType NonAllocatableMask = 83 (1U << FloatRegisters::f23) * Spread; 84 #endif 85 86 static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; 87 }; 88 89 template <typename T> 90 class TypedRegisterSet; 91 92 class FloatRegister : public FloatRegisterMIPSShared { 93 public: 94 typedef FloatRegisters Codes; 95 typedef size_t Code; 96 typedef Codes::Encoding Encoding; 97 typedef Codes::ContentType ContentType; 98 99 Encoding reg_ : 6; 100 101 private: 102 ContentType kind_ : 3; 103 104 public: 105 constexpr explicit FloatRegister(uint32_t r, ContentType kind = Codes::Double) 106 : reg_(Encoding(r)), kind_(kind) {} 107 constexpr FloatRegister() 108 : reg_(Encoding(FloatRegisters::invalid_freg)), kind_(Codes::Double) {} 109 110 static uint32_t SetSize(SetType x) { 111 // Count the number of non-aliased registers. 112 x |= x >> Codes::TotalPhys; 113 x &= Codes::AllPhysMask; 114 static_assert(Codes::AllPhysMask <= 0xffffffff, 115 "We can safely use CountPopulation32"); 116 return mozilla::CountPopulation32(x); 117 } 118 119 bool operator==(const FloatRegister& other) const { 120 MOZ_ASSERT(!isInvalid()); 121 MOZ_ASSERT(!other.isInvalid()); 122 return kind_ == other.kind_ && reg_ == other.reg_; 123 } 124 bool equiv(const FloatRegister& other) const { return other.kind_ == kind_; } 125 size_t size() const { 126 return (kind_ == Codes::Double) ? sizeof(double) : sizeof(float); 127 } 128 // Always push doubles to maintain 8-byte stack alignment. 129 size_t pushSize() const { return sizeof(double); } 130 bool isInvalid() const { return reg_ == FloatRegisters::invalid_freg; } 131 132 bool isSingle() const { return kind_ == Codes::Single; } 133 bool isDouble() const { return kind_ == Codes::Double; } 134 bool isSimd128() const { return false; } 135 136 FloatRegister singleOverlay() const; 137 FloatRegister doubleOverlay() const; 138 139 FloatRegister asSingle() const { return singleOverlay(); } 140 FloatRegister asDouble() const { return doubleOverlay(); } 141 FloatRegister asSimd128() const { MOZ_CRASH("NYI"); } 142 143 Code code() const { 144 MOZ_ASSERT(!isInvalid()); 145 return Code(reg_ | (kind_ << 5)); 146 } 147 Encoding encoding() const { 148 MOZ_ASSERT(!isInvalid()); 149 MOZ_ASSERT(uint32_t(reg_) < Codes::TotalPhys); 150 return reg_; 151 } 152 uint32_t id() const { return reg_; } 153 static FloatRegister FromCode(uint32_t i) { 154 uint32_t code = i & 0x1f; 155 uint32_t kind = i >> 5; 156 return FloatRegister(Code(code), ContentType(kind)); 157 } 158 159 bool volatile_() const { 160 return !!((1 << reg_) & FloatRegisters::VolatileMask); 161 } 162 const char* name() const { return FloatRegisters::GetName(reg_); } 163 bool operator!=(const FloatRegister& other) const { 164 return kind_ != other.kind_ || reg_ != other.reg_; 165 } 166 bool aliases(const FloatRegister& other) { return reg_ == other.reg_; } 167 uint32_t numAliased() const { return 2; } 168 FloatRegister aliased(uint32_t aliasIdx) { 169 if (aliasIdx == 0) { 170 return *this; 171 } 172 MOZ_ASSERT(aliasIdx == 1); 173 if (isDouble()) { 174 return singleOverlay(); 175 } 176 return doubleOverlay(); 177 } 178 uint32_t numAlignedAliased() const { return 2; } 179 FloatRegister alignedAliased(uint32_t aliasIdx) { 180 MOZ_ASSERT(isDouble()); 181 if (aliasIdx == 0) { 182 return *this; 183 } 184 MOZ_ASSERT(aliasIdx == 1); 185 return singleOverlay(); 186 } 187 188 SetType alignedOrDominatedAliasedSet() const { return Codes::Spread << reg_; } 189 190 static constexpr RegTypeName DefaultType = RegTypeName::Float64; 191 192 template <RegTypeName = DefaultType> 193 static SetType LiveAsIndexableSet(SetType s) { 194 return SetType(0); 195 } 196 197 template <RegTypeName Name = DefaultType> 198 static SetType AllocatableAsIndexableSet(SetType s) { 199 static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable"); 200 return LiveAsIndexableSet<Name>(s); 201 } 202 203 static Code FromName(const char* name) { 204 return FloatRegisters::FromName(name); 205 } 206 static TypedRegisterSet<FloatRegister> ReduceSetForPush( 207 const TypedRegisterSet<FloatRegister>& s); 208 static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s); 209 uint32_t getRegisterDumpOffsetInBytes(); 210 }; 211 212 template <> 213 inline FloatRegister::SetType 214 FloatRegister::LiveAsIndexableSet<RegTypeName::Float32>(SetType set) { 215 return set & FloatRegisters::AllSingleMask; 216 } 217 218 template <> 219 inline FloatRegister::SetType 220 FloatRegister::LiveAsIndexableSet<RegTypeName::Float64>(SetType set) { 221 return set & FloatRegisters::AllDoubleMask; 222 } 223 224 template <> 225 inline FloatRegister::SetType 226 FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set) { 227 return set; 228 } 229 230 } // namespace jit 231 } // namespace js 232 233 #endif /* jit_mips64_Architecture_mips64_h */