Architecture-mips-shared.h (7863B)
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_mips_shared_Architecture_mips_shared_h 8 #define jit_mips_shared_Architecture_mips_shared_h 9 10 #include "mozilla/MathAlgorithms.h" 11 12 #include <algorithm> 13 #include <limits.h> 14 #include <stdint.h> 15 16 #include "jit/shared/Architecture-shared.h" 17 18 #include "js/Utility.h" 19 20 #if defined(_MIPS_SIM) 21 # if (_MIPS_SIM != _ABI64) 22 # error "Unsupported ABI" 23 # endif 24 #elif !defined(JS_SIMULATOR_MIPS64) 25 # error "Unknown ABI" 26 #endif 27 28 #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 6)) 29 # define MIPSR6 30 #endif 31 32 namespace js { 33 namespace jit { 34 35 // How far forward/back can a jump go? Provide a generous buffer for thunks. 36 static const uint32_t JumpImmediateRange = UINT32_MAX; 37 38 class Registers { 39 public: 40 enum RegisterID { 41 r0 = 0, 42 r1, 43 r2, 44 r3, 45 r4, 46 r5, 47 r6, 48 r7, 49 r8, 50 r9, 51 r10, 52 r11, 53 r12, 54 r13, 55 r14, 56 r15, 57 r16, 58 r17, 59 r18, 60 r19, 61 r20, 62 r21, 63 r22, 64 r23, 65 r24, 66 r25, 67 r26, 68 r27, 69 r28, 70 r29, 71 r30, 72 r31, 73 zero = r0, 74 at = r1, 75 v0 = r2, 76 v1 = r3, 77 a0 = r4, 78 a1 = r5, 79 a2 = r6, 80 a3 = r7, 81 a4 = r8, 82 a5 = r9, 83 a6 = r10, 84 a7 = r11, 85 t4 = r12, 86 t5 = r13, 87 t6 = r14, 88 t7 = r15, 89 ta0 = a4, 90 ta1 = a5, 91 ta2 = a6, 92 ta3 = a7, 93 s0 = r16, 94 s1 = r17, 95 s2 = r18, 96 s3 = r19, 97 s4 = r20, 98 s5 = r21, 99 s6 = r22, 100 s7 = r23, 101 t8 = r24, 102 t9 = r25, 103 k0 = r26, 104 k1 = r27, 105 gp = r28, 106 sp = r29, 107 fp = r30, 108 ra = r31, 109 invalid_reg 110 }; 111 typedef uint8_t Code; 112 typedef RegisterID Encoding; 113 114 // Content spilled during bailouts. 115 union RegisterContent { 116 uintptr_t r; 117 }; 118 119 static const char* const RegNames[]; 120 static const char* GetName(Code code) { 121 MOZ_ASSERT(code < Total); 122 return RegNames[code]; 123 } 124 static const char* GetName(Encoding i) { return GetName(Code(i)); } 125 126 static Code FromName(const char* name); 127 128 static const Encoding StackPointer = sp; 129 static const Encoding Invalid = invalid_reg; 130 131 static const uint32_t Total = 32; 132 static const uint32_t Allocatable; 133 134 typedef uint32_t SetType; 135 static const SetType AllMask = 0xffffffff; 136 static const SetType SharedArgRegMask = 137 (1 << a0) | (1 << a1) | (1 << a2) | (1 << a3); 138 static const SetType ArgRegMask; 139 140 static const SetType VolatileMask = 141 (1 << Registers::v0) | (1 << Registers::v1) | (1 << Registers::a0) | 142 (1 << Registers::a1) | (1 << Registers::a2) | (1 << Registers::a3) | 143 (1 << Registers::a4) | (1 << Registers::a5) | (1 << Registers::a6) | 144 (1 << Registers::a7) | (1 << Registers::t4) | (1 << Registers::t5) | 145 (1 << Registers::t6) | (1 << Registers::t7) | (1 << Registers::t8) | 146 (1 << Registers::t9); 147 148 // We use this constant to save registers when entering functions. This 149 // is why $ra is added here even though it is not "Non Volatile". 150 static const SetType NonVolatileMask = 151 (1 << Registers::s0) | (1 << Registers::s1) | (1 << Registers::s2) | 152 (1 << Registers::s3) | (1 << Registers::s4) | (1 << Registers::s5) | 153 (1 << Registers::s6) | (1 << Registers::s7) | (1 << Registers::fp) | 154 (1 << Registers::ra); 155 156 static const SetType WrapperMask = VolatileMask | // = arguments 157 (1 << Registers::t4) | // = outReg 158 (1 << Registers::t5); // = argBase 159 160 static const SetType NonAllocatableMask = 161 (1 << Registers::zero) | (1 << Registers::at) | // at = scratch 162 (1 << Registers::t8) | // t8 = scratch 163 (1 << Registers::t9) | // t9 = scratch or call 164 (1 << Registers::k0) | (1 << Registers::k1) | (1 << Registers::gp) | 165 (1 << Registers::sp) | (1 << Registers::ra) | (1 << Registers::fp); 166 167 // Registers returned from a JS -> JS call. 168 static const SetType JSCallMask; 169 170 // Registers returned from a JS -> C call. 171 static const SetType SharedCallMask = (1 << Registers::v0); 172 static const SetType CallMask; 173 174 static const SetType AllocatableMask = AllMask & ~NonAllocatableMask; 175 176 static uint32_t SetSize(SetType x) { 177 static_assert(sizeof(SetType) == 4, "SetType must be 32 bits"); 178 return mozilla::CountPopulation32(x); 179 } 180 static uint32_t FirstBit(SetType x) { 181 return mozilla::CountTrailingZeroes32(x); 182 } 183 static uint32_t LastBit(SetType x) { 184 return 31 - mozilla::CountLeadingZeroes32(x); 185 } 186 }; 187 188 // Smallest integer type that can hold a register bitmask. 189 typedef uint32_t PackedRegisterMask; 190 191 class FloatRegistersMIPSShared { 192 public: 193 enum FPRegisterID { 194 f0 = 0, 195 f1, 196 f2, 197 f3, 198 f4, 199 f5, 200 f6, 201 f7, 202 f8, 203 f9, 204 f10, 205 f11, 206 f12, 207 f13, 208 f14, 209 f15, 210 f16, 211 f17, 212 f18, 213 f19, 214 f20, 215 f21, 216 f22, 217 f23, 218 f24, 219 f25, 220 f26, 221 f27, 222 f28, 223 f29, 224 f30, 225 f31, 226 invalid_freg 227 }; 228 typedef uint32_t Code; 229 typedef FPRegisterID Encoding; 230 231 // Content spilled during bailouts. 232 union RegisterContent { 233 double d; 234 }; 235 236 static const char* GetName(Encoding code) { 237 static const char* const Names[] = { 238 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 239 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", 240 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", 241 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; 242 return Names[code]; 243 } 244 245 static const Encoding Invalid = invalid_freg; 246 247 typedef uint64_t SetType; 248 }; 249 250 static const uint32_t SpillSlotSize = 251 std::max(sizeof(Registers::RegisterContent), 252 sizeof(FloatRegistersMIPSShared::RegisterContent)); 253 254 template <typename T> 255 class TypedRegisterSet; 256 257 class FloatRegisterMIPSShared { 258 public: 259 bool isSimd128() const { return false; } 260 261 typedef FloatRegistersMIPSShared::SetType SetType; 262 263 static uint32_t SetSize(SetType x) { 264 static_assert(sizeof(SetType) == 8, "SetType must be 64 bits"); 265 return mozilla::CountPopulation64(x); 266 } 267 static uint32_t FirstBit(SetType x) { 268 static_assert(sizeof(SetType) == 8, "SetType must be 64 bits"); 269 return mozilla::CountTrailingZeroes64(x); 270 } 271 static uint32_t LastBit(SetType x) { 272 static_assert(sizeof(SetType) == 8, "SetType must be 64 bits"); 273 return 63 - mozilla::CountLeadingZeroes64(x); 274 } 275 }; 276 277 class MIPSFlags final { 278 static inline bool initialized = false; 279 280 static inline uint32_t flags = 0; 281 static inline bool hasFPU = false; 282 static inline bool hasR2 = false; 283 static inline bool isLoongson = false; 284 285 public: 286 MIPSFlags() = delete; 287 288 // MIPSFlags::Init is called from the JitContext constructor to read the 289 // hardware flags. This method must only be called exactly once. 290 static void Init(); 291 292 static bool IsInitialized() { return initialized; } 293 294 static uint32_t GetFlags() { 295 MOZ_ASSERT(IsInitialized()); 296 return flags; 297 } 298 299 static bool HasFPU() { return hasFPU; } 300 static bool HasR2() { return hasR2; } 301 static bool IsLoongson() { return isLoongson; } 302 }; 303 304 inline uint32_t GetMIPSFlags() { return MIPSFlags::GetFlags(); } 305 inline bool hasFPU() { return MIPSFlags::HasFPU(); } 306 inline bool isLoongson() { return MIPSFlags::IsLoongson(); } 307 inline bool hasR2() { return MIPSFlags::HasR2(); } 308 309 // MIPS doesn't have double registers that can NOT be treated as float32. 310 inline bool hasUnaliasedDouble() { return false; } 311 312 // MIPS64 doesn't support it. 313 inline bool hasMultiAlias() { return false; } 314 315 } // namespace jit 316 } // namespace js 317 318 #endif /* jit_mips_shared_Architecture_mips_shared_h */