Fix error logic for undefined reference in library
[tinycc.git] / i386-gen.c
blobd9c4dde0c8f3bff5b903ce308a1abcab3391e7d5
1 /*
2 * X86 code generator for TCC
3 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #ifdef TARGET_DEFS_ONLY
23 /* number of available registers */
24 #define NB_REGS 5
25 #define NB_ASM_REGS 8
27 /* a register can belong to several classes. The classes must be
28 sorted from more general to more precise (see gv2() code which does
29 assumptions on it). */
30 #define RC_INT 0x0001 /* generic integer register */
31 #define RC_FLOAT 0x0002 /* generic float register */
32 #define RC_EAX 0x0004
33 #define RC_ST0 0x0008
34 #define RC_ECX 0x0010
35 #define RC_EDX 0x0020
36 #define RC_EBX 0x0040
38 #define RC_IRET RC_EAX /* function return: integer register */
39 #define RC_LRET RC_EDX /* function return: second integer register */
40 #define RC_FRET RC_ST0 /* function return: float register */
42 /* pretty names for the registers */
43 enum {
44 TREG_EAX = 0,
45 TREG_ECX,
46 TREG_EDX,
47 TREG_EBX,
48 TREG_ST0,
49 TREG_ESP = 4
52 /* return registers for function */
53 #define REG_IRET TREG_EAX /* single word int return register */
54 #define REG_LRET TREG_EDX /* second word return register (for long long) */
55 #define REG_FRET TREG_ST0 /* float return register */
57 /* defined if function parameters must be evaluated in reverse order */
58 #define INVERT_FUNC_PARAMS
60 /* defined if structures are passed as pointers. Otherwise structures
61 are directly pushed on stack. */
62 /* #define FUNC_STRUCT_PARAM_AS_PTR */
64 /* pointer size, in bytes */
65 #define PTR_SIZE 4
67 /* long double size and alignment, in bytes */
68 #define LDOUBLE_SIZE 12
69 #define LDOUBLE_ALIGN 4
70 /* maximum alignment (for aligned attribute support) */
71 #define MAX_ALIGN 8
74 #define psym oad
76 /******************************************************/
77 /* ELF defines */
79 #define EM_TCC_TARGET EM_386
81 /* relocation type for 32 bit data relocation */
82 #define R_DATA_32 R_386_32
83 #define R_DATA_PTR R_386_32
84 #define R_JMP_SLOT R_386_JMP_SLOT
85 #define R_COPY R_386_COPY
87 #define ELF_START_ADDR 0x08048000
88 #define ELF_PAGE_SIZE 0x1000
90 /******************************************************/
91 #else /* ! TARGET_DEFS_ONLY */
92 /******************************************************/
93 #include "tcc.h"
95 /* define to 1/0 to [not] have EBX as 4th register */
96 #define USE_EBX 1
98 ST_DATA const int reg_classes[NB_REGS] = {
99 /* eax */ RC_INT | RC_EAX,
100 /* ecx */ RC_INT | RC_ECX,
101 /* edx */ RC_INT | RC_EDX,
102 /* ebx */ (RC_INT | RC_EBX) * USE_EBX,
103 /* st0 */ RC_FLOAT | RC_ST0,
106 static unsigned long func_sub_sp_offset;
107 static int func_ret_sub;
108 #ifdef CONFIG_TCC_BCHECK
109 static addr_t func_bound_offset;
110 static unsigned long func_bound_ind;
111 #endif
113 /* XXX: make it faster ? */
114 ST_FUNC void g(int c)
116 int ind1;
117 ind1 = ind + 1;
118 if (ind1 > cur_text_section->data_allocated)
119 section_realloc(cur_text_section, ind1);
120 cur_text_section->data[ind] = c;
121 ind = ind1;
124 ST_FUNC void o(unsigned int c)
126 while (c) {
127 g(c);
128 c = c >> 8;
132 ST_FUNC void gen_le16(int v)
134 g(v);
135 g(v >> 8);
138 ST_FUNC void gen_le32(int c)
140 g(c);
141 g(c >> 8);
142 g(c >> 16);
143 g(c >> 24);
146 /* output a symbol and patch all calls to it */
147 ST_FUNC void gsym_addr(int t, int a)
149 while (t) {
150 unsigned char *ptr = cur_text_section->data + t;
151 uint32_t n = read32le(ptr); /* next value */
152 write32le(ptr, a - t - 4);
153 t = n;
157 ST_FUNC void gsym(int t)
159 gsym_addr(t, ind);
162 /* psym is used to put an instruction with a data field which is a
163 reference to a symbol. It is in fact the same as oad ! */
164 #define psym oad
166 /* instruction + 4 bytes data. Return the address of the data */
167 ST_FUNC int oad(int c, int s)
169 int ind1;
171 o(c);
172 ind1 = ind + 4;
173 if (ind1 > cur_text_section->data_allocated)
174 section_realloc(cur_text_section, ind1);
175 write32le(cur_text_section->data + ind, s);
176 s = ind;
177 ind = ind1;
178 return s;
181 /* output constant with relocation if 'r & VT_SYM' is true */
182 ST_FUNC void gen_addr32(int r, Sym *sym, int c)
184 if (r & VT_SYM)
185 greloc(cur_text_section, sym, ind, R_386_32);
186 gen_le32(c);
189 ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
191 if (r & VT_SYM)
192 greloc(cur_text_section, sym, ind, R_386_PC32);
193 gen_le32(c - 4);
196 /* generate a modrm reference. 'op_reg' contains the addtionnal 3
197 opcode bits */
198 static void gen_modrm(int op_reg, int r, Sym *sym, int c)
200 op_reg = op_reg << 3;
201 if ((r & VT_VALMASK) == VT_CONST) {
202 /* constant memory reference */
203 o(0x05 | op_reg);
204 gen_addr32(r, sym, c);
205 } else if ((r & VT_VALMASK) == VT_LOCAL) {
206 /* currently, we use only ebp as base */
207 if (c == (char)c) {
208 /* short reference */
209 o(0x45 | op_reg);
210 g(c);
211 } else {
212 oad(0x85 | op_reg, c);
214 } else {
215 g(0x00 | op_reg | (r & VT_VALMASK));
219 /* load 'r' from value 'sv' */
220 ST_FUNC void load(int r, SValue *sv)
222 int v, t, ft, fc, fr;
223 SValue v1;
225 #ifdef TCC_TARGET_PE
226 SValue v2;
227 sv = pe_getimport(sv, &v2);
228 #endif
230 fr = sv->r;
231 ft = sv->type.t;
232 fc = sv->c.i;
234 ft &= ~(VT_VOLATILE | VT_CONSTANT);
236 v = fr & VT_VALMASK;
237 if (fr & VT_LVAL) {
238 if (v == VT_LLOCAL) {
239 v1.type.t = VT_INT;
240 v1.r = VT_LOCAL | VT_LVAL;
241 v1.c.i = fc;
242 fr = r;
243 if (!(reg_classes[fr] & RC_INT))
244 fr = get_reg(RC_INT);
245 load(fr, &v1);
247 if ((ft & VT_BTYPE) == VT_FLOAT) {
248 o(0xd9); /* flds */
249 r = 0;
250 } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
251 o(0xdd); /* fldl */
252 r = 0;
253 } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
254 o(0xdb); /* fldt */
255 r = 5;
256 } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
257 o(0xbe0f); /* movsbl */
258 } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
259 o(0xb60f); /* movzbl */
260 } else if ((ft & VT_TYPE) == VT_SHORT) {
261 o(0xbf0f); /* movswl */
262 } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
263 o(0xb70f); /* movzwl */
264 } else {
265 o(0x8b); /* movl */
267 gen_modrm(r, fr, sv->sym, fc);
268 } else {
269 if (v == VT_CONST) {
270 o(0xb8 + r); /* mov $xx, r */
271 gen_addr32(fr, sv->sym, fc);
272 } else if (v == VT_LOCAL) {
273 if (fc) {
274 o(0x8d); /* lea xxx(%ebp), r */
275 gen_modrm(r, VT_LOCAL, sv->sym, fc);
276 } else {
277 o(0x89);
278 o(0xe8 + r); /* mov %ebp, r */
280 } else if (v == VT_CMP) {
281 oad(0xb8 + r, 0); /* mov $0, r */
282 o(0x0f); /* setxx %br */
283 o(fc);
284 o(0xc0 + r);
285 } else if (v == VT_JMP || v == VT_JMPI) {
286 t = v & 1;
287 oad(0xb8 + r, t); /* mov $1, r */
288 o(0x05eb); /* jmp after */
289 gsym(fc);
290 oad(0xb8 + r, t ^ 1); /* mov $0, r */
291 } else if (v != r) {
292 o(0x89);
293 o(0xc0 + r + v * 8); /* mov v, r */
298 /* store register 'r' in lvalue 'v' */
299 ST_FUNC void store(int r, SValue *v)
301 int fr, bt, ft, fc;
303 #ifdef TCC_TARGET_PE
304 SValue v2;
305 v = pe_getimport(v, &v2);
306 #endif
308 ft = v->type.t;
309 fc = v->c.i;
310 fr = v->r & VT_VALMASK;
311 ft &= ~(VT_VOLATILE | VT_CONSTANT);
312 bt = ft & VT_BTYPE;
313 /* XXX: incorrect if float reg to reg */
314 if (bt == VT_FLOAT) {
315 o(0xd9); /* fsts */
316 r = 2;
317 } else if (bt == VT_DOUBLE) {
318 o(0xdd); /* fstpl */
319 r = 2;
320 } else if (bt == VT_LDOUBLE) {
321 o(0xc0d9); /* fld %st(0) */
322 o(0xdb); /* fstpt */
323 r = 7;
324 } else {
325 if (bt == VT_SHORT)
326 o(0x66);
327 if (bt == VT_BYTE || bt == VT_BOOL)
328 o(0x88);
329 else
330 o(0x89);
332 if (fr == VT_CONST ||
333 fr == VT_LOCAL ||
334 (v->r & VT_LVAL)) {
335 gen_modrm(r, v->r, v->sym, fc);
336 } else if (fr != r) {
337 o(0xc0 + fr + r * 8); /* mov r, fr */
341 static void gadd_sp(int val)
343 if (val == (char)val) {
344 o(0xc483);
345 g(val);
346 } else {
347 oad(0xc481, val); /* add $xxx, %esp */
351 static void gen_static_call(int v)
353 Sym *sym;
355 sym = external_global_sym(v, &func_old_type, 0);
356 oad(0xe8, -4);
357 greloc(cur_text_section, sym, ind-4, R_386_PC32);
360 /* 'is_jmp' is '1' if it is a jump */
361 static void gcall_or_jmp(int is_jmp)
363 int r;
364 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
365 int rt;
366 /* constant case */
367 if (vtop->r & VT_SYM) {
368 /* relocation case */
369 greloc(cur_text_section, vtop->sym,
370 ind + 1, R_386_PC32);
371 } else {
372 /* put an empty PC32 relocation */
373 put_elf_reloc(symtab_section, cur_text_section,
374 ind + 1, R_386_PC32, 0);
376 oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
377 /* extend the return value to the whole register if necessary
378 visual studio and gcc do not always set the whole eax register
379 when assigning the return value of a function */
380 rt = vtop->type.ref->type.t;
381 switch (rt & VT_BTYPE) {
382 case VT_BYTE:
383 if (rt & VT_UNSIGNED) {
384 o(0xc0b60f); /* movzx %al, %eax */
386 else {
387 o(0xc0be0f); /* movsx %al, %eax */
389 break;
390 case VT_SHORT:
391 if (rt & VT_UNSIGNED) {
392 o(0xc0b70f); /* movzx %ax, %eax */
394 else {
395 o(0xc0bf0f); /* movsx %ax, %eax */
397 break;
398 default:
399 break;
401 } else {
402 /* otherwise, indirect call */
403 r = gv(RC_INT);
404 o(0xff); /* call/jmp *r */
405 o(0xd0 + r + (is_jmp << 4));
409 static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
410 static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
412 /* Return the number of registers needed to return the struct, or 0 if
413 returning via struct pointer. */
414 ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
416 #ifdef TCC_TARGET_PE
417 int size, align;
419 *ret_align = 1; // Never have to re-align return values for x86
420 *regsize = 4;
421 size = type_size(vt, &align);
422 if (size > 8) {
423 return 0;
424 } else if (size > 4) {
425 ret->ref = NULL;
426 ret->t = VT_LLONG;
427 return 1;
428 } else {
429 ret->ref = NULL;
430 ret->t = VT_INT;
431 return 1;
433 #else
434 *ret_align = 1; // Never have to re-align return values for x86
435 return 0;
436 #endif
439 /* Generate function call. The function address is pushed first, then
440 all the parameters in call order. This functions pops all the
441 parameters and the function address. */
442 ST_FUNC void gfunc_call(int nb_args)
444 int size, align, r, args_size, i, func_call;
445 Sym *func_sym;
447 args_size = 0;
448 for(i = 0;i < nb_args; i++) {
449 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
450 size = type_size(&vtop->type, &align);
451 /* align to stack align size */
452 size = (size + 3) & ~3;
453 /* allocate the necessary size on stack */
454 oad(0xec81, size); /* sub $xxx, %esp */
455 /* generate structure store */
456 r = get_reg(RC_INT);
457 o(0x89); /* mov %esp, r */
458 o(0xe0 + r);
459 vset(&vtop->type, r | VT_LVAL, 0);
460 vswap();
461 vstore();
462 args_size += size;
463 } else if (is_float(vtop->type.t)) {
464 gv(RC_FLOAT); /* only one float register */
465 if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
466 size = 4;
467 else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
468 size = 8;
469 else
470 size = 12;
471 oad(0xec81, size); /* sub $xxx, %esp */
472 if (size == 12)
473 o(0x7cdb);
474 else
475 o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
476 g(0x24);
477 g(0x00);
478 args_size += size;
479 } else {
480 /* simple type (currently always same size) */
481 /* XXX: implicit cast ? */
482 r = gv(RC_INT);
483 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
484 size = 8;
485 o(0x50 + vtop->r2); /* push r */
486 } else {
487 size = 4;
489 o(0x50 + r); /* push r */
490 args_size += size;
492 vtop--;
494 save_regs(0); /* save used temporary registers */
495 func_sym = vtop->type.ref;
496 func_call = func_sym->a.func_call;
497 /* fast call case */
498 if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
499 func_call == FUNC_FASTCALLW) {
500 int fastcall_nb_regs;
501 uint8_t *fastcall_regs_ptr;
502 if (func_call == FUNC_FASTCALLW) {
503 fastcall_regs_ptr = fastcallw_regs;
504 fastcall_nb_regs = 2;
505 } else {
506 fastcall_regs_ptr = fastcall_regs;
507 fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
509 for(i = 0;i < fastcall_nb_regs; i++) {
510 if (args_size <= 0)
511 break;
512 o(0x58 + fastcall_regs_ptr[i]); /* pop r */
513 /* XXX: incorrect for struct/floats */
514 args_size -= 4;
517 #ifndef TCC_TARGET_PE
518 else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
519 args_size -= 4;
520 #endif
521 gcall_or_jmp(0);
523 if (args_size && func_call != FUNC_STDCALL)
524 gadd_sp(args_size);
525 vtop--;
528 #ifdef TCC_TARGET_PE
529 #define FUNC_PROLOG_SIZE (10 + USE_EBX)
530 #else
531 #define FUNC_PROLOG_SIZE (9 + USE_EBX)
532 #endif
534 /* generate function prolog of type 't' */
535 ST_FUNC void gfunc_prolog(CType *func_type)
537 int addr, align, size, func_call, fastcall_nb_regs;
538 int param_index, param_addr;
539 uint8_t *fastcall_regs_ptr;
540 Sym *sym;
541 CType *type;
543 sym = func_type->ref;
544 func_call = sym->a.func_call;
545 addr = 8;
546 loc = 0;
547 func_vc = 0;
549 if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
550 fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
551 fastcall_regs_ptr = fastcall_regs;
552 } else if (func_call == FUNC_FASTCALLW) {
553 fastcall_nb_regs = 2;
554 fastcall_regs_ptr = fastcallw_regs;
555 } else {
556 fastcall_nb_regs = 0;
557 fastcall_regs_ptr = NULL;
559 param_index = 0;
561 ind += FUNC_PROLOG_SIZE;
562 func_sub_sp_offset = ind;
563 /* if the function returns a structure, then add an
564 implicit pointer parameter */
565 func_vt = sym->type;
566 func_var = (sym->c == FUNC_ELLIPSIS);
567 #ifdef TCC_TARGET_PE
568 size = type_size(&func_vt,&align);
569 if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
570 #else
571 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
572 #endif
573 /* XXX: fastcall case ? */
574 func_vc = addr;
575 addr += 4;
576 param_index++;
578 /* define parameters */
579 while ((sym = sym->next) != NULL) {
580 type = &sym->type;
581 size = type_size(type, &align);
582 size = (size + 3) & ~3;
583 #ifdef FUNC_STRUCT_PARAM_AS_PTR
584 /* structs are passed as pointer */
585 if ((type->t & VT_BTYPE) == VT_STRUCT) {
586 size = 4;
588 #endif
589 if (param_index < fastcall_nb_regs) {
590 /* save FASTCALL register */
591 loc -= 4;
592 o(0x89); /* movl */
593 gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
594 param_addr = loc;
595 } else {
596 param_addr = addr;
597 addr += size;
599 sym_push(sym->v & ~SYM_FIELD, type,
600 VT_LOCAL | lvalue_type(type->t), param_addr);
601 param_index++;
603 func_ret_sub = 0;
604 /* pascal type call ? */
605 if (func_call == FUNC_STDCALL)
606 func_ret_sub = addr - 8;
607 #ifndef TCC_TARGET_PE
608 else if (func_vc)
609 func_ret_sub = 4;
610 #endif
612 #ifdef CONFIG_TCC_BCHECK
613 /* leave some room for bound checking code */
614 if (tcc_state->do_bounds_check) {
615 func_bound_offset = lbounds_section->data_offset;
616 func_bound_ind = ind;
617 oad(0xb8, 0); /* lbound section pointer */
618 oad(0xb8, 0); /* call to function */
620 #endif
623 /* generate function epilog */
624 ST_FUNC void gfunc_epilog(void)
626 addr_t v, saved_ind;
628 #ifdef CONFIG_TCC_BCHECK
629 if (tcc_state->do_bounds_check
630 && func_bound_offset != lbounds_section->data_offset) {
631 addr_t saved_ind;
632 addr_t *bounds_ptr;
633 Sym *sym_data;
635 /* add end of table info */
636 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
637 *bounds_ptr = 0;
639 /* generate bound local allocation */
640 saved_ind = ind;
641 ind = func_bound_ind;
642 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
643 func_bound_offset, lbounds_section->data_offset);
644 greloc(cur_text_section, sym_data,
645 ind + 1, R_386_32);
646 oad(0xb8, 0); /* mov %eax, xxx */
647 gen_static_call(TOK___bound_local_new);
648 ind = saved_ind;
650 /* generate bound check local freeing */
651 o(0x5250); /* save returned value, if any */
652 greloc(cur_text_section, sym_data, ind + 1, R_386_32);
653 oad(0xb8, 0); /* mov %eax, xxx */
654 gen_static_call(TOK___bound_local_delete);
655 o(0x585a); /* restore returned value, if any */
657 #endif
658 o(0x5b * USE_EBX); /* pop ebx */
659 o(0xc9); /* leave */
660 if (func_ret_sub == 0) {
661 o(0xc3); /* ret */
662 } else {
663 o(0xc2); /* ret n */
664 g(func_ret_sub);
665 g(func_ret_sub >> 8);
667 /* align local size to word & save local variables */
669 v = (-loc + 3) & -4;
670 saved_ind = ind;
671 ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
672 #ifdef TCC_TARGET_PE
673 if (v >= 4096) {
674 oad(0xb8, v); /* mov stacksize, %eax */
675 gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
676 } else
677 #endif
679 o(0xe58955); /* push %ebp, mov %esp, %ebp */
680 o(0xec81); /* sub esp, stacksize */
681 gen_le32(v);
682 #ifdef TCC_TARGET_PE
683 o(0x90); /* adjust to FUNC_PROLOG_SIZE */
684 #endif
686 o(0x53 * USE_EBX); /* push ebx */
687 ind = saved_ind;
690 /* generate a jump to a label */
691 ST_FUNC int gjmp(int t)
693 return psym(0xe9, t);
696 /* generate a jump to a fixed address */
697 ST_FUNC void gjmp_addr(int a)
699 int r;
700 r = a - ind - 2;
701 if (r == (char)r) {
702 g(0xeb);
703 g(r);
704 } else {
705 oad(0xe9, a - ind - 5);
709 ST_FUNC void gtst_addr(int inv, int a)
711 inv ^= (vtop--)->c.i;
712 a -= ind + 2;
713 if (a == (char)a) {
714 g(inv - 32);
715 g(a);
716 } else {
717 g(0x0f);
718 oad(inv - 16, a - 4);
722 /* generate a test. set 'inv' to invert test. Stack entry is popped */
723 ST_FUNC int gtst(int inv, int t)
725 int v = vtop->r & VT_VALMASK;
726 if (v == VT_CMP) {
727 /* fast case : can jump directly since flags are set */
728 g(0x0f);
729 t = psym((vtop->c.i - 16) ^ inv, t);
730 } else if (v == VT_JMP || v == VT_JMPI) {
731 /* && or || optimization */
732 if ((v & 1) == inv) {
733 /* insert vtop->c jump list in t */
734 uint32_t n1, n = vtop->c.i;
735 if (n) {
736 while ((n1 = read32le(cur_text_section->data + n)))
737 n = n1;
738 write32le(cur_text_section->data + n, t);
739 t = vtop->c.i;
741 } else {
742 t = gjmp(t);
743 gsym(vtop->c.i);
746 vtop--;
747 return t;
750 /* generate an integer binary operation */
751 ST_FUNC void gen_opi(int op)
753 int r, fr, opc, c;
755 switch(op) {
756 case '+':
757 case TOK_ADDC1: /* add with carry generation */
758 opc = 0;
759 gen_op8:
760 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
761 /* constant case */
762 vswap();
763 r = gv(RC_INT);
764 vswap();
765 c = vtop->c.i;
766 if (c == (char)c) {
767 /* generate inc and dec for smaller code */
768 if (c==1 && opc==0 && op != TOK_ADDC1) {
769 o (0x40 | r); // inc
770 } else if (c==1 && opc==5 && op != TOK_SUBC1) {
771 o (0x48 | r); // dec
772 } else {
773 o(0x83);
774 o(0xc0 | (opc << 3) | r);
775 g(c);
777 } else {
778 o(0x81);
779 oad(0xc0 | (opc << 3) | r, c);
781 } else {
782 gv2(RC_INT, RC_INT);
783 r = vtop[-1].r;
784 fr = vtop[0].r;
785 o((opc << 3) | 0x01);
786 o(0xc0 + r + fr * 8);
788 vtop--;
789 if (op >= TOK_ULT && op <= TOK_GT) {
790 vtop->r = VT_CMP;
791 vtop->c.i = op;
793 break;
794 case '-':
795 case TOK_SUBC1: /* sub with carry generation */
796 opc = 5;
797 goto gen_op8;
798 case TOK_ADDC2: /* add with carry use */
799 opc = 2;
800 goto gen_op8;
801 case TOK_SUBC2: /* sub with carry use */
802 opc = 3;
803 goto gen_op8;
804 case '&':
805 opc = 4;
806 goto gen_op8;
807 case '^':
808 opc = 6;
809 goto gen_op8;
810 case '|':
811 opc = 1;
812 goto gen_op8;
813 case '*':
814 gv2(RC_INT, RC_INT);
815 r = vtop[-1].r;
816 fr = vtop[0].r;
817 vtop--;
818 o(0xaf0f); /* imul fr, r */
819 o(0xc0 + fr + r * 8);
820 break;
821 case TOK_SHL:
822 opc = 4;
823 goto gen_shift;
824 case TOK_SHR:
825 opc = 5;
826 goto gen_shift;
827 case TOK_SAR:
828 opc = 7;
829 gen_shift:
830 opc = 0xc0 | (opc << 3);
831 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
832 /* constant case */
833 vswap();
834 r = gv(RC_INT);
835 vswap();
836 c = vtop->c.i & 0x1f;
837 o(0xc1); /* shl/shr/sar $xxx, r */
838 o(opc | r);
839 g(c);
840 } else {
841 /* we generate the shift in ecx */
842 gv2(RC_INT, RC_ECX);
843 r = vtop[-1].r;
844 o(0xd3); /* shl/shr/sar %cl, r */
845 o(opc | r);
847 vtop--;
848 break;
849 case '/':
850 case TOK_UDIV:
851 case TOK_PDIV:
852 case '%':
853 case TOK_UMOD:
854 case TOK_UMULL:
855 /* first operand must be in eax */
856 /* XXX: need better constraint for second operand */
857 gv2(RC_EAX, RC_ECX);
858 r = vtop[-1].r;
859 fr = vtop[0].r;
860 vtop--;
861 save_reg(TREG_EDX);
862 /* save EAX too if used otherwise */
863 save_reg_upstack(TREG_EAX, 1);
864 if (op == TOK_UMULL) {
865 o(0xf7); /* mul fr */
866 o(0xe0 + fr);
867 vtop->r2 = TREG_EDX;
868 r = TREG_EAX;
869 } else {
870 if (op == TOK_UDIV || op == TOK_UMOD) {
871 o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
872 o(0xf0 + fr);
873 } else {
874 o(0xf799); /* cltd, idiv fr, %eax */
875 o(0xf8 + fr);
877 if (op == '%' || op == TOK_UMOD)
878 r = TREG_EDX;
879 else
880 r = TREG_EAX;
882 vtop->r = r;
883 break;
884 default:
885 opc = 7;
886 goto gen_op8;
890 /* generate a floating point operation 'v = t1 op t2' instruction. The
891 two operands are guaranted to have the same floating point type */
892 /* XXX: need to use ST1 too */
893 ST_FUNC void gen_opf(int op)
895 int a, ft, fc, swapped, r;
897 /* convert constants to memory references */
898 if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
899 vswap();
900 gv(RC_FLOAT);
901 vswap();
903 if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
904 gv(RC_FLOAT);
906 /* must put at least one value in the floating point register */
907 if ((vtop[-1].r & VT_LVAL) &&
908 (vtop[0].r & VT_LVAL)) {
909 vswap();
910 gv(RC_FLOAT);
911 vswap();
913 swapped = 0;
914 /* swap the stack if needed so that t1 is the register and t2 is
915 the memory reference */
916 if (vtop[-1].r & VT_LVAL) {
917 vswap();
918 swapped = 1;
920 if (op >= TOK_ULT && op <= TOK_GT) {
921 /* load on stack second operand */
922 load(TREG_ST0, vtop);
923 save_reg(TREG_EAX); /* eax is used by FP comparison code */
924 if (op == TOK_GE || op == TOK_GT)
925 swapped = !swapped;
926 else if (op == TOK_EQ || op == TOK_NE)
927 swapped = 0;
928 if (swapped)
929 o(0xc9d9); /* fxch %st(1) */
930 if (op == TOK_EQ || op == TOK_NE)
931 o(0xe9da); /* fucompp */
932 else
933 o(0xd9de); /* fcompp */
934 o(0xe0df); /* fnstsw %ax */
935 if (op == TOK_EQ) {
936 o(0x45e480); /* and $0x45, %ah */
937 o(0x40fC80); /* cmp $0x40, %ah */
938 } else if (op == TOK_NE) {
939 o(0x45e480); /* and $0x45, %ah */
940 o(0x40f480); /* xor $0x40, %ah */
941 op = TOK_NE;
942 } else if (op == TOK_GE || op == TOK_LE) {
943 o(0x05c4f6); /* test $0x05, %ah */
944 op = TOK_EQ;
945 } else {
946 o(0x45c4f6); /* test $0x45, %ah */
947 op = TOK_EQ;
949 vtop--;
950 vtop->r = VT_CMP;
951 vtop->c.i = op;
952 } else {
953 /* no memory reference possible for long double operations */
954 if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
955 load(TREG_ST0, vtop);
956 swapped = !swapped;
959 switch(op) {
960 default:
961 case '+':
962 a = 0;
963 break;
964 case '-':
965 a = 4;
966 if (swapped)
967 a++;
968 break;
969 case '*':
970 a = 1;
971 break;
972 case '/':
973 a = 6;
974 if (swapped)
975 a++;
976 break;
978 ft = vtop->type.t;
979 fc = vtop->c.i;
980 if ((ft & VT_BTYPE) == VT_LDOUBLE) {
981 o(0xde); /* fxxxp %st, %st(1) */
982 o(0xc1 + (a << 3));
983 } else {
984 /* if saved lvalue, then we must reload it */
985 r = vtop->r;
986 if ((r & VT_VALMASK) == VT_LLOCAL) {
987 SValue v1;
988 r = get_reg(RC_INT);
989 v1.type.t = VT_INT;
990 v1.r = VT_LOCAL | VT_LVAL;
991 v1.c.i = fc;
992 load(r, &v1);
993 fc = 0;
996 if ((ft & VT_BTYPE) == VT_DOUBLE)
997 o(0xdc);
998 else
999 o(0xd8);
1000 gen_modrm(a, r, vtop->sym, fc);
1002 vtop--;
1006 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1007 and 'long long' cases. */
1008 ST_FUNC void gen_cvt_itof(int t)
1010 save_reg(TREG_ST0);
1011 gv(RC_INT);
1012 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
1013 /* signed long long to float/double/long double (unsigned case
1014 is handled generically) */
1015 o(0x50 + vtop->r2); /* push r2 */
1016 o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
1017 o(0x242cdf); /* fildll (%esp) */
1018 o(0x08c483); /* add $8, %esp */
1019 } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
1020 (VT_INT | VT_UNSIGNED)) {
1021 /* unsigned int to float/double/long double */
1022 o(0x6a); /* push $0 */
1023 g(0x00);
1024 o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
1025 o(0x242cdf); /* fildll (%esp) */
1026 o(0x08c483); /* add $8, %esp */
1027 } else {
1028 /* int to float/double/long double */
1029 o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
1030 o(0x2404db); /* fildl (%esp) */
1031 o(0x04c483); /* add $4, %esp */
1033 vtop->r = TREG_ST0;
1036 /* convert fp to int 't' type */
1037 ST_FUNC void gen_cvt_ftoi(int t)
1039 #if 1
1040 gv(RC_FLOAT);
1041 save_reg(TREG_EAX);
1042 save_reg(TREG_EDX);
1043 gen_static_call(TOK___tcc_cvt_ftol);
1044 vtop->r = TREG_EAX; /* mark reg as used */
1045 if (t == VT_LLONG)
1046 vtop->r2 = TREG_EDX;
1047 #else
1048 int bt = vtop->type.t & VT_BTYPE;
1049 if (bt == VT_FLOAT)
1050 vpush_global_sym(&func_old_type, TOK___fixsfdi);
1051 else if (bt == VT_LDOUBLE)
1052 vpush_global_sym(&func_old_type, TOK___fixxfdi);
1053 else
1054 vpush_global_sym(&func_old_type, TOK___fixdfdi);
1055 vswap();
1056 gfunc_call(1);
1057 vpushi(0);
1058 vtop->r = REG_IRET;
1059 vtop->r2 = REG_LRET;
1060 #endif
1063 /* convert from one floating point type to another */
1064 ST_FUNC void gen_cvt_ftof(int t)
1066 /* all we have to do on i386 is to put the float in a register */
1067 gv(RC_FLOAT);
1070 /* computed goto support */
1071 ST_FUNC void ggoto(void)
1073 gcall_or_jmp(1);
1074 vtop--;
1077 /* bound check support functions */
1078 #ifdef CONFIG_TCC_BCHECK
1080 /* generate a bounded pointer addition */
1081 ST_FUNC void gen_bounded_ptr_add(void)
1083 /* prepare fast i386 function call (args in eax and edx) */
1084 gv2(RC_EAX, RC_EDX);
1085 /* save all temporary registers */
1086 vtop -= 2;
1087 save_regs(0);
1088 /* do a fast function call */
1089 gen_static_call(TOK___bound_ptr_add);
1090 /* returned pointer is in eax */
1091 vtop++;
1092 vtop->r = TREG_EAX | VT_BOUNDED;
1093 /* address of bounding function call point */
1094 vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
1097 /* patch pointer addition in vtop so that pointer dereferencing is
1098 also tested */
1099 ST_FUNC void gen_bounded_ptr_deref(void)
1101 addr_t func;
1102 int size, align;
1103 Elf32_Rel *rel;
1104 Sym *sym;
1106 size = 0;
1107 /* XXX: put that code in generic part of tcc */
1108 if (!is_float(vtop->type.t)) {
1109 if (vtop->r & VT_LVAL_BYTE)
1110 size = 1;
1111 else if (vtop->r & VT_LVAL_SHORT)
1112 size = 2;
1114 if (!size)
1115 size = type_size(&vtop->type, &align);
1116 switch(size) {
1117 case 1: func = TOK___bound_ptr_indir1; break;
1118 case 2: func = TOK___bound_ptr_indir2; break;
1119 case 4: func = TOK___bound_ptr_indir4; break;
1120 case 8: func = TOK___bound_ptr_indir8; break;
1121 case 12: func = TOK___bound_ptr_indir12; break;
1122 case 16: func = TOK___bound_ptr_indir16; break;
1123 default:
1124 tcc_error("unhandled size when dereferencing bounded pointer");
1125 func = 0;
1126 break;
1129 /* patch relocation */
1130 /* XXX: find a better solution ? */
1131 rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
1132 sym = external_global_sym(func, &func_old_type, 0);
1133 if (!sym->c)
1134 put_extern_sym(sym, NULL, 0, 0);
1135 rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
1137 #endif
1139 /* Save the stack pointer onto the stack */
1140 ST_FUNC void gen_vla_sp_save(int addr) {
1141 /* mov %esp,addr(%ebp)*/
1142 o(0x89);
1143 gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
1146 /* Restore the SP from a location on the stack */
1147 ST_FUNC void gen_vla_sp_restore(int addr) {
1148 o(0x8b);
1149 gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
1152 /* Subtract from the stack pointer, and push the resulting value onto the stack */
1153 ST_FUNC void gen_vla_alloc(CType *type, int align) {
1154 #ifdef TCC_TARGET_PE
1155 /* alloca does more than just adjust %rsp on Windows */
1156 vpush_global_sym(&func_old_type, TOK_alloca);
1157 vswap(); /* Move alloca ref past allocation size */
1158 gfunc_call(1);
1159 #else
1160 int r;
1161 r = gv(RC_INT); /* allocation size */
1162 /* sub r,%rsp */
1163 o(0x2b);
1164 o(0xe0 | r);
1165 /* We align to 16 bytes rather than align */
1166 /* and ~15, %esp */
1167 o(0xf0e483);
1168 vpop();
1169 #endif
1172 /* end of X86 code generator */
1173 /*************************************************************/
1174 #endif
1175 /*************************************************************/