improved flag checks with tmp vars when needed, refactoring
[ia32rtools.git] / tools / translate.c
CommitLineData
c36e914d 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
13const char *asmfn;
14static 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
69a3cdfc 23enum 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 */
c36e914d 29};
30
31enum op_op {
32 OP_INVAL,
33 OP_PUSH,
34 OP_POP,
35 OP_MOV,
850c9265 36 OP_LEA,
37 OP_MOVZX,
38 OP_MOVSX,
39 OP_NOT,
c36e914d 40 OP_RET,
41 OP_ADD,
91977a1c 42 OP_SUB,
850c9265 43 OP_AND,
44 OP_OR,
45 OP_XOR,
46 OP_SHL,
47 OP_SHR,
48 OP_SAR,
69a3cdfc 49 OP_ADC,
850c9265 50 OP_SBB,
51 OP_INC,
52 OP_DEC,
53 OP_MUL,
54 OP_IMUL,
c36e914d 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
77enum opr_type {
78 OPT_UNSPEC,
79 OPT_REG,
80 OPT_REGMEM,
81 OPT_LABEL,
850c9265 82 OPT_OFFSET,
c36e914d 83 OPT_CONST,
84};
85
86enum opr_lenmod {
91977a1c 87 OPLM_UNSPEC,
88 OPLM_BYTE,
89 OPLM_WORD,
90 OPLM_DWORD,
c36e914d 91};
92
850c9265 93#define MAX_OPERANDS 3
c36e914d 94
95struct parsed_opr {
91977a1c 96 enum opr_type type;
97 enum opr_lenmod lmod;
98 int reg;
99 unsigned int val;
100 char name[256];
c36e914d 101};
102
103struct parsed_op {
91977a1c 104 enum op_op op;
105 struct parsed_opr operand[MAX_OPERANDS];
69a3cdfc 106 unsigned int flags;
91977a1c 107 int operand_cnt;
69a3cdfc 108 int regmask_src; // all referensed regs
109 int regmask_dst;
110 int pfomask; // parsed_flag_op that can't be delayed
91977a1c 111 void *datap;
112};
113
69a3cdfc 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
91977a1c 119struct parsed_equ {
120 char name[64];
121 enum opr_lenmod lmod;
122 int offset;
c36e914d 123};
124
125#define MAX_OPS 1024
126
127static struct parsed_op ops[MAX_OPS];
91977a1c 128static struct parsed_equ *g_eqs;
129static int g_eqcnt;
130static char g_labels[MAX_OPS][32];
131static struct parsed_proto g_func_pp;
132static char g_func[256];
133static char g_comment[256];
134static int g_bp_frame;
135static int g_bp_stack;
136#define ferr(op_, fmt, ...) do { \
850c9265 137 printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
138 dump_op(op_), ##__VA_ARGS__); \
91977a1c 139 exit(1); \
140} while (0)
141
142#define MAX_REGS 8
143
144const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
145const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
146const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
147const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
148
149enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
150
69a3cdfc 151// possible basic comparison types (without inversion)
152enum 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
163static const char *parsed_flag_op_names[] = {
164 "o", "c", "z", "be", "s", "p", "l", "le"
165};
166
91977a1c 167static int char_array_i(const char *array[], size_t len, const char *s)
168{
169 int i;
c36e914d 170
91977a1c 171 for (i = 0; i < len; i++)
172 if (IS(s, array[i]))
173 return i;
c36e914d 174
91977a1c 175 return -1;
176}
177
850c9265 178static int parse_reg(int *reg_out, enum opr_lenmod *reg_lmod,
179 int *regmask, char *s)
91977a1c 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) {
850c9265 194 *reg_lmod = OPLM_DWORD;
91977a1c 195 *regmask |= 1 << reg;
196 continue;
197 }
198 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), w);
199 if (reg >= 0) {
850c9265 200 *reg_lmod = OPLM_WORD;
91977a1c 201 *regmask |= 1 << reg;
202 continue;
203 }
204 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), w);
205 if (reg >= 0) {
850c9265 206 *reg_lmod = OPLM_BYTE;
91977a1c 207 *regmask |= 1 << reg;
208 continue;
209 }
210 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), w);
211 if (reg >= 0) {
850c9265 212 *reg_lmod = OPLM_BYTE;
91977a1c 213 *regmask |= 1 << reg;
214 continue;
215 }
216
850c9265 217 return -1;
91977a1c 218 }
219
850c9265 220 if (c == 1) {
221 *reg_out = reg;
222 return 0;
223 }
224
225 return -1;
91977a1c 226}
227
228static 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
850c9265 258static 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
69a3cdfc 275static 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)
c36e914d 278{
850c9265 279 enum opr_lenmod tmplmod;
280 int tmpreg;
281 int ret, len;
282 int i;
c36e914d 283
284 if (w >= wordc)
285 aerr("parse_operand w %d, wordc %d\n", w, wordc);
286
91977a1c 287 opr->reg = xUNSPEC;
288
c36e914d 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
69a3cdfc 298 if (op_flags & OPF_JMP) {
c36e914d 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"))
91977a1c 318 opr->lmod = OPLM_DWORD;
c36e914d 319 else if (IS(words[w], "word"))
91977a1c 320 opr->lmod = OPLM_WORD;
c36e914d 321 else if (IS(words[w], "byte"))
91977a1c 322 opr->lmod = OPLM_BYTE;
c36e914d 323 else
324 aerr("type parsing failed\n");
325 w += 2;
326 }
327 }
328
329 if (wordc - w == 2 && IS(words[w], "offset")) {
850c9265 330 opr->type = OPT_OFFSET;
c36e914d 331 strcpy(opr->name, words[w + 1]);
332 return wordc;
333 }
334
850c9265 335 if (wordc - w != 1)
336 aerr("parse_operand 1 word expected\n");
c36e914d 337
850c9265 338 strcpy(opr->name, words[w]);
c36e914d 339
850c9265 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
69a3cdfc 346 parse_reg(&tmpreg, &tmplmod, regmask_indirect, opr->name);
850c9265 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);
69a3cdfc 354 parse_reg(&tmpreg, &tmplmod, regmask_indirect,
355 strchr(words[w], '['));
850c9265 356 return wordc;
357 }
358 else if (('0' <= words[w][0] && words[w][0] <= '9')
359 || words[w][0] == '-')
360 {
91977a1c 361 opr->type = OPT_CONST;
362 opr->val = (unsigned int)parse_number(words[w]);
363 return wordc;
850c9265 364 }
c36e914d 365
850c9265 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;
91977a1c 379
850c9265 380 // TODO: scan data seg to determine type?
381 return wordc;
c36e914d 382}
383
384static const struct {
850c9265 385 const char *name;
386 enum op_op op;
69a3cdfc 387 unsigned int minopr;
388 unsigned int maxopr;
389 unsigned int flags;
c36e914d 390} op_table[] = {
69a3cdfc 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};
c36e914d 447
448static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
449{
69a3cdfc 450 int regmask_ind;
451 int regmask;
91977a1c 452 int opr = 0;
453 int w = 1;
454 int i;
c36e914d 455
91977a1c 456 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
69a3cdfc 457 if (IS(words[0], op_table[i].name))
458 break;
459 }
c36e914d 460
69a3cdfc 461 if (i == ARRAY_SIZE(op_table))
462 aerr("unhandled op: '%s'\n", words[0]);
c36e914d 463
69a3cdfc 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 }
c36e914d 478
69a3cdfc 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);
91977a1c 483 }
c36e914d 484
69a3cdfc 485 op->operand_cnt = opr;
c36e914d 486
91977a1c 487 if (w < wordc)
488 aerr("parse_op %s incomplete: %d/%d\n",
489 words[0], w, wordc);
c36e914d 490}
491
850c9265 492static 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
504static 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
91977a1c 523static const char *opr_name(struct parsed_op *po, int opr_num)
c36e914d 524{
91977a1c 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;
c36e914d 528}
529
91977a1c 530static unsigned int opr_const(struct parsed_op *po, int opr_num)
c36e914d 531{
91977a1c 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}
c36e914d 538
91977a1c 539static 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}
c36e914d 545
850c9265 546static struct parsed_equ *equ_find(struct parsed_op *po, const char *name)
91977a1c 547{
850c9265 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
559static 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 = "";
91977a1c 564 struct parsed_equ *eq;
565 int i, arg_i, arg_s;
850c9265 566 int sf_ofs;
91977a1c 567
568 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
569
850c9265 570 eq = equ_find(po, bp_arg);
91977a1c 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);
850c9265 586 if (is_lea)
587 ferr(po, "lea to arg?\n");
588
91977a1c 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");
850c9265 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 }
91977a1c 616 }
617}
c36e914d 618
91977a1c 619static char *out_src_opr(char *buf, size_t buf_size,
850c9265 620 struct parsed_op *po, struct parsed_opr *popr, int is_lea)
91977a1c 621{
850c9265 622 const char *cast = "";
623 char tmp1[256], tmp2[256];
624 char expr[256];
625 int ret;
626
91977a1c 627 switch (popr->type) {
628 case OPT_REG:
850c9265 629 if (is_lea)
630 ferr(po, "lea from reg?\n");
631
91977a1c 632 switch (popr->lmod) {
633 case OPLM_DWORD:
634 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
635 break;
850c9265 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;
91977a1c 642 default:
643 ferr(po, "invalid src lmod: %d\n", popr->lmod);
644 }
645 break;
850c9265 646
91977a1c 647 case OPT_REGMEM:
648 if (g_bp_frame && !strncmp(popr->name, "ebp+", 4)) {
850c9265 649 bg_frame_access(po, popr->lmod, buf, buf_size,
650 popr->name + 4, 1, is_lea);
91977a1c 651 break;
652 }
850c9265 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);
91977a1c 683 break;
850c9265 684
91977a1c 685 case OPT_LABEL:
850c9265 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);
91977a1c 696 break;
850c9265 697
91977a1c 698 case OPT_CONST:
850c9265 699 if (is_lea)
700 ferr(po, "lea from const?\n");
701
91977a1c 702 snprintf(buf, buf_size, popr->val < 10 ? "%u" : "0x%02x", popr->val);
703 break;
850c9265 704
91977a1c 705 default:
706 ferr(po, "invalid src type: %d\n", popr->type);
707 }
708
709 return buf;
710}
c36e914d 711
91977a1c 712static 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;
850c9265 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;
91977a1c 729 default:
730 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
731 }
732 break;
850c9265 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
91977a1c 743 default:
744 ferr(po, "invalid dst type: %d\n", popr->type);
745 }
746
747 return buf;
748}
c36e914d 749
69a3cdfc 750static 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
766static 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
782static enum parsed_flag_op split_cond(struct parsed_op *po,
783 enum op_op op, int *is_neg)
91977a1c 784{
785 *is_neg = 0;
786
69a3cdfc 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
91977a1c 805 case OP_JNO:
91977a1c 806 *is_neg = 1;
69a3cdfc 807 return PFO_O;
91977a1c 808 case OP_JNC:
91977a1c 809 *is_neg = 1;
69a3cdfc 810 return PFO_C;
91977a1c 811 case OP_JNZ:
91977a1c 812 *is_neg = 1;
69a3cdfc 813 return PFO_Z;
814 case OP_JA:
815 *is_neg = 1;
816 return PFO_BE;
91977a1c 817 case OP_JNS:
91977a1c 818 *is_neg = 1;
69a3cdfc 819 return PFO_S;
91977a1c 820 case OP_JNP:
91977a1c 821 *is_neg = 1;
69a3cdfc 822 return PFO_P;
850c9265 823 case OP_JGE:
850c9265 824 *is_neg = 1;
69a3cdfc 825 return PFO_L;
91977a1c 826 case OP_JG:
69a3cdfc 827 *is_neg = 1;
828 return PFO_LE;
829
830 case OP_ADC:
831 case OP_SBB:
832 return PFO_C;
833
91977a1c 834 default:
69a3cdfc 835 ferr(po, "split_cond: bad op %d\n", op);
836 return -1;
91977a1c 837 }
838}
c36e914d 839
91977a1c 840static void out_test_for_cc(char *buf, size_t buf_size,
69a3cdfc 841 struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
842 enum opr_lenmod lmod, const char *expr)
91977a1c 843{
69a3cdfc 844 const char *cast, *scast;
91977a1c 845
69a3cdfc 846 cast = lmod_cast_u(po, lmod);
847 scast = lmod_cast_s(po, lmod);
848
849 switch (pfo) {
850 case PFO_Z:
850c9265 851 snprintf(buf, buf_size, "(%s%s %s 0)",
852 cast, expr, is_neg ? "!=" : "==");
91977a1c 853 break;
850c9265 854
69a3cdfc 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 ? ">" : "<=");
850c9265 858 break;
859
91977a1c 860 default:
69a3cdfc 861 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
91977a1c 862 }
863}
c36e914d 864
850c9265 865static void out_cmp_for_cc(char *buf, size_t buf_size,
69a3cdfc 866 struct parsed_op *po, enum parsed_flag_op pfo, int is_neg,
867 enum opr_lenmod lmod, const char *expr1, const char *expr2)
850c9265 868{
69a3cdfc 869 const char *cast, *scast;
850c9265 870
69a3cdfc 871 cast = lmod_cast_u(po, lmod);
872 scast = lmod_cast_s(po, lmod);
850c9265 873
69a3cdfc 874 switch (pfo) {
875 case PFO_Z:
850c9265 876 snprintf(buf, buf_size, "(%s%s %s %s%s)",
877 cast, expr1, is_neg ? "!=" : "==", cast, expr2);
878 break;
879
69a3cdfc 880 case PFO_C:
850c9265 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
69a3cdfc 886 case PFO_L:
887 // note: must be signed compare
850c9265 888 snprintf(buf, buf_size, "(%s%s %s %s%s)",
889 scast, expr1, is_neg ? ">=" : "<", scast, expr2);
890 break;
891
892 default:
69a3cdfc 893 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
850c9265 894 }
895}
896
69a3cdfc 897static 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
850c9265 924static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
91977a1c 925 struct parsed_opr *popr2)
926{
850c9265 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
91977a1c 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}
c36e914d 951
850c9265 952static 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
978static int scan_for_pop(int i, int opcnt, const char *reg)
979{
980 for (; i < opcnt; i++) {
69a3cdfc 981 if (ops[i].flags & OPF_RMD)
850c9265 982 continue;
983
69a3cdfc 984 if ((ops[i].flags & OPF_JMP) || g_labels[i][0] != 0)
850c9265 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
69a3cdfc 995// scan for pop starting from 'ret' op (all paths)
850c9265 996static 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--) {
69a3cdfc 1006 if (ops[j].flags & OPF_RMD)
1007 continue;
1008 if (ops[j].flags & OPF_JMP)
850c9265 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)
69a3cdfc 1016 ops[j].flags |= OPF_RMD;
850c9265 1017 break;
1018 }
1019
1020 if (g_labels[j][0] != 0)
1021 return -1;
1022 }
1023 }
1024
1025 return found ? 0 : -1;
1026}
1027
69a3cdfc 1028// is operand opr modified by parsed_op po?
1029static 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
1046static 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
1056static 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
91977a1c 1071static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1072{
69a3cdfc 1073 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
850c9265 1074 struct parsed_opr *last_arith_dst = NULL;
91977a1c 1075 char buf1[256], buf2[256], buf3[256];
1076 struct parsed_proto *pp;
1077 const char *tmpname;
69a3cdfc 1078 int save_arg_vars = 0;
1079 int cmp_result_vars = 0;
91977a1c 1080 int had_decl = 0;
1081 int regmask_arg = 0;
1082 int regmask = 0;
69a3cdfc 1083 int special_sbb = 0;
91977a1c 1084 int no_output;
69a3cdfc 1085 int dummy;
91977a1c 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;
69a3cdfc 1113 ops[0].flags |= OPF_RMD;
1114 ops[1].flags |= OPF_RMD;
91977a1c 1115
1116 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1117 g_bp_stack = opr_const(&ops[2], 1);
69a3cdfc 1118 ops[2].flags |= OPF_RMD;
91977a1c 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");
69a3cdfc 1128 ops[i - 1].flags |= OPF_RMD;
91977a1c 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 }
69a3cdfc 1137 ops[i - 2].flags |= OPF_RMD;
91977a1c 1138 }
1139 i++;
1140 } while (i < opcnt);
1141 }
1142
1143 // pass2:
69a3cdfc 1144 // - find POPs for PUSHes, rm both
91977a1c 1145 // - scan for all used registers
69a3cdfc 1146 // - find flag set ops for their users
91977a1c 1147 // - process calls
1148 for (i = 0; i < opcnt; i++) {
69a3cdfc 1149 po = &ops[i];
1150 if (po->flags & OPF_RMD)
91977a1c 1151 continue;
850c9265 1152
69a3cdfc 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);
850c9265 1158 if (ret >= 0) {
69a3cdfc 1159 po->flags |= OPF_RMD;
1160 ops[ret].flags |= OPF_RMD;
850c9265 1161 continue;
1162 }
69a3cdfc 1163 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
850c9265 1164 if (ret == 0) {
69a3cdfc 1165 po->flags |= OPF_RMD;
1166 scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 1);
850c9265 1167 continue;
1168 }
1169 }
1170 }
1171
69a3cdfc 1172 regmask |= po->regmask_src | po->regmask_dst;
91977a1c 1173
69a3cdfc 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 {
91977a1c 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)
69a3cdfc 1198 ferr(po, "proto_parse failed for '%s'\n", tmpname);
91977a1c 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--) {
69a3cdfc 1205 if (ops[j].flags & OPF_RMD)
91977a1c 1206 continue;
1207 if (ops[j].op != OP_PUSH)
1208 continue;
69a3cdfc 1209 if (g_labels[j + 1][0] != 0)
1210 ferr(po, "arg search interrupted by '%s'\n", g_labels[j + 1]);
91977a1c 1211
1212 pp->arg[arg].datap = &ops[j];
69a3cdfc 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
91977a1c 1223 for (arg++; arg < pp->argc; arg++)
1224 if (pp->arg[arg].reg == NULL)
1225 break;
1226 }
1227 if (arg < pp->argc)
69a3cdfc 1228 ferr(po, "arg collect failed for '%s'\n", tmpname);
1229 po->datap = pp;
91977a1c 1230 }
1231 }
1232
850c9265 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
91977a1c 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",
850c9265 1248 g_func_pp.arg[i].reg, i + 1);
91977a1c 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
69a3cdfc 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
91977a1c 1289 if (had_decl)
1290 fprintf(fout, "\n");
1291
1292 // output ops
69a3cdfc 1293 for (i = 0; i < opcnt; i++)
1294 {
91977a1c 1295 if (g_labels[i][0] != 0)
1296 fprintf(fout, "\n%s:\n", g_labels[i]);
1297
69a3cdfc 1298 po = &ops[i];
1299 if (po->flags & OPF_RMD)
91977a1c 1300 continue;
1301
1302 no_output = 0;
1303
91977a1c 1304 #define assert_operand_cnt(n_) \
850c9265 1305 if (po->operand_cnt != n_) \
1306 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
1307
69a3cdfc 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 }
850c9265 1318 }
91977a1c 1319
69a3cdfc 1320 if (last_arith_dst != NULL) {
1321 if (is_opr_modified(last_arith_dst, po))
1322 last_arith_dst = NULL;
1323 }
850c9265 1324
69a3cdfc 1325 // conditional/flag using op?
1326 if (po->flags & OPF_CC)
850c9265 1327 {
69a3cdfc 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;
850c9265 1335
69a3cdfc 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)
850c9265 1339 {
69a3cdfc 1340 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_neg);
91977a1c 1341 }
850c9265 1342 else if (last_arith_dst != NULL
69a3cdfc 1343 && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
850c9265 1344 {
1345 out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
69a3cdfc 1346 out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_neg,
850c9265 1347 last_arith_dst->lmod, buf3);
1348 }
69a3cdfc 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 }
850c9265 1362
69a3cdfc 1363 if (po->flags & OPF_JMP) {
850c9265 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 }
69a3cdfc 1370 else if (po->flags & OPF_JMP) { // setc
850c9265 1371 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
1372 fprintf(fout, " %s = %s;", buf2, buf1);
91977a1c 1373 }
69a3cdfc 1374 else {
1375 ferr(po, "unhandled conditional op\n");
1376 }
91977a1c 1377 }
1378
850c9265 1379 switch (po->op)
91977a1c 1380 {
1381 case OP_MOV:
1382 assert_operand_cnt(2);
850c9265 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);
91977a1c 1399 fprintf(fout, " %s = %s;",
850c9265 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];
69a3cdfc 1444 delayed_flag_op = NULL;
850c9265 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];
69a3cdfc 1467 delayed_flag_op = NULL;
850c9265 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];
69a3cdfc 1493 delayed_flag_op = NULL;
850c9265 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];
69a3cdfc 1501 delayed_flag_op = NULL;
91977a1c 1502 break;
1503
1504 case OP_TEST:
1505 case OP_CMP:
850c9265 1506 propagate_lmod(po, &po->operand[0], &po->operand[1]);
69a3cdfc 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;
91977a1c 1519 break;
1520
69a3cdfc 1521 // note: we reuse OP_Jcc for SETcc, only flags differ
91977a1c 1522 case OP_JO ... OP_JG:
69a3cdfc 1523 if (po->flags & OPF_CC)
850c9265 1524 fprintf(fout, " goto %s;", po->operand[0].name);
69a3cdfc 1525 else
1526 ferr(po, "TODO SETcc\n");
850c9265 1527 break;
1528
1529 case OP_JMP:
1530 fprintf(fout, " goto %s;", po->operand[0].name);
91977a1c 1531 break;
1532
1533 case OP_CALL:
850c9265 1534 pp = po->datap;
91977a1c 1535 if (pp == NULL)
850c9265 1536 ferr(po, "NULL pp\n");
91977a1c 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 }
850c9265 1544 fprintf(fout, "%s(", opr_name(po, 0));
91977a1c 1545 for (arg = 0; arg < pp->argc; arg++) {
1546 if (arg > 0)
1547 fprintf(fout, ", ");
1548 if (pp->arg[arg].reg != NULL) {
850c9265 1549 fprintf(fout, "%s", pp->arg[arg].reg);
91977a1c 1550 continue;
1551 }
1552
1553 // stack arg
1554 tmp_op = pp->arg[arg].datap;
1555 if (tmp_op == NULL)
850c9265 1556 ferr(po, "parsed_op missing for arg%d\n", arg);
69a3cdfc 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 }
91977a1c 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:
69a3cdfc 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 }
850c9265 1583 ferr(po, "push encountered\n");
91977a1c 1584 break;
1585
1586 case OP_POP:
850c9265 1587 ferr(po, "pop encountered\n");
91977a1c 1588 break;
1589
1590 default:
1591 no_output = 1;
69a3cdfc 1592 ferr(po, "unhandled op type %d, flags %x\n",
1593 po->op, po->flags);
91977a1c 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}
c36e914d 1620
91977a1c 1621int 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;
91977a1c 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;
c36e914d 1769}
91977a1c 1770
1771// vim:ts=2:shiftwidth=2:expandtab