84#define DIRECT_PAGE 0x2100
87#define KEEP_COMMENTS 1
89#define DO_DIRECT_PAGE 1
94static inline char _toUpper(
char a) {
95 return (a>=
'a' && a<=
'z') ? a-
'a'+
'A' : a;
99static inline int _eol(
char c) {
100 return c==
'\0' || c==
'\n';
104static inline int _eq(
char pat,
char txt) {
105 return (pat<=
' ') ? (txt<=
' ') : (_toUpper(pat)==_toUpper(txt));
110 char * _buffer = buf->
str;
115 if ( *_buffer ==
'\r' || *_buffer ==
'\n' ) {
119 if ( *_buffer ==
' ' || *_buffer ==
'\t' ) {
121 }
else if ( *_buffer ==
';' ) {
131static int change = 0;
132static int peephole_pass = 0;
133static int num_dp = 0;
134static int num_inlined = 0;
135static int num_unread = 0;
138static void optim(
POBuffer buf,
const char *rule,
const char *repl, ...)
139 __attribute__ ((format (printf, 3, 4)));
144#define RULE "r" R_(__LINE__) " "
148static void optim(
POBuffer buf,
const char *rule,
const char *repl, ...) {
157 if(rule)
po_buf_printf(tmp,
"; peephole(%d): %s\n", peephole_pass, rule);
163 if ( (s = strchr(buf->
str,
'\n')) != NULL) *s =
'\0';
186static int isZero(
char *s) {
188 while(*s ==
'0') ++s;
192 return buf!=NULL && isZero(buf->
str);
196static int chg_reg(
POBuffer buf,
char * REG) {
197 if ( strcmp( REG,
"A" ) == 0 ) {
204 }
else if ( strcmp( REG,
"X" ) == 0 ) {
206 }
else if ( strcmp( REG,
"Y" ) == 0 ) {
228static int chg_write(
POBuffer buf,
char * REG) {
229 if ( strcmp( REG,
"A" ) == 0 ) {
231 }
else if ( strcmp( REG,
"X" ) == 0 ) {
233 }
else if ( strcmp( REG,
"Y" ) == 0 ) {
275 optim( buf[0],
RULE "(JSR, RTS)->(JMP)",
"\tJMP %s", v1->
str );
276 optim( buf[1],
RULE "(JSR, RTS)->(JMP)", NULL );
281 optim( buf[0],
RULE "(LDA #, LDA #)->(LDA #)", NULL );
456 && strstr( v1->
str,
"$" ) == NULL
458 optim( buf[0],
RULE "(LDA x, LDA x)->(LDA x) [1]", NULL );
463 chg_write( buf[1], v1->
str) &&
465 && strcmp( v1->
str, v3->
str ) == 0 && strcmp( v2->
str, v4->
str ) == 0
466 && strchr( v4->
str,
'+' ) == NULL ) {
467 optim( buf[2],
RULE "(LD x, |STx, LD y)->(LD y)", NULL );
472 chg_write( buf[1], v1->
str) &&
473 chg_write( buf[2], v1->
str) &&
475 && strcmp( v1->
str, v3->
str ) == 0 && strcmp( v2->
str, v4->
str ) == 0 ) {
476 optim( buf[3],
RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
481 chg_write( buf[1], v1->
str) &&
482 chg_write( buf[2], v1->
str) &&
483 chg_write( buf[3], v1->
str) &&
485 && strcmp( v1->
str, v3->
str ) == 0 && strcmp( v2->
str, v4->
str ) == 0 ) {
486 optim( buf[4],
RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
491 chg_write( buf[1], v1->
str) &&
492 chg_write( buf[2], v1->
str) &&
493 chg_write( buf[3], v1->
str) &&
494 chg_write( buf[4], v1->
str) &&
496 && strcmp( v1->
str, v3->
str ) == 0 && strcmp( v2->
str, v4->
str ) == 0 ) {
497 optim( buf[5],
RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
502 chg_write( buf[1], v1->
str) &&
503 chg_write( buf[2], v1->
str) &&
504 chg_write( buf[3], v1->
str) &&
505 chg_write( buf[4], v1->
str) &&
506 chg_write( buf[5], v1->
str) &&
508 && strcmp( v1->
str, v3->
str ) == 0 && strcmp( v2->
str, v4->
str ) == 0 ) {
509 optim( buf[6],
RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
515 && strcmp( v1->
str, v3->
str ) == 0 && strcmp( v2->
str, v4->
str ) == 0 &&
516 strstr( v2->
str,
"$FF" ) == NULL ) {
517 optim( buf[1],
RULE "(STx y, LDx y)->()", NULL );
528 strcmp( v2->
str, v3->
str ) == 0 ) {
529 optim( buf[2],
RULE "(LDA x, STA y, LDA y, STz)->(LDA x, STA z)", NULL );
641static void vars_clear(
void) {
643 for(i=0; i<vars.size; ++i) {
644 struct var *v = &vars.tab[i];
646 if(v->init)
free(v->init);
655 struct var *ret = NULL;
658 char *s=strchr(
name,
'+');
663 memmove( s, s+2, strlen(
name)-2);
669 memmove( s, s+2, strlen(
name)-2);
673 for(i=0; i<vars.size ; ++i) {
674 if(strcmp(vars.tab[i].name,
name)==0) {
679 if(vars.size == vars.capacity) {
681 vars.tab = realloc(vars.tab,
sizeof(*vars.tab)*vars.capacity);
683 ret = &vars.tab[vars.size++];
684 ret->name = strdup(
name);
773 strstr(
"A X Y", tmp->
str)!=NULL
783 strstr(
"A X Y", tmp->
str)!=NULL
791 strstr(
"A X Y", tmp->
str)!=NULL
820 strstr(
"A X Y", tmp->
str)!=NULL
828 strstr(
"A X Y", tmp->
str)!=NULL
836 strstr(
"A X Y", tmp->
str)!=NULL
877 if(
po_buf_match( buf[0],
" ST* *", tmp, arg ) && strstr(
"A X Y", tmp->
str)!=NULL )
925 if(
po_buf_match( buf[0],
"*: .byte *", tmp, arg) && vars_ok(tmp) && strchr(arg->
str,
',')==NULL ) {
928 v->init = strdup(isZero(arg->
str) ?
"1-1" : arg->
str);
932 if(
po_buf_match(buf[0],
"*: .word *", tmp, arg) && vars_ok(tmp) && strchr(arg->
str,
',')==NULL ) {
935 v->init = strdup(arg->
str);
938 if(
po_buf_match(buf[0],
"*: .res *,*", tmp, arg, arg2) && vars_ok(tmp) ) {
940 v->size = atoi( arg->
str );
941 v->init = strdup( arg2->
str );
943 }
else if(
po_buf_match(buf[0],
"*: .res *,*", tmp, arg, arg2) && vars_ok(tmp) ) {
945 v->size = atoi( arg->
str );
946 v->init = strdup( arg2->
str );
948 }
else if(
po_buf_match(buf[0],
"*: .res *", tmp, arg) && vars_ok(tmp) ) {
950 v->size = atoi( arg->
str );
955 if(
po_buf_match(buf[0],
" * *", tmp, arg) )
if(vars_ok(arg)) {
958 if ( (v->offset > -2) ) {
990 if ( v->offset == -1 ) {
1005static int vars_cmp(
const void *_a,
const void *_b) {
1006 const struct var *a = _a;
1007 const struct var *b = _b;
1009 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
1011 return -(diff!=0 ? diff : strcmp(a->name, b->name));
1025 if(
po_buf_match( buf[1],
" ST* *, *", op, var, tmp) && vars_ok(var)) {
1027 if(v->nb_rd == 0 && v->offset!=-2 && strchr(v->name,
'+') == NULL && strchr(v->name,
'-') == NULL) {
1029 optim(buf[1],
"unread", NULL);
1032 }
else if(
po_buf_match( buf[1],
" ST* *", op, var) && vars_ok(var)) {
1034 if(v->nb_rd == 0 && v->offset!=-2 && strchr(v->name,
'+') == NULL && strchr(v->name,
'-') == NULL) {
1036 optim(buf[1],
"unread", NULL);
1048 )
if(vars_ok(var)) {
1052 if ( v->offset==-2 ) {
1055 optim(buf[0],
"inlined",NULL);
1058 if(v->nb_rd==0 && 0<v->size && 0==(v->flags &
NO_REMOVE)) {
1059 optim(buf[0],
"unread",NULL);
1068static void out(FILE *f,
POBuffer _buf) {
1069 char *s = _buf->
str;
1071 while(*s==
' ' || *s==
'\t') {
tab = 1; ++s;}
1072 if(
tab) fputs(
"\t", f);
1077static void fixes_indexed_syntax(
POBuffer buf) {
1081 if(!_eq(
' ', *s))
return;
1084 do ++s;
while(*s && _eq(
' ', *s));
1090 while(*s && !_eq(
' ', *s)) ++s;
1094 do ++s;
while(*s && _eq(
' ', *s));
1098 do ++s;
while(*s && !_eq(
' ', *s));
1129 if(
po_buf_match( buf[0],
" * *", op, var) && vars_ok(var) && strstr( buf[0]->str,
"#<") == NULL && strstr( buf[0]->str,
"#>") == NULL ) {
1132 if( v->offset == -1 && v->size == 1 && chg_reg2(op) ) {
1134 if ( strstr( var->
str,
"+" ) == NULL ) {
1137 optim(buf[0],
"inlined1",
"\t%s #%s%s\n%s = *-%d", op->
str,
1138 v->init==NULL ?
"*" : v->init,
1139 v->init==NULL ? (v->size==2 ?
"" :
"&255") :
"",
1148 ||
po_buf_match( buf[0],
"*: .word ", var) )
if(vars_ok(var)) {
1150 if(v->offset == -2) {
1151 optim(buf[0],
"inlined3", NULL);
1159static void vars_prepare_relocation(
void) {
1165 qsort(vars.tab, vars.size,
sizeof(*vars.tab), vars_cmp);
1167 for(i = 0; i<vars.size; ++i) {
1168 struct var *v = &vars.tab[i];
1171 if(v->size == 0)
continue;
1174 if(v->nb_rd == 0)
continue;
1181 if(v->offset == -1 && v->size>2) v->offset = 0;
1234 FILE * fileOptimized;
1241 int sourceLine = -1;
1246 adiline2(
"POP:0:%d:%d", peephole_pass, kind );
1259 vars_prepare_relocation();
1271 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1272 if(fileAsm == NULL) {
1277 fileOptimized = fopen( fileNameOptimized,
"wt" );
1278 if(fileOptimized == NULL) {
1279 perror(fileNameOptimized);
1289 while( still_to_go ) {
1291 if ( line >=
LOOK_AHEAD ) out(fileOptimized, buf[0]);
1308 sourceLine = atoi( ln->
str );
1321 }
while(!feof(fileAsm));
1325 basic_peephole(_environment, buf, zA, zB);
1328 if(change == 0) vars_scan(buf);
1332 vars_remove(_environment, buf);
1337 vars_relocate(_environment, buf);
1350 fprintf(fileOptimized,
"; peephole: pass %d, %d change%s.\n", peephole_pass,
1351 change, change>1 ?
"s":
"");
1355 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s removed.\n", peephole_pass,
1356 num_unread, num_unread>1 ?
"s":
"");
1360 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
1361 num_dp, num_dp>1 ?
"s":
"",
1362 num_inlined, num_inlined>1 ?
"s":
"");
1369 (void)fclose(fileAsm);
1370 (void)fclose(fileOptimized);
1383 struct _UnusedSymbol *
next;
1387static void optim_remove_unused_temporary(
Environment * _environment ) {
1404 FILE * fileOptimized;
1408 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1409 if(fileAsm == NULL) {
1414 fileOptimized = fopen( fileNameOptimized,
"wt" );
1415 if(fileOptimized == NULL) {
1416 perror(fileNameOptimized);
1427 while( !feof(fileAsm) ) {
1437 s->
next = currentlyUnusedSymbols;
1438 currentlyUnusedSymbols = s;
1443 s->
next = currentlySymbols;
1444 currentlySymbols = s;
1449 s->
next = currentlyUnusedSymbolsQ;
1450 currentlyUnusedSymbolsQ = s;
1455 s->
next = currentlySymbolsQ;
1456 currentlySymbolsQ = s;
1467 fseek( fileAsm, vspPointer, SEEK_SET );
1469 while( !feof(fileAsm) ) {
1474 if ( ! result ) result =
po_buf_match(bufLine,
" AND *", v1 );
1475 if ( ! result ) result =
po_buf_match(bufLine,
" EOR *", v1 );
1476 if ( ! result ) result =
po_buf_match(bufLine,
" LD* *", v2, v1 );
1477 if ( ! result ) result =
po_buf_match(bufLine,
" ORA *", v1 );
1478 if ( ! result ) result =
po_buf_match(bufLine,
" SBC *", v1 );
1479 if ( ! result ) result =
po_buf_match(bufLine,
" CMP *", v1 );
1480 if ( ! result ) result =
po_buf_match(bufLine,
" CPX *", v1 );
1481 if ( ! result ) result =
po_buf_match(bufLine,
" CPY *", v1 );
1483 char * realVarName = strdup( v1->
str );
1484 char * c = strstr( realVarName,
"+" );
1488 c = strstr( realVarName,
"#" );
1495 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1499 currentlyUnusedSymbols = tmp->
next;
1507 tmp = currentlyUnusedSymbolsQ;
1510 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1514 currentlyUnusedSymbolsQ = tmp->
next;
1537 fseek( fileAsm, vspPointer, SEEK_SET );
1547 while( !feof(fileAsm) ) {
1549 int endOfSection = 0;
1551 if ( line >= 2 ) out(fileOptimized, buf[0]);
1558 while(
isAComment( buf[4] ) && !endOfSection && !feof( fileAsm ) ) {
1590 char * realVarName = strdup( v2->
str );
1591 char * c = strstr( realVarName,
"+" );
1598 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1607 optim( buf[0],
RULE "unused temporary", NULL );
1608 optim( buf[1],
RULE "unused temporary", NULL );
1609 optim( buf[3],
RULE "unused temporary",
"\tCMP #$%s", v1->
str );
1628 char * realVarName = strdup( v2->
str );
1629 char * c = strstr( realVarName,
"+" );
1636 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1646 optim( buf[1],
RULE "unused temporary", NULL );
1647 optim( buf[2],
RULE "unused temporary", NULL );
1661 char * realVarName = strdup( v2->
str );
1662 char * c = strstr( realVarName,
"+" );
1669 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1679 optim( buf[2],
RULE "unused temporary", NULL );
1698 char * realVarName = strdup( v1->
str );
1699 char * c = strstr( realVarName,
"+" );
1706 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1716 optim( buf[3],
RULE "unused temporary", NULL );
1722 if ( endOfSection ) {
1725 out(fileOptimized, buf[0]);
1726 out(fileOptimized, buf[1]);
1727 out(fileOptimized, buf[2]);
1728 out(fileOptimized, buf[3]);
1729 out(fileOptimized, buf[4]);
1740 vspPointer = ftell( fileAsm );
1744 currentlyUnusedSymbols = NULL;
1745 currentlyUnusedSymbolsQ = NULL;
1751 fseek( fileAsm, vspPointer, SEEK_SET );
1753 while( !feof(fileAsm) ) {
1757 out(fileOptimized, bufLine);
1761 (void)fclose(fileAsm);
1762 (void)fclose(fileOptimized);
1971static void optim_remove_comments(
Environment * _environment ) {
1979 FILE * fileOptimized;
1983 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1984 if(fileAsm == NULL) {
1989 fileOptimized = fopen( fileNameOptimized,
"wt" );
1990 if(fileOptimized == NULL) {
1991 perror(fileNameOptimized);
1995 while( !feof(fileAsm) ) {
2000 out( fileOptimized, bufLine );
2005 (void)fclose(fileAsm);
2006 (void)fclose(fileOptimized);
2016 optim_remove_unused_temporary( _environment );
2027 while(optim_pass(_environment, buf,
PEEPHOLE)&&optimization_limit_count) {
2028 --optimization_limit_count;
2030 optim_pass(_environment, buf,
DEADVARS);
2031 }
while(change&&optimization_limit_count);
2038 optim_remove_unused_temporary( _environment );
2040 optim_remove_comments(_environment);
2062 int sourceLine = -1;
2069 fileAsm = fopen( _environment->
asmFileName,
"rb" );
2070 if(fileAsm == NULL) {
2076 if(fileListing == NULL) {
2084 while( !feof(fileAsm) && !feof(fileListing)) {
2092 sourceLine = atoi( ln->
str );
2103 *bufferListing->
str = 0;
2104 pos = ftell( fileListing );
2107 while( !feof(fileListing) && (strstr( bufferListing->
str, bufferAsm->
str ) == NULL) ) {
2109 if ( ! posUpdated ) {
2111 pos = ftell( fileListing );
2116 if ( feof(fileListing) ) {
2119 pos = ftell( fileListing );
2120 char * bufferAsmEscaped = strdup( bufferAsm->
str );
2121 for(
int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
2122 if ( bufferAsmEscaped[i] ==
':' ) {
2123 bufferAsmEscaped[i] = 6;
2125 if ( bufferAsmEscaped[i] == 9 ) {
2126 bufferAsmEscaped[i] =
' ';
2130 if (
po_buf_match( bufferListing,
"* * * * * *", bufferAddress, bufferVersion,
2131 bufferA, bufferB, bufferC, bufferD ) ) {
2132 if ( bufferAddress->
len == 7 ) {
2133 if ( bufferA->
len == 2 &&
2134 ( ( isxdigit( bufferA->
str[0] ) && isxdigit( bufferA->
str[1] ) ) || strcmp( bufferA->
str,
"rr" ) == 0 )
2136 if ( bufferB->
len == 2 &&
2137 ( ( isxdigit( bufferB->
str[0] ) && isxdigit( bufferB->
str[1] ) ) || strcmp( bufferB->
str,
"rr" ) == 0 )
2139 if ( bufferC->
len == 2 &&
2140 ( ( isxdigit( bufferC->
str[0] ) && isxdigit( bufferC->
str[1] ) ) || strcmp( bufferC->
str,
"rr" ) == 0 )
2142 if ( bufferD->
len == 2 &&
2143 ( ( isxdigit( bufferD->
str[0] ) && isxdigit( bufferD->
str[1] ) ) || strcmp( bufferD->
str,
"rr" ) == 0 )
2146 }
else if (
po_buf_match( bufferListing,
"* * * * *", bufferAddress, bufferVersion,
2147 bufferA, bufferB, bufferC ) ) {
2148 if ( bufferAddress->
len == 7 ) {
2149 if ( bufferA->
len == 2 &&
2150 ( ( isxdigit( bufferA->
str[0] ) && isxdigit( bufferA->
str[1] ) ) || strcmp( bufferA->
str,
"rr" ) == 0 )
2152 if ( bufferB->
len == 2 &&
2153 ( ( isxdigit( bufferB->
str[0] ) && isxdigit( bufferB->
str[1] ) ) || strcmp( bufferB->
str,
"rr" ) == 0 )
2155 if ( bufferC->
len == 2 &&
2156 ( ( isxdigit( bufferC->
str[0] ) && isxdigit( bufferC->
str[1] ) ) || strcmp( bufferC->
str,
"rr" ) == 0 )
2159 }
else if (
po_buf_match( bufferListing,
"* * * *", bufferAddress, bufferVersion,
2160 bufferA, bufferB ) ) {
2161 if ( bufferAddress->
len == 7 ) {
2162 if ( bufferA->
len == 2 &&
2163 ( ( isxdigit( bufferA->
str[0] ) && isxdigit( bufferA->
str[1] ) ) || strcmp( bufferA->
str,
"rr" ) == 0 )
2165 if ( bufferB->
len == 2 &&
2166 ( ( isxdigit( bufferB->
str[0] ) && isxdigit( bufferB->
str[1] ) ) || strcmp( bufferB->
str,
"rr" ) == 0 )
2169 }
else if (
po_buf_match( bufferListing,
"* * *", bufferAddress, bufferVersion,
2171 if ( bufferAddress->
len == 7 ) {
2172 if ( bufferA->
len == 2 &&
2173 ( ( isxdigit( bufferA->
str[0] ) && isxdigit( bufferA->
str[1] ) ) || strcmp( bufferA->
str,
"rr" ) == 0 )
2181 fseek( fileListing, pos, SEEK_SET );
2189 (void)fclose(fileListing);
2190 (void)fclose(fileAsm);
char * get_temporary_filename(Environment *_environment)
struct _UnusedSymbol UnusedSymbol
struct @110344003176124301103124235173106120065272160135::var * tab
void target_finalize(Environment *_environment)
void target_peephole_optimizer(Environment *_environment)
struct var * vars_get(POBuffer _name)
int isAComment(POBuffer buf)
POBuffer po_buf_match(POBuffer _buf, const char *_pattern,...)
POBuffer po_buf_new(int size)
POBuffer po_buf_printf(POBuffer buf, const char *fmt,...)
POBuffer po_buf_cpy(POBuffer buf, char *string)
POBuffer po_buf_del(POBuffer buf)
POBuffer po_buf_add(POBuffer buf, char c)
int po_buf_trim(POBuffer buf)
POBuffer po_buf_vprintf(POBuffer buf, const char *fmt, va_list ap)
POBuffer po_buf_cat(POBuffer buf, char *string)
int po_buf_cmp(POBuffer a, POBuffer b)
POBuffer po_buf_fgets(POBuffer buf, FILE *f)
int currentSourceLineAnalyzed
FILE * additionalInfoFile
int peepholeOptimizationLimit
struct _UnusedSymbol * next
#define adiline4(s, a, b, c, d)
#define MAX_TEMPORARY_STORAGE
enum _PeepHoleOptimizationKind PeepHoleOptimizationKind
struct _POBuffer * POBuffer
struct _Environment Environment
Structure of compilation environment.
#define adiline3(s, a, b, c)
#define BUILD_SAFE_MOVE(_environment, source, destination)
#define adiline2(s, a, b)
char * strcopy(char *_dest, char *_source)