consecutive argument numbering for -si
[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 2223 2005-04-05 18:01:56Z christian $
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_memindex(reg,disp,basereg,indexreg,scale) \
228     do { \
229         if ((basereg) == -1) { \
230             x86_64_address_byte(0,(reg),4); \
231             x86_64_address_byte((scale),(indexreg),5); \
232             x86_64_emit_imm32((disp)); \
233         \
234         } else if ((disp) == 0 && (basereg) != RBP && (basereg) != R13) { \
235             x86_64_address_byte(0,(reg),4); \
236             x86_64_address_byte((scale),(indexreg),(basereg)); \
237         \
238         } else if (IS_IMM8((disp))) { \
239             x86_64_address_byte(1,(reg),4); \
240             x86_64_address_byte((scale),(indexreg),(basereg)); \
241             x86_64_emit_imm8 ((disp)); \
242         \
243         } else { \
244             x86_64_address_byte(2,(reg),4); \
245             x86_64_address_byte((scale),(indexreg),(basereg)); \
246             x86_64_emit_imm32((disp)); \
247         }    \
248      } while (0)
249
250
251 #define x86_64_emit_imm8(imm) \
252     *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
253
254
255 #define x86_64_emit_imm16(imm) \
256     do { \
257         x86_64_imm_buf imb; \
258         imb.i = (s4) (imm); \
259         *(cd->mcodeptr++) = imb.b[0]; \
260         *(cd->mcodeptr++) = imb.b[1]; \
261     } while (0)
262
263
264 #define x86_64_emit_imm32(imm) \
265     do { \
266         x86_64_imm_buf imb; \
267         imb.i = (s4) (imm); \
268         *(cd->mcodeptr++) = imb.b[0]; \
269         *(cd->mcodeptr++) = imb.b[1]; \
270         *(cd->mcodeptr++) = imb.b[2]; \
271         *(cd->mcodeptr++) = imb.b[3]; \
272     } while (0)
273
274
275 #define x86_64_emit_imm64(imm) \
276     do { \
277         x86_64_imm_buf imb; \
278         imb.l = (s8) (imm); \
279         *(cd->mcodeptr++) = imb.b[0]; \
280         *(cd->mcodeptr++) = imb.b[1]; \
281         *(cd->mcodeptr++) = imb.b[2]; \
282         *(cd->mcodeptr++) = imb.b[3]; \
283         *(cd->mcodeptr++) = imb.b[4]; \
284         *(cd->mcodeptr++) = imb.b[5]; \
285         *(cd->mcodeptr++) = imb.b[6]; \
286         *(cd->mcodeptr++) = imb.b[7]; \
287     } while (0)
288
289
290 /* additional functions and macros to generate code ***************************/
291
292 #define BlockPtrOfPC(pc)  ((basicblock *) iptr->target)
293
294
295 #ifdef STATISTICS
296 #define COUNT_SPILLS count_spills++
297 #else
298 #define COUNT_SPILLS
299 #endif
300
301
302 #define CALCOFFSETBYTES(var, reg, val) \
303     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
304     else if ((s4) (val) != 0) (var) += 1; \
305     else if ((reg) == RBP || (reg) == RSP || (reg) == R12 || (reg) == R13) (var) += 1;
306
307
308 #define CALCIMMEDIATEBYTES(var, val) \
309     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
310     else (var) += 1;
311
312
313 /* gen_nullptr_check(objreg) */
314
315 #define gen_nullptr_check(objreg) \
316         if (checknull) { \
317         x86_64_test_reg_reg(cd, (objreg), (objreg)); \
318         x86_64_jcc(cd, X86_64_CC_E, 0); \
319             codegen_addxnullrefs(cd, cd->mcodeptr); \
320         }
321
322
323 #define gen_bound_check \
324     if (checkbounds) { \
325         x86_64_alul_membase_reg(cd, X86_64_CMP, s1, OFFSET(java_arrayheader, size), s2); \
326         x86_64_jcc(cd, X86_64_CC_AE, 0); \
327         codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
328     }
329
330
331 #define gen_div_check(v) \
332     if (checknull) { \
333         if ((v)->flags & INMEMORY) { \
334             x86_64_alu_imm_membase(cd, X86_64_CMP, 0, REG_SP, src->regoff * 8); \
335         } else { \
336             x86_64_test_reg_reg(cd, src->regoff, src->regoff); \
337         } \
338         x86_64_jcc(cd, X86_64_CC_E, 0); \
339         codegen_addxdivrefs(cd, cd->mcodeptr); \
340     }
341
342
343 /* MCODECHECK(icnt) */
344
345 #define MCODECHECK(icnt) \
346         if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
347         cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
348
349 /* M_INTMOVE:
350     generates an integer-move from register a to b.
351     if a and b are the same int-register, no code will be generated.
352 */ 
353
354 #define M_INTMOVE(reg,dreg) \
355     if ((reg) != (dreg)) { \
356         x86_64_mov_reg_reg(cd, (reg),(dreg)); \
357     }
358
359
360 /* M_FLTMOVE:
361     generates a floating-point-move from register a to b.
362     if a and b are the same float-register, no code will be generated
363 */ 
364
365 #define M_FLTMOVE(reg,dreg) \
366     if ((reg) != (dreg)) { \
367         x86_64_movq_reg_reg(cd, (reg),(dreg)); \
368     }
369
370
371 /* var_to_reg_xxx:
372     this function generates code to fetch data from a pseudo-register
373     into a real register. 
374     If the pseudo-register has actually been assigned to a real 
375     register, no code will be emitted, since following operations
376     can use this register directly.
377     
378     v: pseudoregister to be fetched from
379     tempregnum: temporary register to be used if v is actually spilled to ram
380
381     return: the register number, where the operand can be found after 
382             fetching (this wil be either tempregnum or the register
383             number allready given to v)
384 */
385
386 #define var_to_reg_int(regnr,v,tempnr) \
387     if ((v)->flags & INMEMORY) { \
388         COUNT_SPILLS; \
389         if ((v)->type == TYPE_INT) { \
390             x86_64_movl_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
391         } else { \
392             x86_64_mov_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
393         } \
394         regnr = tempnr; \
395     } else { \
396         regnr = (v)->regoff; \
397     }
398
399
400
401 #define var_to_reg_flt(regnr,v,tempnr) \
402     if ((v)->flags & INMEMORY) { \
403         COUNT_SPILLS; \
404         if ((v)->type == TYPE_FLT) { \
405             x86_64_movlps_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
406         } else { \
407             x86_64_movlpd_membase_reg(cd, REG_SP, (v)->regoff * 8, tempnr); \
408         } \
409 /*        x86_64_movq_membase_reg(REG_SP, (v)->regoff * 8, tempnr);*/ \
410         regnr = tempnr; \
411     } else { \
412         regnr = (v)->regoff; \
413     }
414
415
416 /* store_reg_to_var_xxx:
417     This function generates the code to store the result of an operation
418     back into a spilled pseudo-variable.
419     If the pseudo-variable has not been spilled in the first place, this 
420     function will generate nothing.
421     
422     v ............ Pseudovariable
423     tempregnum ... Number of the temporary registers as returned by
424                    reg_of_var.
425 */      
426
427 #define store_reg_to_var_int(sptr, tempregnum) \
428     if ((sptr)->flags & INMEMORY) { \
429         COUNT_SPILLS; \
430         x86_64_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
431     }
432
433
434 #define store_reg_to_var_flt(sptr, tempregnum) \
435     if ((sptr)->flags & INMEMORY) { \
436          COUNT_SPILLS; \
437          x86_64_movq_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 8); \
438     }
439
440
441 #define M_COPY(from,to) \
442     d = reg_of_var(rd, to, REG_ITMP1); \
443         if ((from->regoff != to->regoff) || \
444             ((from->flags ^ to->flags) & INMEMORY)) { \
445                 if (IS_FLT_DBL_TYPE(from->type)) { \
446                         var_to_reg_flt(s1, from, d); \
447                         M_FLTMOVE(s1, d); \
448                         store_reg_to_var_flt(to, d); \
449                 } else { \
450                         var_to_reg_int(s1, from, d); \
451                         M_INTMOVE(s1, d); \
452                         store_reg_to_var_int(to, d); \
453                 } \
454         }
455
456
457 /* function gen_resolvebranch **************************************************
458
459     backpatches a branch instruction
460
461     parameters: ip ... pointer to instruction after branch (void*)
462                 so ... offset of instruction after branch  (s8)
463                 to ... offset of branch target             (s8)
464
465 *******************************************************************************/
466
467 #define gen_resolvebranch(ip,so,to) \
468     *((s4*) ((ip) - 4)) = (s4) ((to) - (so));
469
470
471 /* function prototypes */
472
473 void thread_restartcriticalsection(ucontext_t *uc);
474
475 #endif /* _CODEGEN_H */
476
477
478 /*
479  * These are local overrides for various environment variables in Emacs.
480  * Please do not remove this and leave it at the end of the file, where
481  * Emacs will automagically detect them.
482  * ---------------------------------------------------------------------
483  * Local variables:
484  * mode: c
485  * indent-tabs-mode: t
486  * c-basic-offset: 4
487  * tab-width: 4
488  * End:
489  */