1/*
2 * Copyright (C) 2011 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#ifndef DFGGPRInfo_h
27#define DFGGPRInfo_h
28
29#include <wtf/Platform.h>
30
31#if ENABLE(DFG_JIT)
32
33#include "DFGRegisterBank.h"
34#include "MacroAssembler.h"
35
36namespace JSC { namespace DFG {
37
38typedef MacroAssembler::RegisterID GPRReg;
39#define InvalidGPRReg ((GPRReg)-1)
40
41#if USE(JSVALUE64)
42class JSValueRegs {
43public:
44    JSValueRegs()
45        : m_gpr(InvalidGPRReg)
46    {
47    }
48
49    explicit JSValueRegs(GPRReg gpr)
50        : m_gpr(gpr)
51    {
52    }
53
54    bool operator!() const { return m_gpr == InvalidGPRReg; }
55
56    GPRReg gpr() const { return m_gpr; }
57
58private:
59    GPRReg m_gpr;
60};
61
62class JSValueSource {
63public:
64    JSValueSource()
65        : m_offset(notAddress())
66        , m_base(InvalidGPRReg)
67    {
68    }
69
70    JSValueSource(JSValueRegs regs)
71        : m_offset(notAddress())
72        , m_base(regs.gpr())
73    {
74    }
75
76    explicit JSValueSource(GPRReg gpr)
77        : m_offset(notAddress())
78        , m_base(gpr)
79    {
80    }
81
82    JSValueSource(MacroAssembler::Address address)
83        : m_offset(address.offset)
84        , m_base(address.base)
85    {
86        ASSERT(m_offset != notAddress());
87        ASSERT(m_base != InvalidGPRReg);
88    }
89
90    static JSValueSource unboxedCell(GPRReg payloadGPR)
91    {
92        return JSValueSource(payloadGPR);
93    }
94
95    bool operator!() const { return m_base == InvalidGPRReg; }
96
97    bool isAddress() const { return m_offset != notAddress(); }
98
99    int32_t offset() const
100    {
101        ASSERT(isAddress());
102        return m_offset;
103    }
104
105    GPRReg base() const
106    {
107        ASSERT(isAddress());
108        return m_base;
109    }
110
111    GPRReg gpr() const
112    {
113        ASSERT(!isAddress());
114        return m_base;
115    }
116
117    MacroAssembler::Address asAddress() const { return MacroAssembler::Address(base(), offset()); }
118
119private:
120    static inline int32_t notAddress() { return 0x80000000; }
121
122    int32_t m_offset;
123    GPRReg m_base;
124};
125#endif
126
127#if USE(JSVALUE32_64)
128class JSValueRegs {
129public:
130    JSValueRegs()
131        : m_tagGPR(static_cast<int8_t>(InvalidGPRReg))
132        , m_payloadGPR(static_cast<int8_t>(InvalidGPRReg))
133    {
134    }
135
136    JSValueRegs(GPRReg tagGPR, GPRReg payloadGPR)
137        : m_tagGPR(tagGPR)
138        , m_payloadGPR(payloadGPR)
139    {
140        ASSERT((static_cast<GPRReg>(m_tagGPR) == InvalidGPRReg) == (static_cast<GPRReg>(payloadGPR) == InvalidGPRReg));
141    }
142
143    bool operator!() const { return static_cast<GPRReg>(m_tagGPR) == InvalidGPRReg; }
144
145    GPRReg tagGPR() const { return static_cast<GPRReg>(m_tagGPR); }
146    GPRReg payloadGPR() const { return static_cast<GPRReg>(m_payloadGPR); }
147
148private:
149    int8_t m_tagGPR;
150    int8_t m_payloadGPR;
151};
152
153class JSValueSource {
154public:
155    JSValueSource()
156        : m_offset(notAddress())
157        , m_baseOrTag(static_cast<int8_t>(InvalidGPRReg))
158        , m_payload(static_cast<int8_t>(InvalidGPRReg))
159        , m_tagType(0)
160    {
161    }
162
163    JSValueSource(JSValueRegs regs)
164        : m_offset(notAddress())
165        , m_baseOrTag(regs.tagGPR())
166        , m_payload(regs.payloadGPR())
167        , m_tagType(0)
168    {
169    }
170
171    JSValueSource(GPRReg tagGPR, GPRReg payloadGPR)
172        : m_offset(notAddress())
173        , m_baseOrTag(static_cast<int8_t>(tagGPR))
174        , m_payload(static_cast<int8_t>(payloadGPR))
175        , m_tagType(0)
176    {
177    }
178
179    JSValueSource(MacroAssembler::Address address)
180        : m_offset(address.offset)
181        , m_baseOrTag(static_cast<int8_t>(address.base))
182        , m_payload(static_cast<int8_t>(InvalidGPRReg))
183        , m_tagType(0)
184    {
185        ASSERT(m_offset != notAddress());
186        ASSERT(static_cast<GPRReg>(m_baseOrTag) != InvalidGPRReg);
187    }
188
189    static JSValueSource unboxedCell(GPRReg payloadGPR)
190    {
191        JSValueSource result;
192        result.m_offset = notAddress();
193        result.m_baseOrTag = static_cast<int8_t>(InvalidGPRReg);
194        result.m_payload = static_cast<int8_t>(payloadGPR);
195        result.m_tagType = static_cast<int8_t>(JSValue::CellTag);
196        return result;
197    }
198
199    bool operator!() const { return static_cast<GPRReg>(m_baseOrTag) == InvalidGPRReg && static_cast<GPRReg>(m_payload) == InvalidGPRReg; }
200
201    bool isAddress() const
202    {
203        ASSERT(!!*this);
204        return m_offset != notAddress();
205    }
206
207    int32_t offset() const
208    {
209        ASSERT(isAddress());
210        return m_offset;
211    }
212
213    GPRReg base() const
214    {
215        ASSERT(isAddress());
216        return static_cast<GPRReg>(m_baseOrTag);
217    }
218
219    GPRReg tagGPR() const
220    {
221        ASSERT(!isAddress() && static_cast<GPRReg>(m_baseOrTag) != InvalidGPRReg);
222        return static_cast<GPRReg>(m_baseOrTag);
223    }
224
225    GPRReg payloadGPR() const
226    {
227        ASSERT(!isAddress());
228        return static_cast<GPRReg>(m_payload);
229    }
230
231    bool hasKnownTag() const
232    {
233        ASSERT(!!*this);
234        ASSERT(!isAddress());
235        return static_cast<GPRReg>(m_baseOrTag) == InvalidGPRReg;
236    }
237
238    uint32_t tag() const
239    {
240        return static_cast<int32_t>(m_tagType);
241    }
242
243    MacroAssembler::Address asAddress(unsigned additionalOffset = 0) const { return MacroAssembler::Address(base(), offset() + additionalOffset); }
244
245private:
246    static inline int32_t notAddress() { return 0x80000000; }
247
248    int32_t m_offset;
249    int8_t m_baseOrTag;
250    int8_t m_payload;
251    int8_t m_tagType; // Contains the low bits of the tag.
252};
253#endif
254
255#if CPU(X86)
256#define NUMBER_OF_ARGUMENT_REGISTERS 0
257
258class GPRInfo {
259public:
260    typedef GPRReg RegisterType;
261    static const unsigned numberOfRegisters = 5;
262
263    // Temporary registers.
264    static const GPRReg regT0 = X86Registers::eax;
265    static const GPRReg regT1 = X86Registers::edx;
266    static const GPRReg regT2 = X86Registers::ecx;
267    static const GPRReg regT3 = X86Registers::ebx;
268    static const GPRReg regT4 = X86Registers::esi;
269    // These registers match the baseline JIT.
270    static const GPRReg cachedResultRegister = regT0;
271    static const GPRReg cachedResultRegister2 = regT1;
272    static const GPRReg callFrameRegister = X86Registers::edi;
273    // These constants provide the names for the general purpose argument & return value registers.
274    static const GPRReg argumentGPR0 = X86Registers::ecx; // regT2
275    static const GPRReg argumentGPR1 = X86Registers::edx; // regT1
276    static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0
277    static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
278    static const GPRReg nonArgGPR2 = X86Registers::esi; // regT4
279    static const GPRReg returnValueGPR = X86Registers::eax; // regT0
280    static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
281    static const GPRReg nonPreservedNonReturnGPR = X86Registers::ecx;
282
283    static GPRReg toRegister(unsigned index)
284    {
285        ASSERT(index < numberOfRegisters);
286        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4 };
287        return registerForIndex[index];
288    }
289
290    static unsigned toIndex(GPRReg reg)
291    {
292        ASSERT(reg != InvalidGPRReg);
293        ASSERT(static_cast<int>(reg) < 8);
294        static const unsigned indexForRegister[8] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 4, InvalidIndex };
295        unsigned result = indexForRegister[reg];
296        ASSERT(result != InvalidIndex);
297        return result;
298    }
299
300    static const char* debugName(GPRReg reg)
301    {
302        ASSERT(reg != InvalidGPRReg);
303        ASSERT(static_cast<int>(reg) < 8);
304        static const char* nameForRegister[8] = {
305            "eax", "ecx", "edx", "ebx",
306            "esp", "ebp", "esi", "edi",
307        };
308        return nameForRegister[reg];
309    }
310private:
311
312    static const unsigned InvalidIndex = 0xffffffff;
313};
314
315#endif
316
317#if CPU(X86_64)
318#define NUMBER_OF_ARGUMENT_REGISTERS 6
319
320class GPRInfo {
321public:
322    typedef GPRReg RegisterType;
323    static const unsigned numberOfRegisters = 9;
324
325    // These registers match the baseline JIT.
326    static const GPRReg cachedResultRegister = X86Registers::eax;
327    static const GPRReg callFrameRegister = X86Registers::r13;
328    static const GPRReg tagTypeNumberRegister = X86Registers::r14;
329    static const GPRReg tagMaskRegister = X86Registers::r15;
330    // Temporary registers.
331    static const GPRReg regT0 = X86Registers::eax;
332    static const GPRReg regT1 = X86Registers::edx;
333    static const GPRReg regT2 = X86Registers::ecx;
334    static const GPRReg regT3 = X86Registers::ebx;
335    static const GPRReg regT4 = X86Registers::edi;
336    static const GPRReg regT5 = X86Registers::esi;
337    static const GPRReg regT6 = X86Registers::r8;
338    static const GPRReg regT7 = X86Registers::r9;
339    static const GPRReg regT8 = X86Registers::r10;
340    // These constants provide the names for the general purpose argument & return value registers.
341    static const GPRReg argumentGPR0 = X86Registers::edi; // regT4
342    static const GPRReg argumentGPR1 = X86Registers::esi; // regT5
343    static const GPRReg argumentGPR2 = X86Registers::edx; // regT1
344    static const GPRReg argumentGPR3 = X86Registers::ecx; // regT2
345    static const GPRReg argumentGPR4 = X86Registers::r8;  // regT6
346    static const GPRReg argumentGPR5 = X86Registers::r9;  // regT7
347    static const GPRReg nonArgGPR0 = X86Registers::eax; // regT0
348    static const GPRReg nonArgGPR1 = X86Registers::ebx; // regT3
349    static const GPRReg nonArgGPR2 = X86Registers::r10; // regT8
350    static const GPRReg returnValueGPR = X86Registers::eax; // regT0
351    static const GPRReg returnValueGPR2 = X86Registers::edx; // regT1
352    static const GPRReg nonPreservedNonReturnGPR = X86Registers::esi;
353
354    static GPRReg toRegister(unsigned index)
355    {
356        ASSERT(index < numberOfRegisters);
357        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regT8 };
358        return registerForIndex[index];
359    }
360
361    static unsigned toIndex(GPRReg reg)
362    {
363        ASSERT(reg != InvalidGPRReg);
364        ASSERT(static_cast<int>(reg) < 16);
365        static const unsigned indexForRegister[16] = { 0, 2, 1, 3, InvalidIndex, InvalidIndex, 5, 4, 6, 7, 8, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
366        unsigned result = indexForRegister[reg];
367        ASSERT(result != InvalidIndex);
368        return result;
369    }
370
371    static const char* debugName(GPRReg reg)
372    {
373        ASSERT(reg != InvalidGPRReg);
374        ASSERT(static_cast<int>(reg) < 16);
375        static const char* nameForRegister[16] = {
376            "rax", "rcx", "rdx", "rbx",
377            "rsp", "rbp", "rsi", "rdi",
378            "r8", "r9", "r10", "r11",
379            "r12", "r13", "r14", "r15"
380        };
381        return nameForRegister[reg];
382    }
383private:
384
385    static const unsigned InvalidIndex = 0xffffffff;
386};
387
388#endif
389
390#if CPU(ARM)
391#define NUMBER_OF_ARGUMENT_REGISTERS 4
392
393class GPRInfo {
394public:
395    typedef GPRReg RegisterType;
396    static const unsigned numberOfRegisters = 8;
397
398    // Temporary registers.
399    static const GPRReg regT0 = ARMRegisters::r0;
400    static const GPRReg regT1 = ARMRegisters::r1;
401    static const GPRReg regT2 = ARMRegisters::r2;
402    static const GPRReg regT3 = ARMRegisters::r4;
403    static const GPRReg regT4 = ARMRegisters::r8;
404    static const GPRReg regT5 = ARMRegisters::r9;
405    static const GPRReg regT6 = ARMRegisters::r10;
406    static const GPRReg regT7 = ARMRegisters::r11;
407    // These registers match the baseline JIT.
408    static const GPRReg cachedResultRegister = regT0;
409    static const GPRReg cachedResultRegister2 = regT1;
410    static const GPRReg callFrameRegister = ARMRegisters::r5;
411    // These constants provide the names for the general purpose argument & return value registers.
412    static const GPRReg argumentGPR0 = ARMRegisters::r0; // regT0
413    static const GPRReg argumentGPR1 = ARMRegisters::r1; // regT1
414    static const GPRReg argumentGPR2 = ARMRegisters::r2; // regT2
415    // FIXME: r3 is currently used be the MacroAssembler as a temporary - it seems
416    // This could threoretically be a problem if this is used in code generation
417    // between the arguments being set up, and the call being made. That said,
418    // any change introducing a problem here is likely to be immediately apparent!
419    static const GPRReg argumentGPR3 = ARMRegisters::r3; // FIXME!
420    static const GPRReg nonArgGPR0 = ARMRegisters::r4; // regT3
421    static const GPRReg nonArgGPR1 = ARMRegisters::r8; // regT4
422    static const GPRReg nonArgGPR2 = ARMRegisters::r9; // regT5
423    static const GPRReg returnValueGPR = ARMRegisters::r0; // regT0
424    static const GPRReg returnValueGPR2 = ARMRegisters::r1; // regT1
425    static const GPRReg nonPreservedNonReturnGPR = ARMRegisters::r2;
426
427    static GPRReg toRegister(unsigned index)
428    {
429        ASSERT(index < numberOfRegisters);
430        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7 };
431        return registerForIndex[index];
432    }
433
434    static unsigned toIndex(GPRReg reg)
435    {
436        ASSERT(static_cast<unsigned>(reg) != InvalidGPRReg);
437        ASSERT(static_cast<unsigned>(reg) < 16);
438        static const unsigned indexForRegister[16] = { 0, 1, 2, InvalidIndex, 3, InvalidIndex, InvalidIndex, InvalidIndex, 4, 5, 6, 7, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
439        unsigned result = indexForRegister[reg];
440        ASSERT(result != InvalidIndex);
441        return result;
442    }
443
444    static const char* debugName(GPRReg reg)
445    {
446        ASSERT(static_cast<unsigned>(reg) != InvalidGPRReg);
447        ASSERT(static_cast<unsigned>(reg) < 16);
448        static const char* nameForRegister[16] = {
449            "r0", "r1", "r2", "r3",
450            "r4", "r5", "r6", "r7",
451            "r8", "r9", "r10", "r11",
452            "r12", "r13", "r14", "r15"
453        };
454        return nameForRegister[reg];
455    }
456private:
457
458    static const unsigned InvalidIndex = 0xffffffff;
459};
460
461#endif
462
463#if CPU(MIPS)
464#define NUMBER_OF_ARGUMENT_REGISTERS 4
465
466class GPRInfo {
467public:
468    typedef GPRReg RegisterType;
469    static const unsigned numberOfRegisters = 6;
470
471    // Temporary registers.
472    static const GPRReg regT0 = MIPSRegisters::v0;
473    static const GPRReg regT1 = MIPSRegisters::v1;
474    static const GPRReg regT2 = MIPSRegisters::t4;
475    static const GPRReg regT3 = MIPSRegisters::t5;
476    static const GPRReg regT4 = MIPSRegisters::t6;
477    static const GPRReg regT5 = MIPSRegisters::t7;
478    // These registers match the baseline JIT.
479    static const GPRReg cachedResultRegister = regT0;
480    static const GPRReg cachedResultRegister2 = regT1;
481    static const GPRReg callFrameRegister = MIPSRegisters::s0;
482    // These constants provide the names for the general purpose argument & return value registers.
483    static const GPRReg argumentGPR0 = MIPSRegisters::a0;
484    static const GPRReg argumentGPR1 = MIPSRegisters::a1;
485    static const GPRReg argumentGPR2 = MIPSRegisters::a2;
486    static const GPRReg argumentGPR3 = MIPSRegisters::a3;
487    static const GPRReg nonArgGPR0 = regT2;
488    static const GPRReg nonArgGPR1 = regT3;
489    static const GPRReg nonArgGPR2 = regT4;
490    static const GPRReg returnValueGPR = regT0;
491    static const GPRReg returnValueGPR2 = regT1;
492    static const GPRReg nonPreservedNonReturnGPR = regT5;
493
494    static GPRReg toRegister(unsigned index)
495    {
496        ASSERT(index < numberOfRegisters);
497        static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5 };
498        return registerForIndex[index];
499    }
500
501    static unsigned toIndex(GPRReg reg)
502    {
503        ASSERT(reg != InvalidGPRReg);
504        ASSERT(reg < 16);
505        static const unsigned indexForRegister[16] = { InvalidIndex, InvalidIndex, 0, 1, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, 2, 3, 4, 5 };
506        unsigned result = indexForRegister[reg];
507        ASSERT(result != InvalidIndex);
508        return result;
509    }
510
511    static const char* debugName(GPRReg reg)
512    {
513        ASSERT(reg != InvalidGPRReg);
514        ASSERT(reg < 16);
515        static const char* nameForRegister[16] = {
516            "zero", "at", "v0", "v1",
517            "a0", "a1", "a2", "a3",
518            "t0", "t1", "t2", "t3",
519            "t4", "t5", "t6", "t7"
520        };
521        return nameForRegister[reg];
522    }
523private:
524
525    static const unsigned InvalidIndex = 0xffffffff;
526};
527
528#endif
529
530typedef RegisterBank<GPRInfo>::iterator gpr_iterator;
531
532} } // namespace JSC::DFG
533
534#endif
535#endif
536