1/*
2 * Copyright (C) 2011-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#pragma once
27
28#include "MacroAssembler.h"
29#include <wtf/PrintStream.h>
30
31namespace JSC {
32
33typedef MacroAssembler::FPRegisterID FPRReg;
34static constexpr FPRReg InvalidFPRReg { FPRReg::InvalidFPRReg };
35
36#if ENABLE(ASSEMBLER)
37
38#if CPU(X86) || CPU(X86_64)
39
40class FPRInfo {
41public:
42 typedef FPRReg RegisterType;
43 static constexpr unsigned numberOfRegisters = 6;
44 static constexpr unsigned numberOfArgumentRegisters = is64Bit() ? 8 : 0;
45
46 // Temporary registers.
47 static constexpr FPRReg fpRegT0 = X86Registers::xmm0;
48 static constexpr FPRReg fpRegT1 = X86Registers::xmm1;
49 static constexpr FPRReg fpRegT2 = X86Registers::xmm2;
50 static constexpr FPRReg fpRegT3 = X86Registers::xmm3;
51 static constexpr FPRReg fpRegT4 = X86Registers::xmm4;
52 static constexpr FPRReg fpRegT5 = X86Registers::xmm5;
53#if CPU(X86_64)
54 // Only X86_64 passes aguments in xmm registers
55 static constexpr FPRReg argumentFPR0 = X86Registers::xmm0; // fpRegT0
56 static constexpr FPRReg argumentFPR1 = X86Registers::xmm1; // fpRegT1
57 static constexpr FPRReg argumentFPR2 = X86Registers::xmm2; // fpRegT2
58 static constexpr FPRReg argumentFPR3 = X86Registers::xmm3; // fpRegT3
59 static constexpr FPRReg argumentFPR4 = X86Registers::xmm4; // fpRegT4
60 static constexpr FPRReg argumentFPR5 = X86Registers::xmm5; // fpRegT5
61 static constexpr FPRReg argumentFPR6 = X86Registers::xmm6;
62 static constexpr FPRReg argumentFPR7 = X86Registers::xmm7;
63#endif
64 // On X86 the return will actually be on the x87 stack,
65 // so we'll copy to xmm0 for sanity!
66 static constexpr FPRReg returnValueFPR = X86Registers::xmm0; // fpRegT0
67
68 // FPRReg mapping is direct, the machine regsiter numbers can
69 // be used directly as indices into the FPR RegisterBank.
70 COMPILE_ASSERT(X86Registers::xmm0 == 0, xmm0_is_0);
71 COMPILE_ASSERT(X86Registers::xmm1 == 1, xmm1_is_1);
72 COMPILE_ASSERT(X86Registers::xmm2 == 2, xmm2_is_2);
73 COMPILE_ASSERT(X86Registers::xmm3 == 3, xmm3_is_3);
74 COMPILE_ASSERT(X86Registers::xmm4 == 4, xmm4_is_4);
75 COMPILE_ASSERT(X86Registers::xmm5 == 5, xmm5_is_5);
76 static FPRReg toRegister(unsigned index)
77 {
78 return (FPRReg)index;
79 }
80 static unsigned toIndex(FPRReg reg)
81 {
82 unsigned result = (unsigned)reg;
83 if (result >= numberOfRegisters)
84 return InvalidIndex;
85 return result;
86 }
87
88 static FPRReg toArgumentRegister(unsigned index)
89 {
90 return (FPRReg)index;
91 }
92
93 static const char* debugName(FPRReg reg)
94 {
95 ASSERT(reg != InvalidFPRReg);
96 return MacroAssembler::fprName(reg);
97 }
98
99 static constexpr unsigned InvalidIndex = 0xffffffff;
100};
101
102#endif // CPU(X86) || CPU(X86_64)
103
104#if CPU(ARM)
105
106class FPRInfo {
107public:
108 typedef FPRReg RegisterType;
109 static constexpr unsigned numberOfRegisters = 6;
110
111#if CPU(ARM_HARDFP)
112 static constexpr unsigned numberOfArgumentRegisters = 8;
113#else
114 static constexpr unsigned numberOfArgumentRegisters = 0;
115#endif
116
117 // Temporary registers.
118 // d7 is use by the MacroAssembler as fpTempRegister.
119 static constexpr FPRReg fpRegT0 = ARMRegisters::d0;
120 static constexpr FPRReg fpRegT1 = ARMRegisters::d1;
121 static constexpr FPRReg fpRegT2 = ARMRegisters::d2;
122 static constexpr FPRReg fpRegT3 = ARMRegisters::d3;
123 static constexpr FPRReg fpRegT4 = ARMRegisters::d4;
124 static constexpr FPRReg fpRegT5 = ARMRegisters::d5;
125 // ARMv7 doesn't pass arguments in fp registers. The return
126 // value is also actually in integer registers, for now
127 // we'll return in d0 for simplicity.
128 static constexpr FPRReg returnValueFPR = ARMRegisters::d0; // fpRegT0
129
130#if CPU(ARM_HARDFP)
131 static constexpr FPRReg argumentFPR0 = ARMRegisters::d0; // fpRegT0
132 static constexpr FPRReg argumentFPR1 = ARMRegisters::d1; // fpRegT1
133#endif
134
135 // FPRReg mapping is direct, the machine regsiter numbers can
136 // be used directly as indices into the FPR RegisterBank.
137 COMPILE_ASSERT(ARMRegisters::d0 == 0, d0_is_0);
138 COMPILE_ASSERT(ARMRegisters::d1 == 1, d1_is_1);
139 COMPILE_ASSERT(ARMRegisters::d2 == 2, d2_is_2);
140 COMPILE_ASSERT(ARMRegisters::d3 == 3, d3_is_3);
141 COMPILE_ASSERT(ARMRegisters::d4 == 4, d4_is_4);
142 COMPILE_ASSERT(ARMRegisters::d5 == 5, d5_is_5);
143 static FPRReg toRegister(unsigned index)
144 {
145 return (FPRReg)index;
146 }
147 static unsigned toIndex(FPRReg reg)
148 {
149 return (unsigned)reg;
150 }
151
152#if CPU(ARM_HARDFP)
153 static FPRReg toArgumentRegister(unsigned index)
154 {
155 ASSERT(index < numberOfArgumentRegisters);
156 return static_cast<FPRReg>(index);
157 }
158#endif
159
160 static const char* debugName(FPRReg reg)
161 {
162 ASSERT(reg != InvalidFPRReg);
163 return MacroAssembler::fprName(reg);
164 }
165
166 static constexpr unsigned InvalidIndex = 0xffffffff;
167};
168
169#endif // CPU(ARM)
170
171#if CPU(ARM64)
172
173class FPRInfo {
174public:
175 typedef FPRReg RegisterType;
176 static constexpr unsigned numberOfRegisters = 23;
177 static constexpr unsigned numberOfArgumentRegisters = 8;
178
179 // Temporary registers.
180 // q8-q15 are callee saved, q31 is use by the MacroAssembler as fpTempRegister.
181 static constexpr FPRReg fpRegT0 = ARM64Registers::q0;
182 static constexpr FPRReg fpRegT1 = ARM64Registers::q1;
183 static constexpr FPRReg fpRegT2 = ARM64Registers::q2;
184 static constexpr FPRReg fpRegT3 = ARM64Registers::q3;
185 static constexpr FPRReg fpRegT4 = ARM64Registers::q4;
186 static constexpr FPRReg fpRegT5 = ARM64Registers::q5;
187 static constexpr FPRReg fpRegT6 = ARM64Registers::q6;
188 static constexpr FPRReg fpRegT7 = ARM64Registers::q7;
189 static constexpr FPRReg fpRegT8 = ARM64Registers::q16;
190 static constexpr FPRReg fpRegT9 = ARM64Registers::q17;
191 static constexpr FPRReg fpRegT10 = ARM64Registers::q18;
192 static constexpr FPRReg fpRegT11 = ARM64Registers::q19;
193 static constexpr FPRReg fpRegT12 = ARM64Registers::q20;
194 static constexpr FPRReg fpRegT13 = ARM64Registers::q21;
195 static constexpr FPRReg fpRegT14 = ARM64Registers::q22;
196 static constexpr FPRReg fpRegT15 = ARM64Registers::q23;
197 static constexpr FPRReg fpRegT16 = ARM64Registers::q24;
198 static constexpr FPRReg fpRegT17 = ARM64Registers::q25;
199 static constexpr FPRReg fpRegT18 = ARM64Registers::q26;
200 static constexpr FPRReg fpRegT19 = ARM64Registers::q27;
201 static constexpr FPRReg fpRegT20 = ARM64Registers::q28;
202 static constexpr FPRReg fpRegT21 = ARM64Registers::q29;
203 static constexpr FPRReg fpRegT22 = ARM64Registers::q30;
204 static constexpr FPRReg fpRegCS0 = ARM64Registers::q8;
205 static constexpr FPRReg fpRegCS1 = ARM64Registers::q9;
206 static constexpr FPRReg fpRegCS2 = ARM64Registers::q10;
207 static constexpr FPRReg fpRegCS3 = ARM64Registers::q11;
208 static constexpr FPRReg fpRegCS4 = ARM64Registers::q12;
209 static constexpr FPRReg fpRegCS5 = ARM64Registers::q13;
210 static constexpr FPRReg fpRegCS6 = ARM64Registers::q14;
211 static constexpr FPRReg fpRegCS7 = ARM64Registers::q15;
212
213 static constexpr FPRReg argumentFPR0 = ARM64Registers::q0; // fpRegT0
214 static constexpr FPRReg argumentFPR1 = ARM64Registers::q1; // fpRegT1
215 static constexpr FPRReg argumentFPR2 = ARM64Registers::q2; // fpRegT2
216 static constexpr FPRReg argumentFPR3 = ARM64Registers::q3; // fpRegT3
217 static constexpr FPRReg argumentFPR4 = ARM64Registers::q4; // fpRegT4
218 static constexpr FPRReg argumentFPR5 = ARM64Registers::q5; // fpRegT5
219 static constexpr FPRReg argumentFPR6 = ARM64Registers::q6; // fpRegT6
220 static constexpr FPRReg argumentFPR7 = ARM64Registers::q7; // fpRegT7
221
222 static constexpr FPRReg returnValueFPR = ARM64Registers::q0; // fpRegT0
223
224 static FPRReg toRegister(unsigned index)
225 {
226 ASSERT(index < numberOfRegisters);
227 static const FPRReg registerForIndex[numberOfRegisters] = {
228 fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5, fpRegT6, fpRegT7,
229 fpRegT8, fpRegT9, fpRegT10, fpRegT11, fpRegT12, fpRegT13, fpRegT14, fpRegT15,
230 fpRegT16, fpRegT17, fpRegT18, fpRegT19, fpRegT20, fpRegT21, fpRegT22
231 };
232 return registerForIndex[index];
233 }
234
235 static unsigned toIndex(FPRReg reg)
236 {
237 ASSERT(reg != InvalidFPRReg);
238 ASSERT(static_cast<int>(reg) < 32);
239 static const unsigned indexForRegister[32] = {
240 0, 1, 2, 3, 4, 5, 6, 7,
241 InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex,
242 8, 9, 10, 11, 12, 13, 14, 15,
243 16, 17, 18, 19, 20, 21, 22, InvalidIndex
244 };
245 unsigned result = indexForRegister[reg];
246 return result;
247 }
248
249 static FPRReg toArgumentRegister(unsigned index)
250 {
251 ASSERT(index < 8);
252 return static_cast<FPRReg>(index);
253 }
254
255 static const char* debugName(FPRReg reg)
256 {
257 ASSERT(reg != InvalidFPRReg);
258 return MacroAssembler::fprName(reg);
259 }
260
261 static constexpr unsigned InvalidIndex = 0xffffffff;
262};
263
264#endif // CPU(ARM64)
265
266#if CPU(MIPS)
267
268class FPRInfo {
269public:
270 typedef FPRReg RegisterType;
271 static constexpr unsigned numberOfRegisters = 7;
272 static constexpr unsigned numberOfArgumentRegisters = 2;
273
274 // Temporary registers.
275 static constexpr FPRReg fpRegT0 = MIPSRegisters::f0;
276 static constexpr FPRReg fpRegT1 = MIPSRegisters::f2;
277 static constexpr FPRReg fpRegT2 = MIPSRegisters::f4;
278 static constexpr FPRReg fpRegT3 = MIPSRegisters::f6;
279 static constexpr FPRReg fpRegT4 = MIPSRegisters::f8;
280 static constexpr FPRReg fpRegT5 = MIPSRegisters::f10;
281 static constexpr FPRReg fpRegT6 = MIPSRegisters::f18;
282
283 static constexpr FPRReg returnValueFPR = MIPSRegisters::f0;
284
285 static constexpr FPRReg argumentFPR0 = MIPSRegisters::f12;
286 static constexpr FPRReg argumentFPR1 = MIPSRegisters::f14;
287
288 static FPRReg toRegister(unsigned index)
289 {
290 static const FPRReg registerForIndex[numberOfRegisters] = {
291 fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5, fpRegT6 };
292
293 ASSERT(index < numberOfRegisters);
294 return registerForIndex[index];
295 }
296
297 static FPRReg toArgumentRegister(unsigned index)
298 {
299 ASSERT(index < numberOfArgumentRegisters);
300 static const FPRReg indexForRegister[2] = {
301 argumentFPR0, argumentFPR1
302 };
303 return indexForRegister[index];
304 }
305
306 static unsigned toIndex(FPRReg reg)
307 {
308 ASSERT(reg != InvalidFPRReg);
309 ASSERT(reg < 20);
310 static const unsigned indexForRegister[20] = {
311 0, InvalidIndex, 1, InvalidIndex,
312 2, InvalidIndex, 3, InvalidIndex,
313 4, InvalidIndex, 5, InvalidIndex,
314 InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex,
315 InvalidIndex, InvalidIndex, 6, InvalidIndex,
316 };
317 unsigned result = indexForRegister[reg];
318 return result;
319 }
320
321 static const char* debugName(FPRReg reg)
322 {
323 ASSERT(reg != InvalidFPRReg);
324 return MacroAssembler::fprName(reg);
325 }
326
327 static constexpr unsigned InvalidIndex = 0xffffffff;
328};
329
330#endif // CPU(MIPS)
331
332// We use this hack to get the FPRInfo from the FPRReg type in templates because our code is bad and we should feel bad..
333constexpr FPRInfo toInfoFromReg(FPRReg) { return FPRInfo(); }
334
335#endif // ENABLE(ASSEMBLER)
336
337} // namespace JSC
338
339namespace WTF {
340
341inline void printInternal(PrintStream& out, JSC::FPRReg reg)
342{
343#if ENABLE(ASSEMBLER)
344 out.print("%", JSC::FPRInfo::debugName(reg));
345#else
346 out.printf("%%fr%d", reg);
347#endif
348}
349
350} // namespace WTF
351