Datafile: don't fail on overly long gui names
[rofl0r-agsutils.git] / asmparse.y
blob5dc7ddf50c713b0e9226cdb9d2f1a2ae558812d1
1 %{
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <assert.h>
6 extern int yylex();
7 extern int yylineno;
8 extern void yyerror(char*);
9 int yydebug = 1;
10 extern const char *yyfilename;
11 extern int yyfatalerrors;
12 void yylex_reset(FILE *f, const char *fn);
15 %code requires {
16 #include "ags_cpu.h"
17 #include "tglist.h"
19 struct variable {
20 int type;
21 int elems;
22 int value;
23 int export;
24 char* name;
27 struct instruction {
28 int tok[4];
29 char *strdata;
32 struct basicblock {
33 int isfunc;
34 char *label;
35 tglist(struct instruction) *insns;
38 tglist(struct variable) *vars;
39 tglist(struct basicblock) *blocks;
40 #ifndef complain
41 #define complain(fmt, args...) do { fprintf(stderr, "%d: " fmt, yylineno, ## args); exit(1); } while(0)
42 #endif
44 #define tok2scmd(tok) ((tok - KW_SCMD_ADD) + SCMD_ADD)
45 #define tok2reg(tok) ((tok - RN_AR_SP) + AR_SP)
49 %union {
50 int i;
51 char *s;
54 %code {
55 static void opcheck(int tok, int nargs, int nregs) {
56 const struct opcode_info *i = &opcodes[tok2scmd(tok)];
57 if(i->argcount != nargs)
58 complain("mnemonic '%s' requires %d args!\n", i->mnemonic, i->argcount);
59 if(i->regcount != nregs)
60 complain("mnemonic '%s' requires %d register args!\n", i->mnemonic, i->regcount);
63 static void add_block(char *name, int isfunc) {
64 struct basicblock b = {
65 .isfunc = isfunc,
66 .label = name,
67 .insns = tglist_new(),
69 tglist_add(blocks, b);
72 #define INS(A, B, C, D, E) add_insn((int[]){A, B, C, D}, E)
73 static void add_insn(int toks[4], char *strdata) {
74 struct instruction i = {
75 .tok = {toks[0], toks[1], toks[2], toks[3]},
76 .strdata = strdata,
78 size_t l = tglist_getsize(blocks);
79 if(l) --l;
80 tglist_add(tglist_get(blocks, l).insns, i);
83 static void add_var(char *id, int type, int nelems, int value, int export)
85 struct variable v = {
86 .name = strdup(id),
87 .elems = nelems,
88 .value = value,
89 .type = type,
90 .export = export,
92 tglist_add(vars, v);
96 %token <i> NUMBER
97 %token <s> ID STRING
98 %token <s> FN_I FN_E LABEL
100 %token <i> SECTION_DATA SECTION_TEXT SECTION_STRINGS SECTION_FIXUPS
101 %token <i> SECTION_IMPORTS SECTION_EXPORTS SECTION_SECTIONS
103 %token <i> D_EXPORT D_INT D_SHORT D_CHAR
105 %token <i> KW_SCMD_ADD KW_SCMD_SUB KW_SCMD_REGTOREG KW_SCMD_WRITELIT KW_SCMD_RET
106 %token <i> KW_SCMD_LITTOREG KW_SCMD_MEMREAD KW_SCMD_MEMWRITE KW_SCMD_MULREG
107 %token <i> KW_SCMD_DIVREG KW_SCMD_ADDREG KW_SCMD_SUBREG KW_SCMD_BITAND
108 %token <i> KW_SCMD_BITOR KW_SCMD_ISEQUAL KW_SCMD_NOTEQUAL KW_SCMD_GREATER
109 %token <i> KW_SCMD_LESSTHAN KW_SCMD_GTE KW_SCMD_LTE KW_SCMD_AND KW_SCMD_OR
110 %token <i> KW_SCMD_CALL KW_SCMD_MEMREADB KW_SCMD_MEMREADW KW_SCMD_MEMWRITEB
111 %token <i> KW_SCMD_MEMWRITEW KW_SCMD_JZ KW_SCMD_PUSHREG KW_SCMD_POPREG KW_SCMD_JMP
112 %token <i> KW_SCMD_MUL KW_SCMD_CALLEXT KW_SCMD_PUSHREAL KW_SCMD_SUBREALSTACK
113 %token <i> KW_SCMD_LINENUM KW_SCMD_CALLAS KW_SCMD_THISBASE KW_SCMD_NUMFUNCARGS
114 %token <i> KW_SCMD_MODREG KW_SCMD_XORREG KW_SCMD_NOTREG KW_SCMD_SHIFTLEFT
115 %token <i> KW_SCMD_SHIFTRIGHT KW_SCMD_CALLOBJ KW_SCMD_CHECKBOUNDS
116 %token <i> KW_SCMD_MEMWRITEPTR KW_SCMD_MEMREADPTR KW_SCMD_MEMZEROPTR
117 %token <i> KW_SCMD_MEMINITPTR KW_SCMD_LOADSPOFFS KW_SCMD_CHECKNULL KW_SCMD_FADD
118 %token <i> KW_SCMD_FSUB KW_SCMD_FMULREG KW_SCMD_FDIVREG KW_SCMD_FADDREG
119 %token <i> KW_SCMD_FSUBREG KW_SCMD_FGREATER KW_SCMD_FLESSTHAN KW_SCMD_FGTE
120 %token <i> KW_SCMD_FLTE KW_SCMD_ZEROMEMORY KW_SCMD_CREATESTRING KW_SCMD_STRINGSEQUAL
121 %token <i> KW_SCMD_STRINGSNOTEQ KW_SCMD_CHECKNULLREG KW_SCMD_LOOPCHECKOFF
122 %token <i> KW_SCMD_MEMZEROPTRND KW_SCMD_JNZ KW_SCMD_DYNAMICBOUNDS KW_SCMD_NEWARRAY
123 %token <i> KW_SCMD_NEWUSEROBJECT
125 %token <i> RN_AR_NULL RN_AR_SP RN_AR_MAR RN_AR_AX RN_AR_BX RN_AR_CX RN_AR_OP RN_AR_DX
126 /* these are only used in the parser */
127 %token <i> FIXUP_LOCAL FIXUP_GLOBAL
129 %type <i> mnemonic register type export exportornot
133 module: nlsornot dataornot textornot stringsecornot fixupsecornot importsecornot exportsecornot sectionsecornot
135 fixupsecornot: fixupsec
138 fixupsec: SECTION_FIXUPS nls fixupsornot
139 fixupsornot: fixups
142 fixups: fixup
143 | fixups fixup
145 fixup: ID ':' NUMBER nls
147 sectionsecornot: sectionsec
150 sectionsec: SECTION_SECTIONS nls sectionsornot
151 sectionsornot: sections
154 sections: section
155 | sections section
157 section: STRING '=' NUMBER nls
159 exportsecornot: exportsec
162 exportsec: SECTION_EXPORTS nls exportsornot
164 exportsornot: exports
167 exports: export
168 | exports export
170 export: NUMBER STRING '\n' NUMBER ':' NUMBER nls
172 importsecornot: importsec
175 importsec: SECTION_IMPORTS nls importsornot
176 importsornot: imports
179 imports: import
180 | imports import
182 import: NUMBER STRING nls
184 stringsecornot: stringsec
187 stringsec: SECTION_STRINGS nls stringsornot
188 stringsornot: strings
191 strings: string
192 | strings string
194 string: STRING nls
196 dataornot: data
200 data: SECTION_DATA nls vardeclsornot
202 vardeclsornot: vardecls
206 vardecls: vardecl
207 | vardecls vardecl
209 vardecl: exportornot type ID nls { add_var($3, $2, 1, 0, $1); }
210 | exportornot type ID '=' NUMBER nls { add_var($3, $2, 1, $5, $1); }
211 | exportornot type '[' NUMBER ']' ID nls { add_var($6, $2, $4, 0, $1); }
212 | exportornot type '[' NUMBER ']' ID '=' NUMBER nls { add_var($6, $2, $4, $8, $1); }
215 type : D_INT
216 | D_SHORT
217 | D_CHAR
220 exportornot: export { $$ = 1; }
221 | { $$ = 0; }
224 export: D_EXPORT;
226 textornot: text
230 text: SECTION_TEXT nls funcs
232 nlsornot: nls
236 funcs: func
237 | funcs func
239 func: fndecl asmstats
241 nls: '\n'
242 | nls '\n'
244 fndecl: FN_I ':' nls { add_block($1, 1); }
246 asmstats: asmstat
247 | asmstats asmstat
249 asmstat: mnemonic nls { opcheck($1, 0, 0); INS($1, 0, 0, 0, 0);}
250 | mnemonic register nls { opcheck($1, 1, 1); INS($1, $2, 0, 0, 0);}
251 | mnemonic LABEL nls { opcheck($1, 1, 0); INS($1, LABEL, 0, 0, $2);}
252 | mnemonic NUMBER nls { opcheck($1, 1, 0); INS($1, $2, 0, 0, 0);}
253 | mnemonic NUMBER ',' NUMBER nls { opcheck($1, 2, 0); INS($1, $2, $4, 0, 0);}
254 | mnemonic register ',' register nls { opcheck($1, 2, 2); INS($1, $2, $4, 0, 0);}
255 | mnemonic register ',' NUMBER nls { opcheck($1, 2, 1); INS($1, $2, $4, 0, 0);}
256 | mnemonic register ',' STRING nls { opcheck($1, 2, 1); INS($1, $2, STRING, 0, $4);}
257 | mnemonic register ',' FN_I nls { opcheck($1, 2, 1); INS($1, $2, FN_I, 0, $4);}
258 | mnemonic register ',' FN_E nls { opcheck($1, 2, 1); INS($1, $2, FN_E, 0, $4);}
259 | mnemonic register ',' '@' ID nls { opcheck($1, 2, 1); INS($1, $2, FIXUP_LOCAL, 0, $5);}
260 | mnemonic register ',' ID nls { opcheck($1, 2, 1); INS($1, $2, FIXUP_GLOBAL, 0, $4);}
261 | mnemonic register ',' NUMBER ',' NUMBER nls { opcheck($1, 3, 1); INS($1, $2, $4, $6, 0);} /* the odd-ball newarr insn */
262 | LABEL ':' nls { add_block($1, 0); }
265 register:
266 RN_AR_SP { $$ = $1; }
267 | RN_AR_MAR { $$ = $1; }
268 | RN_AR_OP { $$ = $1; }
269 | RN_AR_AX { $$ = $1; }
270 | RN_AR_BX { $$ = $1; }
271 | RN_AR_CX { $$ = $1; }
272 | RN_AR_DX { $$ = $1; }
275 mnemonic:
276 KW_SCMD_ADD { $$ = $1; }
277 | KW_SCMD_SUB { $$ = $1; }
278 | KW_SCMD_REGTOREG { $$ = $1; }
279 | KW_SCMD_WRITELIT { $$ = $1; }
280 | KW_SCMD_RET { $$ = $1; }
281 | KW_SCMD_LITTOREG { $$ = $1; }
282 | KW_SCMD_MEMREAD { $$ = $1; }
283 | KW_SCMD_MEMWRITE { $$ = $1; }
284 | KW_SCMD_MULREG { $$ = $1; }
285 | KW_SCMD_DIVREG { $$ = $1; }
286 | KW_SCMD_ADDREG { $$ = $1; }
287 | KW_SCMD_SUBREG { $$ = $1; }
288 | KW_SCMD_BITAND { $$ = $1; }
289 | KW_SCMD_BITOR { $$ = $1; }
290 | KW_SCMD_ISEQUAL { $$ = $1; }
291 | KW_SCMD_NOTEQUAL { $$ = $1; }
292 | KW_SCMD_GREATER { $$ = $1; }
293 | KW_SCMD_LESSTHAN { $$ = $1; }
294 | KW_SCMD_GTE { $$ = $1; }
295 | KW_SCMD_LTE { $$ = $1; }
296 | KW_SCMD_AND { $$ = $1; }
297 | KW_SCMD_OR { $$ = $1; }
298 | KW_SCMD_CALL { $$ = $1; }
299 | KW_SCMD_MEMREADB { $$ = $1; }
300 | KW_SCMD_MEMREADW { $$ = $1; }
301 | KW_SCMD_MEMWRITEB { $$ = $1; }
302 | KW_SCMD_MEMWRITEW { $$ = $1; }
303 | KW_SCMD_JZ { $$ = $1; }
304 | KW_SCMD_PUSHREG { $$ = $1; }
305 | KW_SCMD_POPREG { $$ = $1; }
306 | KW_SCMD_JMP { $$ = $1; }
307 | KW_SCMD_MUL { $$ = $1; }
308 | KW_SCMD_CALLEXT { $$ = $1; }
309 | KW_SCMD_PUSHREAL { $$ = $1; }
310 | KW_SCMD_SUBREALSTACK { $$ = $1; }
311 | KW_SCMD_LINENUM { $$ = $1; }
312 | KW_SCMD_CALLAS { $$ = $1; }
313 | KW_SCMD_THISBASE { $$ = $1; }
314 | KW_SCMD_NUMFUNCARGS { $$ = $1; }
315 | KW_SCMD_MODREG { $$ = $1; }
316 | KW_SCMD_XORREG { $$ = $1; }
317 | KW_SCMD_NOTREG { $$ = $1; }
318 | KW_SCMD_SHIFTLEFT { $$ = $1; }
319 | KW_SCMD_SHIFTRIGHT { $$ = $1; }
320 | KW_SCMD_CALLOBJ { $$ = $1; }
321 | KW_SCMD_CHECKBOUNDS { $$ = $1; }
322 | KW_SCMD_MEMWRITEPTR { $$ = $1; }
323 | KW_SCMD_MEMREADPTR { $$ = $1; }
324 | KW_SCMD_MEMZEROPTR { $$ = $1; }
325 | KW_SCMD_MEMINITPTR { $$ = $1; }
326 | KW_SCMD_LOADSPOFFS { $$ = $1; }
327 | KW_SCMD_CHECKNULL { $$ = $1; }
328 | KW_SCMD_FADD { $$ = $1; }
329 | KW_SCMD_FSUB { $$ = $1; }
330 | KW_SCMD_FMULREG { $$ = $1; }
331 | KW_SCMD_FDIVREG { $$ = $1; }
332 | KW_SCMD_FADDREG { $$ = $1; }
333 | KW_SCMD_FSUBREG { $$ = $1; }
334 | KW_SCMD_FGREATER { $$ = $1; }
335 | KW_SCMD_FLESSTHAN { $$ = $1; }
336 | KW_SCMD_FGTE { $$ = $1; }
337 | KW_SCMD_FLTE { $$ = $1; }
338 | KW_SCMD_ZEROMEMORY { $$ = $1; }
339 | KW_SCMD_CREATESTRING { $$ = $1; }
340 | KW_SCMD_STRINGSEQUAL { $$ = $1; }
341 | KW_SCMD_STRINGSNOTEQ { $$ = $1; }
342 | KW_SCMD_CHECKNULLREG { $$ = $1; }
343 | KW_SCMD_LOOPCHECKOFF { $$ = $1; }
344 | KW_SCMD_MEMZEROPTRND { $$ = $1; }
345 | KW_SCMD_JNZ { $$ = $1; }
346 | KW_SCMD_DYNAMICBOUNDS { $$ = $1; }
347 | KW_SCMD_NEWARRAY { $$ = $1; }
348 | KW_SCMD_NEWUSEROBJECT { $$ = $1; }
355 statement:
356 expr { solution = yyval; }
358 expr: expr '+' expr { $$ = $1 + $3; }
359 | expr '-' expr { $$ = $1 - $3; }
360 | expr '*' expr { $$ = $1 * $3; }
361 | LPAREN expr RPAREN { $$ = $2; }
362 | '-' expr %prec UMINUS { $$ = 0 - $2; }
363 | NUMBER
368 static void print_insn(struct instruction *i) {
369 if(i->tok[0] == 0) return;
370 int op = tok2scmd(i->tok[0]);
371 const struct opcode_info *oi = &opcodes[op];
372 printf("\t%s ", oi->mnemonic);
373 switch(oi->argcount) {
374 case 0: goto end;
375 case 1:
376 if(i->strdata && i->tok[1] == LABEL)
377 printf("%s", i->strdata);
378 else if(oi->regcount == 1)
379 printf("%s", regnames[tok2reg(i->tok[1])]);
380 else printf("%d", i->tok[1]);
381 break;
382 case 2:
383 if(oi->regcount == 2)
384 printf("%s, %s", regnames[tok2reg(i->tok[1])], regnames[tok2reg(i->tok[2])]);
385 else if(oi->regcount == 0)
386 printf("%d, %d", i->tok[1], i->tok[2]);
387 else if(oi->regcount == 1) {
388 printf("%s, ", regnames[tok2reg(i->tok[1])]);
389 if(!i->strdata)
390 printf("%d", i->tok[2]);
391 else switch(i->tok[2]) {
392 case FIXUP_LOCAL:
393 printf("@");
394 /* fall through */
395 case STRING:
396 case FN_I:
397 case FN_E:
398 case FIXUP_GLOBAL:
399 printf("%s", i->strdata);
400 break;
401 default: assert(0);
404 break;
405 case 3:
406 printf("%s, %d, %d", regnames[tok2reg(i->tok[1])], i->tok[2], i->tok[3]);
407 break;
408 default: assert(0);
410 end:
411 printf("\n");
414 static int print_insns() {
415 int count = 0;
416 size_t i, nb = tglist_getsize(blocks);
417 for(i = 0; i < nb; ++i) {
418 struct basicblock *b = &tglist_get(blocks, i);
419 printf("%s:\n", b->label);
420 size_t j, ni = tglist_getsize(b->insns);
421 for(j = 0; j < ni; ++j, ++count) {
422 struct instruction *ins = &tglist_get(b->insns, j);
423 print_insn(ins);
426 return count;
428 static int opt_pushpop() {
429 int count = 0;
430 size_t i, nb = tglist_getsize(blocks);
431 for(i = 0; i < nb; ++i) {
432 struct basicblock *b = &tglist_get(blocks, i);
433 size_t j, ni = tglist_getsize(b->insns);
434 if(ni < 2) continue;
435 for(j = 0; j < ni-1; ++j) {
436 struct instruction *ins1 = &tglist_get(b->insns, j);
437 struct instruction *ins2 = &tglist_get(b->insns, j+1);
438 if(ins1->tok[0] == KW_SCMD_PUSHREG
439 && ins2->tok[0] == KW_SCMD_POPREG) {
440 if(ins1->tok[1] == ins2->tok[1]) {
441 /* push ax; pop ax -> */
442 ins1->tok[0] = 0, ins2->tok[0] = 0;
443 count += 2;
444 } else {
445 /* push ax; pop bx -> mr bx, ax */
446 ins2->tok[0] = KW_SCMD_REGTOREG;
447 ins2->tok[2] = ins1->tok[1];
448 ins1->tok[0] = 0;
449 ++count;
450 if(j+2<ni) {
451 struct instruction *ins3 = &tglist_get(b->insns, j+2);
452 if(ins3->tok[0] == KW_SCMD_REGTOREG
453 && ins3->tok[1] == ins2->tok[2]
454 && ins3->tok[2] == ins2->tok[1]) {
455 /* push ax; pop mar; mr ax, mar -> mr mar, ax */
456 ins3->tok[0] = 0;
457 ++count;
464 return count;
466 static int opt_pushlipop() {
467 int count = 0;
468 size_t i, nb = tglist_getsize(blocks);
469 for(i = 0; i < nb; ++i) {
470 struct basicblock *b = &tglist_get(blocks, i);
471 size_t j, ni = tglist_getsize(b->insns);
472 if(ni < 3) continue;
473 for(j = 0; j < ni-2; ++j) {
474 struct instruction *ins1 = &tglist_get(b->insns, j);
475 struct instruction *ins2 = &tglist_get(b->insns, j+1);
476 struct instruction *ins3 = &tglist_get(b->insns, j+2);
477 if(ins1->tok[0] == KW_SCMD_PUSHREG
478 && ins2->tok[0] == KW_SCMD_LITTOREG
479 && ins3->tok[0] == KW_SCMD_POPREG) {
480 if(ins1->tok[1] == ins3->tok[1]
481 && ins1->tok[1] != ins2->tok[1]) {
482 /* push ax; li bx, 1; pop ax -> li bx, 1 */
483 ins1->tok[0] = 0, ins3->tok[0] = 0;
484 count += 2;
485 } else if(ins1->tok[1] == ins2->tok[1]) {
486 /* this one is called "ll - load literal in py optimizer */
487 /* push ax; li ax, 1; pop bx -> mr bx, ax; li ax, 1 */
488 ins1->tok[0] = KW_SCMD_REGTOREG;
489 ins1->tok[1] = ins3->tok[1];
490 ins1->tok[2] = ins2->tok[1];
491 ins3->tok[0] = 0;
492 ++count;
497 return count;
499 #include "regusage.h"
500 static int is_reg_overwritten(int reg, struct basicblock *b, size_t first, size_t count)
502 size_t i, j;
503 for(i=first; i<count; ++i) {
504 struct instruction *ins = &tglist_get(b->insns, i);
505 int op = tok2scmd(ins->tok[0]);
506 if(op == SCMD_JMP) break; /* we can't see what happens past uncond. jump */
507 /* if the func returns we don't need to save the reg, so we can classify
508 it as being discarded/overwritten */
509 else if(op == SCMD_RET) return 1;
510 const struct opcode_info *oi = &opcodes[op];
511 for(j=0;j<oi->regcount;++j) if(tok2reg(ins->tok[1+j]) == reg) {
512 const struct regaccess_info *ri = &regaccess_info[op];
513 unsigned char rub[2], *ru = &ri->ra_reg1;
514 if(op == SCMD_REGTOREG) {
515 /* since the tokens in our block represent the textual
516 representation, but the regusage data binary, we need
517 to swap the values here, as 'mr' is the oddball
518 instruction with switched registers. */
519 rub[0] = ru[1];
520 rub[1] = ru[0];
521 ru = rub;
523 switch(ru[j]) {
524 case RA_READ: case RA_READWRITE:
525 return 0;
526 case RA_WRITE:
527 return 1;
531 return 0;
534 static int opt_loadnegfloat() {
535 int count = 0;
536 size_t i, nb = tglist_getsize(blocks);
537 for(i = 0; i < nb; ++i) {
538 struct basicblock *b = &tglist_get(blocks, i);
539 size_t j, ni = tglist_getsize(b->insns);
540 if(ni < 4) continue;
541 for(j = 0; j < ni-3; ++j) {
542 struct instruction *ins1 = &tglist_get(b->insns, j);
543 struct instruction *ins2 = &tglist_get(b->insns, j+1);
544 struct instruction *ins3 = &tglist_get(b->insns, j+2);
545 struct instruction *ins4 = &tglist_get(b->insns, j+3);
546 if(ins1->tok[0] == KW_SCMD_LITTOREG
547 && ins2->tok[0] == KW_SCMD_LITTOREG
548 && ins3->tok[0] == KW_SCMD_FSUBREG
549 && ins4->tok[0] == KW_SCMD_REGTOREG
550 && ins2->tok[2] == 0
551 && ins3->tok[1] == ins2->tok[1]
552 && ins3->tok[2] == ins1->tok[1]
553 && ins4->tok[1] == ins1->tok[1]
554 && ins4->tok[2] == ins2->tok[1]
556 float f;
557 memcpy(&f, &ins1->tok[2], 4);
558 f = 0 - f;
559 memcpy(&ins1->tok[2], &f, 4);
560 /* scan rest of block whether reg of ins2 is later discarded */
561 if(is_reg_overwritten(tok2reg(ins2->tok[1]), b, j+4, ni)) {
562 ins2->tok[0] = 0;
563 ++count;
564 } else
565 memcpy(&ins2->tok[2], &f, 4);
566 ins3->tok[0] = 0;
567 ins4->tok[0] = 0;
568 count += 2;
572 return count;
574 static int opt_loadnegint() {
575 int count = 0;
576 size_t i, nb = tglist_getsize(blocks);
577 for(i = 0; i < nb; ++i) {
578 struct basicblock *b = &tglist_get(blocks, i);
579 size_t j, ni = tglist_getsize(b->insns);
580 if(ni < 4) continue;
581 for(j = 0; j < ni-3; ++j) {
582 struct instruction *ins1 = &tglist_get(b->insns, j);
583 struct instruction *ins2 = &tglist_get(b->insns, j+1);
584 struct instruction *ins3 = &tglist_get(b->insns, j+2);
585 struct instruction *ins4 = &tglist_get(b->insns, j+3);
586 if(ins1->tok[0] == KW_SCMD_LITTOREG
587 && ins2->tok[0] == KW_SCMD_LITTOREG
588 && ins3->tok[0] == KW_SCMD_SUBREG
589 && ins4->tok[0] == KW_SCMD_REGTOREG
590 && ins2->tok[2] == 0
591 && ins3->tok[1] == ins2->tok[1]
592 && ins3->tok[2] == ins1->tok[1]
593 && ins4->tok[1] == ins1->tok[1]
594 && ins4->tok[2] == ins2->tok[1]
596 int x = -ins1->tok[2];
597 ins1->tok[2] = x;
598 /* scan rest of block whether reg of ins2 is later discarded */
599 if(is_reg_overwritten(tok2reg(ins2->tok[1]), b, j+4, ni)) {
600 ins2->tok[0] = 0;
601 ++count;
602 } else
603 ins2->tok[2] = x;
604 ins3->tok[0] = 0;
605 ins4->tok[0] = 0;
606 count += 2;
610 return count;
613 static void discard_removed_insns() {
614 int count = 0;
615 size_t i, j, nb = tglist_getsize(blocks);
616 for(i = 0; i < nb; ++i) {
617 struct basicblock *b = &tglist_get(blocks, i);
618 for(j = 0; j < tglist_getsize(b->insns); ) {
619 struct instruction *ins = &tglist_get(b->insns, j);
620 if(ins->tok[0] == 0) tglist_delete(b->insns, j);
621 else ++j;
626 static void optimize() {
627 dprintf(2, "loadnegfloat: removed %d insns\n", opt_loadnegfloat());
628 dprintf(2, "loadnegint: removed %d insns\n", opt_loadnegint());
629 discard_removed_insns();
630 dprintf(2, "pushpop: removed %d insns\n", opt_pushpop());
631 discard_removed_insns();
632 dprintf(2, "pushlipop: removed %d insns\n", opt_pushlipop());
635 static int parse_one(char *fn) {
636 vars = tglist_new();
637 blocks = tglist_new();
638 int ret = yyparse();
639 printf("%s: %s\n", fn, (const char*[]){"FAIL", "OK"}[ret==0]);
640 optimize();
641 print_insns();
642 tglist_free(vars);
643 tglist_free(blocks);
644 return ret;
647 int main(int argc, char **argv) {
648 #if YYDEBUG
649 yydebug = 1;
650 #endif
651 yyfatalerrors = 0;
652 int errs = 0;
653 if(argc == 1) return parse_one("stdin");
654 else while(*(++argv)) {
655 FILE* f;
656 f = fopen(*argv, "r");
657 if(!f) {
658 complain("error opening %s!\n", *argv);
659 continue;
661 yylex_reset(f, *argv);
662 if(parse_one(*argv)) errs++;
663 fclose(f);
665 return !!errs;