Subversion Repositories Kolibri OS

Rev

Rev 647 | Go to most recent revision | 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.     if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
  357.         /* constant case */
  358.         if (vtop->r & VT_SYM) {
  359.             /* relocation case */
  360.             greloc(cur_text_section, vtop->sym,
  361.                    ind + 1, R_386_PC32);
  362.         } else {
  363.             /* put an empty PC32 relocation */
  364.             put_elf_reloc(symtab_section, cur_text_section,
  365.                           ind + 1, R_386_PC32, 0);
  366.         }
  367.         oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
  368.     } else {
  369.         /* otherwise, indirect call */
  370.         r = gv(RC_INT);
  371.         o(0xff); /* call/jmp *r */
  372.         o(0xd0 + r + (is_jmp << 4));
  373.     }
  374. }
  375.  
  376. static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
  377. static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
  378.  
  379. /* Return the number of registers needed to return the struct, or 0 if
  380.    returning via struct pointer. */
  381. ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
  382. {
  383. #ifdef TCC_TARGET_PE
  384.     int size, align;
  385.  
  386.     *ret_align = 1; // Never have to re-align return values for x86
  387.     *regsize = 4;
  388.     size = type_size(vt, &align);
  389.     if (size > 8) {
  390.         return 0;
  391.     } else if (size > 4) {
  392.         ret->ref = NULL;
  393.         ret->t = VT_LLONG;
  394.         return 1;
  395.     } else {
  396.         ret->ref = NULL;
  397.         ret->t = VT_INT;
  398.         return 1;
  399.     }
  400. #else
  401.     *ret_align = 1; // Never have to re-align return values for x86
  402.     return 0;
  403. #endif
  404. }
  405.  
  406. /* Generate function call. The function address is pushed first, then
  407.    all the parameters in call order. This functions pops all the
  408.    parameters and the function address. */
  409. ST_FUNC void gfunc_call(int nb_args)
  410. {
  411.     int size, align, r, args_size, i, func_call;
  412.     Sym *func_sym;
  413.    
  414.     args_size = 0;
  415.     for(i = 0;i < nb_args; i++) {
  416.         if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
  417.             size = type_size(&vtop->type, &align);
  418.             /* align to stack align size */
  419.             size = (size + 3) & ~3;
  420.             /* allocate the necessary size on stack */
  421.             oad(0xec81, size); /* sub $xxx, %esp */
  422.             /* generate structure store */
  423.             r = get_reg(RC_INT);
  424.             o(0x89); /* mov %esp, r */
  425.             o(0xe0 + r);
  426.             vset(&vtop->type, r | VT_LVAL, 0);
  427.             vswap();
  428.             vstore();
  429.             args_size += size;
  430.         } else if (is_float(vtop->type.t)) {
  431.             gv(RC_FLOAT); /* only one float register */
  432.             if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
  433.                 size = 4;
  434.             else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
  435.                 size = 8;
  436.             else
  437.                 size = 12;
  438.             oad(0xec81, size); /* sub $xxx, %esp */
  439.             if (size == 12)
  440.                 o(0x7cdb);
  441.             else
  442.                 o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
  443.             g(0x24);
  444.             g(0x00);
  445.             args_size += size;
  446.         } else {
  447.             /* simple type (currently always same size) */
  448.             /* XXX: implicit cast ? */
  449.             r = gv(RC_INT);
  450.             if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
  451.                 size = 8;
  452.                 o(0x50 + vtop->r2); /* push r */
  453.             } else {
  454.                 size = 4;
  455.             }
  456.             o(0x50 + r); /* push r */
  457.             args_size += size;
  458.         }
  459.         vtop--;
  460.     }
  461.     save_regs(0); /* save used temporary registers */
  462.     func_sym = vtop->type.ref;
  463.     func_call = func_sym->a.func_call;
  464.     /* fast call case */
  465.     if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
  466.         func_call == FUNC_FASTCALLW) {
  467.         int fastcall_nb_regs;
  468.         uint8_t *fastcall_regs_ptr;
  469.         if (func_call == FUNC_FASTCALLW) {
  470.             fastcall_regs_ptr = fastcallw_regs;
  471.             fastcall_nb_regs = 2;
  472.         } else {
  473.             fastcall_regs_ptr = fastcall_regs;
  474.             fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
  475.         }
  476.         for(i = 0;i < fastcall_nb_regs; i++) {
  477.             if (args_size <= 0)
  478.                 break;
  479.             o(0x58 + fastcall_regs_ptr[i]); /* pop r */
  480.             /* XXX: incorrect for struct/floats */
  481.             args_size -= 4;
  482.         }
  483.     }
  484. #ifndef TCC_TARGET_PE
  485.     else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
  486.         args_size -= 4;
  487. #endif
  488.     gcall_or_jmp(0);
  489.  
  490.     if (args_size && func_call != FUNC_STDCALL)
  491.         gadd_sp(args_size);
  492.     vtop--;
  493. }
  494.  
  495. #ifdef TCC_TARGET_PE
  496. #define FUNC_PROLOG_SIZE 10
  497. #else
  498. #define FUNC_PROLOG_SIZE 9
  499. #endif
  500.  
  501. /* generate function prolog of type 't' */
  502. ST_FUNC void gfunc_prolog(CType *func_type)
  503. {
  504.     int addr, align, size, func_call, fastcall_nb_regs;
  505.     int param_index, param_addr;
  506.     uint8_t *fastcall_regs_ptr;
  507.     Sym *sym;
  508.     CType *type;
  509.  
  510.     sym = func_type->ref;
  511.     func_call = sym->a.func_call;
  512.     addr = 8;
  513.     loc = 0;
  514.     func_vc = 0;
  515.  
  516.     if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
  517.         fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
  518.         fastcall_regs_ptr = fastcall_regs;
  519.     } else if (func_call == FUNC_FASTCALLW) {
  520.         fastcall_nb_regs = 2;
  521.         fastcall_regs_ptr = fastcallw_regs;
  522.     } else {
  523.         fastcall_nb_regs = 0;
  524.         fastcall_regs_ptr = NULL;
  525.     }
  526.     param_index = 0;
  527.  
  528.     ind += FUNC_PROLOG_SIZE;
  529.     func_sub_sp_offset = ind;
  530.     /* if the function returns a structure, then add an
  531.        implicit pointer parameter */
  532.     func_vt = sym->type;
  533.     func_var = (sym->c == FUNC_ELLIPSIS);
  534. #ifdef TCC_TARGET_PE
  535.     size = type_size(&func_vt,&align);
  536.     if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
  537. #else
  538.     if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
  539. #endif
  540.         /* XXX: fastcall case ? */
  541.         func_vc = addr;
  542.         addr += 4;
  543.         param_index++;
  544.     }
  545.     /* define parameters */
  546.     while ((sym = sym->next) != NULL) {
  547.         type = &sym->type;
  548.         size = type_size(type, &align);
  549.         size = (size + 3) & ~3;
  550. #ifdef FUNC_STRUCT_PARAM_AS_PTR
  551.         /* structs are passed as pointer */
  552.         if ((type->t & VT_BTYPE) == VT_STRUCT) {
  553.             size = 4;
  554.         }
  555. #endif
  556.         if (param_index < fastcall_nb_regs) {
  557.             /* save FASTCALL register */
  558.             loc -= 4;
  559.             o(0x89);     /* movl */
  560.             gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
  561.             param_addr = loc;
  562.         } else {
  563.             param_addr = addr;
  564.             addr += size;
  565.         }
  566.         sym_push(sym->v & ~SYM_FIELD, type,
  567.                  VT_LOCAL | lvalue_type(type->t), param_addr);
  568.         param_index++;
  569.     }
  570.     func_ret_sub = 0;
  571.     /* pascal type call ? */
  572.     if (func_call == FUNC_STDCALL)
  573.         func_ret_sub = addr - 8;
  574. #ifndef TCC_TARGET_PE
  575.     else if (func_vc)
  576.         func_ret_sub = 4;
  577. #endif
  578.  
  579. #ifdef CONFIG_TCC_BCHECK
  580.     /* leave some room for bound checking code */
  581.     if (tcc_state->do_bounds_check) {
  582.         oad(0xb8, 0); /* lbound section pointer */
  583.         oad(0xb8, 0); /* call to function */
  584.         func_bound_offset = lbounds_section->data_offset;
  585.     }
  586. #endif
  587. }
  588.  
  589. /* generate function epilog */
  590. ST_FUNC void gfunc_epilog(void)
  591. {
  592.     addr_t v, saved_ind;
  593.  
  594. #ifdef CONFIG_TCC_BCHECK
  595.     if (tcc_state->do_bounds_check
  596.      && func_bound_offset != lbounds_section->data_offset) {
  597.         addr_t saved_ind;
  598.         addr_t *bounds_ptr;
  599.         Sym *sym_data;
  600.         /* add end of table info */
  601.         bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
  602.         *bounds_ptr = 0;
  603.         /* generate bound local allocation */
  604.         saved_ind = ind;
  605.         ind = func_sub_sp_offset;
  606.         sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
  607.                                func_bound_offset, lbounds_section->data_offset);
  608.         greloc(cur_text_section, sym_data,
  609.                ind + 1, R_386_32);
  610.         oad(0xb8, 0); /* mov %eax, xxx */
  611.         gen_static_call(TOK___bound_local_new);
  612.  
  613.         ind = saved_ind;
  614.         /* generate bound check local freeing */
  615.         o(0x5250); /* save returned value, if any */
  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_delete);
  620.  
  621.         o(0x585a); /* restore returned value, if any */
  622.     }
  623. #endif
  624.     o(0xc9); /* leave */
  625.     if (func_ret_sub == 0) {
  626.         o(0xc3); /* ret */
  627.     } else {
  628.         o(0xc2); /* ret n */
  629.         g(func_ret_sub);
  630.         g(func_ret_sub >> 8);
  631.     }
  632.     /* align local size to word & save local variables */
  633.    
  634.     v = (-loc + 3) & -4;
  635.     saved_ind = ind;
  636.     ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
  637. #ifdef TCC_TARGET_PE
  638.     if (v >= 4096) {
  639.         oad(0xb8, v); /* mov stacksize, %eax */
  640.         gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
  641.     } else
  642. #endif
  643.     {
  644.         o(0xe58955);  /* push %ebp, mov %esp, %ebp */
  645.         o(0xec81);  /* sub esp, stacksize */
  646.         gen_le32(v);
  647. #if FUNC_PROLOG_SIZE == 10
  648.         o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
  649. #endif
  650.     }
  651.     ind = saved_ind;
  652. }
  653.  
  654. /* generate a jump to a label */
  655. ST_FUNC int gjmp(int t)
  656. {
  657.     return psym(0xe9, t);
  658. }
  659.  
  660. /* generate a jump to a fixed address */
  661. ST_FUNC void gjmp_addr(int a)
  662. {
  663.     int r;
  664.     r = a - ind - 2;
  665.     if (r == (char)r) {
  666.         g(0xeb);
  667.         g(r);
  668.     } else {
  669.         oad(0xe9, a - ind - 5);
  670.     }
  671. }
  672.  
  673. /* generate a test. set 'inv' to invert test. Stack entry is popped */
  674. ST_FUNC int gtst(int inv, int t)
  675. {
  676.     int v = vtop->r & VT_VALMASK;
  677.     if (v == VT_CMP) {
  678.         /* fast case : can jump directly since flags are set */
  679.         g(0x0f);
  680.         t = psym((vtop->c.i - 16) ^ inv, t);
  681.     } else if (v == VT_JMP || v == VT_JMPI) {
  682.         /* && or || optimization */
  683.         if ((v & 1) == inv) {
  684.             /* insert vtop->c jump list in t */
  685.             uint32_t n1, n = vtop->c.i;
  686.             if (n) {
  687.                 while ((n1 = read32le(cur_text_section->data + n)))
  688.                     n = n1;
  689.                 write32le(cur_text_section->data + n, t);
  690.                 t = vtop->c.i;
  691.             }
  692.         } else {
  693.             t = gjmp(t);
  694.             gsym(vtop->c.i);
  695.         }
  696.     }
  697.     vtop--;
  698.     return t;
  699. }
  700.  
  701. /* generate an integer binary operation */
  702. ST_FUNC void gen_opi(int op)
  703. {
  704.     int r, fr, opc, c;
  705.  
  706.     switch(op) {
  707.     case '+':
  708.     case TOK_ADDC1: /* add with carry generation */
  709.         opc = 0;
  710.     gen_op8:
  711.         if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  712.             /* constant case */
  713.             vswap();
  714.             r = gv(RC_INT);
  715.             vswap();
  716.             c = vtop->c.i;
  717.             if (c == (char)c) {
  718.                 /* generate inc and dec for smaller code */
  719.                 if (c==1 && opc==0) {
  720.                     o (0x40 | r); // inc
  721.                 } else if (c==1 && opc==5) {
  722.                     o (0x48 | r); // dec
  723.                 } else {
  724.                     o(0x83);
  725.                     o(0xc0 | (opc << 3) | r);
  726.                     g(c);
  727.                 }
  728.             } else {
  729.                 o(0x81);
  730.                 oad(0xc0 | (opc << 3) | r, c);
  731.             }
  732.         } else {
  733.             gv2(RC_INT, RC_INT);
  734.             r = vtop[-1].r;
  735.             fr = vtop[0].r;
  736.             o((opc << 3) | 0x01);
  737.             o(0xc0 + r + fr * 8);
  738.         }
  739.         vtop--;
  740.         if (op >= TOK_ULT && op <= TOK_GT) {
  741.             vtop->r = VT_CMP;
  742.             vtop->c.i = op;
  743.         }
  744.         break;
  745.     case '-':
  746.     case TOK_SUBC1: /* sub with carry generation */
  747.         opc = 5;
  748.         goto gen_op8;
  749.     case TOK_ADDC2: /* add with carry use */
  750.         opc = 2;
  751.         goto gen_op8;
  752.     case TOK_SUBC2: /* sub with carry use */
  753.         opc = 3;
  754.         goto gen_op8;
  755.     case '&':
  756.         opc = 4;
  757.         goto gen_op8;
  758.     case '^':
  759.         opc = 6;
  760.         goto gen_op8;
  761.     case '|':
  762.         opc = 1;
  763.         goto gen_op8;
  764.     case '*':
  765.         gv2(RC_INT, RC_INT);
  766.         r = vtop[-1].r;
  767.         fr = vtop[0].r;
  768.         vtop--;
  769.         o(0xaf0f); /* imul fr, r */
  770.         o(0xc0 + fr + r * 8);
  771.         break;
  772.     case TOK_SHL:
  773.         opc = 4;
  774.         goto gen_shift;
  775.     case TOK_SHR:
  776.         opc = 5;
  777.         goto gen_shift;
  778.     case TOK_SAR:
  779.         opc = 7;
  780.     gen_shift:
  781.         opc = 0xc0 | (opc << 3);
  782.         if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  783.             /* constant case */
  784.             vswap();
  785.             r = gv(RC_INT);
  786.             vswap();
  787.             c = vtop->c.i & 0x1f;
  788.             o(0xc1); /* shl/shr/sar $xxx, r */
  789.             o(opc | r);
  790.             g(c);
  791.         } else {
  792.             /* we generate the shift in ecx */
  793.             gv2(RC_INT, RC_ECX);
  794.             r = vtop[-1].r;
  795.             o(0xd3); /* shl/shr/sar %cl, r */
  796.             o(opc | r);
  797.         }
  798.         vtop--;
  799.         break;
  800.     case '/':
  801.     case TOK_UDIV:
  802.     case TOK_PDIV:
  803.     case '%':
  804.     case TOK_UMOD:
  805.     case TOK_UMULL:
  806.         /* first operand must be in eax */
  807.         /* XXX: need better constraint for second operand */
  808.         gv2(RC_EAX, RC_ECX);
  809.         r = vtop[-1].r;
  810.         fr = vtop[0].r;
  811.         vtop--;
  812.         save_reg(TREG_EDX);
  813.         if (op == TOK_UMULL) {
  814.             o(0xf7); /* mul fr */
  815.             o(0xe0 + fr);
  816.             vtop->r2 = TREG_EDX;
  817.             r = TREG_EAX;
  818.         } else {
  819.             if (op == TOK_UDIV || op == TOK_UMOD) {
  820.                 o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
  821.                 o(0xf0 + fr);
  822.             } else {
  823.                 o(0xf799); /* cltd, idiv fr, %eax */
  824.                 o(0xf8 + fr);
  825.             }
  826.             if (op == '%' || op == TOK_UMOD)
  827.                 r = TREG_EDX;
  828.             else
  829.                 r = TREG_EAX;
  830.         }
  831.         vtop->r = r;
  832.         break;
  833.     default:
  834.         opc = 7;
  835.         goto gen_op8;
  836.     }
  837. }
  838.  
  839. /* generate a floating point operation 'v = t1 op t2' instruction. The
  840.    two operands are guaranted to have the same floating point type */
  841. /* XXX: need to use ST1 too */
  842. ST_FUNC void gen_opf(int op)
  843. {
  844.     int a, ft, fc, swapped, r;
  845.  
  846.     /* convert constants to memory references */
  847.     if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
  848.         vswap();
  849.         gv(RC_FLOAT);
  850.         vswap();
  851.     }
  852.     if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
  853.         gv(RC_FLOAT);
  854.  
  855.     /* must put at least one value in the floating point register */
  856.     if ((vtop[-1].r & VT_LVAL) &&
  857.         (vtop[0].r & VT_LVAL)) {
  858.         vswap();
  859.         gv(RC_FLOAT);
  860.         vswap();
  861.     }
  862.     swapped = 0;
  863.     /* swap the stack if needed so that t1 is the register and t2 is
  864.        the memory reference */
  865.     if (vtop[-1].r & VT_LVAL) {
  866.         vswap();
  867.         swapped = 1;
  868.     }
  869.     if (op >= TOK_ULT && op <= TOK_GT) {
  870.         /* load on stack second operand */
  871.         load(TREG_ST0, vtop);
  872.         save_reg(TREG_EAX); /* eax is used by FP comparison code */
  873.         if (op == TOK_GE || op == TOK_GT)
  874.             swapped = !swapped;
  875.         else if (op == TOK_EQ || op == TOK_NE)
  876.             swapped = 0;
  877.         if (swapped)
  878.             o(0xc9d9); /* fxch %st(1) */
  879.         if (op == TOK_EQ || op == TOK_NE)
  880.             o(0xe9da); /* fucompp */
  881.         else
  882.             o(0xd9de); /* fcompp */
  883.         o(0xe0df); /* fnstsw %ax */
  884.         if (op == TOK_EQ) {
  885.             o(0x45e480); /* and $0x45, %ah */
  886.             o(0x40fC80); /* cmp $0x40, %ah */
  887.         } else if (op == TOK_NE) {
  888.             o(0x45e480); /* and $0x45, %ah */
  889.             o(0x40f480); /* xor $0x40, %ah */
  890.             op = TOK_NE;
  891.         } else if (op == TOK_GE || op == TOK_LE) {
  892.             o(0x05c4f6); /* test $0x05, %ah */
  893.             op = TOK_EQ;
  894.         } else {
  895.             o(0x45c4f6); /* test $0x45, %ah */
  896.             op = TOK_EQ;
  897.         }
  898.         vtop--;
  899.         vtop->r = VT_CMP;
  900.         vtop->c.i = op;
  901.     } else {
  902.         /* no memory reference possible for long double operations */
  903.         if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
  904.             load(TREG_ST0, vtop);
  905.             swapped = !swapped;
  906.         }
  907.        
  908.         switch(op) {
  909.         default:
  910.         case '+':
  911.             a = 0;
  912.             break;
  913.         case '-':
  914.             a = 4;
  915.             if (swapped)
  916.                 a++;
  917.             break;
  918.         case '*':
  919.             a = 1;
  920.             break;
  921.         case '/':
  922.             a = 6;
  923.             if (swapped)
  924.                 a++;
  925.             break;
  926.         }
  927.         ft = vtop->type.t;
  928.         fc = vtop->c.i;
  929.         if ((ft & VT_BTYPE) == VT_LDOUBLE) {
  930.             o(0xde); /* fxxxp %st, %st(1) */
  931.             o(0xc1 + (a << 3));
  932.         } else {
  933.             /* if saved lvalue, then we must reload it */
  934.             r = vtop->r;
  935.             if ((r & VT_VALMASK) == VT_LLOCAL) {
  936.                 SValue v1;
  937.                 r = get_reg(RC_INT);
  938.                 v1.type.t = VT_INT;
  939.                 v1.r = VT_LOCAL | VT_LVAL;
  940.                 v1.c.i = fc;
  941.                 load(r, &v1);
  942.                 fc = 0;
  943.             }
  944.  
  945.             if ((ft & VT_BTYPE) == VT_DOUBLE)
  946.                 o(0xdc);
  947.             else
  948.                 o(0xd8);
  949.             gen_modrm(a, r, vtop->sym, fc);
  950.         }
  951.         vtop--;
  952.     }
  953. }
  954.  
  955. /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
  956.    and 'long long' cases. */
  957. ST_FUNC void gen_cvt_itof(int t)
  958. {
  959.     save_reg(TREG_ST0);
  960.     gv(RC_INT);
  961.     if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
  962.         /* signed long long to float/double/long double (unsigned case
  963.            is handled generically) */
  964.         o(0x50 + vtop->r2); /* push r2 */
  965.         o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  966.         o(0x242cdf); /* fildll (%esp) */
  967.         o(0x08c483); /* add $8, %esp */
  968.     } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
  969.                (VT_INT | VT_UNSIGNED)) {
  970.         /* unsigned int to float/double/long double */
  971.         o(0x6a); /* push $0 */
  972.         g(0x00);
  973.         o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  974.         o(0x242cdf); /* fildll (%esp) */
  975.         o(0x08c483); /* add $8, %esp */
  976.     } else {
  977.         /* int to float/double/long double */
  978.         o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  979.         o(0x2404db); /* fildl (%esp) */
  980.         o(0x04c483); /* add $4, %esp */
  981.     }
  982.     vtop->r = TREG_ST0;
  983. }
  984.  
  985. /* convert fp to int 't' type */
  986. ST_FUNC void gen_cvt_ftoi(int t)
  987. {
  988.  #ifndef COMMIT_4ad186c5ef61_IS_FIXED
  989.     /* a good version but it takes a more time to execute */
  990.     gv(RC_FLOAT);
  991.     save_reg(TREG_EAX);
  992.     save_reg(TREG_EDX);
  993.     gen_static_call(TOK___tcc_cvt_ftol);
  994.     vtop->r = TREG_EAX; /* mark reg as used */
  995.     if (t == VT_LLONG)
  996.         vtop->r2 = TREG_EDX;
  997.  #else
  998.     /* a new version with a bug: t2a = 44100312 */
  999.     /*
  1000.     #include<stdio.h>
  1001.     int main() {
  1002.         int t1 = 176401255;
  1003.         float f = 0.25f;
  1004.         int t2a = (int)(t1 * f); // must be 44100313
  1005.         int t2b = (int)(t1 * (float)0.25f);
  1006.         printf("t2a=%d t2b=%d \n",t2a,t2b);
  1007.         return 0;
  1008.     }
  1009.     */
  1010.     int bt = vtop->type.t & VT_BTYPE;
  1011.     if (bt == VT_FLOAT)
  1012.         vpush_global_sym(&func_old_type, TOK___fixsfdi);
  1013.     else if (bt == VT_LDOUBLE)
  1014.         vpush_global_sym(&func_old_type, TOK___fixxfdi);
  1015.     else
  1016.         vpush_global_sym(&func_old_type, TOK___fixdfdi);
  1017.     vswap();
  1018.     gfunc_call(1);
  1019.     vpushi(0);
  1020.     vtop->r = REG_IRET;
  1021.     vtop->r2 = REG_LRET;
  1022.  #endif
  1023. }
  1024.  
  1025. /* convert from one floating point type to another */
  1026. ST_FUNC void gen_cvt_ftof(int t)
  1027. {
  1028.     /* all we have to do on i386 is to put the float in a register */
  1029.     gv(RC_FLOAT);
  1030. }
  1031.  
  1032. /* computed goto support */
  1033. ST_FUNC void ggoto(void)
  1034. {
  1035.     gcall_or_jmp(1);
  1036.     vtop--;
  1037. }
  1038.  
  1039. /* bound check support functions */
  1040. #ifdef CONFIG_TCC_BCHECK
  1041.  
  1042. /* generate a bounded pointer addition */
  1043. ST_FUNC void gen_bounded_ptr_add(void)
  1044. {
  1045.     /* prepare fast i386 function call (args in eax and edx) */
  1046.     gv2(RC_EAX, RC_EDX);
  1047.     /* save all temporary registers */
  1048.     vtop -= 2;
  1049.     save_regs(0);
  1050.     /* do a fast function call */
  1051.     gen_static_call(TOK___bound_ptr_add);
  1052.     /* returned pointer is in eax */
  1053.     vtop++;
  1054.     vtop->r = TREG_EAX | VT_BOUNDED;
  1055.     /* address of bounding function call point */
  1056.     vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
  1057. }
  1058.  
  1059. /* patch pointer addition in vtop so that pointer dereferencing is
  1060.    also tested */
  1061. ST_FUNC void gen_bounded_ptr_deref(void)
  1062. {
  1063.     addr_t func;
  1064.     int  size, align;
  1065.     Elf32_Rel *rel;
  1066.     Sym *sym;
  1067.  
  1068.     size = 0;
  1069.     /* XXX: put that code in generic part of tcc */
  1070.     if (!is_float(vtop->type.t)) {
  1071.         if (vtop->r & VT_LVAL_BYTE)
  1072.             size = 1;
  1073.         else if (vtop->r & VT_LVAL_SHORT)
  1074.             size = 2;
  1075.     }
  1076.     if (!size)
  1077.         size = type_size(&vtop->type, &align);
  1078.     switch(size) {
  1079.     case  1: func = TOK___bound_ptr_indir1; break;
  1080.     case  2: func = TOK___bound_ptr_indir2; break;
  1081.     case  4: func = TOK___bound_ptr_indir4; break;
  1082.     case  8: func = TOK___bound_ptr_indir8; break;
  1083.     case 12: func = TOK___bound_ptr_indir12; break;
  1084.     case 16: func = TOK___bound_ptr_indir16; break;
  1085.     default:
  1086.         tcc_error("unhandled size when dereferencing bounded pointer");
  1087.         func = 0;
  1088.         break;
  1089.     }
  1090.  
  1091.     /* patch relocation */
  1092.     /* XXX: find a better solution ? */
  1093.     rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
  1094.     sym = external_global_sym(func, &func_old_type, 0);
  1095.     if (!sym->c)
  1096.         put_extern_sym(sym, NULL, 0, 0);
  1097.     rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
  1098. }
  1099. #endif
  1100.  
  1101. /* Save the stack pointer onto the stack */
  1102. ST_FUNC void gen_vla_sp_save(int addr) {
  1103.     /* mov %esp,addr(%ebp)*/
  1104.     o(0x89);
  1105.     gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
  1106. }
  1107.  
  1108. /* Restore the SP from a location on the stack */
  1109. ST_FUNC void gen_vla_sp_restore(int addr) {
  1110.     o(0x8b);
  1111.     gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
  1112. }
  1113.  
  1114. /* Subtract from the stack pointer, and push the resulting value onto the stack */
  1115. ST_FUNC void gen_vla_alloc(CType *type, int align) {
  1116. #ifdef TCC_TARGET_PE
  1117.     /* alloca does more than just adjust %rsp on Windows */
  1118.     vpush_global_sym(&func_old_type, TOK_alloca);
  1119.     vswap(); /* Move alloca ref past allocation size */
  1120.     gfunc_call(1);
  1121. #else
  1122.     int r;
  1123.     r = gv(RC_INT); /* allocation size */
  1124.     /* sub r,%rsp */
  1125.     o(0x2b);
  1126.     o(0xe0 | r);
  1127.     /* We align to 16 bytes rather than align */
  1128.     /* and ~15, %esp */
  1129.     o(0xf0e483);
  1130.     vpop();
  1131. #endif
  1132. }
  1133.  
  1134. /* end of X86 code generator */
  1135. /*************************************************************/
  1136. #endif
  1137. /*************************************************************/
  1138.