movs, rol, reg save, esp frame..
[ia32rtools.git] / tools / translate.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "my_assert.h"
7 #include "my_str.h"
8
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
10 #define IS(w, y) !strcmp(w, y)
11
12 #include "protoparse.h"
13
14 const char *asmfn;
15 static int asmln;
16
17 #define anote(fmt, ...) \
18         printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
19 #define awarn(fmt, ...) \
20         printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
21 #define aerr(fmt, ...) do { \
22         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
23   fcloseall(); \
24         exit(1); \
25 } while (0)
26
27 enum op_flags {
28   OPF_RMD    = (1 << 0), /* removed or optimized out */
29   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
30   OPF_FLAGS  = (1 << 2), /* sets flags */
31   OPF_JMP    = (1 << 3), /* branches, ret and call */
32   OPF_CC     = (1 << 4), /* uses flags */
33   OPF_TAIL   = (1 << 5), /* ret or tail call */
34   OPF_REP    = (1 << 6), /* prefixed by rep */
35   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
36 };
37
38 enum op_op {
39         OP_INVAL,
40         OP_NOP,
41         OP_PUSH,
42         OP_POP,
43         OP_MOV,
44         OP_LEA,
45         OP_MOVZX,
46         OP_MOVSX,
47         OP_NOT,
48         OP_CDQ,
49         OP_STOS,
50         OP_MOVS,
51         OP_RET,
52         OP_ADD,
53         OP_SUB,
54         OP_AND,
55         OP_OR,
56         OP_XOR,
57         OP_SHL,
58         OP_SHR,
59         OP_SAR,
60         OP_ROL,
61         OP_ROR,
62         OP_ADC,
63         OP_SBB,
64         OP_INC,
65         OP_DEC,
66         OP_NEG,
67         OP_MUL,
68         OP_IMUL,
69         OP_DIV,
70         OP_IDIV,
71         OP_TEST,
72         OP_CMP,
73         OP_CALL,
74         OP_JMP,
75         OP_JO,
76         OP_JNO,
77         OP_JC,
78         OP_JNC,
79         OP_JZ,
80         OP_JNZ,
81         OP_JBE,
82         OP_JA,
83         OP_JS,
84         OP_JNS,
85         OP_JP,
86         OP_JNP,
87         OP_JL,
88         OP_JGE,
89         OP_JLE,
90         OP_JG,
91 };
92
93 enum opr_type {
94   OPT_UNSPEC,
95   OPT_REG,
96   OPT_REGMEM,
97   OPT_LABEL,
98   OPT_OFFSET,
99   OPT_CONST,
100 };
101
102 enum opr_lenmod {
103         OPLM_UNSPEC,
104         OPLM_BYTE,
105         OPLM_WORD,
106         OPLM_DWORD,
107 };
108
109 #define MAX_OPERANDS 3
110
111 struct parsed_opr {
112   enum opr_type type;
113   enum opr_lenmod lmod;
114   int reg;
115   unsigned int val;
116   char name[256];
117 };
118
119 struct parsed_op {
120   enum op_op op;
121   struct parsed_opr operand[MAX_OPERANDS];
122   unsigned int flags;
123   int operand_cnt;
124   int regmask_src;        // all referensed regs
125   int regmask_dst;
126   int pfomask;            // flagop: parsed_flag_op that can't be delayed
127   int argmask;            // push: args that are altered before call
128   int cc_scratch;         // scratch storage during analysis
129   int bt_i;               // branch target (for branches)
130   struct parsed_op *lrl;  // label reference list entry
131   void *datap;
132 };
133
134 // datap:
135 // OP_CALL - ptr to parsed_proto
136 // (OPF_CC) - point to corresponding (OPF_FLAGS)
137
138 struct parsed_equ {
139   char name[64];
140   enum opr_lenmod lmod;
141   int offset;
142 };
143
144 #define MAX_OPS 1024
145
146 static struct parsed_op ops[MAX_OPS];
147 static struct parsed_equ *g_eqs;
148 static int g_eqcnt;
149 static char g_labels[MAX_OPS][32];
150 static struct parsed_op *g_label_refs[MAX_OPS];
151 static struct parsed_proto g_func_pp;
152 static char g_func[256];
153 static char g_comment[256];
154 static int g_bp_frame;
155 static int g_bp_stack;
156 #define ferr(op_, fmt, ...) do { \
157   printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
158     dump_op(op_), ##__VA_ARGS__); \
159   fcloseall(); \
160   exit(1); \
161 } while (0)
162
163 #define MAX_REGS 8
164
165 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
166 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
167 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
168 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
169
170 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
171
172 // possible basic comparison types (without inversion)
173 enum parsed_flag_op {
174   PFO_O,  // 0 OF=1
175   PFO_C,  // 2 CF=1
176   PFO_Z,  // 4 ZF=1
177   PFO_BE, // 6 CF=1||ZF=1
178   PFO_S,  // 8 SF=1
179   PFO_P,  // a PF=1
180   PFO_L,  // c SF!=OF
181   PFO_LE, // e ZF=1||SF!=OF
182 };
183
184 static const char *parsed_flag_op_names[] = {
185   "o", "c", "z", "be", "s", "p", "l", "le"
186 };
187
188 static int char_array_i(const char *array[], size_t len, const char *s)
189 {
190   int i;
191
192   for (i = 0; i < len; i++)
193     if (IS(s, array[i]))
194       return i;
195
196   return -1;
197 }
198
199 static void printf_number(char *buf, size_t buf_size, long number)
200 {
201   // output in C-friendly form
202   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
203 }
204
205 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
206 {
207   int reg;
208
209   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
210   if (reg >= 0) {
211     *reg_lmod = OPLM_DWORD;
212     return reg;
213   }
214   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
215   if (reg >= 0) {
216     *reg_lmod = OPLM_WORD;
217     return reg;
218   }
219   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
220   if (reg >= 0) {
221     *reg_lmod = OPLM_BYTE;
222     return reg;
223   }
224   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
225   if (reg >= 0) {
226     *reg_lmod = OPLM_BYTE;
227     return reg;
228   }
229
230   return -1;
231 }
232
233 static long parse_number(const char *number)
234 {
235   int len = strlen(number);
236   const char *p = number;
237   char *endp = NULL;
238   int neg = 0;
239   int bad;
240   long ret;
241
242   if (*p == '-') {
243     neg = 1;
244     p++;
245   }
246   if (len > 1 && *p == '0')
247     p++;
248   if (number[len - 1] == 'h') {
249     ret = strtol(p, &endp, 16);
250     bad = (*endp != 'h');
251   }
252   else {
253     ret = strtol(p, &endp, 10);
254     bad = (*endp != 0);
255   }
256   if (bad)
257     aerr("number parsing failed\n");
258   if (neg)
259     ret = -ret;
260   return ret;
261 }
262
263 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
264 {
265   enum opr_lenmod lmod;
266   char cvtbuf[256];
267   char *d = cvtbuf;
268   char *s = name;
269   char w[64];
270   long number;
271   int reg;
272   int c = 0;
273
274   *d = 0;
275
276   while (*s != 0) {
277     d += strlen(d);
278     while (my_isblank(*s))
279       s++;
280     for (; my_issep(*s); d++, s++)
281       *d = *s;
282     while (my_isblank(*s))
283       s++;
284     *d = 0;
285
286     // skip 'ds:' prefix
287     if (!strncmp(s, "ds:", 3))
288       s += 3;
289
290     s = next_idt(w, sizeof(w), s);
291     if (w[0] == 0)
292       break;
293     c++;
294
295     reg = parse_reg(&lmod, w);
296     if (reg >= 0) {
297       *regmask |= 1 << reg;
298       goto pass;
299     }
300
301     if ('0' <= w[0] && w[0] <= '9') {
302       number = parse_number(w);
303       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
304       continue;
305     }
306
307     // probably some label/identifier - pass
308
309 pass:
310     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
311   }
312
313   if (need_c_cvt)
314     strcpy(name, cvtbuf);
315
316   return c;
317 }
318
319 static const char *parse_stack_el(const char *name)
320 {
321   const char *p;
322   char buf[32];
323   int len;
324
325   if (!strncmp(name, "ebp+", 4)
326       && !('0' <= name[4] && name[4] <= '9'))
327   {
328     return name + 4;
329   }
330   if (strncmp(name, "esp+", 4) != 0)
331     return NULL;
332
333   p = strchr(name + 4, '+');
334   if (p) {
335     // must be a number after esp+
336     if (!('0' <= name[4] && name[4] <= '9'))
337       return NULL;
338     len = p - (name + 4);
339     if (len < sizeof(buf) - 1) {
340       strncpy(buf, name + 4, len);
341       buf[len] = 0;
342       parse_number(buf);
343     }
344     p++;
345   }
346   else
347     p = name + 4;
348
349   if ('0' <= *p && *p <= '9')
350     return NULL;
351
352   return p;
353 }
354
355 static int guess_lmod_from_name(struct parsed_opr *opr)
356 {
357   if (!strncmp(opr->name, "dword_", 6)) {
358     opr->lmod = OPLM_DWORD;
359     return 1;
360   }
361   if (!strncmp(opr->name, "word_", 5)) {
362     opr->lmod = OPLM_WORD;
363     return 1;
364   }
365   if (!strncmp(opr->name, "byte_", 5)) {
366     opr->lmod = OPLM_BYTE;
367     return 1;
368   }
369   return 0;
370 }
371
372 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
373   int *regmask)
374 {
375   opr->type = OPT_REG;
376   opr->reg = reg;
377   opr->lmod = lmod;
378   *regmask |= 1 << reg;
379 }
380
381 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name);
382
383 static int parse_operand(struct parsed_opr *opr,
384   int *regmask, int *regmask_indirect,
385         char words[16][256], int wordc, int w, unsigned int op_flags)
386 {
387   enum opr_lenmod tmplmod;
388   int ret, len;
389   long number;
390   int i;
391
392         if (w >= wordc)
393                 aerr("parse_operand w %d, wordc %d\n", w, wordc);
394
395         opr->reg = xUNSPEC;
396
397         for (i = w; i < wordc; i++) {
398                 len = strlen(words[i]);
399                 if (words[i][len - 1] == ',') {
400                         words[i][len - 1] = 0;
401                         wordc = i + 1;
402                         break;
403                 }
404         }
405
406         if (op_flags & OPF_JMP) {
407                 const char *label;
408
409                 if (wordc - w == 3 && IS(words[w + 1], "ptr"))
410                         label = words[w + 2];
411                 else if (wordc - w == 2 && IS(words[w], "short"))
412                         label = words[w + 1];
413                 else if (wordc - w == 1)
414                         label = words[w];
415                 else
416                         aerr("jump parse error");
417
418                 opr->type = OPT_LABEL;
419                 strcpy(opr->name, label);
420                 return wordc;
421         }
422
423         if (wordc - w >= 3) {
424                 if (IS(words[w + 1], "ptr")) {
425                         if (IS(words[w], "dword"))
426                                 opr->lmod = OPLM_DWORD;
427                         else if (IS(words[w], "word"))
428                                 opr->lmod = OPLM_WORD;
429                         else if (IS(words[w], "byte"))
430                                 opr->lmod = OPLM_BYTE;
431                         else
432                                 aerr("type parsing failed\n");
433                         w += 2;
434                 }
435         }
436
437         if (wordc - w == 2 && IS(words[w], "offset")) {
438                 opr->type = OPT_OFFSET;
439                 strcpy(opr->name, words[w + 1]);
440                 return wordc;
441         }
442
443   if (wordc - w != 1)
444     aerr("parse_operand 1 word expected\n");
445
446   strcpy(opr->name, words[w]);
447
448   if (words[w][0] == '[') {
449     opr->type = OPT_REGMEM;
450     ret = sscanf(words[w], "[%[^]]]", opr->name);
451     if (ret != 1)
452       aerr("[] parse failure\n");
453
454     parse_indmode(opr->name, regmask_indirect, 1);
455     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name)) {
456       // might be an equ
457       struct parsed_equ *eq =
458         equ_find(NULL, parse_stack_el(opr->name));
459       if (eq)
460         opr->lmod = eq->lmod;
461     }
462     return wordc;
463   }
464   else if (strchr(words[w], '[')) {
465     // label[reg] form
466     opr->type = OPT_REGMEM;
467     if (opr->lmod == OPLM_UNSPEC)
468       guess_lmod_from_name(opr);
469     parse_indmode(strchr(words[w], '['), regmask_indirect, 0);
470     return wordc;
471   }
472   else if (('0' <= words[w][0] && words[w][0] <= '9')
473     || words[w][0] == '-')
474   {
475     number = parse_number(words[w]);
476     opr->type = OPT_CONST;
477     opr->val = number;
478     printf_number(opr->name, sizeof(opr->name), number);
479     return wordc;
480   }
481
482   ret = parse_reg(&tmplmod, opr->name);
483   if (ret >= 0) {
484     setup_reg_opr(opr, ret, tmplmod, regmask);
485     return wordc;
486   }
487
488   // most likely var in data segment
489   opr->type = OPT_LABEL;
490   if (opr->lmod == OPLM_UNSPEC)
491     guess_lmod_from_name(opr);
492   if (opr->lmod != OPLM_UNSPEC)
493     return wordc;
494
495   // TODO: scan data seg to determine type?
496   return wordc;
497 }
498
499 static const struct {
500   const char *name;
501   unsigned int flags;
502 } pref_table[] = {
503   { "rep",    OPF_REP },
504 };
505
506 static const struct {
507   const char *name;
508   enum op_op op;
509   unsigned int minopr;
510   unsigned int maxopr;
511   unsigned int flags;
512 } op_table[] = {
513   { "nop",  OP_NOP,    0, 0, 0 },
514   { "push", OP_PUSH,   1, 1, 0 },
515   { "pop",  OP_POP,    1, 1, OPF_DATA },
516   { "mov" , OP_MOV,    2, 2, OPF_DATA },
517   { "lea",  OP_LEA,    2, 2, OPF_DATA },
518   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
519   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
520   { "not",  OP_NOT,    1, 1, OPF_DATA },
521   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
522   { "stosb",OP_STOS,   0, 0, OPF_DATA },
523   { "stosw",OP_STOS,   0, 0, OPF_DATA },
524   { "stosd",OP_STOS,   0, 0, OPF_DATA },
525   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
526   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
527   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
528   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
529   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
530   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
531   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
532   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
533   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
534   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
535   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
536   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
537   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
538   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
539   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
540   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
541   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
542   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
543   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
544   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
545   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
546   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
547   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
548   { "test", OP_TEST,   2, 2, OPF_FLAGS },
549   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
550   { "retn", OP_RET,    0, 1, OPF_JMP|OPF_TAIL },
551   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_FLAGS },
552   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
553   { "jo",   OP_JO,     1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
554   { "jno",  OP_JNO,    1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
555   { "jc",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
556   { "jb",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72
557   { "jnc",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
558   { "jnb",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
559   { "jae",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
560   { "jz",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
561   { "je",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74
562   { "jnz",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
563   { "jne",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75
564   { "jbe",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
565   { "jna",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76
566   { "ja",   OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
567   { "jnbe", OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77
568   { "js",   OP_JS,     1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
569   { "jns",  OP_JNS,    1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
570   { "jp",   OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
571   { "jpe",  OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a
572   { "jnp",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
573   { "jpo",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b
574   { "jl",   OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
575   { "jnge", OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c
576   { "jge",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
577   { "jnl",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d
578   { "jle",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
579   { "jng",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e
580   { "jg",   OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
581   { "jnle", OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f
582   { "seto",   OP_JO,   1, 1, OPF_DATA|OPF_CC },
583   { "setno",  OP_JNO,  1, 1, OPF_DATA|OPF_CC },
584   { "setc",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
585   { "setb",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
586   { "setnc",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
587   { "setae",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
588   { "setz",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
589   { "sete",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
590   { "setnz",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
591   { "setne",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
592   { "setbe",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
593   { "setna",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
594   { "seta",   OP_JA,   1, 1, OPF_DATA|OPF_CC },
595   { "setnbe", OP_JA,   1, 1, OPF_DATA|OPF_CC },
596   { "sets",   OP_JS,   1, 1, OPF_DATA|OPF_CC },
597   { "setns",  OP_JNS,  1, 1, OPF_DATA|OPF_CC },
598   { "setp",   OP_JP,   1, 1, OPF_DATA|OPF_CC },
599   { "setpe",  OP_JP,   1, 1, OPF_DATA|OPF_CC },
600   { "setnp",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
601   { "setpo",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
602   { "setl",   OP_JL,   1, 1, OPF_DATA|OPF_CC },
603   { "setnge", OP_JL,   1, 1, OPF_DATA|OPF_CC },
604   { "setge",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
605   { "setnl",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
606   { "setle",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
607   { "setng",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
608   { "setg",   OP_JG,   1, 1, OPF_DATA|OPF_CC },
609   { "setnle", OP_JG,   1, 1, OPF_DATA|OPF_CC },
610 };
611
612 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
613 {
614   enum opr_lenmod lmod = OPLM_UNSPEC;
615   int prefix_flags = 0;
616   int regmask_ind;
617   int regmask;
618   int op_w = 0;
619   int opr = 0;
620   int w = 0;
621   int i;
622
623   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
624     if (IS(words[w], pref_table[i].name)) {
625       prefix_flags = pref_table[i].flags;
626       break;
627     }
628   }
629
630   if (prefix_flags) {
631     if (wordc <= 1)
632       aerr("lone prefix: '%s'\n", words[0]);
633     w++;
634   }
635
636   op_w = w;
637   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
638     if (IS(words[w], op_table[i].name))
639       break;
640   }
641
642   if (i == ARRAY_SIZE(op_table))
643     aerr("unhandled op: '%s'\n", words[0]);
644   w++;
645
646   op->op = op_table[i].op;
647   op->flags = op_table[i].flags | prefix_flags;
648   op->regmask_src = op->regmask_dst = 0;
649
650   for (opr = 0; opr < op_table[i].minopr; opr++) {
651     regmask = regmask_ind = 0;
652     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
653       words, wordc, w, op->flags);
654
655     if (opr == 0 && (op->flags & OPF_DATA))
656       op->regmask_dst = regmask;
657     // for now, mark dst as src too
658     op->regmask_src |= regmask | regmask_ind;
659   }
660
661   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
662     w = parse_operand(&op->operand[opr],
663       &op->regmask_src, &op->regmask_src,
664       words, wordc, w, op->flags);
665   }
666
667   if (w < wordc)
668     aerr("parse_op %s incomplete: %d/%d\n",
669       words[0], w, wordc);
670
671   // special cases
672   op->operand_cnt = opr;
673   if (!strncmp(op_table[i].name, "set", 3))
674     op->operand[0].lmod = OPLM_BYTE;
675
676   // ops with implicit argumets
677   switch (op->op) {
678   case OP_CDQ:
679     op->operand_cnt = 2;
680     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
681     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
682     break;
683
684   case OP_STOS:
685     if (op->operand_cnt != 0)
686       break;
687     if      (IS(words[op_w], "stosb"))
688       lmod = OPLM_BYTE;
689     else if (IS(words[op_w], "stosw"))
690       lmod = OPLM_WORD;
691     else if (IS(words[op_w], "stosd"))
692       lmod = OPLM_DWORD;
693     op->operand_cnt = 3;
694     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
695     setup_reg_opr(&op->operand[1], xCX, OPLM_DWORD, &op->regmask_src);
696     op->regmask_dst = op->regmask_src;
697     setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD, &op->regmask_src);
698     break;
699
700   case OP_MOVS:
701     if (op->operand_cnt != 0)
702       break;
703     if      (IS(words[op_w], "movsb"))
704       lmod = OPLM_BYTE;
705     else if (IS(words[op_w], "movsw"))
706       lmod = OPLM_WORD;
707     else if (IS(words[op_w], "movsd"))
708       lmod = OPLM_DWORD;
709     op->operand_cnt = 3;
710     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
711     setup_reg_opr(&op->operand[1], xSI, OPLM_DWORD, &op->regmask_src);
712     setup_reg_opr(&op->operand[2], xCX, OPLM_DWORD, &op->regmask_src);
713     op->regmask_dst = op->regmask_src;
714     break;
715
716   case OP_IMUL:
717     if (op->operand_cnt != 1)
718       break;
719     // fallthrough
720   case OP_MUL:
721     // singleop mul
722     op->regmask_dst = (1 << xDX) | (1 << xAX);
723     op->regmask_src |= (1 << xAX);
724     if (op->operand[0].lmod == OPLM_UNSPEC)
725       op->operand[0].lmod = OPLM_DWORD;
726     break;
727
728   case OP_DIV:
729   case OP_IDIV:
730     // we could set up operands for edx:eax, but there is no real need to
731     // (see is_opr_modified())
732     regmask = (1 << xDX) | (1 << xAX);
733     op->regmask_dst = regmask;
734     op->regmask_src |= regmask;
735     if (op->operand[0].lmod == OPLM_UNSPEC)
736       op->operand[0].lmod = OPLM_DWORD;
737     break;
738
739   case OP_SHL:
740   case OP_SHR:
741   case OP_SAR:
742   case OP_ROL:
743   case OP_ROR:
744     if (op->operand[1].lmod == OPLM_UNSPEC)
745       op->operand[1].lmod = OPLM_BYTE;
746     break;
747
748   default:
749     break;
750   }
751 }
752
753 static const char *op_name(enum op_op op)
754 {
755   int i;
756
757   for (i = 0; i < ARRAY_SIZE(op_table); i++)
758     if (op_table[i].op == op)
759       return op_table[i].name;
760
761   return "???";
762 }
763
764 // debug
765 static const char *dump_op(struct parsed_op *po)
766 {
767   static char out[128];
768   char *p = out;
769   int i;
770
771   snprintf(out, sizeof(out), "%s", op_name(po->op));
772   for (i = 0; i < po->operand_cnt; i++) {
773     p += strlen(p);
774     if (i > 0)
775       *p++ = ',';
776     snprintf(p, sizeof(out) - (p - out),
777       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
778       po->operand[i].name);
779   }
780
781   return out;
782 }
783
784 static const char *lmod_cast_u(struct parsed_op *po,
785   enum opr_lenmod lmod)
786 {
787   switch (lmod) {
788   case OPLM_DWORD:
789     return "";
790   case OPLM_WORD:
791     return "(u16)";
792   case OPLM_BYTE:
793     return "(u8)";
794   default:
795     ferr(po, "invalid lmod: %d\n", lmod);
796     return "(_invalid_)";
797   }
798 }
799
800 static const char *lmod_cast_u_ptr(struct parsed_op *po,
801   enum opr_lenmod lmod)
802 {
803   switch (lmod) {
804   case OPLM_DWORD:
805     return "*(u32 *)";
806   case OPLM_WORD:
807     return "*(u16 *)";
808   case OPLM_BYTE:
809     return "*(u8 *)";
810   default:
811     ferr(po, "invalid lmod: %d\n", lmod);
812     return "(_invalid_)";
813   }
814 }
815
816 static const char *lmod_cast_s(struct parsed_op *po,
817   enum opr_lenmod lmod)
818 {
819   switch (lmod) {
820   case OPLM_DWORD:
821     return "(s32)";
822   case OPLM_WORD:
823     return "(s16)";
824   case OPLM_BYTE:
825     return "(s8)";
826   default:
827     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
828     return "(_invalid_)";
829   }
830 }
831
832 static const char *lmod_cast(struct parsed_op *po,
833   enum opr_lenmod lmod, int is_signed)
834 {
835   return is_signed ?
836     lmod_cast_s(po, lmod) :
837     lmod_cast_u(po, lmod);
838 }
839
840 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
841 {
842   switch (lmod) {
843   case OPLM_DWORD:
844     return 4;
845   case OPLM_WORD:
846     return 2;
847   case OPLM_BYTE:
848     return 1;
849   default:
850     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
851     return 0;
852   }
853 }
854
855 static const char *opr_name(struct parsed_op *po, int opr_num)
856 {
857   if (opr_num >= po->operand_cnt)
858     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
859   return po->operand[opr_num].name;
860 }
861
862 static unsigned int opr_const(struct parsed_op *po, int opr_num)
863 {
864   if (opr_num >= po->operand_cnt)
865     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
866   if (po->operand[opr_num].type != OPT_CONST)
867     ferr(po, "opr %d: const expected\n", opr_num);
868   return po->operand[opr_num].val;
869 }
870
871 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
872 {
873   if ((unsigned int)popr->reg >= MAX_REGS)
874     ferr(po, "invalid reg: %d\n", popr->reg);
875   return regs_r32[popr->reg];
876 }
877
878 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name)
879 {
880   int i;
881
882   for (i = 0; i < g_eqcnt; i++)
883     if (IS(g_eqs[i].name, name))
884       break;
885   if (i >= g_eqcnt) {
886     if (po != NULL)
887       ferr(po, "unresolved equ name: '%s'\n", name);
888     return NULL;
889   }
890
891   return &g_eqs[i];
892 }
893
894 static void bg_frame_access(struct parsed_op *po, enum opr_lenmod lmod,
895   char *buf, size_t buf_size, const char *name,
896   int is_src, int is_lea)
897 {
898   const char *prefix = "";
899   struct parsed_equ *eq;
900   int i, arg_i, arg_s;
901   const char *bp_arg;
902   int stack_ra = 0;
903   int sf_ofs;
904
905   bp_arg = parse_stack_el(name);
906   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
907   eq = equ_find(po, bp_arg);
908   if (eq == NULL)
909     ferr(po, "detected but missing eq\n");
910
911   if (!strncmp(name, "ebp", 3))
912     stack_ra = 4;
913
914   if (stack_ra <= eq->offset && eq->offset < stack_ra + 4)
915     ferr(po, "reference to ra? %d %d\n", eq->offset, stack_ra);
916
917   if (eq->offset > stack_ra) {
918     arg_i = (eq->offset - stack_ra - 4) / 4;
919     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
920       ferr(po, "offset %d doesn't map to any arg\n", eq->offset);
921
922     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
923       if (g_func_pp.arg[i].reg != NULL)
924         continue;
925       if (arg_s == arg_i)
926         break;
927       arg_s++;
928     }
929     if (i == g_func_pp.argc)
930       ferr(po, "arg %d not in prototype?\n", arg_i);
931     if (is_lea)
932       ferr(po, "lea to arg?\n");
933
934     snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
935   }
936   else {
937     if (g_bp_stack == 0)
938       ferr(po, "bp_stack access after it was not detected\n");
939
940     sf_ofs = g_bp_stack + eq->offset;
941     if (sf_ofs < 0)
942       ferr(po, "bp_stack offset %d/%d\n", eq->offset, g_bp_stack);
943
944     if (is_lea)
945       prefix = "(u32)&";
946
947     switch (lmod)
948     {
949     case OPLM_BYTE:
950       snprintf(buf, buf_size, "%ssf.b[%d]", prefix, sf_ofs);
951       break;
952     case OPLM_WORD:
953       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
954       break;
955     case OPLM_DWORD:
956       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
957       break;
958     default:
959       ferr(po, "bp_stack bad lmod: %d\n", lmod);
960     }
961   }
962 }
963
964 static char *out_src_opr(char *buf, size_t buf_size,
965         struct parsed_op *po, struct parsed_opr *popr, int is_lea)
966 {
967   char tmp1[256], tmp2[256];
968   char expr[256];
969   int ret;
970
971   switch (popr->type) {
972   case OPT_REG:
973     if (is_lea)
974       ferr(po, "lea from reg?\n");
975
976     switch (popr->lmod) {
977     case OPLM_DWORD:
978       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
979       break;
980     case OPLM_WORD:
981       snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
982       break;
983     case OPLM_BYTE:
984       if (popr->name[1] == 'h') // XXX..
985         snprintf(buf, buf_size, "(u8)(%s >> 8)", opr_reg_p(po, popr));
986       else
987         snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
988       break;
989     default:
990       ferr(po, "invalid src lmod: %d\n", popr->lmod);
991     }
992     break;
993
994   case OPT_REGMEM:
995     if (parse_stack_el(popr->name)) {
996       bg_frame_access(po, popr->lmod, buf, buf_size,
997         popr->name, 1, is_lea);
998       break;
999     }
1000
1001     strcpy(expr, popr->name);
1002     if (strchr(expr, '[')) {
1003       // special case: '[' can only be left for label[reg] form
1004       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
1005       if (ret != 2)
1006         ferr(po, "parse failure for '%s'\n", expr);
1007       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
1008     }
1009
1010     // XXX: do we need more parsing?
1011     if (is_lea) {
1012       snprintf(buf, buf_size, "%s", expr);
1013       break;
1014     }
1015
1016     snprintf(buf, buf_size, "%s(%s)",
1017       lmod_cast_u_ptr(po, popr->lmod), expr);
1018     break;
1019
1020   case OPT_LABEL:
1021     if (is_lea)
1022       snprintf(buf, buf_size, "(u32)&%s", popr->name);
1023     else
1024       snprintf(buf, buf_size, "(u32)%s", popr->name);
1025     break;
1026
1027   case OPT_OFFSET:
1028     if (is_lea)
1029       ferr(po, "lea an offset?\n");
1030     snprintf(buf, buf_size, "(u32)&%s", popr->name);
1031     break;
1032
1033   case OPT_CONST:
1034     if (is_lea)
1035       ferr(po, "lea from const?\n");
1036
1037     printf_number(buf, buf_size, popr->val);
1038     break;
1039
1040   default:
1041     ferr(po, "invalid src type: %d\n", popr->type);
1042   }
1043
1044   return buf;
1045 }
1046
1047 static char *out_dst_opr(char *buf, size_t buf_size,
1048         struct parsed_op *po, struct parsed_opr *popr)
1049 {
1050   switch (popr->type) {
1051   case OPT_REG:
1052     switch (popr->lmod) {
1053     case OPLM_DWORD:
1054       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1055       break;
1056     case OPLM_WORD:
1057       // ugh..
1058       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
1059       break;
1060     case OPLM_BYTE:
1061       // ugh..
1062       if (popr->name[1] == 'h') // XXX..
1063         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
1064       else
1065         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
1066       break;
1067     default:
1068       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
1069     }
1070     break;
1071
1072   case OPT_REGMEM:
1073     if (parse_stack_el(popr->name)) {
1074       bg_frame_access(po, popr->lmod, buf, buf_size,
1075         popr->name, 0, 0);
1076       break;
1077     }
1078
1079     return out_src_opr(buf, buf_size, po, popr, 0);
1080
1081   case OPT_LABEL:
1082     snprintf(buf, buf_size, "%s", popr->name);
1083     break;
1084
1085   default:
1086     ferr(po, "invalid dst type: %d\n", popr->type);
1087   }
1088
1089   return buf;
1090 }
1091
1092 static enum parsed_flag_op split_cond(struct parsed_op *po,
1093   enum op_op op, int *is_inv)
1094 {
1095   *is_inv = 0;
1096
1097   switch (op) {
1098   case OP_JO:
1099     return PFO_O;
1100   case OP_JC:
1101     return PFO_C;
1102   case OP_JZ:
1103     return PFO_Z;
1104   case OP_JBE:
1105     return PFO_BE;
1106   case OP_JS:
1107     return PFO_S;
1108   case OP_JP:
1109     return PFO_P;
1110   case OP_JL:
1111     return PFO_L;
1112   case OP_JLE:
1113     return PFO_LE;
1114
1115   case OP_JNO:
1116     *is_inv = 1;
1117     return PFO_O;
1118   case OP_JNC:
1119     *is_inv = 1;
1120     return PFO_C;
1121   case OP_JNZ:
1122     *is_inv = 1;
1123     return PFO_Z;
1124   case OP_JA:
1125     *is_inv = 1;
1126     return PFO_BE;
1127   case OP_JNS:
1128     *is_inv = 1;
1129     return PFO_S;
1130   case OP_JNP:
1131     *is_inv = 1;
1132     return PFO_P;
1133   case OP_JGE:
1134     *is_inv = 1;
1135     return PFO_L;
1136   case OP_JG:
1137     *is_inv = 1;
1138     return PFO_LE;
1139
1140   case OP_ADC:
1141   case OP_SBB:
1142     return PFO_C;
1143
1144   default:
1145     ferr(po, "split_cond: bad op %d\n", op);
1146     return -1;
1147   }
1148 }
1149
1150 static void out_test_for_cc(char *buf, size_t buf_size,
1151   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1152   enum opr_lenmod lmod, const char *expr)
1153 {
1154   const char *cast, *scast;
1155
1156   cast = lmod_cast_u(po, lmod);
1157   scast = lmod_cast_s(po, lmod);
1158
1159   switch (pfo) {
1160   case PFO_Z:
1161   case PFO_BE: // CF=1||ZF=1; CF=0
1162     snprintf(buf, buf_size, "(%s%s %s 0)",
1163       cast, expr, is_inv ? "!=" : "==");
1164     break;
1165
1166   case PFO_S:
1167   case PFO_L: // SF!=OF; OF=0
1168     snprintf(buf, buf_size, "(%s%s %s 0)",
1169       scast, expr, is_inv ? ">=" : "<");
1170     break;
1171
1172   case PFO_LE: // ZF=1||SF!=OF; OF=0
1173     snprintf(buf, buf_size, "(%s%s %s 0)",
1174       scast, expr, is_inv ? ">" : "<=");
1175     break;
1176
1177   default:
1178     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1179   }
1180 }
1181
1182 static void out_cmp_for_cc(char *buf, size_t buf_size,
1183   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1184   enum opr_lenmod lmod, const char *expr1, const char *expr2)
1185 {
1186   const char *cast, *scast;
1187
1188   cast = lmod_cast_u(po, lmod);
1189   scast = lmod_cast_s(po, lmod);
1190
1191   switch (pfo) {
1192   case PFO_C:
1193     // note: must be unsigned compare
1194     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1195       cast, expr1, is_inv ? ">=" : "<", cast, expr2);
1196     break;
1197
1198   case PFO_Z:
1199     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1200       cast, expr1, is_inv ? "!=" : "==", cast, expr2);
1201     break;
1202
1203   case PFO_BE: // !a
1204     // note: must be unsigned compare
1205     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1206       cast, expr1, is_inv ? ">" : "<=", cast, expr2);
1207     break;
1208
1209   // note: must be signed compare
1210   case PFO_S:
1211     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1212       scast, expr1, expr2, is_inv ? ">=" : "<");
1213     break;
1214
1215   case PFO_L: // !ge
1216     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1217       scast, expr1, is_inv ? ">=" : "<", scast, expr2);
1218     break;
1219
1220   case PFO_LE:
1221     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1222       scast, expr1, is_inv ? ">" : "<=", scast, expr2);
1223     break;
1224
1225   default:
1226     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1227   }
1228 }
1229
1230 static void out_cmp_test(char *buf, size_t buf_size,
1231   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
1232 {
1233   char buf1[256], buf2[256], buf3[256];
1234
1235   if (po->op == OP_TEST) {
1236     if (IS(opr_name(po, 0), opr_name(po, 1))) {
1237       out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
1238     }
1239     else {
1240       out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1241       out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
1242       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1243     }
1244     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
1245       po->operand[0].lmod, buf3);
1246   }
1247   else if (po->op == OP_CMP) {
1248     out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1249     out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
1250     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv,
1251       po->operand[0].lmod, buf2, buf3);
1252   }
1253   else
1254     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1255 }
1256
1257 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
1258         struct parsed_opr *popr2)
1259 {
1260   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1261     ferr(po, "missing lmod for both operands\n");
1262
1263   if (popr1->lmod == OPLM_UNSPEC)
1264     popr1->lmod = popr2->lmod;
1265   else if (popr2->lmod == OPLM_UNSPEC)
1266     popr2->lmod = popr1->lmod;
1267   else if (popr1->lmod != popr2->lmod)
1268     ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
1269 }
1270
1271 static const char *op_to_c(struct parsed_op *po)
1272 {
1273   switch (po->op)
1274   {
1275     case OP_ADD:
1276     case OP_ADC:
1277       return "+";
1278     case OP_SUB:
1279     case OP_SBB:
1280       return "-";
1281     case OP_AND:
1282       return "&";
1283     case OP_OR:
1284       return "|";
1285     case OP_XOR:
1286       return "^";
1287     case OP_SHL:
1288       return "<<";
1289     case OP_SHR:
1290       return ">>";
1291     case OP_MUL:
1292     case OP_IMUL:
1293       return "*";
1294     default:
1295       ferr(po, "op_to_c was supplied with %d\n", po->op);
1296   }
1297 }
1298
1299 static void set_flag_no_dup(struct parsed_op *po, enum op_flags flag,
1300   enum op_flags flag_check)
1301 {
1302   if (po->flags & flag)
1303     ferr(po, "flag %x already set\n", flag);
1304   if (po->flags & flag_check)
1305     ferr(po, "flag_check %x already set\n", flag_check);
1306
1307   po->flags |= flag;
1308 }
1309
1310 static int scan_for_pop(int i, int opcnt, const char *reg,
1311   int magic, int depth, int *maxdepth, int do_flags)
1312 {
1313   struct parsed_op *po;
1314   int ret = 0;
1315
1316   for (; i < opcnt; i++) {
1317     po = &ops[i];
1318     if (po->cc_scratch == magic)
1319       break; // already checked
1320     po->cc_scratch = magic;
1321
1322     if (po->flags & OPF_TAIL)
1323       return -1; // deadend
1324
1325     if (po->flags & OPF_RMD)
1326       continue;
1327
1328     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
1329       if (po->bt_i < 0) {
1330         ferr(po, "dead branch\n");
1331         return -1;
1332       }
1333
1334       if (po->flags & OPF_CC) {
1335         ret |= scan_for_pop(po->bt_i, opcnt, reg, magic,
1336                  depth, maxdepth, do_flags);
1337         if (ret < 0)
1338           return ret; // dead end
1339       }
1340       else {
1341         i = po->bt_i - 1;
1342       }
1343       continue;
1344     }
1345
1346     if ((po->op == OP_POP || po->op == OP_PUSH)
1347         && po->operand[0].type == OPT_REG
1348         && IS(po->operand[0].name, reg))
1349     {
1350       if (po->op == OP_PUSH) {
1351         depth++;
1352         if (depth > *maxdepth)
1353           *maxdepth = depth;
1354         if (do_flags)
1355           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1356       }
1357       else if (depth == 0) {
1358         if (do_flags)
1359           set_flag_no_dup(po, OPF_RMD, OPF_RSAVE);
1360         return 1;
1361       }
1362       else {
1363         depth--;
1364         if (depth < 0) // should not happen
1365           ferr(po, "fail with depth\n");
1366         if (do_flags)
1367           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1368       }
1369     }
1370   }
1371
1372   return ret;
1373 }
1374
1375 // scan for pop starting from 'ret' op (all paths)
1376 static int scan_for_pop_ret(int i, int opcnt, const char *reg,
1377   int flag_set)
1378 {
1379   int found = 0;
1380   int j;
1381
1382   for (; i < opcnt; i++) {
1383     if (!(ops[i].flags & OPF_TAIL))
1384       continue;
1385
1386     for (j = i - 1; j >= 0; j--) {
1387       if (ops[j].flags & OPF_RMD)
1388         continue;
1389       if (ops[j].flags & OPF_JMP)
1390         return -1;
1391
1392       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1393           && IS(ops[j].operand[0].name, reg))
1394       {
1395         found = 1;
1396         ops[j].flags |= flag_set;
1397         break;
1398       }
1399
1400       if (g_labels[j][0] != 0)
1401         return -1;
1402     }
1403   }
1404
1405   return found ? 0 : -1;
1406 }
1407
1408 // is operand 'opr modified' by parsed_op 'po'?
1409 static int is_opr_modified(const struct parsed_opr *opr,
1410   const struct parsed_op *po)
1411 {
1412   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1413     return 0;
1414
1415   if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1416     if (po->regmask_dst & (1 << opr->reg))
1417       return 1;
1418     else
1419       return 0;
1420   }
1421
1422   return IS(po->operand[0].name, opr->name);
1423 }
1424
1425 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
1426 static int is_any_opr_modified(const struct parsed_op *po_test,
1427   const struct parsed_op *po)
1428 {
1429   int i;
1430
1431   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1432     return 0;
1433
1434   if (po_test->regmask_src & po->regmask_dst)
1435     return 1;
1436
1437   for (i = 0; i < po_test->operand_cnt; i++)
1438     if (IS(po_test->operand[i].name, po->operand[0].name))
1439       return 1;
1440
1441   return 0;
1442 }
1443
1444 // scan for any po_test operand modification in range given
1445 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt)
1446 {
1447   for (; i < opcnt; i++) {
1448     if (is_any_opr_modified(po_test, &ops[i]))
1449       return i;
1450   }
1451
1452   return -1;
1453 }
1454
1455 // scan for po_test operand[0] modification in range given
1456 static int scan_for_mod_opr0(struct parsed_op *po_test,
1457   int i, int opcnt)
1458 {
1459   for (; i < opcnt; i++) {
1460     if (is_opr_modified(&po_test->operand[0], &ops[i]))
1461       return i;
1462   }
1463
1464   return -1;
1465 }
1466
1467 static int scan_for_flag_set(int i)
1468 {
1469   for (; i >= 0; i--) {
1470     if (ops[i].flags & OPF_FLAGS)
1471       return i;
1472
1473     if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1474       return -1;
1475     if (g_labels[i][0] != 0)
1476       return -1;
1477   }
1478
1479   return -1;
1480 }
1481
1482 // scan back for cdq, if anything modifies edx, fail
1483 static int scan_for_cdq_edx(int i)
1484 {
1485   for (; i >= 0; i--) {
1486     if (ops[i].op == OP_CDQ)
1487       return i;
1488
1489     if (ops[i].regmask_dst & (1 << xDX))
1490       return -1;
1491     if (g_labels[i][0] != 0)
1492       return -1;
1493   }
1494
1495   return -1;
1496 }
1497
1498 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1499 {
1500   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
1501   struct parsed_opr *last_arith_dst = NULL;
1502   char buf1[256], buf2[256], buf3[256];
1503   struct parsed_proto *pp, *pp_tmp;
1504   const char *tmpname;
1505   enum parsed_flag_op pfo;
1506   int save_arg_vars = 0;
1507   int cmp_result_vars = 0;
1508   int need_mul_var = 0;
1509   int had_decl = 0;
1510   int regmask_save = 0;
1511   int regmask_arg = 0;
1512   int regmask = 0;
1513   int pfomask = 0;
1514   int depth = 0;
1515   int no_output;
1516   int dummy;
1517   int arg;
1518   int i, j;
1519   int reg;
1520   int ret;
1521
1522   g_bp_frame = g_bp_stack = 0;
1523
1524   ret = proto_parse(fhdr, funcn, &g_func_pp);
1525   if (ret)
1526     ferr(ops, "proto_parse failed for '%s'\n", funcn);
1527
1528   fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
1529   for (i = 0; i < g_func_pp.argc; i++) {
1530     if (i > 0)
1531       fprintf(fout, ", ");
1532     fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
1533   }
1534   fprintf(fout, ")\n{\n");
1535
1536   // pass1:
1537   // - handle ebp frame, remove ops related to it
1538   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
1539       && ops[1].op == OP_MOV
1540       && IS(opr_name(&ops[1], 0), "ebp")
1541       && IS(opr_name(&ops[1], 1), "esp"))
1542   {
1543     int ecx_push = 0;
1544
1545     g_bp_frame = 1;
1546     ops[0].flags |= OPF_RMD;
1547     ops[1].flags |= OPF_RMD;
1548
1549     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1550       g_bp_stack = opr_const(&ops[2], 1);
1551       ops[2].flags |= OPF_RMD;
1552     }
1553     else {
1554       // another way msvc builds stack frame..
1555       i = 2;
1556       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
1557         g_bp_stack += 4;
1558         ops[i].flags |= OPF_RMD;
1559         ecx_push++;
1560         i++;
1561       }
1562     }
1563
1564     i = 2;
1565     do {
1566       for (; i < opcnt; i++)
1567         if (ops[i].op == OP_RET)
1568           break;
1569       if (ops[i - 1].op != OP_POP || !IS(opr_name(&ops[i - 1], 0), "ebp"))
1570         ferr(&ops[i - 1], "'pop ebp' expected\n");
1571       ops[i - 1].flags |= OPF_RMD;
1572
1573       if (g_bp_stack != 0) {
1574         if (ops[i - 2].op != OP_MOV
1575             || !IS(opr_name(&ops[i - 2], 0), "esp")
1576             || !IS(opr_name(&ops[i - 2], 1), "ebp"))
1577         {
1578           ferr(&ops[i - 2], "esp restore expected\n");
1579         }
1580         ops[i - 2].flags |= OPF_RMD;
1581
1582         if (ecx_push && ops[i - 3].op == OP_POP
1583           && IS(opr_name(&ops[i - 3], 0), "ecx"))
1584         {
1585           ferr(&ops[i - 3], "unexpected ecx pop\n");
1586         }
1587       }
1588
1589       i++;
1590     } while (i < opcnt);
1591   }
1592
1593   // pass2:
1594   // - resolve all branches
1595   for (i = 0; i < opcnt; i++) {
1596     po = &ops[i];
1597     po->bt_i = -1;
1598
1599     if ((po->flags & OPF_RMD) || !(po->flags & OPF_JMP)
1600         || po->op == OP_CALL || po->op == OP_RET)
1601       continue;
1602
1603     for (j = 0; j < opcnt; j++) {
1604       if (g_labels[j][0] && IS(po->operand[0].name, g_labels[j])) {
1605         po->bt_i = j;
1606         po->lrl = g_label_refs[j];
1607         g_label_refs[j] = po;
1608         break;
1609       }
1610     }
1611
1612     if (po->bt_i == -1) {
1613       // assume tail call
1614       po->op = OP_CALL;
1615       po->flags |= OPF_TAIL;
1616     }
1617   }
1618
1619   // pass3:
1620   // - process calls
1621   for (i = 0; i < opcnt; i++) {
1622     po = &ops[i];
1623     if (po->flags & OPF_RMD)
1624       continue;
1625
1626     if (po->op == OP_CALL)
1627     {
1628       pp = malloc(sizeof(*pp));
1629       my_assert_not(pp, NULL);
1630       tmpname = opr_name(&ops[i], 0);
1631       ret = proto_parse(fhdr, tmpname, pp);
1632       if (ret)
1633         ferr(po, "proto_parse failed for '%s'\n", tmpname);
1634
1635       for (arg = 0; arg < pp->argc; arg++)
1636         if (pp->arg[arg].reg == NULL)
1637           break;
1638
1639       for (j = i - 1; j >= 0 && arg < pp->argc; j--) {
1640         if (ops[j].op == OP_CALL) {
1641           pp_tmp = ops[j].datap;
1642           if (pp_tmp == NULL)
1643             ferr(po, "arg collect hit unparsed call\n");
1644           if (pp_tmp->argc_stack > 0)
1645             ferr(po, "arg collect hit '%s' with %d stack args\n",
1646               opr_name(&ops[j], 0), pp_tmp->argc_stack);
1647         }
1648         else if ((ops[j].flags & OPF_TAIL)
1649             || (ops[j].flags & (OPF_JMP|OPF_CC)) == OPF_JMP)
1650         {
1651           break;
1652         }
1653
1654         if (ops[j].op == OP_PUSH) {
1655           pp->arg[arg].datap = &ops[j];
1656           ret = scan_for_mod(&ops[j], j + 1, i);
1657           if (ret >= 0) {
1658             // mark this push as one that needs operand saving
1659             ops[j].argmask |= 1 << arg;
1660             save_arg_vars |= 1 << arg;
1661           }
1662           else
1663             ops[j].flags |= OPF_RMD;
1664
1665           // next arg
1666           for (arg++; arg < pp->argc; arg++)
1667             if (pp->arg[arg].reg == NULL)
1668               break;
1669         }
1670
1671         if (g_labels[j][0] != 0) {
1672           if (j > 0 && ((ops[j - 1].flags & OPF_TAIL)
1673             || (ops[j - 1].flags & (OPF_JMP|OPF_CC)) == OPF_JMP))
1674           {
1675             // follow the branch in reverse
1676             if (g_label_refs[j] == NULL)
1677               ferr(po, "no refs for '%s'?\n", g_labels[j]);
1678             if (g_label_refs[j]->lrl != NULL)
1679               ferr(po, "unhandled multiple fefs to '%s'\n", g_labels[j]);
1680             j = (g_label_refs[j] - ops) + 1;
1681             continue;
1682           }
1683           break;
1684         }
1685       }
1686       if (arg < pp->argc)
1687         ferr(po, "arg collect failed for '%s'\n", tmpname);
1688       po->datap = pp;
1689     }
1690   }
1691
1692   // pass4:
1693   // - find POPs for PUSHes, rm both
1694   // - scan for all used registers
1695   // - find flag set ops for their users
1696   for (i = 0; i < opcnt; i++) {
1697     po = &ops[i];
1698     if (po->flags & OPF_RMD)
1699       continue;
1700
1701     if (po->op == OP_PUSH
1702         && po->argmask == 0 && !(po->flags & OPF_RSAVE)
1703         && po->operand[0].type == OPT_REG)
1704     {
1705       reg = po->operand[0].reg;
1706       if (reg < 0)
1707         ferr(po, "reg not set for push?\n");
1708
1709       depth = 0;
1710       ret = scan_for_pop(i + 1, opcnt,
1711               po->operand[0].name, i + opcnt, 0, &depth, 0);
1712       if (ret == 1) {
1713         if (depth > 1)
1714           ferr(po, "too much depth: %d\n", depth);
1715         if (depth > 0)
1716           regmask_save |= 1 << reg;
1717
1718         po->flags |= OPF_RMD;
1719         scan_for_pop(i + 1, opcnt, po->operand[0].name,
1720           i + opcnt * 2, 0, &depth, 1);
1721         continue;
1722       }
1723       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
1724       if (ret == 0) {
1725         arg = OPF_RMD;
1726         if (regmask & (1 << reg)) {
1727           if (regmask_save & (1 << reg))
1728             ferr(po, "%s already saved?\n", po->operand[0].name);
1729           arg = OPF_RSAVE;
1730         }
1731         po->flags |= arg;
1732         scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, arg);
1733         continue;
1734       }
1735     }
1736
1737     regmask |= po->regmask_src | po->regmask_dst;
1738
1739     if (po->flags & OPF_CC)
1740     {
1741       ret = scan_for_flag_set(i - 1);
1742       if (ret < 0)
1743         ferr(po, "unable to trace flag setter\n");
1744
1745       tmp_op = &ops[ret]; // flag setter
1746       pfo = split_cond(po, po->op, &dummy);
1747       pfomask = 0;
1748
1749       // to get nicer code, we try to delay test and cmp;
1750       // if we can't because of operand modification, or if we
1751       // have math op, make it calculate flags explicitly
1752       if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP) {
1753         if (scan_for_mod(tmp_op, ret + 1, i) >= 0)
1754           pfomask = 1 << pfo;
1755       }
1756       else {
1757         if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
1758             || scan_for_mod_opr0(tmp_op, ret + 1, i) >= 0)
1759           pfomask = 1 << pfo;
1760       }
1761       if (pfomask) {
1762         tmp_op->pfomask |= pfomask;
1763         cmp_result_vars |= pfomask;
1764         po->datap = tmp_op;
1765       }
1766
1767       if (po->op == OP_ADC || po->op == OP_SBB)
1768         cmp_result_vars |= 1 << PFO_C;
1769     }
1770     else if (po->op == OP_MUL
1771       || (po->op == OP_IMUL && po->operand_cnt == 1))
1772     {
1773       need_mul_var = 1;
1774     }
1775   }
1776
1777   // declare stack frame
1778   if (g_bp_stack)
1779     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
1780       (g_bp_stack + 3) / 4, (g_bp_stack + 1) / 2, g_bp_stack);
1781
1782   // declare arg-registers
1783   for (i = 0; i < g_func_pp.argc; i++) {
1784     if (g_func_pp.arg[i].reg != NULL) {
1785       reg = char_array_i(regs_r32,
1786               ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
1787       if (reg < 0)
1788         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
1789
1790       regmask_arg |= 1 << reg;
1791       fprintf(fout, "  u32 %s = (u32)a%d;\n",
1792         g_func_pp.arg[i].reg, i + 1);
1793       had_decl = 1;
1794     }
1795   }
1796
1797   // declare other regs - special case for eax
1798   if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
1799     fprintf(fout, "  u32 eax = 0;\n");
1800     had_decl = 1;
1801   }
1802
1803   regmask &= ~regmask_arg;
1804   regmask &= ~(1 << xSP);
1805   if (g_bp_frame)
1806     regmask &= ~(1 << xBP);
1807   if (regmask) {
1808     for (reg = 0; reg < 8; reg++) {
1809       if (regmask & (1 << reg)) {
1810         fprintf(fout, "  u32 %s;\n", regs_r32[reg]);
1811         had_decl = 1;
1812       }
1813     }
1814   }
1815
1816   if (regmask_save) {
1817     for (reg = 0; reg < 8; reg++) {
1818       if (regmask_save & (1 << reg)) {
1819         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
1820         had_decl = 1;
1821       }
1822     }
1823   }
1824
1825   if (save_arg_vars) {
1826     for (reg = 0; reg < 32; reg++) {
1827       if (save_arg_vars & (1 << reg)) {
1828         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
1829         had_decl = 1;
1830       }
1831     }
1832   }
1833
1834   if (cmp_result_vars) {
1835     for (i = 0; i < 8; i++) {
1836       if (cmp_result_vars & (1 << i)) {
1837         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
1838         had_decl = 1;
1839       }
1840     }
1841   }
1842
1843   if (need_mul_var) {
1844     fprintf(fout, "  u64 mul_tmp;\n");
1845     had_decl = 1;
1846   }
1847
1848   if (had_decl)
1849     fprintf(fout, "\n");
1850
1851   // output ops
1852   for (i = 0; i < opcnt; i++)
1853   {
1854     if (g_labels[i][0] != 0 && g_label_refs[i] != NULL)
1855       fprintf(fout, "\n%s:\n", g_labels[i]);
1856
1857     po = &ops[i];
1858     if (po->flags & OPF_RMD)
1859       continue;
1860
1861     no_output = 0;
1862
1863     #define assert_operand_cnt(n_) \
1864       if (po->operand_cnt != n_) \
1865         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
1866
1867     // conditional/flag using op?
1868     if (po->flags & OPF_CC)
1869     {
1870       int is_delayed = 0;
1871       int is_inv = 0;
1872
1873       pfo = split_cond(po, po->op, &is_inv);
1874
1875       // we go through all this trouble to avoid using parsed_flag_op,
1876       // which makes generated code much nicer
1877       if (delayed_flag_op != NULL)
1878       {
1879         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_inv);
1880         is_delayed = 1;
1881       }
1882       else if (last_arith_dst != NULL
1883         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
1884       {
1885         out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
1886         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
1887           last_arith_dst->lmod, buf3);
1888         is_delayed = 1;
1889       }
1890       else if (po->datap != NULL) {
1891         // use preprocessed results
1892         tmp_op = po->datap;
1893         if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
1894           ferr(po, "not prepared for pfo %d\n", pfo);
1895
1896         // note: is_inv was not yet applied
1897         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
1898           is_inv ? "!" : "", parsed_flag_op_names[pfo]);
1899       }
1900       else {
1901         ferr(po, "all methods of finding comparison failed\n");
1902       }
1903  
1904       if (po->flags & OPF_JMP) {
1905         fprintf(fout, "  if %s\n", buf1);
1906       }
1907       else if (po->op == OP_ADC || po->op == OP_SBB) {
1908         if (is_delayed)
1909           fprintf(fout, "  cond_%s = %s;\n",
1910             parsed_flag_op_names[pfo], buf1);
1911       }
1912       else if (po->flags & OPF_DATA) { // SETcc
1913         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
1914         fprintf(fout, "  %s = %s;", buf2, buf1);
1915       }
1916       else {
1917         ferr(po, "unhandled conditional op\n");
1918       }
1919     }
1920
1921     pfomask = po->pfomask;
1922
1923     switch (po->op)
1924     {
1925       case OP_MOV:
1926         assert_operand_cnt(2);
1927         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1928         fprintf(fout, "  %s = %s;",
1929             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1930             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1931         break;
1932
1933       case OP_LEA:
1934         assert_operand_cnt(2);
1935         po->operand[1].lmod = OPLM_DWORD; // always
1936         fprintf(fout, "  %s = %s;",
1937             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1938             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
1939         break;
1940
1941       case OP_MOVZX:
1942         assert_operand_cnt(2);
1943         fprintf(fout, "  %s = %s;",
1944             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1945             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1946         break;
1947
1948       case OP_MOVSX:
1949         assert_operand_cnt(2);
1950         switch (po->operand[1].lmod) {
1951         case OPLM_BYTE:
1952           strcpy(buf3, "(s8)");
1953           break;
1954         case OPLM_WORD:
1955           strcpy(buf3, "(s16)");
1956           break;
1957         default:
1958           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
1959         }
1960         fprintf(fout, "  %s = %s%s;",
1961             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1962             buf3,
1963             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1964         break;
1965
1966       case OP_NOT:
1967         assert_operand_cnt(1);
1968         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1969         fprintf(fout, "  %s = ~%s;", buf1, buf1);
1970         break;
1971
1972       case OP_CDQ:
1973         assert_operand_cnt(2);
1974         fprintf(fout, "  %s = (s32)%s >> 31;",
1975             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1976             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1977         strcpy(g_comment, "cdq");
1978         break;
1979
1980       case OP_STOS:
1981         // assumes DF=0
1982         assert_operand_cnt(3);
1983         if (po->flags & OPF_REP) {
1984           fprintf(fout, "  for (; ecx != 0; ecx--, edi += %d)\n",
1985             lmod_bytes(po, po->operand[0].lmod));
1986           fprintf(fout, "    %sedi = eax;",
1987             lmod_cast_u_ptr(po, po->operand[0].lmod));
1988           strcpy(g_comment, "rep stos");
1989         }
1990         else {
1991           fprintf(fout, "    %sedi = eax; edi += %d;",
1992             lmod_cast_u_ptr(po, po->operand[0].lmod),
1993             lmod_bytes(po, po->operand[0].lmod));
1994           strcpy(g_comment, "stos");
1995         }
1996         break;
1997
1998       case OP_MOVS:
1999         // assumes DF=0
2000         assert_operand_cnt(3);
2001         j = lmod_bytes(po, po->operand[0].lmod);
2002         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
2003         if (po->flags & OPF_REP) {
2004           fprintf(fout,
2005             "  for (; ecx != 0; ecx--, edi += %d, esi += %d)\n",
2006             j, j);
2007           fprintf(fout,
2008             "    %sedi = %sesi;", buf1, buf1);
2009           strcpy(g_comment, "rep movs");
2010         }
2011         else {
2012           fprintf(fout, "    %sedi = %sesi; edi += %d; esi += %d;",
2013             buf1, buf1, j, j);
2014           strcpy(g_comment, "movs");
2015         }
2016         break;
2017
2018       // arithmetic w/flags
2019       case OP_ADD:
2020       case OP_SUB:
2021       case OP_AND:
2022       case OP_OR:
2023         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2024         // fallthrough
2025       case OP_SHL:
2026       case OP_SHR:
2027       dualop_arith:
2028         assert_operand_cnt(2);
2029         fprintf(fout, "  %s %s= %s;",
2030             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2031             op_to_c(po),
2032             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2033         last_arith_dst = &po->operand[0];
2034         delayed_flag_op = NULL;
2035         break;
2036
2037       case OP_SAR:
2038         assert_operand_cnt(2);
2039         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2040         fprintf(fout, "  %s = %s%s >> %s;", buf1,
2041           lmod_cast_s(po, po->operand[0].lmod), buf1,
2042           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2043         last_arith_dst = &po->operand[0];
2044         delayed_flag_op = NULL;
2045         break;
2046
2047       case OP_ROL:
2048       case OP_ROR:
2049         assert_operand_cnt(2);
2050         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2051         if (po->operand[1].type == OPT_CONST) {
2052           j = po->operand[1].val;
2053           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
2054           fprintf(fout, po->op == OP_ROL ?
2055             "  %s = (%s << %d) | (%s >> %d);" :
2056             "  %s = (%s >> %d) | (%s << %d);",
2057             buf1, buf1, j, buf1,
2058             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
2059         }
2060         else
2061           ferr(po, "TODO\n");
2062         last_arith_dst = &po->operand[0];
2063         delayed_flag_op = NULL;
2064         break;
2065
2066       case OP_XOR:
2067         assert_operand_cnt(2);
2068         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2069         if (IS(opr_name(po, 0), opr_name(po, 1))) {
2070           // special case for XOR
2071           fprintf(fout, "  %s = 0;",
2072             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
2073           last_arith_dst = &po->operand[0];
2074           delayed_flag_op = NULL;
2075           break;
2076         }
2077         goto dualop_arith;
2078
2079       case OP_ADC:
2080       case OP_SBB:
2081         assert_operand_cnt(2);
2082         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2083         fprintf(fout, "  %s %s= %s + cond_c;",
2084             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2085             op_to_c(po),
2086             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2087         last_arith_dst = &po->operand[0];
2088         delayed_flag_op = NULL;
2089         break;
2090
2091       case OP_INC:
2092       case OP_DEC:
2093         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2094         strcpy(buf2, po->op == OP_INC ? "++" : "--");
2095         fprintf(fout, "  %s%s;", buf1, buf2);
2096         last_arith_dst = &po->operand[0];
2097         delayed_flag_op = NULL;
2098         break;
2099
2100       case OP_NEG:
2101         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2102         out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
2103         fprintf(fout, "  %s = -%s%s;", buf1,
2104           lmod_cast_s(po, po->operand[0].lmod), buf2);
2105         last_arith_dst = &po->operand[0];
2106         delayed_flag_op = NULL;
2107         if (pfomask & (1 << PFO_C)) {
2108           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
2109           pfomask &= ~(1 << PFO_C);
2110         }
2111         break;
2112
2113       case OP_IMUL:
2114         if (po->operand_cnt == 2)
2115           goto dualop_arith;
2116         if (po->operand_cnt == 3)
2117           ferr(po, "TODO imul3\n");
2118         // fallthrough
2119       case OP_MUL:
2120         assert_operand_cnt(1);
2121         strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
2122         fprintf(fout, "  mul_tmp = %seax * %s%s;\n", buf1, buf1,
2123           out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0));
2124         fprintf(fout, "  edx = mul_tmp >> 32;\n");
2125         fprintf(fout, "  eax = mul_tmp;");
2126         last_arith_dst = NULL;
2127         delayed_flag_op = NULL;
2128         break;
2129
2130       case OP_DIV:
2131       case OP_IDIV:
2132         assert_operand_cnt(1);
2133         if (po->operand[0].lmod != OPLM_DWORD)
2134           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
2135
2136         // 32bit division is common, look for it
2137         if (scan_for_cdq_edx(i - 1) >= 0) {
2138           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2139           strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
2140             po->op == OP_IDIV));
2141           fprintf(fout, "  edx = %seax %% %s%s;\n", buf2, buf2, buf1);
2142           fprintf(fout, "  eax = %seax / %s%s;", buf2, buf2, buf1);
2143         }
2144         else
2145           ferr(po, "TODO 64bit divident\n");
2146         last_arith_dst = NULL;
2147         delayed_flag_op = NULL;
2148         break;
2149
2150       case OP_TEST:
2151       case OP_CMP:
2152         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2153         if (pfomask != 0) {
2154           for (j = 0; j < 8; j++) {
2155             if (pfomask & (1 << j)) {
2156               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
2157               fprintf(fout, "  cond_%s = %s;",
2158                 parsed_flag_op_names[j], buf1);
2159             }
2160           }
2161           pfomask = 0;
2162         }
2163         else
2164           no_output = 1;
2165         delayed_flag_op = po;
2166         break;
2167
2168       // note: we reuse OP_Jcc for SETcc, only flags differ
2169       case OP_JO ... OP_JG:
2170         if (po->flags & OPF_JMP)
2171           fprintf(fout, "    goto %s;", po->operand[0].name);
2172         // else SETcc - should already be handled
2173         break;
2174
2175       case OP_JMP:
2176         assert_operand_cnt(1);
2177         if (po->operand[0].type != OPT_LABEL)
2178           ferr(po, "unhandled call type\n");
2179
2180         fprintf(fout, "  goto %s;", po->operand[0].name);
2181         break;
2182
2183       case OP_CALL:
2184         assert_operand_cnt(1);
2185         if (po->operand[0].type != OPT_LABEL)
2186           ferr(po, "unhandled call type\n");
2187
2188         pp = po->datap;
2189         if (pp == NULL)
2190           ferr(po, "NULL pp\n");
2191
2192         fprintf(fout, "  ");
2193         if (!IS(pp->ret_type, "void")) {
2194           if (po->flags & OPF_TAIL)
2195             fprintf(fout, "return ");
2196           else
2197             fprintf(fout, "eax = ");
2198           if (strchr(pp->ret_type, '*'))
2199             fprintf(fout, "(u32)");
2200         }
2201
2202         fprintf(fout, "%s(", opr_name(po, 0));
2203         for (arg = 0; arg < pp->argc; arg++) {
2204           if (arg > 0)
2205             fprintf(fout, ", ");
2206
2207           if (strchr(pp->arg[arg].type, '*'))
2208             fprintf(fout, "(%s)", pp->arg[arg].type);
2209
2210           if (pp->arg[arg].reg != NULL) {
2211             fprintf(fout, "%s", pp->arg[arg].reg);
2212             continue;
2213           }
2214
2215           // stack arg
2216           tmp_op = pp->arg[arg].datap;
2217           if (tmp_op == NULL)
2218             ferr(po, "parsed_op missing for arg%d\n", arg);
2219           if (tmp_op->argmask) {
2220             fprintf(fout, "s_a%d", arg + 1);
2221           }
2222           else {
2223             fprintf(fout, "%s",
2224               out_src_opr(buf1, sizeof(buf1),
2225                 tmp_op, &tmp_op->operand[0], 0));
2226           }
2227         }
2228         fprintf(fout, ");");
2229
2230         if (po->flags & OPF_TAIL) {
2231           strcpy(g_comment, "tailcall");
2232           if (IS(pp->ret_type, "void"))
2233             fprintf(fout, "\n  return;");
2234         }
2235         delayed_flag_op = NULL;
2236         last_arith_dst = NULL;
2237         break;
2238
2239       case OP_RET:
2240         if (IS(g_func_pp.ret_type, "void"))
2241           fprintf(fout, "  return;");
2242         else if (strchr(g_func_pp.ret_type, '*'))
2243           fprintf(fout, "  return (%s)eax;",
2244             g_func_pp.ret_type);
2245         else
2246           fprintf(fout, "  return eax;");
2247         break;
2248
2249       case OP_PUSH:
2250         if (po->argmask) {
2251           // special case - saved func arg
2252           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2253           for (j = 0; j < 32; j++) {
2254             if (po->argmask & (1 << j))
2255               fprintf(fout, "  s_a%d = %s;", j + 1, buf1);
2256           }
2257           break;
2258         }
2259         else if (po->flags & OPF_RSAVE) {
2260           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2261           fprintf(fout, "  s_%s = %s;", buf1, buf1);
2262           break;
2263         }
2264         ferr(po, "stray push encountered\n");
2265         break;
2266
2267       case OP_POP:
2268         if (po->flags & OPF_RSAVE) {
2269           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2270           fprintf(fout, "  %s = s_%s;", buf1, buf1);
2271           break;
2272         }
2273         ferr(po, "stray pop encountered\n");
2274         break;
2275
2276       case OP_NOP:
2277         break;
2278
2279       default:
2280         no_output = 1;
2281         ferr(po, "unhandled op type %d, flags %x\n",
2282           po->op, po->flags);
2283         break;
2284     }
2285
2286     if (g_comment[0] != 0) {
2287       fprintf(fout, "  // %s", g_comment);
2288       g_comment[0] = 0;
2289       no_output = 0;
2290     }
2291     if (!no_output)
2292       fprintf(fout, "\n");
2293
2294     if (pfomask != 0)
2295         ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
2296
2297     // see is delayed flag stuff is still valid
2298     if (delayed_flag_op != NULL && delayed_flag_op != po) {
2299       if (is_any_opr_modified(delayed_flag_op, po))
2300         delayed_flag_op = NULL;
2301     }
2302
2303     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
2304       if (is_opr_modified(last_arith_dst, po))
2305         last_arith_dst = NULL;
2306     }
2307   }
2308
2309   fprintf(fout, "}\n\n");
2310
2311   // cleanup
2312   for (i = 0; i < opcnt; i++) {
2313     if (ops[i].op == OP_CALL) {
2314       pp = ops[i].datap;
2315       if (pp) {
2316         proto_release(pp);
2317         free(pp);
2318       }
2319     }
2320   }
2321   proto_release(&g_func_pp);
2322 }
2323
2324 static void set_label(int i, const char *name)
2325 {
2326   const char *p;
2327   int len;
2328
2329   len = strlen(name);
2330   p = strchr(name, ':');
2331   if (p != NULL)
2332     len = p - name;
2333
2334   if (len > sizeof(g_labels[0]) - 1)
2335     aerr("label '%s' too long: %d\n", name, len);
2336   if (g_labels[i][0] != 0)
2337     aerr("dupe label '%s'?\n", name);
2338   memcpy(g_labels[i], name, len);
2339   g_labels[i][len] = 0;
2340 }
2341
2342 // '=' needs special treatment..
2343 static char *next_word_s(char *w, size_t wsize, char *s)
2344 {
2345         size_t i;
2346
2347         s = sskip(s);
2348
2349         for (i = 0; i < wsize - 1; i++) {
2350                 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
2351                         break;
2352                 w[i] = s[i];
2353         }
2354         w[i] = 0;
2355
2356         if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
2357                 printf("warning: '%s' truncated\n", w);
2358
2359         return s + i;
2360 }
2361
2362 static int cmpstringp(const void *p1, const void *p2)
2363 {
2364   return strcmp(*(char * const *)p1, *(char * const *)p2);
2365 }
2366
2367 int main(int argc, char *argv[])
2368 {
2369   FILE *fout, *fasm, *fhdr, *frlist;
2370   char line[256];
2371   char words[16][256];
2372   int in_func = 0;
2373   int skip_func = 0;
2374   int skip_warned = 0;
2375   int eq_alloc;
2376   char **rlist = NULL;
2377   int rlist_len = 0;
2378   int rlist_alloc = 0;
2379   int verbose = 0;
2380   int arg_out;
2381   int arg = 1;
2382   int pi = 0;
2383   int len;
2384   char *p;
2385   int wordc;
2386
2387   if (argv[1] && IS(argv[1], "-v")) {
2388     verbose = 1;
2389     arg++;
2390   }
2391
2392   if (argc < arg + 3) {
2393     printf("usage:\n%s [-v] <.c> <.asm> <hdrf> [rlist]*\n",
2394       argv[0]);
2395     return 1;
2396   }
2397
2398   arg_out = arg++;
2399
2400   asmfn = argv[arg++];
2401   fasm = fopen(asmfn, "r");
2402   my_assert_not(fasm, NULL);
2403
2404   hdrfn = argv[arg++];
2405   fhdr = fopen(hdrfn, "r");
2406   my_assert_not(fhdr, NULL);
2407
2408   rlist_alloc = 64;
2409   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
2410   my_assert_not(rlist, NULL);
2411   // needs special handling..
2412   rlist[rlist_len++] = "__alloca_probe";
2413
2414   for (; arg < argc; arg++) {
2415     frlist = fopen(argv[arg], "r");
2416     my_assert_not(frlist, NULL);
2417
2418     while (fgets(line, sizeof(line), frlist)) {
2419       p = sskip(line);
2420       if (*p == 0 || *p == ';' || *p == '#')
2421         continue;
2422
2423       p = next_word(words[0], sizeof(words[0]), p);
2424       if (words[0][0] == 0)
2425         continue;
2426
2427       if (rlist_len >= rlist_alloc) {
2428         rlist_alloc = rlist_alloc * 2 + 64;
2429         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
2430         my_assert_not(rlist, NULL);
2431       }
2432       rlist[rlist_len++] = strdup(words[0]);
2433     }
2434
2435     fclose(frlist);
2436     frlist = NULL;
2437   }
2438
2439   if (rlist_len > 0)
2440     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
2441
2442   fout = fopen(argv[arg_out], "w");
2443   my_assert_not(fout, NULL);
2444
2445   eq_alloc = 128;
2446   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
2447   my_assert_not(g_eqs, NULL);
2448
2449   while (fgets(line, sizeof(line), fasm))
2450   {
2451     asmln++;
2452
2453     p = sskip(line);
2454     if (*p == 0 || *p == ';')
2455       continue;
2456
2457     memset(words, 0, sizeof(words));
2458     for (wordc = 0; wordc < 16; wordc++) {
2459       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
2460       if (*p == 0 || *p == ';') {
2461         wordc++;
2462         break;
2463       }
2464     }
2465
2466     if (wordc == 0) {
2467       // shouldn't happen
2468       awarn("wordc == 0?\n");
2469       continue;
2470     }
2471
2472     // don't care about this:
2473     if (words[0][0] == '.'
2474         || IS(words[0], "include")
2475         || IS(words[0], "assume") || IS(words[1], "segment")
2476         || IS(words[0], "align"))
2477     {
2478       continue;
2479     }
2480
2481     if (IS(words[1], "proc")) {
2482       if (in_func)
2483         aerr("proc '%s' while in_func '%s'?\n",
2484           words[0], g_func);
2485       p = words[0];
2486       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
2487         skip_func = 1;
2488       strcpy(g_func, words[0]);
2489       set_label(0, words[0]);
2490       in_func = 1;
2491       continue;
2492     }
2493
2494     if (IS(words[1], "endp")) {
2495       if (!in_func)
2496         aerr("endp '%s' while not in_func?\n", words[0]);
2497       if (!IS(g_func, words[0]))
2498         aerr("endp '%s' while in_func '%s'?\n",
2499           words[0], g_func);
2500
2501       if (in_func && !skip_func)
2502         gen_func(fout, fhdr, g_func, pi);
2503
2504       in_func = 0;
2505       skip_warned = 0;
2506       skip_func = 0;
2507       g_func[0] = 0;
2508       if (pi != 0) {
2509         memset(&ops, 0, pi * sizeof(ops[0]));
2510         memset(g_labels, 0, pi * sizeof(g_labels[0]));
2511         memset(g_label_refs, 0, pi * sizeof(g_label_refs[0]));
2512         pi = 0;
2513       }
2514       g_eqcnt = 0;
2515       continue;
2516     }
2517
2518     p = strchr(words[0], ':');
2519     if (p != NULL) {
2520       set_label(pi, words[0]);
2521       continue;
2522     }
2523
2524     if (!in_func || skip_func) {
2525       if (!skip_warned && !skip_func && g_labels[pi][0] != 0) {
2526         if (verbose)
2527           anote("skipping from '%s'\n", g_labels[pi]);
2528         skip_warned = 1;
2529       }
2530       g_labels[pi][0] = 0;
2531       continue;
2532     }
2533
2534     if (IS(words[1], "=")) {
2535       if (wordc != 5)
2536         aerr("unhandled equ, wc=%d\n", wordc);
2537       if (g_eqcnt >= eq_alloc) {
2538         eq_alloc *= 2;
2539         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
2540         my_assert_not(g_eqs, NULL);
2541       }
2542
2543       len = strlen(words[0]);
2544       if (len > sizeof(g_eqs[0].name) - 1)
2545         aerr("equ name too long: %d\n", len);
2546       strcpy(g_eqs[g_eqcnt].name, words[0]);
2547
2548       if (!IS(words[3], "ptr"))
2549         aerr("unhandled equ\n");
2550       if (IS(words[2], "dword"))
2551         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
2552       else if (IS(words[2], "word"))
2553         g_eqs[g_eqcnt].lmod = OPLM_WORD;
2554       else if (IS(words[2], "byte"))
2555         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
2556       else
2557         aerr("bad lmod: '%s'\n", words[2]);
2558
2559       g_eqs[g_eqcnt].offset = parse_number(words[4]);
2560       g_eqcnt++;
2561       continue;
2562     }
2563
2564     if (pi >= ARRAY_SIZE(ops))
2565       aerr("too many ops\n");
2566
2567     parse_op(&ops[pi], words, wordc);
2568     pi++;
2569   }
2570
2571   fclose(fout);
2572   fclose(fasm);
2573   fclose(fhdr);
2574
2575   return 0;
2576 }
2577
2578 // vim:ts=2:shiftwidth=2:expandtab