Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / nanojit / Nativei386.h
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is [Open Source Virtual Machine].
17  *
18  * The Initial Developer of the Original Code is
19  * Adobe System Incorporated.
20  * Portions created by the Initial Developer are Copyright (C) 2004-2007
21  * the Initial Developer. All Rights Reserved.
22  *
23  * Contributor(s):
24  *   Adobe AS3 Team
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40
41 #ifndef __nanojit_Nativei386__
42 #define __nanojit_Nativei386__
43
44 #include "NativeCommon.h"
45
46 #ifdef PERFM
47 #define DOPROF
48 #include "../vprof/vprof.h"
49 #define count_instr() _nvprof("x86",1)
50 #define count_ret() _nvprof("x86-ret",1); count_instr();
51 #define count_push() _nvprof("x86-push",1); count_instr();
52 #define count_pop() _nvprof("x86-pop",1); count_instr();
53 #define count_st() _nvprof("x86-st",1); count_instr();
54 #define count_stq() _nvprof("x86-stq",1); count_instr();
55 #define count_ld() _nvprof("x86-ld",1); count_instr();
56 #define count_ldq() _nvprof("x86-ldq",1); count_instr();
57 #define count_call() _nvprof("x86-call",1); count_instr();
58 #define count_calli() _nvprof("x86-calli",1); count_instr();
59 #define count_prolog() _nvprof("x86-prolog",1); count_instr();
60 #define count_alu() _nvprof("x86-alu",1); count_instr();
61 #define count_mov() _nvprof("x86-mov",1); count_instr();
62 #define count_fpu() _nvprof("x86-fpu",1); count_instr();
63 #define count_jmp() _nvprof("x86-jmp",1); count_instr();
64 #define count_jcc() _nvprof("x86-jcc",1); count_instr();
65 #define count_fpuld() _nvprof("x86-ldq",1); _nvprof("x86-fpu",1); count_instr()
66 #define count_aluld() _nvprof("x86-ld",1); _nvprof("x86-alu",1); count_instr()
67 #define count_alust() _nvprof("x86-ld",1); _nvprof("x86-alu",1); _nvprof("x86-st",1); count_instr()
68 #define count_pushld() _nvprof("x86-ld",1); _nvprof("x86-push",1); count_instr()
69 #define count_imt() _nvprof("x86-imt",1) count_instr()
70 #else
71 #define count_instr()
72 #define count_ret()
73 #define count_push()
74 #define count_pop()
75 #define count_st()
76 #define count_stq()
77 #define count_ld()
78 #define count_ldq()
79 #define count_call()
80 #define count_calli()
81 #define count_prolog()
82 #define count_alu()
83 #define count_mov()
84 #define count_fpu()
85 #define count_jmp()
86 #define count_jcc()
87 #define count_fpuld()
88 #define count_aluld()
89 #define count_alust()
90 #define count_pushld()
91 #define count_imt()
92 #endif
93
94 namespace nanojit
95 {
96     const int NJ_MAX_REGISTERS = 24; // gpregs, x87 regs, xmm regs
97
98     #define NJ_MAX_STACK_ENTRY           4096
99     #define NJ_MAX_PARAMETERS               1
100
101     #define NJ_USES_IMMD_POOL          1
102
103     #define NJ_JTBL_SUPPORTED               1
104     #define NJ_EXPANDED_LOADSTORE_SUPPORTED 1
105     #define NJ_F2I_SUPPORTED                1
106     #define NJ_SOFTFLOAT_SUPPORTED          0
107     #define NJ_DIVI_SUPPORTED               1
108     
109         // Preserve a 16-byte stack alignment, to support the use of
110         // SSE instructions like MOVDQA (if not by Tamarin itself,
111         // then by the C functions it calls).
112     const int NJ_ALIGN_STACK = 16;
113
114     const int32_t LARGEST_UNDERRUN_PROT = 32;  // largest value passed to underrunProtect
115
116     typedef uint8_t NIns;
117
118     // Bytes of icache to flush after patch
119     const size_t LARGEST_BRANCH_PATCH = 16 * sizeof(NIns);
120
121     static const Register
122         // General purpose 32 bit registers.  The names are rEAX, rEBX, etc,
123         // because EAX, EBX, et al clash with <sys/regset.h> on Solaris (sigh).
124         // See bug 570726 for details.
125         rEAX = { 0 }, // return value, scratch
126         rECX = { 1 }, // this/arg0, scratch
127         rEDX = { 2 }, // arg1, return-msw, scratch
128         rEBX = { 3 },
129         rESP = { 4 }, // stack pointer
130         rEBP = { 5 }, // frame pointer
131         rESI = { 6 },
132         rEDI = { 7 },
133
134         SP = rESP,    // alias SP to ESP for convenience
135         FP = rEBP,    // alias FP to EBP for convenience
136
137         // SSE regs come before X87 so we prefer them
138         XMM0 = { 8 },
139         XMM1 = { 9 },
140         XMM2 = { 10 },
141         XMM3 = { 11 },
142         XMM4 = { 12 },
143         XMM5 = { 13 },
144         XMM6 = { 14 },
145         XMM7 = { 15 },
146
147         // X87 regs
148         FST0 = { 16 },
149
150         deprecated_UnknownReg = { 17 }, // XXX: remove eventually, see bug 538924
151         UnspecifiedReg = { 17 };
152
153     static const uint32_t FirstRegNum = 0;
154     static const uint32_t LastRegNum = 16;
155
156     typedef int RegisterMask;
157
158     static const int NumSavedRegs = 3;
159     static const RegisterMask SavedRegs   = 1<<REGNUM(rEBX) | 1<<REGNUM(rEDI) | 1<<REGNUM(rESI);
160     static const RegisterMask GpRegs      = SavedRegs | 1<<REGNUM(rEAX) | 1<<REGNUM(rECX) |
161                                                         1<<REGNUM(rEDX);
162     static const RegisterMask XmmRegs     = 1<<REGNUM(XMM0) | 1<<REGNUM(XMM1) | 1<<REGNUM(XMM2) |
163                                             1<<REGNUM(XMM3) | 1<<REGNUM(XMM4) | 1<<REGNUM(XMM5) |
164                                             1<<REGNUM(XMM6) | 1<<REGNUM(XMM7);
165     static const RegisterMask x87Regs     = 1<<REGNUM(FST0);
166     static const RegisterMask FpRegs      = x87Regs | XmmRegs;
167     static const RegisterMask ScratchRegs = 1<<REGNUM(rEAX) | 1<<REGNUM(rECX) | 1<<REGNUM(rEDX) |
168                                             FpRegs;
169
170     static const RegisterMask AllowableByteRegs = 1<<REGNUM(rEAX) | 1<<REGNUM(rECX) |
171                                                   1<<REGNUM(rEDX) | 1<<REGNUM(rEBX);
172
173     static inline bool IsGpReg(Register r) {
174         return ((1<<REGNUM(r)) & GpRegs) != 0;
175     }
176     static inline bool IsXmmReg(Register r) {
177         return ((1<<REGNUM(r)) & XmmRegs) != 0;
178     }
179
180     verbose_only( extern const char* regNames[]; )
181
182     #define DECLARE_PLATFORM_STATS()
183
184     #define DECLARE_PLATFORM_REGALLOC()
185
186     #define JCC32 0x0f
187     #define JMP8  0xeb
188     #define JMP32 0xe9
189
190     #define DECLARE_PLATFORM_ASSEMBLER()    \
191         const static Register argRegs[2], retRegs[2]; \
192         int32_t max_stk_args;\
193         void nativePageReset();\
194         void nativePageSetup();\
195         void underrunProtect(int);\
196         bool hardenNopInsertion(const Config& c) { return c.harden_nop_insertion; } \
197         void asm_immi(Register r, int32_t val, bool canClobberCCs);\
198         void asm_stkarg(LIns* p, int32_t& stkd);\
199         void asm_farg(LIns*, int32_t& stkd);\
200         void asm_arg(ArgType ty, LIns* p, Register r, int32_t& stkd);\
201         void asm_pusharg(LIns*);\
202         void asm_cmp(LIns *cond); \
203         void asm_cmpi(LIns *cond); \
204         void asm_cmpd(LIns *cond);\
205         NIns* asm_branch_helper(bool, LIns* cond, NIns*);\
206         NIns* asm_branchi_helper(bool, LIns* cond, NIns*);\
207         NIns* asm_branchd_helper(bool, LIns* cond, NIns*);\
208         void asm_div_mod(LIns *cond); \
209         void asm_load(int d, Register r); \
210         void asm_immd(Register r, uint64_t q, double d, bool canClobberCCs); \
211         \
212         /* These function generate fragments of instructions. */ \
213         void IMM8(int32_t i) { /* Length: 1 byte. */ \
214             _nIns -= 1; \
215             *((int8_t*)_nIns) = int8_t(i); \
216         }; \
217         void IMM16(int32_t i) { /* Length: 2 bytes. */ \
218             _nIns -= 2; \
219             *((int16_t*)_nIns) = int16_t(i); \
220         }; \
221         void IMM32(int32_t i) { /* Length: 4 bytes. */ \
222             _nIns -= 4; \
223             *((int32_t*)_nIns) = int32_t(i); \
224         }; \
225         void MODRM(int32_t mod, int32_t ro, int32_t rm) { /* Length: 1 byte. */ \
226             NanoAssert(unsigned(mod) < 4 && unsigned(ro) < 8 && unsigned(rm) < 8); \
227             *(--_nIns) = uint8_t(mod << 6 | ro << 3 | rm); \
228         } \
229         void SIB(int32_t s, int32_t i, int32_t b) { /* Length: 1 byte. */ \
230             NanoAssert(unsigned(s) < 4 && unsigned(i) < 8 && unsigned(b) < 8); \
231             *(--_nIns) = uint8_t(s << 6 | i << 3 | b); \
232         } \
233         void MODRMr(int32_t d, int32_t s) { /* Length: 1 byte. */ \
234             NanoAssert(unsigned(d) < 8 && unsigned(s) < 8); \
235             MODRM(3, d, s); \
236         }; \
237         void MODRMm(int32_t r, int32_t d, Register b); \
238         void MODRMsib(int32_t r, Register b, Register i, int32_t s, int32_t d); \
239         void MODRMdm(int32_t r, int32_t addr); \
240         \
241         /* These functions generate entire instructions. */ \
242         void ALU0(int32_t o); \
243         void ALUm(int32_t c, int32_t r, int32_t d, Register b); \
244         void ALUdm(int32_t c, Register r, int32_t addr); \
245         void ALUsib(int32_t c, Register r, Register base, Register index, int32_t scale, int32_t disp); \
246         void ALUsib16(int32_t c, Register r, Register base, Register index, int32_t scale, int32_t disp); \
247         void ALUm16(int32_t c, int32_t r, int32_t d, Register b); \
248         void ALU2dm(int32_t c, Register r, int32_t addr); \
249         void ALU2m(int32_t c, Register r, int32_t d, Register b); \
250         void ALU2sib(int32_t c, Register r, Register base, Register index, int32_t scale, int32_t disp); \
251         void ALU(int32_t c, int32_t d, Register s) { \
252             underrunProtect(2); \
253             MODRMr(d, REGNUM(s)); \
254             *(--_nIns) = uint8_t(c); \
255         }; \
256         void ALUi(int32_t c, Register r, int32_t i); \
257         void ALUmi(int32_t c, int32_t d, Register b, int32_t i); \
258         void ALU2(int32_t c, Register d, Register s); \
259         Register AL2AHReg(Register r); \
260         void OR(Register l, Register r); \
261         void AND(Register l, Register r); \
262         void AND8R(Register r); \
263         void XOR(Register l, Register r); \
264         void ADD(Register l, Register r); \
265         void SUB(Register l, Register r); \
266         void IMUL(Register l, Register r); \
267         void DIV(Register r); \
268         void NOT(Register r); \
269         void NEG(Register r); \
270         void SHR(Register r, Register s); \
271         void SAR(Register r, Register s); \
272         void SHL(Register r, Register s); \
273         void SHIFT(int32_t c, Register r, int32_t i); \
274         void SHLi(Register r, int32_t i); \
275         void SHRi(Register r, int32_t i); \
276         void SARi(Register r, int32_t i); \
277         void MOVZX8(Register d, Register s); \
278         void SUBi(Register r, int32_t i); \
279         void ADDi(Register r, int32_t i); \
280         void ANDi(Register r, int32_t i); \
281         void ORi(Register r, int32_t i); \
282         void XORi(Register r, int32_t i); \
283         void ADDmi(int32_t d, Register b, int32_t i); \
284         void TEST(Register d, Register s); \
285         void CMP(Register l, Register r); \
286         void CMPi(Register r, int32_t i); \
287         void MR(Register d, Register s) { \
288             count_mov(); \
289             ALU(0x8b, REGNUM(d), s); \
290             asm_output("mov %s,%s", gpn(d), gpn(s)); \
291         }; \
292         void LEA(Register r, int32_t d, Register b); \
293         void LEAmi4(Register r, int32_t d, Register i); \
294         void CDQ(); \
295         void INCLi(int32_t p); \
296         void SETE( Register r); \
297         void SETNP(Register r); \
298         void SETNPH(Register r); \
299         void SETL( Register r); \
300         void SETLE(Register r); \
301         void SETG( Register r); \
302         void SETGE(Register r); \
303         void SETB( Register r); \
304         void SETBE(Register r); \
305         void SETA( Register r); \
306         void SETAE(Register r); \
307         void SETO( Register r); \
308         void MREQ(Register d, Register s); \
309         void MRNE(Register d, Register s); \
310         void MRL( Register d, Register s); \
311         void MRLE(Register d, Register s); \
312         void MRG( Register d, Register s); \
313         void MRGE(Register d, Register s); \
314         void MRB( Register d, Register s); \
315         void MRBE(Register d, Register s); \
316         void MRA( Register d, Register s); \
317         void MRAE(Register d, Register s); \
318         void MRNO(Register d, Register s); \
319         void LD(Register reg, int32_t disp, Register base); \
320         void LDdm(Register reg, int32_t addr); \
321         void LDsib(Register reg, int32_t disp, Register base, Register index, int32_t scale); \
322         void LD16S(Register r, int32_t d, Register b); \
323         void LD16Sdm(Register r, int32_t addr); \
324         void LD16Ssib(Register r, int32_t disp, Register base, Register index, int32_t scale); \
325         void LD16Z(Register r, int32_t d, Register b); \
326         void LD16Zdm(Register r, int32_t addr); \
327         void LD16Zsib(Register r, int32_t disp, Register base, Register index, int32_t scale); \
328         void LD8Z(Register r, int32_t d, Register b); \
329         void LD8Zdm(Register r, int32_t addr); \
330         void LD8Zsib(Register r, int32_t disp, Register base, Register index, int32_t scale); \
331         void LD8S(Register r, int32_t d, Register b); \
332         void LD8Sdm(Register r, int32_t addr); \
333         void LD8Ssib(Register r, int32_t disp, Register base, Register index, int32_t scale); \
334         void LDi(Register r, int32_t i); \
335         void ST8(Register base, int32_t disp, Register reg); \
336         void ST8sib(int32_t disp, Register base, Register index, int32_t scale, Register reg); \
337         void ST16(Register base, int32_t disp, Register reg); \
338         void ST16sib(int32_t disp, Register base, Register index, int32_t scale, Register reg); \
339         void ST(Register base, int32_t disp, Register reg); \
340         void STsib(int32_t disp, Register base, Register index, int32_t scale, Register reg); \
341         void ST8i(Register base, int32_t disp, int32_t imm); \
342         void ST8isib(int32_t disp, Register base, Register index, int32_t scale, int32_t imm); \
343         void ST16i(Register base, int32_t disp, int32_t imm); \
344         void ST16isib(int32_t disp, Register base, Register index, int32_t scale, int32_t imm); \
345         void STi(Register base, int32_t disp, int32_t imm); \
346         void STisib(int32_t disp, Register base, Register index, int32_t scale, int32_t imm); \
347         void RET(); \
348         void NOP(); \
349         void INT3(); \
350         void PUSHi(int32_t i); \
351         void PUSHr(Register r); \
352         void PUSHm(int32_t d, Register b); \
353         void POPr(Register r); \
354         void JCC(int32_t o, NIns* t, const char* n); \
355         void JMP_long(NIns* t); \
356         void JMP(NIns* t) { \
357             count_jmp(); \
358             underrunProtect(5); \
359             intptr_t tt = t ? (intptr_t)t - (intptr_t)_nIns : 0; \
360             if (t && isS8(tt)) { \
361                 *(--_nIns) = uint8_t(tt & 0xff); \
362                 *(--_nIns) = JMP8; \
363             } else { \
364                 IMM32(tt); \
365                 *(--_nIns) = JMP32; \
366             } \
367             asm_output("jmp %p", t); \
368         }; \
369         void JMP_indirect(Register r); \
370         void JMP_indexed(Register x, int32_t ss, NIns** addr); \
371         void JE(NIns* t); \
372         void JNE(NIns* t); \
373         void JP(NIns* t); \
374         void JNP(NIns* t); \
375         void JB(NIns* t); \
376         void JNB(NIns* t); \
377         void JBE(NIns* t); \
378         void JNBE(NIns* t); \
379         void JA(NIns* t); \
380         void JNA(NIns* t); \
381         void JAE(NIns* t); \
382         void JNAE(NIns* t); \
383         void JL(NIns* t); \
384         void JNL(NIns* t); \
385         void JLE(NIns* t); \
386         void JNLE(NIns* t); \
387         void JG(NIns* t); \
388         void JNG(NIns* t); \
389         void JGE(NIns* t); \
390         void JNGE(NIns* t); \
391         void JO(NIns* t); \
392         void JNO(NIns* t); \
393         void SSE(int32_t c, Register d, Register s); \
394         void SSEm(int32_t c, Register r, int32_t d, Register b); \
395         void SSEsib(int32_t c, Register rr, int32_t d, Register rb, Register ri, int32_t scale); \
396         void LDSDm(Register r, const double* addr); \
397         void SSE_LDQ( Register r, int32_t d, Register b); \
398         void SSE_LDSS(Register r, int32_t d, Register b); \
399         void SSE_LDQsib(Register r, int32_t d, Register rb, Register ri, int32_t scale); \
400         void SSE_LDSSsib(Register r, int32_t d, Register rb, Register ri, int32_t scale); \
401         void SSE_STSD(int32_t d, Register b, Register r); \
402         void SSE_STQ( int32_t d, Register b, Register r); \
403         void SSE_STSS(int32_t d, Register b, Register r); \
404         void SSE_STQsib(int32_t d, Register rb, Register ri, int32_t scale, Register rv); \
405         void SSE_CVTSI2SD(Register xr, Register gr); \
406         void SSE_CVTSD2SI(Register gr, Register xr); \
407         void SSE_CVTTSD2SI(Register gr, Register xr); \
408         void SSE_CVTSD2SS(Register xr, Register gr); \
409         void SSE_CVTSS2SD(Register xr, Register gr); \
410         void SSE_CVTDQ2PD(Register d, Register r); \
411         void SSE_MOVD(Register d, Register s); \
412         void SSE_MOVSD(Register rd, Register rs); \
413         void SSE_ADDSD(Register rd, Register rs); \
414         void SSE_ADDSDm(Register r, const double* addr); \
415         void SSE_SUBSD(Register rd, Register rs); \
416         void SSE_MULSD(Register rd, Register rs); \
417         void SSE_DIVSD(Register rd, Register rs); \
418         void SSE_UCOMISD(Register rl, Register rr); \
419         void SSE_XORPD(Register r, const uint32_t* maskaddr); \
420         void SSE_XORPDr(Register rd, Register rs); \
421         void FPUc(int32_t o); \
422         void FPU(int32_t o, Register r) { \
423             underrunProtect(2); \
424             *(--_nIns) = uint8_t((uint8_t(o) & 0xff) | (REGNUM(r) & 7)); \
425             *(--_nIns) = uint8_t((o >> 8) & 0xff); \
426         }; \
427         void FPUm(int32_t o, int32_t d, Register b); \
428         void FPUdm(int32_t o, const double* const m); \
429         void TEST_AH(int32_t i); \
430         void TEST_AX(int32_t i); \
431         void FNSTSW_AX(); \
432         void FCHS(); \
433         void FLD1(); \
434         void FLDZ(); \
435         void FST32(bool p, int32_t d, Register b); \
436         void FSTQ(bool p, int32_t d, Register b); \
437         void FSTPQ(int32_t d, Register b); \
438         void FCOM(bool p, int32_t d, Register b); \
439         void FCOMdm(bool p, const double* dm); \
440         void FLD32(int32_t d, Register b); \
441         void FLDQ(int32_t d, Register b); \
442         void FLDQdm(const double* dm); \
443         void FILDQ(int32_t d, Register b); \
444         void FILD(int32_t d, Register b); \
445         void FIST(bool p, int32_t d, Register b); \
446         void FADD( int32_t d, Register b); \
447         void FSUB( int32_t d, Register b); \
448         void FSUBR(int32_t d, Register b); \
449         void FMUL( int32_t d, Register b); \
450         void FDIV( int32_t d, Register b); \
451         void FDIVR(int32_t d, Register b); \
452         void FADDdm( const double *dm); \
453         void FSUBRdm(const double* dm); \
454         void FMULdm( const double* dm); \
455         void FDIVRdm(const double* dm); \
456         void FSTP(Register r) { \
457             count_fpu(); \
458             FPU(0xddd8, r); \
459             asm_output("fstp %s", gpn(r)); \
460             fpu_pop(); \
461         }; \
462         void FCOMP(); \
463         void FCOMPP(); \
464         void FLDr(Register r); \
465         void EMMS(); \
466         void CALL(const CallInfo* ci); \
467         void CALLr(const CallInfo* ci, Register r);
468 }
469
470
471
472 #endif // __nanojit_Nativei386__