ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
_optimizer.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31 /* 6809 optimizations for ugBasic by S.Devulder
32 *
33 * The idea here is to look for specific patterns over consecutive (1 to 4)
34 * lines of code generated by ugBasic compiler, and reorganize it locally
35 * by another pattern that contains a more efficent code achieving the same
36 * result.
37 *
38 * It does multiple passes over the source as local rewrites can be
39 * applied on previous rewrites, resulting in a avalanche effects that
40 * optimizes the source far away from one can guess from the basic patterns.
41 *
42 * The optimizer can also perform some data flow analysis. It can for
43 * instance see that one of the accumulator is $00 to simplify code. It can
44 * also detect that some data in memory are written but never read. These
45 * are called dead-data. It will then remove all reference to these data in
46 * the code making it smaller and faster (as a useless write is not
47 * performed anymore).
48 *
49 * Real full data-flow analysis should normally be able to detect data which
50 * is written two times in a row whithout being read in-between. These are
51 * also called dead-data since the first written value is also lost. These
52 * dead-data typically appear during the avalanche effect occuring during
53 * previous optimizations passes. Write operation to these dead-data can
54 * also be removed harmlessly.
55 *
56 * Unfortunately this version of the optimized doesn't have yet a complete
57 * data-flow analyzer. Instead, heuristics is used to guess whether a memory
58 * operation accesses a dead data. In that case the optimizer will indicate
59 * in the commented-out code that the data is *presumed dead*. The
60 * heuristics are carefully choosen from the patterns generated by ugBasic
61 * and make good guesses. But if you consider these as too dangerous you
62 * can disable all of them with the "ALLOW_UNSAFE" flag below.
63 *
64 * Last the optimizer will also attempt to reorganize the data to get a
65 * faster & shorter code. Some data will be "inlined" in the code, making
66 * the code auto-modifiable which is no problem for the mc6809. And some
67 * "heavily used" data will be moved into the direct-page location for
68 * faster accesses.
69 */
70
71/****************************************************************************
72 * INCLUDE SECTION
73 ****************************************************************************/
74
75#include "../../ugbc.h"
76#include <stdarg.h>
77#include <ctype.h>
78#include <string.h>
79
80/****************************************************************************
81 * CODE SECTION
82 ****************************************************************************/
83
84#define DIRECT_PAGE 0x2100
85#define LOOK_AHEAD 10
86#define ALLOW_UNSAFE 0
87#define KEEP_COMMENTS 1
88
89#define DO_DIRECT_PAGE 1
90#define DO_INLINE 1
91#define DO_UNREAD 1
92
93/* returns an UPPER-cased char */
94static inline char _toUpper(char a) {
95 return (a>='a' && a<='z') ? a-'a'+'A' : a;
96}
97
98/* returns true if char is end of line ? */
99static inline int _eol(char c) {
100 return c=='\0' || c=='\n';
101}
102
103/* returns true if both char matches */
104static inline int _eq(char pat, char txt) {
105 return (pat<=' ') ? (txt<=' ') : (_toUpper(pat)==_toUpper(txt));
106}
107
108/* returns true if the POBuffer matches a comment or and empty line */
110 char * _buffer = buf->str;
111
112 if ( ! *_buffer ) {
113 return 1;
114 }
115 if ( *_buffer == '\r' || *_buffer == '\n' ) {
116 return 1;
117 }
118 while( * _buffer ) {
119 if ( *_buffer == ' ' || *_buffer == '\t' ) {
120 ++_buffer;
121 } else if ( *_buffer == ';' ) {
122 return 1;
123 } else {
124 return 0;
125 }
126 }
127 return 0;
128}
129
130/* returns true if buf matches any op using the ALU between memory and a register */
131static int chg_reg(POBuffer buf, POBuffer REG) {
132 if(po_buf_match(buf, " ADD* ", REG)) return 1;
133 if(po_buf_match(buf, " AND* ", REG)) return 1;
134 if(po_buf_match(buf, " CMP* ", REG)) return 1;
135 if(po_buf_match(buf, " EOR* ", REG)) return 1;
136 if(po_buf_match(buf, " LD* ", REG)) return 1;
137 if(po_buf_match(buf, " OR* ", REG)) return 1;
138 if(po_buf_match(buf, " SBC* ", REG)) return 1;
139 if(po_buf_match(buf, " SUB* ", REG)) return 1;
140
141 return 0;
142}
143
144/* returns true if buf matches an op that sets the CCR */
145static int sets_flag(POBuffer buf, char REG) {
146 POBuffer tmp = TMP_BUF;
147
148 if(chg_reg(buf, tmp) && _toUpper(*tmp->str)==REG) return 1;
149 if(po_buf_match(buf, " ASL*", tmp) && _toUpper(*tmp->str)==REG) return 1;
150 if(po_buf_match(buf, " ASR*", tmp) && _toUpper(*tmp->str)==REG) return 1;
151 if(po_buf_match(buf, " COM*", tmp) && _toUpper(*tmp->str)==REG) return 1;
152 if(po_buf_match(buf, " DEC*", tmp) && _toUpper(*tmp->str)==REG) return 1;
153 if(po_buf_match(buf, " INC*", tmp) && _toUpper(*tmp->str)==REG) return 1;
154 if(po_buf_match(buf, " LSL*", tmp) && _toUpper(*tmp->str)==REG) return 1;
155 if(po_buf_match(buf, " LSR*", tmp) && _toUpper(*tmp->str)==REG) return 1;
156 if(po_buf_match(buf, " ROL*", tmp) && _toUpper(*tmp->str)==REG) return 1;
157 if(po_buf_match(buf, " ROR*", tmp) && _toUpper(*tmp->str)==REG) return 1;
158 if(po_buf_match(buf, " TST*", tmp) && _toUpper(*tmp->str)==REG) return 1;
159 if(po_buf_match(buf, " ST* ", tmp) && _toUpper(*tmp->str)==REG) return 1;
160
161 return 0;
162}
163
164/* returns true if this is a conditionnal branch */
165static int isConditionnal(POBuffer buf) {
166 /* short jumps */
167 if(po_buf_match(buf, " BGT ")) return 1;
168 if(po_buf_match(buf, " BLE ")) return 1;
169 if(po_buf_match(buf, " BGE ")) return 1;
170 if(po_buf_match(buf, " BLT ")) return 1;
171 if(po_buf_match(buf, " BEQ ")) return 1;
172 if(po_buf_match(buf, " BNE ")) return 1;
173 if(po_buf_match(buf, " BHI ")) return 1;
174 if(po_buf_match(buf, " BLS ")) return 1;
175 if(po_buf_match(buf, " BHS ")) return 1;
176 if(po_buf_match(buf, " BLO ")) return 1;
177 if(po_buf_match(buf, " BMI ")) return 1;
178 if(po_buf_match(buf, " BPL ")) return 1;
179
180 /* long jumps */
181 if(po_buf_match(buf, " LBGT ")) return 1;
182 if(po_buf_match(buf, " LBLE ")) return 1;
183 if(po_buf_match(buf, " LBGE ")) return 1;
184 if(po_buf_match(buf, " LBLT ")) return 1;
185 if(po_buf_match(buf, " LBEQ ")) return 1;
186 if(po_buf_match(buf, " LBNE ")) return 1;
187 if(po_buf_match(buf, " LBHI ")) return 1;
188 if(po_buf_match(buf, " LBLS ")) return 1;
189 if(po_buf_match(buf, " LBHS ")) return 1;
190 if(po_buf_match(buf, " LBLO ")) return 1;
191 if(po_buf_match(buf, " LBMI ")) return 1;
192 if(po_buf_match(buf, " LBPL ")) return 1;
193
194 return 0;
195}
196
197/* returns true if buf matches a jump */
198static int isBranch(POBuffer buf) {
199 if(po_buf_match(buf, " BRA ")) return 1;
200 if(po_buf_match(buf, " BSR ")) return 1;
201 if(po_buf_match(buf, " JMP ")) return 1;
202 if(po_buf_match(buf, " JSR ")) return 1;
203 return isConditionnal(buf);
204 }
205
206/* number of lines changed */
207static int change = 0;
208static int peephole_pass = 0;
209static int num_dp = 0; /* number of variables relocated to direct-page */
210static int num_inlined = 0; /* number of variables inlined */
211static int num_unread = 0; /* number of variables not read */
212
213#ifdef __GNUC__
214static void optim(POBuffer buf, const char *rule, const char *repl, ...)
215 __attribute__ ((format (printf, 3, 4)));
216#endif
217
218#define R__(X) #X
219#define R_(X) R__(X)
220#define RULE "r" R_(__LINE__) " "
221
222/* replaces the POBuffer with an optimized code */
223/* original POBuffer is kept as comment */
224static void optim(POBuffer buf, const char *rule, const char *repl, ...) {
225 va_list ap;
226 POBuffer tmp = TMP_BUF;
227 char *s;
228
229 va_start(ap, repl);
230 po_buf_cpy(tmp, "");
231
232 /* add our own comment if any */
233 if(rule) po_buf_printf(tmp, "; peephole(%d): %s\n", peephole_pass, rule);
234
235 /* comment out line */
236 po_buf_cat(tmp, ";");
237
238 /* copy upto the end of string or upto end of string */
239 if ( (s = strchr(buf->str, '\n')) != NULL) *s = '\0'; /* cut at \n */
240 po_buf_cat(tmp, buf->str);
241 if( s != NULL ) po_buf_add(tmp, *s++ = '\n'); /* restore \n */
242
243 /* insert replacement if provided */
244 if(repl) {
245 po_buf_vprintf(tmp, repl, ap);
246 po_buf_cat(tmp, "\n");
247 }
248
249 /* copy remaining comments */
250 if(s) po_buf_cat(tmp, s);
251
252 /* write result back into input POBuffer */
253 po_buf_cpy(buf, tmp->str);
254
255 /* one more change */
256 ++change;
257
258 va_end(ap);
259}
260
261/* returns true if the POBuffer matches a zero value */
262static int isZero(char *s) {
263 if(*s == '$') ++s;
264 while(*s == '0') ++s;
265 return _eq(' ', *s);
266}
267static int _isZero(POBuffer buf) {
268 return buf!=NULL && isZero(buf->str);
269}
270
271static int vars_ok(POBuffer name) {
272 if(po_buf_match(name, "^_Tstr")) return 0;
273 if(po_buf_match(name, "_^_Tstr")) return 0;
274 if(po_buf_match(name, "^_TRtmp")) return 0;
275 if(po_buf_match(name, "_label")) return 0;
276 if(po_buf_match(name, "_SHELL")) return 0;
277 if(po_buf_match(name, "DUFFDEVICE")) return 0;
278 if(po_buf_match(name, "_TAB")) return 0;
279 if(po_buf_match(name, "ISV")) return 0;
280 if(po_buf_match(name, "BINTO^")) return 0;
281
282 if(name->str[0]=='_') return 1;
283 if(po_buf_match(name, "CLIP")) return 1;
284 if(po_buf_match(name, "XCUR")) return 1;
285 if(po_buf_match(name, "YCUR")) return 1;
286 if(po_buf_match(name, "CURRENT")) return 1;
287 if(po_buf_match(name, "FONT")) return 1;
288 if(po_buf_match(name, "TEXT")) return 1;
289 if(po_buf_match(name, "LAST")) return 1;
290 if(po_buf_match(name, "XGR")) return 1;
291 if(po_buf_match(name, "YGR")) return 1;
292 if(po_buf_match(name, "FREE_")) return 1;
293 if(po_buf_match(name, "CONSOLE")) return 1;
294 if(po_buf_match(name, "ORIGIN")) return 1;
295 if(po_buf_match(name, "RESOLUTION")) return 1;
296 if(po_buf_match(name, "TILEMAPVISIBLE")) return 1;
297 if(po_buf_match(name, "DOUBLEBUFFERENABLED")) return 1;
298 if(po_buf_match(name, "LINE")) return 1;
299 if(po_buf_match(name, "XSCROLL")) return 1;
300 if(po_buf_match(name, "YSCROLL")) return 1;
301 if(po_buf_match(name, "BLIT")) return 1;
302 if(po_buf_match(name, "CURRENTMODE")) return 1;
303 if(po_buf_match(name, "BITMAPADDRESS")) return 1;
304 if(po_buf_match(name, "COLORMAPADDRESS")) return 1;
305 if(po_buf_match(name, "DATAPTR")) return 1;
306 if(po_buf_match(name, "DOJOERROR")) return 1;
307 if(po_buf_match(name, "XCURSYS")) return 1;
308 if(po_buf_match(name, "YCURSYS")) return 1;
309 if(po_buf_match(name, "<XCURSYS")) return 1;
310 if(po_buf_match(name, "<YCURSYS")) return 1;
311
312 return 0;
313}
314
315/* perform basic peephole optimization with a length-4 look-ahead */
316static void basic_peephole(Environment * _environment, POBuffer buf[LOOK_AHEAD], int zA, int zB) {
317 /* allows presumably safe operations */
318 int unsafe = ALLOW_UNSAFE;
319
320 /* various local buffers */
321 POBuffer v1 = TMP_BUF;
322 POBuffer v2 = TMP_BUF;
323 POBuffer v3 = TMP_BUF;
324 POBuffer v4 = TMP_BUF;
325 POBuffer v5 = TMP_BUF;
326
327 if ( po_buf_match( buf[0], " CLRA" )
328 && po_buf_match( buf[1], " ANDA") ) {
329 optim( buf[1], RULE "(CLEAR*,?,AND*)->(CLEAR*)", NULL);
330 ++_environment->removedAssemblyLines;
331 }
332
333 /* move B stuff after A stuff */
334 if( (po_buf_match(buf[0], " LDB *", v1) || po_buf_match(buf[0], " STB *", v1)) && !strchr("AD$", v1->str[0]) && strstr(v1->str, "BASE_SEGMENT" ) == NULL
335 && sets_flag(buf[1], 'A')
336 && (!po_buf_match(buf[1], " * *", NULL, v2) || po_buf_strcmp(v1, v2)) ) {
337 int x = 1, i;
338 if( po_buf_match(buf[x+1], "* equ ", NULL)) ++x;
339 if(!po_buf_match(buf[x+1], " IF ") && !isConditionnal(buf[x+1])) {
340 po_buf_cpy(v1, buf[0]->str);
341 for(i=0; i<x; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
342 po_buf_cpy(buf[x], v1->str);
343 }
344 }
345 /* move D stuff before X stuff */
346 if( (po_buf_match(buf[0], " LDX _*", v1) || po_buf_match(buf[0], " LDX #*", v1) || po_buf_match(buf[0], " STX _*", v1))
347 && po_buf_match(buf[1], " *DD _*", NULL,v2)
348 && strchr(v1->str,'+')==NULL
349 && strchr(v2->str,'+')==NULL
350 && po_buf_strcmp(v1, v2) ) {
351 int x = 1, i;
352 if( po_buf_match(buf[x+1], "* equ ", NULL)) ++x;
353 if(!po_buf_match(buf[x+1], " IF ") && !isConditionnal(buf[x+1])) {
354 po_buf_cpy(v1, buf[0]->str);
355 for(i=0; i<x; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
356 po_buf_cpy(buf[x], v1->str);
357 } else {
358 printf("XXX %s", buf[x+1]->str);
359 }
360 }
361
362 if( po_buf_match( buf[0], " LDB #*", v1)
363 && po_buf_match( buf[1], " LDB #*", v2)) {
364 optim( buf[0], RULE "(LDB, LDB)->(LDB)", NULL);
365 ++_environment->removedAssemblyLines;
366 }
367
368 if( po_buf_match( buf[0], " CLRA")
369 && po_buf_match( buf[1], " CLRB")
370 && po_buf_match( buf[2], " LDA *", v1)
371 ) {
372 optim( buf[0], RULE "(CLRA,CLRB,LDA)->(CLRB,LDA)", NULL);
373 --_environment->removedAssemblyLines;
374 }
375
376 if( po_buf_match( buf[0], " LDB ")
377 && po_buf_match( buf[1], " LDX ")
378 && po_buf_match( buf[2], " LDB ")
379 ) {
380 optim( buf[0], RULE "(LDB,LDX,LDB)->(LDX,LDB)", NULL);
381 --_environment->removedAssemblyLines;
382 }
383
384 /* a bunch of rules */
385 if( po_buf_match( buf[0], " STA *", v1)
386 && po_buf_match( buf[1], " CLRB")
387 && po_buf_match( buf[2], " LDA *", v2)
388 && po_buf_cmp( v1, v2 ) == 0 ) {
389 optim( buf[0], RULE "(STAx,CLRB,LDAx)->(CLRB)", NULL);
390 optim( buf[1], NULL, NULL);
391 optim( buf[2], NULL, "\tCLRB");
392 ++_environment->removedAssemblyLines;
393 ++_environment->removedAssemblyLines;
394 }
395
396 // if( po_buf_match( buf[0], " STB *", v1)
397 // && po_buf_match( buf[1], " CLRA")
398 // && po_buf_match( buf[2], " LDB *", v2)
399 // && po_buf_cmp( v1, v2 ) == 0 ) {
400 // optim( buf[0], RULE "(STBx,CLRA,LDBx)->(CLRA)", NULL);
401 // optim( buf[1], NULL, NULL);
402 // optim( buf[2], NULL, "\tCLRA");
403 // }
404
405 if( po_buf_match( buf[0], " LDA #*", v1)
406 && po_buf_match( buf[1], " LDB #*", v2)
407 && strchr( v1->str, '(' ) == NULL && strchr( v2->str, '(' ) == NULL ) {
408 optim( buf[0], RULE "(LDA,LDB)->(LDD)", NULL);
409 optim( buf[1], NULL, "\tLDD #((%s)&255)*256+((%s)&255)", v1->str, v2->str);
410 }
411 if ( po_buf_match( buf[0], " ST* *", v1, v2 )
412 && po_buf_match( buf[1], " LD* *", v3, v4 )
413 && !po_buf_match( buf[2], " PSHS *", v3 )
414 && po_buf_strcmp(v1, v3)==0
415 && po_buf_strcmp(v2, v4)==0) {
416 if(0 && unsafe && po_buf_match(v2, "_Ttmp") && !po_buf_match(buf[2], "*SR ") && !(*v1->str=='D' && po_buf_match(buf[2], " IF "))) {
417 char *fmt = NULL;
418 /* in case flags are necessary (IF,LBcc), insert TST or LEAX */
419 if(po_buf_match(buf[2], " IF ") && po_buf_match(buf[3], " LB"))
420 fmt = *v1->str=='X' ? "\tLEAX ,X" : "\tTST%c";
421 optim( buf[0], "(unsafe, presumed dead)", fmt, _toUpper(*v1->str));
422 }
423
424 if(unsafe && po_buf_match(buf[2], " * [", NULL)) {
425 optim( buf[0], "(unsafe, presumed dead)", NULL);
426 ++_environment->removedAssemblyLines;
427 }
428
429 if ( !po_buf_match(v2, "_Ttmp") && strcmp( v2->str, "BASE_SEGMENT+$C1") && strcmp( v2->str, "$FFDE") && strcmp( v2->str, "$FFDF")
430 &&
431 strcmp( v4->str, "BASE_SEGMENT+$C1") && strcmp( v4->str, "$FFDE") && strcmp( v4->str, "$FFDF") ) {
432 optim( buf[1], RULE "(STORE*,LOAD*)->(STORE*)", NULL);
433 ++_environment->removedAssemblyLines;
434 }
435 }
436
437 if ( po_buf_match( buf[0], " LDD *", v1 )
438 && po_buf_match( buf[1], " LDD *", v2 )
439 ) {
440 optim( buf[0], RULE "(LDD, LDD)->(LDD)", NULL);
441 ++_environment->removedAssemblyLines;
442 }
443
444 if ( po_buf_match( buf[0], " ST* *", v1, v2 )
445 && po_buf_match( buf[1], " CLR*", v3 )
446 && po_buf_match( buf[2], " LD* *", v4, v5 )
447 && po_buf_strcmp(v1, v4)==0
448 && po_buf_strcmp(v2, v5)==0
449 && po_buf_strcmp(v1, v3)!=0
450 ) {
451 optim( buf[2], RULE "(ST*, CLR, LD*)->(STD*, CLR)", NULL);
452 ++_environment->removedAssemblyLines;
453 }
454
455 if ( po_buf_match( buf[0], " CLR *", v1 )
456 && po_buf_match( buf[2], " ST* *", v2, v3 )
457 && strchr("AB", _toUpper(*v2->str))
458 && po_buf_strcmp(v1, v3)==0) {
459 optim( buf[0], RULE "(CLEAR*,?,STORE*)->(?,STORE*)", NULL);
460 ++_environment->removedAssemblyLines;
461 }
462
463 if ( _isZero(po_buf_match(buf[0], " LD* #*", v1, v2) )
464 && strchr("AB", _toUpper(*v1->str))
465 && ( !po_buf_match(buf[1], " ROL*", v3) || (*v1->str != *v3->str) )
466 ) {
467 optim(buf[0], RULE "(LOAD#0)->(CLEAR)", "\tCLR%c", _toUpper(*v1->str));
468 }
469
470 if ( po_buf_match(buf[0], " EOR* #$ff", v1)
471 && strchr("AB", _toUpper(*v1->str)) ) {
472 optim(buf[0], RULE "(EOR#$FF)->(COM)", "\tCOM%c", _toUpper(*v1->str));
473 }
474
475 if ( (po_buf_match(buf[0], " LD* ", v1) || po_buf_match(buf[0], " CLR*", v1))
476 && po_buf_match(buf[1], " LD* *,*", v2, v3, v4)
477 && po_buf_strcmp(v1,v2)==0 && po_buf_strcmp(v2,v3)!=0 && po_buf_strcmp(v1,v4)!=0
478 && ( strcmp(v1->str,"A")!=0 && strcmp(v1->str,"B")!=0 && strcmp(v3->str,"D")!=0 ) ) {
479 optim(buf[0], RULE "(LOAD/CLR,LOAD)->(LOAD)", NULL);
480 ++_environment->removedAssemblyLines;
481 }
482
483 if ( po_buf_match( buf[0], " LD")
484 && po_buf_match( buf[1], " ST")
485 && po_buf_strcmp( buf[2], buf[0] )==0
486 && !strchr( buf[0]->str, '+' )
487 && unsafe) {
488 optim( buf[2], RULE "(LOAD*,STORE,LOAD*)->(LOAD*,STORE)", NULL);
489 ++_environment->removedAssemblyLines;
490 }
491 if ( po_buf_match( buf[0], " LD")
492 && po_buf_match( buf[1], " ST")
493 && po_buf_match( buf[2], " ST")
494 && po_buf_strcmp( buf[3], buf[0] )==0
495 && unsafe) {
496 optim( buf[3], RULE "(LOAD*,STORE,STORE,LOAD*)->(LOAD*,STORE,STORE)", NULL);
497 ++_environment->removedAssemblyLines;
498 }
499 if ( po_buf_match( buf[0], " LD")
500 && po_buf_match( buf[1], " ST")
501 && po_buf_match( buf[2], " ST")
502 && po_buf_match( buf[3], " ST")
503 && po_buf_strcmp( buf[4], buf[0] )==0
504 && unsafe) {
505 optim( buf[4], RULE "(LOAD*,STORE,STORE,STORE,LOAD*)->(LOAD*,STORE,STORE,STORE)", NULL);
506 ++_environment->removedAssemblyLines;
507 }
508
509 if ( po_buf_match(buf[0], " ST* *", NULL, v1)
510 && po_buf_match(buf[1], " LD* *", NULL, v2)
511 && !po_buf_match(buf[0], " ST* *,*", NULL, v3, v4)
512 && ( !strchr(v1->str,'+') && !strchr(v2->str,'+') )
513 && po_buf_strcmp(v1, v2)!=0
514 && po_buf_strcmp(buf[0],buf[2])==0 ) {
515 optim(buf[0], RULE "(STORE*,LOAD,STORE*)->(LOAD,STORE*)", NULL);
516 ++_environment->removedAssemblyLines;
517 }
518
519 // if ( (po_buf_match( buf[0], " LD* *", v1, v3) || po_buf_match( buf[0], " CLR* *", v1, v3))
520 // && (po_buf_match( buf[1], " LD* *", v2, v4) || po_buf_match( buf[1], " CLR* *", v2, v4))
521 // && po_buf_strcmp( v1, v2)==0 && !strstr( v3->str, "+" ) && !strstr( v4->str, "+" ) && !strstr( v3->str, "-" ) && !strstr( v4->str, "-" ) ) {
522 // optim(buf[0], RULE "(LOAD/CLR,LOAD/CLR)->(LOAD/CLR)", NULL);
523 // ++_environment->removedAssemblyLines;
524 // }
525
526
527 if ( po_buf_match(buf[0], " ST")
528 && po_buf_strcmp(buf[0], buf[1])==0
529 && ( (strstr( buf[0]->str, "++" ) == NULL) && (strstr( buf[0]->str, "--" ) == NULL) )
530 ) {
531 optim(buf[0], RULE "(STORE*,STORE*)->(STORE*)", NULL);
532 ++_environment->removedAssemblyLines;
533 }
534 if ( (po_buf_match(buf[0], " ST* *+", NULL, v1) || po_buf_match(buf[0], " ST* *", NULL, v1))
535 && !isBranch(buf[1]) && po_buf_match(buf[1], " * *", NULL, v2) && po_buf_strcmp(v1, v2)!=0
536 && strchr(buf[0]->str,'+')==NULL
537 && strchr(buf[1]->str,'+')==NULL
538 && !po_buf_match(buf[0], " ST* *,*", NULL, v3, v4)
539 && po_buf_strcmp(buf[2], buf[0])==0) {
540 optim(buf[0], RULE "(STORE*,?,STORE*)->(?,STORE*)", NULL);
541 ++_environment->removedAssemblyLines;
542 }
543
544 if ((po_buf_match(buf[0], " ST* *+", NULL, v1) || po_buf_match(buf[0], " ST* *", NULL, v1))
545 && !isBranch(buf[1]) && po_buf_match(buf[1], " * *", NULL, v2) && po_buf_strcmp(v1, v2)!=0
546 && !isBranch(buf[2]) && po_buf_match(buf[2], " * *", NULL, v2) && po_buf_strcmp(v1, v2)!=0
547 && po_buf_strcmp(buf[3], buf[0])==0 && strcmp(v2->str, "BASE_SEGMENT+$E5")==0 ) {
548 optim(buf[0], RULE "(STORE*,?,?,STORE*)->(?,?,STORE*)", NULL);
549 ++_environment->removedAssemblyLines;
550 }
551
552 if( (po_buf_match(buf[0], " LD* ", v1) || po_buf_match(buf[0], " ST* ",v1))
553 && _isZero(po_buf_match(buf[1], " CMP* #*", v2, v3))
554 && ( (strcmp( v1->str, "D" ) == 0) && (strcmp( v1->str, "X" ) == 0) && (strcmp( v1->str, "Y" ) == 0) )
555 && po_buf_strcmp(v1, v2)==0
556 ) {
557 optim(buf[1], RULE "(LOAD/STORE(8 bit),CMP#0)->(LOAD/STORE)", NULL);
558 ++_environment->removedAssemblyLines;
559 }
560
561 if( (po_buf_match(buf[0], " LD* ", v1) || po_buf_match(buf[0], " ST* ",v1))
562 && _isZero(po_buf_match(buf[1], " CMP* #*", v2, v3))
563 && ( !strcmp( v1->str, "D" ) || !strcmp( v1->str, "X" ) || !strcmp( v1->str, "Y" ) )
564 && (po_buf_match(buf[2], " BLS *", v4) == NULL)
565 && (po_buf_match(buf[2], " BLO *", v4) == NULL)
566 && (po_buf_match(buf[2], " BLE *", v4) == NULL)
567 && (po_buf_match(buf[2], " BLT *", v4) == NULL)
568 && (po_buf_match(buf[2], " BGT *", v4) == NULL)
569 && (po_buf_match(buf[2], " BGE *", v4) == NULL)
570 && (po_buf_match(buf[2], " BHI *", v4) == NULL)
571 && (po_buf_match(buf[2], " BHS *", v4) == NULL)
572 && po_buf_strcmp(v1, v2)==0
573 ) {
574 optim(buf[1], RULE "(LOAD/STORE(16 bit),CMP#0,!check carry)->(LOAD/STORE)", NULL);
575 ++_environment->removedAssemblyLines;
576 }
577
578 if ( po_buf_match(buf[0], " LDD *", v1)
579 && po_buf_match(buf[1], " STD _Ttmp*", v2)
580 && po_buf_match(buf[2], " CLRB")
581 && po_buf_match(buf[3], " LDX *", v3)
582 && po_buf_match(buf[4], " CMPX _Ttmp*", v4)
583 && po_buf_strcmp(v2, v4)==0
584 && strstr( v1->str, "X" ) == NULL) {
585 if(unsafe) {
586 optim(buf[0], RULE "(LDD+,STD*,LDX,CMPX*)->(LDX,CMP+)", NULL);
587 ++_environment->removedAssemblyLines;
588 optim(buf[1], "(unsafe, presumed dead)", NULL);
589 ++_environment->removedAssemblyLines;
590 optim(buf[4], NULL, "\tCMPX %s", v1->str);
591 } else {
592 optim(buf[4], RULE "(LDD+,STD*,LDX,CMPX*)->(LDD+,STD*,LDX,CMPX+)", "\tCMPX %s", v1->str);
593 }
594 }
595
596 if ( po_buf_match(buf[0], " LDD *", v1)
597 && po_buf_match(buf[1], " STD _Ttmp*", v2)
598 && po_buf_match(buf[2], " LDD *", v3)
599 && po_buf_match(buf[3], " ADD _Ttmp*", v4)
600 && po_buf_strcmp(v2, v4)==0) {
601 if(unsafe) {
602 optim(buf[0], RULE "(LDD+,STD*,LDD,ADDD*)->(LDD,ADD+)", NULL);
603 ++_environment->removedAssemblyLines;
604 optim(buf[1], "(unsafe, presumed dead)", NULL);
605 ++_environment->removedAssemblyLines;
606 optim(buf[3], NULL, "\tADDD %s", v1->str);
607 } else {
608 optim(buf[3], RULE "(LDD+,STD*,LDD,ADDD*)->(LDD+,STD*,LDD,ADD+)", "\tADDD %s", v1->str);
609 }
610 }
611
612 if ( po_buf_match(buf[0], " STD *", v1)
613 && po_buf_match(buf[1], " LDX *", v2)
614 && po_buf_strcmp(v1,v2)==0) {
615 //if(unsafe) optim(buf[0], "(unsafe, presumed dead)", NULL);
616 optim(buf[1], RULE "(STD*,LDX*)->(STD*,TDX)", "\tTFR D,X");
617 }
618
619 if ( po_buf_match(buf[0], " STD *", v1)
620 && po_buf_match(buf[1], " LDB *+1", v2)
621 && po_buf_strcmp(v1, v2)==0) {
622 if(unsafe) {
623 optim(buf[0], "(unsafe, presumed dead)", NULL);
624 ++_environment->removedAssemblyLines;
625 }
626 optim(buf[1], RULE "(STD,LDB+1)->()", NULL);
627 ++_environment->removedAssemblyLines;
628 }
629
630 if ( po_buf_match(buf[0], " LDD #*", v1)
631 && po_buf_match(buf[1], " ADDD #*", v2)
632 && !po_buf_match(buf[2], "* equ ", NULL)
633 && !vars_ok(v2) && !vars_ok(v1) ) {
634 optim(buf[0], RULE "(LDD#,ADD#)->(LDD#)", "\tLDD #(%s+%s)", v1->str, v2->str);
635 optim(buf[1], NULL, NULL);
636 ++_environment->removedAssemblyLines;
637 }
638
639 if ( po_buf_match(buf[0], " STX *", v1)
640 && po_buf_match(buf[1], " CLRA")
641 && po_buf_match(buf[2], " LDX *", v2)
642 && po_buf_strcmp(v1,v2)==0) {
643 optim(buf[0], RULE "(STX*,CLRA,LDX*)->(CLRA,STX*)", NULL);
644 optim(buf[2], NULL, "\tSTX %s", v1->str);
645 }
646
647 // if ( po_buf_match(buf[0], " STD *", v1)
648 // && po_buf_match(buf[1], " LDD *", v2)
649 // && po_buf_match(buf[2], " ADDD *", v3)
650 // && po_buf_strcmp(v1,v3)==0) {
651 // // if(unsafe) optim(buf[0], "(unsafe, presumed dead)", NULL);
652 // optim(buf[1], RULE "(STD*,LDD+,ADD*)->(STD*,ADD+)", NULL);
653 // optim(buf[2], NULL, "\tADDD %s", v2->str);
654 // }
655
656 if ( po_buf_match(buf[0], " STB *", v1)
657 && po_buf_match(buf[1], " LDB *", v2)
658 && po_buf_match(buf[2], " *B *", v3, v4)
659 && po_buf_strcmp(v1,v4)==0
660 && (po_buf_match(v3, "OR") || po_buf_match(v3,"AND") || po_buf_match(v3,"EOR") || po_buf_match(v3,"ADD"))
661 ) {
662 if(unsafe) {
663 optim(buf[0], "(unsafe, presumed dead)", NULL);
664 ++_environment->removedAssemblyLines;
665 }
666 optim(buf[1], RULE "(STB*,LDB+,ORB/ANDB/EORB/ADDB*)->(STB*,ORB/ANDB/EORB/ADDB+)", NULL);
667 optim(buf[2], NULL, "\t%sB %s", v3->str, v2->str);
668 }
669
670
671 if ( po_buf_match(buf[0], " STD _Ttmp*", v1) // 6
672 && po_buf_match(buf[1], " LD* [_Ttmp*]", v2, v3) // 9
673 && po_buf_strcmp(v1,v3)==0) {
674 //if(unsafe) optim(buf[0], "(unsafe, presumed dead)", NULL);
675 optim(buf[1], RULE "(STD,LDD[])->(TDX,LOAD*X)", "\tTFR D,X\n\tLD%c ,X", _toUpper(*v2->str));
676 }
677
678 if ( po_buf_match(buf[1], " TST*", v1)
679 && sets_flag(buf[0], *v1->str)) {
680 optim(buf[1], RULE "(FLAG-SET,TST)->(FLAG-SET)", NULL);
681 ++_environment->removedAssemblyLines;
682 }
683
684 if ( po_buf_match(buf[0], " LDB #$01")
685 && po_buf_match(buf[1], " LDX *", v1)
686 && po_buf_match(buf[2], " JSR CPUMATHMUL16BITTO32*", NULL)) {
687 optim(buf[0], RULE "(MUL#1)->(NOP)", "\tLDD %s", v1->str);
688 optim(buf[1], NULL, "\tLDX #0");
689 optim(buf[2], NULL, NULL);
690 ++_environment->removedAssemblyLines;
691 }
692
693 // A VOIR
694 if ( po_buf_match(buf[0], " STB *", v1)
695 && po_buf_match(buf[1], " STA ")
696 && po_buf_match(buf[2], " LDA *", v2)
697 && po_buf_match(buf[3], " STA *", v3)
698 && po_buf_strcmp(v1, v2)==0
699 && unsafe /* A is considered dead after */) {
700 optim(buf[2], RULE "(STB*,STA,LDA*,STA+)->(STB*,STA,STB+)", NULL);
701 optim(buf[3], NULL, "\tSTB %s", v3->str);
702 }
703
704 if( po_buf_match(buf[0], " STD _Ttmp*", v1)
705 && po_buf_match(buf[1], " LDD _Ttmp*", v2)
706 && po_buf_match(buf[2], " LDX _Ttmp*", v3)
707 && po_buf_strcmp(v1,v3)==0
708 && !po_buf_match(buf[3], " IF ")
709 && unsafe) {
710 optim(buf[0], RULE "(STD*,LDD,LDX*)->(TDX,LDD)", "\tTFR D,X");
711 optim(buf[2], NULL, NULL);
712 ++_environment->removedAssemblyLines;
713 }
714
715 if( po_buf_match(buf[0], " STA *", v1)
716 && po_buf_match(buf[1], " LDA *", v2)
717 && po_buf_match(buf[2], " STA *", v3)
718 && po_buf_strcmp(v1, v2)==0 ) {
719 optim(buf[0], RULE "(STAa,LDAa,STAb)->(STAb)", NULL );
720 optim(buf[1], NULL, NULL);
721 ++_environment->removedAssemblyLines;
722 ++_environment->removedAssemblyLines;
723 }
724
725 if( po_buf_match(buf[0], " STB *", v1)
726 && po_buf_match(buf[1], " LDB *", v2)
727 && po_buf_match(buf[2], " STB *", v3)
728 && po_buf_strcmp(v1, v2)==0 ) {
729 // If we are compiling "Cocon" game with a recent
730 // version of the compiler (>1.16.3), we must use the disruptive
731 // optimization rule to reduce executable size.
732 if ( _environment->vestigialConfig.rchack_cocon_1163 ) {
733 optim(buf[0], RULE "(STBa,LDBa,STBb)->(STBb)", NULL );
734 optim(buf[1], NULL, NULL);
735 ++_environment->removedAssemblyLines;
736 ++_environment->removedAssemblyLines;
737 } else {
738 optim(buf[1], RULE "(STBa,LDBa,STBb)->(STBb)", NULL );
739 ++_environment->removedAssemblyLines;
740 }
741 }
742
743 if( po_buf_match(buf[0], " STD *", v1)
744 && po_buf_match(buf[1], " LDD *", v2)
745 && po_buf_match(buf[2], " STD *", v3)
746 && po_buf_strcmp(v1, v2)==0 ) {
747 optim(buf[1], RULE "(STDa,LDDa,STDb)->(STDb)", NULL );
748 ++_environment->removedAssemblyLines;
749 }
750
751 if( po_buf_match(buf[0], " STD *", v1)
752 && po_buf_match(buf[1], " LDD *", v2)
753 && po_buf_match(buf[2], " STB *", v3)
754 && po_buf_strcmp(v1, v2)==0 ) {
755 optim(buf[1], RULE "(STDa,LDDa,STBb)->(STBb)", NULL );
756 // optim(buf[1], NULL, NULL);
757 ++_environment->removedAssemblyLines;
758 }
759
760 if( po_buf_match(buf[0], " STD *", v1)
761 && po_buf_match(buf[1], " LDD *", v2)
762 && po_buf_match(buf[2], " STA *", v3)
763 && po_buf_strcmp(v1, v2)==0 ) {
764 optim(buf[1], RULE "(STDa,LDDa,STAb)->(STBb)", NULL );
765 // optim(buf[1], NULL, NULL);
766 ++_environment->removedAssemblyLines;
767 ++_environment->removedAssemblyLines;
768 }
769
770 if( po_buf_match(buf[0], " LDD *", v1)
771 && po_buf_match(buf[1], " STD *", v2)
772 && po_buf_match(buf[2], " TFR D,X")
773 && !po_buf_match(buf[3], " *SR ", NULL)) {
774 optim(buf[0], RULE "(LDD*,STD+,TDX)->(LDX*,STX+)", "\tLDX %s", v1->str);
775 optim(buf[1], NULL, "\tSTX %s", v2->str);
776 optim(buf[2], NULL, NULL);
777 ++_environment->removedAssemblyLines;
778 }
779
780 if( po_buf_match(buf[0], " STD *", v1)
781 && po_buf_match(buf[1], " ST* *", NULL, v2)
782 && po_buf_match(buf[2], " LDD *", v3)
783 && po_buf_strcmp(v1, v3)==0
784 && po_buf_strcmp(v1, v2)!=0
785 && strchr((const char*)v2 ,'+')==NULL) {
786 optim(buf[2], RULE "(STD*,ST?,LDD*)->(STD*,ST?)", NULL);
787 ++_environment->removedAssemblyLines;
788 }
789
790 if( po_buf_match(buf[0], " STD *", v1)
791 && po_buf_match(buf[1], " LSLB")
792 && po_buf_match(buf[2], " ROLA")
793 && po_buf_match(buf[3], " STD *", v2)
794 && po_buf_strcmp(v1, v2)==0) {
795 optim(buf[0], RULE "(STD*,LSLB,ROLA,STD*)->(LSLB,ROLA,STD*)", NULL);
796 ++_environment->removedAssemblyLines;
797 }
798
799 if( po_buf_match(buf[0], " STD *", v1)
800 && po_buf_match(buf[1], " ADDD *", v2)
801 && po_buf_match(buf[2], " STD *", v3)
802 && po_buf_strcmp(v1, v3)==0
803 && po_buf_strcmp(v1, v2)!=0) {
804 optim(buf[0], RULE "(STD*,ADDD,STD*)->(ADDD,STD*)", NULL);
805 ++_environment->removedAssemblyLines;
806 }
807
808 if ( peephole_pass>2
809 && po_buf_match(buf[0], " STD _Ttmp*", v1)
810 && po_buf_match(buf[1], " LD* ", v2)
811 && po_buf_match(buf[2], " ST* [_Ttmp*]", v3, v4)
812 && po_buf_strcmp(v2,v3)==0
813 && po_buf_strcmp(v1,v4)==0) {
814 if(unsafe)
815 optim(buf[0], RULE "(unsafe, presumed dead) (STD,LOAD,STORE[])->(TDX,LOAD,STORE*X)", "\tTFR D,X");
816 else
817 optim(buf[0], RULE "(STD,LOAD,STORE[])", "\tSTD _Ttmp%s\n\tTFR D,X", v1->str);
818 optim(buf[2], NULL, "\tST%c ,X", *v2->str);
819 }
820
821 if(po_buf_match( buf[0], " STD *", v1)
822 && po_buf_match( buf[1], " LDB *+1", v2)
823 && po_buf_strcmp(v1, v2)==0) {
824 optim(buf[1], RULE "(STD,LDB+1)", NULL);
825 ++_environment->removedAssemblyLines;
826 }
827 if(po_buf_match( buf[0], " STD *", v1)
828 && po_buf_match( buf[1], " ST* *", NULL, v2) && 0!=po_buf_strcmp(v1,v2)
829 && po_buf_match( buf[2], " LDB *+1", v2)
830 && po_buf_strcmp(v1, v2)==0) {
831 optim(buf[2], RULE "(STD,?,LDB+1)", NULL);
832 ++_environment->removedAssemblyLines;
833 }
834 if(po_buf_match( buf[0], " STD *", v1)
835 && po_buf_match( buf[1], " ST* *", NULL, v2) && 0!=po_buf_strcmp(v1,v2)
836 && po_buf_match( buf[2], " ST* *", NULL, v2) && 0!=po_buf_strcmp(v1,v2)
837 && po_buf_match( buf[3], " LDB *+1", v2)
838 && po_buf_strcmp(v1, v2)==0) {
839 optim(buf[3], RULE "(STD,?,?,LDB+1)", NULL);
840 ++_environment->removedAssemblyLines;
841 }
842
843 if( po_buf_match(buf[0], " ST* *", v1, v2)
844 && po_buf_match(buf[1], " LD* *", v3, v4)
845 && po_buf_strcmp(v1, v3)==0 && po_buf_strcmp(v2, v4)==0 && strchr( v2->str, '$' ) == NULL ) {
846 optim(buf[1], RULE "(ST*a,LD*a)->(ST*a)", NULL );
847 ++_environment->removedAssemblyLines;
848 }
849
850 if( po_buf_match(buf[0], " STD *", v1)
851 && po_buf_match(buf[1], " LDD #$*", v2)
852 && po_buf_match(buf[2], " ADDD *", v3)
853 && po_buf_match(buf[3], " STD *", v4)
854 && (po_buf_strcmp(v1, v3) == 0) && (po_buf_strcmp(v3, v4) == 0)
855 ) {
856 optim(buf[1], RULE "(STD,LDD#,ADD,STD)->(LDD,ADD#,STD)", " LDD %s", v1->str );
857 optim(buf[2], RULE "(STD,LDD#,ADD,STD)->(LDD,ADD#,STD)", " ADDD #$%s", v2->str );
858 optim(buf[3], RULE "(STD,LDD#,ADD,STD)->(LDD,ADD#,STD)", " STD %s", v1->str );
859 ++_environment->removedAssemblyLines;
860 }
861
862 if( po_buf_match(buf[0], " ADDD #$*", v1)
863 && po_buf_match(buf[1], " ADDD #$*", v2)
864 ) {
865 long int vi1 = strtol(v1->str, NULL, 16);
866 long int vi2 = strtol(v2->str, NULL, 16);
867 optim(buf[0], RULE "(ADD#,ADD#)->(ADD#)", " ADDD #$%4.4x", (int)(vi1+vi2) );
868 optim(buf[1], RULE "(ADD#,ADD#)->(ADD#)", NULL );
869 ++_environment->removedAssemblyLines;
870 }
871
872 if( po_buf_match(buf[0], " LDD #$0000")
873 && po_buf_match(buf[1], " STD *", v2)
874 && po_buf_match(buf[2], " LDB *", v3)
875 && po_buf_match(buf[3], " ADDD *", v4)
876 && po_buf_match(buf[4], " STD *", v5)
877 && (po_buf_strcmp(v2, v4) == 0) && (po_buf_strcmp(v4, v5) == 0)
878 ) {
879 optim(buf[0], RULE "(LDD#0,STD,LDB,ADDD,STD)->(CLRA,LDB,STD)", NULL );
880 optim(buf[1], RULE "(LDD#0,STD,LDB,ADDD,STD)->(CLRA,LDB,STD)", " CLRA" );
881 optim(buf[3], RULE "(LDD#0,STD,LDB,ADDD,STD)->(CLRA,LDB,STD)", NULL );
882 ++_environment->removedAssemblyLines;
883 }
884
885 if( po_buf_match(buf[0], " JSR BANKREAD1")
886 && po_buf_match(buf[1], " INC *", v1 )
887 && po_buf_match(buf[2], " LDB #$*", v2)
888 && po_buf_match(buf[3], " LDY *", v3)
889 && po_buf_match(buf[4], " LDX #*", v4)
890 && po_buf_match(buf[5], " JSR BANKWRITE1")
891 && (po_buf_strcmp(v1, v4) == 0)
892 ) {
893 optim(buf[2], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
894 optim(buf[3], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
895 optim(buf[4], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
896 ++_environment->removedAssemblyLines;
897 }
898
899 if( po_buf_match(buf[0], " JSR BANKREAD1")
900 && po_buf_match(buf[1], " DEC *", v1 )
901 && po_buf_match(buf[2], " LDB #$*", v2)
902 && po_buf_match(buf[3], " LDY *", v3)
903 && po_buf_match(buf[4], " LDX #*", v4)
904 && po_buf_match(buf[5], " JSR BANKWRITE1")
905 && (po_buf_strcmp(v1, v4) == 0)
906 ) {
907 optim(buf[2], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
908 optim(buf[3], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
909 optim(buf[4], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
910 ++_environment->removedAssemblyLines;
911 }
912
913 if( po_buf_match(buf[0], " LDB *", v1)
914 && po_buf_match(buf[1], " CLRB" )
915 ) {
916 optim(buf[0], RULE "(BANKREAD1,BANWRITE1)->(BANKREADWRITE1)", NULL );
917 ++_environment->removedAssemblyLines;
918 }
919
920 if( po_buf_match(buf[0], " LDB *", v1)
921 && po_buf_match(buf[1], " LDB *", v2)
922 && strstr( v2->str, "," ) == NULL
923 ) {
924 optim(buf[0], RULE "(LDB,LDB)->(LDB)", NULL );
925 ++_environment->removedAssemblyLines;
926 }
927
928 if( po_buf_match(buf[0], " LDY #$*", v1)
929 && po_buf_match(buf[1], " LEAY *,Y", v2)
930 ) {
931 long address = strtol( v1->str, NULL, 16 );
932 long offset = strtol( v2->str, NULL, 16 );
933 optim(buf[0], RULE "(LDY#,LEAY+)->(LDY#+)", "\tLDY #$%4.4x", (unsigned int)(address+offset) );
934 optim(buf[1], RULE "(LDY#,LEAY+)->(LDY#+)", NULL );
935 ++_environment->removedAssemblyLines;
936 }
937
938 if( po_buf_match(buf[0], " LDD #$0000")
939 && po_buf_match(buf[1], " STD *", v1)
940 && po_buf_match(buf[2], " LDB *", v2)
941 && po_buf_match(buf[3], " ADD *", v3)
942 ) {
943 optim(buf[0], RULE "(LD#0,STD,LDB,ADD)->(CLRA,LDB)", " CLRA" );
944 optim(buf[1], RULE "(LD#0,STD,LDB,ADD)->(CLRA,LDB)", NULL );
945 ++_environment->removedAssemblyLines;
946 }
947
948 if( po_buf_match(buf[0], " LDD *", v1) && po_buf_match(buf[1], " LDD *", v2 ) ) {
949 optim(buf[0], RULE "(LDD,LDD)->(LDD)", NULL );
950 }
951
952 if( po_buf_match(buf[0], " CLRA") && po_buf_match(buf[1], " CLRB" ) && po_buf_match(buf[2], " LDD *", v1 ) ) {
953 optim(buf[0], RULE "(CLRA,CLRB,LDD)->(LDD)", NULL );
954 optim(buf[1], RULE "(CLRA,CLRB,LDD)->(LDD)", NULL );
955 }
956
957 if( po_buf_match(buf[0], " CLRD") && po_buf_match(buf[1], " LDD *", v1 ) ) {
958 optim(buf[0], RULE "(CLRS,LDD)->(LDD)", NULL );
959 }
960
961 if( po_buf_match(buf[0], " LDD #0000") || po_buf_match(buf[0], " LDD #$0000") ) {
962 optim(buf[0], RULE "(LDD#0000)->(CLRA, CLRB)", "\tCLRD" );
963 }
964
965 if( po_buf_match(buf[0], " LDD #$*", v1)
966 && po_buf_match(buf[1], " LDB #$*", v3, v2)
967 ) {
968 optim(buf[0], RULE "(LDD#,LDB#)->(LDA)", "\tLDA #$%2.2x", (unsigned char)(atoi( v1->str ) >> 8 ) );
969 }
970
971 if( po_buf_match(buf[0], " LDD #$*", v1)
972 && po_buf_match(buf[1], " CLRB")
973 ) {
974 optim(buf[0], RULE "(LDD#,CLRB)->(LDA)", "\tLDA #$%2.2x", (unsigned char)(atoi( v1->str ) >> 8 ) );
975 }
976
977 if( po_buf_match(buf[0], " CLRB", v1)
978 && po_buf_match(buf[1], " LDD")
979 ) {
980 optim(buf[0], RULE "(CLRB,LDD)->(LDD)", NULL );
981 }
982
983 if( po_buf_match(buf[0], " CLRA")
984 && po_buf_match(buf[1], " LDD *", v1)
985 ) {
986 optim(buf[0], RULE "(CLRA,LDD)->(LDD)", NULL );
987 ++_environment->removedAssemblyLines;
988 }
989
990 if( po_buf_match(buf[0], " LDB #$*", v1)
991 && po_buf_match(buf[1], " LDD #$*", v2)
992 ) {
993 optim(buf[0], RULE "(LDB#,LDD#)->(LDD)", NULL );
994 ++_environment->removedAssemblyLines;
995 }
996
997 if( po_buf_match(buf[0], " B* *", v1, v2)
998 && ( po_buf_match(buf[1], " DECB" ) || po_buf_match(buf[1], " INCB" ) )
999 && po_buf_match(buf[3], " *", v5)
1000 && po_buf_match(buf[4], " IF" )
1001 && po_buf_match(buf[5], " LBEQ *", v3)
1002 && po_buf_match(buf[6], " ELSE" )
1003 && po_buf_match(buf[7], " BEQ *", v4)
1004 && po_buf_match(buf[8], " ENDIF" )
1005 && ( strcmp(v5->str, "ANDB" ) != 0 && strcmp(v5->str, "ORB" ) != 0 && strcmp(v5->str, "EORB" ) != 0 )
1006 ) {
1007
1008 int inversed = 0;
1009
1010 if ( strstr(buf[1]->str, "DECB") ) {
1011 if (strcmp(v5->str, "TSTB") == 0) {
1012 inversed = 1;
1013 } if (strstr(buf[3]->str, "CMPB #$ff")) {
1014 inversed = 1;
1015 } else if ( strstr(v5->str, "COMB") ) {
1016 inversed = 1;
1017 }
1018 } else if ( strstr(buf[1]->str, "INCB") ) {
1019 if (strcmp(v5->str, "TSTB") == 0) {
1020 inversed = 1;
1021 } if (strstr(buf[3]->str, "CMPB #$00")) {
1022 inversed = 1;
1023 } if (strstr(buf[3]->str, "STB")) {
1024 inversed = 1;
1025 } else if ( strstr(v5->str, "COMB") ) {
1026
1027 }
1028 }
1029
1030 optim(buf[0], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1031 optim(buf[1], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1032 optim(buf[2], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1033 optim(buf[3], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1034
1035 if ( inversed ) {
1036 char conditional[4];
1037 if ( strcmp( v1->str, "CC") == 0 ) {
1038 strcopy( conditional, "CS" );
1039 }
1040 else if ( strcmp( v1->str, "CS" ) == 0 ) {
1041 strcopy( conditional, "CC" );
1042 } else if ( strcmp( v1->str, "EQ" ) == 0 ) {
1043 strcopy( conditional, "NE" );
1044 }
1045 else if ( strcmp( v1->str, "GE" ) == 0 ) {
1046 strcopy( conditional, "LT" );
1047 }
1048 else if ( strcmp( v1->str, "GT" ) == 0 ) {
1049 strcopy( conditional, "LE" );
1050 }
1051 else if ( strcmp( v1->str, "HI" ) == 0 ) {
1052 strcopy( conditional, "LS" );
1053 }
1054 else if ( strcmp( v1->str, "HS" ) == 0 ) {
1055 strcopy( conditional, "LO" );
1056 }
1057 else if ( strcmp( v1->str, "LE" ) == 0 ) {
1058 strcopy( conditional, "GT" );
1059 }
1060 else if ( strcmp( v1->str, "LO" ) == 0 ) {
1061 strcopy( conditional, "HS" );
1062 }
1063 else if ( strcmp( v1->str, "LS" ) == 0 ) {
1064 strcopy( conditional, "HI" );
1065 }
1066 else if ( strcmp( v1->str, "LT" ) == 0 ) {
1067 strcopy( conditional, "GE" );
1068 }
1069 else if ( strcmp( v1->str, "MI" ) == 0 ) {
1070 strcopy( conditional, "PL" );
1071 }
1072 else if ( strcmp( v1->str, "NE" ) == 0 ) {
1073 strcopy( conditional, "EQ" );
1074 }
1075 else if ( strcmp( v1->str, "PL" ) == 0 ) {
1076 strcopy( conditional, "MI" );
1077 }
1078 else if ( strcmp( v1->str, "RA" ) == 0 ) {
1079 strcopy( conditional, "RA" );
1080 }
1081 else if ( strcmp( v1->str, "RN" ) == 0 ) {
1082 strcopy( conditional, "RN" );
1083 }
1084 else if ( strcmp( v1->str, "VC" ) == 0 ) {
1085 strcopy( conditional, "VS" );
1086 }
1087 else if ( strcmp( v1->str, "VS" ) == 0 ) {
1088 strcopy( conditional, "VC" );
1089 }
1090 else {
1091 strcopy( conditional, v1->str );
1092 }
1093
1094 optim(buf[5], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", " LB%s %s", conditional, v3->str );
1095 optim(buf[7], RULE "(B?,DECB,TSTB/STB,[L]B)->([L]B)", " B%s %s", conditional, v4->str );
1096 } else {
1097 optim(buf[5], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", " LB%s %s", v1->str, v3->str );
1098 optim(buf[7], RULE "(B?,DECB,TSTB/STB,[L]B)->([L]B)", " B%s %s", v1->str, v4->str );
1099 }
1100 ++_environment->removedAssemblyLines;
1101 ++_environment->removedAssemblyLines;
1102 ++_environment->removedAssemblyLines;
1103 ++_environment->removedAssemblyLines;
1104 }
1105
1106 if( po_buf_match(buf[0], " CLRA")
1107 && po_buf_match(buf[1], " LDB *", v1)
1108 && po_buf_match(buf[2], " STD *", v2)
1109 && po_buf_match(buf[3], " LDD *", v3)
1110 && po_buf_match(buf[4], " ADDD *", v4)
1111 && po_buf_match(buf[5], " STD *", v5)
1112 ) {
1113 optim(buf[0], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " LDX %s", v3->str );
1114 optim(buf[1], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " LDB %s", v1->str );
1115 optim(buf[2], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " ABX" );
1116 optim(buf[3], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " STX %s", v5->str );
1117 optim(buf[4], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", NULL );
1118 optim(buf[5], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", NULL );
1119 ++_environment->removedAssemblyLines;
1120 ++_environment->removedAssemblyLines;
1121 }
1122
1123// 55EF 4F CLRA
1124// 55F0 F633AA LDB _Ttmp477
1125// 55F3 FD61AC STD _Ttmp553
1126// 55F6 FC61AA LDD _Ttmp552
1127// 55F9 F361AC ADDD _Ttmp553
1128// 55FC FD618C STD _Ttmp296
1129
1130
1131// 55F6 FC61AA LDX _Ttmp552
1132// 55F0 F633AA LDB _Ttmp477
1133// 55F3 FD61AC ABX
1134// 55FC FD618C STX _Ttmp296
1135
1136}
1137
1138/* check if POBuffer matches any of xxyy (used for LDD #$xxyy op) */
1139static POBuffer chkLDD(POBuffer buf, char *xxyy, POBuffer value) {
1140 return po_buf_match( buf, " LDD #$*", value) &&
1141 value->len==4 &&
1142 (xxyy[0]=='-' || xxyy[0]==value->str[0]) &&
1143 (xxyy[1]=='-' || xxyy[1]==value->str[1]) &&
1144 (xxyy[2]=='-' || xxyy[2]==value->str[2]) &&
1145 (xxyy[3]=='-' || xxyy[3]==value->str[3]) ? buf : NULL;
1146}
1147
1148/* can this opcode make A non zero */
1149static int can_nzA(POBuffer buf) {
1150 char *s;
1151
1152 for(s = buf->str; !_eol(*s) && *s!=','; ++s);
1153
1154 if(!po_buf_match(buf, " ")) return 1;
1155 if(po_buf_match(buf, " ADDA ")) return 1;
1156 if(po_buf_match(buf, " ADDD ")) return 1;
1157 if(po_buf_match(buf, " BSR ")) return 1;
1158 if(po_buf_match(buf, " COMA")) return 1;
1159 if(po_buf_match(buf, " DECA")) return 1;
1160 if(po_buf_match(buf, " EORA ")) return 1;
1161 if(po_buf_match(buf, " EXG ")) return 1;
1162 if(po_buf_match(buf, " INCA")) return 1;
1163 if(po_buf_match(buf, " JSR ")) return 1;
1164 if(po_buf_match(buf, " LDA ")) return 1;
1165 if(po_buf_match(buf, " LDD ")) return 1;
1166 if(po_buf_match(buf, " ORA ")) return 1;
1167 if(po_buf_match(buf, " PULS ")) return 1;
1168 if(po_buf_match(buf, " PULU ")) return 1;
1169 if(po_buf_match(buf, " ROLA")) return 1;
1170 if(po_buf_match(buf, " RORA")) return 1;
1171 if(po_buf_match(buf, " RTI")) return 1;
1172 if(po_buf_match(buf, " RTS")) return 1;
1173 if(po_buf_match(buf, " SBCA ")) return 1;
1174 if(po_buf_match(buf, " SEX")) return 1;
1175 if(po_buf_match(buf, " SUBA ")) return 1;
1176 if(po_buf_match(buf, " SUBD ")) return 1;
1177 if(po_buf_match(buf, " TFR ") && s[0]==',' && (s[1]=='A' || s[1]=='D')) return 1;
1178
1179 return 0;
1180}
1181
1182/* can this opcode make B non zero */
1183static int can_nzB(POBuffer buf) {
1184 char *s;
1185
1186 for(s = buf->str; !_eol(*s) && *s!=','; ++s);
1187
1188 if(!po_buf_match(buf, " ")) return 1;
1189 if(po_buf_match(buf, " ADDB ")) return 1;
1190 if(po_buf_match(buf, " ADDD ")) return 1;
1191 if(po_buf_match(buf, " BSR ")) return 1;
1192 if(po_buf_match(buf, " COMB")) return 1;
1193 if(po_buf_match(buf, " DECB")) return 1;
1194 if(po_buf_match(buf, " EORB ")) return 1;
1195 if(po_buf_match(buf, " EXG ")) return 1;
1196 if(po_buf_match(buf, " INCB")) return 1;
1197 if(po_buf_match(buf, " JSR ")) return 1;
1198 if(po_buf_match(buf, " LDB ")) return 1;
1199 if(po_buf_match(buf, " LDD ")) return 1;
1200 if(po_buf_match(buf, " ORB ")) return 1;
1201 if(po_buf_match(buf, " PULS ")) return 1;
1202 if(po_buf_match(buf, " PULU ")) return 1;
1203 if(po_buf_match(buf, " ROLB")) return 1;
1204 if(po_buf_match(buf, " RORB")) return 1;
1205 if(po_buf_match(buf, " RTI")) return 1;
1206 if(po_buf_match(buf, " RTS")) return 1;
1207 if(po_buf_match(buf, " SBCB ")) return 1;
1208 if(po_buf_match(buf, " SUBB ")) return 1;
1209 if(po_buf_match(buf, " SUBD ")) return 1;
1210 if(po_buf_match(buf, " TFR ") && s[0]==',' && (s[1]=='B' || s[1]=='D')) return 1;
1211
1212 return 0;
1213}
1214
1215/* optimizations related to A or B being zero */
1216static void optim_zAB(Environment * _environment, POBuffer buf[LOOK_AHEAD], int *zA, int *zB) {
1217 POBuffer v1 = TMP_BUF;
1218 POBuffer v2 = TMP_BUF;
1219 POBuffer v3 = TMP_BUF;
1220
1221 int unsafe = ALLOW_UNSAFE;
1222
1223 if(*zA) {
1224 if (po_buf_match( buf[0], " CLRA")) {
1225 optim( buf[0], RULE "[A=0](CLRA)->()", NULL);
1226 ++_environment->removedAssemblyLines;
1227 } else if (po_buf_match( buf[0], " LDA #$ff")) {
1228 optim( buf[0], RULE "[A=0](LDA#ff)->(DECA)", "\tDECA");
1229 *zA = 0;
1230 } else if ( po_buf_match(buf[0], " LDA #$01")) {
1231 optim( buf[0], RULE "[A=0](LDA#1)->(INCA)", "\tINCA");
1232 *zA = 0;
1233 // } else if ( chkLDD( buf[0], "00--", v1)) {
1234 // optim(buf[0], RULE "[A=0](LDD#00xx)->(LDB#xx)", "\tLDB #$%c%c", v1->str[2], v1->str[3]);
1235 // *zB = 0;
1236 } else if (po_buf_match( buf[0], " TFR A,B")) {
1237 optim( buf[0], RULE "[A=0](TAB)->(CLRB)", "\tCLRB");
1238 *zB = 1;
1239 } else if (peephole_pass>2
1240 && po_buf_match( buf[0], " STA *", v1)
1241 && po_buf_match( buf[1], " LDB *", v2)
1242 && po_buf_strcmp(v1,v2)==0) {
1243 optim(buf[1], RULE "[A=0](STA*,LDB*)->(CLRB)", "\tCLRB");
1244 } else if (*zB
1245 && po_buf_match(buf[0], " ADDD *", v1)) {
1246 optim(buf[0], RULE "[D=0](ADD)->(LDD)", "\tLDD %s", v1->str);
1247 } else if (*zB
1248 && po_buf_match(buf[0], " STD _Ttmp*", v1)
1249 && po_buf_match(buf[1], " LDX *", v2)
1250 && po_buf_match(buf[2], " CMPX _Ttmp*", v3)
1251 && po_buf_strcmp(v1, v3)==0) {
1252 if(unsafe) {
1253 optim(buf[0], "(unsafe, presumed dead)", NULL);
1254 ++_environment->removedAssemblyLines;
1255 }
1256 optim(buf[2], RULE "[D=0](STD*,LDX,CMPX*)->(LDX)", NULL);
1257 ++_environment->removedAssemblyLines;
1258 } else if(can_nzA(buf[0])) {
1259 *zA = 0;
1260 }
1261 } else if ( po_buf_match( buf[0], " ROLD") ||
1262 po_buf_match( buf[0], " RORD") ||
1263 po_buf_match( buf[0], " LSLD") ||
1264 po_buf_match( buf[0], " lSRD") ) {
1265 *zA = 0;
1266 *zB = 0;
1267 } else if ( chkLDD(buf[0], "00--", v1) || po_buf_match( buf[0], " LDD #0") || po_buf_match( buf[0], " CLRA") ) {
1268 *zA = 1;
1269 }
1270
1271 if(*zB) {
1272 if (po_buf_match( buf[0], " CLRB")) {
1273 optim( buf[0], RULE "[B=0](CLRB)->()", NULL);
1274 ++_environment->removedAssemblyLines;
1275 } else if (po_buf_match( buf[0], " LDB #$ff")) {
1276 optim( buf[0], RULE "[B=0](LDB#ff)->(DECB)", "\tDECB");
1277 *zB = 0;
1278 } else if (po_buf_match( buf[0], " LDB #$01")) {
1279 optim( buf[0], RULE "[B=0](LDB#1)->(INCB)", "\tINCB");
1280 *zB = 0;
1281 } else if ( chkLDD( buf[0], "--00", v1) ) {
1282 optim( buf[0], RULE "[B=0](LDB#xx00)->(LDA#xx)", "\tLDA #$%c%c", v1->str[0], v1->str[1]);
1283 *zA = 0;
1284 } else if (po_buf_match( buf[0], " TFR B,A")) {
1285 optim( buf[0], RULE "[B=0](TBA)->(CLRA)", "\tCLRA");
1286 *zA = 1;
1287 } else if(can_nzB(buf[0])) {
1288 *zB = 0;
1289 }
1290 } else if ( po_buf_match( buf[0], " ROLD") ||
1291 po_buf_match( buf[0], " RORD") ||
1292 po_buf_match( buf[0], " LSLD") ||
1293 po_buf_match( buf[0], " lSRD") ) {
1294 *zA = 0;
1295 *zB = 0;
1296 } else if ( chkLDD(buf[0], "--00", v1) || po_buf_match( buf[0], " LDD #0") || po_buf_match( buf[0], " CLRB") ) {
1297 *zB = 1;
1298 }
1299
1300 if(!*zA
1301 && po_buf_match( buf[0], " LDB #$*", v1)
1302 && po_buf_match( buf[1], " STB ")
1303 && po_buf_match( buf[2], " CLRA")) {
1304 optim(buf[0], RULE "(LDB#,STB,CLRA)->(LDD#,STB)", "\tLDD #$00%s", v1->str);
1305 optim(buf[2], NULL, NULL);
1306 ++_environment->removedAssemblyLines;
1307 *zA = 0;
1308 }
1309}
1310
1311/* optimizations related to variables */
1312
1313/* variables database */
1314static struct {
1315 struct var {
1316 char *name;
1317#define NO_REORG 1
1318#define NO_DP 2
1319#define NO_INLINE 4
1320#define NO_REMOVE 8
1322 int size;
1325 int offset; /* 0=unchanged, >0 offset to page 0; -1 = candidate for inlining, -2 = inlined, -3 = in ram */
1326 char *init;
1330 int size;
1332} vars;
1333
1334/* clears the database */
1335static void vars_clear(void) {
1336 int i;
1337 for(i=0; i<vars.size; ++i) {
1338 struct var *v = &vars.tab[i];
1339 free(v->name);
1340 if(v->init) free(v->init);
1341 }
1342 vars.size = 0;
1343 vars.page0_max = 0;
1344}
1345
1346/* gets (or creates) an entry for a variable from the data-base */
1347struct var *vars_get(POBuffer _name) {
1348 char *name = _name->str;
1349 struct var *ret = NULL;
1350 int i;
1351
1352 char *s=strchr(name,'+');
1353 if(s) *s='\0';
1354
1355 for(i=0; i<vars.size ; ++i) {
1356 if(strcmp(vars.tab[i].name, name)==0) {
1357 ret = &vars.tab[i];
1358 }
1359 }
1360 if(ret == NULL) {
1361 if(vars.size == vars.capacity) {
1362 vars.capacity += 16;
1363 vars.tab = realloc(vars.tab, sizeof(*vars.tab)*vars.capacity);
1364 }
1365 ret = &vars.tab[vars.size++];
1366 ret->name = strdup(name);
1367 ret->flags = 0;
1368 ret->size = 0;
1369 ret->nb_rd = 0;
1370 ret->nb_wr = 0;
1371 ret->offset = 0;
1372 ret->init = NULL;
1373 }
1374 if(s) *s='+';
1375
1376 return ret;
1377}
1378
1379/* look for variable uses and collect data about he variables */
1380static void vars_scan(POBuffer buf[LOOK_AHEAD]) {
1381 POBuffer tmp = TMP_BUF;
1382 POBuffer arg = TMP_BUF;
1383 POBuffer arg2 = TMP_BUF;
1384
1385 // if( po_buf_match( buf[0], " * _*+", NULL, buf) ) {
1386 // struct var *v = vars_get(buf);
1387 // v->flags |= NO_INLINE;
1388 // }
1389
1390 if( po_buf_match( buf[0], " * #*", NULL, arg)
1391 || po_buf_match( buf[0], " * [*]", NULL, arg)
1392 || po_buf_match( buf[0], " * <*", NULL, arg) ) if(vars_ok(arg)) {
1393 struct var *v = vars_get(arg);
1394 v->flags |= NO_REMOVE/*|NO_DP*/;
1395 v->nb_rd++;
1396 }
1397
1398 if( po_buf_match( buf[0], " LDX #*", arg)
1399 && po_buf_match( buf[1], " JSR BANKREAD1" )
1400 ) if(vars_ok(arg)) {
1401 struct var *v = vars_get(arg);
1402 v->bank_read = 1;
1403 }
1404
1405 if( po_buf_match( buf[0], " CLR *", arg)
1406 || po_buf_match( buf[0], " ST* *", tmp, arg) ) if(vars_ok(arg)) {
1407 struct var *v = vars_get(arg);
1408 v->nb_wr++;
1409 }
1410
1411 if (po_buf_match( buf[0], " ADD* *", NULL, arg)
1412 || po_buf_match( buf[0], " ADC* *", NULL, arg)
1413 || po_buf_match( buf[0], " AND* *", NULL, arg)
1414 || po_buf_match( buf[0], " CMP* *", NULL, arg)
1415 || po_buf_match( buf[0], " EOR* *", NULL, arg)
1416 || po_buf_match( buf[0], " LD* *", NULL, arg)
1417 || po_buf_match( buf[0], " OR* *", NULL, arg)
1418 || po_buf_match( buf[0], " SBC* *", NULL, arg)
1419 || po_buf_match( buf[0], " SUB* *", NULL, arg)
1420 || po_buf_match( buf[0], " DIV* *", NULL, arg)
1421
1422 || po_buf_match( buf[0], " ADD* <*", NULL, arg)
1423 || po_buf_match( buf[0], " ADC* <*", NULL, arg)
1424 || po_buf_match( buf[0], " AND* <*", NULL, arg)
1425 || po_buf_match( buf[0], " CMP* <*", NULL, arg)
1426 || po_buf_match( buf[0], " EOR* <*", NULL, arg)
1427 || po_buf_match( buf[0], " LD* <*", NULL, arg)
1428 || po_buf_match( buf[0], " OR* <*", NULL, arg)
1429 || po_buf_match( buf[0], " SBC* <*", NULL, arg)
1430 || po_buf_match( buf[0], " SUB* <*", NULL, arg)
1431 || po_buf_match( buf[0], " DIVQ* <*", NULL, arg)
1432 || po_buf_match( buf[0], " DIVD* <*", NULL, arg)
1433 ) if(vars_ok(arg)) {
1434 struct var *v = vars_get(arg);
1435 v->nb_rd++;
1436 }
1437 if(
1438 po_buf_match( buf[0], " ASL *", arg)
1439 || po_buf_match( buf[0], " ASR *", arg)
1440 || po_buf_match( buf[0], " COM *", arg)
1441 || po_buf_match( buf[0], " DEC *", arg)
1442 || po_buf_match( buf[0], " INC *", arg)
1443 || po_buf_match( buf[0], " LSL *", arg)
1444 || po_buf_match( buf[0], " LSR *", arg)
1445 || po_buf_match( buf[0], " ROL *", arg)
1446 || po_buf_match( buf[0], " ROR *", arg)
1447 || po_buf_match( buf[0], " TST *", arg)
1448
1449 || po_buf_match( buf[0], " ASL <*", arg)
1450 || po_buf_match( buf[0], " ASR <*", arg)
1451 || po_buf_match( buf[0], " COM <*", arg)
1452 || po_buf_match( buf[0], " DEC <*", arg)
1453 || po_buf_match( buf[0], " INC <*", arg)
1454 || po_buf_match( buf[0], " LSL <*", arg)
1455 || po_buf_match( buf[0], " LSR <*", arg)
1456 || po_buf_match( buf[0], " ROL <*", arg)
1457 || po_buf_match( buf[0], " ROR <*", arg)
1458 || po_buf_match( buf[0], " TST< *", arg)
1459
1460 ) if(vars_ok(arg)) {
1461 struct var *v = vars_get(arg);
1462 v->nb_wr++;
1463 v->nb_rd++;
1464 }
1465 if( po_buf_match(buf[0], " * *", tmp, arg)
1466 || po_buf_match(buf[0], " * [*]", tmp, arg) ) if(vars_ok(arg)) {
1467 struct var *v = vars_get(arg);
1468 if ( v->offset != -3 ) {
1469 v->offset = -1; /* candidate for inlining */
1470 }
1471 }
1472
1473 if( po_buf_match( buf[0], "* rzb *", tmp, arg) && vars_ok(tmp)) {
1474 struct var *v = vars_get(tmp);
1475 v->size = atoi(arg->str);
1476 v->init = strdup("1-1");
1477 }
1478
1479 if( po_buf_match(buf[0], "* fcb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
1480 struct var *v = vars_get(tmp);
1481 v->size = 1;
1482 v->init = strdup(isZero(arg->str) ? "1-1" : arg->str);
1483 }
1484
1485 if( po_buf_match(buf[0], "* fdb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
1486 struct var *v = vars_get(tmp);
1487 v->size = 2;
1488 v->init = strdup(arg->str);
1489 }
1490
1491 if(
1492 po_buf_match(buf[0], " * equ *+*", tmp, arg2, arg) ||
1493 po_buf_match(buf[0], "* equ *+*", tmp, arg2, arg)
1494 ) {
1495 struct var *v = vars_get(arg2);
1496 if ( v ) {
1497 v->nb_rd = 1;
1498 }
1499 struct var *v2 = vars_get(tmp);
1500 if ( v2 ) {
1501 v2->nb_rd = 1;
1502 }
1503 }
1504
1505 /* variable in RAMs are not eligibile to inlining */
1506 if( po_buf_match(buf[0], "* equ $*", tmp, arg) ) {
1507 struct var *v = vars_get(tmp);
1508 if ( v ) {
1509 if ( v->offset == -1 ) {
1510 v->offset = -3;
1511 }
1512 }
1513 }
1514
1515 /* heurstic to find the max used index in direct-page */
1516 if( po_buf_match(buf[0], "* equ $*", tmp, arg)
1517 && arg->len==2
1518 && (*tmp->str!='_' || tmp->str[1]=='T')) {
1519 int v = strtol(arg->str, NULL, 16);
1520 if (v >= vars.page0_max) vars.page0_max = v+2;
1521 }
1522}
1523
1524/* compares two variables according to their access-count */
1525static int vars_cmp(const void *_a, const void *_b) {
1526 const struct var *a = _a;
1527 const struct var *b = _b;
1528
1529 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
1530
1531 return -(diff!=0 ? diff : strcmp(a->name, b->name)); // Ttmp < Tstr
1532}
1533
1534/* decide which variable goes in direct-page, which will be inlined */
1535static void vars_prepare_relocation(void) {
1536 int i;
1537
1538 num_dp = 0;
1539 num_inlined = 0;
1540
1541 qsort(vars.tab, vars.size, sizeof(*vars.tab), vars_cmp);
1542
1543 for(i = 0; i<vars.size; ++i) {
1544 struct var *v = &vars.tab[i];
1545
1546 /* skip over unknown size var */
1547 if(v->size == 0) continue;
1548
1549 /* skip over unread variables */
1550 if(v->nb_rd == 0) continue;
1551
1552 /* flagged as not inline */
1553 if(v->flags & NO_INLINE) v->offset = 0;
1554 if(!DO_INLINE) v->offset = 0;
1555
1556 /* can't inline > 2 bytes */
1557 if(v->offset == -1 && v->size>2) v->offset = 0;
1558
1559 /* check if inlining is good */
1560 if(v->offset == -1) {
1561 /* LDA: imm=2, dp=4, extended=5
1562 LDD: imm=3, dp=5, extended=6 */
1563 int dp_cost = (3+v->size)*(v->nb_rd + v->nb_wr);
1564 int inline_cost = (4+v->size)*(v->nb_rd + v->nb_wr - 1)+(1+v->size);
1565
1566 if( (v->init==NULL || isZero(v->init) || 0==strcmp("1-1", v->init)) && dp_cost < inline_cost ) {
1567 if(DO_DIRECT_PAGE) v->offset = 0;
1568 }
1569 }
1570 if(DO_DIRECT_PAGE
1571 && 0==v->offset
1572 && 0==(v->flags && NO_DP)
1573 && v->size<=4 /* not too big to let room for others */
1574 && vars.page0_max + v->size <= 256
1575 ) {
1576
1577 if ( vars.page0_max == 0xd8 )
1578 ++vars.page0_max;
1579 if ( vars.page0_max == 0xa3 )
1580 ++vars.page0_max;
1581 if ( vars.page0_max == 0xd5 )
1582 ++vars.page0_max;
1583 if ( vars.page0_max == 0xe3 )
1584 ++vars.page0_max;
1585 if ( vars.page0_max == 0xef )
1586 ++vars.page0_max;
1587 while ( vars.page0_max < 0xf0 )
1588 ++vars.page0_max;
1589 if ( vars.page0_max == 0xf0 )
1590 ++vars.page0_max;
1591 if ( vars.page0_max == 0xf1 )
1592 ++vars.page0_max;
1593 if ( vars.page0_max == 0xf2 )
1594 ++vars.page0_max;
1595 if ( vars.page0_max == 0xf6 )
1596 ++vars.page0_max;
1597
1598 v->offset = vars.page0_max;
1599 vars.page0_max += v->size;
1600 }
1601
1602 // printf("%s %d/%d %d %d %d\n", v->name, v->nb_rd, v->nb_wr, v->offset, v->size, vars.page0_max);
1603 }
1604}
1605
1606/* removes unread variables */
1607static void vars_remove(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
1608 POBuffer var = TMP_BUF;
1609 POBuffer op = TMP_BUF;
1610
1611 if(!DO_UNREAD) return;
1612
1613 /* unread */
1614 if(po_buf_match( buf[0], " ST* *", op, var) && vars_ok(var)) {
1615 struct var *v = vars_get(var);
1616 if(v->nb_rd == 0 && v->offset!=-2) {
1617 char *rep = NULL;
1618 v->offset = 0;
1619 if(po_buf_match(buf[1], " IF ") && po_buf_match(buf[2], " LB")) {
1620 if(*op->str=='X') rep = "\tLEAX ,X";
1621 else {
1622 static char tst[8];
1623 sprintf(tst, "\tTST%c", *op->str);
1624 rep = tst;
1625 }
1626 }
1627 optim(buf[0], "unread1", rep != NULL ? "%s" : NULL, rep);
1628 ++_environment->removedAssemblyLines;
1629 }
1630 }
1631
1632 if(po_buf_match( buf[0], " NEG *", var) && vars_ok(var)) {
1633 struct var *v = vars_get(var);
1634 if(v->nb_rd == 0 && v->offset!=-2) {
1635 char *rep = NULL;
1636 v->offset = 0;
1637 if(po_buf_match(buf[1], " IF ") && po_buf_match(buf[2], " LB")) {
1638 if(*op->str=='X') rep = "\tLEAX ,X";
1639 else {
1640 static char tst[8];
1641 sprintf(tst, "\tTST%c", *op->str);
1642 rep = tst;
1643 }
1644 }
1645 optim(buf[0], "unread1", rep != NULL ? "%s" : NULL, rep);
1646 ++_environment->removedAssemblyLines;
1647 }
1648 }
1649
1650 /* remove changed variables */
1651 if(po_buf_match( buf[0], "* rzb ", var)
1652 || po_buf_match( buf[0], "* fcb ", var)
1653 || po_buf_match( buf[0], "* fdb ", var) ) if(vars_ok(var)) {
1654 struct var *v = vars_get(var);
1655 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags & NO_REMOVE) && v->offset!=-2) {
1656 // fprintf( stderr, "[unread2] = %s\n", buf[0]->str );
1657 optim(buf[0], "unread2",NULL);
1658 ++_environment->removedAssemblyLines;
1659 ++num_unread;
1660 }
1661 }
1662}
1663
1664
1665/* performs optimizations related to variables relocation */
1666static void vars_relocate(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
1667 POBuffer REG = TMP_BUF;
1668 POBuffer var = TMP_BUF;
1669 POBuffer op = TMP_BUF;
1670
1671 /* direct page or inlined */
1672 if(po_buf_match( buf[0], " * *", op, var) && vars_ok(var) ) {
1673 struct var *v = vars_get(var);
1674 // fprintf( stderr, " v->offset = %d\n", v->offset );
1675 if(v->offset > 0) {
1676 optim(buf[0], "direct-page1", "\t%s <(%s)", op->str, var->str);
1677 } else if(v->offset == -1 && chg_reg(buf[0], REG)
1678 && ((strchr("DXYU", *REG->str)!=NULL && v->size==2) || v->size==1) ) {
1679 if ( strstr( var->str, "+" ) == NULL && v->bank_read == 0 ) {
1680 v->offset = -2;
1681 v->flags |= NO_REMOVE;
1682 optim(buf[0], "inlined1", "\t%s #%s%s\n%s equ *-%d", op->str,
1683 v->init==NULL ? "*" : v->init,
1684 v->init==NULL ? (v->size==2 ? "" : "&255") : "",
1685 var->str, v->size);
1686 }
1687 }
1688 }
1689
1690 // if(po_buf_match( buf[0], " * [*]", op, var) && vars_ok(var)) {
1691 // struct var *v = vars_get(var);
1692 // if(v->offset > 0) {
1693 // optim(buf[0], "direct-page2", "\t%s [%s+$%04x]", op->str, var->str, DIRECT_PAGE);
1694 // } else if(v->offset == -1 && strstr(var->str,"+$")==NULL) {
1695 // v->offset = -2;
1696 // optim(buf[0], "inlined2", "\t%s >%s\n%s equ *-2", op->str,
1697 // v->init==NULL ? var->str : v->init, var->str);
1698 // }
1699 // }
1700
1701 if(po_buf_match( buf[0], " * #*", op, var) && vars_ok(var) ) {
1702 struct var *v = vars_get(var);
1703 if(v->offset > 0 && strstr(var->str,"+$")==NULL) {
1704 optim(buf[0], "direct-page3", "\t%s #%s+$%04x", op->str, var->str, DIRECT_PAGE);
1705 }
1706 }
1707
1708 /* remove changed variables */
1709 if(po_buf_match( buf[0], "* rzb ", var)
1710 || po_buf_match( buf[0], "* fcb ", var)
1711 || po_buf_match( buf[0], "* fdb ", var) ) if(vars_ok(var)) {
1712 struct var *v = vars_get(var);
1713 if(v->offset > 0) {
1714 optim(buf[0], "direct-page4", "%s equ $%02x", var->str, v->offset);
1715 ++num_dp;
1716 } else if(v->offset == -2 && v->bank_read == 0 ) {
1717 optim(buf[0], "inlined3", NULL);
1718 ++_environment->removedAssemblyLines;
1719 ++num_inlined;
1720 }
1721 }
1722}
1723
1724/* collapse all heading spaces into a single tabulation */
1725static void out(FILE *f, POBuffer _buf) {
1726 char *s = _buf->str;
1727 int tab = 0;
1728 while(*s==' ' || *s=='\t') {tab = 1; ++s;}
1729 if(tab) fputs("\t", f);
1730 fputs(s, f);
1731}
1732
1733/* remove space that is sometimes used in indexing mode and makes the optimized produce bad dcode */
1734static void fixes_indexed_syntax(POBuffer buf) {
1735 char *s = buf->str;
1736
1737 /* not an instruction */
1738 if(!_eq(' ', *s)) return;
1739
1740 /* skip over spaces */
1741 do ++s; while(*s && _eq(' ', *s));
1742
1743 /* comment */
1744 if(*s==';') return;
1745
1746 /* skip over instruction */
1747 while(*s && !_eq(' ', *s)) ++s;
1748 if(!*s) return;
1749
1750 /* skip over spaces */
1751 do ++s; while(*s && _eq(' ', *s));
1752 if(!*s) return;
1753
1754 /* process argment */
1755 do ++s; while(*s && !_eq(' ', *s));
1756 if(!*s) return;
1757
1758 /* space found check if case "LDA 1, X" */
1759 if(s[-1]==',') {
1760 char *t = s;
1761 do ++t; while(*t && _eq(' ', *t));
1762 switch(_toUpper(*t)) {
1763 case 'X': case 'Y': case 'U': case 'S':
1764 /* yes ==> move register after coma */
1765 *s = *t;
1766 *t = ' ';
1767 break;
1768 default:
1769 break;
1770 }
1771 }
1772}
1773
1774/* various kind of optimization */
1775static int optim_pass( Environment * _environment, POBuffer buf[LOOK_AHEAD], PeepHoleOptimizationKind kind) {
1776 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1777 FILE * fileAsm;
1778 FILE * fileOptimized;
1779 int i;
1780 int still_to_go = LOOK_AHEAD;
1781
1782 int line = 0;
1783 int zA = 0, zB = 0;
1784
1785 int sourceLine = -1;
1786
1787 _environment->currentSourceLineAnalyzed = 0;
1788 _environment->removedAssemblyLines = 0;
1789
1790 adiline2( "POP:0:%d:%d", peephole_pass, kind );
1791
1792 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1793
1794 /* prepare for phase */
1795 switch(kind) {
1796 case DEADVARS:
1797 ++peephole_pass;
1798 num_unread = 0;
1799 break;
1800
1801 case RELOCATION1:
1802 ++peephole_pass;
1803 vars_prepare_relocation();
1804 break;
1805
1806 case RELOCATION2:
1807 break;
1808
1809 case PEEPHOLE:
1810 ++peephole_pass;
1811 vars_clear();
1812 break;
1813 }
1814
1815 fileAsm = fopen( _environment->asmFileName, "rt" );
1816 if(fileAsm == NULL) {
1817 perror(_environment->asmFileName);
1818 exit(-1);
1819 }
1820
1821 fileOptimized = fopen( fileNameOptimized, "wt" );
1822 if(fileOptimized == NULL) {
1823 perror(fileNameOptimized);
1824 exit(-1);
1825 }
1826
1827 /* clears our look-ahead buffers */
1828 for(i = 0; i<LOOK_AHEAD; ++i) po_buf_cpy(buf[i], "");
1829
1830 /* global change flag */
1831 change = 0;
1832
1833 while( still_to_go ) {
1834 /* print out oldest POBuffer */
1835 if ( line >= LOOK_AHEAD ) out(fileOptimized, buf[0]);
1836
1837 /* shift the buffers */
1838 for(i=0; i<LOOK_AHEAD-1; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
1839
1840 /* read next line, merging adjacent comments */
1841 if(feof(fileAsm)) {
1842 --still_to_go;
1843 po_buf_cpy(buf[LOOK_AHEAD-1], "");
1844 } else do {
1845 /* read next line */
1846 po_buf_fgets( buf[LOOK_AHEAD-1], fileAsm );
1847 fixes_indexed_syntax(buf[LOOK_AHEAD-1]);
1848 /* merge comment with previous line if we do not overflow the POBuffer */
1849 if(isAComment(buf[LOOK_AHEAD-1])) {
1850 POBuffer ln = TMP_BUF;
1851 if (po_buf_match( buf[LOOK_AHEAD-1], " ; L:*", ln ) ) {
1852 sourceLine = atoi( ln->str );
1853 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
1854 if ( _environment->currentSourceLineAnalyzed ) {
1855 adiline3( "POL:0:%d:%d:%d",
1856 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
1857 }
1858 _environment->currentSourceLineAnalyzed = sourceLine;
1859 _environment->removedAssemblyLines = 0;
1860 }
1861 }
1862 if(KEEP_COMMENTS) po_buf_cat(buf[LOOK_AHEAD-2], buf[LOOK_AHEAD-1]->str);
1863 po_buf_cpy(buf[LOOK_AHEAD-1], "");
1864 } else break;
1865 } while(!feof(fileAsm));
1866
1867 switch(kind) {
1868 case PEEPHOLE:
1869 // fprintf( stderr, "kind = PEEPHOLE buf = [%s]\n", buf[0]->str );
1870 basic_peephole(_environment, buf, zA, zB);
1871 optim_zAB(_environment, buf, &zA, &zB);
1872
1873 // fprintf( stderr, "change = %d buf = [%s]\n", change, buf[0]->str );
1874
1875 /* only look fo variable when no peephole has been performed */
1876 /*if(change == 0)*/ vars_scan(buf);
1877 break;
1878
1879 case DEADVARS:
1880 // fprintf( stderr, "kind = DEADVARS buf = [%s]\n", buf[0]->str );
1881 vars_remove(_environment, buf);
1882 break;
1883
1884 case RELOCATION1:
1885 case RELOCATION2:
1886 // fprintf( stderr, "kind = RELOCATION 1/2 buf = [%s]\n", buf[0]->str );
1887 vars_relocate(_environment, buf);
1888 break;
1889 }
1890
1891 // for(int i=0; i<vars.size; ++i) {
1892 // fprintf( stderr, "%d ) %s (rd = %d, wr = %d)\n", i, vars.tab[i].name, vars.tab[i].nb_rd, vars.tab[i].nb_wr );
1893 // }
1894 // fprintf( stderr, "\n------------------------\n" );
1895
1896 ++line;
1897 }
1898
1899 /* log info at the end of the file */
1900 switch(kind) {
1901 case PEEPHOLE:
1902 fprintf(fileOptimized, "; peephole: pass %d, %d change%s.\n", peephole_pass,
1903 change, change>1 ?"s":"");
1904 break;
1905
1906 case DEADVARS:
1907 fprintf(fileOptimized, "; peephole: pass %d, %d var%s removed.\n", peephole_pass,
1908 num_unread, num_unread>1 ?"s":"");
1909 break;
1910
1911 case RELOCATION2:
1912 fprintf(fileOptimized, "; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
1913 num_dp, num_dp>1 ?"s":"",
1914 num_inlined, num_inlined>1 ? "s":"");
1915 break;
1916
1917 default:
1918 break;
1919 }
1920
1921 (void)fclose(fileAsm);
1922 (void)fclose(fileOptimized);
1923
1924 /* makes our generated file the new asm file */
1925 remove(_environment->asmFileName);
1926 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1927
1928 return change;
1929}
1930
1931typedef struct _UnusedSymbol {
1932
1933 char * realName;
1934
1935 struct _UnusedSymbol * next;
1936
1938
1939static void optim_remove_unused_temporary( Environment * _environment ) {
1940
1941 int i;
1942
1943 POBuffer bufLine = TMP_BUF;
1944 POBuffer v1 = TMP_BUF;
1945 POBuffer v2 = TMP_BUF;
1946 POBuffer v3 = TMP_BUF;
1947 POBuffer v4 = TMP_BUF;
1948 POBuffer v5 = TMP_BUF;
1949 POBuffer v6 = TMP_BUF;
1950 POBuffer buf[5];
1951
1952 for(i=0; i<5; ++i) buf[i] = po_buf_new(0);
1953
1954 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1955 FILE * fileAsm;
1956 FILE * fileOptimized;
1957
1958 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1959
1960 fileAsm = fopen( _environment->asmFileName, "rt" );
1961 if(fileAsm == NULL) {
1962 perror(_environment->asmFileName);
1963 exit(-1);
1964 }
1965
1966 fileOptimized = fopen( fileNameOptimized, "wt" );
1967 if(fileOptimized == NULL) {
1968 perror(fileNameOptimized);
1969 exit(-1);
1970 }
1971
1972 UnusedSymbol * currentlySymbols = NULL;
1973 UnusedSymbol * currentlySymbolsQ = NULL;
1974 UnusedSymbol * currentlyUnusedSymbols = NULL;
1975 UnusedSymbol * currentlyUnusedSymbolsQ = NULL;
1976
1977 int vspPointer = 0;
1978
1979 while( !feof(fileAsm) ) {
1980
1981 po_buf_fgets( bufLine, fileAsm );
1982
1983 // printf( "### %s\n", bufLine->str );
1984
1985 if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
1986 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1987 memset( s, 0, sizeof( UnusedSymbol ) );
1988 s->realName = strdup( v1->str );
1989 s->next = currentlyUnusedSymbols;
1990 currentlyUnusedSymbols = s;
1991
1992 s = malloc( sizeof( UnusedSymbol ) );
1993 memset( s, 0, sizeof( UnusedSymbol ) );
1994 s->realName = strdup( v1->str );
1995 s->next = currentlySymbols;
1996 currentlySymbols = s;
1997 } else if ( po_buf_match( bufLine, " ; Q *", v1 ) ) {
1998 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1999 memset( s, 0, sizeof( UnusedSymbol ) );
2000 s->realName = strdup( v1->str );
2001 s->next = currentlyUnusedSymbolsQ;
2002 currentlyUnusedSymbolsQ = s;
2003
2004 s = malloc( sizeof( UnusedSymbol ) );
2005 memset( s, 0, sizeof( UnusedSymbol ) );
2006 s->realName = strdup( v1->str );
2007 s->next = currentlySymbolsQ;
2008 currentlySymbolsQ = s;
2009 } else if ( po_buf_match( bufLine, " ; VSP" ) ) {
2010
2011 // printf( "SYMBOLS COMPLETE (Q): " );
2012 // UnusedSymbol * s = currentlyUnusedSymbolsQ;
2013 // while( s ) {
2014 // printf( "%s, ", s->realName );
2015 // s = s->next;
2016 // }
2017 // printf( "\n\n" );
2018
2019 fseek( fileAsm, vspPointer, SEEK_SET );
2020
2021 while( !feof(fileAsm) ) {
2022
2023 po_buf_fgets( bufLine, fileAsm );
2024
2025 POBuffer result = po_buf_match(bufLine, "* equ **-1", v1 );
2026 if ( ! result ) result = po_buf_match(bufLine, "* equ **-2", v2, v1 );
2027 if ( ! result ) result = po_buf_match(bufLine, " ADC* [*]", v2, v1 );
2028 if ( ! result ) result = po_buf_match( bufLine, " ADD* [*]", v2, v1);
2029 if ( ! result ) result = po_buf_match( bufLine, " ADC* [*]", v2, v1);
2030 if ( ! result ) result = po_buf_match( bufLine, " AND* [*]", v2, v1);
2031 if ( ! result ) result = po_buf_match( bufLine, " CMP* [*]", v2, v1);
2032 if ( ! result ) result = po_buf_match( bufLine, " EOR* [*]", v2, v1);
2033 if ( ! result ) result = po_buf_match( bufLine, " LD* [*]", v2, v1);
2034 if ( ! result ) result = po_buf_match( bufLine, " OR* [*]", v2, v1);
2035 if ( ! result ) result = po_buf_match( bufLine, " SBC* [*]", v2, v1);
2036 if ( ! result ) result = po_buf_match( bufLine, " ST* [*]", v2, v1);
2037 if ( ! result ) result = po_buf_match( bufLine, " SUB* [*]", v2, v1);
2038 if ( ! result ) result = po_buf_match( bufLine, " ASL [*]", v1);
2039 if ( ! result ) result = po_buf_match( bufLine, " ASR [*]", v1);
2040 if ( ! result ) result = po_buf_match( bufLine, " TST [*]", v1);
2041 if ( ! result ) result = po_buf_match( bufLine, " ADC* *", v2, v1);
2042 if ( ! result ) result = po_buf_match( bufLine, " ADD* *", v2, v1);
2043 if ( ! result ) result = po_buf_match( bufLine, " ADC* *", v2, v1);
2044 if ( ! result ) result = po_buf_match( bufLine, " AND* *", v2, v1);
2045 if ( ! result ) result = po_buf_match( bufLine, " CMP* *", v2, v1);
2046 if ( ! result ) result = po_buf_match( bufLine, " EOR* *", v2, v1);
2047 if ( ! result ) result = po_buf_match( bufLine, " LD* #*", v2, v1);
2048 if ( ! result ) result = po_buf_match( bufLine, " LD* *", v2, v1);
2049 if ( ! result ) result = po_buf_match( bufLine, " LD* *", v2, v1);
2050 if ( ! result ) result = po_buf_match( bufLine, " OR* *", v2, v1);
2051 if ( ! result ) result = po_buf_match( bufLine, " SBC* *", v2, v1);
2052 if ( ! result ) result = po_buf_match( bufLine, " SUB* *", v2, v1);
2053 if ( ! result ) result = po_buf_match( bufLine, " ASL *", v1);
2054 if ( ! result ) result = po_buf_match( bufLine, " ASR *", v1);
2055 if ( ! result ) result = po_buf_match( bufLine, " TST *", v1);
2056 if ( result ) {
2057 char * realVarName = strdup( v1->str );
2058 char * c = strstr( realVarName, "+" );
2059 if ( c ) {
2060 *c = 0;
2061 }
2062 c = strstr( realVarName, "#" );
2063 if ( c ) {
2064 strcopy( c, c+1 );
2065 }
2066 c = strstr( realVarName, "<(" );
2067 if ( c ) {
2068 strcopy( c, c+2 );
2069 }
2070 c = strstr( realVarName, ")" );
2071 if ( c ) {
2072 *c = 0;
2073 }
2074 UnusedSymbol * tmp = currentlyUnusedSymbols;
2075 UnusedSymbol * previous = NULL;
2076 while( tmp ) {
2077 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2078 if ( previous ) {
2079 previous->next = tmp->next;
2080 } else {
2081 currentlyUnusedSymbols = tmp->next;
2082 }
2083 break;
2084 }
2085 previous = tmp;
2086 tmp = tmp->next;
2087 }
2088
2089 tmp = currentlyUnusedSymbolsQ;
2090 previous = NULL;
2091 while( tmp ) {
2092 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2093 if ( previous ) {
2094 previous->next = tmp->next;
2095 } else {
2096 currentlyUnusedSymbolsQ = tmp->next;
2097 }
2098 break;
2099 }
2100 previous = tmp;
2101 tmp = tmp->next;
2102 }
2103 }
2104
2105 if ( po_buf_match( bufLine, " ; VSP" ) ) {
2106 break;
2107 }
2108
2109 }
2110
2111 // printf( "REALLY UNUSED SYMBOLS (Q): " );
2112 // s = currentlyUnusedSymbolsQ;
2113 // while( s ) {
2114 // printf( "%s, ", s->realName );
2115 // s = s->next;
2116 // }
2117 // printf( "\n\n" );
2118
2119 fseek( fileAsm, vspPointer, SEEK_SET );
2120
2121 int line = 0;
2122
2123 po_buf_cpy(buf[0], "");
2124 po_buf_cpy(buf[1], "");
2125 po_buf_cpy(buf[2], "");
2126 po_buf_cpy(buf[3], "");
2127 po_buf_cpy(buf[4], "");
2128
2129 while( !feof(fileAsm) ) {
2130
2131 int endOfSection = 0;
2132
2133 if ( line >= 2 ) out(fileOptimized, buf[0]);
2134 po_buf_cpy(buf[0], buf[1]->str);
2135 po_buf_cpy(buf[1], buf[2]->str);
2136 po_buf_cpy(buf[2], buf[3]->str);
2137 po_buf_cpy(buf[3], buf[4]->str);
2138 po_buf_fgets( buf[4], fileAsm );
2139 while( isAComment( buf[4] ) && !endOfSection && !feof( fileAsm ) ) {
2140 if ( po_buf_match( buf[4], " ; VSP" ) ) {
2141 endOfSection = 1;
2142 }
2143 if(KEEP_COMMENTS) po_buf_cat(buf[3], buf[4]->str);
2144 po_buf_fgets( buf[4], fileAsm );
2145 }
2146 ++line;
2147
2148 // printf("Checking: - - - - - - - - - - -\n");
2149 // printf("1: %s\n", buf[0]->str );
2150 // printf("2: %s\n", buf[1]->str );
2151 // printf("3: %s\n", buf[2]->str );
2152 // printf("- - - - - - - - - - - checking\n");
2153
2154 if (
2155 po_buf_match( buf[0], " ST* *", v1, v2 ) &&
2156 po_buf_match( buf[1], " LD* *", v3, v4 ) &&
2157 po_buf_match( buf[2], " ST* *", v5, v6 ) &&
2158 po_buf_cmp( v2, v4 ) == 0 &&
2159 po_buf_cmp( v3, v5 ) == 0
2160 ) {
2161
2162 // printf(" RULE #1\n");
2163
2164 char * realVarName = strdup( v4->str );
2165 char * c = strstr( realVarName, "+" );
2166 if ( c ) {
2167 *c = 0;
2168 }
2169 c = strstr( realVarName, "<(" );
2170 if ( c ) {
2171 strcopy( c, c+2 );
2172 }
2173 c = strstr( realVarName, ")" );
2174 if ( c ) {
2175 *c = 0;
2176 }
2177
2178 // printf( "realVarName = %s\n", realVarName );
2179
2180 char * realVarName2 = strdup( v6->str );
2181 c = strstr( realVarName2, "+" );
2182 if ( c ) {
2183 *c = 0;
2184 }
2185 c = strstr( realVarName2, "<(" );
2186 if ( c ) {
2187 strcopy( c, c+2 );
2188 }
2189 c = strstr( realVarName2, ")" );
2190 if ( c ) {
2191 *c = 0;
2192 }
2193
2194 // printf( "realVarName2 = %s\n", realVarName2 );
2195
2196 UnusedSymbol * tmp = currentlySymbols;
2197 while( tmp ) {
2198 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2199 break;
2200 }
2201 tmp = tmp->next;
2202 }
2203 UnusedSymbol * tmp2 = currentlySymbolsQ;
2204 while( tmp2 ) {
2205 if ( strcmp( realVarName2, tmp2->realName ) == 0 ) {
2206 break;
2207 }
2208 tmp2 = tmp2->next;
2209 }
2210 UnusedSymbol * tmp3 = currentlySymbols;
2211 while( tmp3 ) {
2212 if ( strcmp( realVarName2, tmp3->realName ) == 0 ) {
2213 break;
2214 }
2215 tmp3 = tmp3->next;
2216 }
2217 if ( tmp && ( tmp2 || tmp3 ) ) {
2218 // printf( "found!\n\n" );
2219 // printf(" APPLIED #1\n");
2220 // optim( buf[0], RULE "unused temporary", NULL );
2221 optim( buf[0], RULE "unused temporary", "\tST%s %s", v1->str, v6->str );
2222 optim( buf[1], RULE "unused temporary", NULL );
2223 optim( buf[2], RULE "unused temporary", NULL );
2224 ++_environment->removedAssemblyLines;
2225 ++_environment->removedAssemblyLines;
2226 }
2227 } else if (
2228 ( ( po_buf_match( buf[0], " LDA #*", v1 ) || po_buf_match( buf[0], " CLRA") ) && po_buf_match( buf[1], " STA *", v2 ) && po_buf_match( buf[4], " ABX" ) ) ||
2229 ( ( po_buf_match( buf[0], " LDB #*", v1 ) || po_buf_match( buf[0], " CLRB") ) && po_buf_match( buf[1], " STB *", v2 ) && po_buf_match( buf[4], " ABX" ) )
2230 ) {
2231
2232 char * realVarName = strdup( v2->str );
2233 char * c = strstr( realVarName, "+" );
2234 if ( c ) {
2235 *c = 0;
2236 }
2237 c = strstr( realVarName, "<(" );
2238 if ( c ) {
2239 strcopy( c, c+2 );
2240 }
2241 c = strstr( realVarName, ")" );
2242 if ( c ) {
2243 *c = 0;
2244 }
2245
2246 // printf(" RULE #2 for [%s]\n", realVarName );
2247
2248 UnusedSymbol * tmp = currentlyUnusedSymbols;
2249 while( tmp ) {
2250 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2251 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2252 // printf(" > found!\n" );
2253 break;
2254 }
2255 tmp = tmp->next;
2256 }
2257 // printf( "\n" );
2258 if ( tmp ) {
2259 // printf(" APPLIED #2\n");
2260 optim( buf[1], RULE "unused temporary", NULL );
2261 ++_environment->removedAssemblyLines;
2262 }
2263 } else if (
2264 po_buf_match( buf[0], " STD *", v2 ) &&
2265 po_buf_match( buf[1], " LDD *", v4 ) &&
2266 po_buf_match( buf[2], " ST* *", v5, v6 ) &&
2267 po_buf_cmp( v2, v4 ) == 0 &&
2268 ( strcmp( v5->str, "A" ) == 0 || strcmp( v5->str, "B" ) == 0 )
2269 ) {
2270
2271 // printf(" RULE #1\n");
2272
2273 char * realVarName = strdup( v4->str );
2274 char * c = strstr( realVarName, "+" );
2275 if ( c ) {
2276 *c = 0;
2277 }
2278 c = strstr( realVarName, "<(" );
2279 if ( c ) {
2280 strcopy( c, c+2 );
2281 }
2282 c = strstr( realVarName, ")" );
2283 if ( c ) {
2284 *c = 0;
2285 }
2286
2287 // printf( "realVarName = %s\n", realVarName );
2288
2289 char * realVarName2 = strdup( v6->str );
2290 c = strstr( realVarName2, "+" );
2291 if ( c ) {
2292 *c = 0;
2293 }
2294 c = strstr( realVarName2, "<(" );
2295 if ( c ) {
2296 strcopy( c, c+2 );
2297 }
2298 c = strstr( realVarName2, ")" );
2299 if ( c ) {
2300 *c = 0;
2301 }
2302
2303 // printf( "realVarName2 = %s\n", realVarName2 );
2304
2305 UnusedSymbol * tmp = currentlySymbols;
2306 while( tmp ) {
2307 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2308 break;
2309 }
2310 tmp = tmp->next;
2311 }
2312 UnusedSymbol * tmp2 = currentlySymbolsQ;
2313 while( tmp2 ) {
2314 if ( strcmp( realVarName2, tmp2->realName ) == 0 ) {
2315 break;
2316 }
2317 tmp2 = tmp2->next;
2318 }
2319 UnusedSymbol * tmp3 = currentlySymbols;
2320 while( tmp3 ) {
2321 if ( strcmp( realVarName2, tmp3->realName ) == 0 ) {
2322 break;
2323 }
2324 tmp3 = tmp3->next;
2325 }
2326 if ( tmp && ( tmp2 || tmp3 ) ) {
2327 // printf( "found!\n\n" );
2328 // printf(" APPLIED #1\n");
2329 // optim( buf[0], RULE "unused temporary", NULL );
2330 optim( buf[0], RULE "unused temporary", "\tST%s %s", v5->str, v6->str );
2331 optim( buf[1], RULE "unused temporary", NULL );
2332 optim( buf[2], RULE "unused temporary", NULL );
2333 ++_environment->removedAssemblyLines;
2334 ++_environment->removedAssemblyLines;
2335 }
2336 } else if (
2337 ( ( po_buf_match( buf[0], " LDA #*", v1 ) || po_buf_match( buf[0], " CLRA") ) && po_buf_match( buf[1], " STA *", v2 ) && po_buf_match( buf[4], " ABX" ) ) ||
2338 ( ( po_buf_match( buf[0], " LDB #*", v1 ) || po_buf_match( buf[0], " CLRB") ) && po_buf_match( buf[1], " STB *", v2 ) && po_buf_match( buf[4], " ABX" ) )
2339 ) {
2340
2341 char * realVarName = strdup( v2->str );
2342 char * c = strstr( realVarName, "+" );
2343 if ( c ) {
2344 *c = 0;
2345 }
2346 c = strstr( realVarName, "<(" );
2347 if ( c ) {
2348 strcopy( c, c+2 );
2349 }
2350 c = strstr( realVarName, ")" );
2351 if ( c ) {
2352 *c = 0;
2353 }
2354
2355 // printf(" RULE #2 for [%s]\n", realVarName );
2356
2357 UnusedSymbol * tmp = currentlyUnusedSymbols;
2358 while( tmp ) {
2359 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2360 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2361 // printf(" > found!\n" );
2362 break;
2363 }
2364 tmp = tmp->next;
2365 }
2366 // printf( "\n" );
2367 if ( tmp ) {
2368 // printf(" APPLIED #2\n");
2369 optim( buf[1], RULE "unused temporary", NULL );
2370 ++_environment->removedAssemblyLines;
2371 }
2372 } else if (
2373 ( po_buf_match( buf[0], " LDA #*", v1 ) && po_buf_match( buf[1], " STA *", v2 ) && ( po_buf_match( buf[2], " ADDA *", v3 ) || po_buf_match( buf[2], " SUBA *", v3 ) || po_buf_match( buf[2], " MUL" ) ) ) ||
2374 ( po_buf_match( buf[0], " LDB #*", v1 ) && po_buf_match( buf[1], " STB *", v2 ) && ( po_buf_match( buf[2], " ADDB *", v3 ) || po_buf_match( buf[2], " SUBB *", v3 ) || po_buf_match( buf[2], " MUL" ) ) ) ||
2375 ( po_buf_match( buf[0], " LDD #*", v1 ) && po_buf_match( buf[1], " STD *", v2 ) && ( po_buf_match( buf[2], " ADDD *", v3 ) || po_buf_match( buf[2], " SUBD *", v3 ) || po_buf_match( buf[2], " MUL" ) ) )
2376 ) {
2377
2378 // printf(" RULE #1\n");
2379
2380 char * realVarName = strdup( v2->str );
2381 char * c = strstr( realVarName, "+" );
2382 if ( c ) {
2383 *c = 0;
2384 }
2385 c = strstr( realVarName, "<(" );
2386 if ( c ) {
2387 strcopy( c, c+2 );
2388 }
2389 c = strstr( realVarName, ")" );
2390 if ( c ) {
2391 *c = 0;
2392 }
2393
2394 UnusedSymbol * tmp = currentlyUnusedSymbols;
2395 while( tmp ) {
2396 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2397 break;
2398 }
2399 tmp = tmp->next;
2400 }
2401 if ( tmp ) {
2402 // printf(" APPLIED #1\n");
2403 // optim( buf[0], RULE "unused temporary", NULL );
2404 optim( buf[1], RULE "unused temporary", NULL );
2405 ++_environment->removedAssemblyLines;
2406 ++_environment->removedAssemblyLines;
2407 }
2408 } else if (
2409 ( ( po_buf_match( buf[0], " LDA #*", v1 ) || po_buf_match( buf[0], " CLRA") ) && po_buf_match( buf[1], " STA *", v2 ) && po_buf_match( buf[2], " STA *", v3 ) ) ||
2410 ( ( po_buf_match( buf[0], " LDB #*", v1 ) || po_buf_match( buf[0], " CLRB") ) && po_buf_match( buf[1], " STB *", v2 ) && po_buf_match( buf[2], " STB *", v3 ) ) ||
2411 ( po_buf_match( buf[0], " LDD #*", v1 ) && po_buf_match( buf[1], " STD *", v2 ) && po_buf_match( buf[1], " STD *", v3 ) )
2412 ) {
2413
2414 char * realVarName = strdup( v2->str );
2415 char * c = strstr( realVarName, "+" );
2416 if ( c ) {
2417 *c = 0;
2418 }
2419 c = strstr( realVarName, "<(" );
2420 if ( c ) {
2421 strcopy( c, c+2 );
2422 }
2423 c = strstr( realVarName, ")" );
2424 if ( c ) {
2425 *c = 0;
2426 }
2427
2428 // printf(" RULE #2 for [%s]\n", realVarName );
2429
2430 UnusedSymbol * tmp = currentlyUnusedSymbols;
2431 while( tmp ) {
2432 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2433 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2434 // printf(" > found!\n" );
2435 break;
2436 }
2437 tmp = tmp->next;
2438 }
2439 // printf( "\n" );
2440 if ( tmp ) {
2441 // printf(" APPLIED #2\n");
2442 // optim( buf[0], RULE "unused temporary", NULL );
2443 optim( buf[1], RULE "unused temporary", NULL );
2444 ++_environment->removedAssemblyLines;
2445 ++_environment->removedAssemblyLines;
2446 }
2447 } else if (
2448 po_buf_match( buf[0], " DEC*", v1 ) &&
2449 po_buf_match( buf[1], "_*", v4 ) &&
2450 po_buf_match( buf[2], " ST* *", v3, v2 ) &&
2451 (po_buf_cmp( v1, v3 ) == 0)
2452 ) {
2453
2454 char * realVarName = strdup( v2->str );
2455 char * c = strstr( realVarName, "+" );
2456 if ( c ) {
2457 *c = 0;
2458 }
2459 c = strstr( realVarName, "<(" );
2460 if ( c ) {
2461 strcopy( c, c+2 );
2462 }
2463 c = strstr( realVarName, ")" );
2464 if ( c ) {
2465 *c = 0;
2466 }
2467
2468 // printf(" RULE #2 for [%s]\n", realVarName );
2469
2470 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2471 while( tmp ) {
2472 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2473 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2474 // printf(" > found!\n" );
2475 break;
2476 }
2477 tmp = tmp->next;
2478 }
2479 // printf( "\n" );
2480 if ( tmp ) {
2481 // printf(" APPLIED #2\n");
2482 // optim( buf[0], RULE "unused temporary", NULL );
2483 optim( buf[2], RULE "unused temporary", "\tTST%s", v1->str );
2484 ++_environment->removedAssemblyLines;
2485 }
2486
2487 } else if (
2488 ( ( po_buf_match( buf[0], " LDA #*", v1 ) || po_buf_match( buf[0], " CLRA") ) && po_buf_match( buf[1], " STA *", v2 ) && po_buf_match( buf[2], " STD *", v3 ) ) ||
2489 ( ( po_buf_match( buf[0], " LDB #*", v1 ) || po_buf_match( buf[0], " CLRB") ) && po_buf_match( buf[1], " STB *", v2 ) && po_buf_match( buf[2], " STD *", v3 ) )
2490 ) {
2491
2492 char * realVarName = strdup( v2->str );
2493 char * c = strstr( realVarName, "+" );
2494 if ( c ) {
2495 *c = 0;
2496 }
2497 c = strstr( realVarName, "<(" );
2498 if ( c ) {
2499 strcopy( c, c+2 );
2500 }
2501 c = strstr( realVarName, ")" );
2502 if ( c ) {
2503 *c = 0;
2504 }
2505
2506 // printf(" RULE #2 for [%s]\n", realVarName );
2507
2508 UnusedSymbol * tmp = currentlyUnusedSymbols;
2509 while( tmp ) {
2510 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2511 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2512 // printf(" > found!\n" );
2513 break;
2514 }
2515 tmp = tmp->next;
2516 }
2517 // printf( "\n" );
2518 if ( tmp ) {
2519 // printf(" APPLIED #2\n");
2520 // optim( buf[0], RULE "unused temporary bug", NULL );
2521 optim( buf[1], RULE "unused temporary", NULL );
2522 ++_environment->removedAssemblyLines;
2523 ++_environment->removedAssemblyLines;
2524 }
2525 } else if (
2526 po_buf_match( buf[0], " DEC*", v1 ) &&
2527 po_buf_match( buf[1], "_*", v4 ) &&
2528 po_buf_match( buf[2], " ST* *", v3, v2 ) &&
2529 (po_buf_cmp( v1, v3 ) == 0)
2530 ) {
2531
2532 char * realVarName = strdup( v2->str );
2533 char * c = strstr( realVarName, "+" );
2534 if ( c ) {
2535 *c = 0;
2536 }
2537 c = strstr( realVarName, "<(" );
2538 if ( c ) {
2539 strcopy( c, c+2 );
2540 }
2541 c = strstr( realVarName, ")" );
2542 if ( c ) {
2543 *c = 0;
2544 }
2545
2546 // printf(" RULE #2 for [%s]\n", realVarName );
2547
2548 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2549 while( tmp ) {
2550 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2551 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2552 // printf(" > found!\n" );
2553 break;
2554 }
2555 tmp = tmp->next;
2556 }
2557 // printf( "\n" );
2558 if ( tmp ) {
2559 // printf(" APPLIED #2\n");
2560 // optim( buf[0], RULE "unused temporary", NULL );
2561 optim( buf[2], RULE "unused temporary", "\tTST%s", v1->str );
2562 ++_environment->removedAssemblyLines;
2563 }
2564
2565 } else if (
2566 ( ( po_buf_match( buf[0], " LDA #*", v1 ) || po_buf_match( buf[0], " CLRA") ) && po_buf_match( buf[1], " STA *", v2 ) ) ||
2567 ( ( po_buf_match( buf[0], " LDB #*", v1 ) || po_buf_match( buf[0], " CLRB") ) && po_buf_match( buf[1], " STB *", v2 ) ) ||
2568 ( po_buf_match( buf[0], " LDD #*", v1 ) && po_buf_match( buf[1], " STD *", v2 ) )
2569 ) {
2570
2571 char * realVarName = strdup( v2->str );
2572 char * c = strstr( realVarName, "+" );
2573 if ( c ) {
2574 *c = 0;
2575 }
2576 c = strstr( realVarName, "<(" );
2577 if ( c ) {
2578 strcopy( c, c+2 );
2579 }
2580 c = strstr( realVarName, ")" );
2581 if ( c ) {
2582 *c = 0;
2583 }
2584
2585 // printf(" RULE #2 for [%s]\n", realVarName );
2586
2587 UnusedSymbol * tmp = currentlyUnusedSymbols;
2588 while( tmp ) {
2589 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2590 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2591 // printf(" > found!\n" );
2592 break;
2593 }
2594 tmp = tmp->next;
2595 }
2596 // printf( "\n" );
2597 if ( tmp ) {
2598 // printf(" APPLIED #2\n");
2599 // optim( buf[0], RULE "unused temporary bug", NULL );
2600 optim( buf[1], RULE "unused temporary", NULL );
2601 ++_environment->removedAssemblyLines;
2602 ++_environment->removedAssemblyLines;
2603 }
2604 } else if (
2605 po_buf_match( buf[0], " DEC*", v1 ) &&
2606 po_buf_match( buf[1], "_*", v4 ) &&
2607 po_buf_match( buf[2], " ST* *", v3, v2 ) &&
2608 (po_buf_cmp( v1, v3 ) == 0)
2609 ) {
2610
2611 char * realVarName = strdup( v2->str );
2612 char * c = strstr( realVarName, "+" );
2613 if ( c ) {
2614 *c = 0;
2615 }
2616 c = strstr( realVarName, "<(" );
2617 if ( c ) {
2618 strcopy( c, c+2 );
2619 }
2620 c = strstr( realVarName, ")" );
2621 if ( c ) {
2622 *c = 0;
2623 }
2624
2625 // printf(" RULE #2 for [%s]\n", realVarName );
2626
2627 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2628 while( tmp ) {
2629 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2630 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2631 // printf(" > found!\n" );
2632 break;
2633 }
2634 tmp = tmp->next;
2635 }
2636 // printf( "\n" );
2637 if ( tmp ) {
2638 // printf(" APPLIED #2\n");
2639 // optim( buf[0], RULE "unused temporary", NULL );
2640 optim( buf[2], RULE "unused temporary", "\tTST%s", v1->str );
2641 ++_environment->removedAssemblyLines;
2642 }
2643 } else if(
2644 ( po_buf_match( buf[0], " STA *", v2 ) ||
2645 po_buf_match( buf[0], " STB *", v2 ) ||
2646 po_buf_match( buf[0], " STD *", v2 ) ) &&
2647 ( po_buf_match( buf[2], " DIVQ *", v2 ) == NULL && po_buf_match( buf[2], " DIVD *", v2 ) )
2648 )
2649 {
2650
2651 // printf(" RULE #3\n");
2652
2653 char * realVarName = strdup( v2->str );
2654 char * c = strstr( realVarName, "+" );
2655 if ( c ) {
2656 *c = 0;
2657 }
2658 c = strstr( realVarName, "<(" );
2659 if ( c ) {
2660 strcopy( c, c+2 );
2661 }
2662 c = strstr( realVarName, ")" );
2663 if ( c ) {
2664 *c = 0;
2665 }
2666
2667 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2668 while( tmp ) {
2669 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2670 break;
2671 }
2672 tmp = tmp->next;
2673 }
2674 if ( tmp ) {
2675 // printf(" APPLIED #3\n");
2676 optim( buf[0], RULE "unused temporary", NULL );
2677 ++_environment->removedAssemblyLines;
2678 }
2679 }
2680
2681 if ( endOfSection ) {
2682 out(fileOptimized, buf[0]);
2683 out(fileOptimized, buf[1]);
2684 out(fileOptimized, buf[2]);
2685 out(fileOptimized, buf[3]);
2686 out(fileOptimized, buf[4]);
2687 break;
2688 }
2689
2690 // if ( po_buf_match( buf[1], " ; VSP" ) ) {
2691 // out(fileOptimized, buf[0]);
2692 // break;
2693 // }
2694
2695 }
2696
2697 vspPointer = ftell( fileAsm );
2698
2699 // printf( "vspPointer = %d\n", vspPointer );
2700
2701 currentlyUnusedSymbols = NULL;
2702 currentlyUnusedSymbolsQ = NULL;
2703
2704 }
2705
2706 }
2707
2708 fseek( fileAsm, vspPointer, SEEK_SET );
2709
2710 while( !feof(fileAsm) ) {
2711
2712 po_buf_fgets( bufLine, fileAsm );
2713
2714 out(fileOptimized, bufLine);
2715
2716 }
2717
2718 (void)fclose(fileAsm);
2719 (void)fclose(fileOptimized);
2720
2721 /* makes our generated file the new asm file */
2722 remove(_environment->asmFileName);
2723 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
2724
2725}
2726
2727static void optim_remove_comments( Environment * _environment ) {
2728
2729 int i;
2730
2731 POBuffer bufLine = TMP_BUF;
2732
2733 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
2734 FILE * fileAsm;
2735 FILE * fileOptimized;
2736
2737 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
2738
2739 fileAsm = fopen( _environment->asmFileName, "rt" );
2740 if(fileAsm == NULL) {
2741 perror(_environment->asmFileName);
2742 exit(-1);
2743 }
2744
2745 fileOptimized = fopen( fileNameOptimized, "wt" );
2746 if(fileOptimized == NULL) {
2747 perror(fileNameOptimized);
2748 exit(-1);
2749 }
2750
2751 while( !feof(fileAsm) ) {
2752
2753 po_buf_fgets( bufLine, fileAsm );
2754
2755 if ( !isAComment( bufLine ) ) {
2756 out( fileOptimized, bufLine );
2757 }
2758
2759 }
2760
2761 (void)fclose(fileAsm);
2762 (void)fclose(fileOptimized);
2763
2764 /* makes our generated file the new asm file */
2765 remove(_environment->asmFileName);
2766 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
2767
2768}
2769
2770/* main entry-point for this service */
2772
2773 // optim_used_temporary( _environment );
2774
2775 // printf("FIRST 1)\n");
2776 optim_remove_unused_temporary( _environment );
2777
2778 // _environment->peepholeOptimizationLimit = 4;
2779
2780 if ( _environment->peepholeOptimizationLimit > 0 ) {
2781 POBuffer buf[LOOK_AHEAD];
2782 int i;
2783
2784 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_new(0);
2785
2786 int optimization_limit_count = _environment->peepholeOptimizationLimit;
2787
2788 do {
2789 while(optim_pass(_environment, buf, PEEPHOLE)&&optimization_limit_count) {
2790 --optimization_limit_count;
2791 };
2792 optim_pass(_environment, buf, DEADVARS);
2793 optim_remove_unused_temporary( _environment );
2794 } while(change&&optimization_limit_count);
2795 optim_pass(_environment, buf, RELOCATION1);
2796 optim_pass(_environment, buf, RELOCATION2);
2797
2798 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_del(buf[i]);
2800 }
2801
2802 // printf("SECOND 2)\n");
2803 optim_remove_unused_temporary( _environment );
2804
2805 if ( _environment->removeComments ) {
2806 optim_remove_comments(_environment);
2807 }
2808
2809}
2810
2811void target_finalize( Environment * _environment ) {
2812
2813 if ( _environment->additionalInfoFile ) {
2814
2815 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
2816 FILE * fileAsm;
2817 FILE * fileListing;
2818 POBuffer bufferAsm = TMP_BUF;
2819 POBuffer bufferListing = TMP_BUF;
2820 POBuffer bufferAddress = TMP_BUF;
2821 POBuffer bufferVersion = TMP_BUF;
2822 POBuffer bufferBytes = TMP_BUF;
2823
2824 int sourceLine = -1;
2825
2826 _environment->currentSourceLineAnalyzed = 0;
2827 _environment->bytesProduced = 0;
2828
2829 adiline0( "A:0" );
2830
2831 fileAsm = fopen( _environment->asmFileName, "rb" );
2832 if(fileAsm == NULL) {
2833 perror(_environment->asmFileName);
2834 exit(-1);
2835 }
2836
2837 fileListing = fopen( _environment->listingFileName, "rb" );
2838 if(fileListing == NULL) {
2839 perror(_environment->listingFileName);
2840 exit(-1);
2841 }
2842
2843 while( !feof(fileAsm) && !feof(fileListing)) {
2844
2845 po_buf_fgets( bufferAsm, fileAsm );
2846 int leftPadding = po_buf_trim( bufferAsm );
2847
2848 if ( isAComment( bufferAsm ) ) {
2849 POBuffer ln = TMP_BUF;
2850 if (po_buf_match( bufferAsm, "; L:*", ln ) ) {
2851 sourceLine = atoi( ln->str );
2852 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
2853 adiline2( "AB:0:%d:%d",
2854 _environment->currentSourceLineAnalyzed, _environment->bytesProduced );
2855 _environment->currentSourceLineAnalyzed = sourceLine;
2856 _environment->bytesProduced = 0;
2857 }
2858 }
2859 continue;
2860 }
2861
2862 *bufferListing->str = 0;
2863 int pos = ftell( fileListing );
2864 while( !feof(fileListing) && (strstr( bufferListing->str, bufferAsm->str ) == NULL) ) {
2865 po_buf_fgets( bufferListing, fileListing );
2866 po_buf_trim( bufferListing );
2867 }
2868
2869 if ( feof(fileListing) ) {
2870 fseek( fileListing, pos, SEEK_SET );
2871 } else {
2872 char * bufferAsmEscaped = strdup( bufferAsm->str );
2873 for( int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
2874 if ( bufferAsmEscaped[i] == ':' ) {
2875 bufferAsmEscaped[i] = 6;
2876 }
2877 if ( bufferAsmEscaped[i] == 9 ) {
2878 bufferAsmEscaped[i] = ' ';
2879 }
2880 }
2881
2882 if ( po_buf_match( bufferListing, "* * *", bufferAddress, bufferBytes, bufferVersion ) ) {
2883 if ( bufferAddress->len == 4 ) {
2884 int i = 0;
2885 for( i=0; i<bufferBytes->len; ++i ) {
2886 if ( !isxdigit(bufferBytes->str[i]) )
2887 break;
2888 }
2889 if ( i<bufferBytes->len ) {
2890
2891 } else {
2892 _environment->bytesProduced += bufferBytes->len >> 1;
2893 }
2894 }
2895 }
2896 adiline4( "AL:0:%d:%*s%s",
2897 _environment->currentSourceLineAnalyzed, leftPadding, "", bufferAsmEscaped );
2898 }
2899
2900 }
2901
2902 if ( _environment->currentSourceLineAnalyzed ) {
2903 adiline1( "AF:0:%d",
2904 _environment->bytesProduced );
2905 }
2906
2907 (void)fclose(fileListing);
2908 (void)fclose(fileAsm);
2909
2910 }
2911
2912}
char * get_temporary_filename(Environment *_environment)
#define DO_DIRECT_PAGE
Definition _optimizer.c:89
#define DO_INLINE
Definition _optimizer.c:90
struct _UnusedSymbol UnusedSymbol
int size
Definition _optimizer.c:678
struct @110344003176124301103124235173106120065272160135::var * tab
void target_finalize(Environment *_environment)
void target_peephole_optimizer(Environment *_environment)
struct var * vars_get(POBuffer _name)
Definition _optimizer.c:702
char * name
Definition _optimizer.c:672
#define ALLOW_UNSAFE
Definition _optimizer.c:86
int page0_max
Definition _optimizer.c:686
#define DO_UNREAD
Definition _optimizer.c:91
char * init
Definition _optimizer.c:682
int nb_rd
Definition _optimizer.c:679
#define NO_DP
Definition _optimizer.c:674
#define NO_INLINE
Definition _optimizer.c:675
int nb_wr
Definition _optimizer.c:680
#define DIRECT_PAGE
Definition _optimizer.c:84
#define RULE
Definition _optimizer.c:144
int flags
Definition _optimizer.c:677
#define NO_REMOVE
Definition _optimizer.c:676
int isAComment(POBuffer buf)
Definition _optimizer.c:109
int capacity
Definition _optimizer.c:684
#define KEEP_COMMENTS
Definition _optimizer.c:87
int offset
Definition _optimizer.c:681
#define LOOK_AHEAD
Definition _optimizer.c:85
int bank_read
POBuffer po_buf_match(POBuffer _buf, const char *_pattern,...)
Definition _optimizer.c:271
POBuffer po_buf_new(int size)
Definition _optimizer.c:62
POBuffer po_buf_printf(POBuffer buf, const char *fmt,...)
Definition _optimizer.c:129
int po_buf_strcmp(POBuffer _s, POBuffer _t)
Definition _optimizer.c:251
POBuffer po_buf_cpy(POBuffer buf, char *string)
Definition _optimizer.c:94
POBuffer po_buf_del(POBuffer buf)
Definition _optimizer.c:49
POBuffer po_buf_add(POBuffer buf, char c)
Definition _optimizer.c:100
int po_buf_trim(POBuffer buf)
Definition _optimizer.c:157
POBuffer po_buf_vprintf(POBuffer buf, const char *fmt, va_list ap)
Definition _optimizer.c:111
POBuffer po_buf_cat(POBuffer buf, char *string)
Definition _optimizer.c:83
int po_buf_cmp(POBuffer a, POBuffer b)
Definition _optimizer.c:152
POBuffer po_buf_fgets(POBuffer buf, FILE *f)
Definition _optimizer.c:138
int currentSourceLineAnalyzed
Definition ugbc.h:3025
char * listingFileName
Definition ugbc.h:2305
FILE * additionalInfoFile
Definition ugbc.h:3330
int peepholeOptimizationLimit
Definition ugbc.h:2370
int removeComments
Definition ugbc.h:3194
int removedAssemblyLines
Definition ugbc.h:3030
int bytesProduced
Definition ugbc.h:3035
char * asmFileName
Definition ugbc.h:2285
VestigialConfig vestigialConfig
Definition ugbc.h:2442
char * str
Definition ugbc.h:293
int len
Definition ugbc.h:294
struct _UnusedSymbol * next
char rchack_cocon_1163
Definition ugbc.h:2034
void * malloc(YYSIZE_T)
void free(void *)
#define adiline4(s, a, b, c, d)
Definition ugbc.h:4202
#define adiline0(s)
Definition ugbc.h:4182
#define MAX_TEMPORARY_STORAGE
Definition ugbc.h:563
#define adiline1(s, a)
Definition ugbc.h:4187
enum _PeepHoleOptimizationKind PeepHoleOptimizationKind
struct _POBuffer * POBuffer
Definition ugbc.h:298
struct _Environment Environment
Structure of compilation environment.
#define adiline3(s, a, b, c)
Definition ugbc.h:4197
#define TMP_BUF_CLR
Definition ugbc.h:5171
#define BUILD_SAFE_MOVE(_environment, source, destination)
Definition ugbc.h:4751
#define TMP_BUF
Definition ugbc.h:5170
@ RELOCATION2
Definition ugbc.h:282
@ DEADVARS
Definition ugbc.h:280
@ RELOCATION1
Definition ugbc.h:281
@ PEEPHOLE
Definition ugbc.h:279
#define adiline2(s, a, b)
Definition ugbc.h:4192
char * strcopy(char *_dest, char *_source)