Subversion Repositories Kolibri OS

Rev

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