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