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/. */
7 #ifndef jit_Registers_h
8 #define jit_Registers_h
10 #include "mozilla/Array.h"
12 #include "jit/IonTypes.h"
13 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
14 # include "jit/x86-shared/Architecture-x86-shared.h"
15 #elif defined(JS_CODEGEN_ARM)
16 # include "jit/arm/Architecture-arm.h"
17 #elif defined(JS_CODEGEN_ARM64)
18 # include "jit/arm64/Architecture-arm64.h"
19 #elif defined(JS_CODEGEN_MIPS32)
20 # include "jit/mips32/Architecture-mips32.h"
21 #elif defined(JS_CODEGEN_MIPS64)
22 # include "jit/mips64/Architecture-mips64.h"
23 #elif defined(JS_CODEGEN_LOONG64)
24 # include "jit/loong64/Architecture-loong64.h"
25 #elif defined(JS_CODEGEN_RISCV64)
26 # include "jit/riscv64/Architecture-riscv64.h"
27 #elif defined(JS_CODEGEN_WASM32)
28 # include "jit/wasm32/Architecture-wasm32.h"
29 #elif defined(JS_CODEGEN_NONE)
30 # include "jit/none/Architecture-none.h"
32 # error "Unknown architecture!"
39 using Codes
= Registers
;
40 using Encoding
= Codes::Encoding
;
41 using Code
= Codes::Code
;
42 using SetType
= Codes::SetType
;
45 explicit constexpr Register(Encoding e
) : reg_(e
) {}
46 Register() : reg_(Encoding(Codes::Invalid
)) {}
48 static Register
FromCode(Code i
) {
49 MOZ_ASSERT(i
< Registers::Total
);
50 Register r
{Encoding(i
)};
53 static Register
FromName(const char* name
) {
54 Code code
= Registers::FromName(name
);
55 Register r
{Encoding(code
)};
58 constexpr static Register
Invalid() {
59 Register r
{Encoding(Codes::Invalid
)};
62 constexpr Code
code() const { return Code(reg_
); }
63 Encoding
encoding() const {
64 MOZ_ASSERT(Code(reg_
) < Registers::Total
);
67 const char* name() const { return Registers::GetName(code()); }
68 constexpr bool operator==(Register other
) const { return reg_
== other
.reg_
; }
69 constexpr bool operator!=(Register other
) const { return reg_
!= other
.reg_
; }
70 bool volatile_() const {
71 return !!((SetType(1) << code()) & Registers::VolatileMask
);
73 bool aliases(const Register
& other
) const { return reg_
== other
.reg_
; }
74 uint32_t numAliased() const { return 1; }
76 Register
aliased(uint32_t aliasIdx
) const {
77 MOZ_ASSERT(aliasIdx
== 0);
81 SetType
alignedOrDominatedAliasedSet() const { return SetType(1) << code(); }
83 static constexpr RegTypeName DefaultType
= RegTypeName::GPR
;
85 template <RegTypeName
= DefaultType
>
86 static SetType
LiveAsIndexableSet(SetType s
) {
90 template <RegTypeName Name
= DefaultType
>
91 static SetType
AllocatableAsIndexableSet(SetType s
) {
92 static_assert(Name
!= RegTypeName::Any
, "Allocatable set are not iterable");
96 static uint32_t SetSize(SetType x
) { return Codes::SetSize(x
); }
97 static uint32_t FirstBit(SetType x
) { return Codes::FirstBit(x
); }
98 static uint32_t LastBit(SetType x
) { return Codes::LastBit(x
); }
100 // Returns the offset of |reg| on the stack, assuming all registers in |set|
101 // were pushed in order (e.g. by |PushRegsInMask|). This is computed by
102 // clearing the lower bits (registers that were pushed later).
103 static size_t OffsetOfPushedRegister(SetType set
, Register reg
) {
104 return sizeof(Codes::RegisterContent
) * Codes::SetSize(set
>> reg
.code());
108 // Architectures where the stack pointer is not a plain register with a standard
109 // register encoding must define JS_HAS_HIDDEN_SP and HiddenSPEncoding.
111 #ifdef JS_HAS_HIDDEN_SP
112 struct RegisterOrSP
{
113 // The register code -- but possibly one that cannot be represented as a bit
114 // position in a 32-bit vector.
117 explicit RegisterOrSP(uint32_t code
) : code(code
) {}
118 explicit RegisterOrSP(Register r
) : code(r
.code()) {}
121 static inline bool IsHiddenSP(RegisterOrSP r
) {
122 return r
.code
== HiddenSPEncoding
;
125 static inline Register
AsRegister(RegisterOrSP r
) {
126 MOZ_ASSERT(!IsHiddenSP(r
));
127 return Register::FromCode(r
.code
);
130 static inline Register
AsRegister(Register r
) { return r
; }
132 inline bool operator==(Register r
, RegisterOrSP e
) {
133 return r
.code() == e
.code
;
136 inline bool operator!=(Register r
, RegisterOrSP e
) { return !(r
== e
); }
138 inline bool operator==(RegisterOrSP e
, Register r
) { return r
== e
; }
140 inline bool operator!=(RegisterOrSP e
, Register r
) { return r
!= e
; }
142 inline bool operator==(RegisterOrSP lhs
, RegisterOrSP rhs
) {
143 return lhs
.code
== rhs
.code
;
146 inline bool operator!=(RegisterOrSP lhs
, RegisterOrSP rhs
) {
147 return !(lhs
== rhs
);
150 // On platforms where there's nothing special about SP, make RegisterOrSP be
151 // just Register, and return false for IsHiddenSP(r) for any r so that we use
152 // "normal" code for handling the SP. This reduces ifdeffery throughout the
154 using RegisterOrSP
= Register
;
156 static inline bool IsHiddenSP(RegisterOrSP r
) { return false; }
158 static inline Register
AsRegister(RegisterOrSP r
) { return r
; }
162 inline Register::SetType
Register::LiveAsIndexableSet
<RegTypeName::GPR
>(
168 inline Register::SetType
Register::LiveAsIndexableSet
<RegTypeName::Any
>(
174 inline Register::SetType
Register::AllocatableAsIndexableSet
<RegTypeName::GPR
>(
179 #if JS_BITS_PER_WORD == 32
180 // Note, some platform code depends on INT64LOW_OFFSET being zero.
181 static const uint32_t INT64LOW_OFFSET
= 0 * sizeof(int32_t);
182 static const uint32_t INT64HIGH_OFFSET
= 1 * sizeof(int32_t);
194 explicit constexpr Register64(Register r
) : reg(r
) {}
195 constexpr bool operator==(Register64 other
) const { return reg
== other
.reg
; }
196 constexpr bool operator!=(Register64 other
) const { return reg
!= other
.reg
; }
197 Register
scratchReg() { return reg
; }
198 static Register64
Invalid() { return Register64(Register::Invalid()); }
200 constexpr Register64(Register h
, Register l
) : high(h
), low(l
) {}
201 constexpr bool operator==(Register64 other
) const {
202 return high
== other
.high
&& low
== other
.low
;
204 constexpr bool operator!=(Register64 other
) const {
205 return high
!= other
.high
|| low
!= other
.low
;
207 Register
scratchReg() { return high
; }
208 Register
secondScratchReg() { return low
; }
209 static Register64
Invalid() {
210 return Register64(Register::Invalid(), Register::Invalid());
217 typedef mozilla::Array
<Registers::RegisterContent
, Registers::Total
> GPRArray
;
218 typedef mozilla::Array
<FloatRegisters::RegisterContent
,
219 FloatRegisters::TotalPhys
>
222 protected: // Silence Clang warning.
227 static size_t offsetOfRegister(Register reg
) {
228 return offsetof(RegisterDump
, regs_
) + reg
.code() * sizeof(uintptr_t);
230 static size_t offsetOfRegister(FloatRegister reg
) {
231 return offsetof(RegisterDump
, fpregs_
) + reg
.getRegisterDumpOffsetInBytes();
235 // Class for mapping each register to an offset.
236 class RegisterOffsets
{
237 mozilla::Array
<uint32_t, Registers::Total
> offsets_
;
239 // Sentinel value representing an uninitialized offset.
240 static constexpr uint32_t InvalidOffset
= UINT32_MAX
;
244 for (size_t i
= 0; i
< Registers::Total
; i
++) {
245 offsets_
[i
] = InvalidOffset
;
249 RegisterOffsets(const RegisterOffsets
&) = delete;
250 void operator=(const RegisterOffsets
&) = delete;
252 bool hasOffset(Register reg
) const {
253 return offsets_
[reg
.code()] != InvalidOffset
;
255 uint32_t getOffset(Register reg
) const {
256 MOZ_ASSERT(hasOffset(reg
));
257 return offsets_
[reg
.code()];
259 void setOffset(Register reg
, size_t offset
) {
260 MOZ_ASSERT(offset
< InvalidOffset
);
261 offsets_
[reg
.code()] = uint32_t(offset
);
265 class MacroAssembler
;
267 // Declares a register as owned within the scope of the object.
268 // In debug mode, owned register state is tracked within the MacroAssembler,
269 // and an assert will fire if ownership is conflicting.
270 // In contrast to ARM64's UseScratchRegisterScope, this class has no overhead
271 // in non-debug builds.
272 template <class RegisterType
>
273 struct AutoGenericRegisterScope
: public RegisterType
{
274 // Prevent MacroAssembler templates from creating copies,
275 // which causes the destructor to fire more than once.
276 AutoGenericRegisterScope(const AutoGenericRegisterScope
& other
) = delete;
279 MacroAssembler
& masm_
;
281 explicit AutoGenericRegisterScope(MacroAssembler
& masm
, RegisterType reg
);
282 ~AutoGenericRegisterScope();
286 constexpr explicit AutoGenericRegisterScope(MacroAssembler
& masm
,
288 : RegisterType(reg
) {}
294 using AutoRegisterScope
= AutoGenericRegisterScope
<Register
>;
295 using AutoFloatRegisterScope
= AutoGenericRegisterScope
<FloatRegister
>;
300 #endif /* jit_Registers_h */