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], " LDD #0000") || po_buf_match(buf[0], " LDD #$0000") ) {
958 optim(buf[0], RULE "(LDD#0000)->(CLRA, CLRB)", "\tCLRA\n\tCLRB" );
959 }
960
961 if( po_buf_match(buf[0], " LDD #$*", v1)
962 && po_buf_match(buf[1], " LDB #$*", v3, v2)
963 ) {
964 optim(buf[0], RULE "(LDD#,LDB#)->(LDA)", "\tLDA #$%2.2x", (unsigned char)(atoi( v1->str ) >> 8 ) );
965 }
966
967 if( po_buf_match(buf[0], " LDD #$*", v1)
968 && po_buf_match(buf[1], " CLRB")
969 ) {
970 optim(buf[0], RULE "(LDD#,CLRB)->(LDA)", "\tLDA #$%2.2x", (unsigned char)(atoi( v1->str ) >> 8 ) );
971 }
972
973 if( po_buf_match(buf[0], " CLRB", v1)
974 && po_buf_match(buf[1], " LDD")
975 ) {
976 optim(buf[0], RULE "(CLRB,LDD)->(LDD)", NULL );
977 }
978
979 if( po_buf_match(buf[0], " CLRA")
980 && po_buf_match(buf[1], " LDD *", v1)
981 ) {
982 optim(buf[0], RULE "(CLRA,LDD)->(LDD)", NULL );
983 ++_environment->removedAssemblyLines;
984 }
985
986 if( po_buf_match(buf[0], " LDB #$*", v1)
987 && po_buf_match(buf[1], " LDD #$*", v2)
988 ) {
989 optim(buf[0], RULE "(LDB#,LDD#)->(LDD)", NULL );
990 ++_environment->removedAssemblyLines;
991 }
992
993 if( po_buf_match(buf[0], " B* *", v1, v2)
994 && ( po_buf_match(buf[1], " DECB" ) || po_buf_match(buf[1], " INCB" ) )
995 && po_buf_match(buf[3], " *", v5)
996 && po_buf_match(buf[4], " IF" )
997 && po_buf_match(buf[5], " LBEQ *", v3)
998 && po_buf_match(buf[6], " ELSE" )
999 && po_buf_match(buf[7], " BEQ *", v4)
1000 && po_buf_match(buf[8], " ENDIF" )
1001 && ( strcmp(v5->str, "ANDB" ) != 0 && strcmp(v5->str, "ORB" ) != 0 && strcmp(v5->str, "EORB" ) != 0 )
1002 ) {
1003
1004 int inversed = 0;
1005
1006 if ( strstr(buf[1]->str, "DECB") ) {
1007 if (strcmp(v5->str, "TSTB") == 0) {
1008 inversed = 1;
1009 } if (strstr(buf[3]->str, "CMPB #$ff")) {
1010 inversed = 1;
1011 } else if ( strstr(v5->str, "COMB") ) {
1012 inversed = 1;
1013 }
1014 } else if ( strstr(buf[1]->str, "INCB") ) {
1015 if (strcmp(v5->str, "TSTB") == 0) {
1016 inversed = 1;
1017 } if (strstr(buf[3]->str, "CMPB #$00")) {
1018 inversed = 1;
1019 } if (strstr(buf[3]->str, "STB")) {
1020 inversed = 1;
1021 } else if ( strstr(v5->str, "COMB") ) {
1022
1023 }
1024 }
1025
1026 optim(buf[0], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1027 optim(buf[1], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1028 optim(buf[2], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1029 optim(buf[3], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", NULL );
1030
1031 if ( inversed ) {
1032 char conditional[4];
1033 if ( strcmp( v1->str, "CC") == 0 ) {
1034 strcopy( conditional, "CS" );
1035 }
1036 else if ( strcmp( v1->str, "CS" ) == 0 ) {
1037 strcopy( conditional, "CC" );
1038 } else if ( strcmp( v1->str, "EQ" ) == 0 ) {
1039 strcopy( conditional, "NE" );
1040 }
1041 else if ( strcmp( v1->str, "GE" ) == 0 ) {
1042 strcopy( conditional, "LT" );
1043 }
1044 else if ( strcmp( v1->str, "GT" ) == 0 ) {
1045 strcopy( conditional, "LE" );
1046 }
1047 else if ( strcmp( v1->str, "HI" ) == 0 ) {
1048 strcopy( conditional, "LS" );
1049 }
1050 else if ( strcmp( v1->str, "HS" ) == 0 ) {
1051 strcopy( conditional, "LO" );
1052 }
1053 else if ( strcmp( v1->str, "LE" ) == 0 ) {
1054 strcopy( conditional, "GT" );
1055 }
1056 else if ( strcmp( v1->str, "LO" ) == 0 ) {
1057 strcopy( conditional, "HS" );
1058 }
1059 else if ( strcmp( v1->str, "LS" ) == 0 ) {
1060 strcopy( conditional, "HI" );
1061 }
1062 else if ( strcmp( v1->str, "LT" ) == 0 ) {
1063 strcopy( conditional, "GE" );
1064 }
1065 else if ( strcmp( v1->str, "MI" ) == 0 ) {
1066 strcopy( conditional, "PL" );
1067 }
1068 else if ( strcmp( v1->str, "NE" ) == 0 ) {
1069 strcopy( conditional, "EQ" );
1070 }
1071 else if ( strcmp( v1->str, "PL" ) == 0 ) {
1072 strcopy( conditional, "MI" );
1073 }
1074 else if ( strcmp( v1->str, "RA" ) == 0 ) {
1075 strcopy( conditional, "RA" );
1076 }
1077 else if ( strcmp( v1->str, "RN" ) == 0 ) {
1078 strcopy( conditional, "RN" );
1079 }
1080 else if ( strcmp( v1->str, "VC" ) == 0 ) {
1081 strcopy( conditional, "VS" );
1082 }
1083 else if ( strcmp( v1->str, "VS" ) == 0 ) {
1084 strcopy( conditional, "VC" );
1085 }
1086 else {
1087 strcopy( conditional, v1->str );
1088 }
1089
1090 optim(buf[5], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", " LB%s %s", conditional, v3->str );
1091 optim(buf[7], RULE "(B?,DECB,TSTB/STB,[L]B)->([L]B)", " B%s %s", conditional, v4->str );
1092 } else {
1093 optim(buf[5], RULE "(B,DECB,TSTB/STB,[L]B)->([L]B)", " LB%s %s", v1->str, v3->str );
1094 optim(buf[7], RULE "(B?,DECB,TSTB/STB,[L]B)->([L]B)", " B%s %s", v1->str, v4->str );
1095 }
1096 ++_environment->removedAssemblyLines;
1097 ++_environment->removedAssemblyLines;
1098 ++_environment->removedAssemblyLines;
1099 ++_environment->removedAssemblyLines;
1100 }
1101
1102 if( po_buf_match(buf[0], " CLRA")
1103 && po_buf_match(buf[1], " LDB *", v1)
1104 && po_buf_match(buf[2], " STD *", v2)
1105 && po_buf_match(buf[3], " LDD *", v3)
1106 && po_buf_match(buf[4], " ADDD *", v4)
1107 && po_buf_match(buf[5], " STD *", v5)
1108 ) {
1109 optim(buf[0], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " LDX %s", v3->str );
1110 optim(buf[1], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " LDB %s", v1->str );
1111 optim(buf[2], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " ABX" );
1112 optim(buf[3], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", " STX %s", v5->str );
1113 optim(buf[4], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", NULL );
1114 optim(buf[5], RULE "(CLRA,LDB,STD,LDD,ADD,STD)->(CLRA,LDB)", NULL );
1115 ++_environment->removedAssemblyLines;
1116 ++_environment->removedAssemblyLines;
1117 }
1118
1119// 55EF 4F CLRA
1120// 55F0 F633AA LDB _Ttmp477
1121// 55F3 FD61AC STD _Ttmp553
1122// 55F6 FC61AA LDD _Ttmp552
1123// 55F9 F361AC ADDD _Ttmp553
1124// 55FC FD618C STD _Ttmp296
1125
1126
1127// 55F6 FC61AA LDX _Ttmp552
1128// 55F0 F633AA LDB _Ttmp477
1129// 55F3 FD61AC ABX
1130// 55FC FD618C STX _Ttmp296
1131
1132}
1133
1134/* check if POBuffer matches any of xxyy (used for LDD #$xxyy op) */
1135static POBuffer chkLDD(POBuffer buf, char *xxyy, POBuffer value) {
1136 return po_buf_match( buf, " LDD #$*", value) &&
1137 value->len==4 &&
1138 (xxyy[0]=='-' || xxyy[0]==value->str[0]) &&
1139 (xxyy[1]=='-' || xxyy[1]==value->str[1]) &&
1140 (xxyy[2]=='-' || xxyy[2]==value->str[2]) &&
1141 (xxyy[3]=='-' || xxyy[3]==value->str[3]) ? buf : NULL;
1142}
1143
1144/* can this opcode make A non zero */
1145static int can_nzA(POBuffer buf) {
1146 char *s;
1147
1148 for(s = buf->str; !_eol(*s) && *s!=','; ++s);
1149
1150 if(!po_buf_match(buf, " ")) return 1;
1151 if(po_buf_match(buf, " ADDA ")) return 1;
1152 if(po_buf_match(buf, " ADDD ")) return 1;
1153 if(po_buf_match(buf, " BSR ")) return 1;
1154 if(po_buf_match(buf, " COMA")) return 1;
1155 if(po_buf_match(buf, " DECA")) return 1;
1156 if(po_buf_match(buf, " EORA ")) return 1;
1157 if(po_buf_match(buf, " EXG ")) return 1;
1158 if(po_buf_match(buf, " INCA")) return 1;
1159 if(po_buf_match(buf, " JSR ")) return 1;
1160 if(po_buf_match(buf, " LDA ")) return 1;
1161 if(po_buf_match(buf, " LDD ")) return 1;
1162 if(po_buf_match(buf, " ORA ")) return 1;
1163 if(po_buf_match(buf, " PULS ")) return 1;
1164 if(po_buf_match(buf, " PULU ")) return 1;
1165 if(po_buf_match(buf, " ROLA")) return 1;
1166 if(po_buf_match(buf, " RORA")) return 1;
1167 if(po_buf_match(buf, " RTI")) return 1;
1168 if(po_buf_match(buf, " RTS")) return 1;
1169 if(po_buf_match(buf, " SBCA ")) return 1;
1170 if(po_buf_match(buf, " SEX")) return 1;
1171 if(po_buf_match(buf, " SUBA ")) return 1;
1172 if(po_buf_match(buf, " SUBD ")) return 1;
1173 if(po_buf_match(buf, " TFR ") && s[0]==',' && (s[1]=='A' || s[1]=='D')) return 1;
1174
1175 return 0;
1176}
1177
1178/* can this opcode make B non zero */
1179static int can_nzB(POBuffer buf) {
1180 char *s;
1181
1182 for(s = buf->str; !_eol(*s) && *s!=','; ++s);
1183
1184 if(!po_buf_match(buf, " ")) return 1;
1185 if(po_buf_match(buf, " ADDB ")) return 1;
1186 if(po_buf_match(buf, " ADDD ")) return 1;
1187 if(po_buf_match(buf, " BSR ")) return 1;
1188 if(po_buf_match(buf, " COMB")) return 1;
1189 if(po_buf_match(buf, " DECB")) return 1;
1190 if(po_buf_match(buf, " EORB ")) return 1;
1191 if(po_buf_match(buf, " EXG ")) return 1;
1192 if(po_buf_match(buf, " INCB")) return 1;
1193 if(po_buf_match(buf, " JSR ")) return 1;
1194 if(po_buf_match(buf, " LDB ")) return 1;
1195 if(po_buf_match(buf, " LDD ")) return 1;
1196 if(po_buf_match(buf, " ORB ")) return 1;
1197 if(po_buf_match(buf, " PULS ")) return 1;
1198 if(po_buf_match(buf, " PULU ")) return 1;
1199 if(po_buf_match(buf, " ROLB")) return 1;
1200 if(po_buf_match(buf, " RORB")) return 1;
1201 if(po_buf_match(buf, " RTI")) return 1;
1202 if(po_buf_match(buf, " RTS")) return 1;
1203 if(po_buf_match(buf, " SBCB ")) return 1;
1204 if(po_buf_match(buf, " SUBB ")) return 1;
1205 if(po_buf_match(buf, " SUBD ")) return 1;
1206 if(po_buf_match(buf, " TFR ") && s[0]==',' && (s[1]=='B' || s[1]=='D')) return 1;
1207
1208 return 0;
1209}
1210
1211/* optimizations related to A or B being zero */
1212static void optim_zAB(Environment * _environment, POBuffer buf[LOOK_AHEAD], int *zA, int *zB) {
1213 POBuffer v1 = TMP_BUF;
1214 POBuffer v2 = TMP_BUF;
1215 POBuffer v3 = TMP_BUF;
1216
1217 int unsafe = ALLOW_UNSAFE;
1218
1219 if(*zA) {
1220 if (po_buf_match( buf[0], " CLRA")) {
1221 optim( buf[0], RULE "[A=0](CLRA)->()", NULL);
1222 ++_environment->removedAssemblyLines;
1223 } else if (po_buf_match( buf[0], " LDA #$ff")) {
1224 optim( buf[0], RULE "[A=0](LDA#ff)->(DECA)", "\tDECA");
1225 *zA = 0;
1226 } else if ( po_buf_match(buf[0], " LDA #$01")) {
1227 optim( buf[0], RULE "[A=0](LDA#1)->(INCA)", "\tINCA");
1228 *zA = 0;
1229 // } else if ( chkLDD( buf[0], "00--", v1)) {
1230 // optim(buf[0], RULE "[A=0](LDD#00xx)->(LDB#xx)", "\tLDB #$%c%c", v1->str[2], v1->str[3]);
1231 // *zB = 0;
1232 } else if (po_buf_match( buf[0], " TFR A,B")) {
1233 optim( buf[0], RULE "[A=0](TAB)->(CLRB)", "\tCLRB");
1234 *zB = 1;
1235 } else if (peephole_pass>2
1236 && po_buf_match( buf[0], " STA *", v1)
1237 && po_buf_match( buf[1], " LDB *", v2)
1238 && po_buf_strcmp(v1,v2)==0) {
1239 optim(buf[1], RULE "[A=0](STA*,LDB*)->(CLRB)", "\tCLRB");
1240 } else if (*zB
1241 && po_buf_match(buf[0], " ADDD *", v1)) {
1242 optim(buf[0], RULE "[D=0](ADD)->(LDD)", "\tLDD %s", v1->str);
1243 } else if (*zB
1244 && po_buf_match(buf[0], " STD _Ttmp*", v1)
1245 && po_buf_match(buf[1], " LDX *", v2)
1246 && po_buf_match(buf[2], " CMPX _Ttmp*", v3)
1247 && po_buf_strcmp(v1, v3)==0) {
1248 if(unsafe) {
1249 optim(buf[0], "(unsafe, presumed dead)", NULL);
1250 ++_environment->removedAssemblyLines;
1251 }
1252 optim(buf[2], RULE "[D=0](STD*,LDX,CMPX*)->(LDX)", NULL);
1253 ++_environment->removedAssemblyLines;
1254 } else if(can_nzA(buf[0])) {
1255 *zA = 0;
1256 }
1257 } else if ( chkLDD(buf[0], "00--", v1) || po_buf_match( buf[0], " LDD #0") || po_buf_match( buf[0], " CLRA") ) {
1258 *zA = 1;
1259 }
1260
1261 if(*zB) {
1262 if (po_buf_match( buf[0], " CLRB")) {
1263 optim( buf[0], RULE "[B=0](CLRB)->()", NULL);
1264 ++_environment->removedAssemblyLines;
1265 } else if (po_buf_match( buf[0], " LDB #$ff")) {
1266 optim( buf[0], RULE "[B=0](LDB#ff)->(DECB)", "\tDECB");
1267 *zB = 0;
1268 } else if (po_buf_match( buf[0], " LDB #$01")) {
1269 optim( buf[0], RULE "[B=0](LDB#1)->(INCB)", "\tINCB");
1270 *zB = 0;
1271 } else if ( chkLDD( buf[0], "--00", v1) ) {
1272 optim( buf[0], RULE "[B=0](LDB#xx00)->(LDA#xx)", "\tLDA #$%c%c", v1->str[0], v1->str[1]);
1273 *zA = 0;
1274 } else if (po_buf_match( buf[0], " TFR B,A")) {
1275 optim( buf[0], RULE "[B=0](TBA)->(CLRA)", "\tCLRA");
1276 *zA = 1;
1277 } else if(can_nzB(buf[0])) {
1278 *zB = 0;
1279 }
1280 } else if ( chkLDD(buf[0], "--00", v1) || po_buf_match( buf[0], " LDD #0") || po_buf_match( buf[0], " CLRB") ) {
1281 *zB = 1;
1282 }
1283
1284 if(!*zA
1285 && po_buf_match( buf[0], " LDB #$*", v1)
1286 && po_buf_match( buf[1], " STB ")
1287 && po_buf_match( buf[2], " CLRA")) {
1288 optim(buf[0], RULE "(LDB#,STB,CLRA)->(LDD#,STB)", "\tLDD #$00%s", v1->str);
1289 optim(buf[2], NULL, NULL);
1290 ++_environment->removedAssemblyLines;
1291 *zA = 0;
1292 }
1293}
1294
1295/* optimizations related to variables */
1296
1297/* variables database */
1298static struct {
1299 struct var {
1300 char *name;
1301#define NO_REORG 1
1302#define NO_DP 2
1303#define NO_INLINE 4
1304#define NO_REMOVE 8
1306 int size;
1309 int offset; /* 0=unchanged, >0 offset to page 0; -1 = candidate for inlining, -2 = inlined, -3 = in ram */
1310 char *init;
1314 int size;
1316} vars;
1317
1318/* clears the database */
1319static void vars_clear(void) {
1320 int i;
1321 for(i=0; i<vars.size; ++i) {
1322 struct var *v = &vars.tab[i];
1323 free(v->name);
1324 if(v->init) free(v->init);
1325 }
1326 vars.size = 0;
1327 vars.page0_max = 0;
1328}
1329
1330/* gets (or creates) an entry for a variable from the data-base */
1331struct var *vars_get(POBuffer _name) {
1332 char *name = _name->str;
1333 struct var *ret = NULL;
1334 int i;
1335
1336 char *s=strchr(name,'+');
1337 if(s) *s='\0';
1338
1339 for(i=0; i<vars.size ; ++i) {
1340 if(strcmp(vars.tab[i].name, name)==0) {
1341 ret = &vars.tab[i];
1342 }
1343 }
1344 if(ret == NULL) {
1345 if(vars.size == vars.capacity) {
1346 vars.capacity += 16;
1347 vars.tab = realloc(vars.tab, sizeof(*vars.tab)*vars.capacity);
1348 }
1349 ret = &vars.tab[vars.size++];
1350 ret->name = strdup(name);
1351 ret->flags = 0;
1352 ret->size = 0;
1353 ret->nb_rd = 0;
1354 ret->nb_wr = 0;
1355 ret->offset = 0;
1356 ret->init = NULL;
1357 }
1358 if(s) *s='+';
1359
1360 return ret;
1361}
1362
1363/* look for variable uses and collect data about he variables */
1364static void vars_scan(POBuffer buf[LOOK_AHEAD]) {
1365 POBuffer tmp = TMP_BUF;
1366 POBuffer arg = TMP_BUF;
1367 POBuffer arg2 = TMP_BUF;
1368
1369 // if( po_buf_match( buf[0], " * _*+", NULL, buf) ) {
1370 // struct var *v = vars_get(buf);
1371 // v->flags |= NO_INLINE;
1372 // }
1373
1374 if( po_buf_match( buf[0], " * #(*+1)", NULL, arg)
1375 || po_buf_match( buf[0], " * [*]", NULL, arg)
1376 || po_buf_match( buf[0], " * <*", NULL, arg)
1377 || po_buf_match( buf[0], " * #*", NULL, arg) ) {
1378 if(vars_ok(arg)) {
1379 struct var *v = vars_get(arg);
1380 v->flags |= NO_REMOVE/*|NO_DP*/;
1381 v->nb_rd++;
1382 }
1383 }
1384
1385 if( po_buf_match( buf[0], " LDX #*", arg)
1386 && po_buf_match( buf[1], " JSR BANKREAD1" )
1387 ) if(vars_ok(arg)) {
1388 struct var *v = vars_get(arg);
1389 v->bank_read = 1;
1390 }
1391
1392 if( po_buf_match( buf[0], " CLR *", arg)
1393 || po_buf_match( buf[0], " ST* *", tmp, arg) ) if(vars_ok(arg)) {
1394 struct var *v = vars_get(arg);
1395 v->nb_wr++;
1396 }
1397
1398 if (po_buf_match( buf[0], " ADD* *", NULL, arg)
1399 || po_buf_match( buf[0], " ADC* *", NULL, arg)
1400 || po_buf_match( buf[0], " AND* *", NULL, arg)
1401 || po_buf_match( buf[0], " CMP* *", NULL, arg)
1402 || po_buf_match( buf[0], " EOR* *", NULL, arg)
1403 || po_buf_match( buf[0], " LD* *", NULL, arg)
1404 || po_buf_match( buf[0], " OR* *", NULL, arg)
1405 || po_buf_match( buf[0], " SBC* *", NULL, arg)
1406 || po_buf_match( buf[0], " SUB* *", NULL, arg)
1407
1408 || po_buf_match( buf[0], " ADD* <*", NULL, arg)
1409 || po_buf_match( buf[0], " ADC* <*", NULL, arg)
1410 || po_buf_match( buf[0], " AND* <*", NULL, arg)
1411 || po_buf_match( buf[0], " CMP* <*", NULL, arg)
1412 || po_buf_match( buf[0], " EOR* <*", NULL, arg)
1413 || po_buf_match( buf[0], " LD* <*", NULL, arg)
1414 || po_buf_match( buf[0], " OR* <*", NULL, arg)
1415 || po_buf_match( buf[0], " SBC* <*", NULL, arg)
1416 || po_buf_match( buf[0], " SUB* <*", NULL, arg)
1417 ) if(vars_ok(arg)) {
1418 struct var *v = vars_get(arg);
1419 v->nb_rd++;
1420 }
1421 if(
1422 po_buf_match( buf[0], " ASL *", arg)
1423 || po_buf_match( buf[0], " ASR *", arg)
1424 || po_buf_match( buf[0], " COM *", arg)
1425 || po_buf_match( buf[0], " DEC *", arg)
1426 || po_buf_match( buf[0], " INC *", arg)
1427 || po_buf_match( buf[0], " LSL *", arg)
1428 || po_buf_match( buf[0], " LSR *", arg)
1429 || po_buf_match( buf[0], " ROL *", arg)
1430 || po_buf_match( buf[0], " ROR *", arg)
1431 || po_buf_match( buf[0], " TST *", arg)
1432
1433 || po_buf_match( buf[0], " ASL <*", arg)
1434 || po_buf_match( buf[0], " ASR <*", arg)
1435 || po_buf_match( buf[0], " COM <*", arg)
1436 || po_buf_match( buf[0], " DEC <*", arg)
1437 || po_buf_match( buf[0], " INC <*", arg)
1438 || po_buf_match( buf[0], " LSL <*", arg)
1439 || po_buf_match( buf[0], " LSR <*", arg)
1440 || po_buf_match( buf[0], " ROL <*", arg)
1441 || po_buf_match( buf[0], " ROR <*", arg)
1442 || po_buf_match( buf[0], " TST< *", arg)
1443
1444 ) if(vars_ok(arg)) {
1445 struct var *v = vars_get(arg);
1446 v->nb_wr++;
1447 v->nb_rd++;
1448 }
1449 if( po_buf_match(buf[0], " * *", tmp, arg)
1450 || po_buf_match(buf[0], " * [*]", tmp, arg) ) if(vars_ok(arg)) {
1451 struct var *v = vars_get(arg);
1452 if ( v->offset != -3 ) {
1453 v->offset = -1; /* candidate for inlining */
1454 }
1455 }
1456
1457 if( po_buf_match( buf[0], "* rzb *", tmp, arg) && vars_ok(tmp)) {
1458 struct var *v = vars_get(tmp);
1459 v->size = atoi(arg->str);
1460 v->init = strdup("1-1");
1461 }
1462
1463 if( po_buf_match(buf[0], "* fcb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
1464 struct var *v = vars_get(tmp);
1465 v->size = 1;
1466 v->init = strdup(isZero(arg->str) ? "1-1" : arg->str);
1467 }
1468
1469 if( po_buf_match(buf[0], "* fdb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
1470 struct var *v = vars_get(tmp);
1471 v->size = 2;
1472 v->init = strdup(arg->str);
1473 }
1474
1475 if(
1476 po_buf_match(buf[0], " * equ *+*", tmp, arg2, arg) ||
1477 po_buf_match(buf[0], "* equ *+*", tmp, arg2, arg)
1478 ) {
1479 struct var *v = vars_get(arg2);
1480 if ( v ) {
1481 v->nb_rd = 1;
1482 }
1483 struct var *v2 = vars_get(tmp);
1484 if ( v2 ) {
1485 v2->nb_rd = 1;
1486 }
1487 }
1488
1489 /* variable in RAMs are not eligibile to inlining */
1490 if( po_buf_match(buf[0], "* equ $*", tmp, arg) ) {
1491 struct var *v = vars_get(tmp);
1492 if ( v ) {
1493 if ( v->offset == -1 ) {
1494 v->offset = -3;
1495 }
1496 }
1497 }
1498
1499 /* heurstic to find the max used index in direct-page */
1500 if( po_buf_match(buf[0], "* equ $*", tmp, arg)
1501 && arg->len==2
1502 && (*tmp->str!='_' || tmp->str[1]=='T')) {
1503 int v = strtol(arg->str, NULL, 16);
1504 if (v >= vars.page0_max) vars.page0_max = v+2;
1505 }
1506}
1507
1508/* compares two variables according to their access-count */
1509static int vars_cmp(const void *_a, const void *_b) {
1510 const struct var *a = _a;
1511 const struct var *b = _b;
1512
1513 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
1514
1515 return -(diff!=0 ? diff : strcmp(a->name, b->name)); // Ttmp < Tstr
1516}
1517
1518/* decide which variable goes in direct-page, which will be inlined */
1519static void vars_prepare_relocation(void) {
1520 int i;
1521
1522 num_dp = 0;
1523 num_inlined = 0;
1524
1525 qsort(vars.tab, vars.size, sizeof(*vars.tab), vars_cmp);
1526
1527 for(i = 0; i<vars.size; ++i) {
1528 struct var *v = &vars.tab[i];
1529
1530 /* skip over unknown size var */
1531 if(v->size == 0) continue;
1532
1533 /* skip over unread variables */
1534 if(v->nb_rd == 0) continue;
1535
1536 /* flagged as not inline */
1537 if(v->flags & NO_INLINE) v->offset = 0;
1538 if(!DO_INLINE) v->offset = 0;
1539
1540 /* can't inline > 2 bytes */
1541 if(v->offset == -1 && v->size>2) v->offset = 0;
1542
1543 /* check if inlining is good */
1544 if(v->offset == -1) {
1545 /* LDA: imm=2, dp=4, extended=5
1546 LDD: imm=3, dp=5, extended=6 */
1547 int dp_cost = (3+v->size)*(v->nb_rd + v->nb_wr);
1548 int inline_cost = (4+v->size)*(v->nb_rd + v->nb_wr - 1)+(1+v->size);
1549
1550 if( (v->init==NULL || isZero(v->init) || 0==strcmp("1-1", v->init)) && dp_cost < inline_cost ) {
1551 if(DO_DIRECT_PAGE) v->offset = 0;
1552 }
1553 }
1554 if(DO_DIRECT_PAGE
1555 && 0==v->offset
1556 && 0==(v->flags && NO_DP)
1557 && v->size<=4 /* not too big to let room for others */
1558 && vars.page0_max + v->size <= 256
1559 ) {
1560
1561 if ( vars.page0_max == 0xd8 )
1562 ++vars.page0_max;
1563 if ( vars.page0_max == 0xa3 )
1564 ++vars.page0_max;
1565 if ( vars.page0_max == 0xd5 )
1566 ++vars.page0_max;
1567 if ( vars.page0_max == 0xe3 )
1568 ++vars.page0_max;
1569 if ( vars.page0_max == 0xef )
1570 ++vars.page0_max;
1571 while ( vars.page0_max < 0xf0 )
1572 ++vars.page0_max;
1573 if ( vars.page0_max == 0xf0 )
1574 ++vars.page0_max;
1575 if ( vars.page0_max == 0xf1 )
1576 ++vars.page0_max;
1577 if ( vars.page0_max == 0xf2 )
1578 ++vars.page0_max;
1579 if ( vars.page0_max == 0xf6 )
1580 ++vars.page0_max;
1581
1582 v->offset = vars.page0_max;
1583 vars.page0_max += v->size;
1584 }
1585
1586 // printf("%s %d/%d %d %d %d\n", v->name, v->nb_rd, v->nb_wr, v->offset, v->size, vars.page0_max);
1587 }
1588}
1589
1590/* removes unread variables */
1591static void vars_remove(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
1592 POBuffer var = TMP_BUF;
1593 POBuffer op = TMP_BUF;
1594
1595 if(!DO_UNREAD) return;
1596
1597 /* unread */
1598 if(po_buf_match( buf[0], " ST* *", op, var) && vars_ok(var)) {
1599 struct var *v = vars_get(var);
1600 if(v->nb_rd == 0 && v->offset!=-2) {
1601 char *rep = NULL;
1602 v->offset = 0;
1603 if(po_buf_match(buf[1], " IF ") && po_buf_match(buf[2], " LB")) {
1604 if(*op->str=='X') rep = "\tLEAX ,X";
1605 else {
1606 static char tst[8];
1607 sprintf(tst, "\tTST%c", *op->str);
1608 rep = tst;
1609 }
1610 }
1611 optim(buf[0], "unread1", rep != NULL ? "%s" : NULL, rep);
1612 ++_environment->removedAssemblyLines;
1613 }
1614 }
1615
1616 if(po_buf_match( buf[0], " NEG *", var) && vars_ok(var)) {
1617 struct var *v = vars_get(var);
1618 if(v->nb_rd == 0 && v->offset!=-2) {
1619 char *rep = NULL;
1620 v->offset = 0;
1621 if(po_buf_match(buf[1], " IF ") && po_buf_match(buf[2], " LB")) {
1622 if(*op->str=='X') rep = "\tLEAX ,X";
1623 else {
1624 static char tst[8];
1625 sprintf(tst, "\tTST%c", *op->str);
1626 rep = tst;
1627 }
1628 }
1629 optim(buf[0], "unread1", rep != NULL ? "%s" : NULL, rep);
1630 ++_environment->removedAssemblyLines;
1631 }
1632 }
1633
1634 /* remove changed variables */
1635 if(po_buf_match( buf[0], "* rzb ", var)
1636 || po_buf_match( buf[0], "* fcb ", var)
1637 || po_buf_match( buf[0], "* fdb ", var) ) if(vars_ok(var)) {
1638 struct var *v = vars_get(var);
1639 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags & NO_REMOVE) && v->offset!=-2) {
1640 // fprintf( stderr, "[unread2] = %s\n", buf[0]->str );
1641 optim(buf[0], "unread2",NULL);
1642 ++_environment->removedAssemblyLines;
1643 ++num_unread;
1644 }
1645 }
1646}
1647
1648
1649/* performs optimizations related to variables relocation */
1650static void vars_relocate(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
1651 POBuffer REG = TMP_BUF;
1652 POBuffer var = TMP_BUF;
1653 POBuffer op = TMP_BUF;
1654
1655 /* direct page or inlined */
1656 if(po_buf_match( buf[0], " * *", op, var) && vars_ok(var) ) {
1657 struct var *v = vars_get(var);
1658 // fprintf( stderr, " v->offset = %d\n", v->offset );
1659 if(v->offset > 0) {
1660 optim(buf[0], "direct-page1", "\t%s <(%s)", op->str, var->str);
1661 } else if(v->offset == -1 && chg_reg(buf[0], REG)
1662 && ((strchr("DXYU", *REG->str)!=NULL && v->size==2) || v->size==1) ) {
1663 if ( strstr( var->str, "+" ) == NULL && v->bank_read == 0 ) {
1664 v->offset = -2;
1665 v->flags |= NO_REMOVE;
1666 optim(buf[0], "inlined1", "\t%s #%s%s\n%s equ *-%d", op->str,
1667 v->init==NULL ? "*" : v->init,
1668 v->init==NULL ? (v->size==2 ? "" : "&255") : "",
1669 var->str, v->size);
1670 }
1671 }
1672 }
1673
1674 // if(po_buf_match( buf[0], " * [*]", op, var) && vars_ok(var)) {
1675 // struct var *v = vars_get(var);
1676 // if(v->offset > 0) {
1677 // optim(buf[0], "direct-page2", "\t%s [%s+$%04x]", op->str, var->str, DIRECT_PAGE);
1678 // } else if(v->offset == -1 && strstr(var->str,"+$")==NULL) {
1679 // v->offset = -2;
1680 // optim(buf[0], "inlined2", "\t%s >%s\n%s equ *-2", op->str,
1681 // v->init==NULL ? var->str : v->init, var->str);
1682 // }
1683 // }
1684
1685 if(po_buf_match( buf[0], " * #*", op, var) && vars_ok(var) ) {
1686 struct var *v = vars_get(var);
1687 if(v->offset > 0 && strstr(var->str,"+$")==NULL) {
1688 optim(buf[0], "direct-page3", "\t%s #%s+$%04x", op->str, var->str, DIRECT_PAGE);
1689 }
1690 }
1691
1692 /* remove changed variables */
1693 if(po_buf_match( buf[0], "* rzb ", var)
1694 || po_buf_match( buf[0], "* fcb ", var)
1695 || po_buf_match( buf[0], "* fdb ", var) ) if(vars_ok(var)) {
1696 struct var *v = vars_get(var);
1697 if(v->offset > 0) {
1698 optim(buf[0], "direct-page4", "%s equ $%02x", var->str, v->offset);
1699 ++num_dp;
1700 } else if(v->offset == -2 && v->bank_read == 0 ) {
1701 optim(buf[0], "inlined3", NULL);
1702 ++_environment->removedAssemblyLines;
1703 ++num_inlined;
1704 }
1705 }
1706}
1707
1708/* collapse all heading spaces into a single tabulation */
1709static void out(FILE *f, POBuffer _buf) {
1710 char *s = _buf->str;
1711 int tab = 0;
1712 while(*s==' ' || *s=='\t') {tab = 1; ++s;}
1713 if(tab) fputs("\t", f);
1714 fputs(s, f);
1715}
1716
1717/* remove space that is sometimes used in indexing mode and makes the optimized produce bad dcode */
1718static void fixes_indexed_syntax(POBuffer buf) {
1719 char *s = buf->str;
1720
1721 /* not an instruction */
1722 if(!_eq(' ', *s)) return;
1723
1724 /* skip over spaces */
1725 do ++s; while(*s && _eq(' ', *s));
1726
1727 /* comment */
1728 if(*s==';') return;
1729
1730 /* skip over instruction */
1731 while(*s && !_eq(' ', *s)) ++s;
1732 if(!*s) return;
1733
1734 /* skip over spaces */
1735 do ++s; while(*s && _eq(' ', *s));
1736 if(!*s) return;
1737
1738 /* process argment */
1739 do ++s; while(*s && !_eq(' ', *s));
1740 if(!*s) return;
1741
1742 /* space found check if case "LDA 1, X" */
1743 if(s[-1]==',') {
1744 char *t = s;
1745 do ++t; while(*t && _eq(' ', *t));
1746 switch(_toUpper(*t)) {
1747 case 'X': case 'Y': case 'U': case 'S':
1748 /* yes ==> move register after coma */
1749 *s = *t;
1750 *t = ' ';
1751 break;
1752 default:
1753 break;
1754 }
1755 }
1756}
1757
1758/* various kind of optimization */
1759static int optim_pass( Environment * _environment, POBuffer buf[LOOK_AHEAD], PeepHoleOptimizationKind kind) {
1760 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1761 FILE * fileAsm;
1762 FILE * fileOptimized;
1763 int i;
1764 int still_to_go = LOOK_AHEAD;
1765
1766 int line = 0;
1767 int zA = 0, zB = 0;
1768
1769 int sourceLine = -1;
1770
1771 _environment->currentSourceLineAnalyzed = 0;
1772 _environment->removedAssemblyLines = 0;
1773
1774 adiline2( "POP:0:%d:%d", peephole_pass, kind );
1775
1776 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1777
1778 /* prepare for phase */
1779 switch(kind) {
1780 case DEADVARS:
1781 ++peephole_pass;
1782 num_unread = 0;
1783 break;
1784
1785 case RELOCATION1:
1786 ++peephole_pass;
1787 vars_prepare_relocation();
1788 break;
1789
1790 case RELOCATION2:
1791 break;
1792
1793 case PEEPHOLE:
1794 ++peephole_pass;
1795 vars_clear();
1796 break;
1797 }
1798
1799 fileAsm = fopen( _environment->asmFileName, "rt" );
1800 if(fileAsm == NULL) {
1801 perror(_environment->asmFileName);
1802 exit(-1);
1803 }
1804
1805 fileOptimized = fopen( fileNameOptimized, "wt" );
1806 if(fileOptimized == NULL) {
1807 perror(fileNameOptimized);
1808 exit(-1);
1809 }
1810
1811 /* clears our look-ahead buffers */
1812 for(i = 0; i<LOOK_AHEAD; ++i) po_buf_cpy(buf[i], "");
1813
1814 /* global change flag */
1815 change = 0;
1816
1817 while( still_to_go ) {
1818 /* print out oldest POBuffer */
1819 if ( line >= LOOK_AHEAD ) out(fileOptimized, buf[0]);
1820
1821 /* shift the buffers */
1822 for(i=0; i<LOOK_AHEAD-1; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
1823
1824 /* read next line, merging adjacent comments */
1825 if(feof(fileAsm)) {
1826 --still_to_go;
1827 po_buf_cpy(buf[LOOK_AHEAD-1], "");
1828 } else do {
1829 /* read next line */
1830 po_buf_fgets( buf[LOOK_AHEAD-1], fileAsm );
1831 fixes_indexed_syntax(buf[LOOK_AHEAD-1]);
1832 /* merge comment with previous line if we do not overflow the POBuffer */
1833 if(isAComment(buf[LOOK_AHEAD-1])) {
1834 POBuffer ln = TMP_BUF;
1835 if (po_buf_match( buf[LOOK_AHEAD-1], " ; L:*", ln ) ) {
1836 sourceLine = atoi( ln->str );
1837 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
1838 if ( _environment->currentSourceLineAnalyzed ) {
1839 adiline3( "POL:0:%d:%d:%d",
1840 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
1841 }
1842 _environment->currentSourceLineAnalyzed = sourceLine;
1843 _environment->removedAssemblyLines = 0;
1844 }
1845 }
1846 if(KEEP_COMMENTS) po_buf_cat(buf[LOOK_AHEAD-2], buf[LOOK_AHEAD-1]->str);
1847 po_buf_cpy(buf[LOOK_AHEAD-1], "");
1848 } else break;
1849 } while(!feof(fileAsm));
1850
1851 switch(kind) {
1852 case PEEPHOLE:
1853 // fprintf( stderr, "kind = PEEPHOLE buf = [%s]\n", buf[0]->str );
1854 basic_peephole(_environment, buf, zA, zB);
1855 optim_zAB(_environment, buf, &zA, &zB);
1856
1857 // fprintf( stderr, "change = %d buf = [%s]\n", change, buf[0]->str );
1858
1859 /* only look fo variable when no peephole has been performed */
1860 /*if(change == 0)*/ vars_scan(buf);
1861 break;
1862
1863 case DEADVARS:
1864 // fprintf( stderr, "kind = DEADVARS buf = [%s]\n", buf[0]->str );
1865 vars_remove(_environment, buf);
1866 break;
1867
1868 case RELOCATION1:
1869 case RELOCATION2:
1870 // fprintf( stderr, "kind = RELOCATION 1/2 buf = [%s]\n", buf[0]->str );
1871 vars_relocate(_environment, buf);
1872 break;
1873 }
1874
1875 // for(int i=0; i<vars.size; ++i) {
1876 // fprintf( stderr, "%d ) %s (rd = %d, wr = %d)\n", i, vars.tab[i].name, vars.tab[i].nb_rd, vars.tab[i].nb_wr );
1877 // }
1878 // fprintf( stderr, "\n------------------------\n" );
1879
1880 ++line;
1881 }
1882
1883 /* log info at the end of the file */
1884 switch(kind) {
1885 case PEEPHOLE:
1886 fprintf(fileOptimized, "; peephole: pass %d, %d change%s.\n", peephole_pass,
1887 change, change>1 ?"s":"");
1888 break;
1889
1890 case DEADVARS:
1891 fprintf(fileOptimized, "; peephole: pass %d, %d var%s removed.\n", peephole_pass,
1892 num_unread, num_unread>1 ?"s":"");
1893 break;
1894
1895 case RELOCATION2:
1896 fprintf(fileOptimized, "; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
1897 num_dp, num_dp>1 ?"s":"",
1898 num_inlined, num_inlined>1 ? "s":"");
1899 break;
1900
1901 default:
1902 break;
1903 }
1904
1905 (void)fclose(fileAsm);
1906 (void)fclose(fileOptimized);
1907
1908 /* makes our generated file the new asm file */
1909 remove(_environment->asmFileName);
1910 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1911
1912 return change;
1913}
1914
1915typedef struct _UnusedSymbol {
1916
1917 char * realName;
1918
1919 struct _UnusedSymbol * next;
1920
1922
1923static void optim_remove_unused_temporary( Environment * _environment ) {
1924
1925 int i;
1926
1927 POBuffer bufLine = TMP_BUF;
1928 POBuffer v1 = TMP_BUF;
1929 POBuffer v2 = TMP_BUF;
1930 POBuffer v3 = TMP_BUF;
1931 POBuffer v4 = TMP_BUF;
1932 POBuffer v5 = TMP_BUF;
1933 POBuffer v6 = TMP_BUF;
1934 POBuffer buf[5];
1935
1936 for(i=0; i<5; ++i) buf[i] = po_buf_new(0);
1937
1938 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1939 FILE * fileAsm;
1940 FILE * fileOptimized;
1941
1942 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1943
1944 fileAsm = fopen( _environment->asmFileName, "rt" );
1945 if(fileAsm == NULL) {
1946 perror(_environment->asmFileName);
1947 exit(-1);
1948 }
1949
1950 fileOptimized = fopen( fileNameOptimized, "wt" );
1951 if(fileOptimized == NULL) {
1952 perror(fileNameOptimized);
1953 exit(-1);
1954 }
1955
1956 UnusedSymbol * currentlySymbols = NULL;
1957 UnusedSymbol * currentlySymbolsQ = NULL;
1958 UnusedSymbol * currentlyUnusedSymbols = NULL;
1959 UnusedSymbol * currentlyUnusedSymbolsQ = NULL;
1960
1961 int vspPointer = 0;
1962
1963 while( !feof(fileAsm) ) {
1964
1965 po_buf_fgets( bufLine, fileAsm );
1966
1967 // printf( "### %s\n", bufLine->str );
1968
1969 if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
1970 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1971 memset( s, 0, sizeof( UnusedSymbol ) );
1972 s->realName = strdup( v1->str );
1973 s->next = currentlyUnusedSymbols;
1974 currentlyUnusedSymbols = s;
1975
1976 s = malloc( sizeof( UnusedSymbol ) );
1977 memset( s, 0, sizeof( UnusedSymbol ) );
1978 s->realName = strdup( v1->str );
1979 s->next = currentlySymbols;
1980 currentlySymbols = s;
1981 } else if ( po_buf_match( bufLine, " ; Q *", v1 ) ) {
1982 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1983 memset( s, 0, sizeof( UnusedSymbol ) );
1984 s->realName = strdup( v1->str );
1985 s->next = currentlyUnusedSymbolsQ;
1986 currentlyUnusedSymbolsQ = s;
1987
1988 s = malloc( sizeof( UnusedSymbol ) );
1989 memset( s, 0, sizeof( UnusedSymbol ) );
1990 s->realName = strdup( v1->str );
1991 s->next = currentlySymbolsQ;
1992 currentlySymbolsQ = s;
1993 } else if ( po_buf_match( bufLine, " ; VSP" ) ) {
1994
1995 // printf( "SYMBOLS COMPLETE (Q): " );
1996 // UnusedSymbol * s = currentlyUnusedSymbolsQ;
1997 // while( s ) {
1998 // printf( "%s, ", s->realName );
1999 // s = s->next;
2000 // }
2001 // printf( "\n\n" );
2002
2003 fseek( fileAsm, vspPointer, SEEK_SET );
2004
2005 while( !feof(fileAsm) ) {
2006
2007 po_buf_fgets( bufLine, fileAsm );
2008
2009 POBuffer result = po_buf_match(bufLine, "* equ **-1", v1 );
2010 if ( ! result ) result = po_buf_match(bufLine, "* equ **-2", v2, v1 );
2011 if ( ! result ) result = po_buf_match(bufLine, " ADC* [*]", v2, v1 );
2012 if ( ! result ) result = po_buf_match( bufLine, " ADD* [*]", v2, v1);
2013 if ( ! result ) result = po_buf_match( bufLine, " ADC* [*]", v2, v1);
2014 if ( ! result ) result = po_buf_match( bufLine, " AND* [*]", v2, v1);
2015 if ( ! result ) result = po_buf_match( bufLine, " CMP* [*]", v2, v1);
2016 if ( ! result ) result = po_buf_match( bufLine, " EOR* [*]", v2, v1);
2017 if ( ! result ) result = po_buf_match( bufLine, " LD* [*]", v2, v1);
2018 if ( ! result ) result = po_buf_match( bufLine, " OR* [*]", v2, v1);
2019 if ( ! result ) result = po_buf_match( bufLine, " SBC* [*]", v2, v1);
2020 if ( ! result ) result = po_buf_match( bufLine, " ST* [*]", v2, v1);
2021 if ( ! result ) result = po_buf_match( bufLine, " SUB* [*]", v2, v1);
2022 if ( ! result ) result = po_buf_match( bufLine, " ASL [*]", v1);
2023 if ( ! result ) result = po_buf_match( bufLine, " ASR [*]", v1);
2024 if ( ! result ) result = po_buf_match( bufLine, " TST [*]", v1);
2025 if ( ! result ) result = po_buf_match( bufLine, " ADC* *", v2, v1);
2026 if ( ! result ) result = po_buf_match( bufLine, " ADD* *", v2, v1);
2027 if ( ! result ) result = po_buf_match( bufLine, " ADC* *", v2, v1);
2028 if ( ! result ) result = po_buf_match( bufLine, " AND* *", v2, v1);
2029 if ( ! result ) result = po_buf_match( bufLine, " CMP* *", v2, v1);
2030 if ( ! result ) result = po_buf_match( bufLine, " EOR* *", v2, v1);
2031 if ( ! result ) result = po_buf_match( bufLine, " LD* #*", v2, v1);
2032 if ( ! result ) result = po_buf_match( bufLine, " LD* *", 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, " SUB* *", v2, v1);
2037 if ( ! result ) result = po_buf_match( bufLine, " ASL *", v1);
2038 if ( ! result ) result = po_buf_match( bufLine, " ASR *", v1);
2039 if ( ! result ) result = po_buf_match( bufLine, " TST *", v1);
2040 if ( result ) {
2041 char * realVarName = strdup( v1->str );
2042 char * c = strstr( realVarName, "+" );
2043 if ( c ) {
2044 *c = 0;
2045 }
2046 c = strstr( realVarName, "#" );
2047 if ( c ) {
2048 strcopy( c, c+1 );
2049 }
2050 c = strstr( realVarName, "<(" );
2051 if ( c ) {
2052 strcopy( c, c+2 );
2053 }
2054 c = strstr( realVarName, ")" );
2055 if ( c ) {
2056 *c = 0;
2057 }
2058 UnusedSymbol * tmp = currentlyUnusedSymbols;
2059 UnusedSymbol * previous = NULL;
2060 while( tmp ) {
2061 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2062 if ( previous ) {
2063 previous->next = tmp->next;
2064 } else {
2065 currentlyUnusedSymbols = tmp->next;
2066 }
2067 break;
2068 }
2069 previous = tmp;
2070 tmp = tmp->next;
2071 }
2072
2073 tmp = currentlyUnusedSymbolsQ;
2074 previous = NULL;
2075 while( tmp ) {
2076 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2077 if ( previous ) {
2078 previous->next = tmp->next;
2079 } else {
2080 currentlyUnusedSymbolsQ = tmp->next;
2081 }
2082 break;
2083 }
2084 previous = tmp;
2085 tmp = tmp->next;
2086 }
2087 }
2088
2089 if ( po_buf_match( bufLine, " ; VSP" ) ) {
2090 break;
2091 }
2092
2093 }
2094
2095 // printf( "REALLY UNUSED SYMBOLS (Q): " );
2096 // s = currentlyUnusedSymbolsQ;
2097 // while( s ) {
2098 // printf( "%s, ", s->realName );
2099 // s = s->next;
2100 // }
2101 // printf( "\n\n" );
2102
2103 fseek( fileAsm, vspPointer, SEEK_SET );
2104
2105 int line = 0;
2106
2107 po_buf_cpy(buf[0], "");
2108 po_buf_cpy(buf[1], "");
2109 po_buf_cpy(buf[2], "");
2110 po_buf_cpy(buf[3], "");
2111 po_buf_cpy(buf[4], "");
2112
2113 while( !feof(fileAsm) ) {
2114
2115 int endOfSection = 0;
2116
2117 if ( line >= 2 ) out(fileOptimized, buf[0]);
2118 po_buf_cpy(buf[0], buf[1]->str);
2119 po_buf_cpy(buf[1], buf[2]->str);
2120 po_buf_cpy(buf[2], buf[3]->str);
2121 po_buf_cpy(buf[3], buf[4]->str);
2122 po_buf_fgets( buf[4], fileAsm );
2123 while( isAComment( buf[4] ) && !endOfSection && !feof( fileAsm ) ) {
2124 if ( po_buf_match( buf[4], " ; VSP" ) ) {
2125 endOfSection = 1;
2126 }
2127 if(KEEP_COMMENTS) po_buf_cat(buf[3], buf[4]->str);
2128 po_buf_fgets( buf[4], fileAsm );
2129 }
2130 ++line;
2131
2132 // printf("Checking: - - - - - - - - - - -\n");
2133 // printf("1: %s\n", buf[0]->str );
2134 // printf("2: %s\n", buf[1]->str );
2135 // printf("3: %s\n", buf[2]->str );
2136 // printf("- - - - - - - - - - - checking\n");
2137
2138 if (
2139 po_buf_match( buf[0], " ST* *", v1, v2 ) &&
2140 po_buf_match( buf[1], " LD* *", v3, v4 ) &&
2141 po_buf_match( buf[2], " ST* *", v5, v6 ) &&
2142 po_buf_cmp( v2, v4 ) == 0 &&
2143 po_buf_cmp( v3, v5 ) == 0
2144 ) {
2145
2146 // printf(" RULE #1\n");
2147
2148 char * realVarName = strdup( v4->str );
2149 char * c = strstr( realVarName, "+" );
2150 if ( c ) {
2151 *c = 0;
2152 }
2153 c = strstr( realVarName, "<(" );
2154 if ( c ) {
2155 strcopy( c, c+2 );
2156 }
2157 c = strstr( realVarName, ")" );
2158 if ( c ) {
2159 *c = 0;
2160 }
2161
2162 // printf( "realVarName = %s\n", realVarName );
2163
2164 char * realVarName2 = strdup( v6->str );
2165 c = strstr( realVarName2, "+" );
2166 if ( c ) {
2167 *c = 0;
2168 }
2169 c = strstr( realVarName2, "<(" );
2170 if ( c ) {
2171 strcopy( c, c+2 );
2172 }
2173 c = strstr( realVarName2, ")" );
2174 if ( c ) {
2175 *c = 0;
2176 }
2177
2178 // printf( "realVarName2 = %s\n", realVarName2 );
2179
2180 UnusedSymbol * tmp = currentlySymbols;
2181 while( tmp ) {
2182 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2183 break;
2184 }
2185 tmp = tmp->next;
2186 }
2187 UnusedSymbol * tmp2 = currentlySymbolsQ;
2188 while( tmp2 ) {
2189 if ( strcmp( realVarName2, tmp2->realName ) == 0 ) {
2190 break;
2191 }
2192 tmp2 = tmp2->next;
2193 }
2194 UnusedSymbol * tmp3 = currentlySymbols;
2195 while( tmp3 ) {
2196 if ( strcmp( realVarName2, tmp3->realName ) == 0 ) {
2197 break;
2198 }
2199 tmp3 = tmp3->next;
2200 }
2201 if ( tmp && ( tmp2 || tmp3 ) ) {
2202 // printf( "found!\n\n" );
2203 // printf(" APPLIED #1\n");
2204 // optim( buf[0], RULE "unused temporary", NULL );
2205 optim( buf[0], RULE "unused temporary", "\tST%s %s", v1->str, v6->str );
2206 optim( buf[1], RULE "unused temporary", NULL );
2207 optim( buf[2], RULE "unused temporary", NULL );
2208 ++_environment->removedAssemblyLines;
2209 ++_environment->removedAssemblyLines;
2210 }
2211 } else if (
2212 ( ( 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" ) ) ||
2213 ( ( 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" ) )
2214 ) {
2215
2216 char * realVarName = strdup( v2->str );
2217 char * c = strstr( realVarName, "+" );
2218 if ( c ) {
2219 *c = 0;
2220 }
2221 c = strstr( realVarName, "<(" );
2222 if ( c ) {
2223 strcopy( c, c+2 );
2224 }
2225 c = strstr( realVarName, ")" );
2226 if ( c ) {
2227 *c = 0;
2228 }
2229
2230 // printf(" RULE #2 for [%s]\n", realVarName );
2231
2232 UnusedSymbol * tmp = currentlyUnusedSymbols;
2233 while( tmp ) {
2234 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2235 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2236 // printf(" > found!\n" );
2237 break;
2238 }
2239 tmp = tmp->next;
2240 }
2241 // printf( "\n" );
2242 if ( tmp ) {
2243 // printf(" APPLIED #2\n");
2244 optim( buf[1], RULE "unused temporary", NULL );
2245 ++_environment->removedAssemblyLines;
2246 }
2247 } else if (
2248 po_buf_match( buf[0], " STD *", v2 ) &&
2249 po_buf_match( buf[1], " LDD *", v4 ) &&
2250 po_buf_match( buf[2], " ST* *", v5, v6 ) &&
2251 po_buf_cmp( v2, v4 ) == 0 &&
2252 ( strcmp( v5->str, "A" ) == 0 || strcmp( v5->str, "B" ) == 0 )
2253 ) {
2254
2255 // printf(" RULE #1\n");
2256
2257 char * realVarName = strdup( v4->str );
2258 char * c = strstr( realVarName, "+" );
2259 if ( c ) {
2260 *c = 0;
2261 }
2262 c = strstr( realVarName, "<(" );
2263 if ( c ) {
2264 strcopy( c, c+2 );
2265 }
2266 c = strstr( realVarName, ")" );
2267 if ( c ) {
2268 *c = 0;
2269 }
2270
2271 // printf( "realVarName = %s\n", realVarName );
2272
2273 char * realVarName2 = strdup( v6->str );
2274 c = strstr( realVarName2, "+" );
2275 if ( c ) {
2276 *c = 0;
2277 }
2278 c = strstr( realVarName2, "<(" );
2279 if ( c ) {
2280 strcopy( c, c+2 );
2281 }
2282 c = strstr( realVarName2, ")" );
2283 if ( c ) {
2284 *c = 0;
2285 }
2286
2287 // printf( "realVarName2 = %s\n", realVarName2 );
2288
2289 UnusedSymbol * tmp = currentlySymbols;
2290 while( tmp ) {
2291 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2292 break;
2293 }
2294 tmp = tmp->next;
2295 }
2296 UnusedSymbol * tmp2 = currentlySymbolsQ;
2297 while( tmp2 ) {
2298 if ( strcmp( realVarName2, tmp2->realName ) == 0 ) {
2299 break;
2300 }
2301 tmp2 = tmp2->next;
2302 }
2303 UnusedSymbol * tmp3 = currentlySymbols;
2304 while( tmp3 ) {
2305 if ( strcmp( realVarName2, tmp3->realName ) == 0 ) {
2306 break;
2307 }
2308 tmp3 = tmp3->next;
2309 }
2310 if ( tmp && ( tmp2 || tmp3 ) ) {
2311 // printf( "found!\n\n" );
2312 // printf(" APPLIED #1\n");
2313 // optim( buf[0], RULE "unused temporary", NULL );
2314 optim( buf[0], RULE "unused temporary", "\tST%s %s", v5->str, v6->str );
2315 optim( buf[1], RULE "unused temporary", NULL );
2316 optim( buf[2], RULE "unused temporary", NULL );
2317 ++_environment->removedAssemblyLines;
2318 ++_environment->removedAssemblyLines;
2319 }
2320 } else if (
2321 ( ( 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" ) ) ||
2322 ( ( 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" ) )
2323 ) {
2324
2325 char * realVarName = strdup( v2->str );
2326 char * c = strstr( realVarName, "+" );
2327 if ( c ) {
2328 *c = 0;
2329 }
2330 c = strstr( realVarName, "<(" );
2331 if ( c ) {
2332 strcopy( c, c+2 );
2333 }
2334 c = strstr( realVarName, ")" );
2335 if ( c ) {
2336 *c = 0;
2337 }
2338
2339 // printf(" RULE #2 for [%s]\n", realVarName );
2340
2341 UnusedSymbol * tmp = currentlyUnusedSymbols;
2342 while( tmp ) {
2343 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2344 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2345 // printf(" > found!\n" );
2346 break;
2347 }
2348 tmp = tmp->next;
2349 }
2350 // printf( "\n" );
2351 if ( tmp ) {
2352 // printf(" APPLIED #2\n");
2353 optim( buf[1], RULE "unused temporary", NULL );
2354 ++_environment->removedAssemblyLines;
2355 }
2356 } else if (
2357 ( 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" ) ) ) ||
2358 ( 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" ) ) ) ||
2359 ( 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" ) ) )
2360 ) {
2361
2362 // printf(" RULE #1\n");
2363
2364 char * realVarName = strdup( v2->str );
2365 char * c = strstr( realVarName, "+" );
2366 if ( c ) {
2367 *c = 0;
2368 }
2369 c = strstr( realVarName, "<(" );
2370 if ( c ) {
2371 strcopy( c, c+2 );
2372 }
2373 c = strstr( realVarName, ")" );
2374 if ( c ) {
2375 *c = 0;
2376 }
2377
2378 UnusedSymbol * tmp = currentlyUnusedSymbols;
2379 while( tmp ) {
2380 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2381 break;
2382 }
2383 tmp = tmp->next;
2384 }
2385 if ( tmp ) {
2386 // printf(" APPLIED #1\n");
2387 // optim( buf[0], RULE "unused temporary", NULL );
2388 optim( buf[1], RULE "unused temporary", NULL );
2389 ++_environment->removedAssemblyLines;
2390 ++_environment->removedAssemblyLines;
2391 }
2392 } else if (
2393 ( ( 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 ) ) ||
2394 ( ( 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 ) ) ||
2395 ( po_buf_match( buf[0], " LDD #*", v1 ) && po_buf_match( buf[1], " STD *", v2 ) && po_buf_match( buf[1], " STD *", v3 ) )
2396 ) {
2397
2398 char * realVarName = strdup( v2->str );
2399 char * c = strstr( realVarName, "+" );
2400 if ( c ) {
2401 *c = 0;
2402 }
2403 c = strstr( realVarName, "<(" );
2404 if ( c ) {
2405 strcopy( c, c+2 );
2406 }
2407 c = strstr( realVarName, ")" );
2408 if ( c ) {
2409 *c = 0;
2410 }
2411
2412 // printf(" RULE #2 for [%s]\n", realVarName );
2413
2414 UnusedSymbol * tmp = currentlyUnusedSymbols;
2415 while( tmp ) {
2416 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2417 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2418 // printf(" > found!\n" );
2419 break;
2420 }
2421 tmp = tmp->next;
2422 }
2423 // printf( "\n" );
2424 if ( tmp ) {
2425 // printf(" APPLIED #2\n");
2426 // optim( buf[0], RULE "unused temporary", NULL );
2427 optim( buf[1], RULE "unused temporary", NULL );
2428 ++_environment->removedAssemblyLines;
2429 ++_environment->removedAssemblyLines;
2430 }
2431 } else if (
2432 po_buf_match( buf[0], " DEC*", v1 ) &&
2433 po_buf_match( buf[1], "_*", v4 ) &&
2434 po_buf_match( buf[2], " ST* *", v3, v2 ) &&
2435 (po_buf_cmp( v1, v3 ) == 0)
2436 ) {
2437
2438 char * realVarName = strdup( v2->str );
2439 char * c = strstr( realVarName, "+" );
2440 if ( c ) {
2441 *c = 0;
2442 }
2443 c = strstr( realVarName, "<(" );
2444 if ( c ) {
2445 strcopy( c, c+2 );
2446 }
2447 c = strstr( realVarName, ")" );
2448 if ( c ) {
2449 *c = 0;
2450 }
2451
2452 // printf(" RULE #2 for [%s]\n", realVarName );
2453
2454 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2455 while( tmp ) {
2456 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2457 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2458 // printf(" > found!\n" );
2459 break;
2460 }
2461 tmp = tmp->next;
2462 }
2463 // printf( "\n" );
2464 if ( tmp ) {
2465 // printf(" APPLIED #2\n");
2466 // optim( buf[0], RULE "unused temporary", NULL );
2467 optim( buf[2], RULE "unused temporary", "\tTST%s", v1->str );
2468 ++_environment->removedAssemblyLines;
2469 }
2470
2471 } else if (
2472 ( ( 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 ) ) ||
2473 ( ( 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 ) )
2474 ) {
2475
2476 char * realVarName = strdup( v2->str );
2477 char * c = strstr( realVarName, "+" );
2478 if ( c ) {
2479 *c = 0;
2480 }
2481 c = strstr( realVarName, "<(" );
2482 if ( c ) {
2483 strcopy( c, c+2 );
2484 }
2485 c = strstr( realVarName, ")" );
2486 if ( c ) {
2487 *c = 0;
2488 }
2489
2490 // printf(" RULE #2 for [%s]\n", realVarName );
2491
2492 UnusedSymbol * tmp = currentlyUnusedSymbols;
2493 while( tmp ) {
2494 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2495 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2496 // printf(" > found!\n" );
2497 break;
2498 }
2499 tmp = tmp->next;
2500 }
2501 // printf( "\n" );
2502 if ( tmp ) {
2503 // printf(" APPLIED #2\n");
2504 // optim( buf[0], RULE "unused temporary bug", NULL );
2505 optim( buf[1], RULE "unused temporary", NULL );
2506 ++_environment->removedAssemblyLines;
2507 ++_environment->removedAssemblyLines;
2508 }
2509 } else if (
2510 po_buf_match( buf[0], " DEC*", v1 ) &&
2511 po_buf_match( buf[1], "_*", v4 ) &&
2512 po_buf_match( buf[2], " ST* *", v3, v2 ) &&
2513 (po_buf_cmp( v1, v3 ) == 0)
2514 ) {
2515
2516 char * realVarName = strdup( v2->str );
2517 char * c = strstr( realVarName, "+" );
2518 if ( c ) {
2519 *c = 0;
2520 }
2521 c = strstr( realVarName, "<(" );
2522 if ( c ) {
2523 strcopy( c, c+2 );
2524 }
2525 c = strstr( realVarName, ")" );
2526 if ( c ) {
2527 *c = 0;
2528 }
2529
2530 // printf(" RULE #2 for [%s]\n", realVarName );
2531
2532 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2533 while( tmp ) {
2534 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2535 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2536 // printf(" > found!\n" );
2537 break;
2538 }
2539 tmp = tmp->next;
2540 }
2541 // printf( "\n" );
2542 if ( tmp ) {
2543 // printf(" APPLIED #2\n");
2544 // optim( buf[0], RULE "unused temporary", NULL );
2545 optim( buf[2], RULE "unused temporary", "\tTST%s", v1->str );
2546 ++_environment->removedAssemblyLines;
2547 }
2548
2549 } else if (
2550 ( ( po_buf_match( buf[0], " LDA #*", v1 ) || po_buf_match( buf[0], " CLRA") ) && po_buf_match( buf[1], " STA *", v2 ) ) ||
2551 ( ( po_buf_match( buf[0], " LDB #*", v1 ) || po_buf_match( buf[0], " CLRB") ) && po_buf_match( buf[1], " STB *", v2 ) ) ||
2552 ( po_buf_match( buf[0], " LDD #*", v1 ) && po_buf_match( buf[1], " STD *", v2 ) )
2553 ) {
2554
2555 char * realVarName = strdup( v2->str );
2556 char * c = strstr( realVarName, "+" );
2557 if ( c ) {
2558 *c = 0;
2559 }
2560 c = strstr( realVarName, "<(" );
2561 if ( c ) {
2562 strcopy( c, c+2 );
2563 }
2564 c = strstr( realVarName, ")" );
2565 if ( c ) {
2566 *c = 0;
2567 }
2568
2569 // printf(" RULE #2 for [%s]\n", realVarName );
2570
2571 UnusedSymbol * tmp = currentlyUnusedSymbols;
2572 while( tmp ) {
2573 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2574 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2575 // printf(" > found!\n" );
2576 break;
2577 }
2578 tmp = tmp->next;
2579 }
2580 // printf( "\n" );
2581 if ( tmp ) {
2582 // printf(" APPLIED #2\n");
2583 // optim( buf[0], RULE "unused temporary bug", NULL );
2584 optim( buf[1], RULE "unused temporary", NULL );
2585 ++_environment->removedAssemblyLines;
2586 ++_environment->removedAssemblyLines;
2587 }
2588 } else if (
2589 po_buf_match( buf[0], " DEC*", v1 ) &&
2590 po_buf_match( buf[1], "_*", v4 ) &&
2591 po_buf_match( buf[2], " ST* *", v3, v2 ) &&
2592 (po_buf_cmp( v1, v3 ) == 0)
2593 ) {
2594
2595 char * realVarName = strdup( v2->str );
2596 char * c = strstr( realVarName, "+" );
2597 if ( c ) {
2598 *c = 0;
2599 }
2600 c = strstr( realVarName, "<(" );
2601 if ( c ) {
2602 strcopy( c, c+2 );
2603 }
2604 c = strstr( realVarName, ")" );
2605 if ( c ) {
2606 *c = 0;
2607 }
2608
2609 // printf(" RULE #2 for [%s]\n", realVarName );
2610
2611 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2612 while( tmp ) {
2613 // printf(" - compare %s = %s\n", realVarName, tmp->realName );
2614 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2615 // printf(" > found!\n" );
2616 break;
2617 }
2618 tmp = tmp->next;
2619 }
2620 // printf( "\n" );
2621 if ( tmp ) {
2622 // printf(" APPLIED #2\n");
2623 // optim( buf[0], RULE "unused temporary", NULL );
2624 optim( buf[2], RULE "unused temporary", "\tTST%s", v1->str );
2625 ++_environment->removedAssemblyLines;
2626 }
2627 } else if(
2628 po_buf_match( buf[0], " STA *", v2 ) ||
2629 po_buf_match( buf[0], " STB *", v2 ) ||
2630 po_buf_match( buf[0], " STD *", v2 ) )
2631 {
2632
2633 // printf(" RULE #3\n");
2634
2635 char * realVarName = strdup( v2->str );
2636 char * c = strstr( realVarName, "+" );
2637 if ( c ) {
2638 *c = 0;
2639 }
2640 c = strstr( realVarName, "<(" );
2641 if ( c ) {
2642 strcopy( c, c+2 );
2643 }
2644 c = strstr( realVarName, ")" );
2645 if ( c ) {
2646 *c = 0;
2647 }
2648
2649 UnusedSymbol * tmp = currentlyUnusedSymbolsQ;
2650 while( tmp ) {
2651 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
2652 break;
2653 }
2654 tmp = tmp->next;
2655 }
2656 if ( tmp ) {
2657 // printf(" APPLIED #3\n");
2658 optim( buf[0], RULE "unused temporary", NULL );
2659 ++_environment->removedAssemblyLines;
2660 }
2661 }
2662
2663 if ( endOfSection ) {
2664 out(fileOptimized, buf[0]);
2665 out(fileOptimized, buf[1]);
2666 out(fileOptimized, buf[2]);
2667 out(fileOptimized, buf[3]);
2668 out(fileOptimized, buf[4]);
2669 break;
2670 }
2671
2672 // if ( po_buf_match( buf[1], " ; VSP" ) ) {
2673 // out(fileOptimized, buf[0]);
2674 // break;
2675 // }
2676
2677 }
2678
2679 vspPointer = ftell( fileAsm );
2680
2681 // printf( "vspPointer = %d\n", vspPointer );
2682
2683 currentlyUnusedSymbols = NULL;
2684 currentlyUnusedSymbolsQ = NULL;
2685
2686 }
2687
2688 }
2689
2690 fseek( fileAsm, vspPointer, SEEK_SET );
2691
2692 while( !feof(fileAsm) ) {
2693
2694 po_buf_fgets( bufLine, fileAsm );
2695
2696 out(fileOptimized, bufLine);
2697
2698 }
2699
2700 (void)fclose(fileAsm);
2701 (void)fclose(fileOptimized);
2702
2703 /* makes our generated file the new asm file */
2704 remove(_environment->asmFileName);
2705 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
2706
2707}
2708
2709static void optim_remove_comments( Environment * _environment ) {
2710
2711 int i;
2712
2713 POBuffer bufLine = TMP_BUF;
2714
2715 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
2716 FILE * fileAsm;
2717 FILE * fileOptimized;
2718
2719 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
2720
2721 fileAsm = fopen( _environment->asmFileName, "rt" );
2722 if(fileAsm == NULL) {
2723 perror(_environment->asmFileName);
2724 exit(-1);
2725 }
2726
2727 fileOptimized = fopen( fileNameOptimized, "wt" );
2728 if(fileOptimized == NULL) {
2729 perror(fileNameOptimized);
2730 exit(-1);
2731 }
2732
2733 while( !feof(fileAsm) ) {
2734
2735 po_buf_fgets( bufLine, fileAsm );
2736
2737 if ( !isAComment( bufLine ) ) {
2738 out( fileOptimized, bufLine );
2739 }
2740
2741 }
2742
2743 (void)fclose(fileAsm);
2744 (void)fclose(fileOptimized);
2745
2746 /* makes our generated file the new asm file */
2747 remove(_environment->asmFileName);
2748 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
2749
2750}
2751
2752/* main entry-point for this service */
2754
2755 // optim_used_temporary( _environment );
2756
2757 // printf("FIRST 1)\n");
2758 optim_remove_unused_temporary( _environment );
2759
2760 // _environment->peepholeOptimizationLimit = 4;
2761
2762 if ( _environment->peepholeOptimizationLimit > 0 ) {
2763 POBuffer buf[LOOK_AHEAD];
2764 int i;
2765
2766 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_new(0);
2767
2768 int optimization_limit_count = _environment->peepholeOptimizationLimit;
2769
2770 do {
2771 while(optim_pass(_environment, buf, PEEPHOLE)&&optimization_limit_count) {
2772 --optimization_limit_count;
2773 };
2774 optim_pass(_environment, buf, DEADVARS);
2775 optim_remove_unused_temporary( _environment );
2776 } while(change&&optimization_limit_count);
2777 optim_pass(_environment, buf, RELOCATION1);
2778 optim_pass(_environment, buf, RELOCATION2);
2779
2780 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_del(buf[i]);
2782 }
2783
2784 // printf("SECOND 2)\n");
2785 optim_remove_unused_temporary( _environment );
2786
2787 if ( _environment->removeComments ) {
2788 optim_remove_comments(_environment);
2789 }
2790
2791}
2792
2793void target_finalize( Environment * _environment ) {
2794
2795 if ( _environment->additionalInfoFile ) {
2796
2797 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
2798 FILE * fileAsm;
2799 FILE * fileListing;
2800 POBuffer bufferAsm = TMP_BUF;
2801 POBuffer bufferListing = TMP_BUF;
2802 POBuffer bufferAddress = TMP_BUF;
2803 POBuffer bufferVersion = TMP_BUF;
2804 POBuffer bufferBytes = TMP_BUF;
2805
2806 int sourceLine = -1;
2807
2808 _environment->currentSourceLineAnalyzed = 0;
2809 _environment->bytesProduced = 0;
2810
2811 adiline0( "A:0" );
2812
2813 fileAsm = fopen( _environment->asmFileName, "rb" );
2814 if(fileAsm == NULL) {
2815 perror(_environment->asmFileName);
2816 exit(-1);
2817 }
2818
2819 fileListing = fopen( _environment->listingFileName, "rb" );
2820 if(fileListing == NULL) {
2821 perror(_environment->listingFileName);
2822 exit(-1);
2823 }
2824
2825 while( !feof(fileAsm) && !feof(fileListing)) {
2826
2827 po_buf_fgets( bufferAsm, fileAsm );
2828 int leftPadding = po_buf_trim( bufferAsm );
2829
2830 if ( isAComment( bufferAsm ) ) {
2831 POBuffer ln = TMP_BUF;
2832 if (po_buf_match( bufferAsm, "; L:*", ln ) ) {
2833 sourceLine = atoi( ln->str );
2834 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
2835 adiline2( "AB:0:%d:%d",
2836 _environment->currentSourceLineAnalyzed, _environment->bytesProduced );
2837 _environment->currentSourceLineAnalyzed = sourceLine;
2838 _environment->bytesProduced = 0;
2839 }
2840 }
2841 continue;
2842 }
2843
2844 *bufferListing->str = 0;
2845 int pos = ftell( fileListing );
2846 while( !feof(fileListing) && (strstr( bufferListing->str, bufferAsm->str ) == NULL) ) {
2847 po_buf_fgets( bufferListing, fileListing );
2848 po_buf_trim( bufferListing );
2849 }
2850
2851 if ( feof(fileListing) ) {
2852 fseek( fileListing, pos, SEEK_SET );
2853 } else {
2854 char * bufferAsmEscaped = strdup( bufferAsm->str );
2855 for( int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
2856 if ( bufferAsmEscaped[i] == ':' ) {
2857 bufferAsmEscaped[i] = 6;
2858 }
2859 if ( bufferAsmEscaped[i] == 9 ) {
2860 bufferAsmEscaped[i] = ' ';
2861 }
2862 }
2863
2864 if ( po_buf_match( bufferListing, "* * *", bufferAddress, bufferBytes, bufferVersion ) ) {
2865 if ( bufferAddress->len == 4 ) {
2866 int i = 0;
2867 for( i=0; i<bufferBytes->len; ++i ) {
2868 if ( !isxdigit(bufferBytes->str[i]) )
2869 break;
2870 }
2871 if ( i<bufferBytes->len ) {
2872
2873 } else {
2874 _environment->bytesProduced += bufferBytes->len >> 1;
2875 }
2876 }
2877 }
2878 adiline4( "AL:0:%d:%*s%s",
2879 _environment->currentSourceLineAnalyzed, leftPadding, "", bufferAsmEscaped );
2880 }
2881
2882 }
2883
2884 if ( _environment->currentSourceLineAnalyzed ) {
2885 adiline1( "AF:0:%d",
2886 _environment->bytesProduced );
2887 }
2888
2889 (void)fclose(fileListing);
2890 (void)fclose(fileAsm);
2891
2892 }
2893
2894}
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)