Lazy loading changes (CHECKCAST and INSTANCEOF are still missing).
[cacao.git] / src / vm / jit / x86_64 / codegen.h
1 /* src/vm/jit/x86_64/codegen.h - code generation macros for x86_64
2
3    Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
4    R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
5    C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
6    Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Andreas Krall
28             Christian Thalinger
29
30    $Id: codegen.h 2265 2005-04-11 09:58:52Z twisti $
31
32 */
33
34
35 #ifndef _CODEGEN_H
36 #define _CODEGEN_H
37
38 #include <ucontext.h>
39
40 #include "vm/jit/x86_64/types.h"
41
42 /* Macro for stack.c to set Argument Stackslots */
43
44 #define SET_ARG_STACKSLOTS {                                                                                    \
45                 s4 iarg = 0;                                                                                                    \
46                 s4 farg = 0;                                                                                                    \
47                 s4 stacksize;     /* Stackoffset for spilled arg */                             \
48                 copy = curstack;                                                                                                \
49                 while (--i >= 0) {                                                                                              \
50                         (IS_FLT_DBL_TYPE(copy->type)) ? farg++ : iarg++;                        \
51                         copy = copy->prev;                                                                                      \
52                 }                                                                                                                               \
53                 stacksize  = (farg < rd->fltreg_argnum)? 0 : (farg - rd->fltreg_argnum); \
54                 stacksize += (iarg < rd->intreg_argnum)? 0 : (iarg - rd->intreg_argnum); \
55                 if (rd->ifmemuse < stacksize)                                                                   \
56                         rd->ifmemuse = stacksize;                                                                       \
57                 i = call_argcount;                                                                                              \
58                 copy = curstack;                                                                                                \
59                 while (--i >= 0) {                                                                                              \
60                         if (IS_FLT_DBL_TYPE(copy->type)) {                                                      \
61                                 farg--;                                                                                                 \
62                                 if (!(copy->flags & SAVEDVAR)) {                                                \
63                                         copy->varnum = i;                                                               \
64                                         copy->varkind = ARGVAR;                                                         \
65                                         if (farg < rd->fltreg_argnum) {                                         \
66                                                 copy->flags = 0;                                                                \
67                                                 copy->regoff = rd->argfltregs[farg];                    \
68                                         } else {                                                                                        \
69                                                 copy->flags = INMEMORY;                                                 \
70                                                 copy->regoff = --stacksize;                                             \
71                                         }                                                                                                       \
72                                 }                                                                                                               \
73                         } else { /* int_arg */                                                                          \
74                                 iarg--;                                                                                                 \
75                                 if (!(copy->flags & SAVEDVAR)) {                                                \
76                                         copy->varnum = i;                                                               \
77                                         copy->varkind = ARGVAR;                                                         \
78                                         if (iarg < rd->intreg_argnum) {                                         \
79                                                 copy->flags = 0;                                                                \
80                                                 copy->regoff = rd->argintregs[iarg];                    \
81                                         } else {                                                                                        \
82                                                 copy->flags = INMEMORY;                                                 \
83                                                 copy->regoff = --stacksize;                                             \
84                                         }                                                                                                       \
85                                 }                                                                                                               \
86                         }                                                                                                                       \
87                 copy = copy->prev;                                                                                              \
88                 }                                                                                                                               \
89         }                                                                                                                                       \
90
91
92 /* macros to create code ******************************************************/
93
94 /* immediate data union */
95
96 typedef union {
97     s4 i;
98     s8 l;
99     float f;
100     double d;
101     void *a;
102     u1 b[8];
103 } x86_64_imm_buf;
104
105
106 /* opcodes for alu instructions */
107
108 typedef enum {
109     X86_64_ADD = 0,
110     X86_64_OR  = 1,
111     X86_64_ADC = 2,
112     X86_64_SBB = 3,
113     X86_64_AND = 4,
114     X86_64_SUB = 5,
115     X86_64_XOR = 6,
116     X86_64_CMP = 7,
117     X86_64_NALU
118 } X86_64_ALU_Opcode;
119
120
121 typedef enum {
122     X86_64_ROL = 0,
123     X86_64_ROR = 1,
124     X86_64_RCL = 2,
125     X86_64_RCR = 3,
126     X86_64_SHL = 4,
127     X86_64_SHR = 5,
128     X86_64_SAR = 7,
129     X86_64_NSHIFT = 8
130 } X86_64_Shift_Opcode;
131
132
133 typedef enum {
134     X86_64_CC_O = 0,
135     X86_64_CC_NO = 1,
136     X86_64_CC_B = 2, X86_64_CC_C = 2, X86_64_CC_NAE = 2,
137     X86_64_CC_BE = 6, X86_64_CC_NA = 6,
138     X86_64_CC_AE = 3, X86_64_CC_NB = 3, X86_64_CC_NC = 3,
139     X86_64_CC_E = 4, X86_64_CC_Z = 4,
140     X86_64_CC_NE = 5, X86_64_CC_NZ = 5,
141     X86_64_CC_A = 7, X86_64_CC_NBE = 7,
142     X86_64_CC_S = 8, X86_64_CC_LZ = 8,
143     X86_64_CC_NS = 9, X86_64_CC_GEZ = 9,
144     X86_64_CC_P = 0x0a, X86_64_CC_PE = 0x0a,
145     X86_64_CC_NP = 0x0b, X86_64_CC_PO = 0x0b,
146     X86_64_CC_L = 0x0c, X86_64_CC_NGE = 0x0c,
147     X86_64_CC_GE = 0x0d, X86_64_CC_NL = 0x0d,
148     X86_64_CC_LE = 0x0e, X86_64_CC_NG = 0x0e,
149     X86_64_CC_G = 0x0f, X86_64_CC_NLE = 0x0f,
150     X86_64_NCC
151 } X86_64_CC;
152
153
154 #define IS_IMM8(imm) \
155     (((long) (imm) >= -128) && ((long) (imm) <= 127))
156
157
158 #define IS_IMM32(imm) \
159     (((long) (imm) >= (-2147483647-1)) && ((long) (imm) <= 2147483647))
160
161
162 /* modrm and stuff */
163
164 #define x86_64_address_byte(mod,reg,rm) \
165     *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | ((rm) & 0x07));
166
167
168 #define x86_64_emit_reg(reg,rm) \
169     x86_64_address_byte(3,(reg),(rm));
170
171
172 #define x86_64_emit_rex(size,reg,index,rm) \
173     if ((size) == 1 || (reg) > 7 || (index) > 7 || (rm) > 7) { \
174         *(cd->mcodeptr++) = (0x40 | (((size) & 0x01) << 3) | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01)); \
175     }
176
177
178 #define x86_64_emit_byte_rex(reg,index,rm) \
179     *(cd->mcodeptr++) = (0x40 | ((((reg) >> 3) & 0x01) << 2) | ((((index) >> 3) & 0x01) << 1) | (((rm) >> 3) & 0x01));
180
181
182 #define x86_64_emit_mem(r,disp) \
183     do { \
184         x86_64_address_byte(0,(r),5); \
185         x86_64_emit_imm32((disp)); \
186     } while (0)
187
188
189 #define x86_64_emit_membase(basereg,disp,dreg) \
190     do { \
191         if ((basereg) == REG_SP || (basereg) == R12) { \
192             if ((disp) == 0) { \
193                 x86_64_address_byte(0,(dreg),REG_SP); \
194                 x86_64_address_byte(0,REG_SP,REG_SP); \
195             } else if (IS_IMM8((disp))) { \
196                 x86_64_address_byte(1,(dreg),REG_SP); \
197                 x86_64_address_byte(0,REG_SP,REG_SP); \
198                 x86_64_emit_imm8((disp)); \
199             } else { \
200                 x86_64_address_byte(2,(dreg),REG_SP); \
201                 x86_64_address_byte(0,REG_SP,REG_SP); \
202                 x86_64_emit_imm32((disp)); \
203             } \
204             break; \
205         } \
206         if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) { \
207             x86_64_address_byte(0,(dreg),(basereg)); \
208             break; \
209         } \
210         \
211         if ((basereg) == RIP) { \
212             x86_64_address_byte(0,(dreg),RBP); \
213             x86_64_emit_imm32((disp)); \
214             break; \
215         } \
216         \
217         if (IS_IMM8((disp))) { \
218             x86_64_address_byte(1,(dreg),(basereg)); \
219             x86_64_emit_imm8((disp)); \
220         } else { \
221             x86_64_address_byte(2,(dreg),(basereg)); \
222             x86_64_emit_imm32((disp)); \
223         } \
224     } while (0)
225
226
227 #define x86_64_emit_membase32(basereg,disp,dreg) \
228     do { \
229         if ((basereg) == REG_SP || (basereg) == R12) { \
230             x86_64_address_byte(2,(dreg),REG_SP); \
231             x86_64_address_byte(0,REG_SP,REG_SP); \
232             x86_64_emit_imm32((disp)); \
233         } else {\
234             x86_64_address_byte(2,(dreg),(basereg)); \
235             x86_64_emit_imm32((disp)); \
236         } \
237     } while (0)
238
239
240 #define x86_64_emit_memindex(reg,disp,basereg,indexreg,scale) \
241     do { \
242         if ((basereg) == -1) { \
243             x86_64_address_byte(0,(reg),4); \
244             x86_64_address_byte((scale),(indexreg),5); \
245             x86_64_emit_imm32((disp)); \
246         \
247         } else if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) { \
248             x86_64_address_byte(0,(reg),4); \
249             x86_64_address_byte((scale),(indexreg),(basereg)); \
250         \
251         } else if (IS_IMM8((disp))) { \
252             x86_64_address_byte(1,(reg),4); \
253             x86_64_address_byte((scale),(indexreg),(basereg)); \
254             x86_64_emit_imm8 ((disp)); \
255         \
256         } else { \
257             x86_64_address_byte(2,(reg),4); \
258             x86_64_address_byte((scale),(indexreg),(basereg)); \
259             x86_64_emit_imm32((disp)); \
260         }    \
261      } while (0)
262
263
264 #define x86_64_emit_imm8(imm) \
265     *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
266
267
268 #define x86_64_emit_imm16(imm) \
269     do { \
270         x86_64_imm_buf imb; \
271         imb.i = (s4) (imm); \
272         *(cd->mcodeptr++) = imb.b[0]; \
273         *(cd->mcodeptr++) = imb.b[1]; \
274     } while (0)
275
276
277 #define x86_64_emit_imm32(imm) \
278     do { \
279         x86_64_imm_buf imb; \
280         imb.i = (s4) (imm); \
281         *(cd->mcodeptr++) = imb.b[0]; \
282         *(cd->mcodeptr++) = imb.b[1]; \
283         *(cd->mcodeptr++) = imb.b[2]; \
284         *(cd->mcodeptr++) = imb.b[3]; \
285     } while (0)
286
287
288 #define x86_64_emit_imm64(imm) \
289     do { \
290         x86_64_imm_buf imb; \
291         imb.l = (s8) (imm); \
292         *(cd->mcodeptr++) = imb.b[0]; \
293         *(cd->mcodeptr++) = imb.b[1]; \
294         *(cd->mcodeptr++) = imb.b[2]; \
295         *(cd->mcodeptr++) = imb.b[3]; \
296         *(cd->mcodeptr++) = imb.b[4]; \
297         *(cd->mcodeptr++) = imb.b[5]; \
298         *(cd->mcodeptr++) = imb.b[6]; \
299         *(cd->mcodeptr++) = imb.b[7]; \
300     } while (0)
301
302
303 /* additional functions and macros to generate code ***************************/
304
305 #define BlockPtrOfPC(pc)  ((basicblock *) iptr->target)
306
307
308 #ifdef STATISTICS
309 #define COUNT_SPILLS count_spills++
310 #else
311 #define COUNT_SPILLS
312 #endif
313
314
315 #define CALCOFFSETBYTES(var, reg, val) \
316     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
317     else if ((s4) (val) != 0) (var) += 1; \
318     else if ((reg) == RBP || (reg) == RSP || (reg) == R12 || (reg) == R13) (var) += 1;
319
320
321 #define CALCIMMEDIATEBYTES(var, val) \
322     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
323     else (var) += 1;
324
325
326 /* gen_nullptr_check(objreg) */
327
328 #define gen_nullptr_check(objreg) \
329         if (checknull) { \
330         x86_64_test_reg_reg(cd, (objreg), (objreg)); \
331         x86_64_jcc(cd, X86_64_CC_E, 0); \
332             codegen_addxnullrefs(cd, cd->mcodeptr); \
333         }
334
335
336 #define gen_bound_check \
337     if (checkbounds) { \
338         x86_64_alul_membase_reg(cd, X86_64_CMP, s1, OFFSET(java_arrayheader, size), s2); \
339         x86_64_jcc(cd, X86_64_CC_AE, 0); \
340         codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
341     }
342
343
344 #define gen_div_check(v) \
345     if (checknull) { \
346         if ((v)->flags & INMEMORY) { \
347             x86_64_alu_imm_membase(cd, X86_64_CMP, 0, REG_SP, src->regoff * 8); \
348         } else { \
349             x86_64_test_reg_reg(cd, src->regoff, src->regoff); \
350         } \
351         x86_64_jcc(cd, X86_64_CC_E, 0); \
352         codegen_addxdivrefs(cd, cd->mcodeptr); \
353     }
354
355
356 /* MCODECHECK(icnt) */
357
358 #define MCODECHECK(icnt) \
359         if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
360         cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
361
362 /* M_INTMOVE:
363     generates an integer-move from register a to b.
364     if a and b are the same int-register, no code will be generated.
365 */ 
366
367 #define M_INTMOVE(reg,dreg) \
368     if ((reg) != (dreg)) { \
369         x86_64_mov_reg_reg(cd, (reg),(dreg)); \
370     }
371
372
373 /* M_FLTMOVE:
374     generates a floating-point-move from register a to b.
375     if a and b are the same float-register, no code will be generated
376 */ 
377
378 #define M_FLTMOVE(reg,dreg) \
379     if ((reg) != (dreg)) { \
380         x86_64_movq_reg_reg(cd, (reg),(dreg)); \
381     }
382
383
384 /* var_to_reg_xxx:
385     this function generates code to fetch data from a pseudo-register
386     into a real register. 
387     If the pseudo-register has actually been assigned to a real 
388     register, no code will be emitted, since following operations
389     can use this register directly.
390     
391     v: pseudoregister to be fetched from
392     tempregnum: temporary register to be used if v is actually spilled to ram
393
394     return: the register number, where the operand can be found after 
395             fetching (this wil be either tempregnum or the register
396             number allready given to v)
397 */
398
399 #define var_to_reg_int(regnr,v,tempnr) \
400     if ((v)->flags & INMEMORY) { \
401         COUNT_SPILLS; \
402         if ((v)->type == TYPE_INT) { \
403             x86_64_movl_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
404         } else { \
405             x86_64_mov_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
406         } \
407         regnr = tempnr; \
408     } else { \
409         regnr = (v)->regoff; \
410     }
411
412
413
414 #define var_to_reg_flt(regnr,v,tempnr) \
415     if ((v)->flags & INMEMORY) { \
416         COUNT_SPILLS; \
417         if ((v)->type == TYPE_FLT) { \
418             x86_64_movlps_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
419         } else { \
420             x86_64_movlpd_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
421         } \
422 /*        x86_64_movq_membase_reg(REG_SP, (v)->regoff * 8, tempnr);*/ \
423         regnr = tempnr; \
424     } else { \
425         regnr = (v)->regoff; \
426     }
427
428
429 /* store_reg_to_var_xxx:
430     This function generates the code to store the result of an operation
431     back into a spilled pseudo-variable.
432     If the pseudo-variable has not been spilled in the first place, this 
433     function will generate nothing.
434     
435     v ............ Pseudovariable
436     tempregnum ... Number of the temporary registers as returned by
437                    reg_of_var.
438 */      
439
440 #define store_reg_to_var_int(sptr, tempregnum) \
441     if ((sptr)->flags & INMEMORY) { \
442         COUNT_SPILLS; \
443         x86_64_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
444     }
445
446
447 #define store_reg_to_var_flt(sptr, tempregnum) \
448     if ((sptr)->flags & INMEMORY) { \
449          COUNT_SPILLS; \
450          x86_64_movq_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
451     }
452
453
454 #define M_COPY(from,to) \
455     d = reg_of_var(rd, to, REG_ITMP1); \
456         if ((from->regoff != to->regoff) || \
457             ((from->flags ^ to->flags) & INMEMORY)) { \
458                 if (IS_FLT_DBL_TYPE(from->type)) { \
459                         var_to_reg_flt(s1, from, d); \
460                         M_FLTMOVE(s1, d); \
461                         store_reg_to_var_flt(to, d); \
462                 } else { \
463                         var_to_reg_int(s1, from, d); \
464                         M_INTMOVE(s1, d); \
465                         store_reg_to_var_int(to, d); \
466                 } \
467         }
468
469
470 /* function gen_resolvebranch **************************************************
471
472     backpatches a branch instruction
473
474     parameters: ip ... pointer to instruction after branch (void*)
475                 so ... offset of instruction after branch  (s8)
476                 to ... offset of branch target             (s8)
477
478 *******************************************************************************/
479
480 #define gen_resolvebranch(ip,so,to) \
481     *((s4*) ((ip) - 4)) = (s4) ((to) - (so));
482
483
484 /* function prototypes */
485
486 void thread_restartcriticalsection(ucontext_t *uc);
487
488 #endif /* _CODEGEN_H */
489
490
491 /*
492  * These are local overrides for various environment variables in Emacs.
493  * Please do not remove this and leave it at the end of the file, where
494  * Emacs will automagically detect them.
495  * ---------------------------------------------------------------------
496  * Local variables:
497  * mode: c
498  * indent-tabs-mode: t
499  * c-basic-offset: 4
500  * tab-width: 4
501  * End:
502  */