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)",
"\tJP %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);
491 if(
name->str[0]==
'_')
return 1;
517 if(
po_buf_match( buf[0],
" LD *, (*+*)", tmp, arg, ofs ) ) {
if(vars_ok(arg)) {
520 } }
else if(
po_buf_match( buf[0],
" LD *, (*+*)", tmp, arg, ofs ) ) {
if(vars_ok(arg)) {
523 } }
else if(
po_buf_match( buf[0],
" LD *, (*)", tmp, arg ) ) {
if(vars_ok(arg)) {
526 } }
else if(
po_buf_match( buf[0],
" LD *,(*)", tmp, arg ) ) {
if(vars_ok(arg)) {
531 if (
po_buf_match( buf[0],
" LD (*+*), *", arg, ofs, tmp) ) {
if(vars_ok(arg)) {
534 } }
else if (
po_buf_match( buf[0],
" LD (*+*),*", arg, ofs, tmp) ) {
if(vars_ok(arg)) {
537 } }
else if (
po_buf_match( buf[0],
" LD (*), *", arg, tmp) ) {
if(vars_ok(arg)) {
540 } }
else if (
po_buf_match( buf[0],
" LD (*),*", arg, tmp) ) {
if(vars_ok(arg)) {
546 strstr(
"A B C D E AD BC DE HL IX IY",
strtoupper(arg->
str))!=NULL
555 strstr(
"A B C D E AD BC DE HL IX IY",
strtoupper(arg->
str))!=NULL
563 if(
po_buf_match( buf[0],
" *: defs *", tmp, arg) && vars_ok(tmp)) {
565 v->size = atoi(arg->
str);
566 v->init = strdup(
"1-1");
569 if(
po_buf_match(buf[0],
" *: defb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,
',')==NULL) {
572 v->init = strdup(isZero(arg->
str) ?
"1-1" : arg->
str);
575 if(
po_buf_match(buf[0],
" *: defw *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,
',')==NULL) {
578 v->init = strdup(arg->
str);
581 if(
po_buf_match(buf[0],
" * = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
590 }
else if(
po_buf_match(buf[0],
"* = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
604static int vars_cmp(
const void *_a,
const void *_b) {
605 const struct var *a = _a;
606 const struct var *b = _b;
608 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
610 return -(diff!=0 ? diff : strcmp(a->name, b->name));
622 if(
po_buf_match( buf[0],
" LD (*+*), *", var, ofs, op) && vars_ok(var)) {
624 if(v->nb_rd == 0 && v->offset!=-2) {
626 optim(buf[0],
"unread", NULL);
629 }
else if(
po_buf_match( buf[0],
" LD (*), *", var, op) && vars_ok(var)) {
631 if(v->nb_rd == 0 && v->offset!=-2) {
633 optim(buf[0],
"unread", NULL);
641 ||
po_buf_match( buf[0],
" *: DEFW ", var) )
if(vars_ok(var)) {
643 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags &
NO_REMOVE) && v->offset!=-2) {
644 optim(buf[0],
"unread",NULL);
652static void out(FILE *f,
POBuffer _buf) {
655 while(*s==
' ' || *s==
'\t') {
tab = 1; ++s;}
656 if(
tab) fputs(
"\t", f);
661static void fixes_indexed_syntax(
POBuffer buf) {
665 if(!_eq(
' ', *s))
return;
668 do ++s;
while(*s && _eq(
' ', *s));
674 while(*s && !_eq(
' ', *s)) ++s;
678 do ++s;
while(*s && _eq(
' ', *s));
682 do ++s;
while(*s && !_eq(
' ', *s));
691 FILE * fileOptimized;
703 adiline2(
"POP:0:%d:%d", peephole_pass, kind );
728 fileAsm = fopen( _environment->
asmFileName,
"rt" );
729 if(fileAsm == NULL) {
734 fileOptimized = fopen( fileNameOptimized,
"wt" );
735 if(fileOptimized == NULL) {
736 perror(fileNameOptimized);
746 while( still_to_go ) {
748 if ( line >=
LOOK_AHEAD ) out(fileOptimized, buf[0]);
765 sourceLine = atoi( ln->
str );
776 }
while(!feof(fileAsm));
780 basic_peephole(buf, zA, zB);
783 if(change == 0) vars_scan(buf);
787 vars_remove(_environment, buf);
805 fprintf(fileOptimized,
"; peephole: pass %d, %d change%s.\n", peephole_pass,
806 change, change>1 ?
"s":
"");
810 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s removed.\n", peephole_pass,
811 num_unread, num_unread>1 ?
"s":
"");
815 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
816 num_dp, num_dp>1 ?
"s":
"",
817 num_inlined, num_inlined>1 ?
"s":
"");
824 (void)fclose(fileAsm);
825 (void)fclose(fileOptimized);
838 struct _UnusedSymbol *
next;
1045static void optim_remove_unused_temporary(
Environment * _environment ) {
1058 FILE * fileOptimized;
1062 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1063 if(fileAsm == NULL) {
1068 fileOptimized = fopen( fileNameOptimized,
"wt" );
1069 if(fileOptimized == NULL) {
1070 perror(fileNameOptimized);
1078 while( !feof(fileAsm) ) {
1086 s->
next = currentlyUnusedSymbols;
1087 currentlyUnusedSymbols = s;
1098 fseek( fileAsm, vspPointer, SEEK_SET );
1100 while( !feof(fileAsm) ) {
1105 if ( ! result ) result =
po_buf_match(bufLine,
" ADD (*)", v1 );
1106 if ( ! result ) result =
po_buf_match(bufLine,
" AND (*)", v1 );
1107 if ( ! result ) result =
po_buf_match(bufLine,
" BIT (*)", v1 );
1108 if ( ! result ) result =
po_buf_match(bufLine,
" CP (*)", v1 );
1109 if ( ! result ) result =
po_buf_match(bufLine,
" CPL (*)", v1 );
1110 if ( ! result ) result =
po_buf_match(bufLine,
" LD *, (*)", v2, v1 );
1111 if ( ! result ) result =
po_buf_match(bufLine,
" OR (*)", v1 );
1112 if ( ! result ) result =
po_buf_match(bufLine,
" SBC (*)", v1 );
1113 if ( ! result ) result =
po_buf_match(bufLine,
" XOR (*)", v1 );
1115 if ( ! result ) result =
po_buf_match(bufLine,
" ADC *", v1 );
1116 if ( ! result ) result =
po_buf_match(bufLine,
" ADD *", v1 );
1117 if ( ! result ) result =
po_buf_match(bufLine,
" AND *", v1 );
1118 if ( ! result ) result =
po_buf_match(bufLine,
" BIT *", v1 );
1119 if ( ! result ) result =
po_buf_match(bufLine,
" CP *", v1 );
1120 if ( ! result ) result =
po_buf_match(bufLine,
" CPL *", v1 );
1121 if ( ! result ) result =
po_buf_match(bufLine,
" LD *, *", v2, v1 );
1122 if ( ! result ) result =
po_buf_match(bufLine,
" OR *", v1 );
1123 if ( ! result ) result =
po_buf_match(bufLine,
" SBC *", v1 );
1124 if ( ! result ) result =
po_buf_match(bufLine,
" XOR *", v1 );
1127 char * realVarName = strdup( v1->
str );
1128 char * c = strstr( realVarName,
"+" );
1135 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1139 currentlyUnusedSymbols = tmp->
next;
1162 fseek( fileAsm, vspPointer, SEEK_SET );
1166 while( !feof(fileAsm) ) {
1168 if ( line >= 1 ) out(fileOptimized, buf[0]);
1177 char * realVarName = strdup( v2->
str );
1178 char * c = strstr( realVarName,
"+" );
1184 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1190 optim( buf[0],
RULE "unused temporary", NULL );
1191 optim( buf[1],
RULE "unused temporary", NULL );
1195 }
else if( (
po_buf_match( buf[0],
" LD (*), A", v2 ) ) ||
1197 char * realVarName = strdup( v2->
str );
1198 char * c = strstr( realVarName,
"+" );
1204 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1210 optim( buf[0],
RULE "unused temporary", NULL );
1216 out(fileOptimized, buf[0]);
1222 vspPointer = ftell( fileAsm );
1226 currentlyUnusedSymbols = NULL;
1232 fseek( fileAsm, vspPointer, SEEK_SET );
1234 while( !feof(fileAsm) ) {
1238 out(fileOptimized, bufLine);
1242 (void)fclose(fileAsm);
1243 (void)fclose(fileOptimized);
1251static void optim_remove_comments(
Environment * _environment ) {
1259 FILE * fileOptimized;
1263 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1264 if(fileAsm == NULL) {
1269 fileOptimized = fopen( fileNameOptimized,
"wt" );
1270 if(fileOptimized == NULL) {
1271 perror(fileNameOptimized);
1275 while( !feof(fileAsm) ) {
1280 out( fileOptimized, bufLine );
1285 (void)fclose(fileAsm);
1286 (void)fclose(fileOptimized);
1297 optim_remove_unused_temporary( _environment );
1308 while(optim_pass(_environment, buf,
PEEPHOLE)&&optimization_limit_count) {
1309 --optimization_limit_count;
1311 optim_pass(_environment, buf,
DEADVARS);
1312 }
while(change&&optimization_limit_count);
1320 optim_remove_comments(_environment);
1337 int sourceLine = -1;
1344 fileAsm = fopen( _environment->
asmFileName,
"rb" );
1345 if(fileAsm == NULL) {
1351 if(fileListing == NULL) {
1356 while( !feof(fileAsm) && !feof(fileListing)) {
1364 sourceLine = atoi( ln->
str );
1375 *bufferListing->
str = 0;
1376 int pos = ftell( fileListing );
1378 while( !feof(fileListing) && (strstr( bufferListing->
str, bufferAsm->
str ) == NULL) ) {
1383 if ( feof(fileListing) ) {
1386 pos = ftell( fileListing );
1387 char * bufferAsmEscaped = strdup( bufferAsm->
str );
1388 for(
int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
1389 if ( bufferAsmEscaped[i] ==
':' ) {
1390 bufferAsmEscaped[i] = 6;
1392 if ( bufferAsmEscaped[i] == 9 ) {
1393 bufferAsmEscaped[i] =
' ';
1396 if (
po_buf_match( bufferListing,
"* * * ", bufferLine, bufferAddress, bufferBytes ) ) {
1403 fseek( fileListing, pos, SEEK_SET );
1412 (void)fclose(fileListing);
1413 (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)