1/*
2 * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "RegisterSet.h"
28
29#if ENABLE(ASSEMBLER)
30
31#include "GPRInfo.h"
32#include "JSCInlines.h"
33#include "MacroAssembler.h"
34#include "RegisterAtOffsetList.h"
35#include <wtf/CommaPrinter.h>
36
37namespace JSC {
38
39RegisterSet RegisterSet::stackRegisters()
40{
41 return RegisterSet(
42 MacroAssembler::stackPointerRegister,
43 MacroAssembler::framePointerRegister);
44}
45
46RegisterSet RegisterSet::reservedHardwareRegisters()
47{
48#if CPU(ARM64)
49#if PLATFORM(IOS_FAMILY)
50 return RegisterSet(ARM64Registers::x18, ARM64Registers::lr);
51#else
52 return RegisterSet(ARM64Registers::lr);
53#endif // PLATFORM(IOS_FAMILY)
54#elif CPU(ARM_THUMB2)
55 return RegisterSet(ARMRegisters::lr, ARMRegisters::pc);
56#else
57 return { };
58#endif
59}
60
61RegisterSet RegisterSet::runtimeTagRegisters()
62{
63#if USE(JSVALUE64)
64 return RegisterSet(GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
65#else
66 return { };
67#endif
68}
69
70RegisterSet RegisterSet::specialRegisters()
71{
72 return RegisterSet(
73 stackRegisters(), reservedHardwareRegisters(), runtimeTagRegisters());
74}
75
76RegisterSet RegisterSet::volatileRegistersForJSCall()
77{
78 RegisterSet volatileRegisters = allRegisters();
79 volatileRegisters.exclude(RegisterSet::stackRegisters());
80 volatileRegisters.exclude(RegisterSet::reservedHardwareRegisters());
81 volatileRegisters.exclude(RegisterSet::vmCalleeSaveRegisters());
82 return volatileRegisters;
83}
84
85RegisterSet RegisterSet::stubUnavailableRegisters()
86{
87 // FIXME: This is overly conservative. We could subtract out those callee-saves that we
88 // actually saved.
89 // https://bugs.webkit.org/show_bug.cgi?id=185686
90 return RegisterSet(specialRegisters(), vmCalleeSaveRegisters());
91}
92
93RegisterSet RegisterSet::macroScratchRegisters()
94{
95#if CPU(X86_64)
96 return RegisterSet(MacroAssembler::s_scratchRegister);
97#elif CPU(ARM64)
98 return RegisterSet(MacroAssembler::dataTempRegister, MacroAssembler::memoryTempRegister);
99#elif CPU(MIPS)
100 RegisterSet result;
101 result.set(MacroAssembler::immTempRegister);
102 result.set(MacroAssembler::dataTempRegister);
103 result.set(MacroAssembler::addrTempRegister);
104 result.set(MacroAssembler::cmpTempRegister);
105 return result;
106#else
107 return { };
108#endif
109}
110
111RegisterSet RegisterSet::calleeSaveRegisters()
112{
113 RegisterSet result;
114#if CPU(X86)
115 result.set(X86Registers::ebx);
116 result.set(X86Registers::ebp);
117 result.set(X86Registers::edi);
118 result.set(X86Registers::esi);
119#elif CPU(X86_64)
120 result.set(X86Registers::ebx);
121 result.set(X86Registers::ebp);
122#if OS(WINDOWS)
123 result.set(X86Registers::edi);
124 result.set(X86Registers::esi);
125#endif
126 result.set(X86Registers::r12);
127 result.set(X86Registers::r13);
128 result.set(X86Registers::r14);
129 result.set(X86Registers::r15);
130#elif CPU(ARM_THUMB2)
131 result.set(ARMRegisters::r4);
132 result.set(ARMRegisters::r5);
133 result.set(ARMRegisters::r6);
134 result.set(ARMRegisters::r8);
135#if !PLATFORM(IOS_FAMILY)
136 result.set(ARMRegisters::r9);
137#endif
138 result.set(ARMRegisters::r10);
139 result.set(ARMRegisters::r11);
140#elif CPU(ARM64)
141 // We don't include LR in the set of callee-save registers even though it technically belongs
142 // there. This is because we use this set to describe the set of registers that need to be saved
143 // beyond what you would save by the platform-agnostic "preserve return address" and "restore
144 // return address" operations in CCallHelpers.
145 for (
146 ARM64Registers::RegisterID reg = ARM64Registers::x19;
147 reg <= ARM64Registers::x28;
148 reg = static_cast<ARM64Registers::RegisterID>(reg + 1))
149 result.set(reg);
150 result.set(ARM64Registers::fp);
151 for (
152 ARM64Registers::FPRegisterID reg = ARM64Registers::q8;
153 reg <= ARM64Registers::q15;
154 reg = static_cast<ARM64Registers::FPRegisterID>(reg + 1))
155 result.set(reg);
156#elif CPU(MIPS)
157 result.set(MIPSRegisters::s0);
158#else
159 UNREACHABLE_FOR_PLATFORM();
160#endif
161 return result;
162}
163
164RegisterSet RegisterSet::vmCalleeSaveRegisters()
165{
166 RegisterSet result;
167#if CPU(X86_64)
168 result.set(GPRInfo::regCS0);
169 result.set(GPRInfo::regCS1);
170 result.set(GPRInfo::regCS2);
171 result.set(GPRInfo::regCS3);
172 result.set(GPRInfo::regCS4);
173#if OS(WINDOWS)
174 result.set(GPRInfo::regCS5);
175 result.set(GPRInfo::regCS6);
176#endif
177#elif CPU(ARM64)
178 result.set(GPRInfo::regCS0);
179 result.set(GPRInfo::regCS1);
180 result.set(GPRInfo::regCS2);
181 result.set(GPRInfo::regCS3);
182 result.set(GPRInfo::regCS4);
183 result.set(GPRInfo::regCS5);
184 result.set(GPRInfo::regCS6);
185 result.set(GPRInfo::regCS7);
186 result.set(GPRInfo::regCS8);
187 result.set(GPRInfo::regCS9);
188 result.set(FPRInfo::fpRegCS0);
189 result.set(FPRInfo::fpRegCS1);
190 result.set(FPRInfo::fpRegCS2);
191 result.set(FPRInfo::fpRegCS3);
192 result.set(FPRInfo::fpRegCS4);
193 result.set(FPRInfo::fpRegCS5);
194 result.set(FPRInfo::fpRegCS6);
195 result.set(FPRInfo::fpRegCS7);
196#elif CPU(ARM_THUMB2) || CPU(MIPS)
197 result.set(GPRInfo::regCS0);
198#endif
199 return result;
200}
201
202RegisterAtOffsetList* RegisterSet::vmCalleeSaveRegisterOffsets()
203{
204 static RegisterAtOffsetList* result;
205 static std::once_flag calleeSavesFlag;
206 std::call_once(calleeSavesFlag, [] () {
207 result = new RegisterAtOffsetList(vmCalleeSaveRegisters(), RegisterAtOffsetList::ZeroBased);
208 });
209 return result;
210}
211
212RegisterSet RegisterSet::llintBaselineCalleeSaveRegisters()
213{
214 RegisterSet result;
215#if CPU(X86)
216#elif CPU(X86_64)
217#if !OS(WINDOWS)
218 result.set(GPRInfo::regCS1);
219 result.set(GPRInfo::regCS2);
220 ASSERT(GPRInfo::regCS3 == GPRInfo::tagTypeNumberRegister);
221 ASSERT(GPRInfo::regCS4 == GPRInfo::tagMaskRegister);
222 result.set(GPRInfo::regCS3);
223 result.set(GPRInfo::regCS4);
224#else
225 result.set(GPRInfo::regCS3);
226 result.set(GPRInfo::regCS4);
227 ASSERT(GPRInfo::regCS5 == GPRInfo::tagTypeNumberRegister);
228 ASSERT(GPRInfo::regCS6 == GPRInfo::tagMaskRegister);
229 result.set(GPRInfo::regCS5);
230 result.set(GPRInfo::regCS6);
231#endif
232#elif CPU(ARM_THUMB2)
233 result.set(GPRInfo::regCS0);
234#elif CPU(ARM64)
235 result.set(GPRInfo::regCS6);
236 result.set(GPRInfo::regCS7);
237 ASSERT(GPRInfo::regCS8 == GPRInfo::tagTypeNumberRegister);
238 ASSERT(GPRInfo::regCS9 == GPRInfo::tagMaskRegister);
239 result.set(GPRInfo::regCS8);
240 result.set(GPRInfo::regCS9);
241#elif CPU(MIPS)
242 result.set(GPRInfo::regCS0);
243#else
244 UNREACHABLE_FOR_PLATFORM();
245#endif
246 return result;
247}
248
249RegisterSet RegisterSet::dfgCalleeSaveRegisters()
250{
251 RegisterSet result;
252#if CPU(X86)
253#elif CPU(X86_64)
254 result.set(GPRInfo::regCS0);
255 result.set(GPRInfo::regCS1);
256 result.set(GPRInfo::regCS2);
257#if !OS(WINDOWS)
258 ASSERT(GPRInfo::regCS3 == GPRInfo::tagTypeNumberRegister);
259 ASSERT(GPRInfo::regCS4 == GPRInfo::tagMaskRegister);
260 result.set(GPRInfo::regCS3);
261 result.set(GPRInfo::regCS4);
262#else
263 result.set(GPRInfo::regCS3);
264 result.set(GPRInfo::regCS4);
265 ASSERT(GPRInfo::regCS5 == GPRInfo::tagTypeNumberRegister);
266 ASSERT(GPRInfo::regCS6 == GPRInfo::tagMaskRegister);
267 result.set(GPRInfo::regCS5);
268 result.set(GPRInfo::regCS6);
269#endif
270#elif CPU(ARM_THUMB2)
271#elif CPU(ARM64)
272 ASSERT(GPRInfo::regCS8 == GPRInfo::tagTypeNumberRegister);
273 ASSERT(GPRInfo::regCS9 == GPRInfo::tagMaskRegister);
274 result.set(GPRInfo::regCS8);
275 result.set(GPRInfo::regCS9);
276#elif CPU(MIPS)
277#else
278 UNREACHABLE_FOR_PLATFORM();
279#endif
280 return result;
281}
282
283RegisterSet RegisterSet::ftlCalleeSaveRegisters()
284{
285 RegisterSet result;
286#if ENABLE(FTL_JIT)
287#if CPU(X86_64) && !OS(WINDOWS)
288 result.set(GPRInfo::regCS0);
289 result.set(GPRInfo::regCS1);
290 result.set(GPRInfo::regCS2);
291 ASSERT(GPRInfo::regCS3 == GPRInfo::tagTypeNumberRegister);
292 ASSERT(GPRInfo::regCS4 == GPRInfo::tagMaskRegister);
293 result.set(GPRInfo::regCS3);
294 result.set(GPRInfo::regCS4);
295#elif CPU(ARM64)
296 // B3 might save and use all ARM64 callee saves specified in the ABI.
297 result.set(GPRInfo::regCS0);
298 result.set(GPRInfo::regCS1);
299 result.set(GPRInfo::regCS2);
300 result.set(GPRInfo::regCS3);
301 result.set(GPRInfo::regCS4);
302 result.set(GPRInfo::regCS5);
303 result.set(GPRInfo::regCS6);
304 result.set(GPRInfo::regCS7);
305 ASSERT(GPRInfo::regCS8 == GPRInfo::tagTypeNumberRegister);
306 ASSERT(GPRInfo::regCS9 == GPRInfo::tagMaskRegister);
307 result.set(GPRInfo::regCS8);
308 result.set(GPRInfo::regCS9);
309 result.set(FPRInfo::fpRegCS0);
310 result.set(FPRInfo::fpRegCS1);
311 result.set(FPRInfo::fpRegCS2);
312 result.set(FPRInfo::fpRegCS3);
313 result.set(FPRInfo::fpRegCS4);
314 result.set(FPRInfo::fpRegCS5);
315 result.set(FPRInfo::fpRegCS6);
316 result.set(FPRInfo::fpRegCS7);
317#else
318 UNREACHABLE_FOR_PLATFORM();
319#endif
320#endif
321 return result;
322}
323
324RegisterSet RegisterSet::argumentGPRS()
325{
326 RegisterSet result;
327#if NUMBER_OF_ARGUMENT_REGISTERS
328 for (unsigned i = 0; i < GPRInfo::numberOfArgumentRegisters; i++)
329 result.set(GPRInfo::toArgumentRegister(i));
330#endif
331 return result;
332}
333
334RegisterSet RegisterSet::registersToNotSaveForJSCall()
335{
336 return RegisterSet(RegisterSet::vmCalleeSaveRegisters(), RegisterSet::stackRegisters(), RegisterSet::reservedHardwareRegisters());
337}
338
339RegisterSet RegisterSet::registersToNotSaveForCCall()
340{
341 return RegisterSet(RegisterSet::calleeSaveRegisters(), RegisterSet::stackRegisters(), RegisterSet::reservedHardwareRegisters());
342}
343
344RegisterSet RegisterSet::allGPRs()
345{
346 RegisterSet result;
347 for (MacroAssembler::RegisterID reg = MacroAssembler::firstRegister(); reg <= MacroAssembler::lastRegister(); reg = static_cast<MacroAssembler::RegisterID>(reg + 1))
348 result.set(reg);
349 return result;
350}
351
352RegisterSet RegisterSet::allFPRs()
353{
354 RegisterSet result;
355 for (MacroAssembler::FPRegisterID reg = MacroAssembler::firstFPRegister(); reg <= MacroAssembler::lastFPRegister(); reg = static_cast<MacroAssembler::FPRegisterID>(reg + 1))
356 result.set(reg);
357 return result;
358}
359
360RegisterSet RegisterSet::allRegisters()
361{
362 RegisterSet result;
363 result.merge(allGPRs());
364 result.merge(allFPRs());
365 return result;
366}
367
368size_t RegisterSet::numberOfSetGPRs() const
369{
370 RegisterSet temp = *this;
371 temp.filter(allGPRs());
372 return temp.numberOfSetRegisters();
373}
374
375size_t RegisterSet::numberOfSetFPRs() const
376{
377 RegisterSet temp = *this;
378 temp.filter(allFPRs());
379 return temp.numberOfSetRegisters();
380}
381
382void RegisterSet::dump(PrintStream& out) const
383{
384 CommaPrinter comma;
385 out.print("[");
386 for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
387 if (get(reg))
388 out.print(comma, reg);
389 }
390 out.print("]");
391}
392
393} // namespace JSC
394
395#endif // ENABLE(ASSEMBLER)
396
397