1/*
2 * Copyright (C) 2013-2019 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 "assembler/RegisterInfo.h"
36#include <wtf/CommaPrinter.h>
37
38namespace JSC {
39
40RegisterSet RegisterSet::stackRegisters()
41{
42 return RegisterSet(
43 MacroAssembler::stackPointerRegister,
44 MacroAssembler::framePointerRegister);
45}
46
47RegisterSet RegisterSet::reservedHardwareRegisters()
48{
49 RegisterSet result;
50
51#define SET_IF_RESERVED(id, name, isReserved, isCalleeSaved) \
52 if (isReserved) \
53 result.set(RegisterNames::id);
54 FOR_EACH_GP_REGISTER(SET_IF_RESERVED)
55 FOR_EACH_FP_REGISTER(SET_IF_RESERVED)
56#undef SET_IF_RESERVED
57
58 return result;
59}
60
61RegisterSet RegisterSet::runtimeTagRegisters()
62{
63#if USE(JSVALUE64)
64 return RegisterSet(GPRInfo::numberTagRegister, GPRInfo::notCellMaskRegister);
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
115#define SET_IF_CALLEESAVED(id, name, isReserved, isCalleeSaved) \
116 if (isCalleeSaved) \
117 result.set(RegisterNames::id);
118 FOR_EACH_GP_REGISTER(SET_IF_CALLEESAVED)
119 FOR_EACH_FP_REGISTER(SET_IF_CALLEESAVED)
120#undef SET_IF_CALLEESAVED
121
122 return result;
123}
124
125RegisterSet RegisterSet::vmCalleeSaveRegisters()
126{
127 RegisterSet result;
128#if CPU(X86_64)
129 result.set(GPRInfo::regCS0);
130 result.set(GPRInfo::regCS1);
131 result.set(GPRInfo::regCS2);
132 result.set(GPRInfo::regCS3);
133 result.set(GPRInfo::regCS4);
134#if OS(WINDOWS)
135 result.set(GPRInfo::regCS5);
136 result.set(GPRInfo::regCS6);
137#endif
138#elif CPU(ARM64)
139 result.set(GPRInfo::regCS0);
140 result.set(GPRInfo::regCS1);
141 result.set(GPRInfo::regCS2);
142 result.set(GPRInfo::regCS3);
143 result.set(GPRInfo::regCS4);
144 result.set(GPRInfo::regCS5);
145 result.set(GPRInfo::regCS6);
146 result.set(GPRInfo::regCS7);
147 result.set(GPRInfo::regCS8);
148 result.set(GPRInfo::regCS9);
149 result.set(FPRInfo::fpRegCS0);
150 result.set(FPRInfo::fpRegCS1);
151 result.set(FPRInfo::fpRegCS2);
152 result.set(FPRInfo::fpRegCS3);
153 result.set(FPRInfo::fpRegCS4);
154 result.set(FPRInfo::fpRegCS5);
155 result.set(FPRInfo::fpRegCS6);
156 result.set(FPRInfo::fpRegCS7);
157#elif CPU(ARM_THUMB2) || CPU(MIPS)
158 result.set(GPRInfo::regCS0);
159#endif
160 return result;
161}
162
163RegisterAtOffsetList* RegisterSet::vmCalleeSaveRegisterOffsets()
164{
165 static RegisterAtOffsetList* result;
166 static std::once_flag calleeSavesFlag;
167 std::call_once(calleeSavesFlag, [] () {
168 result = new RegisterAtOffsetList(vmCalleeSaveRegisters(), RegisterAtOffsetList::ZeroBased);
169 });
170 return result;
171}
172
173RegisterSet RegisterSet::llintBaselineCalleeSaveRegisters()
174{
175 RegisterSet result;
176#if CPU(X86)
177#elif CPU(X86_64)
178#if !OS(WINDOWS)
179 result.set(GPRInfo::regCS1);
180 result.set(GPRInfo::regCS2);
181 static_assert(GPRInfo::regCS3 == GPRInfo::numberTagRegister, "");
182 static_assert(GPRInfo::regCS4 == GPRInfo::notCellMaskRegister, "");
183 result.set(GPRInfo::regCS3);
184 result.set(GPRInfo::regCS4);
185#else
186 result.set(GPRInfo::regCS3);
187 result.set(GPRInfo::regCS4);
188 static_assert(GPRInfo::regCS5 == GPRInfo::numberTagRegister, "");
189 static_assert(GPRInfo::regCS6 == GPRInfo::notCellMaskRegister, "");
190 result.set(GPRInfo::regCS5);
191 result.set(GPRInfo::regCS6);
192#endif
193#elif CPU(ARM_THUMB2)
194 result.set(GPRInfo::regCS0);
195#elif CPU(ARM64)
196 result.set(GPRInfo::regCS6);
197 result.set(GPRInfo::regCS7);
198 static_assert(GPRInfo::regCS8 == GPRInfo::numberTagRegister, "");
199 static_assert(GPRInfo::regCS9 == GPRInfo::notCellMaskRegister, "");
200 result.set(GPRInfo::regCS8);
201 result.set(GPRInfo::regCS9);
202#elif CPU(MIPS)
203 result.set(GPRInfo::regCS0);
204#else
205 UNREACHABLE_FOR_PLATFORM();
206#endif
207 return result;
208}
209
210RegisterSet RegisterSet::dfgCalleeSaveRegisters()
211{
212 RegisterSet result;
213#if CPU(X86)
214#elif CPU(X86_64)
215 result.set(GPRInfo::regCS0);
216 result.set(GPRInfo::regCS1);
217 result.set(GPRInfo::regCS2);
218#if !OS(WINDOWS)
219 static_assert(GPRInfo::regCS3 == GPRInfo::numberTagRegister, "");
220 static_assert(GPRInfo::regCS4 == GPRInfo::notCellMaskRegister, "");
221 result.set(GPRInfo::regCS3);
222 result.set(GPRInfo::regCS4);
223#else
224 result.set(GPRInfo::regCS3);
225 result.set(GPRInfo::regCS4);
226 static_assert(GPRInfo::regCS5 == GPRInfo::numberTagRegister, "");
227 static_assert(GPRInfo::regCS6 == GPRInfo::notCellMaskRegister, "");
228 result.set(GPRInfo::regCS5);
229 result.set(GPRInfo::regCS6);
230#endif
231#elif CPU(ARM_THUMB2)
232#elif CPU(ARM64)
233 static_assert(GPRInfo::regCS8 == GPRInfo::numberTagRegister, "");
234 static_assert(GPRInfo::regCS9 == GPRInfo::notCellMaskRegister, "");
235 result.set(GPRInfo::regCS8);
236 result.set(GPRInfo::regCS9);
237#elif CPU(MIPS)
238#else
239 UNREACHABLE_FOR_PLATFORM();
240#endif
241 return result;
242}
243
244RegisterSet RegisterSet::ftlCalleeSaveRegisters()
245{
246 RegisterSet result;
247#if ENABLE(FTL_JIT)
248#if CPU(X86_64) && !OS(WINDOWS)
249 result.set(GPRInfo::regCS0);
250 result.set(GPRInfo::regCS1);
251 result.set(GPRInfo::regCS2);
252 static_assert(GPRInfo::regCS3 == GPRInfo::numberTagRegister, "");
253 static_assert(GPRInfo::regCS4 == GPRInfo::notCellMaskRegister, "");
254 result.set(GPRInfo::regCS3);
255 result.set(GPRInfo::regCS4);
256#elif CPU(ARM64)
257 // B3 might save and use all ARM64 callee saves specified in the ABI.
258 result.set(GPRInfo::regCS0);
259 result.set(GPRInfo::regCS1);
260 result.set(GPRInfo::regCS2);
261 result.set(GPRInfo::regCS3);
262 result.set(GPRInfo::regCS4);
263 result.set(GPRInfo::regCS5);
264 result.set(GPRInfo::regCS6);
265 result.set(GPRInfo::regCS7);
266 static_assert(GPRInfo::regCS8 == GPRInfo::numberTagRegister, "");
267 static_assert(GPRInfo::regCS9 == GPRInfo::notCellMaskRegister, "");
268 result.set(GPRInfo::regCS8);
269 result.set(GPRInfo::regCS9);
270 result.set(FPRInfo::fpRegCS0);
271 result.set(FPRInfo::fpRegCS1);
272 result.set(FPRInfo::fpRegCS2);
273 result.set(FPRInfo::fpRegCS3);
274 result.set(FPRInfo::fpRegCS4);
275 result.set(FPRInfo::fpRegCS5);
276 result.set(FPRInfo::fpRegCS6);
277 result.set(FPRInfo::fpRegCS7);
278#else
279 UNREACHABLE_FOR_PLATFORM();
280#endif
281#endif
282 return result;
283}
284
285RegisterSet RegisterSet::argumentGPRS()
286{
287 RegisterSet result;
288#if NUMBER_OF_ARGUMENT_REGISTERS
289 for (unsigned i = 0; i < GPRInfo::numberOfArgumentRegisters; i++)
290 result.set(GPRInfo::toArgumentRegister(i));
291#endif
292 return result;
293}
294
295RegisterSet RegisterSet::registersToNotSaveForJSCall()
296{
297 return RegisterSet(RegisterSet::vmCalleeSaveRegisters(), RegisterSet::stackRegisters(), RegisterSet::reservedHardwareRegisters());
298}
299
300RegisterSet RegisterSet::registersToNotSaveForCCall()
301{
302 return RegisterSet(RegisterSet::calleeSaveRegisters(), RegisterSet::stackRegisters(), RegisterSet::reservedHardwareRegisters());
303}
304
305RegisterSet RegisterSet::allGPRs()
306{
307 RegisterSet result;
308 for (MacroAssembler::RegisterID reg = MacroAssembler::firstRegister(); reg <= MacroAssembler::lastRegister(); reg = static_cast<MacroAssembler::RegisterID>(reg + 1))
309 result.set(reg);
310 return result;
311}
312
313RegisterSet RegisterSet::allFPRs()
314{
315 RegisterSet result;
316 for (MacroAssembler::FPRegisterID reg = MacroAssembler::firstFPRegister(); reg <= MacroAssembler::lastFPRegister(); reg = static_cast<MacroAssembler::FPRegisterID>(reg + 1))
317 result.set(reg);
318 return result;
319}
320
321RegisterSet RegisterSet::allRegisters()
322{
323 RegisterSet result;
324 result.merge(allGPRs());
325 result.merge(allFPRs());
326 return result;
327}
328
329size_t RegisterSet::numberOfSetGPRs() const
330{
331 RegisterSet temp = *this;
332 temp.filter(allGPRs());
333 return temp.numberOfSetRegisters();
334}
335
336size_t RegisterSet::numberOfSetFPRs() const
337{
338 RegisterSet temp = *this;
339 temp.filter(allFPRs());
340 return temp.numberOfSetRegisters();
341}
342
343void RegisterSet::dump(PrintStream& out) const
344{
345 CommaPrinter comma;
346 out.print("[");
347 for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
348 if (get(reg))
349 out.print(comma, reg);
350 }
351 out.print("]");
352}
353
354} // namespace JSC
355
356#endif // ENABLE(ASSEMBLER)
357
358