85#define DIRECT_PAGE 0x2100
88#define KEEP_COMMENTS 1
90#define DO_DIRECT_PAGE 1
95static inline char _toUpper(
char a) {
96 return (a>=
'a' && a<=
'z') ? a-
'a'+
'A' : a;
100static inline int _eol(
char c) {
101 return c==
'\0' || c==
'\n';
105static inline int _eq(
char pat,
char txt) {
106 return (pat<=
' ') ? (txt<=
' ') : (_toUpper(pat)==_toUpper(txt));
111 char * _buffer = buf->
str;
116 if ( *_buffer ==
'\r' || *_buffer ==
'\n' ) {
120 if ( *_buffer ==
' ' || *_buffer ==
'\t' ) {
122 }
else if ( *_buffer ==
';' ) {
132static int change = 0;
133static int peephole_pass = 0;
134static int num_dp = 0;
135static int num_inlined = 0;
136static int num_unread = 0;
139static void optim(
POBuffer buf,
const char *rule,
const char *repl, ...)
140 __attribute__ ((format (printf, 3, 4)));
145#define RULE "r" R_(__LINE__) " "
149static void optim(
POBuffer buf,
const char *rule,
const char *repl, ...) {
158 if(rule)
po_buf_printf(tmp,
"; peephole(%d): %s\n", peephole_pass, rule);
164 if ( (s = strchr(buf->
str,
'\n')) != NULL) *s =
'\0';
187static int isZero(
char *s) {
189 while(*s ==
'0') ++s;
193 return buf!=NULL && isZero(buf->
str);
195static int isNumber(
char *s) {
196 for(
int i=0, c=strlen(s); i<c; ++i ) {
197 if ( !isdigit( s[i] ) ) {
204 return buf!=NULL && isNumber(buf->
str);
227 if(
po_buf_match( buf[0],
" LD *, *", v1, v2) && strchr(
"A", _toUpper(*v1->
str) ) && _isNumber( v2 ) && atoi( v2->
str ) == 0 ) {
228 optim( buf[0],
RULE "(LD A, 0)->(XOR A)",
"\tXOR %c", _toUpper(*v1->
str) );
240 optim( buf[0],
RULE "(LD B, x; LD C, x)->(LD BC, xx)",
"\tLD BC, ($%s * 256) + $%s", v1->
str, v2->
str );
241 optim( buf[1],
"", NULL );
250 optim( buf[2],
RULE "(LD A, x; LD (x), A; LD A, x)->(LD A, x; LD (x), A)", NULL );
319 optim( buf[0],
RULE "(XOR $FF)->(CPL)",
"\tCPL" );
349 optim( buf[0],
RULE "(SLA+RL)->(ADD)",
"\tADD HL, HL" );
350 optim( buf[1], NULL, NULL );
384 optim( buf[0],
RULE "(CALL+RET)->(JP)",
"\tJMP %s", v1->
str );
385 optim( buf[1], NULL, NULL );
398 optim( buf[0],
RULE "(DEC B+JR NZ)->(DJNZ)",
"\tDJNZ %s", v1->
str );
399 optim( buf[1], NULL, NULL );
407 strstr( v1->
str,
"$FF" ) == NULL
409 && strstr( v1->
str,
"rP1" ) == NULL
412 optim( buf[0],
RULE "(LD A, *; LD A, *)->(LD, A)", NULL );
440static void vars_clear(
void) {
442 for(i=0; i<vars.size; ++i) {
443 struct var *v = &vars.tab[i];
445 if(v->init)
free(v->init);
454 struct var *ret = NULL;
457 char *s=strchr(
name,
'+');
460 for(i=0; i<vars.size ; ++i) {
461 if(strcmp(vars.tab[i].name,
name)==0) {
466 if(vars.size == vars.capacity) {
468 vars.tab = realloc(vars.tab,
sizeof(*vars.tab)*vars.capacity);
470 ret = &vars.tab[vars.size++];
471 ret->name = strdup(
name);
490 if(
name->str[0]==
'_')
return 1;
516 if(
po_buf_match( buf[0],
" LD *, (*+*)", tmp, arg, ofs ) ) {
if(vars_ok(arg)) {
519 } }
else if(
po_buf_match( buf[0],
" LD *, (*+*)", tmp, arg, ofs ) ) {
if(vars_ok(arg)) {
522 } }
else if(
po_buf_match( buf[0],
" LD *, (*)", tmp, arg ) ) {
if(vars_ok(arg)) {
525 } }
else if(
po_buf_match( buf[0],
" LD *,(*)", tmp, arg ) ) {
if(vars_ok(arg)) {
530 if (
po_buf_match( buf[0],
" LD (*+*), *", arg, ofs, tmp) ) {
if(vars_ok(arg)) {
533 } }
else if (
po_buf_match( buf[0],
" LD (*+*),*", arg, ofs, tmp) ) {
if(vars_ok(arg)) {
536 } }
else if (
po_buf_match( buf[0],
" LD (*), *", arg, tmp) ) {
if(vars_ok(arg)) {
539 } }
else if (
po_buf_match( buf[0],
" LD (*),*", arg, tmp) ) {
if(vars_ok(arg)) {
545 strstr(
"A B C D E AD BC DE HL IX IY",
strtoupper(arg->
str))!=NULL
554 strstr(
"A B C D E AD BC DE HL IX IY",
strtoupper(arg->
str))!=NULL
562 if(
po_buf_match( buf[0],
" *: defs *", tmp, arg) && vars_ok(tmp)) {
564 v->size = atoi(arg->
str);
565 v->init = strdup(
"1-1");
568 if(
po_buf_match(buf[0],
" *: defb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,
',')==NULL) {
571 v->init = strdup(isZero(arg->
str) ?
"1-1" : arg->
str);
574 if(
po_buf_match(buf[0],
" *: defw *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,
',')==NULL) {
577 v->init = strdup(arg->
str);
580 if(
po_buf_match(buf[0],
" * = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
589 }
else if(
po_buf_match(buf[0],
"* = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
603static int vars_cmp(
const void *_a,
const void *_b) {
604 const struct var *a = _a;
605 const struct var *b = _b;
607 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
609 return -(diff!=0 ? diff : strcmp(a->name, b->name));
621 if(
po_buf_match( buf[0],
" LD (*+*), *", var, ofs, op) && vars_ok(var)) {
623 if(v->nb_rd == 0 && v->offset!=-2) {
625 optim(buf[0],
"unread", NULL);
628 }
else if(
po_buf_match( buf[0],
" LD (*), *", var, op) && vars_ok(var)) {
630 if(v->nb_rd == 0 && v->offset!=-2) {
632 optim(buf[0],
"unread", NULL);
640 ||
po_buf_match( buf[0],
" *: DEFW ", var) )
if(vars_ok(var)) {
642 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags &
NO_REMOVE) && v->offset!=-2) {
643 optim(buf[0],
"unread",NULL);
651static void out(FILE *f,
POBuffer _buf) {
654 while(*s==
' ' || *s==
'\t') {
tab = 1; ++s;}
655 if(
tab) fputs(
"\t", f);
660static void fixes_indexed_syntax(
POBuffer buf) {
664 if(!_eq(
' ', *s))
return;
667 do ++s;
while(*s && _eq(
' ', *s));
673 while(*s && !_eq(
' ', *s)) ++s;
677 do ++s;
while(*s && _eq(
' ', *s));
681 do ++s;
while(*s && !_eq(
' ', *s));
690 FILE * fileOptimized;
702 adiline2(
"POP:0:%d:%d", peephole_pass, kind );
727 fileAsm = fopen( _environment->
asmFileName,
"rt" );
728 if(fileAsm == NULL) {
733 fileOptimized = fopen( fileNameOptimized,
"wt" );
734 if(fileOptimized == NULL) {
735 perror(fileNameOptimized);
745 while( still_to_go ) {
747 if ( line >=
LOOK_AHEAD ) out(fileOptimized, buf[0]);
764 sourceLine = atoi( ln->
str );
775 }
while(!feof(fileAsm));
779 basic_peephole(buf, zA, zB);
782 if(change == 0) vars_scan(buf);
786 vars_remove(_environment, buf);
804 fprintf(fileOptimized,
"; peephole: pass %d, %d change%s.\n", peephole_pass,
805 change, change>1 ?
"s":
"");
809 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s removed.\n", peephole_pass,
810 num_unread, num_unread>1 ?
"s":
"");
814 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
815 num_dp, num_dp>1 ?
"s":
"",
816 num_inlined, num_inlined>1 ?
"s":
"");
823 (void)fclose(fileAsm);
824 (void)fclose(fileOptimized);
837 struct _UnusedSymbol *
next;
1044static void optim_remove_unused_temporary(
Environment * _environment ) {
1057 FILE * fileOptimized;
1061 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1062 if(fileAsm == NULL) {
1067 fileOptimized = fopen( fileNameOptimized,
"wt" );
1068 if(fileOptimized == NULL) {
1069 perror(fileNameOptimized);
1077 while( !feof(fileAsm) ) {
1085 s->
next = currentlyUnusedSymbols;
1086 currentlyUnusedSymbols = s;
1097 fseek( fileAsm, vspPointer, SEEK_SET );
1099 while( !feof(fileAsm) ) {
1104 if ( ! result ) result =
po_buf_match(bufLine,
" ADD (*)", v1 );
1105 if ( ! result ) result =
po_buf_match(bufLine,
" AND (*)", v1 );
1106 if ( ! result ) result =
po_buf_match(bufLine,
" BIT (*)", v1 );
1107 if ( ! result ) result =
po_buf_match(bufLine,
" CP (*)", v1 );
1108 if ( ! result ) result =
po_buf_match(bufLine,
" CPL (*)", v1 );
1109 if ( ! result ) result =
po_buf_match(bufLine,
" LD *, (*)", v2, v1 );
1110 if ( ! result ) result =
po_buf_match(bufLine,
" OR (*)", v1 );
1111 if ( ! result ) result =
po_buf_match(bufLine,
" SBC (*)", v1 );
1112 if ( ! result ) result =
po_buf_match(bufLine,
" XOR (*)", v1 );
1114 if ( ! result ) result =
po_buf_match(bufLine,
" ADC *", v1 );
1115 if ( ! result ) result =
po_buf_match(bufLine,
" ADD *", v1 );
1116 if ( ! result ) result =
po_buf_match(bufLine,
" AND *", v1 );
1117 if ( ! result ) result =
po_buf_match(bufLine,
" BIT *", v1 );
1118 if ( ! result ) result =
po_buf_match(bufLine,
" CP *", v1 );
1119 if ( ! result ) result =
po_buf_match(bufLine,
" CPL *", v1 );
1120 if ( ! result ) result =
po_buf_match(bufLine,
" LD *, *", v2, v1 );
1121 if ( ! result ) result =
po_buf_match(bufLine,
" OR *", v1 );
1122 if ( ! result ) result =
po_buf_match(bufLine,
" SBC *", v1 );
1123 if ( ! result ) result =
po_buf_match(bufLine,
" XOR *", v1 );
1126 char * realVarName = strdup( v1->
str );
1127 char * c = strstr( realVarName,
"+" );
1134 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1138 currentlyUnusedSymbols = tmp->
next;
1161 fseek( fileAsm, vspPointer, SEEK_SET );
1165 while( !feof(fileAsm) ) {
1167 if ( line >= 1 ) out(fileOptimized, buf[0]);
1176 char * realVarName = strdup( v2->
str );
1177 char * c = strstr( realVarName,
"+" );
1183 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1189 optim( buf[0],
RULE "unused temporary", NULL );
1190 optim( buf[1],
RULE "unused temporary", NULL );
1194 }
else if( (
po_buf_match( buf[0],
" LD (*), A", v2 ) ) ||
1196 char * realVarName = strdup( v2->
str );
1197 char * c = strstr( realVarName,
"+" );
1203 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1209 optim( buf[0],
RULE "unused temporary", NULL );
1215 out(fileOptimized, buf[0]);
1221 vspPointer = ftell( fileAsm );
1225 currentlyUnusedSymbols = NULL;
1231 fseek( fileAsm, vspPointer, SEEK_SET );
1233 while( !feof(fileAsm) ) {
1237 out(fileOptimized, bufLine);
1241 (void)fclose(fileAsm);
1242 (void)fclose(fileOptimized);
1250static void optim_remove_comments(
Environment * _environment ) {
1258 FILE * fileOptimized;
1262 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1263 if(fileAsm == NULL) {
1268 fileOptimized = fopen( fileNameOptimized,
"wt" );
1269 if(fileOptimized == NULL) {
1270 perror(fileNameOptimized);
1274 while( !feof(fileAsm) ) {
1279 out( fileOptimized, bufLine );
1284 (void)fclose(fileAsm);
1285 (void)fclose(fileOptimized);
1296 optim_remove_unused_temporary( _environment );
1307 while(optim_pass(_environment, buf,
PEEPHOLE)&&optimization_limit_count) {
1308 --optimization_limit_count;
1310 optim_pass(_environment, buf,
DEADVARS);
1311 }
while(change&&optimization_limit_count);
1319 optim_remove_comments(_environment);
1336 int sourceLine = -1;
1343 fileAsm = fopen( _environment->
asmFileName,
"rb" );
1344 if(fileAsm == NULL) {
1350 if(fileListing == NULL) {
1355 while( !feof(fileAsm) && !feof(fileListing)) {
1363 sourceLine = atoi( ln->
str );
1374 *bufferListing->
str = 0;
1375 int pos = ftell( fileListing );
1377 while( !feof(fileListing) && (strstr( bufferListing->
str, bufferAsm->
str ) == NULL) ) {
1382 if ( feof(fileListing) ) {
1385 pos = ftell( fileListing );
1386 char * bufferAsmEscaped = strdup( bufferAsm->
str );
1387 for(
int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
1388 if ( bufferAsmEscaped[i] ==
':' ) {
1389 bufferAsmEscaped[i] = 6;
1391 if ( bufferAsmEscaped[i] == 9 ) {
1392 bufferAsmEscaped[i] =
' ';
1395 if (
po_buf_match( bufferListing,
"* * * ", bufferLine, bufferAddress, bufferBytes ) ) {
1402 fseek( fileListing, pos, SEEK_SET );
1411 (void)fclose(fileListing);
1412 (void)fclose(fileAsm);
char * strtoupper(char *_string)
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,...)
int po_buf_strcmp(POBuffer _s, POBuffer _t)
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)
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)