8 extern
void yyerror(char*);
10 extern
const char *yyfilename
;
11 extern
int yyfatalerrors
;
12 void yylex_reset
(FILE *f
, const char *fn
);
35 tglist
(struct instruction
) *insns
;
38 tglist
(struct variable
) *vars
;
39 tglist
(struct basicblock
) *blocks
;
41 #define complain(fmt, args...) do { fprintf(stderr, "%d: " fmt, yylineno, ## args); exit(1); } while(0)
44 #define tok2scmd(tok) ((tok - KW_SCMD_ADD) + SCMD_ADD)
45 #define tok2reg(tok) ((tok - RN_AR_SP) + AR_SP)
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
= {
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]},
78 size_t l
= tglist_getsize
(blocks
);
80 tglist_add
(tglist_get
(blocks
, l
).insns
, i
);
83 static void add_var
(char *id
, int type
, int nelems
, int value
, int export
)
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
145 fixup: ID
':' NUMBER nls
147 sectionsecornot: sectionsec
150 sectionsec: SECTION_SECTIONS nls sectionsornot
151 sectionsornot: sections
157 section: STRING
'=' NUMBER nls
159 exportsecornot: exportsec
162 exportsec: SECTION_EXPORTS nls exportsornot
164 exportsornot: exports
170 export: NUMBER STRING
'\n' NUMBER
':' NUMBER nls
172 importsecornot: importsec
175 importsec: SECTION_IMPORTS nls importsornot
176 importsornot: imports
182 import: NUMBER STRING nls
184 stringsecornot: stringsec
187 stringsec: SECTION_STRINGS nls stringsornot
188 stringsornot: strings
200 data: SECTION_DATA nls vardeclsornot
202 vardeclsornot: vardecls
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); }
220 exportornot: export
{ $$
= 1; }
230 text: SECTION_TEXT nls funcs
239 func: fndecl asmstats
244 fndecl: FN_I
':' nls
{ add_block
($1, 1); }
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); }
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; }
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; }
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; }
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
) {
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]);
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])]);
390 printf
("%d", i
->tok
[2]);
391 else switch
(i
->tok
[2]) {
399 printf
("%s", i
->strdata
);
406 printf
("%s, %d, %d", regnames
[tok2reg
(i
->tok
[1])], i
->tok
[2], i
->tok
[3]);
414 static int print_insns
() {
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
);
428 static int opt_pushpop
() {
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
);
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;
445 /* push ax; pop bx -> mr bx, ax */
446 ins2
->tok
[0] = KW_SCMD_REGTOREG
;
447 ins2
->tok
[2] = ins1
->tok
[1];
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 */
466 static int opt_pushlipop
() {
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
);
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;
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];
499 #include "regusage.h"
500 static int is_reg_overwritten
(int reg
, struct basicblock
*b
, size_t first
, size_t count
)
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
= ®access_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. */
524 case RA_READ
: case RA_READWRITE
:
534 static int opt_loadnegfloat
() {
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
);
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
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]
557 memcpy
(&f
, &ins1
->tok
[2], 4);
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
)) {
565 memcpy
(&ins2
->tok
[2], &f
, 4);
574 static int opt_loadnegint
() {
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
);
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
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];
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
)) {
613 static void discard_removed_insns
() {
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
);
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
) {
637 blocks
= tglist_new
();
639 printf
("%s: %s\n", fn
, (const char*[]){"FAIL", "OK"}[ret
==0]);
647 int main
(int argc
, char **argv
) {
653 if
(argc
== 1) return parse_one
("stdin");
654 else while
(*(++argv
)) {
656 f
= fopen
(*argv
, "r");
658 complain
("error opening %s!\n", *argv
);
661 yylex_reset
(f
, *argv
);
662 if
(parse_one
(*argv
)) errs
++;