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