1/*
2 * Copyright (C) 2011-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#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 const unsigned numberOfRegisters = 6;
44 static const unsigned numberOfArgumentRegisters = is64Bit() ? 8 : 0;
45
46 // Temporary registers.
47 static const FPRReg fpRegT0 = X86Registers::xmm0;
48 static const FPRReg fpRegT1 = X86Registers::xmm1;
49 static const FPRReg fpRegT2 = X86Registers::xmm2;
50 static const FPRReg fpRegT3 = X86Registers::xmm3;
51 static const FPRReg fpRegT4 = X86Registers::xmm4;
52 static const FPRReg fpRegT5 = X86Registers::xmm5;
53#if CPU(X86_64)
54 // Only X86_64 passes aguments in xmm registers
55 static const FPRReg argumentFPR0 = X86Registers::xmm0; // fpRegT0
56 static const FPRReg argumentFPR1 = X86Registers::xmm1; // fpRegT1
57 static const FPRReg argumentFPR2 = X86Registers::xmm2; // fpRegT2
58 static const FPRReg argumentFPR3 = X86Registers::xmm3; // fpRegT3
59 static const FPRReg argumentFPR4 = X86Registers::xmm4; // fpRegT4
60 static const FPRReg argumentFPR5 = X86Registers::xmm5; // fpRegT5
61 static const FPRReg argumentFPR6 = X86Registers::xmm6;
62 static const 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 const 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 const 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 const unsigned numberOfRegisters = 6;
110
111#if CPU(ARM_HARDFP)
112 static const unsigned numberOfArgumentRegisters = 8;
113#else
114 static const unsigned numberOfArgumentRegisters = 0;
115#endif
116
117 // Temporary registers.
118 // d7 is use by the MacroAssembler as fpTempRegister.
119 static const FPRReg fpRegT0 = ARMRegisters::d0;
120 static const FPRReg fpRegT1 = ARMRegisters::d1;
121 static const FPRReg fpRegT2 = ARMRegisters::d2;
122 static const FPRReg fpRegT3 = ARMRegisters::d3;
123 static const FPRReg fpRegT4 = ARMRegisters::d4;
124 static const 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 const FPRReg returnValueFPR = ARMRegisters::d0; // fpRegT0
129
130#if CPU(ARM_HARDFP)
131 static const FPRReg argumentFPR0 = ARMRegisters::d0; // fpRegT0
132 static const 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 const unsigned InvalidIndex = 0xffffffff;
167};
168
169#endif // CPU(ARM)
170
171#if CPU(ARM64)
172
173class FPRInfo {
174public:
175 typedef FPRReg RegisterType;
176 static const unsigned numberOfRegisters = 23;
177 static const unsigned numberOfArgumentRegisters = 8;
178
179 // Temporary registers.
180 // q8-q15 are callee saved, q31 is use by the MacroAssembler as fpTempRegister.
181 static const FPRReg fpRegT0 = ARM64Registers::q0;
182 static const FPRReg fpRegT1 = ARM64Registers::q1;
183 static const FPRReg fpRegT2 = ARM64Registers::q2;
184 static const FPRReg fpRegT3 = ARM64Registers::q3;
185 static const FPRReg fpRegT4 = ARM64Registers::q4;
186 static const FPRReg fpRegT5 = ARM64Registers::q5;
187 static const FPRReg fpRegT6 = ARM64Registers::q6;
188 static const FPRReg fpRegT7 = ARM64Registers::q7;
189 static const FPRReg fpRegT8 = ARM64Registers::q16;
190 static const FPRReg fpRegT9 = ARM64Registers::q17;
191 static const FPRReg fpRegT10 = ARM64Registers::q18;
192 static const FPRReg fpRegT11 = ARM64Registers::q19;
193 static const FPRReg fpRegT12 = ARM64Registers::q20;
194 static const FPRReg fpRegT13 = ARM64Registers::q21;
195 static const FPRReg fpRegT14 = ARM64Registers::q22;
196 static const FPRReg fpRegT15 = ARM64Registers::q23;
197 static const FPRReg fpRegT16 = ARM64Registers::q24;
198 static const FPRReg fpRegT17 = ARM64Registers::q25;
199 static const FPRReg fpRegT18 = ARM64Registers::q26;
200 static const FPRReg fpRegT19 = ARM64Registers::q27;
201 static const FPRReg fpRegT20 = ARM64Registers::q28;
202 static const FPRReg fpRegT21 = ARM64Registers::q29;
203 static const FPRReg fpRegT22 = ARM64Registers::q30;
204 static const FPRReg fpRegCS0 = ARM64Registers::q8;
205 static const FPRReg fpRegCS1 = ARM64Registers::q9;
206 static const FPRReg fpRegCS2 = ARM64Registers::q10;
207 static const FPRReg fpRegCS3 = ARM64Registers::q11;
208 static const FPRReg fpRegCS4 = ARM64Registers::q12;
209 static const FPRReg fpRegCS5 = ARM64Registers::q13;
210 static const FPRReg fpRegCS6 = ARM64Registers::q14;
211 static const FPRReg fpRegCS7 = ARM64Registers::q15;
212
213 static const FPRReg argumentFPR0 = ARM64Registers::q0; // fpRegT0
214 static const FPRReg argumentFPR1 = ARM64Registers::q1; // fpRegT1
215 static const FPRReg argumentFPR2 = ARM64Registers::q2; // fpRegT2
216 static const FPRReg argumentFPR3 = ARM64Registers::q3; // fpRegT3
217 static const FPRReg argumentFPR4 = ARM64Registers::q4; // fpRegT4
218 static const FPRReg argumentFPR5 = ARM64Registers::q5; // fpRegT5
219 static const FPRReg argumentFPR6 = ARM64Registers::q6; // fpRegT6
220 static const FPRReg argumentFPR7 = ARM64Registers::q7; // fpRegT7
221
222 static const 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 const unsigned InvalidIndex = 0xffffffff;
262};
263
264#endif // CPU(ARM64)
265
266#if CPU(MIPS)
267
268class FPRInfo {
269public:
270 typedef FPRReg RegisterType;
271 static const unsigned numberOfRegisters = 7;
272 static const unsigned numberOfArgumentRegisters = 2;
273
274 // Temporary registers.
275 static const FPRReg fpRegT0 = MIPSRegisters::f0;
276 static const FPRReg fpRegT1 = MIPSRegisters::f2;
277 static const FPRReg fpRegT2 = MIPSRegisters::f4;
278 static const FPRReg fpRegT3 = MIPSRegisters::f6;
279 static const FPRReg fpRegT4 = MIPSRegisters::f8;
280 static const FPRReg fpRegT5 = MIPSRegisters::f10;
281 static const FPRReg fpRegT6 = MIPSRegisters::f18;
282
283 static const FPRReg returnValueFPR = MIPSRegisters::f0;
284
285 static const FPRReg argumentFPR0 = MIPSRegisters::f12;
286 static const 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 const 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