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
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/
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
16 * The Original Code is [Open Source Virtual Machine].
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.
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.
38 * ***** END LICENSE BLOCK ***** */
41 #ifndef __nanojit_Nativei386__
42 #define __nanojit_Nativei386__
44 #include "NativeCommon.h"
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()
81 #define count_prolog()
90 #define count_pushld()
96 const int NJ_MAX_REGISTERS = 24; // gpregs, x87 regs, xmm regs
98 #define NJ_MAX_STACK_ENTRY 4096
99 #define NJ_MAX_PARAMETERS 1
101 #define NJ_USES_IMMD_POOL 1
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
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;
114 const int32_t LARGEST_UNDERRUN_PROT = 32; // largest value passed to underrunProtect
116 typedef uint8_t NIns;
118 // Bytes of icache to flush after patch
119 const size_t LARGEST_BRANCH_PATCH = 16 * sizeof(NIns);
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
129 rESP = { 4 }, // stack pointer
130 rEBP = { 5 }, // frame pointer
134 SP = rESP, // alias SP to ESP for convenience
135 FP = rEBP, // alias FP to EBP for convenience
137 // SSE regs come before X87 so we prefer them
150 deprecated_UnknownReg = { 17 }, // XXX: remove eventually, see bug 538924
151 UnspecifiedReg = { 17 };
153 static const uint32_t FirstRegNum = 0;
154 static const uint32_t LastRegNum = 16;
156 typedef int RegisterMask;
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) |
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) |
170 static const RegisterMask AllowableByteRegs = 1<<REGNUM(rEAX) | 1<<REGNUM(rECX) |
171 1<<REGNUM(rEDX) | 1<<REGNUM(rEBX);
173 static inline bool IsGpReg(Register r) {
174 return ((1<<REGNUM(r)) & GpRegs) != 0;
176 static inline bool IsXmmReg(Register r) {
177 return ((1<<REGNUM(r)) & XmmRegs) != 0;
180 verbose_only( extern const char* regNames[]; )
182 #define DECLARE_PLATFORM_STATS()
184 #define DECLARE_PLATFORM_REGALLOC()
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); \
212 /* These function generate fragments of instructions. */ \
213 void IMM8(int32_t i) { /* Length: 1 byte. */ \
215 *((int8_t*)_nIns) = int8_t(i); \
217 void IMM16(int32_t i) { /* Length: 2 bytes. */ \
219 *((int16_t*)_nIns) = int16_t(i); \
221 void IMM32(int32_t i) { /* Length: 4 bytes. */ \
223 *((int32_t*)_nIns) = int32_t(i); \
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); \
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); \
233 void MODRMr(int32_t d, int32_t s) { /* Length: 1 byte. */ \
234 NanoAssert(unsigned(d) < 8 && unsigned(s) < 8); \
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); \
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); \
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) { \
289 ALU(0x8b, REGNUM(d), s); \
290 asm_output("mov %s,%s", gpn(d), gpn(s)); \
292 void LEA(Register r, int32_t d, Register b); \
293 void LEAmi4(Register r, int32_t d, Register i); \
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); \
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) { \
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); \
365 *(--_nIns) = JMP32; \
367 asm_output("jmp %p", t); \
369 void JMP_indirect(Register r); \
370 void JMP_indexed(Register x, int32_t ss, NIns** addr); \
378 void JNBE(NIns* t); \
382 void JNAE(NIns* t); \
386 void JNLE(NIns* t); \
390 void JNGE(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); \
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); \
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) { \
459 asm_output("fstp %s", gpn(r)); \
464 void FLDr(Register r); \
466 void CALL(const CallInfo* ci); \
467 void CALLr(const CallInfo* ci, Register r);
472 #endif // __nanojit_Nativei386__