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 | |
31 | namespace JSC { |
32 | |
33 | typedef MacroAssembler::FPRegisterID FPRReg; |
34 | static constexpr FPRReg InvalidFPRReg { FPRReg::InvalidFPRReg }; |
35 | |
36 | #if ENABLE(ASSEMBLER) |
37 | |
38 | #if CPU(X86) || CPU(X86_64) |
39 | |
40 | class FPRInfo { |
41 | public: |
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 | |
106 | class FPRInfo { |
107 | public: |
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 | |
173 | class FPRInfo { |
174 | public: |
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 | |
268 | class FPRInfo { |
269 | public: |
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.. |
333 | constexpr FPRInfo toInfoFromReg(FPRReg) { return FPRInfo(); } |
334 | |
335 | #endif // ENABLE(ASSEMBLER) |
336 | |
337 | } // namespace JSC |
338 | |
339 | namespace WTF { |
340 | |
341 | inline 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 | |