Advertisement
Guest User

TinyC 386 optimizer patch

a guest
Sep 26th, 2013
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 93.50 KB | None | 0 0
  1. diff -pruN tcc-0.9.26/i386-asm.h tcc-0.9.26o/i386-asm.h
  2. --- tcc-0.9.26/i386-asm.h   2013-02-16 00:24:00 +1000
  3. +++ tcc-0.9.26o/i386-asm.h  2013-09-05 23:14:30 +1000
  4. @@ -162,8 +162,8 @@ ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODR
  5.  ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
  6.  ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
  7.  ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWL, OPT_IM, OPT_EAX))
  8. -ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
  9.  ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WL, OPT_IM8S, OPT_EA | OPT_REG))
  10. +ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
  11.  
  12.  ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
  13.  ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
  14. diff -pruN tcc-0.9.26/i386-gen.c tcc-0.9.26o/i386-gen.c
  15. --- tcc-0.9.26/i386-gen.c   2013-02-16 00:24:00 +1000
  16. +++ tcc-0.9.26o/i386-gen.c  2013-09-25 23:47:38 +1000
  17. @@ -21,7 +21,7 @@
  18.  #ifdef TARGET_DEFS_ONLY
  19.  
  20.  /* number of available registers */
  21. -#define NB_REGS         4
  22. +#define NB_REGS         5
  23.  #define NB_ASM_REGS     8
  24.  
  25.  /* a register can belong to several classes. The classes must be
  26. @@ -33,6 +33,7 @@
  27.  #define RC_ST0     0x0008
  28.  #define RC_ECX     0x0010
  29.  #define RC_EDX     0x0020
  30. +#define RC_EBX     0x0040
  31.  #define RC_IRET    RC_EAX /* function return: integer register */
  32.  #define RC_LRET    RC_EDX /* function return: second integer register */
  33.  #define RC_FRET    RC_ST0 /* function return: float register */
  34. @@ -42,6 +43,7 @@ enum {
  35.      TREG_EAX = 0,
  36.      TREG_ECX,
  37.      TREG_EDX,
  38. +    TREG_EBX,
  39.      TREG_ST0,
  40.  };
  41.  
  42. @@ -84,6 +86,17 @@ enum {
  43.  #define ELF_PAGE_SIZE  0x1000
  44.  
  45.  /******************************************************/
  46. +/* Optimizations */
  47. +
  48. +#define OPT_PROLOG  1 /* reduce the size of the prolog and epilog */
  49. +#define OPT_JUMPS   2 /* remove redundant jumps, change near to short */
  50. +#define OPT_REGS    4 /* occasionally re-use existing values */
  51. +#define OPT_MULTS   8 /* use LEA for multiplication, reciprocal for ptr */
  52. +#define OPT_SIZE   16 /* remove function padding, only inline small epilog */
  53. +
  54. +#define NB_INT_REGS 4 /* don't work with float registers */
  55. +
  56. +/******************************************************/
  57.  #else /* ! TARGET_DEFS_ONLY */
  58.  /******************************************************/
  59.  #include "tcc.h"
  60. @@ -92,14 +105,59 @@ ST_DATA const int reg_classes[NB_REGS] =
  61.      /* eax */ RC_INT | RC_EAX,
  62.      /* ecx */ RC_INT | RC_ECX,
  63.      /* edx */ RC_INT | RC_EDX,
  64. +    /* ebx */ RC_INT | RC_EBX,
  65.      /* st0 */ RC_FLOAT | RC_ST0,
  66.  };
  67.  
  68. -static unsigned long func_sub_sp_offset;
  69. -static int func_ret_sub;
  70. +static unsigned long func_sub_sp_offset, prolog_reloc_offset;
  71. +static int func_ret_sub, func_uses_args, func_uses_ebx;
  72. +static int push_load;
  73. +static int **jmplst, nb_jmplst;
  74. +static int ins_ind, ins_len;
  75. +static int epilog_ind;
  76. +
  77. +typedef struct CacheValue {
  78. +    SValue ld; /* loaded register from this value */
  79. +    SValue st; /* stored register to this value */
  80. +} CacheValue;
  81. +static CacheValue rv_cache[NB_INT_REGS];
  82. +static int cache_used;
  83. +
  84. +static int q_r[2], q_state;
  85. +static SValue q_lv[2], q_sv[2];
  86. +static CacheValue q_c[NB_INT_REGS];
  87. +enum { Q_IGNORE = -1,
  88. +       Q_READY  = 0,
  89. +       Q_L1     = 1,
  90. +       Q_S1     = 2,
  91. +       Q_L2     = 4,
  92. +       Q_S2     = 8,
  93. +       Q_L      = Q_L1,
  94. +       Q_LS     = Q_L1 | Q_S1,
  95. +       Q_LL     = Q_L1 | Q_L2,
  96. +       Q_LLS    = Q_LS | Q_L2,
  97. +       Q_LLSS   = Q_LLS | Q_S2
  98. +};
  99. +
  100. +typedef struct OfsValue {
  101. +    int indc; /* index of add constant */
  102. +    int lenc; /* its size */
  103. +    int indr; /* index of add register (size is always 2) */
  104. +    int r;    /* register (if indr != 0) */
  105. +    int c;    /* constant (if indc != 0) */
  106. +    CacheValue v; /* previous value of register */
  107. +} OfsValue;
  108. +OfsValue o_v[NB_INT_REGS];
  109. +
  110.  #ifdef CONFIG_TCC_BCHECK
  111.  static unsigned long func_bound_offset;
  112.  #endif
  113. +static void loadc(int);
  114. +static void storec(int);
  115. +static void store_const(int);
  116. +static void jmpopt(void);
  117. +static void adjust_reloc(int t, int s);
  118. +static void adjust_oind(int t, int s);
  119.  
  120.  /* XXX: make it faster ? */
  121.  ST_FUNC void g(int c)
  122. @@ -114,12 +172,45 @@ ST_FUNC void g(int c)
  123.  
  124.  ST_FUNC void o(unsigned int c)
  125.  {
  126. +    if (q_state > Q_READY)
  127. +        flushq();
  128. +    if (tcc_state->optimize & OPT_JUMPS) {
  129. +        if (ind > ins_ind) { /* ignore backtracking */
  130. +            if (ind - ins_ind <= 15) /* ignore padding & prolog */
  131. +                ins_len = (ins_len << 4) | (ind - ins_ind);
  132. +            ins_ind = ind;
  133. +        }
  134. +    }
  135. +    if (tcc_state->optimize & OPT_REGS) {
  136. +        if (cache_ind != ind && cache_used) {
  137. +            if (cache_used == 2) {
  138. +                /* ebx is preserved across a call */
  139. +                SValue ebx = rv_cache[TREG_EBX].ld;
  140. +                CacheValue qebx = q_c[TREG_EBX];
  141. +                memset(rv_cache, -1, sizeof(rv_cache));
  142. +                memset(q_c, -1, sizeof(q_c));
  143. +                rv_cache[TREG_EBX].ld = ebx;
  144. +                q_c[TREG_EBX] = qebx;
  145. +            } else {
  146. +                memset(rv_cache, -1, sizeof(rv_cache));
  147. +                memset(q_c, -1, sizeof(q_c));
  148. +            }
  149. +            memset(o_v, 0, sizeof(o_v));
  150. +            cache_used = 0;
  151. +        }
  152. +    }
  153.      while (c) {
  154.          g(c);
  155.          c = c >> 8;
  156.      }
  157.  }
  158.  
  159. +ST_FUNC void og(int c, int v)
  160. +{
  161. +    o(c);
  162. +    g(v);
  163. +}
  164. +
  165.  ST_FUNC void gen_le16(int v)
  166.  {
  167.      g(v);
  168. @@ -148,9 +239,19 @@ ST_FUNC void gsym_addr(int t, int a)
  169.  
  170.  ST_FUNC void gsym(int t)
  171.  {
  172. +    if (q_state > Q_READY)
  173. +        flushq();
  174.      gsym_addr(t, ind);
  175.  }
  176.  
  177. +static void add_jump(int t, int s)
  178. +{
  179. +    int *j = tcc_malloc(2 * sizeof(int));
  180. +    j[0] = t;
  181. +    j[1] = s;
  182. +    dynarray_add((void ***)&jmplst, &nb_jmplst, j);
  183. +}
  184. +
  185.  /* psym is used to put an instruction with a data field which is a
  186.     reference to a symbol. It is in fact the same as oad ! */
  187.  #define psym oad
  188. @@ -161,6 +262,10 @@ ST_FUNC int oad(int c, int s)
  189.      int ind1;
  190.  
  191.      o(c);
  192. +    if (tcc_state->optimize & OPT_JUMPS) {
  193. +        if (c == 0xe9 || (c & 0xf0ff) == 0x800f)
  194. +            add_jump(ind, c == 0xe9 ? ins_len : (ins_len & 15));
  195. +    }
  196.      ind1 = ind + 4;
  197.      if (ind1 > cur_text_section->data_allocated)
  198.          section_realloc(cur_text_section, ind1);
  199. @@ -185,45 +290,242 @@ ST_FUNC void gen_addrpc32(int r, Sym *sy
  200.      gen_le32(c - 4);
  201.  }
  202.  
  203. -/* generate a modrm reference. 'op_reg' contains the addtionnal 3
  204. +/* generate a modrm reference. 'op_reg' contains the additional 3
  205.     opcode bits */
  206. -static void gen_modrm(int op_reg, int r, Sym *sym, int c)
  207. +static void gen_modrm(int opc, int op_reg, int r, Sym *sym, int c)
  208.  {
  209. +    o(opc);
  210.      op_reg = op_reg << 3;
  211.      if ((r & VT_VALMASK) == VT_CONST) {
  212.          /* constant memory reference */
  213. -        o(0x05 | op_reg);
  214. +        if (op_reg == TREG_EAX && cur_text_section->data[ind-1] >= 0x88 &&
  215. +                                  cur_text_section->data[ind-1] <= 0x8b)
  216. +            cur_text_section->data[ind-1] ^= 0xa3 ^ 0x89; /* use eax directly */
  217. +        else
  218. +            g(0x05 | op_reg);
  219.          gen_addr32(r, sym, c);
  220.      } else if ((r & VT_VALMASK) == VT_LOCAL) {
  221.          /* currently, we use only ebp as base */
  222.          if (c == (char)c) {
  223.              /* short reference */
  224. -            o(0x45 | op_reg);
  225. +            g(0x45 | op_reg);
  226.              g(c);
  227.          } else {
  228. -            oad(0x85 | op_reg, c);
  229. +            g(0x85 | op_reg);
  230. +            gen_le32(c);
  231.          }
  232. +        if (c > 0)
  233. +            func_uses_args = 1;
  234.      } else {
  235. -        g(0x00 | op_reg | (r & VT_VALMASK));
  236. +        r &= VT_VALMASK;
  237. +        if ((tcc_state->optimize & OPT_REGS) &&
  238. +            (o_v[r].indr != 0 || o_v[r].indc != 0)) {
  239. +            if (o_v[r].indr != 0) {
  240. +                if (o_v[r].r == (op_reg >> 3)) {
  241. +                    /* can't do mov op_reg, [r + op_reg] as it won't work with
  242. +                       long longs:
  243. +                         mov eax, [ecx+eax]
  244. +                         mov edx, [ecx+eax+4]  // no good
  245. +                    */
  246. +                    o_v[r].indr = 0;
  247. +                    goto no_offset;
  248. +                }
  249. +                adjust_oind(o_v[r].indr, 2);
  250. +            }
  251. +            if (o_v[r].indc != 0) {
  252. +                adjust_oind(o_v[r].indc, o_v[r].lenc);
  253. +            }
  254. +            opc = push_load == 2 ? op_reg = 0, 0x30 : 0x00;
  255. +            if (o_v[r].indc == 0) {
  256. +                g(opc | 0x04 | op_reg);
  257. +                g(r | (o_v[r].r << 3));
  258. +                o_v[r].indr = -1;
  259. +            } else {
  260. +                opc |= (o_v[r].c == (char)o_v[r].c) ? 0x40 : 0x80;
  261. +                if (o_v[r].indr != 0) {
  262. +                    g(opc | 0x04 | op_reg);
  263. +                    g(r | (o_v[r].r << 3));
  264. +                    o_v[r].indr = -1;
  265. +                } else {
  266. +                    g(opc | op_reg | r);
  267. +                }
  268. +                if (opc & 0x40)
  269. +                    g(o_v[r].c);
  270. +                else
  271. +                    gen_le32(o_v[r].c);
  272. +                o_v[r].indc = -1;
  273. +            }
  274. +            rv_cache[r] = o_v[r].v;
  275. +        } else {
  276. +        no_offset:
  277. +            g(0x00 | op_reg | r);
  278. +        }
  279. +    }
  280. +}
  281. +
  282. +static void adjust_oind(int t, int s)
  283. +{
  284. +    int r;
  285. +
  286. +    if (t < 0)
  287. +        return;
  288. +    for (r = 0; r < NB_INT_REGS; ++r) {
  289. +        if (o_v[r].indc > t)
  290. +            o_v[r].indc -= s;
  291. +        if (o_v[r].indr > t)
  292. +            o_v[r].indr -= s;
  293. +    }
  294. +    adjust_reloc(t, s);
  295. +    memcpy(cur_text_section->data + t,
  296. +           cur_text_section->data + t + s,
  297. +           ind - (t + s));
  298. +    ind -= s;
  299. +
  300. +    if (tcc_state->optimize & OPT_JUMPS) {
  301. +        int cnt = 0;
  302. +        r = ins_ind;
  303. +        ins_ind -= s;
  304. +        s = ins_len;
  305. +        while (s) {
  306. +            r -= s & 15;
  307. +            if (r == t) {
  308. +                if (cnt == 0)
  309. +                    ins_len >>= 4;
  310. +                else {
  311. +                    s = (1 << cnt) - 1;
  312. +                    r = ins_len & s;
  313. +                    ins_len = (unsigned)ins_len >> 4;
  314. +                    ins_len &= ~s;
  315. +                    ins_len |= r;
  316. +                }
  317. +                break;
  318. +            }
  319. +            cnt += 4;
  320. +            s = (unsigned)s >> 4;
  321. +        }
  322. +    }
  323. +}
  324. +
  325. +static void clear_reg(int r)
  326. +{
  327. +    int fr;
  328. +
  329. +    rv_cache[r].ld.r = -1;
  330. +    rv_cache[r].st.r = -1;
  331. +    for (fr = 0; fr < NB_INT_REGS; ++fr) {
  332. +        if ((rv_cache[fr].ld.r & VT_VALMASK) == r)
  333. +            rv_cache[fr].ld.r = -1;
  334. +        if ((rv_cache[fr].st.r & VT_VALMASK) == r)
  335. +            rv_cache[fr].st.r = -1;
  336. +        if (o_v[fr].indr != 0 && o_v[fr].r == r)
  337. +            o_v[fr].indr = o_v[fr].indc = o_v[fr].c = 0;
  338. +    }
  339. +}
  340. +
  341. +static int cmpval(SValue *v1, SValue *v2)
  342. +{
  343. +  if (v1->c.i != v2->c.i)
  344. +      return 0;
  345. +  if (v1->r & VT_SYM)
  346. +      return (v2->r & VT_SYM) && v1->sym == v2->sym;
  347. +  return !(v2->r & VT_SYM);
  348. +}
  349. +
  350. +static void clear_val(SValue *v)
  351. +{
  352. +    int r, fr;
  353. +
  354. +    r = v->r;
  355. +    for (fr = 0; fr < NB_INT_REGS; ++fr) {
  356. +        if (r == rv_cache[fr].ld.r && cmpval(v, &rv_cache[fr].ld))
  357. +            rv_cache[fr].ld.r = -1;
  358. +        if (r == rv_cache[fr].st.r && cmpval(v, &rv_cache[fr].st))
  359. +            rv_cache[fr].st.r = -1;
  360.      }
  361.  }
  362.  
  363. +/* check if a register/value has already been assigned the value/register */
  364. +static int ccheck(int r, SValue *v)
  365. +{
  366. +    int r1, fr, fc;
  367. +    int n;
  368. +
  369. +    if (!cache_used ||
  370. +        cache_ind != ind ||
  371. +        r >= NB_INT_REGS ||
  372. +        q_state > Q_READY)
  373. +        return 0;
  374. +
  375. +    fc = v->c.i;
  376. +    fr = v->r;
  377. +    if (fr == rv_cache[r].ld.r
  378. +     && (fr & VT_VALMASK) == VT_CONST && !(fr & VT_SYM)
  379. +     && (fc & 0xffffff00) == (rv_cache[r].ld.c.i & 0xffffff00)) {
  380. +        if ((fc & 0xff) != (rv_cache[r].ld.c.i & 0xff)) {
  381. +            og(0xb0 + r, fc);
  382. +            cache_ind = ind;
  383. +            rv_cache[r].ld.c.i = fc;
  384. +            o_v[r].indr = o_v[r].indc = o_v[r].c = 0;
  385. +        }
  386. +        return 1;
  387. +    }
  388. +    /* check the register itself first, then the other registers */
  389. +    for (r1 = r, n = NB_INT_REGS; n > 0; --n) {
  390. +        if ((fr == rv_cache[r1].ld.r && cmpval(v, &rv_cache[r1].ld)) ||
  391. +            (fr == rv_cache[r1].st.r && cmpval(v, &rv_cache[r1].st))) {
  392. +            if (r != r1) {
  393. +                if (push_load) {
  394. +                    push_load = 2;
  395. +                    o(0x50 + r1);
  396. +                } else {
  397. +                    if (fc == 0 && !(fr & VT_SYM) &&
  398. +                        (fr & VT_VALMASK) == VT_CONST)
  399. +                        o(O2(0x33, 0xc0 + r * 9));  /* xor r, r */
  400. +                    else
  401. +                        o(O2(0x89, 0xc0 + r + r1 * 8)); /* mov r1, r */
  402. +                    rv_cache[r] = rv_cache[r1];
  403. +                }
  404. +                cache_ind = ind;
  405. +            }
  406. +            o_v[r].indr = o_v[r].indc = o_v[r].c = 0;
  407. +            return 1;
  408. +        }
  409. +        if (n == NB_INT_REGS)
  410. +            r1 = (r == 0) ? 1 : 0;
  411. +        else if (++r1 == r)
  412. +            ++r1;
  413. +    }
  414. +    return 0;
  415. +}
  416. +
  417.  /* load 'r' from value 'sv' */
  418.  ST_FUNC void load(int r, SValue *sv)
  419.  {
  420. -    int v, t, ft, fc, fr;
  421. +    int v, t, ft, fc, fr, sr = r;
  422.      SValue v1;
  423. +    int opc;
  424.  
  425.  #ifdef TCC_TARGET_PE
  426.      SValue v2;
  427.      sv = pe_getimport(sv, &v2);
  428.  #endif
  429.  
  430. +    if (r == TREG_EBX)
  431. +        func_uses_ebx = 1;
  432. +
  433.      fr = sv->r;
  434.      ft = sv->type.t;
  435.      fc = sv->c.ul;
  436.  
  437.      v = fr & VT_VALMASK;
  438. +
  439. +    if (tcc_state->optimize & OPT_REGS) {
  440. +        if (q_state > Q_READY && ((fr & VT_LVAL) || v != VT_CONST))
  441. +            flushq();
  442. +        if (ccheck(r, sv))
  443. +            return;
  444. +    }
  445. +
  446.      if (fr & VT_LVAL) {
  447.          if (v == VT_LLOCAL) {
  448.              v1.type.t = VT_INT;
  449. @@ -232,55 +534,215 @@ ST_FUNC void load(int r, SValue *sv)
  450.              fr = r;
  451.              if (!(reg_classes[fr] & RC_INT))
  452.                  fr = get_reg(RC_INT);
  453. +            t = push_load;
  454. +            push_load = 0;
  455.              load(fr, &v1);
  456. +            push_load = t;
  457.          }
  458.          if ((ft & VT_BTYPE) == VT_FLOAT) {
  459. -            o(0xd9); /* flds */
  460. +            opc = 0xd9; /* flds */
  461.              r = 0;
  462.          } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
  463. -            o(0xdd); /* fldl */
  464. +            opc = 0xdd; /* fldl */
  465.              r = 0;
  466.          } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
  467. -            o(0xdb); /* fldt */
  468. +            opc = 0xdb; /* fldt */
  469.              r = 5;
  470.          } else if ((ft & VT_TYPE) == VT_BYTE) {
  471. -            o(0xbe0f);   /* movsbl */
  472. +            opc = 0xbe0f;   /* movsbl */
  473.          } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
  474. -            o(0xb60f);   /* movzbl */
  475. +            opc = 0xb60f;   /* movzbl */
  476.          } else if ((ft & VT_TYPE) == VT_SHORT) {
  477. -            o(0xbf0f);   /* movswl */
  478. +            opc = 0xbf0f;   /* movswl */
  479.          } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
  480. -            o(0xb70f);   /* movzwl */
  481. +            opc = 0xb70f;   /* movzwl */
  482.          } else {
  483. -            o(0x8b);     /* movl */
  484. +            if (push_load) {
  485. +                push_load = 2;
  486. +                r = 6;
  487. +                opc = 0xff; /* pushl */
  488. +            } else {
  489. +                opc = 0x8b; /* movl */
  490. +            }
  491.          }
  492. -        gen_modrm(r, fr, sv->sym, fc);
  493. +        gen_modrm(opc, r, fr, sv->sym, fc);
  494.      } else {
  495.          if (v == VT_CONST) {
  496. -            o(0xb8 + r); /* mov $xx, r */
  497. -            gen_addr32(fr, sv->sym, fc);
  498. +            if (push_load) {
  499. +                push_load = 2;
  500. +                if ((fr & VT_SYM) || fc != (char)fc) {
  501. +                    o(0x68); /* push $xx */
  502. +                    gen_addr32(fr, sv->sym, fc);
  503. +                } else {
  504. +                    og(0x6a, fc); /* push $x */
  505. +                }
  506. +            } else {
  507. +                if (tcc_state->optimize & OPT_REGS) {
  508. +                    if (q_state == Q_L) {
  509. +                        /* load R1 + load R2
  510. +                           if registers are different, queue R2 (long long);
  511. +                           otherwise R2 can replace R1 (don't know
  512. +                           if that would actually happen) */
  513. +                        if (r != q_r[0]) {
  514. +                            q_r[1] = r;
  515. +                            q_lv[1] = *sv;
  516. +                            q_c[1] = rv_cache[r];
  517. +                            clear_reg(r);
  518. +                            q_state = Q_LL;
  519. +                            return;
  520. +                        }
  521. +                        q_state = Q_READY;
  522. +                    } else if (q_state == Q_LS) {
  523. +                        /* load R1 + store R1 + load R2
  524. +                           if the two loads are the same, load and store R1,
  525. +                           ignore R2 (cached R1) */
  526. +                        q_state = Q_IGNORE;
  527. +                        if (r == q_r[0] && cmpval(sv, &q_lv[0])) {
  528. +                            loadc(0);
  529. +                            storec(0);
  530. +                            q_state = Q_READY;
  531. +                            return;
  532. +                        }
  533. +                        store_const(0);
  534. +                        q_state = Q_READY;
  535. +                    } else if (q_state == Q_LL) {
  536. +                        /* load R1 + load R2 + load R3
  537. +                           don't know if this would actually happen */
  538. +                        if (r == q_r[1]) {
  539. +                            q_lv[1] = *sv;
  540. +                        } else {
  541. +                            if (r != q_r[0]) {
  542. +                                q_state = Q_IGNORE;
  543. +                                loadc(0);
  544. +                                q_c[1] = rv_cache[r];
  545. +                                clear_reg(r);
  546. +                                q_state = Q_LL;
  547. +                            }
  548. +                            q_r[0] = q_r[1];
  549. +                            q_lv[0] = q_lv[1];
  550. +                            q_c[0] = q_c[1];
  551. +                            q_r[1] = r;
  552. +                            q_lv[1] = *sv;
  553. +                        }
  554. +                        return;
  555. +                    } else if (q_state == Q_LLS) {
  556. +                        /* load R1 + load R2 + store R1 + load R3
  557. +                           again, not sure if this actually happens */
  558. +                        q_state = Q_IGNORE;
  559. +                        if (r == q_r[0] && cmpval(sv, &q_lv[0])) {
  560. +                            loadc(0);
  561. +                            loadc(1);
  562. +                            storec(0);
  563. +                            q_state = Q_READY;
  564. +                            return;
  565. +                        }
  566. +                        store_const(0);
  567. +                        if (r != q_r[1])
  568. +                            loadc(1);
  569. +                        q_state = Q_READY;
  570. +                    } else if (q_state == Q_LLSS) {
  571. +                        /* load R1 + load R2 + store R1 + store R2 + load R3 */
  572. +                        q_state = Q_IGNORE;
  573. +                        if ((r == q_r[0] && cmpval(sv, &q_lv[0])) ||
  574. +                            /* take a punt on load R4,0 */
  575. +                            (q_lv[1].c.i == 0 && !(q_lv[1].r & VT_SYM))) {
  576. +                            loadc(0);
  577. +                            loadc(1);
  578. +                            storec(0);
  579. +                            storec(1);
  580. +                            if (r == q_r[0] && cmpval(sv, &q_lv[0])) {
  581. +                                q_state = Q_READY;
  582. +                                return;
  583. +                            }
  584. +                        } else {
  585. +                            store_const(0);
  586. +                            store_const(1);
  587. +                        }
  588. +                        q_state = Q_READY;
  589. +                    }
  590. +                    if (q_state == Q_READY) {
  591. +                        q_r[0] = r;
  592. +                        q_lv[0] = *sv;
  593. +                        q_c[0] = rv_cache[r];
  594. +                        clear_reg(r);
  595. +                        q_state = Q_L;
  596. +                        return;
  597. +                    }
  598. +                }
  599. +                if ((fr & VT_SYM) || fc != 0) {
  600. +                    o(0xb8 + r); /* mov $xx, r */
  601. +                    gen_addr32(fr, sv->sym, fc);
  602. +                } else {
  603. +                    o(O2(0x33, 0xc0 + r * 9)); /* xor r, r */
  604. +                }
  605. +            }
  606.          } else if (v == VT_LOCAL) {
  607.              if (fc) {
  608. -                o(0x8d); /* lea xxx(%ebp), r */
  609. -                gen_modrm(r, VT_LOCAL, sv->sym, fc);
  610. +                gen_modrm(0x8d, /* lea xxx(%ebp), r */
  611. +                          r, VT_LOCAL, sv->sym, fc);
  612.              } else {
  613. -                o(0x89);
  614. -                o(0xe8 + r); /* mov %ebp, r */
  615. +                if (push_load) {
  616. +                    push_load = 2;
  617. +                    o(0x55); /* push %ebp */
  618. +                } else {
  619. +                    o(O2(0x89, 0xe8 + r)); /* mov %ebp, r */
  620. +                }
  621.              }
  622.          } else if (v == VT_CMP) {
  623. -            oad(0xb8 + r, 0); /* mov $0, r */
  624. -            o(0x0f); /* setxx %br */
  625. -            o(fc);
  626. -            o(0xc0 + r);
  627. +            o(O3(0x0f, fc, 0xc0 + r)); /* setxx %br */
  628. +            cache_ind = ind;
  629. +            o(O3(0x0f, 0xb6, 0xc0 + r * 9)); /* movzx br, r */
  630.          } else if (v == VT_JMP || v == VT_JMPI) {
  631.              t = v & 1;
  632. -            oad(0xb8 + r, t); /* mov $1, r */
  633. -            o(0x05eb); /* jmp after */
  634. +            if (push_load) {
  635. +                push_load = 2;
  636. +                og(0x6a, t); /* push t */
  637. +                cache_ind = ind;
  638. +                o(0x02eb); /* jmp after */
  639. +            } else {
  640. +                if (!t) {
  641. +                    /* Note: changing these instructions requires corresponding
  642. +                       change in jmpopt */
  643. +                    o(O2(0x33, 0xc0 + r * 9)); /* xor r, r */
  644. +                    cache_ind = ind;
  645. +                    o(0x05eb); /* jmp after */
  646. +                } else {
  647. +                    oad(0xb8 + r, 1); /* mov $1, r */
  648. +                    cache_ind = ind;
  649. +                    o(0x02eb); /* jmp after */
  650. +                }
  651. +                if (tcc_state->optimize & OPT_JUMPS)
  652. +                    add_jump(-ind, t | (r << 1));
  653. +            }
  654.              gsym(fc);
  655. -            oad(0xb8 + r, t ^ 1); /* mov $0, r */
  656. +            if (push_load) {
  657. +                og(0x6a, t ^ 1);
  658. +            } else if (t) {
  659. +                o(O2(0x33, 0xc0 + r * 9));
  660. +            } else {
  661. +                oad(0xb8 + r, 1);
  662. +            }
  663.          } else if (v != r) {
  664. -            o(0x89);
  665. -            o(0xc0 + r + v * 8); /* mov v, r */
  666. +            if (push_load) {
  667. +                push_load = 2;
  668. +                o(0x50 + v); /* push v */
  669. +            } else {
  670. +                o(O2(0x89, 0xc0 + r + v * 8)); /* mov v, r */
  671. +            }
  672. +        }
  673. +    }
  674. +
  675. +    if (tcc_state->optimize & OPT_REGS) {
  676. +        cache_ind = ind;
  677. +        if (sr < NB_INT_REGS) {
  678. +            if (push_load != 2) {
  679. +                clear_reg(sr);
  680. +                if (v >= VT_CONST) {
  681. +                    rv_cache[sr].ld = *sv;
  682. +                    cache_used = 1;
  683. +                }
  684. +                o_v[sr].indr = o_v[sr].indc = o_v[sr].c = 0;
  685. +            }
  686.          }
  687.      }
  688.  }
  689. @@ -288,7 +750,8 @@ ST_FUNC void load(int r, SValue *sv)
  690.  /* store register 'r' in lvalue 'v' */
  691.  ST_FUNC void store(int r, SValue *v)
  692.  {
  693. -    int fr, bt, ft, fc;
  694. +    int sr = r, fr, bt, ft, fc;
  695. +    int opc;
  696.  
  697.  #ifdef TCC_TARGET_PE
  698.      SValue v2;
  699. @@ -301,46 +764,184 @@ ST_FUNC void store(int r, SValue *v)
  700.      bt = ft & VT_BTYPE;
  701.      /* XXX: incorrect if float reg to reg */
  702.      if (bt == VT_FLOAT) {
  703. -        o(0xd9); /* fsts */
  704. +        opc = 0xd9; /* fsts */
  705.          r = 2;
  706.      } else if (bt == VT_DOUBLE) {
  707. -        o(0xdd); /* fstpl */
  708. +        opc = 0xdd; /* fstpl */
  709.          r = 2;
  710.      } else if (bt == VT_LDOUBLE) {
  711.          o(0xc0d9); /* fld %st(0) */
  712. -        o(0xdb); /* fstpt */
  713. +        cache_ind = ind;
  714. +        opc = 0xdb; /* fstpt */
  715.          r = 7;
  716.      } else {
  717. -        if (bt == VT_SHORT)
  718. -            o(0x66);
  719.          if (bt == VT_BYTE || bt == VT_BOOL)
  720. -            o(0x88);
  721. +            opc = 0x88;
  722. +        else if (bt == VT_SHORT)
  723. +            opc = 0x8966;
  724.          else
  725. -            o(0x89);
  726. +            opc = 0x89;
  727.      }
  728.      if (fr == VT_CONST ||
  729.          fr == VT_LOCAL ||
  730.          (v->r & VT_LVAL)) {
  731. -        gen_modrm(r, v->r, v->sym, fc);
  732. +        if (tcc_state->optimize & OPT_REGS) {
  733. +            if (q_state == Q_L) {
  734. +                /* load R1 + store R2 */
  735. +                if (r == q_r[0]) {
  736. +                    q_sv[0] = *v;
  737. +                    q_state = Q_LS;
  738. +                    return;
  739. +                }
  740. +                q_state = Q_IGNORE;
  741. +                loadc(0);
  742. +                q_state = Q_READY;
  743. +            } else if (q_state == Q_LS) {
  744. +                /* load R1 + store R1 + store R2 */
  745. +                q_state = Q_IGNORE;
  746. +                loadc(0);
  747. +                storec(0);
  748. +                q_state = Q_READY;
  749. +            } else if (q_state == Q_LL) {
  750. +                /* load R1 + load R2 + store R3 */
  751. +                if (r == q_r[0]) {
  752. +                    q_sv[0] = *v;
  753. +                    q_state = Q_LLS;
  754. +                    return;
  755. +                }
  756. +                q_state = Q_IGNORE;
  757. +                if (r == q_r[1]) {
  758. +                    loadc(0);
  759. +                    q_r[0] = q_r[1];
  760. +                    q_lv[0] = q_lv[1];
  761. +                    q_sv[0] = *v;
  762. +                    q_state = Q_LS;
  763. +                    return;
  764. +                }
  765. +                loadc(0);
  766. +                loadc(1);
  767. +                q_state = Q_READY;
  768. +            } else if (q_state == Q_LLS) {
  769. +                /* load R1 + load R2 + store R1 + store R3 */
  770. +                if (r == q_r[1]) {
  771. +                    q_sv[1] = *v;
  772. +                    q_state = Q_LLSS;
  773. +                    return;
  774. +                }
  775. +                q_state = Q_IGNORE;
  776. +                loadc(0);
  777. +                loadc(1);
  778. +                storec(0);
  779. +                q_state = Q_READY;
  780. +            } else if (q_state == Q_LLSS) {
  781. +                /* load R1 + load R2 + store R1 + store R2 + store R3 */
  782. +                q_state = Q_IGNORE;
  783. +                loadc(0);
  784. +                loadc(1);
  785. +                storec(0);
  786. +                storec(1);
  787. +                q_state = Q_READY;
  788. +            }
  789. +        }
  790. +        gen_modrm(opc, r, v->r, v->sym, fc);
  791.      } else if (fr != r) {
  792. -        o(0xc0 + fr + r * 8); /* mov r, fr */
  793. +        og(opc, 0xc0 + fr + r * 8); /* mov r, fr */
  794. +    }
  795. +
  796. +    if (tcc_state->optimize & OPT_REGS) {
  797. +        cache_ind = ind;
  798. +        if (sr < NB_INT_REGS) {
  799. +            if (fr >= VT_CONST) {
  800. +                clear_val(v);
  801. +                rv_cache[sr].st = *v;
  802. +                cache_used = 1;
  803. +            }
  804. +            o_v[sr].indr = o_v[sr].indc = o_v[sr].c = 0;
  805. +        }
  806. +    }
  807. +}
  808. +
  809. +static void loadc(int q)
  810. +{
  811. +    rv_cache[q_r[q]] = q_c[q];
  812. +    load(q_r[q], &q_lv[q]);
  813. +}
  814. +
  815. +static void storec(int q)
  816. +{
  817. +    store(q_r[q], &q_sv[q]);
  818. +}
  819. +
  820. +static void store_const(int q)
  821. +{
  822. +    SValue *sv, *v;
  823. +    int r, bt;
  824. +    int opc;
  825. +
  826. +    r = q_r[q];
  827. +    sv = &q_lv[q];
  828. +    v = &q_sv[q];
  829. +    bt = v->type.t & VT_BTYPE;
  830. +
  831. +    if (bt == VT_BYTE || bt == VT_BOOL)
  832. +        opc = 0xc6;
  833. +    else if (bt == VT_SHORT)
  834. +        opc = 0xc766;
  835. +    else
  836. +        opc = 0xc7;
  837. +    gen_modrm(opc, 0, v->r, v->sym, v->c.i);
  838. +    if (bt == VT_BYTE || bt == VT_BOOL)
  839. +        g(sv->c.i);
  840. +    else if (bt == VT_SHORT)
  841. +        gen_le16(sv->c.i);
  842. +    else
  843. +        gen_addr32(sv->r, sv->sym, sv->c.i);
  844. +
  845. +    cache_ind = ind;
  846. +    rv_cache[r] = q_c[q];
  847. +}
  848. +
  849. +ST_FUNC void flushq(void)
  850. +{
  851. +    if (q_state > Q_READY) {
  852. +        int q = q_state;
  853. +        q_state = Q_IGNORE;
  854. +        if (q & Q_S1)
  855. +            store_const(0);
  856. +        if (q == Q_LLSS) {
  857. +            store_const(1);
  858. +        } else {
  859. +            if (!(q & Q_S1))
  860. +                loadc(0);
  861. +            if (q & Q_L2)
  862. +                loadc(1);
  863. +        }
  864. +        q_state = Q_READY;
  865.      }
  866.  }
  867.  
  868.  static void gadd_sp(int val)
  869.  {
  870. -    if (val == (char)val) {
  871. -        o(0xc483);
  872. -        g(val);
  873. +    if (val < 0) {
  874. +        if (val == (char)val)
  875. +            o(O3(0x83, 0xec, -val));
  876. +        else
  877. +            oad(0xec81, -val); /* sub $xxx, %esp */
  878.      } else {
  879. -        oad(0xc481, val); /* add $xxx, %esp */
  880. +        if (val == (char)val)
  881. +            o(O3(0x83, 0xc4, val));
  882. +        else
  883. +            oad(0xc481, val); /* add $xxx, %esp */
  884.      }
  885. +    cache_ind = ind;
  886.  }
  887.  
  888.  /* 'is_jmp' is '1' if it is a jump */
  889.  static void gcall_or_jmp(int is_jmp)
  890.  {
  891.      int r;
  892. +    if (q_state > Q_READY)
  893. +        flushq();
  894.      if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
  895.          /* constant case */
  896.          if (vtop->r & VT_SYM) {
  897. @@ -353,12 +954,23 @@ static void gcall_or_jmp(int is_jmp)
  898.                            ind + 1, R_386_PC32, 0);
  899.          }
  900.          oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
  901. +    } else if ((vtop->r & (VT_VALMASK | VT_SYM)) == (VT_CONST | VT_SYM)) {
  902. +        greloc(cur_text_section, vtop->sym,
  903. +               ind + 2, R_386_32);
  904. +        oad(0x15ff + (is_jmp << 4), vtop->c.ul); /* call/jmp [im] */
  905. +    } else if ((vtop->r & VT_VALMASK) == VT_LOCAL) {
  906. +        if (vtop->c.i == (char)vtop->c.i)
  907. +            og(0x55ff + (is_jmp << 4), vtop->c.i);
  908. +        else
  909. +            oad(0x95ff + (is_jmp << 4), vtop->c.i); /* call/jmp [ebp+x] */
  910.      } else {
  911.          /* otherwise, indirect call */
  912.          r = gv(RC_INT);
  913. -        o(0xff); /* call/jmp *r */
  914. -        o(0xd0 + r + (is_jmp << 4));
  915. +        o(O2(0xff, 0xd0 + r + (is_jmp << 4))); /* call/jmp *r */
  916.      }
  917. +    if (/*(tcc_state->optimize & OPT_REGS) && */cache_used &&
  918. +        !is_jmp && (short)rv_cache[TREG_EBX].ld.r != -1)
  919. +        cache_used = 2;
  920.  }
  921.  
  922.  static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
  923. @@ -376,18 +988,24 @@ ST_FUNC void gfunc_call(int nb_args)
  924.      for(i = 0;i < nb_args; i++) {
  925.          if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
  926.              size = type_size(&vtop->type, &align);
  927. +            if (size <= 4)
  928. +                goto small_struct;
  929. +            if (size <= 8) {
  930. +                vtop->type.t &= ~VT_BTYPE;
  931. +                vtop->type.t |= VT_LLONG;
  932. +                goto small_struct;
  933. +            }
  934.              /* align to stack align size */
  935.              size = (size + 3) & ~3;
  936.              /* allocate the necessary size on stack */
  937. -            oad(0xec81, size); /* sub $xxx, %esp */
  938. +            gadd_sp(-size);
  939.              /* generate structure store */
  940.              r = get_reg(RC_INT);
  941. -            o(0x89); /* mov %esp, r */
  942. -            o(0xe0 + r);
  943. +            o(O2(0x89, 0xe0 + r)); /* mov %esp, r */
  944. +            cache_ind = ind;
  945.              vset(&vtop->type, r | VT_LVAL, 0);
  946.              vswap();
  947.              vstore();
  948. -            args_size += size;
  949.          } else if (is_float(vtop->type.t)) {
  950.              gv(RC_FLOAT); /* only one float register */
  951.              if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
  952. @@ -396,27 +1014,34 @@ ST_FUNC void gfunc_call(int nb_args)
  953.                  size = 8;
  954.              else
  955.                  size = 12;
  956. -            oad(0xec81, size); /* sub $xxx, %esp */
  957. +            gadd_sp(-size);
  958.              if (size == 12)
  959.                  o(0x7cdb);
  960.              else
  961.                  o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
  962. -            g(0x24);
  963. -            g(0x00);
  964. -            args_size += size;
  965. +            gen_le16(0x0024);
  966. +            cache_ind = ind;
  967.          } else {
  968. +        small_struct:
  969.              /* simple type (currently always same size) */
  970. -            /* XXX: implicit cast ? */
  971. +            if ((tcc_state->optimize & OPT_REGS)
  972. +             && (vtop->type.t & VT_BTYPE) != VT_LLONG) {
  973. +                if (q_state > Q_READY)
  974. +                    flushq();
  975. +                push_load = 1;
  976. +            }
  977.              r = gv(RC_INT);
  978. +            size = 4;
  979.              if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
  980.                  size = 8;
  981.                  o(0x50 + vtop->r2); /* push r */
  982. -            } else {
  983. -                size = 4;
  984.              }
  985. -            o(0x50 + r); /* push r */
  986. -            args_size += size;
  987. +            if (push_load < 2)
  988. +                o(0x50 + r); /* push r */
  989. +            push_load = 0;
  990. +            cache_ind = ind;
  991.          }
  992. +        args_size += size;
  993.          vtop--;
  994.      }
  995.      save_regs(0); /* save used temporary registers */
  996. @@ -445,8 +1070,18 @@ ST_FUNC void gfunc_call(int nb_args)
  997.      gcall_or_jmp(0);
  998.  
  999.  #ifdef TCC_TARGET_PE
  1000. -    if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
  1001. -        args_size -= 4;
  1002. +    if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT) {
  1003. +        size = type_size(&func_sym->type, &align);
  1004. +        if (size > 8) {
  1005. +            args_size -= 4;
  1006. +        } else {
  1007. +            store(TREG_EAX, &ret_st);
  1008. +            if (size > 4) {
  1009. +                ret_st.c.i += 4;
  1010. +                store(TREG_EDX, &ret_st);
  1011. +            }
  1012. +        }
  1013. +    }
  1014.  #endif
  1015.      if (args_size && func_call != FUNC_STDCALL)
  1016.          gadd_sp(args_size);
  1017. @@ -454,9 +1089,9 @@ ST_FUNC void gfunc_call(int nb_args)
  1018.  }
  1019.  
  1020.  #ifdef TCC_TARGET_PE
  1021. -#define FUNC_PROLOG_SIZE 10
  1022. +#define FUNC_PROLOG_SIZE 11
  1023.  #else
  1024. -#define FUNC_PROLOG_SIZE 9
  1025. +#define FUNC_PROLOG_SIZE 10
  1026.  #endif
  1027.  
  1028.  /* generate function prolog of type 't' */
  1029. @@ -488,14 +1123,24 @@ ST_FUNC void gfunc_prolog(CType *func_ty
  1030.  
  1031.      ind += FUNC_PROLOG_SIZE;
  1032.      func_sub_sp_offset = ind;
  1033. +    prolog_reloc_offset = (cur_text_section->reloc)
  1034. +                          ? cur_text_section->reloc->data_offset : 0;
  1035.      /* if the function returns a structure, then add an
  1036.         implicit pointer parameter */
  1037.      func_vt = sym->type;
  1038.      if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
  1039.          /* XXX: fastcall case ? */
  1040. +#ifdef TCC_TARGET_PE
  1041. +        int size, align;
  1042. +        size = type_size(&func_vt, &align);
  1043. +        if (size > 8) {
  1044. +#endif
  1045.          func_vc = addr;
  1046.          addr += 4;
  1047.          param_index++;
  1048. +#ifdef TCC_TARGET_PE
  1049. +        }
  1050. +#endif
  1051.      }
  1052.      /* define parameters */
  1053.      while ((sym = sym->next) != NULL) {
  1054. @@ -511,8 +1156,8 @@ ST_FUNC void gfunc_prolog(CType *func_ty
  1055.          if (param_index < fastcall_nb_regs) {
  1056.              /* save FASTCALL register */
  1057.              loc -= 4;
  1058. -            o(0x89);     /* movl */
  1059. -            gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
  1060. +            gen_modrm(0x89, /* movl */
  1061. +                      fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
  1062.              param_addr = loc;
  1063.          } else {
  1064.              param_addr = addr;
  1065. @@ -522,6 +1167,8 @@ ST_FUNC void gfunc_prolog(CType *func_ty
  1066.                   VT_LOCAL | lvalue_type(type->t), param_addr);
  1067.          param_index++;
  1068.      }
  1069. +    func_uses_ebx = 0;
  1070. +    func_uses_args = 0;
  1071.      func_ret_sub = 0;
  1072.      /* pascal type call ? */
  1073.      if (func_call == FUNC_STDCALL)
  1074. @@ -560,6 +1207,8 @@ ST_FUNC void gfunc_epilog(void)
  1075.          ind = func_sub_sp_offset;
  1076.          sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
  1077.                                 func_bound_offset, lbounds_section->data_offset);
  1078. +        if (q_state > Q_READY)
  1079. +            flushq();
  1080.          greloc(cur_text_section, sym_data,
  1081.                 ind + 1, R_386_32);
  1082.          oad(0xb8, 0); /* mov %eax, xxx */
  1083. @@ -580,14 +1229,21 @@ ST_FUNC void gfunc_epilog(void)
  1084.          o(0x585a); /* restore returned value, if any */
  1085.      }
  1086.  #endif
  1087. -    o(0xc9); /* leave */
  1088. +    epilog_ind = ind;
  1089. +    if (func_uses_ebx)
  1090. +        o(0x5b); /* pop ebx */
  1091. +    if (!(tcc_state->optimize & OPT_PROLOG) || func_uses_args || loc != 0)
  1092. +        o(0xc9); /* leave */
  1093.      if (func_ret_sub == 0) {
  1094.          o(0xc3); /* ret */
  1095.      } else {
  1096.          o(0xc2); /* ret n */
  1097. -        g(func_ret_sub);
  1098. -        g(func_ret_sub >> 8);
  1099. +        gen_le16(func_ret_sub);
  1100.      }
  1101. +
  1102. +    if (tcc_state->optimize & OPT_JUMPS)
  1103. +        jmpopt();
  1104. +
  1105.      /* align local size to word & save local variables */
  1106.      
  1107.      v = (-loc + 3) & -4;
  1108. @@ -599,17 +1255,63 @@ ST_FUNC void gfunc_epilog(void)
  1109.          oad(0xb8, v); /* mov stacksize, %eax */
  1110.          oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
  1111.          greloc(cur_text_section, sym, ind-4, R_386_PC32);
  1112. +        if (func_uses_ebx)
  1113. +            o(0x53);  /* push ebx */
  1114. +        else
  1115. +            o(0x90);
  1116.      } else
  1117.  #endif
  1118.      {
  1119. -        o(0xe58955);  /* push %ebp, mov %esp, %ebp */
  1120. -        o(0xec81);  /* sub esp, stacksize */
  1121. -        gen_le32(v);
  1122. -#if FUNC_PROLOG_SIZE == 10
  1123. -        o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
  1124. +        if (!(tcc_state->optimize & OPT_PROLOG)) {
  1125. +            o(0xe58955);  /* push %ebp, mov %esp, %ebp */
  1126. +            oad(0xec81, v);  /* sub esp, stacksize */
  1127. +#if FUNC_PROLOG_SIZE == 11
  1128. +            if (func_uses_ebx)
  1129. +                o(0x9053);  /* push %ebx, nop */
  1130. +            else
  1131. +                o(0xff8b);  /* mov %edi, %edi */
  1132. +#else
  1133. +            if (func_uses_ebx)
  1134. +                o(0x53);  /* push ebx */
  1135. +            else
  1136. +                o(0x90);
  1137.  #endif
  1138. +        } else {
  1139. +            int skip = ind;
  1140. +            if (v != 0 || func_uses_args) {
  1141. +                o(0xe58955);  /* push %ebp, mov %esp, %ebp */
  1142. +                if (v != 0) {
  1143. +                    if (v == (char)v)
  1144. +                        o(O3(0x83, 0xec, v)); /* sub esp, stacksize */
  1145. +                    else
  1146. +                        oad(0xec81, v); /* sub esp, stacksize */
  1147. +                }
  1148. +            }
  1149. +            if (func_uses_ebx)
  1150. +                o(0x53);  /* push ebx */
  1151. +            skip = FUNC_PROLOG_SIZE - (ind - skip);
  1152. +#ifdef CONFIG_TCC_BCHECK
  1153. +            if (tcc_state->do_bounds_check
  1154. +             && func_bound_offset == lbounds_section->data_offset)
  1155. +                skip += 10;
  1156. +#endif
  1157. +            if (skip) {
  1158. +                saved_ind -= skip;
  1159. +                memcpy(cur_text_section->data + ind,
  1160. +                       cur_text_section->data + ind + skip,
  1161. +                       saved_ind - ind);
  1162. +                memset(cur_text_section->data + saved_ind, 0, skip);
  1163. +                adjust_reloc(ind, skip);
  1164. +            }
  1165. +        }
  1166.      }
  1167.      ind = saved_ind;
  1168. +#ifdef TCC_TARGET_PE
  1169. +    /* align next function to 16 bytes */
  1170. +    if (!(tcc_state->optimize & OPT_SIZE))
  1171. +        while (ind & 15)
  1172. +            g(0x90);
  1173. +#endif
  1174.  }
  1175.  
  1176.  /* generate a jump to a label */
  1177. @@ -622,13 +1324,13 @@ ST_FUNC int gjmp(int t)
  1178.  ST_FUNC void gjmp_addr(int a)
  1179.  {
  1180.      int r;
  1181. +    if (q_state > Q_READY)
  1182. +        flushq();
  1183.      r = a - ind - 2;
  1184. -    if (r == (char)r) {
  1185. -        g(0xeb);
  1186. -        g(r);
  1187. -    } else {
  1188. +    if (r == (char)r && !(tcc_state->optimize & OPT_JUMPS))
  1189. +        og(0xeb, r);
  1190. +    else
  1191.          oad(0xe9, a - ind - 5);
  1192. -    }
  1193.  }
  1194.  
  1195.  /* generate a test. set 'inv' to invert test. Stack entry is popped */
  1196. @@ -639,8 +1341,8 @@ ST_FUNC int gtst(int inv, int t)
  1197.      v = vtop->r & VT_VALMASK;
  1198.      if (v == VT_CMP) {
  1199.          /* fast case : can jump directly since flags are set */
  1200. -        g(0x0f);
  1201. -        t = psym((vtop->c.i - 16) ^ inv, t);
  1202. +        t = psym(O2(0x0f, (vtop->c.i - 16) ^ inv), t);
  1203. +        cache_ind = ind;
  1204.      } else if (v == VT_JMP || v == VT_JMPI) {
  1205.          /* && or || optimization */
  1206.          if ((v & 1) == inv) {
  1207. @@ -650,6 +1352,7 @@ ST_FUNC int gtst(int inv, int t)
  1208.                  p = (int *)(cur_text_section->data + *p);
  1209.              *p = t;
  1210.              t = vtop->c.i;
  1211. +            cache_ind = ind;
  1212.          } else {
  1213.              t = gjmp(t);
  1214.              gsym(vtop->c.i);
  1215. @@ -666,10 +1369,9 @@ ST_FUNC int gtst(int inv, int t)
  1216.                  t = gjmp(t);
  1217.          } else {
  1218.              v = gv(RC_INT);
  1219. -            o(0x85);
  1220. -            o(0xc0 + v * 9);
  1221. -            g(0x0f);
  1222. -            t = psym(0x85 ^ inv, t);
  1223. +            o(O2(0x85, 0xc0 + v * 9)); cache_ind = ind;
  1224. +            t = psym(O2(0x0f, 0x85 ^ inv), t);
  1225. +            cache_ind = ind;
  1226.          }
  1227.      }
  1228.      vtop--;
  1229. @@ -680,6 +1382,8 @@ ST_FUNC int gtst(int inv, int t)
  1230.  ST_FUNC void gen_opi(int op)
  1231.  {
  1232.      int r, fr, opc, c;
  1233. +    static int shl_ind, shl_val;
  1234. +    int add_len = 0;
  1235.  
  1236.      switch(op) {
  1237.      case '+':
  1238. @@ -688,37 +1392,83 @@ ST_FUNC void gen_opi(int op)
  1239.      gen_op8:
  1240.          if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  1241.              /* constant case */
  1242. +            int i = ind;
  1243.              vswap();
  1244.              r = gv(RC_INT);
  1245.              vswap();
  1246.              c = vtop->c.i;
  1247. -            if (c == (char)c) {
  1248. -                /* generate inc and dec for smaller code */
  1249. -                if (c==1 && opc==0) {
  1250. -                    o (0x40 | r); // inc
  1251. -                } else if (c==1 && opc==5) {
  1252. -                    o (0x48 | r); // dec
  1253. -                } else {
  1254. -                    o(0x83);
  1255. -                    o(0xc0 | (opc << 3) | r);
  1256. -                    g(c);
  1257. +            if (c == 0) {
  1258. +                if (opc == 7) {
  1259. +                    o(O2(0x85, 0xc0 + r * 9)); /* test r, r */
  1260. +                } else if (opc == 4) {
  1261. +                    ind = i; /* replace the load */
  1262. +                    o(O2(0x33, 0xc0 + r * 9)); /* xor r, r */
  1263.                  }
  1264. +            } else if (opc == 4 && (c == 0xff || c == 0xffff)) {
  1265. +                o(O3(0x0f, c == 0xff ? 0xb6 : 0xb7, 0xc0 + r * 9)); /* movzx */
  1266. +            } else if (opc == 1 && c == -1) {
  1267. +                ind = i;
  1268. +                o(O3(0x83, 0xc8 + r, -1)); /* or $-1, r */
  1269.              } else {
  1270. -                o(0x81);
  1271. -                oad(0xc0 | (opc << 3) | r, c);
  1272. +                if (opc == 0 && (tcc_state->optimize & OPT_REGS)) {
  1273. +                    if (o_v[r].indc <= 0) {
  1274. +                        o_v[r].indc = ind;
  1275. +                        o_v[r].c += c;
  1276. +                        o_v[r].v = rv_cache[r];
  1277. +                        add_len = 1;
  1278. +                    } else if (o_v[r].indc + o_v[r].lenc == ind) {
  1279. +                        o_v[r].c += c;
  1280. +                        add_len = 1;
  1281. +                    } else {
  1282. +                        /* two non-consecutive adds - the first is an offset,
  1283. +                           the second invalidates the cache */
  1284. +                        o_v[r].v.ld.r = -1;
  1285. +                        o_v[r].v.st.r = -1;
  1286. +                    }
  1287. +                }
  1288. +                if (c == (char)c) {
  1289. +                    /* generate inc and dec for smaller code */
  1290. +                    if ((c==1 && opc==0) || (c==-1 && opc==5)) {
  1291. +                        o(0x40 | r); // inc
  1292. +                    } else if ((c==1 && opc==5) || (c==-1 && opc==0)) {
  1293. +                        o(0x48 | r); // dec
  1294. +                    } else {
  1295. +                        o(O3(0x83, 0xc0 + r + opc * 8, c));
  1296. +                    }
  1297. +                } else {
  1298. +                    if (r == TREG_EAX)
  1299. +                        opc = 0x05 + opc * 8;
  1300. +                    else
  1301. +                        opc = O2(0x81, 0xc0 + r + opc * 8);
  1302. +                    oad(opc, c);
  1303. +                }
  1304.              }
  1305.          } else {
  1306.              gv2(RC_INT, RC_INT);
  1307.              r = vtop[-1].r;
  1308.              fr = vtop[0].r;
  1309. -            o((opc << 3) | 0x01);
  1310. -            o(0xc0 + r + fr * 8);
  1311. +            if (opc == 0 && (tcc_state->optimize & OPT_REGS)) {
  1312. +                if (o_v[r].indr <= 0) {
  1313. +                    o_v[r].indr = ind;
  1314. +                    o_v[r].r = fr;
  1315. +                    o_v[r].v = rv_cache[r];
  1316. +                } else {
  1317. +                    o_v[r].v.ld.r = -1;
  1318. +                    o_v[r].v.st.r = -1;
  1319. +                }
  1320. +            }
  1321. +            o(O2(0x01 + opc * 8, 0xc0 + r + fr * 8));
  1322.          }
  1323.          vtop--;
  1324.          if (op >= TOK_ULT && op <= TOK_GT) {
  1325.              vtop->r = VT_CMP;
  1326.              vtop->c.i = op;
  1327. +        } else if (tcc_state->optimize & OPT_REGS) {
  1328. +            if (add_len)
  1329. +                o_v[r].lenc = ind - o_v[r].indc;
  1330. +            clear_reg(r);
  1331.          }
  1332. +        cache_ind = ind;
  1333.          break;
  1334.      case '-':
  1335.      case TOK_SUBC1: /* sub with carry generation */
  1336. @@ -740,12 +1490,83 @@ ST_FUNC void gen_opi(int op)
  1337.          opc = 1;
  1338.          goto gen_op8;
  1339.      case '*':
  1340. -        gv2(RC_INT, RC_INT);
  1341. -        r = vtop[-1].r;
  1342. -        fr = vtop[0].r;
  1343. +        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  1344. +            int i = ind;
  1345. +            vswap();
  1346. +            r = gv(RC_INT);
  1347. +            vswap();
  1348. +            c = vtop->c.i;
  1349. +            if (c == 0) {
  1350. +                ind = i;               /* replace the load */
  1351. +                o(O2(0x33, 0xc0 + r)); /* xor r, r */
  1352. +            } else if (c == 1) {
  1353. +                /* nothing to do */
  1354. +            } else if (c == -1) {
  1355. +                o(O2(0xf7, 0xd8 + r)); /* neg r */
  1356. +            } else if ((c & (c - 1)) == 0) {
  1357. +                int n = 1;
  1358. +                while ((c >>= 1))
  1359. +                    ++n;
  1360. +                o(O3(0xc1, 0xe0 + r, n)); /* shl $xxx, r */
  1361. +            } else if (c > 0 && (tcc_state->optimize & OPT_MULTS)) {
  1362. +                int msb;
  1363. +                opc = 0;
  1364. +                msb = c & (c - 1);
  1365. +                if ((msb & (msb - 1)) == 0) {
  1366. +                    if (c == (msb | (msb >> 1)))       /* 3 * 2**N */
  1367. +                        opc = 0x40;
  1368. +                    else if (c == (msb | (msb >> 2)))  /* 5 * 2**N */
  1369. +                        opc = 0x80;
  1370. +                    else if (c == (msb | (msb >> 3)))  /* 9 * 2**N */
  1371. +                        opc = 0xc0;
  1372. +                }
  1373. +                fr = 0;
  1374. +                if (opc) {
  1375. +                    while (!(c & 1)) {
  1376. +                        ++fr;
  1377. +                        c >>= 1;
  1378. +                    }
  1379. +                    o(O3(0x8d, 0x04 + r * 8, opc + r * 9)); /* lea r, [r*N+r] */
  1380. +                    cache_ind = ind;
  1381. +                    if (fr == 1)
  1382. +                        o(O2(0x03, 0xc0 + r * 9)); /* add r, r */
  1383. +                    else if (fr != 0)
  1384. +                        o(O3(0xc1, 0xe0 + r, fr)); /* shl r, fr */
  1385. +                } else {
  1386. +                    switch(c) {
  1387. +                    case 25: fr += 0x40; /* r*4+r */
  1388. +                    case 15: fr += 0x40; /* r*2+r */
  1389. +                        opc = 0x80;      /* * r*4+r */
  1390. +                        break;
  1391. +                    case 81: fr += 0x40; /* r*8+r */
  1392. +                    case 45: fr += 0x40; /* r*4+r */
  1393. +                    case 27: fr += 0x40; /* r*2+r */
  1394. +                        opc = 0xc0;      /* * r*8+r */
  1395. +                        break;
  1396. +                    default:
  1397. +                        goto no_lea;
  1398. +                    }
  1399. +                    o(O3(0x8d, 0x04 + r * 8, opc + r * 9)); cache_ind = ind;
  1400. +                    o(O3(0x8d, 0x04 + r * 8, fr + r * 9));
  1401. +                }
  1402. +            } else {
  1403. +            no_lea:
  1404. +                if (c == (char)c)
  1405. +                    o(O3(0x6b, 0xc0 + r * 9, c)); /* imul $xxx, r */
  1406. +                else
  1407. +                    oad(O2(0x69, 0xc0 + r * 9), c);
  1408. +            }
  1409. +        } else {
  1410. +            gv2(RC_INT, RC_INT);
  1411. +            r = vtop[-1].r;
  1412. +            fr = vtop[0].r;
  1413. +            o(O3(0x0f, 0xaf, 0xc0 + fr + r * 8)); /* imul fr, r */
  1414. +        }
  1415.          vtop--;
  1416. -        o(0xaf0f); /* imul fr, r */
  1417. -        o(0xc0 + fr + r * 8);
  1418. +        if (tcc_state->optimize & OPT_REGS) {
  1419. +            cache_ind = ind;
  1420. +            clear_reg(r);
  1421. +        }
  1422.          break;
  1423.      case TOK_SHL:
  1424.          opc = 4;
  1425. @@ -763,43 +1584,104 @@ ST_FUNC void gen_opi(int op)
  1426.              r = gv(RC_INT);
  1427.              vswap();
  1428.              c = vtop->c.i & 0x1f;
  1429. -            o(0xc1); /* shl/shr/sar $xxx, r */
  1430. -            o(opc | r);
  1431. -            g(c);
  1432. +            if (op == TOK_SAR && ind == shl_ind + 3 && c == shl_val) {
  1433. +                ind = shl_ind;
  1434. +                o(O3(0x0f, c == 24 ? 0xbe : 0xbf, 0xc0 + r * 9)); /* movsx */
  1435. +            } else {
  1436. +                if (op == TOK_SHL && (c == 24 || c == 16)) {
  1437. +                    shl_ind = ind;
  1438. +                    shl_val = c;
  1439. +                }
  1440. +                o(O3(0xc1, opc | r, c)); /* shl/shr/sar $xxx, r */
  1441. +            }
  1442.          } else {
  1443.              /* we generate the shift in ecx */
  1444.              gv2(RC_INT, RC_ECX);
  1445.              r = vtop[-1].r;
  1446. -            o(0xd3); /* shl/shr/sar %cl, r */
  1447. -            o(opc | r);
  1448. +            o(O2(0xd3, opc | r)); /* shl/shr/sar %cl, r */
  1449.          }
  1450.          vtop--;
  1451. +        if (tcc_state->optimize & OPT_REGS) {
  1452. +            cache_ind = ind;
  1453. +            clear_reg(r);
  1454. +        }
  1455.          break;
  1456. +    case TOK_PDIV:
  1457. +        if (tcc_state->optimize & OPT_MULTS)
  1458. +        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST &&
  1459. +            vtop->c.i > 0) {
  1460. +            /* calculate suitable reciprocal, from Hacker's Delight */
  1461. +            int p;
  1462. +            unsigned ad, anc, delta, q1, r1, q2, r2;
  1463. +            const unsigned two31 = 0x80000000;    // 2**31.
  1464. +
  1465. +            ad = vtop->c.ui;
  1466. +            if ((ad & (ad - 1)) == 0) {
  1467. +                p = 1;
  1468. +                while ((ad >>= 1))
  1469. +                    p++;
  1470. +                vtop->c.i = p;
  1471. +                opc = 7;
  1472. +                goto gen_shift;
  1473. +            }
  1474. +            anc = two31 - 1 - two31 % ad;
  1475. +            p = 31;
  1476. +            q1 = two31 / anc;
  1477. +            r1 = two31 - q1 * anc;
  1478. +            q2 = two31 / ad;
  1479. +            r2 = two31 - q2 * ad;
  1480. +            do {
  1481. +               ++p;
  1482. +               q1 <<= 1;
  1483. +               r1 <<= 1;
  1484. +               if (r1 >= anc) {
  1485. +                  ++q1;
  1486. +                  r1 -= anc;
  1487. +               }
  1488. +               q2 <<= 1;
  1489. +               r2 <<= 1;
  1490. +               if (r2 >= ad) {
  1491. +                  ++q2;
  1492. +                  r2 -= ad;
  1493. +               }
  1494. +               delta = ad - r2;
  1495. +            } while (q1 < delta || (q1 == delta && r1 == 0));
  1496. +            vtop->c.ui = q2 + 1;
  1497. +            p -= 32;
  1498. +            gv2(RC_EAX, RC_EDX);
  1499. +            vtop--;
  1500. +            /* since the dividend should be a multiple of the divisor, and to
  1501. +               avoid testing for negative, add one beforehand */
  1502. +            o(0x40); /* inc eax */
  1503. +            o(0xeaf7); /* imul edx */
  1504. +            if (p != 0)
  1505. +                o(O3(0xc1, 0xfa, p)); /* sar $xxx, r */
  1506. +            vtop->r = TREG_EDX;
  1507. +            break;
  1508. +        }
  1509.      case '/':
  1510.      case TOK_UDIV:
  1511. -    case TOK_PDIV:
  1512.      case '%':
  1513.      case TOK_UMOD:
  1514.      case TOK_UMULL:
  1515.          /* first operand must be in eax */
  1516.          /* XXX: need better constraint for second operand */
  1517. -        gv2(RC_EAX, RC_ECX);
  1518. +        gv2(RC_EAX, RC_ECX | RC_EBX);
  1519.          r = vtop[-1].r;
  1520.          fr = vtop[0].r;
  1521.          vtop--;
  1522.          save_reg(TREG_EDX);
  1523.          if (op == TOK_UMULL) {
  1524. -            o(0xf7); /* mul fr */
  1525. -            o(0xe0 + fr);
  1526. +            o(O2(0xf7, 0xe0 + fr)); /* mul fr */
  1527.              vtop->r2 = TREG_EDX;
  1528.              r = TREG_EAX;
  1529.          } else {
  1530.              if (op == TOK_UDIV || op == TOK_UMOD) {
  1531. -                o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
  1532. -                o(0xf0 + fr);
  1533. +                o(0xd231); /* xor %edx, %edx */
  1534. +                o(O2(0xf7, 0xf0 + fr)); /* div fr, %eax */
  1535.              } else {
  1536. -                o(0xf799); /* cltd, idiv fr, %eax */
  1537. -                o(0xf8 + fr);
  1538. +                o(0x99); /* cltd */
  1539. +                o(O2(0xf7, 0xf8 + fr)); /* idiv fr, %eax */
  1540.              }
  1541.              if (op == '%' || op == TOK_UMOD)
  1542.                  r = TREG_EDX;
  1543. @@ -809,6 +1691,12 @@ ST_FUNC void gen_opi(int op)
  1544.          vtop->r = r;
  1545.          break;
  1546.      default:
  1547. +        if ((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
  1548. +            /* turn something like (1 <= argc) into (argc >= 1) */
  1549. +            vswap();
  1550. +            if (op != TOK_EQ && op != TOK_NE)
  1551. +                op ^= (op & 8) ? 3 : 5;
  1552. +        }
  1553.          opc = 7;
  1554.          goto gen_op8;
  1555.      }
  1556. @@ -857,12 +1745,11 @@ ST_FUNC void gen_opf(int op)
  1557.          o(0xe9da); /* fucompp */
  1558.          o(0xe0df); /* fnstsw %ax */
  1559.          if (op == TOK_EQ) {
  1560. -            o(0x45e480); /* and $0x45, %ah */
  1561. -            o(0x40fC80); /* cmp $0x40, %ah */
  1562. +            o(0x44e480); /* and $0x44, %ah */
  1563. +            op = 0x9b;   /* parity odd - 1 bit set is equal */
  1564.          } else if (op == TOK_NE) {
  1565. -            o(0x45e480); /* and $0x45, %ah */
  1566. -            o(0x40f480); /* xor $0x40, %ah */
  1567. -            op = TOK_NE;
  1568. +            o(0x44e480); /* and $0x44, %ah */
  1569. +            op = 0x9a;   /* parity even - no bits is !equal, two is bad */
  1570.          } else if (op == TOK_GE || op == TOK_LE) {
  1571.              o(0x05c4f6); /* test $0x05, %ah */
  1572.              op = TOK_EQ;
  1573. @@ -902,8 +1789,7 @@ ST_FUNC void gen_opf(int op)
  1574.          ft = vtop->type.t;
  1575.          fc = vtop->c.ul;
  1576.          if ((ft & VT_BTYPE) == VT_LDOUBLE) {
  1577. -            o(0xde); /* fxxxp %st, %st(1) */
  1578. -            o(0xc1 + (a << 3));
  1579. +            o(O2(0xde, 0xc1 + (a << 3))); /* fxxxp %st, %st(1) */
  1580.          } else {
  1581.              /* if saved lvalue, then we must reload it */
  1582.              r = vtop->r;
  1583. @@ -918,10 +1804,10 @@ ST_FUNC void gen_opf(int op)
  1584.              }
  1585.  
  1586.              if ((ft & VT_BTYPE) == VT_DOUBLE)
  1587. -                o(0xdc);
  1588. +                op = 0xdc;
  1589.              else
  1590. -                o(0xd8);
  1591. -            gen_modrm(a, r, vtop->sym, fc);
  1592. +                op = 0xd8;
  1593. +            gen_modrm(op, a, r, vtop->sym, fc);
  1594.          }
  1595.          vtop--;
  1596.      }
  1597. @@ -943,8 +1829,7 @@ ST_FUNC void gen_cvt_itof(int t)
  1598.      } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
  1599.                 (VT_INT | VT_UNSIGNED)) {
  1600.          /* unsigned int to float/double/long double */
  1601. -        o(0x6a); /* push $0 */
  1602. -        g(0x00);
  1603. +        og(0x6a, 0x00); /* push $0 */
  1604.          o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
  1605.          o(0x242cdf); /* fildll (%esp) */
  1606.          o(0x08c483); /* add $8, %esp */
  1607. @@ -981,12 +1866,11 @@ ST_FUNC void gen_cvt_ftoi(int t)
  1608.             ind, R_386_32);
  1609.      gen_le32(0);
  1610.      
  1611. -    oad(0xec81, size); /* sub $xxx, %esp */
  1612. +    gadd_sp(-size);
  1613.      if (size == 4)
  1614. -        o(0x1cdb); /* fistpl */
  1615. +        o(0x241cdb); /* fistpl */
  1616.      else
  1617. -        o(0x3cdf); /* fistpll */
  1618. -    o(0x24);
  1619. +        o(0x243cdf); /* fistpll */
  1620.      o(0x2dd9); /* ldcw xxx */
  1621.      sym = external_global_sym(TOK___tcc_fpu_control,
  1622.                                &ushort_type, VT_LVAL);
  1623. @@ -1038,6 +1922,8 @@ ST_FUNC void gen_bounded_ptr_add(void)
  1624.      save_regs(0);
  1625.      /* do a fast function call */
  1626.      sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
  1627. +    if (q_state > Q_READY)
  1628. +        flushq();
  1629.      greloc(cur_text_section, sym,
  1630.             ind + 1, R_386_PC32);
  1631.      oad(0xe8, -4);
  1632. @@ -1090,6 +1976,417 @@ ST_FUNC void gen_bounded_ptr_deref(void)
  1633.  }
  1634.  #endif
  1635.  
  1636. +/* jump optimiser */
  1637. +
  1638. +/* 's' bytes have been removed at 't', adjust relocs to suit */
  1639. +static void adjust_reloc(int t, int s)
  1640. +{
  1641. +    if (cur_text_section->reloc) {
  1642. +        ElfW_Rel *end = (ElfW_Rel*)(cur_text_section->reloc->data
  1643. +                                    + cur_text_section->reloc->data_offset);
  1644. +        ElfW_Rel *rel = (ElfW_Rel*)(cur_text_section->reloc->data
  1645. +                                    + prolog_reloc_offset);
  1646. +        for (; rel != end; ++rel) {
  1647. +            if (rel->r_offset >= t)
  1648. +                rel->r_offset -= s;
  1649. +        }
  1650. +    }
  1651. +}
  1652. +
  1653. +/* 's' bytes have been removed at 't', adjust jumps to suit */
  1654. +static void adjust_jmp(int t, int s)
  1655. +{
  1656. +    int **j, f, n, a, r;
  1657. +
  1658. +    for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  1659. +        f = **j;
  1660. +        if (f == 0 || f == t - 1)
  1661. +            continue;
  1662. +        if (f < 0) {
  1663. +            if (-f > t)
  1664. +                **j += s;
  1665. +            continue;
  1666. +        }
  1667. +        r = cur_text_section->data[f-1];
  1668. +        r = (r == 0xeb || r < 0x80);
  1669. +        if (r)
  1670. +            a = f + (char)cur_text_section->data[f] + 1;
  1671. +        else
  1672. +            a = f + *(int *)(cur_text_section->data + f) + 4;
  1673. +        if (f < t) {
  1674. +            if (a >= t) {
  1675. +                if (r)
  1676. +                    cur_text_section->data[f] -= s;
  1677. +                else
  1678. +                    *(int *)(cur_text_section->data + f) -= s;
  1679. +            }
  1680. +        } else {
  1681. +            if (a < t) {
  1682. +                if (r)
  1683. +                    cur_text_section->data[f] += s;
  1684. +                else
  1685. +                    *(int *)(cur_text_section->data + f) += s;
  1686. +            }
  1687. +            **j -= s;
  1688. +        }
  1689. +    }
  1690. +    adjust_reloc(t, s);
  1691. +}
  1692. +
  1693. +/* change jumps made to code between 't' and 'e' to jumps starting at 'o' */
  1694. +static void adjust_jump_dest(int t, int e, int o)
  1695. +{
  1696. +    int **j, f, n, a;
  1697. +
  1698. +    for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  1699. +        f = **j;
  1700. +        if (f <= 0)
  1701. +            continue;
  1702. +        if (f >= t && f < e) {
  1703. +            **j = 0;
  1704. +            continue;
  1705. +        }
  1706. +        a = f + *(int *)(cur_text_section->data + f) + 4;
  1707. +        if (a >= t && a < e)
  1708. +            *(int *)(cur_text_section->data + f) = o + (a - t) - f - 4;
  1709. +    }
  1710. +}
  1711. +
  1712. +static void remove_code(int t, int s)
  1713. +{
  1714. +    if (cur_text_section->reloc) {
  1715. +        ElfW_Rel *end = (ElfW_Rel*)(cur_text_section->reloc->data
  1716. +                                    + cur_text_section->reloc->data_offset);
  1717. +        ElfW_Rel *rel = (ElfW_Rel*)(cur_text_section->reloc->data
  1718. +                                    + prolog_reloc_offset);
  1719. +        for (; rel != end; ++rel) {
  1720. +            if (rel->r_offset >= t && rel->r_offset < t + s) {
  1721. +                cur_text_section->reloc->data_offset -= sizeof(ElfW_Rel);
  1722. +                --end;
  1723. +                memcpy(rel, rel + 1, (end - rel) * sizeof(ElfW_Rel));
  1724. +                --rel;
  1725. +            }
  1726. +        }
  1727. +    }
  1728. +    adjust_jmp(t, s);
  1729. +    memcpy(cur_text_section->data + t, cur_text_section->data + t + s,
  1730. +           ind - (t + s));
  1731. +    epilog_ind -= s;
  1732. +    ins_ind -= s;
  1733. +    ind -= s;
  1734. +    memset(cur_text_section->data + ind, 0, s);
  1735. +}
  1736. +
  1737. +static void remove_jmp(int t)
  1738. +{
  1739. +    int s = cur_text_section->data[t-1] == 0xe9 ? 1 : 2;
  1740. +    remove_code(t - s, s + 4);
  1741. +}
  1742. +
  1743. +/* replace a jmp to the epilog with the epilog */
  1744. +static void epilog_jmp(int t)
  1745. +{
  1746. +    int s, e;
  1747. +
  1748. +    s = cur_text_section->data[t-1] == 0xe9 ? 1 : 2;
  1749. +    t -= s;
  1750. +    e = ind - epilog_ind;
  1751. +    memcpy(cur_text_section->data + t, cur_text_section->data + epilog_ind, e);
  1752. +    remove_code(t + e, s + 4 - e);
  1753. +}
  1754. +
  1755. +static void short_jmp(int *j)
  1756. +{
  1757. +    int t, s;
  1758. +
  1759. +    t = *j;
  1760. +    if (cur_text_section->data[t-1] == 0xe9) { /* jmp near */
  1761. +        cur_text_section->data[t-1] = 0xeb; /* jmp short */
  1762. +        ++t;
  1763. +        s = 3;
  1764. +    } else {
  1765. +        /* convert jcc near (0x8X0F) to short (0x7X) */
  1766. +        cur_text_section->data[t-2] = cur_text_section->data[t-1] - 0x10;
  1767. +        cur_text_section->data[t-1] = cur_text_section->data[t];
  1768. +        --*j;
  1769. +        s = 4;
  1770. +    }
  1771. +    if ((char)cur_text_section->data[*j] < 0)
  1772. +        cur_text_section->data[*j] += s;
  1773. +    remove_code(t, s);
  1774. +}
  1775. +
  1776. +/* optimise jumps */
  1777. +static void jmpopt(void)
  1778. +{
  1779. +    int **j, t, n, o, s, opt;
  1780. +    int le, lj, opc;
  1781. +    int **j1, n1, t1;
  1782. +    ElfW_Rel *rel_t, *rel_o, *end;
  1783. +
  1784. +    /* replace jumps to jmp with the destination of the jmp */
  1785. +    for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  1786. +        t = **j;
  1787. +        if (t < 0)
  1788. +            continue;
  1789. +        o = t + *(int *)(cur_text_section->data + t) + 4;
  1790. +        opt = o;
  1791. +        while (cur_text_section->data[o] == 0xe9)
  1792. +            o += *(int *)(cur_text_section->data + o + 1) + 5;
  1793. +        if (o != opt)
  1794. +            *(int *)(cur_text_section->data + t) = o - t - 4;
  1795. +    }
  1796. +
  1797. +    /* test if the code (up to eight instructions) before a jmp matches the
  1798. +       code before its destination; if so, remove the code before the jmp, jump
  1799. +       to the earlier dest. */
  1800. +    for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  1801. +        int jmp = 0;
  1802. +        t = **j;
  1803. +        if (t < 0) {
  1804. +            /* skip the jump of a boolean cast */
  1805. +            ++j;
  1806. +            --n;
  1807. +            continue;
  1808. +        }
  1809. +        if (cur_text_section->data[t-1] != 0xe9 ||
  1810. +            (cur_text_section->data[t+3] & 0x80)) /* must be forward */
  1811. +            continue;
  1812. +        o = t + *(int *)(cur_text_section->data + t) + 4;
  1813. +        if (o == epilog_ind)
  1814. +            continue;
  1815. +        /* ignore an empty jmp before the dest, since they haven't been
  1816. +           removed yet (so instruction lengths are consistent) */
  1817. +        if (cur_text_section->data[o-5] == 0xe9 &&
  1818. +            *(int *)(cur_text_section->data + o - 4) == 0) {
  1819. +            o -= 5;
  1820. +            jmp = 5;
  1821. +        }
  1822. +        --t;
  1823. +        le = 0;
  1824. +        s = (*j)[1];
  1825. +        lj = 0;
  1826. +        if (cur_text_section->reloc) {
  1827. +            end = (ElfW_Rel*)(cur_text_section->reloc->data
  1828. +                              + prolog_reloc_offset);
  1829. +            rel_o = (ElfW_Rel*)(cur_text_section->reloc->data
  1830. +                                + cur_text_section->reloc->data_offset);
  1831. +            while (--rel_o >= end && rel_o->r_offset > o)
  1832. +                ;
  1833. +            rel_t = rel_o;
  1834. +            while (rel_t >= end && rel_t->r_offset > t)
  1835. +                --rel_t;
  1836. +        } else {
  1837. +            end = rel_o = rel_t = NULL;
  1838. +        }
  1839. +        while (o > **j && s) {
  1840. +            lj = s & 15;
  1841. +            t -= lj;
  1842. +            o -= lj;
  1843. +            opc = cur_text_section->data[t];
  1844. +            /* check the destination of a relative call/jmp */
  1845. +            if (opc == 0xe8 || opc == 0xe9) {
  1846. +                int d1 = t + *(int *)(cur_text_section->data + t + 1) + 5;
  1847. +                int d2 = o + *(int *)(cur_text_section->data + o + 1) + 5;
  1848. +                if (d1 != d2)
  1849. +                    break;
  1850. +            }
  1851. +            /* stop before a jump */
  1852. +            if ((opc == 0x0f && (cur_text_section->data[t+1] & 0xf0) == 0x80) ||
  1853. +                opc == 0xeb) {
  1854. +                break;
  1855. +            }
  1856. +            if (memcmp(cur_text_section->data + t,
  1857. +                       cur_text_section->data + o, lj)) {
  1858. +                break;
  1859. +            }
  1860. +            /* check relocations match */
  1861. +            if (end) {
  1862. +                while (rel_t >= end && rel_t->r_offset >= t + lj) {
  1863. +                    --rel_o;
  1864. +                    --rel_t;
  1865. +                }
  1866. +                while (rel_t >= end && rel_t->r_offset > t) {
  1867. +                    if (rel_t->r_info != rel_o->r_info)
  1868. +                        goto ins_match_end;
  1869. +                    --rel_o;
  1870. +                    --rel_t;
  1871. +                }
  1872. +            }
  1873. +            le += lj;
  1874. +            lj = 0;
  1875. +            s = (unsigned)s >> 4;
  1876. +        }
  1877. +        ins_match_end:
  1878. +        if (le) {
  1879. +            t += lj;
  1880. +            o += lj;
  1881. +            adjust_jump_dest(t, t + le, o);
  1882. +            *(int *)(cur_text_section->data + t + le + 1) -= le + jmp;
  1883. +            remove_code(t, le);
  1884. +        }
  1885. +    }
  1886. +
  1887. +    /* replace jcc/jmp pairs with jncc and remove unreferenced jmps */
  1888. +    for (j = jmplst + nb_jmplst - 1, n = nb_jmplst; n > 1; --j, --n) {
  1889. +        t = **j;
  1890. +        if (*j[-1] + 5 == t) {
  1891. +            if (cur_text_section->data[t-6] != 0xe9) {
  1892. +                if (*(int *)(cur_text_section->data + t - 5) != 5)
  1893. +                    continue;
  1894. +                o = *(int *)(cur_text_section->data + t);
  1895. +                if (o != 0) {
  1896. +                    o += t + 4;
  1897. +                    cur_text_section->data[t-6] ^= 1;
  1898. +                    *(int *)(cur_text_section->data + t - 5) = o - (t - 5) - 4;
  1899. +                }
  1900. +            }
  1901. +            **j = 0;
  1902. +            remove_jmp(t);
  1903. +        }
  1904. +    }
  1905. +
  1906. +    /* check if all conditional jumps to a boolean are the same type
  1907. +       (quite complicated just to efficiently set 0 or 1, and it's still not
  1908. +       as good as it could be, since test already knows if it's 0) */
  1909. +    for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  1910. +        int tst = 1;
  1911. +        t = **j;
  1912. +        if (t >= 0)
  1913. +            continue;
  1914. +        t = -t;
  1915. +        t1 = t - ((*j)[1] ? 7 : 4);
  1916. +        opc = 0;
  1917. +        for (j1 = jmplst, n1 = nb_jmplst; n1 > 0; ++j1, --n1) {
  1918. +            int op1, op2;
  1919. +            o = **j1;
  1920. +            if (o <= 0)
  1921. +                continue;
  1922. +            s = cur_text_section->data[o-1];
  1923. +            op1 = cur_text_section->data[o-4];
  1924. +            op2 = cur_text_section->data[o-3];
  1925. +            o += *(int *)(cur_text_section->data + o) + 4;
  1926. +            if (o == t1) {
  1927. +                s ^= 1;
  1928. +                o = t;
  1929. +            }
  1930. +            if (o == t) {
  1931. +                if (opc == 0)
  1932. +                    opc = s;
  1933. +                else if (s != opc) {
  1934. +                    opc = -1;
  1935. +                    if (!tst)
  1936. +                        break;
  1937. +                }
  1938. +                if ((*j1)[1] != 2 || op1 != 0x85 ||
  1939. +                    op2 < 0xc0 || (op2 - 0xc0) % 9) {
  1940. +                    tst = 0;
  1941. +                    if (opc == -1)
  1942. +                        break;
  1943. +                }
  1944. +            }
  1945. +        }
  1946. +        if (opc > 0) {
  1947. +            int r;
  1948. +            o = (*j)[1] & 1;
  1949. +            s = o ? 7 : 4;
  1950. +            adjust_jump_dest(t, t + 1, t - s);
  1951. +            t -= s;
  1952. +            r = (*j)[1] >> 1;
  1953. +            cur_text_section->data[t++] = 0x0f; /* setcc %br */
  1954. +            cur_text_section->data[t++] = (opc + 16) ^ o;
  1955. +            cur_text_section->data[t++] = 0xc0 + r;
  1956. +            cur_text_section->data[t++] = 0x0f; /* movzx %br, %r */
  1957. +            cur_text_section->data[t++] = 0xb6;
  1958. +            cur_text_section->data[t++] = 0xc0 + r * 9;
  1959. +            remove_code(t, 3);
  1960. +        } else if (tst) {
  1961. +            int r = cur_text_section->data[t];
  1962. +            if (r == 0x33) {
  1963. +                r = cur_text_section->data[t+1] & 7;
  1964. +                adjust_jump_dest(t, t + 1, t - 7);
  1965. +                t -= 7;
  1966. +                cur_text_section->data[t-4] = 1; /* jump over stc */
  1967. +                cur_text_section->data[t-5] ^= 1; /* invert condition */
  1968. +            } else {
  1969. +                r &= 7;
  1970. +                adjust_jump_dest(t, t + 1, t - 3);
  1971. +                t -= 4;
  1972. +            }
  1973. +            cur_text_section->data[t++] = 0xf9; /* stc */
  1974. +            cur_text_section->data[t++] = 0x1b; /* sbb %r, %r */
  1975. +            cur_text_section->data[t++] = 0xc0 + r * 9;
  1976. +            cur_text_section->data[t++] = 0x40 + r; /* inc %r */
  1977. +            remove_code(t, 5);
  1978. +        }
  1979. +        **j = 0;
  1980. +    }
  1981. +
  1982. +    /* remove empty jumps */
  1983. +    for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  1984. +        t = **j;
  1985. +        if (t <= 0)
  1986. +            continue;
  1987. +        o = *(int *)(cur_text_section->data + t);
  1988. +        if (o == 0) {
  1989. +            **j = 0;
  1990. +            remove_jmp(t);
  1991. +        }
  1992. +    }
  1993. +
  1994. +#ifdef CONFIG_TCC_BCHECK
  1995. +    if (!tcc_state->do_bounds_check)
  1996. +#endif
  1997. +    if (ind - epilog_ind <= 5 ||
  1998. +        ((tcc_state->optimize & OPT_SIZE) && ind - epilog_ind <= 2)) {
  1999. +        /* inline jmps to the epilog */
  2000. +        le = 0; /* last epilog */
  2001. +        lj = 0; /* last jcc - may be able to shorten it */
  2002. +        for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  2003. +            t = **j;
  2004. +            if (t <= 0)
  2005. +                continue;
  2006. +            o = t + *(int *)(cur_text_section->data + t) + 4;
  2007. +            if (o == epilog_ind) {
  2008. +                if (cur_text_section->data[t-1] == 0xe9) {
  2009. +                    **j = 0;
  2010. +                    epilog_jmp(t);
  2011. +                    le = t - 1;
  2012. +                    if (lj) {
  2013. +                        *(int *)(cur_text_section->data + lj) = le - lj - 4;
  2014. +                        lj = 0;
  2015. +                    }
  2016. +                } else {
  2017. +                    if (le)
  2018. +                        *(int *)(cur_text_section->data + t) = le - t - 4;
  2019. +                    else
  2020. +                        lj = t;
  2021. +                }
  2022. +            }
  2023. +        }
  2024. +    }
  2025. +
  2026. +    /* convert appropriate near jumps to short */
  2027. +    do {
  2028. +        opt = 0;
  2029. +        for (j = jmplst, n = nb_jmplst; n > 0; ++j, --n) {
  2030. +            t = **j;
  2031. +            if (t <= 0)
  2032. +                continue;
  2033. +            /* no need to test opcode, since 000000 needs to follow, which
  2034. +               translates to add [eax],al and something similar, so the char
  2035. +               test should be sufficient */
  2036. +            o = *(int *)(cur_text_section->data + t);
  2037. +            if (o == (char)o) {
  2038. +                short_jmp(*j);
  2039. +                opt = 1;
  2040. +            }
  2041. +        }
  2042. +    } while (opt);
  2043. +
  2044. +    dynarray_reset(&jmplst, &nb_jmplst);
  2045. +}
  2046. +
  2047.  /* end of X86 code generator */
  2048.  /*************************************************************/
  2049.  #endif
  2050. diff -pruN tcc-0.9.26/libtcc.c tcc-0.9.26o/libtcc.c
  2051. --- tcc-0.9.26/libtcc.c 2013-02-16 00:24:00 +1000
  2052. +++ tcc-0.9.26o/libtcc.c    2013-09-24 15:53:36 +1000
  2053. @@ -999,6 +999,10 @@ LIBTCCAPI TCCState *tcc_new(void)
  2054.      data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
  2055.      bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
  2056.  
  2057. +#if defined TCC_TARGET_PE && defined TCC_TARGET_I386
  2058. +    text_section->sh_addralign = 16;
  2059. +#endif
  2060. +
  2061.      /* symbols are always generated for linking stage */
  2062.      symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
  2063.                                  ".strtab",
  2064. @@ -1876,6 +1880,41 @@ PUB_FUNC int tcc_parse_args(TCCState *s,
  2065.              printf ("%s\n", TCC_VERSION);
  2066.              exit(0);
  2067.          case TCC_OPTION_O:
  2068. +#ifdef TCC_TARGET_I386
  2069. +            if (*optarg == '\0')
  2070. +                s->optimize = -1;
  2071. +            else
  2072. +            do {
  2073. +                switch(*optarg++) {
  2074. +                case '0':
  2075. +                    s->optimize = 0;
  2076. +                    break;
  2077. +                case '1':
  2078. +                    s->optimize |= OPT_PROLOG | OPT_REGS | OPT_MULTS;
  2079. +                    break;
  2080. +                case '2':
  2081. +                case 'x':
  2082. +                    s->optimize = -1;
  2083. +                    break;
  2084. +                case 's':
  2085. +                    s->optimize |= OPT_PROLOG | OPT_REGS | OPT_JUMPS | OPT_SIZE;
  2086. +                    break;
  2087. +                case 'f':
  2088. +                    s->optimize |= OPT_PROLOG;
  2089. +                    break;
  2090. +                case 'j':
  2091. +                    s->optimize |= OPT_JUMPS;
  2092. +                    break;
  2093. +                case 'm':
  2094. +                    s->optimize |= OPT_MULTS;
  2095. +                    break;
  2096. +                case 'r':
  2097. +                    s->optimize |= OPT_REGS;
  2098. +                    break;
  2099. +                }
  2100. +            } while (*optarg);
  2101. +            break;
  2102. +#endif
  2103.          case TCC_OPTION_pedantic:
  2104.          case TCC_OPTION_pipe:
  2105.          case TCC_OPTION_s:
  2106. diff -pruN tcc-0.9.26/tcc.h tcc-0.9.26o/tcc.h
  2107. --- tcc-0.9.26/tcc.h    2013-02-16 00:24:00 +1000
  2108. +++ tcc-0.9.26o/tcc.h   2013-09-23 16:51:41 +1000
  2109. @@ -355,9 +355,9 @@ typedef struct Section {
  2110.      int nb_hashed_syms;      /* used to resize the hash table */
  2111.      struct Section *link;    /* link to another section */
  2112.      struct Section *reloc;   /* corresponding section for relocation, if any */
  2113. -    struct Section *hash;     /* hash table for symbols */
  2114. +    struct Section *hash;    /* hash table for symbols */
  2115.      struct Section *next;
  2116. -    char name[1];           /* section name */
  2117. +    char name[1];            /* section name */
  2118.  } Section;
  2119.  
  2120.  typedef struct DLLReference {
  2121. @@ -553,6 +553,7 @@ struct TCCState {
  2122.      
  2123.  #ifdef TCC_TARGET_I386
  2124.      int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
  2125. +    int optimize;
  2126.  #endif
  2127.  
  2128.      /* array of all loaded dlls (including those referenced by loaded dlls) */
  2129. @@ -787,7 +788,7 @@ struct TCCState {
  2130.  #define TOK_SHL   0x01 /* shift left */
  2131.  #define TOK_SAR   0x02 /* signed shift right */
  2132.    
  2133. -/* assignement operators : normal operator or 0x80 */
  2134. +/* assignment operators : normal operator or 0x80 */
  2135.  #define TOK_A_MOD 0xa5
  2136.  #define TOK_A_AND 0xa6
  2137.  #define TOK_A_MUL 0xaa
  2138. @@ -1141,6 +1142,9 @@ ST_DATA CType char_pointer_type, func_ol
  2139.  ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop;
  2140.  #define vstack  (__vstack + 1)
  2141.  ST_DATA int rsym, anon_sym, ind, loc;
  2142. +#ifdef TCC_TARGET_I386
  2143. +ST_DATA int cache_ind;
  2144. +#endif
  2145.  
  2146.  ST_DATA int const_wanted; /* true if constant wanted */
  2147.  ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
  2148. @@ -1279,12 +1283,17 @@ ST_FUNC void gen_cvt_itof(int t);
  2149.  
  2150.  /* ------------ i386-gen.c ------------ */
  2151.  #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
  2152. +/* make an int out of opcode bytes */
  2153. +#define O2(o1, o2)         ((unsigned char)(o1) | ((unsigned char)(o2) << 8))
  2154. +#define O3(o1, o2, o3)     (O2(o1, o2) | ((unsigned char)(o3) << 16))
  2155. +#define O4(o1, o2, o3, o4) (O3(o1, o2, o3) | ((unsigned char)(o4) << 24))
  2156.  ST_FUNC void g(int c);
  2157.  ST_FUNC int oad(int c, int s);
  2158.  ST_FUNC void gen_le16(int c);
  2159.  ST_FUNC void gen_le32(int c);
  2160.  ST_FUNC void gen_addr32(int r, Sym *sym, int c);
  2161.  ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
  2162. +ST_FUNC void flushq(void);
  2163.  #endif
  2164.  
  2165.  #ifdef CONFIG_TCC_BCHECK
  2166. diff -pruN tcc-0.9.26/tccgen.c tcc-0.9.26o/tccgen.c
  2167. --- tcc-0.9.26/tccgen.c 2013-02-16 00:24:00 +1000
  2168. +++ tcc-0.9.26o/tccgen.c    2013-09-25 19:24:46 +1000
  2169. @@ -29,6 +29,14 @@
  2170.     anon_sym: anonymous symbol index
  2171.  */
  2172.  ST_DATA int rsym, anon_sym, ind, loc;
  2173. +#ifdef TCC_TARGET_I386
  2174. +ST_DATA int cache_ind;
  2175. +#define SET_CACHE_IND   cache_ind = ind
  2176. +#define RESET_CACHE_IND do { flushq(); cache_ind = -1; } while (0)
  2177. +#else
  2178. +#define SET_CACHE_IND
  2179. +#define RESET_CACHE_IND
  2180. +#endif
  2181.  
  2182.  ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
  2183.  ST_DATA Section *cur_text_section; /* current section where function code is generated */
  2184. @@ -67,6 +75,10 @@ ST_DATA char *funcname;
  2185.  
  2186.  ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
  2187.  
  2188. +#if defined TCC_TARGET_PE && defined TCC_TARGET_I386
  2189. +ST_DATA SValue ret_st;
  2190. +#endif
  2191. +
  2192.  /* ------------------------------------------------------------------------- */
  2193.  static void gen_cast(CType *type);
  2194.  static inline CType *pointed_type(CType *type);
  2195. @@ -522,6 +534,7 @@ ST_FUNC void save_reg(int r)
  2196.                  /* x86 specific: need to pop fp register ST0 if saved */
  2197.                  if (r == TREG_ST0) {
  2198.                      o(0xd8dd); /* fstp %st(0) */
  2199. +                    SET_CACHE_IND;
  2200.                  }
  2201.  #endif
  2202.  #ifndef TCC_TARGET_X86_64
  2203. @@ -687,7 +700,7 @@ static void gbound(void)
  2204.     register value (such as structures). */
  2205.  ST_FUNC int gv(int rc)
  2206.  {
  2207. -    int r, bit_pos, bit_size, size, align, i;
  2208. +    int r, bit_pos, bit_size, size, align, i, bt;
  2209.  #ifndef TCC_TARGET_X86_64
  2210.      int rc2;
  2211.  #endif
  2212. @@ -765,10 +778,16 @@ ST_FUNC int gv(int rc)
  2213.  #endif
  2214.  
  2215.          r = vtop->r & VT_VALMASK;
  2216. +        bt = vtop->type.t & VT_BTYPE;
  2217.  #ifndef TCC_TARGET_X86_64
  2218.          rc2 = RC_INT;
  2219.          if (rc == RC_IRET)
  2220.              rc2 = RC_LRET;
  2221. +        if (VT_STRUCT == bt) {
  2222. +           int align;
  2223. +           if (type_size(&vtop->type, &align) == 8)
  2224. +               bt = VT_LLONG;
  2225. +        }
  2226.  #endif
  2227.          /* need to reload if:
  2228.             - constant
  2229. @@ -778,13 +797,13 @@ ST_FUNC int gv(int rc)
  2230.           || (vtop->r & VT_LVAL)
  2231.           || !(reg_classes[r] & rc)
  2232.  #ifndef TCC_TARGET_X86_64
  2233. -         || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2))
  2234. +         || (bt == VT_LLONG && !(reg_classes[vtop->r2] & rc2))
  2235.  #endif
  2236.              )
  2237.          {
  2238.              r = get_reg(rc);
  2239.  #ifndef TCC_TARGET_X86_64
  2240. -            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
  2241. +            if (bt == VT_LLONG) {
  2242.                  int r2;
  2243.                  unsigned long long ll;
  2244.                  /* two register type load : expand to two words
  2245. @@ -854,7 +873,7 @@ ST_FUNC int gv(int rc)
  2246.          vtop->r = r;
  2247.  #ifdef TCC_TARGET_C67
  2248.          /* uses register pairs for doubles */
  2249. -        if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
  2250. +        if (bt == VT_DOUBLE)
  2251.              vtop->r2 = r+1;
  2252.  #endif
  2253.      }
  2254. @@ -1012,6 +1031,7 @@ ST_FUNC void vpop(void)
  2255.      /* for x86, we need to pop the FP stack */
  2256.      if (v == TREG_ST0 && !nocode_wanted) {
  2257.          o(0xd8dd); /* fstp %st(0) */
  2258. +        SET_CACHE_IND;
  2259.      } else
  2260.  #endif
  2261.      if (v == VT_JMP || v == VT_JMPI) {
  2262. @@ -1180,7 +1200,7 @@ static void gen_opl(int op)
  2263.              c = (int)vtop->c.i;
  2264.              /* constant: simpler */
  2265.              /* NOTE: all comments are for SHL. the other cases are
  2266. -               done by swaping words */
  2267. +               done by swapping words */
  2268.              vpop();
  2269.              if (op != TOK_SHL)
  2270.                  vswap();
  2271. @@ -1596,7 +1616,7 @@ ST_FUNC void gen_op(int op)
  2272.          
  2273.      if (bt1 == VT_PTR || bt2 == VT_PTR) {
  2274.          /* at least one operand is a pointer */
  2275. -        /* relationnal op: must be both pointers */
  2276. +        /* relational op: must be both pointers */
  2277.          if (op >= TOK_ULT && op <= TOK_LOR) {
  2278.              check_comparison_pointer_types(vtop - 1, vtop, op);
  2279.              /* pointers are handled are unsigned */
  2280. @@ -1670,7 +1690,7 @@ ST_FUNC void gen_op(int op)
  2281.              {
  2282.                  gen_opic(op);
  2283.              }
  2284. -            /* put again type if gen_opic() swaped operands */
  2285. +            /* put again type if gen_opic() swapped operands */
  2286.              vtop->type = type1;
  2287.          }
  2288.      } else if (is_float(bt1) || is_float(bt2)) {
  2289. @@ -1742,7 +1762,7 @@ ST_FUNC void gen_op(int op)
  2290.          else
  2291.              gen_opic(op);
  2292.          if (op >= TOK_ULT && op <= TOK_GT) {
  2293. -            /* relationnal op: the result is an int */
  2294. +            /* relational op: the result is an int */
  2295.              vtop->type.t = VT_INT;
  2296.          } else {
  2297.              vtop->type.t = t;
  2298. @@ -1977,8 +1997,8 @@ static void gen_cast(CType *type)
  2299.                      int r = gv(RC_INT);
  2300.                      if (sbt != (VT_INT | VT_UNSIGNED)) {
  2301.                          /* x86_64 specific: movslq */
  2302. -                        o(0x6348);
  2303. -                        o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
  2304. +                        o(O3(0x48, 0x63,
  2305. +                             0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)));
  2306.                      }
  2307.                  }
  2308.  #endif
  2309. @@ -2385,6 +2405,13 @@ ST_FUNC void vstore(void)
  2310.          if (!nocode_wanted) {
  2311.              size = type_size(&vtop->type, &align);
  2312.  
  2313. +            if (size == 4)
  2314. +                goto small_struct;
  2315. +            if (size == 8) {
  2316. +                ft = VT_LLONG;
  2317. +                goto small_struct;
  2318. +            }
  2319. +
  2320.              /* destination */
  2321.              vswap();
  2322.              vtop->type.t = VT_PTR;
  2323. @@ -2470,6 +2497,7 @@ ST_FUNC void vstore(void)
  2324.          }
  2325.  #endif
  2326.          if (!nocode_wanted) {
  2327. +        small_struct:
  2328.              rc = RC_INT;
  2329.              if (is_float(ft)) {
  2330.                  rc = RC_FLOAT;
  2331. @@ -3876,6 +3904,10 @@ ST_FUNC void unary(void)
  2332.              if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
  2333.                  /* get some space for the returned structure */
  2334.                  size = type_size(&s->type, &align);
  2335. +#if defined TCC_TARGET_PE && defined TCC_TARGET_I386
  2336. +                if (size <= 8)
  2337. +                    align = 4;
  2338. +#endif
  2339.                  loc = (loc - size) & -align;
  2340.                  ret.type = s->type;
  2341.                  ret.r = VT_LOCAL | VT_LVAL;
  2342. @@ -3883,6 +3915,12 @@ ST_FUNC void unary(void)
  2343.                     problems */
  2344.                  vseti(VT_LOCAL, loc);
  2345.                  ret.c = vtop->c;
  2346. +#if defined TCC_TARGET_PE && defined TCC_TARGET_I386
  2347. +                if (size <= 8) {
  2348. +                    ret_st = ret;
  2349. +                    vtop--;
  2350. +                } else
  2351. +#endif
  2352.                  nb_args++;
  2353.              } else {
  2354.                  ret.type = s->type;
  2355. @@ -4090,6 +4128,7 @@ static void expr_cond(void)
  2356.      int tt, u, r1, r2, rc, t1, t2, bt1, bt2;
  2357.      SValue sv;
  2358.      CType type, type1, type2;
  2359. +    int small_struct = 0;
  2360.  
  2361.      if (const_wanted) {
  2362.          expr_lor_const();
  2363. @@ -4130,8 +4169,8 @@ static void expr_cond(void)
  2364.                  }
  2365.                  else
  2366.                      rc = RC_INT;
  2367. -                    gv(rc);
  2368. -                    save_regs(1);
  2369. +                gv(rc);
  2370. +                save_regs(1);
  2371.              }
  2372.              if (tok == ':' && gnu_ext) {
  2373.                  gv_dup();
  2374. @@ -4200,8 +4239,14 @@ static void expr_cond(void)
  2375.                  
  2376.              /* now we convert second operand */
  2377.              gen_cast(&type);
  2378. -            if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
  2379. -                gaddrof();
  2380. +            if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) {
  2381. +                int align;
  2382. +                small_struct = type_size(&vtop->type, &align);
  2383. +                if (small_struct != 4 && small_struct != 8) {
  2384. +                    small_struct = 0;
  2385. +                    gaddrof();
  2386. +                }
  2387. +            }
  2388.              rc = RC_INT;
  2389.              if (is_float(type.t)) {
  2390.                  rc = RC_FLOAT;
  2391. @@ -4210,7 +4255,7 @@ static void expr_cond(void)
  2392.                      rc = RC_ST0;
  2393.                  }
  2394.  #endif
  2395. -            } else if ((type.t & VT_BTYPE) == VT_LLONG) {
  2396. +            } else if ((type.t & VT_BTYPE) == VT_LLONG || small_struct == 8) {
  2397.                  /* for long longs, we use fixed registers to avoid having
  2398.                     to handle a complicated move */
  2399.                  rc = RC_IRET;
  2400. @@ -4224,8 +4269,10 @@ static void expr_cond(void)
  2401.              /* put again first value and cast it */
  2402.              *vtop = sv;
  2403.              gen_cast(&type);
  2404. -            if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
  2405. -                gaddrof();
  2406. +            if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) {
  2407. +                if (!small_struct)
  2408. +                    gaddrof();
  2409. +            }
  2410.              r1 = gv(rc);
  2411.              move_reg(r2, r1);
  2412.              vtop->r = r2;
  2413. @@ -4394,8 +4441,10 @@ static void block(int *bsym, int *csym,
  2414.              gsym(d); /* patch else jmp */
  2415.          } else
  2416.              gsym(a);
  2417. +        RESET_CACHE_IND;
  2418.      } else if (tok == TOK_WHILE) {
  2419.          next();
  2420. +        RESET_CACHE_IND;
  2421.          d = ind;
  2422.          skip('(');
  2423.          gexpr();
  2424. @@ -4490,6 +4539,18 @@ static void block(int *bsym, int *csym,
  2425.                      gv(RC_IRET);
  2426.                  } else {
  2427.  #endif
  2428. +#if defined TCC_TARGET_PE && defined TCC_TARGET_I386
  2429. +                int align, size;
  2430. +                size = type_size(&func_vt, &align);
  2431. +                if (size <= 8) {
  2432. +                    vtop->type = int_type;
  2433. +                    if (size > 4) {
  2434. +                        vtop->type.t &= ~VT_BTYPE;
  2435. +                        vtop->type.t |= VT_LLONG;
  2436. +                    }
  2437. +                    gv(RC_IRET);
  2438. +                } else {
  2439. +#endif
  2440.                  type = func_vt;
  2441.                  mk_pointer(&type);
  2442.                  vset(&type, VT_LOCAL | VT_LVAL, func_vc);
  2443. @@ -4497,7 +4558,7 @@ static void block(int *bsym, int *csym,
  2444.                  vswap();
  2445.                  /* copy structure value to pointer */
  2446.                  vstore();
  2447. -#ifdef TCC_ARM_EABI
  2448. +#if defined TCC_ARM_EABI || defined TCC_TARGET_PE
  2449.                  }
  2450.  #endif
  2451.              } else if (is_float(func_vt.t)) {
  2452. @@ -4540,6 +4601,7 @@ static void block(int *bsym, int *csym,
  2453.              }
  2454.          }
  2455.          skip(';');
  2456. +        RESET_CACHE_IND;
  2457.          d = ind;
  2458.          c = ind;
  2459.          a = 0;
  2460. @@ -4567,6 +4629,7 @@ static void block(int *bsym, int *csym,
  2461.      } else
  2462.      if (tok == TOK_DO) {
  2463.          next();
  2464. +        RESET_CACHE_IND;
  2465.          a = 0;
  2466.          b = 0;
  2467.          d = ind;
  2468. @@ -4574,6 +4637,7 @@ static void block(int *bsym, int *csym,
  2469.          skip(TOK_WHILE);
  2470.          skip('(');
  2471.          gsym(b);
  2472. +        RESET_CACHE_IND;
  2473.          gexpr();
  2474.          c = gtst(0, 0);
  2475.          gsym_addr(c, d);
  2476. @@ -4594,6 +4658,7 @@ static void block(int *bsym, int *csym,
  2477.          c = 0;
  2478.          block(&a, csym, &b, &c, case_reg, 0);
  2479.          /* if no default, jmp after switch */
  2480. +        RESET_CACHE_IND;
  2481.          if (c == 0)
  2482.              c = ind;
  2483.          /* default label */
  2484. @@ -4689,6 +4754,7 @@ static void block(int *bsym, int *csym,
  2485.              } else {
  2486.                  s = label_push(&global_label_stack, b, LABEL_DEFINED);
  2487.              }
  2488. +            RESET_CACHE_IND;
  2489.              s->jnext = ind;
  2490.              /* we accept this, but it is a mistake */
  2491.          block_after_label:
  2492. @@ -4697,6 +4763,7 @@ static void block(int *bsym, int *csym,
  2493.              } else {
  2494.                  if (is_expr)
  2495.                      vpop();
  2496. +                RESET_CACHE_IND;
  2497.                  block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
  2498.              }
  2499.          } else {
  2500. diff -pruN tcc-0.9.26/win32/build-tcc.bat tcc-0.9.26o/win32/build-tcc.bat
  2501. --- tcc-0.9.26/win32/build-tcc.bat  2013-02-16 00:24:00 +1000
  2502. +++ tcc-0.9.26o/win32/build-tcc.bat 2013-09-26 01:26:37 +1000
  2503. @@ -5,18 +5,18 @@
  2504.  @set /p VERSION= < ..\VERSION
  2505.  echo>..\config.h #define TCC_VERSION "%VERSION%"
  2506.  
  2507. -@if _%PROCESSOR_ARCHITEW6432%_==_AMD64_ goto x86_64
  2508. -@if _%PROCESSOR_ARCHITECTURE%_==_AMD64_ goto x86_64
  2509. +@for /F "delims=-" %%A in ('gcc -dumpmachine') do @if %%A==x86_64 goto x86_64
  2510.  
  2511.  @set target=-DTCC_TARGET_PE -DTCC_TARGET_I386
  2512.  @set CC=gcc -Os -s -fno-strict-aliasing
  2513.  @set P=32
  2514. +@set OPT=-O
  2515.  @goto tools
  2516.  
  2517.  :x86_64
  2518.  @set target=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
  2519.  @rem mingw 64 has an ICE with -Os
  2520. -@set CC=x86_64-pc-mingw32-gcc -O0 -s -fno-strict-aliasing
  2521. +@set CC=gcc -O0 -s -fno-strict-aliasing
  2522.  @set P=64
  2523.  @goto tools
  2524.  
  2525. @@ -28,6 +28,7 @@ echo>..\config.h #define TCC_VERSION "%V
  2526.  if not exist libtcc\nul mkdir libtcc
  2527.  copy ..\libtcc.h libtcc\libtcc.h
  2528.  %CC% %target% -shared -DLIBTCC_AS_DLL -DONE_SOURCE ../libtcc.c -o libtcc.dll -Wl,-out-implib,libtcc/libtcc.a
  2529. +if errorlevel 1 goto the_end
  2530.  tiny_impdef libtcc.dll -o libtcc/libtcc.def
  2531.  
  2532.  :tcc
  2533. @@ -37,24 +38,26 @@ tiny_impdef libtcc.dll -o libtcc/libtcc.
  2534.  copy ..\include\*.h include
  2535.  
  2536.  :libtcc1.a
  2537. -.\tcc %target% -c ../lib/libtcc1.c
  2538. -.\tcc %target% -c lib/crt1.c
  2539. -.\tcc %target% -c lib/wincrt1.c
  2540. -.\tcc %target% -c lib/dllcrt1.c
  2541. -.\tcc %target% -c lib/dllmain.c
  2542. -.\tcc %target% -c lib/chkstk.S
  2543. +.\tcc %target% %OPT% -c ../lib/libtcc1.c
  2544. +.\tcc %target% %OPT% -c lib/crt1.c
  2545. +.\tcc %target% %OPT% -c lib/wincrt1.c
  2546. +.\tcc %target% %OPT% -c lib/dllcrt1.c
  2547. +.\tcc %target% %OPT% -c lib/dllmain.c
  2548. +.\tcc %target% %OPT% -c lib/chkstk.S
  2549.  goto lib%P%
  2550.  
  2551.  :lib32
  2552. -.\tcc %target% -c ../lib/alloca86.S
  2553. -.\tcc %target% -c ../lib/alloca86-bt.S
  2554. -.\tcc %target% -c ../lib/bcheck.c
  2555. -tiny_libmaker lib/libtcc1.a libtcc1.o alloca86.o alloca86-bt.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o bcheck.o
  2556. +.\tcc %target% %OPT% -c lib/seh.S
  2557. +.\tcc %target% %OPT% -c ../lib/alloca86.S
  2558. +.\tcc %target% %OPT% -c ../lib/alloca86-bt.S
  2559. +.\tcc %target% %OPT% -c ../lib/bcheck.c
  2560. +tiny_libmaker lib/libtcc1.a libtcc1.o alloca86.o alloca86-bt.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o seh.o bcheck.o
  2561.  @goto the_end
  2562.  
  2563.  :lib64
  2564. +.\tcc %target% -c lib/sjlj.S
  2565.  .\tcc %target% -c ../lib/alloca86_64.S
  2566. -tiny_libmaker lib/libtcc1.a libtcc1.o alloca86_64.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
  2567. +tiny_libmaker lib/libtcc1.a libtcc1.o alloca86_64.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o sjlj.o
  2568.  
  2569.  :the_end
  2570.  del *.o
  2571. diff -pruN tcc-0.9.26/win32/lib/chkstk.S tcc-0.9.26o/win32/lib/chkstk.S
  2572. --- tcc-0.9.26/win32/lib/chkstk.S   2013-02-16 00:24:00 +1000
  2573. +++ tcc-0.9.26o/win32/lib/chkstk.S  2013-09-09 15:27:51 +1000
  2574. @@ -55,137 +55,5 @@ P0:
  2575.      jmp     *8(%rax)
  2576.  
  2577.  /* ---------------------------------------------- */
  2578. -/* setjmp/longjmp support */
  2579. -
  2580. -.globl tinyc_getbp
  2581. -tinyc_getbp:
  2582. -    mov %rbp,%rax
  2583. -    ret
  2584. -
  2585. -/* ---------------------------------------------- */
  2586. -#endif
  2587. -/* ---------------------------------------------- */
  2588. -
  2589. -
  2590. -/* ---------------------------------------------- */
  2591. -#ifndef TCC_TARGET_X86_64
  2592. -/* ---------------------------------------------- */
  2593. -
  2594. -/*
  2595. -    int _except_handler3(
  2596. -       PEXCEPTION_RECORD exception_record,
  2597. -       PEXCEPTION_REGISTRATION registration,
  2598. -       PCONTEXT context,
  2599. -       PEXCEPTION_REGISTRATION dispatcher
  2600. -    );
  2601. -
  2602. -    int __cdecl _XcptFilter(
  2603. -       unsigned long xcptnum,
  2604. -       PEXCEPTION_POINTERS pxcptinfoptrs
  2605. -    );
  2606. -
  2607. -    struct _sehrec {
  2608. -       void *esp;                // 0
  2609. -       void *exception_pointers; // 1
  2610. -       void *prev;               // 2
  2611. -       void *handler;            // 3
  2612. -       void *scopetable;         // 4
  2613. -       int trylevel;             // 5
  2614. -       void *ebp                 // 6
  2615. -    };
  2616. -
  2617. -    // this is what the assembler code below means:
  2618. -    __try
  2619. -    {
  2620. -         // ...
  2621. -    }
  2622. -    __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation()))
  2623. -    {
  2624. -         exit(GetExceptionCode());
  2625. -    }
  2626. -*/
  2627. -
  2628. -.globl _exception_info
  2629. -_exception_info:
  2630. -    mov 1*4-24(%ebp),%eax
  2631. -    ret
  2632. -
  2633. -.globl _exception_code
  2634. -_exception_code:
  2635. -    call _exception_info
  2636. -    mov (%eax),%eax
  2637. -    mov (%eax),%eax
  2638. -    ret
  2639. -
  2640. -seh_filter:
  2641. -    call _exception_info
  2642. -    push %eax
  2643. -    call _exception_code
  2644. -    push %eax
  2645. -    call _XcptFilter
  2646. -    add $ 8,%esp
  2647. -    ret
  2648. -
  2649. -seh_except:
  2650. -    mov 0*4-24(%ebp),%esp
  2651. -    call _exception_code
  2652. -    push %eax
  2653. -    call _exit
  2654. -
  2655. -// msvcrt wants scopetables aligned and in read-only segment (using .text)
  2656. -.align 4
  2657. -seh_scopetable:
  2658. -    .long -1
  2659. -    .long seh_filter
  2660. -    .long seh_except
  2661. -
  2662. -seh_handler:
  2663. -    jmp _except_handler3
  2664. -
  2665. -.globl ___try__
  2666. -___try__:
  2667. -.globl __try__
  2668. -__try__:
  2669. -    push %ebp
  2670. -    mov 8(%esp),%ebp
  2671. -
  2672. -//    void *esp;
  2673. -    lea 12(%esp),%eax
  2674. -    mov %eax,0*4(%ebp)
  2675. -
  2676. -//    void *exception_pointers;
  2677. -    xor %eax,%eax
  2678. -    mov %eax,1*4(%ebp)
  2679. -
  2680. -//    void *prev;
  2681. -    mov %fs:0,%eax
  2682. -    mov %eax,2*4(%ebp)
  2683. -
  2684. -//    void *handler;
  2685. -    mov $ seh_handler,%eax
  2686. -    mov %eax,3*4(%ebp)
  2687. -
  2688. -//    void *scopetable;
  2689. -    mov $ seh_scopetable,%eax
  2690. -    mov %eax,4*4(%ebp)
  2691. -
  2692. -//    int trylevel;
  2693. -    xor %eax,%eax
  2694. -    mov %eax,5*4(%ebp)
  2695. -
  2696. -//    register new SEH
  2697. -    lea 2*4(%ebp),%eax
  2698. -    mov %eax,%fs:0
  2699. -
  2700. -    pop %ebp
  2701. -    ret
  2702. -
  2703. -/* ---------------------------------------------- */
  2704. -#else
  2705. -/* ---------------------------------------------- */
  2706. -
  2707. -/* SEH on x86-64 not implemented */
  2708. -
  2709. -/* ---------------------------------------------- */
  2710.  #endif
  2711.  /* ---------------------------------------------- */
  2712. diff -pruN tcc-0.9.26/win32/lib/seh.S tcc-0.9.26o/win32/lib/seh.S
  2713. --- tcc-0.9.26/win32/lib/seh.S  1970-01-01 10:00:00 +1000
  2714. +++ tcc-0.9.26o/win32/lib/seh.S 2013-09-24 16:17:05 +1000
  2715. @@ -0,0 +1,112 @@
  2716. +/* ---------------------------------------------- */
  2717. +/* seh.S */
  2718. +
  2719. +/* structured exception handling for i386 */
  2720. +
  2721. +/*
  2722. +    int _except_handler3(
  2723. +       PEXCEPTION_RECORD exception_record,
  2724. +       PEXCEPTION_REGISTRATION registration,
  2725. +       PCONTEXT context,
  2726. +       PEXCEPTION_REGISTRATION dispatcher
  2727. +    );
  2728. +
  2729. +    int __cdecl _XcptFilter(
  2730. +       unsigned long xcptnum,
  2731. +       PEXCEPTION_POINTERS pxcptinfoptrs
  2732. +    );
  2733. +
  2734. +    struct _sehrec {
  2735. +       void *esp;                // 0
  2736. +       void *exception_pointers; // 1
  2737. +       void *prev;               // 2
  2738. +       void *handler;            // 3
  2739. +       void *scopetable;         // 4
  2740. +       int trylevel;             // 5
  2741. +       void *ebp                 // 6
  2742. +    };
  2743. +
  2744. +    // this is what the assembler code below means:
  2745. +    __try
  2746. +    {
  2747. +         // ...
  2748. +    }
  2749. +    __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation()))
  2750. +    {
  2751. +         exit(GetExceptionCode());
  2752. +    }
  2753. +*/
  2754. +
  2755. +.globl _exception_info
  2756. +_exception_info:
  2757. +    mov 1*4-24(%ebp),%eax
  2758. +    ret
  2759. +
  2760. +.globl _exception_code
  2761. +_exception_code:
  2762. +    call _exception_info
  2763. +    mov (%eax),%eax
  2764. +    mov (%eax),%eax
  2765. +    ret
  2766. +
  2767. +seh_filter:
  2768. +    call _exception_info
  2769. +    push %eax
  2770. +    call _exception_code
  2771. +    push %eax
  2772. +    call _XcptFilter
  2773. +    add $ 8,%esp
  2774. +    ret
  2775. +
  2776. +seh_except:
  2777. +    mov 0*4-24(%ebp),%esp
  2778. +    call _exception_code
  2779. +    push %eax
  2780. +    call _exit
  2781. +
  2782. +// msvcrt wants scopetables aligned and in read-only segment (using .text)
  2783. +.align 4
  2784. +seh_scopetable:
  2785. +    .long -1
  2786. +    .long seh_filter
  2787. +    .long seh_except
  2788. +
  2789. +seh_handler:
  2790. +    jmp _except_handler3
  2791. +
  2792. +.align 16
  2793. +.globl ___try__
  2794. +___try__:
  2795. +.globl __try__
  2796. +__try__:
  2797. +    push %ebp
  2798. +    mov 8(%esp),%ebp
  2799. +
  2800. +//    void *esp;
  2801. +    lea 12(%esp),%eax
  2802. +    mov %eax,0*4(%ebp)
  2803. +
  2804. +//    void *exception_pointers;
  2805. +    xor %eax,%eax
  2806. +    mov %eax,1*4(%ebp)
  2807. +
  2808. +//    int trylevel;
  2809. +    mov %eax,5*4(%ebp)
  2810. +
  2811. +//    void *prev;
  2812. +    mov %fs:0,%eax
  2813. +    mov %eax,2*4(%ebp)
  2814. +
  2815. +//    void *handler;
  2816. +    movl $ seh_handler,3*4(%ebp)
  2817. +
  2818. +//    void *scopetable;
  2819. +    movl $ seh_scopetable,4*4(%ebp)
  2820. +
  2821. +//    register new SEH
  2822. +    lea 2*4(%ebp),%eax
  2823. +    mov %eax,%fs:0
  2824. +
  2825. +    pop %ebp
  2826. +    ret
  2827. +/* ---------------------------------------------- */
  2828. diff -pruN tcc-0.9.26/win32/lib/sjlj.S tcc-0.9.26o/win32/lib/sjlj.S
  2829. --- tcc-0.9.26/win32/lib/sjlj.S 1970-01-01 10:00:00 +1000
  2830. +++ tcc-0.9.26o/win32/lib/sjlj.S    2013-09-09 15:18:12 +1000
  2831. @@ -0,0 +1,10 @@
  2832. +/* ---------------------------------------------- */
  2833. +/* sjlj.S */
  2834. +
  2835. +/* setjmp/longjmp x86-64 support function */
  2836. +
  2837. +.globl tinyc_getbp
  2838. +tinyc_getbp:
  2839. +    mov %rbp,%rax
  2840. +    ret
  2841. +/* ---------------------------------------------- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement