2 * X86 code generator for TCC
4 * Copyright (c) 2001 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* number of available registers */
24 /* a register can belong to several classes */
25 #define RC_INT 0x0001 /* generic integer register */
26 #define RC_FLOAT 0x0002 /* generic float register */
27 #define RC_IRET 0x0004 /* function returned integer register */
28 #define RC_FRET 0x0008 /* function returned float register */
30 /* pretty names for the registers */
38 int reg_classes
[NB_REGS
] = {
39 /* eax */ RC_INT
| RC_IRET
,
42 /* st0 */ RC_FLOAT
| RC_FRET
,
45 /* return registers for function */
46 #define REG_IRET REG_EAX
47 #define REG_FRET REG_ST0
49 /* defined if function parameters must be evaluated in reverse order */
50 #define INVERT_FUNC_PARAMS
52 /* defined if structures are passed as pointers. Otherwise structures
53 are directly pushed on stack. */
54 //#define FUNC_STRUCT_PARAM_AS_PTR
56 /* pointer size, in bytes */
59 /* long double size and alignment, in bytes */
60 #define LDOUBLE_SIZE 12
61 #define LDOUBLE_ALIGN 4
63 /* function call context */
64 typedef struct GFuncContext
{
68 /******************************************************/
91 /* patch relocation entry with value 'val' */
92 void greloc_patch1(Reloc
*p
, int val
)
96 *(int *)p
->addr
= val
;
99 *(int *)p
->addr
= val
- p
->addr
- 4;
104 /* output a symbol and patch all calls to it */
109 n
= *(int *)t
; /* next value */
110 *(int *)t
= a
- t
- 4;
120 /* psym is used to put an instruction with a data field which is a
121 reference to a symbol. It is in fact the same as oad ! */
124 /* instruction + 4 bytes data. Return the address of the data */
125 int oad(int c
, int s
)
134 /* output constant with relocation if 'r & VT_FORWARD' is true */
135 void gen_addr32(int r
, int c
)
137 if (!(r
& VT_FORWARD
)) {
140 greloc((Sym
*)c
, ind
, RELOC_ADDR32
);
145 /* generate a modrm reference. 'op_reg' contains the addtionnal 3
147 void gen_modrm(int op_reg
, int r
, int c
)
149 op_reg
= op_reg
<< 3;
150 if ((r
& VT_VALMASK
) == VT_CONST
) {
151 /* constant memory reference */
154 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
155 /* currently, we use only ebp as base */
157 /* short reference */
161 oad(0x85 | op_reg
, c
);
164 g(0x00 | op_reg
| (r
& VT_VALMASK
));
169 /* load 'r' from value 'sv' */
170 void load(int r
, SValue
*sv
)
172 int v
, t
, ft
, fc
, fr
;
181 if (v
== VT_LLOCAL
) {
183 v1
.r
= VT_LOCAL
| VT_LVAL
;
188 if ((ft
& VT_BTYPE
) == VT_FLOAT
) {
191 } else if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
194 } else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
) {
197 } else if ((ft
& VT_TYPE
) == VT_BYTE
)
198 o(0xbe0f); /* movsbl */
199 else if ((ft
& VT_TYPE
) == (VT_BYTE
| VT_UNSIGNED
))
200 o(0xb60f); /* movzbl */
201 else if ((ft
& VT_TYPE
) == VT_SHORT
)
202 o(0xbf0f); /* movswl */
203 else if ((ft
& VT_TYPE
) == (VT_SHORT
| VT_UNSIGNED
))
204 o(0xb70f); /* movzwl */
207 gen_modrm(r
, fr
, fc
);
210 o(0xb8 + r
); /* mov $xx, r */
212 } else if (v
== VT_LOCAL
) {
213 o(0x8d); /* lea xxx(%ebp), r */
214 gen_modrm(r
, VT_LOCAL
, fc
);
215 } else if (v
== VT_CMP
) {
216 oad(0xb8 + r
, 0); /* mov $0, r */
217 o(0x0f); /* setxx %br */
220 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
222 oad(0xb8 + r
, t
); /* mov $1, r */
223 oad(0xe9, 5); /* jmp after */
225 oad(0xb8 + r
, t
^ 1); /* mov $0, r */
228 o(0xc0 + r
+ v
* 8); /* mov v, r */
233 /* store register 'r' in lvalue 'v' */
234 void store(int r
, SValue
*v
)
240 fr
= v
->r
& VT_VALMASK
;
242 /* XXX: incorrect if float reg to reg */
243 if (bt
== VT_FLOAT
) {
246 } else if (bt
== VT_DOUBLE
) {
249 } else if (bt
== VT_LDOUBLE
) {
250 o(0xc0d9); /* fld %st(0) */
261 if (fr
== VT_CONST
||
264 gen_modrm(r
, v
->r
, fc
);
265 } else if (fr
!= r
) {
266 o(0xc0 + fr
+ r
* 8); /* mov r, fr */
270 /* start function call and return function call context */
271 void gfunc_start(GFuncContext
*c
)
276 /* push function parameter which is in (vtop->t, vtop->c). Stack entry
278 void gfunc_param(GFuncContext
*c
)
282 if ((vtop
->t
& VT_BTYPE
) == VT_STRUCT
) {
283 size
= type_size(vtop
->t
, &align
);
284 /* align to stack align size */
285 size
= (size
+ 3) & ~3;
286 /* allocate the necessary size on stack */
287 oad(0xec81, size
); /* sub $xxx, %esp */
288 /* generate structure store */
290 o(0x89); /* mov %esp, r */
295 c
->args_size
+= size
;
296 } else if (is_float(vtop
->t
)) {
297 gv(RC_FLOAT
); /* only one float register */
298 if ((vtop
->t
& VT_BTYPE
) == VT_FLOAT
)
300 else if ((vtop
->t
& VT_BTYPE
) == VT_DOUBLE
)
304 oad(0xec81, size
); /* sub $xxx, %esp */
308 o(0x5cd9 + size
- 4); /* fstp[s|l] 0(%esp) */
311 c
->args_size
+= size
;
313 /* simple type (currently always same size) */
314 /* XXX: implicit cast ? */
316 o(0x50 + r
); /* push r */
322 /* generate function call with address in (vtop->t, vtop->c) and free function
323 context. Stack entry is popped */
324 void gfunc_call(GFuncContext
*c
)
327 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
329 /* forward reference */
330 if (vtop
->r
& VT_FORWARD
) {
331 greloc(vtop
->c
.sym
, ind
+ 1, RELOC_REL32
);
334 oad(0xe8, vtop
->c
.ul
- ind
- 5);
337 /* otherwise, indirect call */
339 o(0xff); /* call *r */
343 oad(0xc481, c
->args_size
); /* add $xxx, %esp */
349 return psym(0xe9, t
);
352 /* generate a test. set 'inv' to invert test. Stack entry is popped */
353 int gtst(int inv
, int t
)
356 v
= vtop
->r
& VT_VALMASK
;
358 /* fast case : can jump directly since flags are set */
360 t
= psym((vtop
->c
.i
- 16) ^ inv
, t
);
361 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
362 /* && or || optimization */
363 if ((v
& 1) == inv
) {
364 /* insert vtop->c jump list in t */
375 if (is_float(vtop
->t
)) {
379 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_FORWARD
)) == VT_CONST
) {
380 /* constant jmp optimization */
381 if ((vtop
->c
.i
!= 0) != inv
)
388 t
= psym(0x85 ^ inv
, t
);
395 /* generate an integer binary operation */
408 o(0xc0 + r
+ fr
* 8);
409 } else if (op
== '-') {
411 o(0xc0 + r
+ fr
* 8);
412 } else if (op
== '&') {
414 o(0xc0 + r
+ fr
* 8);
415 } else if (op
== '^') {
417 o(0xc0 + r
+ fr
* 8);
418 } else if (op
== '|') {
420 o(0xc0 + r
+ fr
* 8);
421 } else if (op
== '*') {
422 o(0xaf0f); /* imul fr, r */
423 o(0xc0 + fr
+ r
* 8);
424 } else if (op
== TOK_SHL
| op
== TOK_SHR
| op
== TOK_SAR
) {
430 o(0x87); /* xchg r, %ecx */
435 o(0xd3); /* shl/shr/sar %cl, r */
438 else if (op
== TOK_SHR
)
443 } else if (op
== '/' | op
== TOK_UDIV
| op
== TOK_PDIV
|
444 op
== '%' | op
== TOK_UMOD
) {
445 save_reg(2); /* save edx */
446 t
= save_reg_forced(fr
); /* save fr and get op2 location */
447 move_reg(0, r
); /* op1 is %eax */
448 if (op
== TOK_UDIV
| op
== TOK_UMOD
) {
449 o(0xf7d231); /* xor %edx, %edx, div t(%ebp), %eax */
452 o(0xf799); /* cltd, idiv t(%ebp), %eax */
455 if (op
== '%' | op
== TOK_UMOD
)
463 o(0xc0 + r
+ fr
* 8); /* cmp fr, r */
464 vset(VT_INT
, VT_CMP
, op
);
468 /* generate a floating point operation 'v = t1 op t2' instruction. The
469 two operands are guaranted to have the same floating point type */
470 /* NOTE: currently floats can only be lvalues */
473 int a
, ft
, fc
, swapped
;
475 /* convert constants to memory references */
476 if ((vtop
[-1].r
& (VT_CONST
| VT_LVAL
)) == VT_CONST
) {
481 if ((vtop
[0].r
& (VT_CONST
| VT_LVAL
)) == VT_CONST
)
484 /* must put at least one value in the floating point register */
485 if ((vtop
[-1].r
& VT_LVAL
) &&
486 (vtop
[0].r
& VT_LVAL
)) {
491 if (op
>= TOK_EQ
&& op
<= TOK_GT
) {
492 /* load on stack second operand */
494 if (op
== TOK_GE
|| op
== TOK_GT
)
495 o(0xc9d9); /* fxch %st(1) */
496 o(0xe9da); /* fucompp */
497 o(0xe0df); /* fnstsw %ax */
499 o(0x45e480); /* and $0x45, %ah */
500 o(0x40fC80); /* cmp $0x40, %ah */
501 } else if (op
== TOK_NE
) {
502 o(0x45e480); /* and $0x45, %ah */
503 o(0x40f480); /* xor $0x40, %ah */
505 } else if (op
== TOK_GE
|| op
== TOK_LE
) {
506 o(0x05c4f6); /* test $0x05, %ah */
509 o(0x45c4f6); /* test $0x45, %ah */
517 /* swap the stack if needed so that t1 is the register and t2 is
518 the memory reference */
519 if (vtop
[-1].r
& VT_LVAL
) {
523 /* no memory reference possible for long double operations */
524 if ((vtop
->t
& VT_BTYPE
) == VT_LDOUBLE
) {
550 if ((ft
& VT_BTYPE
) == VT_LDOUBLE
) {
551 o(0xde); /* fxxxp %st, %st(1) */
554 if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
558 gen_modrm(a
, vtop
->r
, fc
);
564 /* convert integers to fp 't' type */
565 void gen_cvt_itof(int t
)
568 if ((vtop
->t
& (VT_BTYPE
| VT_UNSIGNED
)) == (VT_INT
| VT_UNSIGNED
)) {
569 /* unsigned int to float/double/long double */
570 o(0x6a); /* push $0 */
572 o(0x50 + (vtop
->r
& VT_VALMASK
)); /* push r */
573 o(0x242cdf); /* fildll (%esp) */
574 o(0x08c483); /* add $8, %esp */
576 /* int to float/double/long double */
577 o(0x50 + (vtop
->r
& VT_VALMASK
)); /* push r */
578 o(0x2404db); /* fildl (%esp) */
579 o(0x04c483); /* add $4, %esp */
584 /* FPU control word for rounding to nearest mode */
585 /* XXX: should move that into tcc lib support code ! */
586 static unsigned short __tcc_fpu_control
= 0x137f;
587 /* FPU control word for round to zero mode for int convertion */
588 static unsigned short __tcc_int_fpu_control
= 0x137f | 0x0c00;
590 /* convert fp to int 't' type */
591 /* XXX: handle long long case */
592 void gen_cvt_ftoi(int t
)
597 if (t
== VT_INT
| VT_UNSIGNED
&&
598 t
== VT_LLONG
| VT_UNSIGNED
&&
605 oad(0x2dd9, (int)&__tcc_int_fpu_control
); /* ldcw xxx */
606 oad(0xec81, size
); /* sub $xxx, %esp */
608 o(0x1cdb); /* fistpl */
610 o(0x3cdb); /* fistpll */
612 oad(0x2dd9, (int)&__tcc_fpu_control
); /* ldcw xxx */
613 o(0x58 + r
); /* pop r */
615 o(0x04c483); /* add $4, %esp */
619 /* convert from one floating point type to another */
620 void gen_cvt_ftof(int t
)
622 /* all we have to do on i386 is to put the float in a register */
626 /* pop stack value */
629 /* for x86, we need to pop the FP stack */
630 if ((vtop
->r
& VT_VALMASK
) == REG_ST0
) {
631 o(0xd9dd); /* fstp %st(1) */
638 /* end of X86 code generator */
639 /*************************************************************/