4 Byte Stackslots for i386 (native Calling Convention)
[cacao.git] / src / vm / jit / i386 / codegen.h
1 /* src/vm/jit/i386/codegen.h - code generation macros and definitions for i386
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    Changes:
31
32    $Id: codegen.h 2356 2005-04-22 17:33:35Z christian $
33
34 */
35
36
37 #ifndef _CODEGEN_H
38 #define _CODEGEN_H
39
40 #include <ucontext.h>
41
42 #ifdef LSRA
43 /* let LSRA allocate reserved registers (REG_ITMP[1|2|3]) */
44 #define LSRA_USES_REG_RES
45 #endif
46
47 /* SET_ARG_STACKSLOTS ***************************************************
48 Macro for stack.c to set Argument Stackslots
49
50 Sets the first call_argcount stackslots of curstack to varkind ARGVAR, if
51 they to not have the SAVEDVAR flag set. According to the calling
52 conventions these stackslots are assigned argument registers or memory
53 locations
54
55 --- in
56 i:                Number of arguments for this method
57 curstack:         instack of the method invokation
58
59 --- uses
60 i, copy
61
62 --- out
63 copy:             Points to first stackslot after the parameters
64 rd->ifmemuse:     max. number of stackslots used for spilling parameters
65                   so far
66 ************************************************************************/
67 #if defined(HAS_4BYTE_STACKSLOT)
68 #define SET_ARG_STACKSLOTS {                                                            \
69                 s4 stacksize = 0;                                                                       \
70                 copy = curstack;                                                                        \
71                 while (--i >= 0) {                                                                      \
72                         stacksize+=IS_2_WORD_TYPE(copy->type)?2:1;              \
73                         copy = copy->prev;                                                              \
74                 }                                                                                                       \
75                 i=call_argcount;                                                                        \
76                 copy=curstack;                                                                          \
77                 if (stacksize > rd->ifmemuse)                                           \
78                         rd->ifmemuse = stacksize;                                               \
79                 while (--i >= 0) {                                                                      \
80                         stacksize -= IS_2_WORD_TYPE(copy->type)?2:1;    \
81                         if (!(copy->flags & SAVEDVAR)) {                                \
82                                 copy->varkind = ARGVAR;                                         \
83                                 copy->varnum = i;                                                       \
84                                 copy->flags |= INMEMORY;                                        \
85                                 copy->regoff = stacksize;                                       \
86                         }                                                                                               \
87                         copy = copy->prev;                                                              \
88                 }                                                                                                       \
89         }
90 #else
91 #define SET_ARG_STACKSLOTS {                                    \
92                 copy = curstack;                                                \
93                 if (i > rd->ifmemuse)                                   \
94                         rd->ifmemuse = i;                                       \
95                 while (--i >= 0) {                                              \
96                         if (!(copy->flags & SAVEDVAR)) {        \
97                                 copy->varkind = ARGVAR;                 \
98                                 copy->varnum = i;                               \
99                                 copy->flags |= INMEMORY;                \
100                                 copy->regoff = i;                               \
101                         }                                                                       \
102                         copy = copy->prev;                                      \
103                 }                                                                               \
104         }
105 #endif /*  defined(HAS_4BYTE_STACKSLOTS) */
106
107 /* additional functions and macros to generate code ***************************/
108
109 #define BlockPtrOfPC(pc)  ((basicblock *) iptr->target)
110
111
112 #ifdef STATISTICS
113 #define COUNT_SPILLS count_spills++
114 #else
115 #define COUNT_SPILLS
116 #endif
117
118
119 #define CALCOFFSETBYTES(var, reg, val) \
120     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
121     else if ((s4) (val) != 0) (var) += 1; \
122     else if ((reg) == EBP) (var) += 1;
123
124
125 #define CALCIMMEDIATEBYTES(var, val) \
126     if ((s4) (val) < -128 || (s4) (val) > 127) (var) += 4; \
127     else (var) += 1;
128
129
130 /* gen_nullptr_check(objreg) */
131
132 #define gen_nullptr_check(objreg) \
133         if (checknull) { \
134         i386_test_reg_reg(cd, (objreg), (objreg)); \
135         i386_jcc(cd, I386_CC_E, 0); \
136             codegen_addxnullrefs(cd, cd->mcodeptr); \
137         }
138
139 #define gen_bound_check \
140     if (checkbounds) { \
141         i386_alu_membase_reg(cd, I386_CMP, s1, OFFSET(java_arrayheader, size), s2); \
142         i386_jcc(cd, I386_CC_AE, 0); \
143         codegen_addxboundrefs(cd, cd->mcodeptr, s2); \
144     }
145
146 #define gen_div_check(v) \
147     if (checknull) { \
148         if ((v)->flags & INMEMORY) { \
149             i386_alu_imm_membase(cd, I386_CMP, 0, REG_SP, src->regoff * 4); \
150         } else { \
151             i386_test_reg_reg(cd, src->regoff, src->regoff); \
152         } \
153         i386_jcc(cd, I386_CC_E, 0); \
154         codegen_addxdivrefs(cd, cd->mcodeptr); \
155     }
156
157
158 /* MCODECHECK(icnt) */
159
160 #define MCODECHECK(icnt) \
161         if ((cd->mcodeptr + (icnt)) > (u1 *) cd->mcodeend) \
162         cd->mcodeptr = (u1 *) codegen_increase(cd, cd->mcodeptr)
163
164
165 /* XXX Do we need code padding on i386? */
166 /*  #define ALIGNCODENOP {if((int)((long)cd->mcodeptr&7)){M_NOP;}} */
167 #define ALIGNCODENOP
168
169
170 /* M_INTMOVE:
171      generates an integer-move from register a to b.
172      if a and b are the same int-register, no code will be generated.
173 */ 
174
175 #define M_INTMOVE(reg,dreg) \
176     if ((reg) != (dreg)) { \
177         i386_mov_reg_reg(cd, (reg),(dreg)); \
178     }
179
180
181 /* M_FLTMOVE:
182     generates a floating-point-move from register a to b.
183     if a and b are the same float-register, no code will be generated
184 */
185
186 #define M_FLTMOVE(reg,dreg) panic("M_FLTMOVE");
187
188 #define M_LNGMEMMOVE(reg,dreg) \
189     do { \
190         i386_mov_membase_reg(cd, REG_SP, (reg) * 4, REG_ITMP1); \
191         i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 4); \
192         i386_mov_membase_reg(cd, REG_SP, (reg) * 4 + 4, REG_ITMP1); \
193         i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, (dreg) * 4 + 4); \
194     } while (0)
195
196
197 /* var_to_reg_xxx:
198     this function generates code to fetch data from a pseudo-register
199     into a real register. 
200     If the pseudo-register has actually been assigned to a real 
201     register, no code will be emitted, since following operations
202     can use this register directly.
203     
204     v: pseudoregister to be fetched from
205     tempregnum: temporary register to be used if v is actually spilled to ram
206
207     return: the register number, where the operand can be found after 
208             fetching (this wil be either tempregnum or the register
209             number allready given to v)
210 */
211
212 #define var_to_reg_int(regnr,v,tempnr) \
213     if ((v)->flags & INMEMORY) { \
214         COUNT_SPILLS; \
215         i386_mov_membase_reg(cd, REG_SP, (v)->regoff * 4, tempnr); \
216         regnr = tempnr; \
217     } else { \
218         regnr = (v)->regoff; \
219     }
220
221
222
223 #define var_to_reg_flt(regnr,v,tempnr) \
224     if ((v)->type == TYPE_FLT) { \
225         if ((v)->flags & INMEMORY) { \
226             COUNT_SPILLS; \
227             i386_flds_membase(cd, REG_SP, (v)->regoff * 4); \
228             fpu_st_offset++; \
229             regnr = tempnr; \
230         } else { \
231             i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
232             fpu_st_offset++; \
233             regnr = (v)->regoff; \
234         } \
235     } else { \
236         if ((v)->flags & INMEMORY) { \
237             COUNT_SPILLS; \
238             i386_fldl_membase(cd, REG_SP, (v)->regoff * 4); \
239             fpu_st_offset++; \
240             regnr = tempnr; \
241         } else { \
242             i386_fld_reg(cd, (v)->regoff + fpu_st_offset); \
243             fpu_st_offset++; \
244             regnr = (v)->regoff; \
245         } \
246     }
247
248 #define NEW_var_to_reg_flt(regnr,v,tempnr) \
249     if ((v)->type == TYPE_FLT) { \
250        if ((v)->flags & INMEMORY) { \
251             COUNT_SPILLS; \
252             i386_flds_membase(cd, REG_SP, (v)->regoff * 4); \
253             fpu_st_offset++; \
254             regnr = tempnr; \
255         } else { \
256             regnr = (v)->regoff; \
257         } \
258     } else { \
259         if ((v)->flags & INMEMORY) { \
260             COUNT_SPILLS; \
261             i386_fldl_membase(cd, REG_SP, (v)->regoff * 4); \
262             fpu_st_offset++; \
263             regnr = tempnr; \
264         } else { \
265             regnr = (v)->regoff; \
266         } \
267     }
268
269
270 /* store_reg_to_var_xxx:
271     This function generates the code to store the result of an operation
272     back into a spilled pseudo-variable.
273     If the pseudo-variable has not been spilled in the first place, this 
274     function will generate nothing.
275     
276     v ............ Pseudovariable
277     tempregnum ... Number of the temporary registers as returned by
278                    reg_of_var.
279 */      
280
281 #define store_reg_to_var_int(sptr, tempregnum) \
282     if ((sptr)->flags & INMEMORY) { \
283         COUNT_SPILLS; \
284         i386_mov_reg_membase(cd, tempregnum, REG_SP, (sptr)->regoff * 4); \
285     }
286
287
288 #define store_reg_to_var_flt(sptr, tempregnum) \
289     if ((sptr)->type == TYPE_FLT) { \
290         if ((sptr)->flags & INMEMORY) { \
291              COUNT_SPILLS; \
292              i386_fstps_membase(cd, REG_SP, (sptr)->regoff * 4); \
293              fpu_st_offset--; \
294         } else { \
295 /*                  i386_fxch_reg((sptr)->regoff);*/ \
296              i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
297              fpu_st_offset--; \
298         } \
299     } else { \
300         if ((sptr)->flags & INMEMORY) { \
301             COUNT_SPILLS; \
302             i386_fstpl_membase(cd, REG_SP, (sptr)->regoff * 4); \
303             fpu_st_offset--; \
304         } else { \
305 /*                  i386_fxch_reg((sptr)->regoff);*/ \
306             i386_fstp_reg(cd, (sptr)->regoff + fpu_st_offset); \
307             fpu_st_offset--; \
308         } \
309     }
310
311
312 #define M_COPY(from,to) \
313     d = reg_of_var(rd, to, REG_ITMP1); \
314         if ((from->regoff != to->regoff) || \
315             ((from->flags ^ to->flags) & INMEMORY)) { \
316                 if (IS_FLT_DBL_TYPE(from->type)) { \
317                         var_to_reg_flt(s1, from, d); \
318                         /*M_FLTMOVE(s1, d);*/ \
319                         store_reg_to_var_flt(to, d); \
320                 } else { \
321             if (!IS_2_WORD_TYPE(from->type)) { \
322                 if (to->flags & INMEMORY) { \
323                      if (from->flags & INMEMORY) { \
324                          i386_mov_membase_reg(cd, REG_SP, from->regoff * 4, REG_ITMP1); \
325                          i386_mov_reg_membase(cd, REG_ITMP1, REG_SP, to->regoff * 4); \
326                      } else { \
327                          i386_mov_reg_membase(cd, from->regoff, REG_SP, to->regoff * 4); \
328                      } \
329                 } else { \
330                      if (from->flags & INMEMORY) { \
331                          i386_mov_membase_reg(cd, REG_SP, from->regoff * 4, to->regoff); \
332                      } else { \
333                          i386_mov_reg_reg(cd, from->regoff, to->regoff); \
334                      } \
335                 } \
336             } else { \
337                 M_LNGMEMMOVE(from->regoff, to->regoff); \
338             } \
339                 } \
340         }
341
342 /* macros to create code ******************************************************/
343
344 typedef enum {
345     I386_AL = 0,
346     I386_CL = 1,
347     I386_DL = 2,
348     I386_BL = 3,
349     I386_AH = 4,
350     I386_CH = 5,
351     I386_DH = 6,
352     I386_BH = 7,
353     I386_NREGB
354 } I386_RegB_No;
355
356
357 /* opcodes for alu instructions */
358
359 typedef enum {
360     I386_ADD = 0,
361     I386_OR  = 1,
362     I386_ADC = 2,
363     I386_SBB = 3,
364     I386_AND = 4,
365     I386_SUB = 5,
366     I386_XOR = 6,
367     I386_CMP = 7,
368     I386_NALU
369 } I386_ALU_Opcode;
370
371 typedef enum {
372     I386_ROL = 0,
373     I386_ROR = 1,
374     I386_RCL = 2,
375     I386_RCR = 3,
376     I386_SHL = 4,
377     I386_SHR = 5,
378     I386_SAR = 7,
379     I386_NSHIFT = 8
380 } I386_Shift_Opcode;
381
382 typedef enum {
383     I386_CC_O = 0,
384     I386_CC_NO = 1,
385     I386_CC_B = 2, I386_CC_C = 2, I386_CC_NAE = 2,
386     I386_CC_BE = 6, I386_CC_NA = 6,
387     I386_CC_AE = 3, I386_CC_NB = 3, I386_CC_NC = 3,
388     I386_CC_E = 4, I386_CC_Z = 4,
389     I386_CC_NE = 5, I386_CC_NZ = 5,
390     I386_CC_A = 7, I386_CC_NBE = 7,
391     I386_CC_S = 8, I386_CC_LZ = 8,
392     I386_CC_NS = 9, I386_CC_GEZ = 9,
393     I386_CC_P = 0x0a, I386_CC_PE = 0x0a,
394     I386_CC_NP = 0x0b, I386_CC_PO = 0x0b,
395     I386_CC_L = 0x0c, I386_CC_NGE = 0x0c,
396     I386_CC_GE = 0x0d, I386_CC_NL = 0x0d,
397     I386_CC_LE = 0x0e, I386_CC_NG = 0x0e,
398     I386_CC_G = 0x0f, I386_CC_NLE = 0x0f,
399     I386_NCC
400 } I386_CC;
401
402
403 /* modrm and stuff */
404
405 #define i386_address_byte(mod,reg,rm) \
406     *(cd->mcodeptr++) = ((((mod) & 0x03) << 6) | (((reg) & 0x07) << 3) | (((rm) & 0x07)));
407
408
409 #define i386_emit_reg(reg,rm) \
410     i386_address_byte(3,(reg),(rm));
411
412
413 #define i386_is_imm8(imm) \
414     (((int)(imm) >= -128 && (int)(imm) <= 127))
415
416
417 #define i386_emit_imm8(imm) \
418     *(cd->mcodeptr++) = (u1) ((imm) & 0xff);
419
420
421 #define i386_emit_imm16(imm) \
422     do { \
423         imm_union imb; \
424         imb.i = (int) (imm); \
425         *(cd->mcodeptr++) = imb.b[0]; \
426         *(cd->mcodeptr++) = imb.b[1]; \
427     } while (0)
428
429
430 #define i386_emit_imm32(imm) \
431     do { \
432         imm_union imb; \
433         imb.i = (int) (imm); \
434         *(cd->mcodeptr++) = imb.b[0]; \
435         *(cd->mcodeptr++) = imb.b[1]; \
436         *(cd->mcodeptr++) = imb.b[2]; \
437         *(cd->mcodeptr++) = imb.b[3]; \
438     } while (0)
439
440
441 #define i386_emit_mem(r,mem) \
442     do { \
443         i386_address_byte(0,(r),5); \
444         i386_emit_imm32((mem)); \
445     } while (0)
446
447
448 #define i386_emit_membase(basereg,disp,dreg) \
449     do { \
450         if ((basereg) == ESP) { \
451             if ((disp) == 0) { \
452                 i386_address_byte(0, (dreg), ESP); \
453                 i386_address_byte(0, ESP, ESP); \
454             } else if (i386_is_imm8((disp))) { \
455                 i386_address_byte(1, (dreg), ESP); \
456                 i386_address_byte(0, ESP, ESP); \
457                 i386_emit_imm8((disp)); \
458             } else { \
459                 i386_address_byte(2, (dreg), ESP); \
460                 i386_address_byte(0, ESP, ESP); \
461                 i386_emit_imm32((disp)); \
462             } \
463             break; \
464         } \
465         \
466         if ((disp) == 0 && (basereg) != EBP) { \
467             i386_address_byte(0, (dreg), (basereg)); \
468             break; \
469         } \
470         \
471         if (i386_is_imm8((disp))) { \
472             i386_address_byte(1, (dreg), (basereg)); \
473             i386_emit_imm8((disp)); \
474         } else { \
475             i386_address_byte(2, (dreg), (basereg)); \
476             i386_emit_imm32((disp)); \
477         } \
478     } while (0)
479
480
481 #define i386_emit_membase32(basereg,disp,dreg) \
482     do { \
483         if ((basereg) == ESP) { \
484             i386_address_byte(2, (dreg), ESP); \
485             i386_address_byte(0, ESP, ESP); \
486             i386_emit_imm32((disp)); \
487         } else { \
488             i386_address_byte(2, (dreg), (basereg)); \
489             i386_emit_imm32((disp)); \
490         } \
491     } while (0)
492
493
494 #define i386_emit_memindex(reg,disp,basereg,indexreg,scale) \
495     do { \
496         if ((basereg) == -1) { \
497             i386_address_byte(0, (reg), 4); \
498             i386_address_byte((scale), (indexreg), 5); \
499             i386_emit_imm32((disp)); \
500         \
501         } else if ((disp) == 0 && (basereg) != EBP) { \
502             i386_address_byte(0, (reg), 4); \
503             i386_address_byte((scale), (indexreg), (basereg)); \
504         \
505         } else if (i386_is_imm8((disp))) { \
506             i386_address_byte(1, (reg), 4); \
507             i386_address_byte((scale), (indexreg), (basereg)); \
508             i386_emit_imm8 ((disp)); \
509         \
510         } else { \
511             i386_address_byte(2, (reg), 4); \
512             i386_address_byte((scale), (indexreg), (basereg)); \
513             i386_emit_imm32((disp)); \
514         }    \
515      } while (0)
516
517
518 /* function gen_resolvebranch **************************************************
519
520     backpatches a branch instruction
521
522     parameters: ip ... pointer to instruction after branch (void*)
523                 so ... offset of instruction after branch  (s4)
524                 to ... offset of branch target             (s4)
525
526 *******************************************************************************/
527
528 #define gen_resolvebranch(ip,so,to) \
529     *((void **) ((ip) - 4)) = (void **) ((to) - (so));
530
531
532 /* function prototypes */
533
534 void thread_restartcriticalsection(ucontext_t *);
535
536 #endif /* _CODEGEN_H */
537
538
539 /*
540  * These are local overrides for various environment variables in Emacs.
541  * Please do not remove this and leave it at the end of the file, where
542  * Emacs will automagically detect them.
543  * ---------------------------------------------------------------------
544  * Local variables:
545  * mode: c
546  * indent-tabs-mode: t
547  * c-basic-offset: 4
548  * tab-width: 4
549  * End:
550  */