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 );
383 optim( buf[0],
RULE "(CALL+RET)->(JP)",
"\tJP %s", v1->
str );
384 optim( buf[1], NULL, NULL );
397 optim( buf[0],
RULE "(DEC B+JR NZ)->(DJNZ)",
"\tDJNZ %s", v1->
str );
398 optim( buf[1], NULL, NULL );
407 optim( buf[0],
RULE "(LD A, *; LD A, *)->(LD, A)", NULL );
435static void vars_clear(
void) {
437 for(i=0; i<vars.size; ++i) {
438 struct var *v = &vars.tab[i];
440 if(v->init)
free(v->init);
449 struct var *ret = NULL;
452 char *s=strchr(
name,
'+');
455 for(i=0; i<vars.size ; ++i) {
456 if(strcmp(vars.tab[i].name,
name)==0) {
461 if(vars.size == vars.capacity) {
463 vars.tab = realloc(vars.tab,
sizeof(*vars.tab)*vars.capacity);
465 ret = &vars.tab[vars.size++];
466 ret->name = strdup(
name);
485 if(
name->str[0]==
'_')
return 1;
511 if(
po_buf_match( buf[0],
" LD *, (*+*)", tmp, arg, ofs ) ) {
if(vars_ok(arg)) {
514 } }
else if(
po_buf_match( buf[0],
" LD *, (*)", tmp, arg ) ) {
if(vars_ok(arg)) {
520 strstr(
"A B C D E AD BC DE HL IX IY", tmp->
str)!=NULL
526 if (
po_buf_match( buf[0],
" LD (*+*), *", arg, ofs, tmp) ) {
if(vars_ok(arg)) {
529 } }
else if (
po_buf_match( buf[0],
" LD (*), *", arg, tmp) ) {
if(vars_ok(arg)) {
535 strstr(
"A B C D E AD BC DE HL IX IY", tmp->
str)!=NULL
541 if(
po_buf_match( buf[0],
" *: defs *", tmp, arg) && vars_ok(tmp)) {
543 v->size = atoi(arg->
str);
544 v->init = strdup(
"1-1");
547 if(
po_buf_match(buf[0],
" *: defb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,
',')==NULL) {
550 v->init = strdup(isZero(arg->
str) ?
"1-1" : arg->
str);
553 if(
po_buf_match(buf[0],
" *: defw *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,
',')==NULL) {
556 v->init = strdup(arg->
str);
562static int vars_cmp(
const void *_a,
const void *_b) {
563 const struct var *a = _a;
564 const struct var *b = _b;
566 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
568 return -(diff!=0 ? diff : strcmp(a->name, b->name));
580 if(
po_buf_match( buf[0],
" LD (*+*), *", var, ofs, op) && vars_ok(var)) {
582 if(v->nb_rd == 0 && v->offset!=-2) {
584 optim(buf[0],
"unread", NULL);
587 }
else if(
po_buf_match( buf[0],
" LD (*), *", var, op) && vars_ok(var)) {
589 if(v->nb_rd == 0 && v->offset!=-2) {
591 optim(buf[0],
"unread", NULL);
599 ||
po_buf_match( buf[0],
" *: DEFW ", var) )
if(vars_ok(var)) {
601 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags &
NO_REMOVE) && v->offset!=-2) {
602 optim(buf[0],
"unread",NULL);
610static void out(FILE *f,
POBuffer _buf) {
613 while(*s==
' ' || *s==
'\t') {
tab = 1; ++s;}
614 if(
tab) fputs(
"\t", f);
619static void fixes_indexed_syntax(
POBuffer buf) {
623 if(!_eq(
' ', *s))
return;
626 do ++s;
while(*s && _eq(
' ', *s));
632 while(*s && !_eq(
' ', *s)) ++s;
636 do ++s;
while(*s && _eq(
' ', *s));
640 do ++s;
while(*s && !_eq(
' ', *s));
649 FILE * fileOptimized;
661 adiline2(
"POP:0:%d:%d", peephole_pass, kind );
686 fileAsm = fopen( _environment->
asmFileName,
"rt" );
687 if(fileAsm == NULL) {
692 fileOptimized = fopen( fileNameOptimized,
"wt" );
693 if(fileOptimized == NULL) {
694 perror(fileNameOptimized);
704 while( still_to_go ) {
706 if ( line >=
LOOK_AHEAD ) out(fileOptimized, buf[0]);
723 sourceLine = atoi( ln->
str );
734 }
while(!feof(fileAsm));
738 basic_peephole(buf, zA, zB);
741 if(change == 0) vars_scan(buf);
745 vars_remove(_environment, buf);
763 fprintf(fileOptimized,
"; peephole: pass %d, %d change%s.\n", peephole_pass,
764 change, change>1 ?
"s":
"");
768 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s removed.\n", peephole_pass,
769 num_unread, num_unread>1 ?
"s":
"");
773 fprintf(fileOptimized,
"; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
774 num_dp, num_dp>1 ?
"s":
"",
775 num_inlined, num_inlined>1 ?
"s":
"");
782 (void)fclose(fileAsm);
783 (void)fclose(fileOptimized);
796 struct _UnusedSymbol *
next;
1003static void optim_remove_unused_temporary(
Environment * _environment ) {
1016 FILE * fileOptimized;
1020 fileAsm = fopen( _environment->
asmFileName,
"rt" );
1021 if(fileAsm == NULL) {
1026 fileOptimized = fopen( fileNameOptimized,
"wt" );
1027 if(fileOptimized == NULL) {
1028 perror(fileNameOptimized);
1036 while( !feof(fileAsm) ) {
1044 s->
next = currentlyUnusedSymbols;
1045 currentlyUnusedSymbols = s;
1056 fseek( fileAsm, vspPointer, SEEK_SET );
1058 while( !feof(fileAsm) ) {
1063 if ( ! result ) result =
po_buf_match(bufLine,
" ADD (*)", v1 );
1064 if ( ! result ) result =
po_buf_match(bufLine,
" AND (*)", v1 );
1065 if ( ! result ) result =
po_buf_match(bufLine,
" BIT (*)", v1 );
1066 if ( ! result ) result =
po_buf_match(bufLine,
" CP (*)", v1 );
1067 if ( ! result ) result =
po_buf_match(bufLine,
" CPL (*)", v1 );
1068 if ( ! result ) result =
po_buf_match(bufLine,
" LD *, (*)", v2, v1 );
1069 if ( ! result ) result =
po_buf_match(bufLine,
" OR (*)", v1 );
1070 if ( ! result ) result =
po_buf_match(bufLine,
" SBC (*)", v1 );
1071 if ( ! result ) result =
po_buf_match(bufLine,
" XOR (*)", v1 );
1073 if ( ! result ) result =
po_buf_match(bufLine,
" ADC *", v1 );
1074 if ( ! result ) result =
po_buf_match(bufLine,
" ADD *", v1 );
1075 if ( ! result ) result =
po_buf_match(bufLine,
" AND *", v1 );
1076 if ( ! result ) result =
po_buf_match(bufLine,
" BIT *", v1 );
1077 if ( ! result ) result =
po_buf_match(bufLine,
" CP *", v1 );
1078 if ( ! result ) result =
po_buf_match(bufLine,
" CPL *", v1 );
1079 if ( ! result ) result =
po_buf_match(bufLine,
" LD *, *", v2, v1 );
1080 if ( ! result ) result =
po_buf_match(bufLine,
" OR *", v1 );
1081 if ( ! result ) result =
po_buf_match(bufLine,
" SBC *", v1 );
1082 if ( ! result ) result =
po_buf_match(bufLine,
" XOR *", v1 );
1085 char * realVarName = strdup( v1->
str );
1086 char * c = strstr( realVarName,
"+" );
1093 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1097 currentlyUnusedSymbols = tmp->
next;
1120 fseek( fileAsm, vspPointer, SEEK_SET );
1124 while( !feof(fileAsm) ) {
1126 if ( line >= 1 ) out(fileOptimized, buf[0]);
1135 char * realVarName = strdup( v2->
str );
1136 char * c = strstr( realVarName,
"+" );
1142 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1148 optim( buf[0],
RULE "unused temporary", NULL );
1149 optim( buf[1],
RULE "unused temporary", NULL );
1153 }
else if( (
po_buf_match( buf[0],
" LD (*), A", v2 ) ) ||
1155 char * realVarName = strdup( v2->
str );
1156 char * c = strstr( realVarName,
"+" );
1162 if ( strcmp( realVarName, tmp->
realName ) == 0 ) {
1168 optim( buf[0],
RULE "unused temporary", NULL );
1174 out(fileOptimized, buf[0]);
1180 vspPointer = ftell( fileAsm );
1184 currentlyUnusedSymbols = NULL;
1190 fseek( fileAsm, vspPointer, SEEK_SET );
1192 while( !feof(fileAsm) ) {
1196 out(fileOptimized, bufLine);
1200 (void)fclose(fileAsm);
1201 (void)fclose(fileOptimized);
1212 optim_remove_unused_temporary( _environment );
1223 while(optim_pass(_environment, buf,
PEEPHOLE)&&optimization_limit_count) {
1224 --optimization_limit_count;
1226 optim_pass(_environment, buf,
DEADVARS);
1227 }
while(change&&optimization_limit_count);
1249 int sourceLine = -1;
1256 fileAsm = fopen( _environment->
asmFileName,
"rb" );
1257 if(fileAsm == NULL) {
1263 if(fileListing == NULL) {
1268 while( !feof(fileAsm) && !feof(fileListing)) {
1276 sourceLine = atoi( ln->
str );
1287 *bufferListing->
str = 0;
1288 int pos = ftell( fileListing );
1290 while( !feof(fileListing) && (strstr( bufferListing->
str, bufferAsm->
str ) == NULL) ) {
1295 if ( feof(fileListing) ) {
1298 pos = ftell( fileListing );
1299 char * bufferAsmEscaped = strdup( bufferAsm->
str );
1300 for(
int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
1301 if ( bufferAsmEscaped[i] ==
':' ) {
1302 bufferAsmEscaped[i] = 6;
1304 if ( bufferAsmEscaped[i] == 9 ) {
1305 bufferAsmEscaped[i] =
' ';
1308 if (
po_buf_match( bufferListing,
"* * * ", bufferLine, bufferAddress, bufferBytes ) ) {
1315 fseek( fileListing, pos, SEEK_SET );
1324 (void)fclose(fileListing);
1325 (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,...)
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)