improved flag checks with tmp vars when needed, refactoring
[ia32rtools.git] / tools / translate.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "my_assert.h"
6 #include "my_str.h"
7
8 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
9 #define IS(w, y) !strcmp(w, y)
10
11 #include "protoparse.h"
12
13 const char *asmfn;
14 static int asmln;
15
16 #define awarn(fmt, ...) \
17         printf("warning:%s:%d: " fmt, asmfn, asmln, ##__VA_ARGS__)
18 #define aerr(fmt, ...) do { \
19         printf("error:%s:%d: " fmt, asmfn, asmln, ##__VA_ARGS__); \
20         exit(1); \
21 } while (0)
22
23 enum op_flags {
24         OPF_RMD    = (1 << 0), /* removed or optimized out */
25         OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
26         OPF_FLAGS  = (1 << 2), /* sets flags */
27         OPF_JMP    = (1 << 3), /* branches, ret and call */
28         OPF_CC     = (1 << 4), /* uses flags */
29 };
30
31 enum op_op {
32         OP_INVAL,
33         OP_PUSH,
34         OP_POP,
35         OP_MOV,
36         OP_LEA,
37         OP_MOVZX,
38         OP_MOVSX,
39         OP_NOT,
40         OP_RET,
41         OP_ADD,
42         OP_SUB,
43         OP_AND,
44         OP_OR,
45         OP_XOR,
46         OP_SHL,
47         OP_SHR,
48         OP_SAR,
49         OP_ADC,
50         OP_SBB,
51         OP_INC,
52         OP_DEC,
53         OP_MUL,
54         OP_IMUL,
55         OP_TEST,
56         OP_CMP,
57         OP_CALL,
58         OP_JMP,
59         OP_JO,
60         OP_JNO,
61         OP_JC,
62         OP_JNC,
63         OP_JZ,
64         OP_JNZ,
65         OP_JBE,
66         OP_JA,
67         OP_JS,
68         OP_JNS,
69         OP_JP,
70         OP_JNP,
71         OP_JL,
72         OP_JGE,
73         OP_JLE,
74         OP_JG,
75 };
76
77 enum opr_type {
78         OPT_UNSPEC,
79         OPT_REG,
80         OPT_REGMEM,
81         OPT_LABEL,
82   OPT_OFFSET,
83         OPT_CONST,
84 };
85
86 enum opr_lenmod {
87         OPLM_UNSPEC,
88         OPLM_BYTE,
89         OPLM_WORD,
90         OPLM_DWORD,
91 };
92
93 #define MAX_OPERANDS 3
94
95 struct parsed_opr {
96   enum opr_type type;
97   enum opr_lenmod lmod;
98   int reg;
99   unsigned int val;
100   char name[256];
101 };
102
103 struct parsed_op {
104   enum op_op op;
105   struct parsed_opr operand[MAX_OPERANDS];
106   unsigned int flags;
107   int operand_cnt;
108   int regmask_src;        // all referensed regs
109   int regmask_dst;
110   int pfomask;            // parsed_flag_op that can't be delayed
111   void *datap;
112 };
113
114 // datap:
115 // OP_PUSH - arg number if arg is altered before call
116 // OP_CALL - ptr to parsed_proto
117 // (OPF_CC) - point to corresponding (OPF_FLAGS)
118
119 struct parsed_equ {
120   char name[64];
121   enum opr_lenmod lmod;
122   int offset;
123 };
124
125 #define MAX_OPS 1024
126
127 static struct parsed_op ops[MAX_OPS];
128 static struct parsed_equ *g_eqs;
129 static int g_eqcnt;
130 static char g_labels[MAX_OPS][32];
131 static struct parsed_proto g_func_pp;
132 static char g_func[256];
133 static char g_comment[256];
134 static int g_bp_frame;
135 static int g_bp_stack;
136 #define ferr(op_, fmt, ...) do { \
137   printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
138     dump_op(op_), ##__VA_ARGS__); \
139   exit(1); \
140 } while (0)
141
142 #define MAX_REGS 8
143
144 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
145 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
146 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
147 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
148
149 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
150
151 // possible basic comparison types (without inversion)
152 enum parsed_flag_op {
153   PFO_O,  // 0 OF=1
154   PFO_C,  // 2 CF=1
155   PFO_Z,  // 4 ZF=1
156   PFO_BE, // 6 CF=1||ZF=1
157   PFO_S,  // 8 SF=1
158   PFO_P,  // a PF=1
159   PFO_L,  // c SF!=OF
160   PFO_LE, // e ZF=1||SF!=OF
161 };
162
163 static const char *parsed_flag_op_names[] = {
164   "o", "c", "z", "be", "s", "p", "l", "le"
165 };
166
167 static int char_array_i(const char *array[], size_t len, const char *s)
168 {
169   int i;
170
171   for (i = 0; i < len; i++)
172     if (IS(s, array[i]))
173       return i;
174
175   return -1;
176 }
177
178 static int parse_reg(int *reg_out, enum opr_lenmod *reg_lmod,
179   int *regmask, char *s)
180 {
181   char w[16];
182   int reg = xUNSPEC;
183   int c = 0;
184
185   while (*s != 0) {
186     while (my_isblank(*s) || my_issep(*s))
187       s++;
188     s = next_idt(w, sizeof(w), s);
189     if (w[0] == 0)
190       break;
191     c++;
192     reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), w);
193     if (reg >= 0) {
194       *reg_lmod = OPLM_DWORD;
195       *regmask |= 1 << reg;
196       continue;
197     }
198     reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), w);
199     if (reg >= 0) {
200       *reg_lmod = OPLM_WORD;
201       *regmask |= 1 << reg;
202       continue;
203     }
204     reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), w);
205     if (reg >= 0) {
206       *reg_lmod = OPLM_BYTE;
207       *regmask |= 1 << reg;
208       continue;
209     }
210     reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), w);
211     if (reg >= 0) {
212       *reg_lmod = OPLM_BYTE;
213       *regmask |= 1 << reg;
214       continue;
215     }
216
217     return -1;
218   }
219
220   if (c == 1) {
221     *reg_out = reg;
222     return 0;
223   }
224
225   return -1;
226 }
227
228 static long parse_number(const char *number)
229 {
230   int len = strlen(number);
231   const char *p = number;
232   char *endp = NULL;
233   int neg = 0;
234   int bad;
235   long ret;
236
237   if (*p == '-') {
238     neg = 1;
239     p++;
240   }
241   if (len > 1 && *p == '0')
242     p++;
243   if (number[len - 1] == 'h') {
244     ret = strtol(p, &endp, 16);
245     bad = (*endp != 'h');
246   }
247   else {
248     ret = strtol(p, &endp, 10);
249     bad = (*endp != 0);
250   }
251   if (bad)
252     aerr("number parsing failed\n");
253   if (neg)
254     ret = -ret;
255   return ret;
256 }
257
258 static int guess_lmod_from_name(struct parsed_opr *opr)
259 {
260   if (!strncmp(opr->name, "dword_", 6)) {
261     opr->lmod = OPLM_DWORD;
262     return 1;
263   }
264   if (!strncmp(opr->name, "word_", 5)) {
265     opr->lmod = OPLM_WORD;
266     return 1;
267   }
268   if (!strncmp(opr->name, "byte_", 5)) {
269     opr->lmod = OPLM_BYTE;
270     return 1;
271   }
272   return 0;
273 }
274
275 static int parse_operand(struct parsed_opr *opr,
276   int *regmask, int *regmask_indirect,
277         char words[16][256], int wordc, int w, unsigned int op_flags)
278 {
279   enum opr_lenmod tmplmod;
280   int tmpreg;
281   int ret, len;
282   int i;
283
284         if (w >= wordc)
285                 aerr("parse_operand w %d, wordc %d\n", w, wordc);
286
287         opr->reg = xUNSPEC;
288
289         for (i = w; i < wordc; i++) {
290                 len = strlen(words[i]);
291                 if (words[i][len - 1] == ',') {
292                         words[i][len - 1] = 0;
293                         wordc = i + 1;
294                         break;
295                 }
296         }
297
298         if (op_flags & OPF_JMP) {
299                 const char *label;
300
301                 if (wordc - w == 3 && IS(words[w + 1], "ptr"))
302                         label = words[w + 2];
303                 else if (wordc - w == 2 && IS(words[w], "short"))
304                         label = words[w + 1];
305                 else if (wordc - w == 1)
306                         label = words[w];
307                 else
308                         aerr("jump parse error");
309
310                 opr->type = OPT_LABEL;
311                 strcpy(opr->name, label);
312                 return wordc;
313         }
314
315         if (wordc - w >= 3) {
316                 if (IS(words[w + 1], "ptr")) {
317                         if (IS(words[w], "dword"))
318                                 opr->lmod = OPLM_DWORD;
319                         else if (IS(words[w], "word"))
320                                 opr->lmod = OPLM_WORD;
321                         else if (IS(words[w], "byte"))
322                                 opr->lmod = OPLM_BYTE;
323                         else
324                                 aerr("type parsing failed\n");
325                         w += 2;
326                 }
327         }
328
329         if (wordc - w == 2 && IS(words[w], "offset")) {
330                 opr->type = OPT_OFFSET;
331                 strcpy(opr->name, words[w + 1]);
332                 return wordc;
333         }
334
335   if (wordc - w != 1)
336     aerr("parse_operand 1 word expected\n");
337
338   strcpy(opr->name, words[w]);
339
340   if (words[w][0] == '[') {
341     opr->type = OPT_REGMEM;
342     ret = sscanf(words[w], "[%[^]]]", opr->name);
343     if (ret != 1)
344       aerr("[] parse failure\n");
345     // only need the regmask
346     parse_reg(&tmpreg, &tmplmod, regmask_indirect, opr->name);
347     return wordc;
348   }
349   else if (strchr(words[w], '[')) {
350     // label[reg] form
351     opr->type = OPT_REGMEM;
352     if (opr->lmod == OPLM_UNSPEC)
353       guess_lmod_from_name(opr);
354     parse_reg(&tmpreg, &tmplmod, regmask_indirect,
355       strchr(words[w], '['));
356     return wordc;
357   }
358   else if (('0' <= words[w][0] && words[w][0] <= '9')
359     || words[w][0] == '-')
360   {
361     opr->type = OPT_CONST;
362     opr->val = (unsigned int)parse_number(words[w]);
363     return wordc;
364   }
365
366   ret = parse_reg(&opr->reg, &tmplmod, regmask, opr->name);
367   if (ret == 0) {
368     opr->type = OPT_REG;
369     opr->lmod = tmplmod;
370     return wordc;
371   }
372
373   // most likely var in data segment
374   opr->type = OPT_LABEL;
375   if (opr->lmod == OPLM_UNSPEC)
376     guess_lmod_from_name(opr);
377   if (opr->lmod != OPLM_UNSPEC)
378     return wordc;
379
380   // TODO: scan data seg to determine type?
381   return wordc;
382 }
383
384 static const struct {
385   const char *name;
386   enum op_op op;
387   unsigned int minopr;
388   unsigned int maxopr;
389   unsigned int flags;
390 } op_table[] = {
391   { "push", OP_PUSH,   1, 1, 0 },
392   { "pop",  OP_POP,    1, 1, OPF_DATA },
393   { "mov" , OP_MOV,    2, 2, OPF_DATA },
394   { "lea",  OP_LEA,    2, 2, OPF_DATA },
395   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
396   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
397   { "not",  OP_NOT,    1, 1, OPF_DATA },
398   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
399   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
400   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
401   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
402   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
403   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
404   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
405   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
406   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
407 //  { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
408   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
409   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
410   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
411 //  { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
412   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
413   { "test", OP_TEST,   2, 2, OPF_FLAGS },
414   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
415   { "retn", OP_RET,    0, 1, OPF_JMP },
416   { "call", OP_CALL,   1, 1, OPF_JMP },
417   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
418   { "jo",   OP_JO,     1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
419   { "jno",  OP_JNO,    1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
420   { "jc",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
421   { "jb",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72
422   { "jnc",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
423   { "jae",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
424   { "jz",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
425   { "je",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74
426   { "jnz",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
427   { "jne",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75
428   { "jbe",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
429   { "jna",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76
430   { "ja",   OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
431   { "jnbe", OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77
432   { "js",   OP_JS,     1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
433   { "jns",  OP_JNS,    1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
434   { "jp",   OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
435   { "jpe",  OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a
436   { "jnp",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
437   { "jpo",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b
438   { "jl",   OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
439   { "jnge", OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c
440   { "jge",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
441   { "jnl",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d
442   { "jle",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
443   { "jng",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e
444   { "jg",   OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
445   { "jnle", OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f
446 };
447
448 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
449 {
450   int regmask_ind;
451   int regmask;
452   int opr = 0;
453   int w = 1;
454   int i;
455
456   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
457     if (IS(words[0], op_table[i].name))
458       break;
459   }
460
461   if (i == ARRAY_SIZE(op_table))
462     aerr("unhandled op: '%s'\n", words[0]);
463
464   op->op = op_table[i].op;
465   op->flags = op_table[i].flags;
466   op->regmask_src = op->regmask_dst = 0;
467
468   for (opr = 0; opr < op_table[i].minopr; opr++) {
469     regmask = regmask_ind = 0;
470     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
471       words, wordc, w, op->flags);
472
473     if (opr == 0 && (op->flags & OPF_DATA))
474       op->regmask_dst = regmask;
475     // for now, mark dst as src too
476     op->regmask_src |= regmask | regmask_ind;
477   }
478
479   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
480     w = parse_operand(&op->operand[opr],
481       &op->regmask_src, &op->regmask_src,
482       words, wordc, w, op->flags);
483   }
484
485   op->operand_cnt = opr;
486
487   if (w < wordc)
488     aerr("parse_op %s incomplete: %d/%d\n",
489       words[0], w, wordc);
490 }
491
492 static const char *op_name(enum op_op op)
493 {
494   int i;
495
496   for (i = 0; i < ARRAY_SIZE(op_table); i++)
497     if (op_table[i].op == op)
498       return op_table[i].name;
499
500   return "???";
501 }
502
503 // debug
504 static const char *dump_op(struct parsed_op *po)
505 {
506   static char out[128];
507   char *p = out;
508   int i;
509
510   snprintf(out, sizeof(out), "%s", op_name(po->op));
511   for (i = 0; i < po->operand_cnt; i++) {
512     p += strlen(p);
513     if (i > 0)
514       *p++ = ',';
515     snprintf(p, sizeof(out) - (p - out),
516       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
517       po->operand[i].name);
518   }
519
520   return out;
521 }
522
523 static const char *opr_name(struct parsed_op *po, int opr_num)
524 {
525   if (opr_num >= po->operand_cnt)
526     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
527   return po->operand[opr_num].name;
528 }
529
530 static unsigned int opr_const(struct parsed_op *po, int opr_num)
531 {
532   if (opr_num >= po->operand_cnt)
533     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
534   if (po->operand[opr_num].type != OPT_CONST)
535     ferr(po, "opr %d: const expected\n", opr_num);
536   return po->operand[opr_num].val;
537 }
538
539 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
540 {
541   if ((unsigned int)popr->reg >= MAX_REGS)
542     ferr(po, "invalid reg: %d\n", popr->reg);
543   return regs_r32[popr->reg];
544 }
545
546 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name)
547 {
548   int i;
549
550   for (i = 0; i < g_eqcnt; i++)
551     if (IS(g_eqs[i].name, name))
552       break;
553   if (i >= g_eqcnt)
554     ferr(po, "unresolved equ name: '%s'\n", name);
555
556   return &g_eqs[i];
557 }
558
559 static void bg_frame_access(struct parsed_op *po, enum opr_lenmod lmod,
560   char *buf, size_t buf_size, const char *bp_arg,
561   int is_src, int is_lea)
562 {
563   const char *prefix = "";
564   struct parsed_equ *eq;
565   int i, arg_i, arg_s;
566   int sf_ofs;
567
568   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
569
570   eq = equ_find(po, bp_arg);
571
572   if (eq->offset >= 0) {
573     arg_i = eq->offset / 4 - 2;
574     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
575       ferr(po, "offset %d doesn't map to any arg\n", eq->offset);
576
577     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
578       if (g_func_pp.arg[i].reg != NULL)
579         continue;
580       if (arg_s == arg_i)
581         break;
582       arg_s++;
583     }
584     if (i == g_func_pp.argc)
585       ferr(po, "arg %d not in prototype?\n", arg_i);
586     if (is_lea)
587       ferr(po, "lea to arg?\n");
588
589     snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
590   }
591   else {
592     if (g_bp_stack == 0)
593       ferr(po, "bp_stack access after it was not detected\n");
594
595     sf_ofs = g_bp_stack + eq->offset;
596     if (sf_ofs < 0)
597       ferr(po, "bp_stack offset %d/%d\n", eq->offset, g_bp_stack);
598
599     if (is_lea)
600       prefix = "&";
601
602     switch (lmod)
603     {
604     case OPLM_BYTE:
605       snprintf(buf, buf_size, "%ssf.b[%d]", prefix, sf_ofs);
606       break;
607     case OPLM_WORD:
608       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
609       break;
610     case OPLM_DWORD:
611       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
612       break;
613     default:
614       ferr(po, "bp_stack bad lmod: %d\n", lmod);
615     }
616   }
617 }
618
619 static char *out_src_opr(char *buf, size_t buf_size,
620         struct parsed_op *po, struct parsed_opr *popr, int is_lea)
621 {
622   const char *cast = "";
623   char tmp1[256], tmp2[256];
624   char expr[256];
625   int ret;
626
627   switch (popr->type) {
628   case OPT_REG:
629     if (is_lea)
630       ferr(po, "lea from reg?\n");
631
632     switch (popr->lmod) {
633     case OPLM_DWORD:
634       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
635       break;
636     case OPLM_WORD:
637       snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
638       break;
639     case OPLM_BYTE:
640       snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
641       break;
642     default:
643       ferr(po, "invalid src lmod: %d\n", popr->lmod);
644     }
645     break;
646
647   case OPT_REGMEM:
648     if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
649       bg_frame_access(po, popr->lmod, buf, buf_size,
650         popr->name + 4, 1, is_lea);
651       break;
652     }
653
654     strcpy(expr, popr->name);
655     if (strchr(expr, '[')) {
656       // special case: '[' can only be left for label[reg] form
657       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
658       if (ret != 2)
659         ferr(po, "parse failure for '%s'\n", expr);
660       snprintf(expr, sizeof(expr), "(u32)%s + %s", tmp1, tmp2);
661     }
662
663     // XXX: do we need more parsing?
664     if (is_lea) {
665       snprintf(buf, buf_size, "%s", expr);
666       break;
667     }
668
669     switch (popr->lmod) {
670     case OPLM_DWORD:
671       cast = "*(u32 *)";
672       break;
673     case OPLM_WORD:
674       cast = "*(u16 *)";
675       break;
676     case OPLM_BYTE:
677       cast = "*(u8 *)";
678       break;
679     default:
680       ferr(po, "invalid lmod: %d\n", popr->lmod);
681     }
682     snprintf(buf, buf_size, "%s(%s)", cast, expr);
683     break;
684
685   case OPT_LABEL:
686     if (is_lea)
687       snprintf(buf, buf_size, "(u32)&%s", popr->name);
688     else
689       snprintf(buf, buf_size, "%s", popr->name);
690     break;
691
692   case OPT_OFFSET:
693     if (is_lea)
694       ferr(po, "lea an offset?\n");
695     snprintf(buf, buf_size, "(u32)&%s", popr->name);
696     break;
697
698   case OPT_CONST:
699     if (is_lea)
700       ferr(po, "lea from const?\n");
701
702     snprintf(buf, buf_size, popr->val < 10 ? "%u" : "0x%02x", popr->val);
703     break;
704
705   default:
706     ferr(po, "invalid src type: %d\n", popr->type);
707   }
708
709   return buf;
710 }
711
712 static char *out_dst_opr(char *buf, size_t buf_size,
713         struct parsed_op *po, struct parsed_opr *popr)
714 {
715   switch (popr->type) {
716   case OPT_REG:
717     switch (popr->lmod) {
718     case OPLM_DWORD:
719       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
720       break;
721     case OPLM_WORD:
722       // ugh..
723       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
724       break;
725     case OPLM_BYTE:
726       // ugh..
727       snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
728       break;
729     default:
730       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
731     }
732     break;
733
734   case OPT_REGMEM:
735     if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
736       bg_frame_access(po, popr->lmod, buf, buf_size,
737         popr->name + 4, 0, 0);
738       break;
739     }
740
741     return out_src_opr(buf, buf_size, po, popr, 0);
742
743   default:
744     ferr(po, "invalid dst type: %d\n", popr->type);
745   }
746
747   return buf;
748 }
749
750 static const char *lmod_cast_u(struct parsed_op *po,
751   enum opr_lenmod lmod)
752 {
753   switch (lmod) {
754   case OPLM_DWORD:
755     return "";
756   case OPLM_WORD:
757     return "(u16)";
758   case OPLM_BYTE:
759     return "(u8)";
760   default:
761     ferr(po, "invalid lmod: %d\n", lmod);
762     return "(_invalid_)";
763   }
764 }
765
766 static const char *lmod_cast_s(struct parsed_op *po,
767   enum opr_lenmod lmod)
768 {
769   switch (lmod) {
770   case OPLM_DWORD:
771     return "(s32)";
772   case OPLM_WORD:
773     return "(s16)";
774   case OPLM_BYTE:
775     return "(s8)";
776   default:
777     ferr(po, "invalid lmod: %d\n", lmod);
778     return "(_invalid_)";
779   }
780 }
781
782 static enum parsed_flag_op split_cond(struct parsed_op *po,
783   enum op_op op, int *is_neg)
784 {
785   *is_neg = 0;
786
787   switch (op) {
788   case OP_JO:
789     return PFO_O;
790   case OP_JC:
791     return PFO_C;
792   case OP_JZ:
793     return PFO_Z;
794   case OP_JBE:
795     return PFO_BE;
796   case OP_JS:
797     return PFO_S;
798   case OP_JP:
799     return PFO_P;
800   case OP_JL:
801     return PFO_L;
802   case OP_JLE:
803     return PFO_LE;
804
805   case OP_JNO:
806     *is_neg = 1;
807     return PFO_O;
808   case OP_JNC:
809     *is_neg = 1;
810     return PFO_C;
811   case OP_JNZ:
812     *is_neg = 1;
813     return PFO_Z;
814   case OP_JA:
815     *is_neg = 1;
816     return PFO_BE;
817   case OP_JNS:
818     *is_neg = 1;
819     return PFO_S;
820   case OP_JNP:
821     *is_neg = 1;
822     return PFO_P;
823   case OP_JGE:
824     *is_neg = 1;
825     return PFO_L;
826   case OP_JG:
827     *is_neg = 1;
828     return PFO_LE;
829
830   case OP_ADC:
831   case OP_SBB:
832     return PFO_C;
833
834   default:
835     ferr(po, "split_cond: bad op %d\n", op);
836     return -1;
837   }
838 }
839
840 static void out_test_for_cc(char *buf, size_t buf_size,
841   struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
842   enum opr_lenmod lmod, const char *expr)
843 {
844   const char *cast, *scast;
845
846   cast = lmod_cast_u(po, lmod);
847   scast = lmod_cast_s(po, lmod);
848
849   switch (pfo) {
850   case PFO_Z:
851     snprintf(buf, buf_size, "(%s%s %s 0)",
852       cast, expr, is_neg ? "!=" : "==");
853     break;
854
855   case PFO_LE: // ZF=1||SF!=OF; OF=0 after test
856     snprintf(buf, buf_size, "(%s%s %s 0)",
857       scast, expr, is_neg ? ">" : "<=");
858     break;
859
860   default:
861     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
862   }
863 }
864
865 static void out_cmp_for_cc(char *buf, size_t buf_size,
866   struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
867   enum opr_lenmod lmod, const char *expr1, const char *expr2)
868 {
869   const char *cast, *scast;
870
871   cast = lmod_cast_u(po, lmod);
872   scast = lmod_cast_s(po, lmod);
873
874   switch (pfo) {
875   case PFO_Z:
876     snprintf(buf, buf_size, "(%s%s %s %s%s)",
877       cast, expr1, is_neg ? "!=" : "==", cast, expr2);
878     break;
879
880   case PFO_C:
881     // note: must be unsigned compare
882     snprintf(buf, buf_size, "(%s%s %s %s%s)",
883       cast, expr1, is_neg ? ">=" : "<", cast, expr2);
884     break;
885
886   case PFO_L:
887     // note: must be signed compare
888     snprintf(buf, buf_size, "(%s%s %s %s%s)",
889       scast, expr1, is_neg ? ">=" : "<", scast, expr2);
890     break;
891
892   default:
893     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
894   }
895 }
896
897 static void out_cmp_test(char *buf, size_t buf_size,
898   struct parsed_op *po, enum parsed_flag_op pfo, int is_neg)
899 {
900   char buf1[256], buf2[256], buf3[256];
901
902   if (po->op == OP_TEST) {
903     if (IS(opr_name(po, 0), opr_name(po, 1))) {
904       out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
905     }
906     else {
907       out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
908       out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
909       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
910     }
911     out_test_for_cc(buf, buf_size, po, pfo, is_neg,
912       po->operand[0].lmod, buf3);
913   }
914   else if (po->op == OP_CMP) {
915     out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
916     out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
917     out_cmp_for_cc(buf, buf_size, po, pfo, is_neg,
918       po->operand[0].lmod, buf2, buf3);
919   }
920   else
921     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
922 }
923
924 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
925         struct parsed_opr *popr2)
926 {
927   struct parsed_equ *eq;
928
929   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC) {
930     // lmod could be specified by equ..
931     if (!strncmp(popr1->name, "ebp+", 4)) {
932       eq = equ_find(po, popr1->name + 4);
933       popr1->lmod = eq->lmod;
934     }
935     if (!strncmp(popr2->name, "ebp+", 4)) {
936       eq = equ_find(po, popr2->name + 4);
937       popr2->lmod = eq->lmod;
938     }
939   }
940
941   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
942     ferr(po, "missing lmod for both operands\n");
943
944   if (popr1->lmod == OPLM_UNSPEC)
945     popr1->lmod = popr2->lmod;
946   else if (popr2->lmod == OPLM_UNSPEC)
947     popr2->lmod = popr1->lmod;
948   else if (popr1->lmod != popr2->lmod)
949     ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
950 }
951
952 static const char *op_to_c(struct parsed_op *po)
953 {
954   switch (po->op)
955   {
956     case OP_ADD:
957       return "+";
958     case OP_SUB:
959       return "-";
960     case OP_AND:
961       return "&";
962     case OP_OR:
963       return "|";
964     case OP_XOR:
965       return "^";
966     case OP_SHL:
967       return "<<";
968     case OP_SHR:
969       return ">>";
970     case OP_MUL:
971     case OP_IMUL:
972       return "*";
973     default:
974       ferr(po, "op_to_c was supplied with %d\n", po->op);
975   }
976 }
977
978 static int scan_for_pop(int i, int opcnt, const char *reg)
979 {
980   for (; i < opcnt; i++) {
981     if (ops[i].flags & OPF_RMD)
982       continue;
983
984     if ((ops[i].flags & OPF_JMP) || g_labels[i][0] != 0)
985       return -1;
986
987     if (ops[i].op == OP_POP && ops[i].operand[0].type == OPT_REG
988         && IS(ops[i].operand[0].name, reg))
989       return i;
990   }
991
992   return -1;
993 }
994
995 // scan for pop starting from 'ret' op (all paths)
996 static int scan_for_pop_ret(int i, int opcnt, const char *reg, int do_patch)
997 {
998   int found = 0;
999   int j;
1000
1001   for (; i < opcnt; i++) {
1002     if (ops[i].op != OP_RET)
1003       continue;
1004
1005     for (j = i - 1; j >= 0; j--) {
1006       if (ops[j].flags & OPF_RMD)
1007         continue;
1008       if (ops[j].flags & OPF_JMP)
1009         return -1;
1010
1011       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1012           && IS(ops[j].operand[0].name, reg))
1013       {
1014         found = 1;
1015         if (do_patch)
1016           ops[j].flags |= OPF_RMD;
1017         break;
1018       }
1019
1020       if (g_labels[j][0] != 0)
1021         return -1;
1022     }
1023   }
1024
1025   return found ? 0 : -1;
1026 }
1027
1028 // is operand opr modified by parsed_op po?
1029 static int is_opr_modified(struct parsed_opr *opr,
1030   const struct parsed_op *po)
1031 {
1032   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1033     return 0;
1034
1035   if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1036     if (po->regmask_dst & (1 << opr->reg))
1037       return 1;
1038     else
1039       return 0;
1040   }
1041
1042   return IS(po->operand[0].name, opr->name);
1043 }
1044
1045 // scan for provided opr modification in range given
1046 static int scan_for_mod(struct parsed_opr *opr, int i, int opcnt)
1047 {
1048   for (; i < opcnt; i++) {
1049     if (is_opr_modified(opr, &ops[i]))
1050       return i;
1051   }
1052
1053   return -1;
1054 }
1055
1056 static int scan_for_flag_set(int i, int opcnt)
1057 {
1058   for (; i >= 0; i--) {
1059     if (ops[i].flags & OPF_FLAGS)
1060       return i;
1061
1062     if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1063       return -1;
1064     if (g_labels[i][0] != 0)
1065       return -1;
1066   }
1067
1068   return -1;
1069 }
1070
1071 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1072 {
1073   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
1074   struct parsed_opr *last_arith_dst = NULL;
1075   char buf1[256], buf2[256], buf3[256];
1076   struct parsed_proto *pp;
1077   const char *tmpname;
1078   int save_arg_vars = 0;
1079   int cmp_result_vars = 0;
1080   int had_decl = 0;
1081   int regmask_arg = 0;
1082   int regmask = 0;
1083   int special_sbb = 0;
1084   int no_output;
1085   int dummy;
1086   int arg;
1087   int i, j;
1088   int reg;
1089   int ret;
1090
1091   g_bp_frame = g_bp_stack = 0;
1092
1093   ret = proto_parse(fhdr, funcn, &g_func_pp);
1094   if (ret)
1095     ferr(ops, "proto_parse failed for '%s'\n", funcn);
1096
1097   fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
1098   for (i = 0; i < g_func_pp.argc; i++) {
1099     if (i > 0)
1100       fprintf(fout, ", ");
1101     fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
1102   }
1103   fprintf(fout, ")\n{\n");
1104
1105   // pass1:
1106   // - handle ebp frame, remove ops related to it
1107   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
1108       && ops[1].op == OP_MOV
1109       && IS(opr_name(&ops[1], 0), "ebp")
1110       && IS(opr_name(&ops[1], 1), "esp"))
1111   {
1112     g_bp_frame = 1;
1113     ops[0].flags |= OPF_RMD;
1114     ops[1].flags |= OPF_RMD;
1115
1116     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1117       g_bp_stack = opr_const(&ops[2], 1);
1118       ops[2].flags |= OPF_RMD;
1119     }
1120
1121     i = 2;
1122     do {
1123       for (; i < opcnt; i++)
1124         if (ops[i].op == OP_RET)
1125           break;
1126       if (ops[i - 1].op != OP_POP || !IS(opr_name(&ops[i - 1], 0), "ebp"))
1127         ferr(&ops[i - 1], "'pop ebp' expected\n");
1128       ops[i - 1].flags |= OPF_RMD;
1129
1130       if (g_bp_stack != 0) {
1131         if (ops[i - 2].op != OP_MOV
1132             || !IS(opr_name(&ops[i - 2], 0), "esp")
1133             || !IS(opr_name(&ops[i - 2], 1), "ebp"))
1134         {
1135           ferr(&ops[i - 2], "esp restore expected\n");
1136         }
1137         ops[i - 2].flags |= OPF_RMD;
1138       }
1139       i++;
1140     } while (i < opcnt);
1141   }
1142
1143   // pass2:
1144   // - find POPs for PUSHes, rm both
1145   // - scan for all used registers
1146   // - find flag set ops for their users
1147   // - process calls
1148   for (i = 0; i < opcnt; i++) {
1149     po = &ops[i];
1150     if (po->flags & OPF_RMD)
1151       continue;
1152
1153     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG) {
1154       if (po->operand[0].reg < 0)
1155         ferr(po, "reg not set for push?\n");
1156       if (!(regmask & (1 << po->operand[0].reg))) { // reg save
1157         ret = scan_for_pop(i + 1, opcnt, po->operand[0].name);
1158         if (ret >= 0) {
1159           po->flags |= OPF_RMD;
1160           ops[ret].flags |= OPF_RMD;
1161           continue;
1162         }
1163         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
1164         if (ret == 0) {
1165           po->flags |= OPF_RMD;
1166           scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 1);
1167           continue;
1168         }
1169       }
1170     }
1171
1172     regmask |= po->regmask_src | po->regmask_dst;
1173
1174     if (po->flags & OPF_CC)
1175     {
1176       ret = scan_for_flag_set(i - 1, opcnt);
1177       if (ret < 0)
1178         ferr(po, "unable to trace flag setter\n");
1179
1180       tmp_op = &ops[ret]; // flag setter
1181       for (j = 0; j < tmp_op->operand_cnt; j++) {
1182         ret = scan_for_mod(&tmp_op->operand[j], tmp_op - ops + 1, i);
1183         if (ret >= 0) {
1184           ret = 1 << split_cond(po, po->op, &dummy);
1185           tmp_op->pfomask |= ret;
1186           cmp_result_vars |= ret;
1187           po->datap = tmp_op;
1188         }
1189       }
1190     }
1191     else if (po->op == OP_CALL)
1192     {
1193       pp = malloc(sizeof(*pp));
1194       my_assert_not(pp, NULL);
1195       tmpname = opr_name(&ops[i], 0);
1196       ret = proto_parse(fhdr, tmpname, pp);
1197       if (ret)
1198         ferr(po, "proto_parse failed for '%s'\n", tmpname);
1199
1200       for (arg = 0; arg < pp->argc; arg++)
1201         if (pp->arg[arg].reg == NULL)
1202           break;
1203
1204       for (j = i - 1; j >= 0 && arg < pp->argc; j--) {
1205         if (ops[j].flags & OPF_RMD)
1206           continue;
1207         if (ops[j].op != OP_PUSH)
1208           continue;
1209         if (g_labels[j + 1][0] != 0)
1210           ferr(po, "arg search interrupted by '%s'\n", g_labels[j + 1]);
1211
1212         pp->arg[arg].datap = &ops[j];
1213         ret = scan_for_mod(&ops[j].operand[0], j + 1, i);
1214         if (ret >= 0) {
1215           // mark this push as one that needs operand saving
1216           ops[j].datap = (void *)(long)(arg + 1);
1217           save_arg_vars |= 1 << arg;
1218         }
1219         else
1220           ops[j].flags |= OPF_RMD;
1221
1222         // next arg
1223         for (arg++; arg < pp->argc; arg++)
1224           if (pp->arg[arg].reg == NULL)
1225             break;
1226       }
1227       if (arg < pp->argc)
1228         ferr(po, "arg collect failed for '%s'\n", tmpname);
1229       po->datap = pp;
1230     }
1231   }
1232
1233   // declare stack frame
1234   if (g_bp_stack)
1235     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
1236       (g_bp_stack + 3) / 4, (g_bp_stack + 1) / 2, g_bp_stack);
1237
1238   // instantiate arg-registers
1239   for (i = 0; i < g_func_pp.argc; i++) {
1240     if (g_func_pp.arg[i].reg != NULL) {
1241       reg = char_array_i(regs_r32,
1242               ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
1243       if (reg < 0)
1244         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
1245
1246       regmask_arg |= 1 << reg;
1247       fprintf(fout, "  u32 %s = (u32)a%d;\n",
1248         g_func_pp.arg[i].reg, i + 1);
1249       had_decl = 1;
1250     }
1251   }
1252
1253   // instantiate other regs - special case for eax
1254   if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
1255     fprintf(fout, "  u32 eax = 0;\n");
1256     had_decl = 1;
1257   }
1258
1259   regmask &= ~regmask_arg;
1260   if (g_bp_frame)
1261     regmask &= ~(1 << xBP);
1262   if (regmask) {
1263     for (reg = 0; reg < 8; reg++) {
1264       if (regmask & (1 << reg)) {
1265         fprintf(fout, "  u32 %s;\n", regs_r32[reg]);
1266         had_decl = 1;
1267       }
1268     }
1269   }
1270
1271   if (save_arg_vars) {
1272     for (reg = 0; reg < 32; reg++) {
1273       if (save_arg_vars & (1 << reg)) {
1274         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
1275         had_decl = 1;
1276       }
1277     }
1278   }
1279
1280   if (cmp_result_vars) {
1281     for (i = 0; i < 8; i++) {
1282       if (cmp_result_vars & (1 << i)) {
1283         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
1284         had_decl = 1;
1285       }
1286     }
1287   }
1288
1289   if (had_decl)
1290     fprintf(fout, "\n");
1291
1292   // output ops
1293   for (i = 0; i < opcnt; i++)
1294   {
1295     if (g_labels[i][0] != 0)
1296       fprintf(fout, "\n%s:\n", g_labels[i]);
1297
1298     po = &ops[i];
1299     if (po->flags & OPF_RMD)
1300       continue;
1301
1302     no_output = 0;
1303
1304     #define assert_operand_cnt(n_) \
1305       if (po->operand_cnt != n_) \
1306         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
1307
1308     // see is delayed flag stuff is still valid
1309     if (delayed_flag_op != NULL) {
1310       if (po->regmask_dst & delayed_flag_op->regmask_src)
1311         delayed_flag_op = NULL;
1312       else {
1313         for (j = 0; j < po->operand_cnt; j++) {
1314           if (is_opr_modified(&delayed_flag_op->operand[0], po))
1315             delayed_flag_op = NULL;
1316         }
1317       }
1318     }
1319
1320     if (last_arith_dst != NULL) {
1321       if (is_opr_modified(last_arith_dst, po))
1322         last_arith_dst = NULL;
1323     }
1324
1325     // conditional/flag using op?
1326     if (po->flags & OPF_CC)
1327     {
1328       enum parsed_flag_op pfo;
1329       int is_neg = 0;
1330
1331       pfo = split_cond(po, po->op, &is_neg);
1332       special_sbb = 0;
1333       if (po->op == OP_SBB && IS(opr_name(po, 0), opr_name(po, 1)))
1334         special_sbb = 1;
1335
1336       // we go through all this trouble to avoid using parsed_flag_op,
1337       // which makes generated code much nicer
1338       if (delayed_flag_op != NULL)
1339       {
1340         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_neg);
1341       }
1342       else if (last_arith_dst != NULL
1343         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
1344       {
1345         out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
1346         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_neg,
1347           last_arith_dst->lmod, buf3);
1348       }
1349       else if (po->datap != NULL) {
1350         // use preprocessed results
1351         tmp_op = po->datap;
1352         if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
1353           ferr(po, "not prepared for pfo %d\n", pfo);
1354
1355         // note: is_neg was not yet applied
1356         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
1357           is_neg ? "!" : "", parsed_flag_op_names[pfo]);
1358       }
1359       else {
1360         ferr(po, "all methods of finding comparison failed\n");
1361       }
1362  
1363       if (po->flags & OPF_JMP) {
1364         fprintf(fout, "  if %s\n", buf1);
1365       }
1366       else if (special_sbb) {
1367         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
1368         fprintf(fout, "  %s = %s * -1;", buf2, buf1);
1369       }
1370       else if (po->flags & OPF_JMP) { // setc
1371         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
1372         fprintf(fout, "  %s = %s;", buf2, buf1);
1373       }
1374       else {
1375         ferr(po, "unhandled conditional op\n");
1376       }
1377     }
1378
1379     switch (po->op)
1380     {
1381       case OP_MOV:
1382         assert_operand_cnt(2);
1383         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1384         fprintf(fout, "  %s = %s;",
1385             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1386             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1387         break;
1388
1389       case OP_LEA:
1390         assert_operand_cnt(2);
1391         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1392         fprintf(fout, "  %s = %s;",
1393             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1394             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
1395         break;
1396
1397       case OP_MOVZX:
1398         assert_operand_cnt(2);
1399         fprintf(fout, "  %s = %s;",
1400             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1401             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1402         break;
1403
1404       case OP_MOVSX:
1405         assert_operand_cnt(2);
1406         switch (po->operand[1].lmod) {
1407         case OPLM_BYTE:
1408           strcpy(buf3, "(s8)");
1409           break;
1410         case OPLM_WORD:
1411           strcpy(buf3, "(s16)");
1412           break;
1413         default:
1414           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
1415         }
1416         fprintf(fout, "  %s = %s%s;",
1417             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1418             buf3,
1419             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1420         break;
1421
1422       case OP_NOT:
1423         assert_operand_cnt(1);
1424         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1425         fprintf(fout, "  %s = ~%s;", buf1, buf1);
1426         break;
1427
1428       // arithmetic w/flags
1429       case OP_ADD:
1430       case OP_SUB:
1431       case OP_AND:
1432       case OP_OR:
1433       case OP_XOR:
1434       case OP_SHL:
1435       case OP_SHR:
1436       dualop_arith:
1437         assert_operand_cnt(2);
1438         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1439         fprintf(fout, "  %s %s= %s;",
1440             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
1441             op_to_c(po),
1442             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1443         last_arith_dst = &po->operand[0];
1444         delayed_flag_op = NULL;
1445         break;
1446
1447       case OP_SAR:
1448         assert_operand_cnt(2);
1449         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1450         switch (po->operand[0].lmod) {
1451         case OPLM_BYTE:
1452           strcpy(buf3, "(s8)");
1453           break;
1454         case OPLM_WORD:
1455           strcpy(buf3, "(s16)");
1456           break;
1457         case OPLM_DWORD:
1458           strcpy(buf3, "(s32)");
1459           break;
1460         default:
1461           ferr(po, "invalid dst lmod: %d\n", po->operand[0].lmod);
1462         }
1463         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1464         fprintf(fout, "  %s = %s%s >> %s;", buf1, buf3, buf1,
1465             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
1466         last_arith_dst = &po->operand[0];
1467         delayed_flag_op = NULL;
1468         break;
1469
1470       case OP_SBB:
1471         if (!special_sbb)
1472           ferr(po, "TODO\n");
1473         break;
1474
1475       case OP_INC:
1476       case OP_DEC:
1477         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
1478         strcpy(buf2, po->op == OP_INC ? "++" : "--");
1479         switch (po->operand[0].lmod) {
1480         case OPLM_BYTE:
1481           fprintf(fout, "  LOBYTE(%s)%s;", buf1, buf2);
1482           break;
1483         case OPLM_WORD:
1484           fprintf(fout, "  LOWORD(%s)%s;", buf1, buf2);
1485           break;
1486         case OPLM_DWORD:
1487           fprintf(fout, "  %s%s;", buf1, buf2);
1488           break;
1489         default:
1490           ferr(po, "invalid dst lmod: %d\n", po->operand[0].lmod);
1491         }
1492         last_arith_dst = &po->operand[0];
1493         delayed_flag_op = NULL;
1494         break;
1495
1496       case OP_IMUL:
1497         if (po->operand_cnt == 2)
1498           goto dualop_arith;
1499         ferr(po, "TODO imul\n");
1500         last_arith_dst = &po->operand[0];
1501         delayed_flag_op = NULL;
1502         break;
1503
1504       case OP_TEST:
1505       case OP_CMP:
1506         propagate_lmod(po, &po->operand[0], &po->operand[1]);
1507         if (po->pfomask != 0) {
1508           for (j = 0; j < 8; j++) {
1509             if (po->pfomask & (1 << j)) {
1510               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
1511               fprintf(fout, "  cond_%s = %s;",
1512                 parsed_flag_op_names[j], buf1);
1513             }
1514           }
1515         }
1516         else
1517           no_output = 1;
1518         delayed_flag_op = po;
1519         break;
1520
1521       // note: we reuse OP_Jcc for SETcc, only flags differ
1522       case OP_JO ... OP_JG:
1523         if (po->flags & OPF_CC)
1524           fprintf(fout, "    goto %s;", po->operand[0].name);
1525         else
1526           ferr(po, "TODO SETcc\n");
1527         break;
1528
1529       case OP_JMP:
1530         fprintf(fout, "  goto %s;", po->operand[0].name);
1531         break;
1532
1533       case OP_CALL:
1534         pp = po->datap;
1535         if (pp == NULL)
1536           ferr(po, "NULL pp\n");
1537
1538         fprintf(fout, "  ");
1539         if (!IS(pp->ret_type, "void")) {
1540           fprintf(fout, "eax = ");
1541           if (strchr(pp->ret_type, '*'))
1542             fprintf(fout, "(u32)");
1543         }
1544         fprintf(fout, "%s(", opr_name(po, 0));
1545         for (arg = 0; arg < pp->argc; arg++) {
1546           if (arg > 0)
1547             fprintf(fout, ", ");
1548           if (pp->arg[arg].reg != NULL) {
1549             fprintf(fout, "%s", pp->arg[arg].reg);
1550             continue;
1551           }
1552
1553           // stack arg
1554           tmp_op = pp->arg[arg].datap;
1555           if (tmp_op == NULL)
1556             ferr(po, "parsed_op missing for arg%d\n", arg);
1557           if (tmp_op->datap) {
1558             fprintf(fout, "s_a%ld", (long)tmp_op->datap);
1559           }
1560           else {
1561             fprintf(fout, "%s",
1562               out_src_opr(buf1, sizeof(buf1),
1563                 tmp_op, &tmp_op->operand[0], 0));
1564           }
1565         }
1566         fprintf(fout, ");");
1567         break;
1568
1569       case OP_RET:
1570         if (IS(g_func_pp.ret_type, "void"))
1571           fprintf(fout, "  return;");
1572         else
1573           fprintf(fout, "  return eax;");
1574         break;
1575
1576       case OP_PUSH:
1577         if (po->datap) {
1578           // special case - saved func arg
1579           fprintf(fout, "  s_a%ld = %s;", (long)po->datap,
1580             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0));
1581           break;
1582         }
1583         ferr(po, "push encountered\n");
1584         break;
1585
1586       case OP_POP:
1587         ferr(po, "pop encountered\n");
1588         break;
1589
1590       default:
1591         no_output = 1;
1592         ferr(po, "unhandled op type %d, flags %x\n",
1593           po->op, po->flags);
1594         break;
1595     }
1596
1597     if (g_comment[0] != 0) {
1598       fprintf(fout, "  // %s", g_comment);
1599       g_comment[0] = 0;
1600       no_output = 0;
1601     }
1602     if (!no_output)
1603       fprintf(fout, "\n");
1604   }
1605
1606   fprintf(fout, "}\n\n");
1607
1608   // cleanup
1609   for (i = 0; i < opcnt; i++) {
1610     if (ops[i].op == OP_CALL) {
1611       pp = ops[i].datap;
1612       if (pp) {
1613         proto_release(pp);
1614         free(pp);
1615       }
1616     }
1617   }
1618   proto_release(&g_func_pp);
1619 }
1620
1621 int main(int argc, char *argv[])
1622 {
1623   FILE *fout, *fasm, *fhdr;
1624   char line[256];
1625   char words[16][256];
1626   int in_func = 0;
1627   int eq_alloc;
1628   int pi = 0;
1629   int len;
1630   char *p;
1631   int wordc;
1632
1633   if (argc != 4) {
1634     printf("usage:\n%s <.c> <.asm> <hdrf>\n",
1635       argv[0]);
1636     return 1;
1637   }
1638
1639   hdrfn = argv[3];
1640   fhdr = fopen(hdrfn, "r");
1641   my_assert_not(fhdr, NULL);
1642
1643   asmfn = argv[2];
1644   fasm = fopen(asmfn, "r");
1645   my_assert_not(fasm, NULL);
1646
1647   fout = fopen(argv[1], "w");
1648   my_assert_not(fout, NULL);
1649
1650   eq_alloc = 128;
1651   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
1652   my_assert_not(g_eqs, NULL);
1653
1654   while (fgets(line, sizeof(line), fasm))
1655   {
1656     asmln++;
1657
1658     p = sskip(line);
1659     if (*p == 0 || *p == ';')
1660       continue;
1661
1662     memset(words, 0, sizeof(words));
1663     for (wordc = 0; wordc < 16; wordc++) {
1664       p = sskip(next_word(words[wordc], sizeof(words[0]), p));
1665       if (*p == 0 || *p == ';') {
1666         wordc++;
1667         break;
1668       }
1669     }
1670
1671     if (wordc == 0) {
1672       // shouldn't happen
1673       awarn("wordc == 0?\n");
1674       continue;
1675     }
1676
1677     // don't care about this:
1678     if (words[0][0] == '.'
1679         || IS(words[0], "include")
1680         || IS(words[0], "assume") || IS(words[1], "segment")
1681         || IS(words[0], "align"))
1682     {
1683       continue;
1684     }
1685
1686     if (IS(words[1], "proc")) {
1687       if (in_func)
1688         aerr("proc '%s' while in_func '%s'?\n",
1689           words[0], g_func);
1690       strcpy(g_func, words[0]);
1691       in_func = 1;
1692       continue;
1693     }
1694
1695     if (IS(words[1], "endp")) {
1696       if (!in_func)
1697         aerr("endp '%s' while not in_func?\n", words[0]);
1698       if (!IS(g_func, words[0]))
1699         aerr("endp '%s' while in_func '%s'?\n",
1700           words[0], g_func);
1701       gen_func(fout, fhdr, g_func, pi);
1702       in_func = 0;
1703       g_func[0] = 0;
1704       if (pi != 0) {
1705         memset(&ops, 0, pi * sizeof(ops[0]));
1706         memset(g_labels, 0, pi * sizeof(g_labels[0]));
1707         pi = 0;
1708       }
1709       g_eqcnt = 0;
1710       continue;
1711     }
1712
1713     if (IS(words[1], "=")) {
1714       if (wordc != 5)
1715         aerr("unhandled equ, wc=%d\n", wordc);
1716       if (g_eqcnt >= eq_alloc) {
1717         eq_alloc *= 2;
1718         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
1719         my_assert_not(g_eqs, NULL);
1720       }
1721
1722       len = strlen(words[0]);
1723       if (len > sizeof(g_eqs[0].name) - 1)
1724         aerr("equ name too long: %d\n", len);
1725       strcpy(g_eqs[g_eqcnt].name, words[0]);
1726
1727       if (!IS(words[3], "ptr"))
1728         aerr("unhandled equ\n");
1729       if (IS(words[2], "dword"))
1730         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
1731       else if (IS(words[2], "word"))
1732         g_eqs[g_eqcnt].lmod = OPLM_WORD;
1733       else if (IS(words[2], "byte"))
1734         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
1735       else
1736         aerr("bad lmod: '%s'\n", words[2]);
1737
1738       g_eqs[g_eqcnt].offset = parse_number(words[4]);
1739       g_eqcnt++;
1740       continue;
1741     }
1742
1743     if (pi >= ARRAY_SIZE(ops))
1744       aerr("too many ops\n");
1745
1746     p = strchr(words[0], ':');
1747     if (p != NULL) {
1748       len = p - words[0];
1749       if (len > sizeof(g_labels[0]) - 1)
1750         aerr("label too long: %d\n", len);
1751       if (g_labels[pi][0] != 0)
1752         aerr("dupe label?\n");
1753       memcpy(g_labels[pi], words[0], len);
1754       g_labels[pi][len] = 0;
1755       continue;
1756     }
1757
1758     parse_op(&ops[pi], words, wordc);
1759     pi++;
1760
1761     (void)proto_parse;
1762   }
1763
1764   fclose(fout);
1765   fclose(fasm);
1766   fclose(fhdr);
1767
1768   return 0;
1769 }
1770
1771 // vim:ts=2:shiftwidth=2:expandtab