Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  X86 code generator for TCC
  3.  *
  4.  *  Copyright (c) 2001-2004 Fabrice Bellard
  5.  *
  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.
  10.  *
  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.
  15.  *
  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
  19.  */
  20.  
  21. /* number of available registers */
  22. #define NB_REGS             4
  23.  
  24. /* a register can belong to several classes. The classes must be
  25.    sorted from more general to more precise (see gv2() code which does
  26.    assumptions on it). */
  27. #define RC_INT     0x0001 /* generic integer register */
  28. #define RC_FLOAT   0x0002 /* generic float register */
  29. #define RC_EAX     0x0004
  30. #define RC_ST0     0x0008
  31. #define RC_ECX     0x0010
  32. #define RC_EDX     0x0020
  33. #define RC_IRET    RC_EAX /* function return: integer register */
  34. #define RC_LRET    RC_EDX /* function return: second integer register */
  35. #define RC_FRET    RC_ST0 /* function return: float register */
  36.  
  37. /* pretty names for the registers */
  38. enum {
  39.     TREG_EAX = 0,
  40.     TREG_ECX,
  41.     TREG_EDX,
  42.     TREG_ST0,
  43. };
  44.  
  45. int reg_classes[NB_REGS] = {
  46.     /* eax */ RC_INT | RC_EAX,
  47.     /* ecx */ RC_INT | RC_ECX,
  48.     /* edx */ RC_INT | RC_EDX,
  49.     /* st0 */ RC_FLOAT | RC_ST0,
  50. };
  51.  
  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 */
  56.  
  57. /* defined if function parameters must be evaluated in reverse order */
  58. #define INVERT_FUNC_PARAMS
  59.  
  60. /* defined if structures are passed as pointers. Otherwise structures
  61.    are directly pushed on stack. */
  62. //#define FUNC_STRUCT_PARAM_AS_PTR
  63.  
  64. /* pointer size, in bytes */
  65. #define PTR_SIZE 4
  66.  
  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
  72.  
  73. /******************************************************/
  74. /* ELF defines */
  75.  
  76. #define EM_TCC_TARGET EM_386
  77.  
  78. /* relocation type for 32 bit data relocation */
  79. #define R_DATA_32   R_386_32
  80. #define R_JMP_SLOT  R_386_JMP_SLOT
  81. #define R_COPY      R_386_COPY
  82.  
  83. #define ELF_START_ADDR 0x08048000
  84. #define ELF_PAGE_SIZE  0x1000
  85.  
  86. /******************************************************/
  87.  
  88. static unsigned long func_sub_sp_offset;
  89. static unsigned long func_bound_offset;
  90. static int func_ret_sub;
  91.  
  92. /* XXX: make it faster ? */
  93. void g(int c)
  94. {
  95.     int ind1;
  96.     ind1 = ind + 1;
  97.     if (ind1 > cur_text_section->data_allocated)
  98.         section_realloc(cur_text_section, ind1);
  99.     cur_text_section->data[ind] = c;
  100.     ind = ind1;
  101. }
  102.  
  103. void o(unsigned int c)
  104. {
  105.     while (c) {
  106.         g(c);
  107.         c = c >> 8;
  108.     }
  109. }
  110.  
  111. void gen_le32(int c)
  112. {
  113.     g(c);
  114.     g(c >> 8);
  115.     g(c >> 16);
  116.     g(c >> 24);
  117. }
  118.  
  119. /* output a symbol and patch all calls to it */
  120. void gsym_addr(int t, int a)
  121. {
  122.     int n, *ptr;
  123.     while (t) {
  124.         ptr = (int *)(cur_text_section->data + t);
  125.         n = *ptr; /* next value */
  126.         *ptr = a - t - 4;
  127.         t = n;
  128.     }
  129. }
  130.  
  131. void gsym(int t)
  132. {
  133.     gsym_addr(t, ind);
  134. }
  135.  
  136. /* psym is used to put an instruction with a data field which is a
  137.    reference to a symbol. It is in fact the same as oad ! */
  138. #define psym oad
  139.  
  140. /* instruction + 4 bytes data. Return the address of the data */
  141. static int oad(int c, int s)
  142. {
  143.     int ind1;
  144.  
  145.     o(c);
  146.     ind1 = ind + 4;
  147.     if (ind1 > cur_text_section->data_allocated)
  148.         section_realloc(cur_text_section, ind1);
  149.     *(int *)(cur_text_section->data + ind) = s;
  150.     s = ind;
  151.     ind = ind1;
  152.     return s;
  153. }
  154.  
  155. /* output constant with relocation if 'r & VT_SYM' is true */
  156. static void gen_addr32(int r, Sym *sym, int c)
  157. {
  158.     if (r & VT_SYM)
  159.         greloc(cur_text_section, sym, ind, R_386_32);
  160.     gen_le32(c);
  161. }
  162.  
  163. /* generate a modrm reference. 'op_reg' contains the addtionnal 3
  164.    opcode bits */
  165. static void gen_modrm(int op_reg, int r, Sym *sym, int c)
  166. {
  167.     op_reg = op_reg << 3;
  168.     if ((r & VT_VALMASK) == VT_CONST) {
  169.         /* constant memory reference */
  170.         o(0x05 | op_reg);
  171.         gen_addr32(r, sym, c);
  172.     } else if ((r & VT_VALMASK) == VT_LOCAL) {
  173.         /* currently, we use only ebp as base */
  174.         if (c == (char)c) {
  175.             /* short reference */
  176.             o(0x45 | op_reg);
  177.             g(c);
  178.         } else {
  179.             oad(0x85 | op_reg, c);
  180.         }
  181.     } else {
  182.         g(0x00 | op_reg | (r & VT_VALMASK));
  183.     }
  184. }
  185.  
  186.  
  187. /* load 'r' from value 'sv' */
  188. void load(int r, SValue *sv)
  189. {
  190.     int v, t, ft, fc, fr;
  191.     SValue v1;
  192.  
  193.     fr = sv->r;
  194.     ft = sv->type.t;
  195.     fc = sv->c.ul;
  196.  
  197.     v = fr & VT_VALMASK;
  198.     if (fr & VT_LVAL) {
  199.         if (v == VT_LLOCAL) {
  200.             v1.type.t = VT_INT;
  201.             v1.r = VT_LOCAL | VT_LVAL;
  202.             v1.c.ul = fc;
  203.             load(r, &v1);
  204.             fr = r;
  205.         }
  206.         if ((ft & VT_BTYPE) == VT_FLOAT) {
  207.             o(0xd9); /* flds */
  208.             r = 0;
  209.         } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
  210.             o(0xdd); /* fldl */
  211.             r = 0;
  212.         } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
  213.             o(0xdb); /* fldt */
  214.             r = 5;
  215.         } else if ((ft & VT_TYPE) == VT_BYTE) {
  216.             o(0xbe0f);   /* movsbl */
  217.         } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
  218.             o(0xb60f);   /* movzbl */
  219.         } else if ((ft & VT_TYPE) == VT_SHORT) {
  220.             o(0xbf0f);   /* movswl */
  221.         } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
  222.             o(0xb70f);   /* movzwl */
  223.         } else {
  224.             o(0x8b);     /* movl */
  225.         }
  226.         gen_modrm(r, fr, sv->sym, fc);
  227.     } else {
  228.         if (v == VT_CONST) {
  229.             o(0xb8 + r); /* mov $xx, r */
  230.             gen_addr32(fr, sv->sym, fc);
  231.         } else if (v == VT_LOCAL) {
  232.             o(0x8d); /* lea xxx(%ebp), r */
  233.             gen_modrm(r, VT_LOCAL, sv->sym, fc);
  234.         } else if (v == VT_CMP) {
  235.             oad(0xb8 + r, 0); /* mov $0, r */
  236.             o(0x0f); /* setxx %br */
  237.             o(fc);
  238.             o(0xc0 + r);
  239.         } else if (v == VT_JMP || v == VT_JMPI) {
  240.             t = v & 1;
  241.             oad(0xb8 + r, t); /* mov $1, r */
  242.             o(0x05eb); /* jmp after */
  243.             gsym(fc);
  244.             oad(0xb8 + r, t ^ 1); /* mov $0, r */
  245.         } else if (v != r) {
  246.             o(0x89);
  247.             o(0xc0 + r + v * 8); /* mov v, r */
  248.         }
  249.     }
  250. }
  251.  
  252. /* store register 'r' in lvalue 'v' */
  253. void store(int r, SValue *v)
  254. {
  255.     int fr, bt, ft, fc;
  256.  
  257.     ft = v->type.t;
  258.     fc = v->c.ul;
  259.     fr = v->r & VT_VALMASK;
  260.     bt = ft & VT_BTYPE;
  261.     /* XXX: incorrect if float reg to reg */
  262.     if (bt == VT_FLOAT) {
  263.         o(0xd9); /* fsts */
  264.         r = 2;
  265.     } else if (bt == VT_DOUBLE) {
  266.         o(0xdd); /* fstpl */
  267.         r = 2;
  268.     } else if (bt == VT_LDOUBLE) {
  269.         o(0xc0d9); /* fld %st(0) */
  270.         o(0xdb); /* fstpt */
  271.         r = 7;
  272.     } else {
  273.         if (bt == VT_SHORT)
  274.             o(0x66);
  275.         if (bt == VT_BYTE || bt == VT_BOOL)
  276.             o(0x88);
  277.         else
  278.             o(0x89);
  279.     }
  280.     if (fr == VT_CONST ||
  281.         fr == VT_LOCAL ||
  282.         (v->r & VT_LVAL)) {
  283.         gen_modrm(r, v->r, v->sym, fc);
  284.     } else if (fr != r) {
  285.         o(0xc0 + fr + r * 8); /* mov r, fr */
  286.     }
  287. }
  288.  
  289. static void gadd_sp(int val)
  290. {
  291.     if (val == (char)val) {
  292.         o(0xc483);
  293.         g(val);
  294.     } else {
  295.         oad(0xc481, val); /* add $xxx, %esp */
  296.     }
  297. }
  298.  
  299. /* 'is_jmp' is '1' if it is a jump */
  300. static void gcall_or_jmp(int is_jmp)
  301. {
  302.     int r;
  303.     if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
  304.         /* constant case */
  305.         if (vtop->r & VT_SYM) {
  306.             /* relocation case */
  307.             greloc(cur_text_section, vtop->sym,
  308.                    ind + 1, R_386_PC32);
  309.         } else {
  310.             /* put an empty PC32 relocation */
  311.             put_elf_reloc(symtab_section, cur_text_section,
  312.                           ind + 1, R_386_PC32, 0);
  313.         }
  314.         oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
  315.     } else {
  316.         /* otherwise, indirect call */
  317.         r = gv(RC_INT);
  318.         o(0xff); /* call/jmp *r */
  319.         o(0xd0 + r + (is_jmp << 4));
  320.     }
  321. }
  322.  
  323. static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
  324.  
  325. /* Generate function call. The function address is pushed first, then
  326.    all the parameters in call order. This functions pops all the
  327.    parameters and the function address. */
  328. void gfunc_call(int nb_args)
  329. {
  330.     int size, align, r, args_size, i, func_call;
  331.     Sym *func_sym;
  332.    
  333.     args_size = 0;
  334.     for(i = 0;i < nb_args; i++) {
  335.         if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
  336.             size = type_size(&vtop->type, &align);
  337.             /* align to stack align size */
  338.             size = (size + 3) & ~3;
  339.             /* allocate the necessary size on stack */
  340.             oad(0xec81, size); /* sub $xxx, %esp */
  341.             /* generate structure store */
  342.             r = get_reg(RC_INT);
  343.             o(0x89); /* mov %esp, r */
  344.             o(0xe0 + r);
  345.             vset(&vtop->type, r | VT_LVAL, 0);
  346.             vswap();
  347.             vstore();
  348.             args_size += size;
  349.         } else if (is_float(vtop->type.t)) {
  350.             gv(RC_FLOAT); /* only one float register */
  351.             if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
  352.                 size = 4;
  353.             else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
  354.                 size = 8;
  355.             else
  356.                 size = 12;
  357.             oad(0xec81, size); /* sub $xxx, %esp */
  358.             if (size == 12)
  359.                 o(0x7cdb);
  360.             else
  361.                 o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
  362.             g(0x24);
  363.             g(0x00);
  364.             args_size += size;
  365.         } else {
  366.             /* simple type (currently always same size) */
  367.             /* XXX: implicit cast ? */
  368.             r = gv(RC_INT);
  369.             if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
  370.                 size = 8;
  371.                 o(0x50 + vtop->r2); /* push r */
  372.             } else {
  373.                 size = 4;
  374.             }
  375.             o(0x50 + r); /* push r */
  376.             args_size += size;
  377.         }
  378.         vtop--;
  379.     }
  380.     save_regs(0); /* save used temporary registers */
  381.     func_sym = vtop->type.ref;
  382.     func_call = func_sym->r;
  383.     /* fast call case */
  384.     if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
  385.         int fastcall_nb_regs;
  386.         fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
  387.         for(i = 0;i < fastcall_nb_regs; i++) {
  388.             if (args_size <= 0)
  389.                 break;
  390.             o(0x58 + fastcall_regs[i]); /* pop r */
  391.             /* XXX: incorrect for struct/floats */
  392.             args_size -= 4;
  393.         }
  394.     }
  395.     gcall_or_jmp(0);
  396.     if (args_size && func_sym->r != FUNC_STDCALL)
  397.         gadd_sp(args_size);
  398.     vtop--;
  399. }
  400.  
  401. #ifdef TCC_TARGET_PE
  402. #define FUNC_PROLOG_SIZE 10
  403. #else
  404. #define FUNC_PROLOG_SIZE 9
  405. #endif
  406.  
  407. /* generate function prolog of type 't' */
  408. void gfunc_prolog(CType *func_type)
  409. {
  410.     int addr, align, size, func_call, fastcall_nb_regs;
  411.     int param_index, param_addr;
  412.     Sym *sym;
  413.     CType *type;
  414.  
  415.     sym = func_type->ref;
  416.     func_call = sym->r;
  417.     addr = 8;
  418.     loc = 0;
  419.     if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
  420.         fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
  421.     } else {
  422.         fastcall_nb_regs = 0;
  423.     }
  424.     param_index = 0;
  425.  
  426.     ind += FUNC_PROLOG_SIZE;
  427.     func_sub_sp_offset = ind;
  428.     /* if the function returns a structure, then add an
  429.        implicit pointer parameter */
  430.     func_vt = sym->type;
  431.     if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
  432.         /* XXX: fastcall case ? */
  433.         func_vc = addr;
  434.         addr += 4;
  435.         param_index++;
  436.     }
  437.     /* define parameters */
  438.     while ((sym = sym->next) != NULL) {
  439.         type = &sym->type;
  440.         size = type_size(type, &align);
  441.         size = (size + 3) & ~3;
  442. #ifdef FUNC_STRUCT_PARAM_AS_PTR
  443.         /* structs are passed as pointer */
  444.         if ((type->t & VT_BTYPE) == VT_STRUCT) {
  445.             size = 4;
  446.         }
  447. #endif
  448.         if (param_index < fastcall_nb_regs) {
  449.             /* save FASTCALL register */
  450.             loc -= 4;
  451.             o(0x89);     /* movl */
  452.             gen_modrm(fastcall_regs[param_index], VT_LOCAL, NULL, loc);
  453.             param_addr = loc;
  454.         } else {
  455.             param_addr = addr;
  456.             addr += size;
  457.         }
  458.         sym_push(sym->v & ~SYM_FIELD, type,
  459.                  VT_LOCAL | VT_LVAL, param_addr);
  460.         param_index++;
  461.     }
  462.     func_ret_sub = 0;
  463.     /* pascal type call ? */
  464.     if (func_call == FUNC_STDCALL)
  465.         func_ret_sub = addr - 8;
  466.  
  467.     /* leave some room for bound checking code */
  468.     if (do_bounds_check) {
  469.         oad(0xb8, 0); /* lbound section pointer */
  470.         oad(0xb8, 0); /* call to function */
  471.         func_bound_offset = lbounds_section->data_offset;
  472.     }
  473. }
  474.  
  475. /* generate function epilog */
  476. void gfunc_epilog(void)
  477. {
  478.     int v, saved_ind;
  479.  
  480. #ifdef CONFIG_TCC_BCHECK
  481.     if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) {
  482.         int saved_ind;
  483.         int *bounds_ptr;
  484.         Sym *sym, *sym_data;
  485.         /* add end of table info */
  486.         bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
  487.         *bounds_ptr = 0;
  488.         /* generate bound local allocation */
  489.         saved_ind = ind;
  490.         ind = func_sub_sp_offset;
  491.         sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
  492.                                func_bound_offset, lbounds_section->data_offset);
  493.         greloc(cur_text_section, sym_data,
  494.                ind + 1, R_386_32);
  495.         oad(0xb8, 0); /* mov %eax, xxx */
  496.         sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
  497.         greloc(cur_text_section, sym,
  498.                ind + 1, R_386_PC32);
  499.         oad(0xe8, -4);
  500.         ind = saved_ind;
  501.         /* generate bound check local freeing */
  502.         o(0x5250); /* save returned value, if any */
  503.         greloc(cur_text_section, sym_data,
  504.                ind + 1, R_386_32);
  505.         oad(0xb8, 0); /* mov %eax, xxx */
  506.         sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
  507.         greloc(cur_text_section, sym,
  508.                ind + 1, R_386_PC32);
  509.         oad(0xe8, -4);
  510.         o(0x585a); /* restore returned value, if any */
  511.     }
  512. #endif
  513.     o(0xc9); /* leave */
  514.     if (func_ret_sub == 0) {
  515.         o(0xc3); /* ret */
  516.     } else {
  517.         o(0xc2); /* ret n */
  518.         g(func_ret_sub);
  519.         g(func_ret_sub >> 8);
  520.     }
  521.     /* align local size to word & save local variables */
  522.    
  523.     v = (-loc + 3) & -4;
  524.     saved_ind = ind;
  525.     ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
  526. #ifdef TCC_TARGET_PE
  527.     if (v >= 4096) {
  528.         Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
  529.         oad(0xb8, v); /* mov stacksize, %eax */
  530.         oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
  531.         greloc(cur_text_section, sym, ind-4, R_386_PC32);
  532.     } else
  533. #endif
  534.     {
  535.         o(0xe58955);  /* push %ebp, mov %esp, %ebp */
  536.         o(0xec81);  /* sub esp, stacksize */
  537.         gen_le32(v);
  538. #if FUNC_PROLOG_SIZE == 10
  539.         o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
  540. #endif
  541.     }
  542.     ind = saved_ind;
  543. }
  544.  
  545. /* generate a jump to a label */
  546. int gjmp(int t)
  547. {
  548.     return psym(0xe9, t);
  549. }
  550.  
  551. /* generate a jump to a fixed address */
  552. void gjmp_addr(int a)
  553. {
  554.     int r;
  555.     r = a - ind - 2;
  556.     if (r == (char)r) {
  557.         g(0xeb);
  558.         g(r);
  559.     } else {
  560.         oad(0xe9, a - ind - 5);
  561.     }
  562. }
  563.  
  564. /* generate a test. set 'inv' to invert test. Stack entry is popped */
  565. int gtst(int inv, int t)
  566. {
  567.     int v, *p;
  568.  
  569.     v = vtop->r & VT_VALMASK;
  570.     if (v == VT_CMP) {
  571.         /* fast case : can jump directly since flags are set */
  572.         g(0x0f);
  573.         t = psym((vtop->c.i - 16) ^ inv, t);
  574.     } else if (v == VT_JMP || v == VT_JMPI) {
  575.         /* && or || optimization */
  576.         if ((v & 1) == inv) {
  577.             /* insert vtop->c jump list in t */
  578.             p = &vtop->c.i;
  579.             while (*p != 0)
  580.                 p = (int *)(cur_text_section->data + *p);
  581.             *p = t;
  582.             t = vtop->c.i;
  583.         } else {
  584.             t = gjmp(t);
  585.             gsym(vtop->c.i);
  586.         }
  587.     } else {
  588.         if (is_float(vtop->type.t)) {
  589.             vpushi(0);
  590.             gen_op(TOK_NE);
  591.         }
  592.         if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  593.             /* constant jmp optimization */
  594.             if ((vtop->c.i != 0) != inv)
  595.                 t = gjmp(t);
  596.         } else {
  597.             v = gv(RC_INT);
  598.             o(0x85);
  599.             o(0xc0 + v * 9);
  600.             g(0x0f);
  601.             t = psym(0x85 ^ inv, t);
  602.         }
  603.     }
  604.     vtop--;
  605.     return t;
  606. }
  607.  
  608. /* generate an integer binary operation */
  609. void gen_opi(int op)
  610. {
  611.     int r, fr, opc, c;
  612.  
  613.     switch(op) {
  614.     case '+':
  615.     case TOK_ADDC1: /* add with carry generation */
  616.         opc = 0;
  617.     gen_op8:
  618.         if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  619.             /* constant case */
  620.             vswap();
  621.             r = gv(RC_INT);
  622.             vswap();
  623.             c = vtop->c.i;
  624.             if (c == (char)c) {
  625.                 /* XXX: generate inc and dec for smaller code ? */
  626.                 o(0x83);
  627.                 o(0xc0 | (opc << 3) | r);
  628.                 g(c);
  629.             } else {
  630.                 o(0x81);
  631.                 oad(0xc0 | (opc << 3) | r, c);
  632.             }
  633.         } else {
  634.             gv2(RC_INT, RC_INT);
  635.             r = vtop[-1].r;
  636.             fr = vtop[0].r;
  637.             o((opc << 3) | 0x01);
  638.             o(0xc0 + r + fr * 8);
  639.         }
  640.         vtop--;
  641.         if (op >= TOK_ULT && op <= TOK_GT) {
  642.             vtop->r = VT_CMP;
  643.             vtop->c.i = op;
  644.         }
  645.         break;
  646.     case '-':
  647.     case TOK_SUBC1: /* sub with carry generation */
  648.         opc = 5;
  649.         goto gen_op8;
  650.     case TOK_ADDC2: /* add with carry use */
  651.         opc = 2;
  652.         goto gen_op8;
  653.     case TOK_SUBC2: /* sub with carry use */
  654.         opc = 3;
  655.         goto gen_op8;
  656.     case '&':
  657.         opc = 4;
  658.         goto gen_op8;
  659.     case '^':
  660.         opc = 6;
  661.         goto gen_op8;
  662.     case '|':
  663.         opc = 1;
  664.         goto gen_op8;
  665.     case '*':
  666.         gv2(RC_INT, RC_INT);
  667.         r = vtop[-1].r;
  668.         fr = vtop[0].r;
  669.         vtop--;
  670.         o(0xaf0f); /* imul fr, r */
  671.         o(0xc0 + fr + r * 8);
  672.         break;
  673.     case TOK_SHL:
  674.         opc = 4;
  675.         goto gen_shift;
  676.     case TOK_SHR:
  677.         opc = 5;
  678.         goto gen_shift;
  679.     case TOK_SAR:
  680.         opc = 7;
  681.     gen_shift:
  682.         opc = 0xc0 | (opc << 3);
  683.         if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  684.             /* constant case */
  685.             vswap();
  686.             r = gv(RC_INT);
  687.             vswap();
  688.             c = vtop->c.i & 0x1f;
  689.             o(0xc1); /* shl/shr/sar $xxx, r */
  690.             o(opc | r);
  691.             g(c);
  692.         } else {
  693.             /* we generate the shift in ecx */
  694.             gv2(RC_INT, RC_ECX);
  695.             r = vtop[-1].r;
  696.             o(0xd3); /* shl/shr/sar %cl, r */
  697.             o(opc | r);
  698.         }
  699.         vtop--;
  700.         break;
  701.     case '/':
  702.     case TOK_UDIV:
  703.     case TOK_PDIV:
  704.     case '%':
  705.     case TOK_UMOD:
  706.     case TOK_UMULL:
  707.         /* first operand must be in eax */
  708.         /* XXX: need better constraint for second operand */
  709.         gv2(RC_EAX, RC_ECX);
  710.         r = vtop[-1].r;
  711.         fr = vtop[0].r;
  712.         vtop--;
  713.         save_reg(TREG_EDX);
  714.         if (op == TOK_UMULL) {
  715.             o(0xf7); /* mul fr */
  716.             o(0xe0 + fr);
  717.             vtop->r2 = TREG_EDX;
  718.             r = TREG_EAX;
  719.         } else {
  720.             if (op == TOK_UDIV || op == TOK_UMOD) {
  721.                 o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
  722.                 o(0xf0 + fr);
  723.             } else {
  724.                 o(0xf799); /* cltd, idiv fr, %eax */
  725.                 o(0xf8 + fr);
  726.             }
  727.             if (op == '%' || op == TOK_UMOD)
  728.                 r = TREG_EDX;
  729.             else
  730.                 r = TREG_EAX;
  731.         }
  732.         vtop->r = r;
  733.         break;
  734.     default:
  735.         opc = 7;
  736.         goto gen_op8;
  737.     }
  738. }
  739.  
  740. /* generate a floating point operation 'v = t1 op t2' instruction. The
  741.    two operands are guaranted to have the same floating point type */
  742. /* XXX: need to use ST1 too */
  743. void gen_opf(int op)
  744. {
  745.     int a, ft, fc, swapped, r;
  746.  
  747.     /* convert constants to memory references */
  748.     if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
  749.         vswap();
  750.         gv(RC_FLOAT);
  751.         vswap();
  752.     }
  753.     if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
  754.         gv(RC_FLOAT);
  755.  
  756.     /* must put at least one value in the floating point register */
  757.     if ((vtop[-1].r & VT_LVAL) &&
  758.         (vtop[0].r & VT_LVAL)) {
  759.         vswap();
  760.         gv(RC_FLOAT);
  761.         vswap();
  762.     }
  763.     swapped = 0;
  764.     /* swap the stack if needed so that t1 is the register and t2 is
  765.        the memory reference */
  766.     if (vtop[-1].r & VT_LVAL) {
  767.         vswap();
  768.         swapped = 1;
  769.     }
  770.     if (op >= TOK_ULT && op <= TOK_GT) {
  771.         /* load on stack second operand */
  772.         load(TREG_ST0, vtop);
  773.         save_reg(TREG_EAX); /* eax is used by FP comparison code */
  774.         if (op == TOK_GE || op == TOK_GT)
  775.             swapped = !swapped;
  776.         else if (op == TOK_EQ || op == TOK_NE)
  777.             swapped = 0;
  778.         if (swapped)
  779.             o(0xc9d9); /* fxch %st(1) */
  780.         o(0xe9da); /* fucompp */
  781.         o(0xe0df); /* fnstsw %ax */
  782.         if (op == TOK_EQ) {
  783.             o(0x45e480); /* and $0x45, %ah */
  784.             o(0x40fC80); /* cmp $0x40, %ah */
  785.         } else if (op == TOK_NE) {
  786.             o(0x45e480); /* and $0x45, %ah */
  787.             o(0x40f480); /* xor $0x40, %ah */
  788.             op = TOK_NE;
  789.         } else if (op == TOK_GE || op == TOK_LE) {
  790.             o(0x05c4f6); /* test $0x05, %ah */
  791.             op = TOK_EQ;
  792.         } else {
  793.             o(0x45c4f6); /* test $0x45, %ah */
  794.             op = TOK_EQ;
  795.         }
  796.         vtop--;
  797.         vtop->r = VT_CMP;
  798.         vtop->c.i = op;
  799.     } else {
  800.         /* no memory reference possible for long double operations */
  801.         if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
  802.             load(TREG_ST0, vtop);
  803.             swapped = !swapped;
  804.         }
  805.        
  806.         switch(op) {
  807.         default:
  808.         case '+':
  809.             a = 0;
  810.             break;
  811.         case '-':
  812.             a = 4;
  813.             if (swapped)
  814.                 a++;
  815.             break;
  816.         case '*':
  817.             a = 1;
  818.             break;
  819.         case '/':
  820.             a = 6;
  821.             if (swapped)
  822.                 a++;
  823.             break;
  824.         }
  825.         ft = vtop->type.t;
  826.         fc = vtop->c.ul;
  827.         if ((ft & VT_BTYPE) == VT_LDOUBLE) {
  828.             o(0xde); /* fxxxp %st, %st(1) */
  829.             o(0xc1 + (a << 3));
  830.         } else {
  831.             /* if saved lvalue, then we must reload it */
  832.             r = vtop->r;
  833.             if ((r & VT_VALMASK) == VT_LLOCAL) {
  834.                 SValue v1;
  835.                 r = get_reg(RC_INT);
  836.                 v1.type.t = VT_INT;
  837.                 v1.r = VT_LOCAL | VT_LVAL;
  838.                 v1.c.ul = fc;
  839.                 load(r, &v1);
  840.                 fc = 0;
  841.             }
  842.  
  843.             if ((ft & VT_BTYPE) == VT_DOUBLE)
  844.                 o(0xdc);
  845.             else
  846.                 o(0xd8);
  847.             gen_modrm(a, r, vtop->sym, fc);
  848.         }
  849.         vtop--;
  850.     }
  851. }
  852.  
  853. /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
  854.    and 'long long' cases. */
  855. void gen_cvt_itof(int t)
  856. {
  857.     save_reg(TREG_ST0);
  858.     gv(RC_INT);
  859.     if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
  860.         /* signed long long to float/double/long double (unsigned case
  861.            is handled generically) */
  862.         o(0x50 + vtop->r2); /* push r2 */
  863.         o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  864.         o(0x242cdf); /* fildll (%esp) */
  865.         o(0x08c483); /* add $8, %esp */
  866.     } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
  867.                (VT_INT | VT_UNSIGNED)) {
  868.         /* unsigned int to float/double/long double */
  869.         o(0x6a); /* push $0 */
  870.         g(0x00);
  871.         o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  872.         o(0x242cdf); /* fildll (%esp) */
  873.         o(0x08c483); /* add $8, %esp */
  874.     } else {
  875.         /* int to float/double/long double */
  876.         o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  877.         o(0x2404db); /* fildl (%esp) */
  878.         o(0x04c483); /* add $4, %esp */
  879.     }
  880.     vtop->r = TREG_ST0;
  881. }
  882.  
  883. /* convert fp to int 't' type */
  884. /* XXX: handle long long case */
  885. void gen_cvt_ftoi(int t)
  886. {
  887.     int r, r2, size;
  888.     Sym *sym;
  889.     CType ushort_type;
  890.  
  891.     ushort_type.t = VT_SHORT | VT_UNSIGNED;
  892.  
  893.     gv(RC_FLOAT);
  894.     if (t != VT_INT)
  895.         size = 8;
  896.     else
  897.         size = 4;
  898.    
  899.     o(0x2dd9); /* ldcw xxx */
  900.     sym = external_global_sym(TOK___tcc_int_fpu_control,
  901.                               &ushort_type, VT_LVAL);
  902.     greloc(cur_text_section, sym,
  903.            ind, R_386_32);
  904.     gen_le32(0);
  905.    
  906.     oad(0xec81, size); /* sub $xxx, %esp */
  907.     if (size == 4)
  908.         o(0x1cdb); /* fistpl */
  909.     else
  910.         o(0x3cdf); /* fistpll */
  911.     o(0x24);
  912.     o(0x2dd9); /* ldcw xxx */
  913.     sym = external_global_sym(TOK___tcc_fpu_control,
  914.                               &ushort_type, VT_LVAL);
  915.     greloc(cur_text_section, sym,
  916.            ind, R_386_32);
  917.     gen_le32(0);
  918.  
  919.     r = get_reg(RC_INT);
  920.     o(0x58 + r); /* pop r */
  921.     if (size == 8) {
  922.         if (t == VT_LLONG) {
  923.             vtop->r = r; /* mark reg as used */
  924.             r2 = get_reg(RC_INT);
  925.             o(0x58 + r2); /* pop r2 */
  926.             vtop->r2 = r2;
  927.         } else {
  928.             o(0x04c483); /* add $4, %esp */
  929.         }
  930.     }
  931.     vtop->r = r;
  932. }
  933.  
  934. /* convert from one floating point type to another */
  935. void gen_cvt_ftof(int t)
  936. {
  937.     /* all we have to do on i386 is to put the float in a register */
  938.     gv(RC_FLOAT);
  939. }
  940.  
  941. /* computed goto support */
  942. void ggoto(void)
  943. {
  944.     gcall_or_jmp(1);
  945.     vtop--;
  946. }
  947.  
  948. /* bound check support functions */
  949. #ifdef CONFIG_TCC_BCHECK
  950.  
  951. /* generate a bounded pointer addition */
  952. void gen_bounded_ptr_add(void)
  953. {
  954.     Sym *sym;
  955.  
  956.     /* prepare fast i386 function call (args in eax and edx) */
  957.     gv2(RC_EAX, RC_EDX);
  958.     /* save all temporary registers */
  959.     vtop -= 2;
  960.     save_regs(0);
  961.     /* do a fast function call */
  962.     sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
  963.     greloc(cur_text_section, sym,
  964.            ind + 1, R_386_PC32);
  965.     oad(0xe8, -4);
  966.     /* returned pointer is in eax */
  967.     vtop++;
  968.     vtop->r = TREG_EAX | VT_BOUNDED;
  969.     /* address of bounding function call point */
  970.     vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
  971. }
  972.  
  973. /* patch pointer addition in vtop so that pointer dereferencing is
  974.    also tested */
  975. void gen_bounded_ptr_deref(void)
  976. {
  977.     int func;
  978.     int size, align;
  979.     Elf32_Rel *rel;
  980.     Sym *sym;
  981.  
  982.     size = 0;
  983.     /* XXX: put that code in generic part of tcc */
  984.     if (!is_float(vtop->type.t)) {
  985.         if (vtop->r & VT_LVAL_BYTE)
  986.             size = 1;
  987.         else if (vtop->r & VT_LVAL_SHORT)
  988.             size = 2;
  989.     }
  990.     if (!size)
  991.         size = type_size(&vtop->type, &align);
  992.     switch(size) {
  993.     case  1: func = TOK___bound_ptr_indir1; break;
  994.     case  2: func = TOK___bound_ptr_indir2; break;
  995.     case  4: func = TOK___bound_ptr_indir4; break;
  996.     case  8: func = TOK___bound_ptr_indir8; break;
  997.     case 12: func = TOK___bound_ptr_indir12; break;
  998.     case 16: func = TOK___bound_ptr_indir16; break;
  999.     default:
  1000.         error("unhandled size when derefencing bounded pointer");
  1001.         func = 0;
  1002.         break;
  1003.     }
  1004.  
  1005.     /* patch relocation */
  1006.     /* XXX: find a better solution ? */
  1007.     rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
  1008.     sym = external_global_sym(func, &func_old_type, 0);
  1009.     if (!sym->c)
  1010.         put_extern_sym(sym, NULL, 0, 0);
  1011.     rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
  1012. }
  1013. #endif
  1014.  
  1015. /* end of X86 code generator */
  1016. /*************************************************************/
  1017.  
  1018.