Bug 1639153 - Part 1: Reserve two slots after stack arguments for the future tls...
[gecko.git] / js / src / jit / mips64 / Assembler-mips64.h
blob6f756b4ab2006d50f44f63f349ae54973eaa9e56
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_mips64_Assembler_mips64_h
8 #define jit_mips64_Assembler_mips64_h
10 #include "jit/mips-shared/Assembler-mips-shared.h"
12 #include "jit/mips64/Architecture-mips64.h"
14 namespace js {
15 namespace jit {
17 static constexpr Register CallTempReg4 = a4;
18 static constexpr Register CallTempReg5 = a5;
20 static constexpr Register CallTempNonArgRegs[] = {t0, t1, t2, t3};
21 static const uint32_t NumCallTempNonArgRegs =
22 mozilla::ArrayLength(CallTempNonArgRegs);
24 class ABIArgGenerator {
25 unsigned usedArgSlots_;
26 bool firstArgFloat;
27 ABIArg current_;
29 public:
30 ABIArgGenerator();
31 ABIArg next(MIRType argType);
32 ABIArg& current() { return current_; }
34 uint32_t stackBytesConsumedSoFar() const {
35 if (usedArgSlots_ <= 8) {
36 return 0;
39 return (usedArgSlots_ - 8) * sizeof(int64_t);
41 void increaseStackOffset(uint32_t bytes) { MOZ_CRASH("NYI"); }
44 // These registers may be volatile or nonvolatile.
45 static constexpr Register ABINonArgReg0 = t0;
46 static constexpr Register ABINonArgReg1 = t1;
47 static constexpr Register ABINonArgReg2 = t2;
48 static constexpr Register ABINonArgReg3 = t3;
50 // This register may be volatile or nonvolatile. Avoid f23 which is the
51 // ScratchDoubleReg.
52 static constexpr FloatRegister ABINonArgDoubleReg{FloatRegisters::f21,
53 FloatRegisters::Double};
55 // These registers may be volatile or nonvolatile.
56 // Note: these three registers are all guaranteed to be different
57 static constexpr Register ABINonArgReturnReg0 = t0;
58 static constexpr Register ABINonArgReturnReg1 = t1;
59 static constexpr Register ABINonVolatileReg = s0;
61 // This register is guaranteed to be clobberable during the prologue and
62 // epilogue of an ABI call which must preserve both ABI argument, return
63 // and non-volatile registers.
64 static constexpr Register ABINonArgReturnVolatileReg = t0;
66 // TLS pointer argument register for WebAssembly functions. This must not alias
67 // any other register used for passing function arguments or return values.
68 // Preserved by WebAssembly functions.
69 static constexpr Register WasmTlsReg = s5;
71 // Registers used for wasm table calls. These registers must be disjoint
72 // from the ABI argument registers, WasmTlsReg and each other.
73 static constexpr Register WasmTableCallScratchReg0 = ABINonArgReg0;
74 static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
75 static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
76 static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
78 // Register used as a scratch along the return path in the fast js -> wasm stub
79 // code. This must not overlap ReturnReg, JSReturnOperand, or WasmTlsReg. It
80 // must be a volatile register.
81 static constexpr Register WasmJitEntryReturnScratch = t1;
83 static constexpr Register InterpreterPCReg = t5;
85 static constexpr Register JSReturnReg = v1;
86 static constexpr Register JSReturnReg_Type = JSReturnReg;
87 static constexpr Register JSReturnReg_Data = JSReturnReg;
88 static constexpr Register64 ReturnReg64(ReturnReg);
89 static constexpr FloatRegister ReturnFloat32Reg = {FloatRegisters::f0,
90 FloatRegisters::Single};
91 static constexpr FloatRegister ReturnDoubleReg = {FloatRegisters::f0,
92 FloatRegisters::Double};
93 static constexpr FloatRegister ScratchFloat32Reg = {FloatRegisters::f23,
94 FloatRegisters::Single};
95 static constexpr FloatRegister ScratchDoubleReg = {FloatRegisters::f23,
96 FloatRegisters::Double};
98 struct ScratchFloat32Scope : public AutoFloatRegisterScope {
99 explicit ScratchFloat32Scope(MacroAssembler& masm)
100 : AutoFloatRegisterScope(masm, ScratchFloat32Reg) {}
103 struct ScratchDoubleScope : public AutoFloatRegisterScope {
104 explicit ScratchDoubleScope(MacroAssembler& masm)
105 : AutoFloatRegisterScope(masm, ScratchDoubleReg) {}
108 static constexpr FloatRegister f0 = {FloatRegisters::f0,
109 FloatRegisters::Double};
110 static constexpr FloatRegister f1 = {FloatRegisters::f1,
111 FloatRegisters::Double};
112 static constexpr FloatRegister f2 = {FloatRegisters::f2,
113 FloatRegisters::Double};
114 static constexpr FloatRegister f3 = {FloatRegisters::f3,
115 FloatRegisters::Double};
116 static constexpr FloatRegister f4 = {FloatRegisters::f4,
117 FloatRegisters::Double};
118 static constexpr FloatRegister f5 = {FloatRegisters::f5,
119 FloatRegisters::Double};
120 static constexpr FloatRegister f6 = {FloatRegisters::f6,
121 FloatRegisters::Double};
122 static constexpr FloatRegister f7 = {FloatRegisters::f7,
123 FloatRegisters::Double};
124 static constexpr FloatRegister f8 = {FloatRegisters::f8,
125 FloatRegisters::Double};
126 static constexpr FloatRegister f9 = {FloatRegisters::f9,
127 FloatRegisters::Double};
128 static constexpr FloatRegister f10 = {FloatRegisters::f10,
129 FloatRegisters::Double};
130 static constexpr FloatRegister f11 = {FloatRegisters::f11,
131 FloatRegisters::Double};
132 static constexpr FloatRegister f12 = {FloatRegisters::f12,
133 FloatRegisters::Double};
134 static constexpr FloatRegister f13 = {FloatRegisters::f13,
135 FloatRegisters::Double};
136 static constexpr FloatRegister f14 = {FloatRegisters::f14,
137 FloatRegisters::Double};
138 static constexpr FloatRegister f15 = {FloatRegisters::f15,
139 FloatRegisters::Double};
140 static constexpr FloatRegister f16 = {FloatRegisters::f16,
141 FloatRegisters::Double};
142 static constexpr FloatRegister f17 = {FloatRegisters::f17,
143 FloatRegisters::Double};
144 static constexpr FloatRegister f18 = {FloatRegisters::f18,
145 FloatRegisters::Double};
146 static constexpr FloatRegister f19 = {FloatRegisters::f19,
147 FloatRegisters::Double};
148 static constexpr FloatRegister f20 = {FloatRegisters::f20,
149 FloatRegisters::Double};
150 static constexpr FloatRegister f21 = {FloatRegisters::f21,
151 FloatRegisters::Double};
152 static constexpr FloatRegister f22 = {FloatRegisters::f22,
153 FloatRegisters::Double};
154 static constexpr FloatRegister f23 = {FloatRegisters::f23,
155 FloatRegisters::Double};
156 static constexpr FloatRegister f24 = {FloatRegisters::f24,
157 FloatRegisters::Double};
158 static constexpr FloatRegister f25 = {FloatRegisters::f25,
159 FloatRegisters::Double};
160 static constexpr FloatRegister f26 = {FloatRegisters::f26,
161 FloatRegisters::Double};
162 static constexpr FloatRegister f27 = {FloatRegisters::f27,
163 FloatRegisters::Double};
164 static constexpr FloatRegister f28 = {FloatRegisters::f28,
165 FloatRegisters::Double};
166 static constexpr FloatRegister f29 = {FloatRegisters::f29,
167 FloatRegisters::Double};
168 static constexpr FloatRegister f30 = {FloatRegisters::f30,
169 FloatRegisters::Double};
170 static constexpr FloatRegister f31 = {FloatRegisters::f31,
171 FloatRegisters::Double};
173 // MIPS64 CPUs can only load multibyte data that is "naturally"
174 // eight-byte-aligned, sp register should be sixteen-byte-aligned.
175 static constexpr uint32_t ABIStackAlignment = 16;
176 static constexpr uint32_t JitStackAlignment = 16;
178 static constexpr uint32_t JitStackValueAlignment =
179 JitStackAlignment / sizeof(Value);
180 static_assert(JitStackAlignment % sizeof(Value) == 0 &&
181 JitStackValueAlignment >= 1,
182 "Stack alignment should be a non-zero multiple of sizeof(Value)");
184 // TODO this is just a filler to prevent a build failure. The MIPS SIMD
185 // alignment requirements still need to be explored.
186 // TODO Copy the static_asserts from x64/x86 assembler files.
187 static constexpr uint32_t SimdMemoryAlignment = 16;
189 static constexpr uint32_t WasmStackAlignment = SimdMemoryAlignment;
190 static const uint32_t WasmTrapInstructionLength = 4;
192 // The offsets are dynamically asserted during
193 // code generation in the prologue/epilogue.
194 static constexpr uint32_t WasmCheckedCallEntryOffset = 0u;
195 static constexpr uint32_t WasmCheckedTailEntryOffset = 16u;
197 static constexpr Scale ScalePointer = TimesEight;
199 class Assembler : public AssemblerMIPSShared {
200 public:
201 Assembler() : AssemblerMIPSShared() {}
203 static uintptr_t GetPointer(uint8_t*);
205 using AssemblerMIPSShared::bind;
207 static void Bind(uint8_t* rawCode, const CodeLabel& label);
209 void processCodeLabels(uint8_t* rawCode);
211 static void TraceJumpRelocations(JSTracer* trc, JitCode* code,
212 CompactBufferReader& reader);
213 static void TraceDataRelocations(JSTracer* trc, JitCode* code,
214 CompactBufferReader& reader);
216 void bind(InstImm* inst, uintptr_t branch, uintptr_t target);
218 // Copy the assembly code to the given buffer, and perform any pending
219 // relocations relying on the target address.
220 void executableCopy(uint8_t* buffer);
222 static uint32_t PatchWrite_NearCallSize();
224 static uint64_t ExtractLoad64Value(Instruction* inst0);
225 static void UpdateLoad64Value(Instruction* inst0, uint64_t value);
226 static void WriteLoad64Instructions(Instruction* inst0, Register reg,
227 uint64_t value);
229 static void PatchWrite_NearCall(CodeLocationLabel start,
230 CodeLocationLabel toCall);
231 static void PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
232 ImmPtr expectedValue);
233 static void PatchDataWithValueCheck(CodeLocationLabel label,
234 PatchedImmPtr newValue,
235 PatchedImmPtr expectedValue);
237 static uint64_t ExtractInstructionImmediate(uint8_t* code);
239 static void ToggleCall(CodeLocationLabel inst_, bool enabled);
240 }; // Assembler
242 static const uint32_t NumIntArgRegs = 8;
243 static const uint32_t NumFloatArgRegs = NumIntArgRegs;
245 static inline bool GetIntArgReg(uint32_t usedArgSlots, Register* out) {
246 if (usedArgSlots < NumIntArgRegs) {
247 *out = Register::FromCode(a0.code() + usedArgSlots);
248 return true;
250 return false;
253 static inline bool GetFloatArgReg(uint32_t usedArgSlots, FloatRegister* out) {
254 if (usedArgSlots < NumFloatArgRegs) {
255 *out = FloatRegister::FromCode(f12.code() + usedArgSlots);
256 return true;
258 return false;
261 // Get a register in which we plan to put a quantity that will be used as an
262 // integer argument. This differs from GetIntArgReg in that if we have no more
263 // actual argument registers to use we will fall back on using whatever
264 // CallTempReg* don't overlap the argument registers, and only fail once those
265 // run out too.
266 static inline bool GetTempRegForIntArg(uint32_t usedIntArgs,
267 uint32_t usedFloatArgs, Register* out) {
268 // NOTE: We can't properly determine which regs are used if there are
269 // float arguments. If this is needed, we will have to guess.
270 MOZ_ASSERT(usedFloatArgs == 0);
272 if (GetIntArgReg(usedIntArgs, out)) {
273 return true;
275 // Unfortunately, we have to assume things about the point at which
276 // GetIntArgReg returns false, because we need to know how many registers it
277 // can allocate.
278 usedIntArgs -= NumIntArgRegs;
279 if (usedIntArgs >= NumCallTempNonArgRegs) {
280 return false;
282 *out = CallTempNonArgRegs[usedIntArgs];
283 return true;
286 static inline uint32_t GetArgStackDisp(uint32_t usedArgSlots) {
287 MOZ_ASSERT(usedArgSlots >= NumIntArgRegs);
288 return (usedArgSlots - NumIntArgRegs) * sizeof(int64_t);
291 } // namespace jit
292 } // namespace js
294 #endif /* jit_mips64_Assembler_mips64_h */