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 /* MOS 6502/6510 optimizations for ugBasic by M.Spedaletti
32 * Based on Motorola 6809 optimizations for ugBasic by S.Devulder
33 *
34 * The idea here is to look for specific patterns over consecutive (1 to 4)
35 * lines of code generated by ugBasic compiler, and reorganize it locally
36 * by another pattern that contains a more efficent code achieving the same
37 * result.
38 *
39 * It does multiple passes over the source as local rewrites can be
40 * applied on previous rewrites, resulting in a avalanche effects that
41 * optimizes the source far away from one can guess from the basic patterns.
42 *
43 * The optimizer can also perform some data flow analysis. It can for
44 * instance see that one of the accumulator is $00 to simplify code. It can
45 * also detect that some data in memory are written but never read. These
46 * are called dead-data. It will then remove all reference to these data in
47 * the code making it smaller and faster (as a useless write is not
48 * performed anymore).
49 *
50 * Real full data-flow analysis should normally be able to detect data which
51 * is written two times in a row whithout being read in-between. These are
52 * also called dead-data since the first written value is also lost. These
53 * dead-data typically appear during the avalanche effect occuring during
54 * previous optimizations passes. Write operation to these dead-data can
55 * also be removed harmlessly.
56 *
57 * Unfortunately this version of the optimized doesn't have yet a complete
58 * data-flow analyzer. Instead, heuristics is used to guess whether a memory
59 * operation accesses a dead data. In that case the optimizer will indicate
60 * in the commented-out code that the data is *presumed dead*. The
61 * heuristics are carefully choosen from the patterns generated by ugBasic
62 * and make good guesses. But if you consider these as too dangerous you
63 * can disable all of them with the "ALLOW_UNSAFE" flag below.
64 *
65 * Last the optimizer will also attempt to reorganize the data to get a
66 * faster & shorter code. Some data will be "inlined" in the code, making
67 * the code auto-modifiable which is no problem for the mc6809. And some
68 * "heavily used" data will be moved into the direct-page location for
69 * faster accesses.
70 */
71
72/****************************************************************************
73 * INCLUDE SECTION
74 ****************************************************************************/
75
76#include "../../ugbc.h"
77#include <stdarg.h>
78#include <ctype.h>
79
80/****************************************************************************
81 * CODE SECTION
82 ****************************************************************************/
83
84#define DIRECT_PAGE 0x2100
85#define LOOK_AHEAD 10
86#define ALLOW_UNSAFE 1
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/* number of lines changed */
131static int change = 0;
132static int peephole_pass = 0;
133static int num_dp = 0; /* number of variables relocated to direct-page */
134static int num_inlined = 0; /* number of variables inlined */
135static int num_unread = 0; /* number of variables not read */
136
137#ifdef __GNUC__
138static void optim(POBuffer buf, const char *rule, const char *repl, ...)
139 __attribute__ ((format (printf, 3, 4)));
140#endif
141
142#define R__(X) #X
143#define R_(X) R__(X)
144#define RULE "r" R_(__LINE__) " "
145
146/* replaces the buffer with an optimized code */
147/* original buffer is kept as comment */
148static void optim(POBuffer buf, const char *rule, const char *repl, ...) {
149 va_list ap;
150 POBuffer tmp = TMP_BUF;
151 char *s;
152
153 va_start(ap, repl);
154 po_buf_cpy(tmp, "");
155
156 /* add our own comment if any */
157 if(rule) po_buf_printf(tmp, "; peephole(%d): %s\n", peephole_pass, rule);
158
159 /* comment out line */
160 po_buf_cat(tmp, ";");
161
162 /* copy upto the end of string or upto end of string */
163 if ( (s = strchr(buf->str, '\n')) != NULL) *s = '\0'; /* cut at \n */
164 po_buf_cat(tmp, buf->str);
165 if( s != NULL ) po_buf_add(tmp, *s++ = '\n'); /* restore \n */
166
167 /* insert replacement if provided */
168 if(repl) {
169 po_buf_vprintf(tmp, repl, ap);
170 po_buf_cat(tmp, "\n");
171 }
172
173 /* copy remaining comments */
174 if(s) po_buf_cat(tmp, s);
175
176 /* write result back into input buffer */
177 po_buf_cpy(buf, tmp->str);
178
179 /* one more change */
180 ++change;
181
182 va_end(ap);
183}
184
185/* returns true if the buffer matches a zero value */
186static int isZero(char *s) {
187 if(*s == '$') ++s;
188 while(*s == '0') ++s;
189 return _eq(' ', *s);
190}
191static int _isZero(POBuffer buf) {
192 return buf!=NULL && isZero(buf->str);
193}
194
195/* returns true if buf matches any op using the ALU between memory and a register */
196static int chg_reg(POBuffer buf, char * REG) {
197 if ( strcmp( REG, "A" ) == 0 ) {
198 if(po_buf_match(buf, " ADC")) return 1;
199 if(po_buf_match(buf, " AND")) return 1;
200 if(po_buf_match(buf, " EOR")) return 1;
201 if(po_buf_match(buf, " LDA")) return 1;
202 if(po_buf_match(buf, " ORA")) return 1;
203 if(po_buf_match(buf, " SBC")) return 1;
204 } else if ( strcmp( REG, "X" ) == 0 ) {
205 if(po_buf_match(buf, " LDX")) return 1;
206 } else if ( strcmp( REG, "Y" ) == 0 ) {
207 if(po_buf_match(buf, " LDY")) return 1;
208 }
209 return 0;
210}
211
212/* returns true if buf matches any read op */
213static int chg_read(POBuffer buf) {
214 if(po_buf_match(buf, "ADC")) return 1;
215 if(po_buf_match(buf, "AND")) return 1;
216 if(po_buf_match(buf, "EOR")) return 1;
217 if(po_buf_match(buf, "LDA")) return 1;
218 if(po_buf_match(buf, "ORA")) return 1;
219 if(po_buf_match(buf, "SBC")) return 1;
220 if(po_buf_match(buf, "CMP")) return 1;
221 if(po_buf_match(buf, "BIT")) return 1;
222 if(po_buf_match(buf, "ASL")) return 1;
223 if(po_buf_match(buf, "DEC")) return 1;
224 if(po_buf_match(buf, "INC")) return 1;
225 return 0;
226}
227
228static int chg_write(POBuffer buf, char * REG) {
229 if ( strcmp( REG, "A" ) == 0 ) {
230 if(po_buf_match(buf, " STA")) return 1;
231 } else if ( strcmp( REG, "X" ) == 0 ) {
232 if(po_buf_match(buf, " STX")) return 1;
233 } else if ( strcmp( REG, "Y" ) == 0 ) {
234 if(po_buf_match(buf, " STY")) return 1;
235 }
236 return 0;
237}
238
239/* perform basic peephole optimization with a length-4 look-ahead */
240static void basic_peephole(Environment * _environment, POBuffer buf[LOOK_AHEAD], int zA, int zB) {
241 /* allows presumably safe operations */
242 int unsafe = ALLOW_UNSAFE;
243
244 /* various local buffers */
245 POBuffer v1 = TMP_BUF;
246 POBuffer v2 = TMP_BUF;
247 POBuffer v3 = TMP_BUF;
248 POBuffer v4 = TMP_BUF;
249 POBuffer v5 = TMP_BUF;
250 POBuffer v6 = TMP_BUF;
251
252 /* a bunch of rules */
253
254 // Avoid a jsr + rts chain
255 //
256 // A tail call occurs when a subroutine finishes by calling another subroutine.
257 // This can be optimised into a JMP instruction:
258 //
259 // MySubroutine
260 // lda Foo
261 // sta Bar
262 // jsr SomeRandomRoutine
263 // rts
264 //
265 // becomes :
266 //
267 // MySubroutine
268 // lda Foo
269 // sta Bar
270 // jmp SomeRandomRoutine
271 //
272 // Savings : 9 cycles, 1 byte
273
274 if( po_buf_match( buf[0], " JSR *", v1 ) && po_buf_match( buf[1], " RTS " ) ) {
275 optim( buf[0], RULE "(JSR, RTS)->(JMP)", "\tJMP %s", v1->str );
276 optim( buf[1], RULE "(JSR, RTS)->(JMP)", NULL );
277 ++_environment->removedAssemblyLines;
278 }
279
280 if( po_buf_match( buf[0], " LDA #$*", v1 ) && po_buf_match( buf[1], " LDA #$*", v2 ) ) {
281 optim( buf[0], RULE "(LDA #, LDA #)->(LDA #)", NULL );
282 ++_environment->removedAssemblyLines;
283 }
284
285 // // ;Instead of
286 // // ld b,$20
287 // // ld c,$30
288 // // ;try this
289 // // ld bc,$2030
290 // // ;or this
291 // // ld bc,(b_num * 256) + c_num ;where b_num goes to b register and c_num to c register
292 // // ; -> save 1 byte and 4 T-states
293 // if( match( buf[0], " LD B, $*", v1) && match( buf[1], " LD C, $*", v2) ) {
294 // optim( buf[0], RULE "(LD B, x; LD C, x)->(LD BC, xx)", "\tLD BC, ($%s * 256) + $%s", v1->str, v2->str );
295 // optim( buf[1], "", NULL );
296 // }
297
298 // //
299 // if( match( buf[0], " LD A, *", v1) &&
300 // match( buf[1], " LD (*), A", v2) &&
301 // match( buf[2], " LD A, *", v3) &&
302 // _strcmp(v1,v3)==0
303 // ) {
304 // optim( buf[2], RULE "(LD A, x; LD (x), A; LD A, x)->(LD A, x; LD (x), A)", NULL );
305 // }
306
307 // // ;Instead of
308 // // ld a,$42
309 // // ld (hl),a
310 // // ;try this
311 // // ld (hl),$42
312 // // ; -> save 1 byte and 4 T-states
313 // if( match( buf[0], " LD A, $*", v1) &&
314 // match( buf[1], " LD (HL), A")
315 // ) {
316 // optim( buf[0], RULE "(LD A, x; LD (HL), A)->(LD (HL), x)", "\tLD HL, $%s", v1->str );
317 // optim( buf[1], NULL, NULL );
318 // }
319
320 // // ;Instead of
321 // // ld A, (var)
322 // // inc a
323 // // ld (var),a
324 // // ;try this ;Note: if hl is not tied up, use indirection:
325 // // ld hl,var
326 // // inc (hl)
327 // // ld A, (hl) ;if you don't need (hl) in a, delete this line
328 // // ; -> save 2 bytes and 2 T-states
329 // if( match( buf[0], " LD A, (*)", v1) &&
330 // match( buf[1], " INC A") &&
331 // match( buf[2], " LD (*), A", v2 ) &&
332 // _strcmp( v1, v2 ) == 0
333 // ) {
334 // optim( buf[0], RULE "(LD A, (x); INC A; LD (x), A)->(LD HL, x; INC (HL))", "\tLD HL, %s", v1->str );
335 // optim( buf[1], NULL, "\tINC (HL)" );
336 // optim( buf[2], NULL, NULL );
337 // }
338
339 // // ; Instead of :
340 // // ld a, (hl)
341 // // ld (de), a
342 // // inc hl
343 // // inc de
344 // // ; Use :
345 // // ldi
346 // // inc bc
347 // // ; -> save 1 byte and 4 T-states
348 // if( match( buf[0], " LD A, (HL)") &&
349 // match( buf[1], " LD (DE), A" ) &&
350 // match( buf[2], " INC HL" ) &&
351 // match( buf[3], " INC DE" )
352 // ) {
353 // optim( buf[0], RULE "(LD A, (HL); LD (DE), A; INC HL; INC DE)->(LDI; INC BC)", "\tLDI" );
354 // optim( buf[1], NULL, "\tINC BC" );
355 // optim( buf[2], NULL, NULL );
356 // optim( buf[3], NULL, NULL );
357 // }
358
359 // // ;Instead of:
360 // // cp 0
361 // // ;Use
362 // // or a
363 // // ; -> save 1 byte and 3 T-states
364 // if( match( buf[0], " CP 0") ) {
365 // optim( buf[0], RULE "(CP 0)->(OR A)", "\tOR A" );
366 // }
367
368 // // xor %11111111
369 // // ; >
370 // // cpl
371 // // ; -> save 1 byte and 3 T-states
372 // if( match( buf[0], " XOR $FF") ) {
373 // optim( buf[0], RULE "(XOR $FF)->(CPL)", "\tCPL" );
374 // }
375
376 // // ;Instead of
377 // // ld de,767
378 // // or a ;reset carry so sbc works as a sub
379 // // sbc hl,de
380 // // ;try this
381 // // ld de,-767 ;negation of de
382 // // add hl,de
383 // // ; -> 2 bytes and 8 T-states !
384 // if(
385 // match( buf[0], " LD DE, $*", v1 ) &&
386 // match( buf[1], " OR A" ) &&
387 // match( buf[2], " SBC HL, DE" )
388 // ) {
389 // optim( buf[0], RULE "(LD DE, x; OR A; SBC HL, DE)->(LD DE, -x; ADD HL, DE)", "\tLD DE, -$%s", v1->str );
390 // optim( buf[1], NULL, "\tADD HL, DE" );
391 // }
392
393 // // ;Instead of
394 // // sla l
395 // // rl h ; I've actually seen this!
396 // // ; >
397 // // add hl,hl
398 // // ; -> save 3 bytes and 5 T-states
399 // if(
400 // match( buf[0], " SLA L" ) &&
401 // match( buf[1], " RL H" )
402 // ) {
403 // optim( buf[0], RULE "(SLA+RL)->(ADD)", "\tADD HL, HL" );
404 // optim( buf[1], NULL, NULL );
405 // }
406
407 // // ; Instead of
408 // // and 1
409 // // cp 1
410 // // jr z,foo
411 // // ; >
412 // // and 1 ;and sets zero flag, no need for cp
413 // // jr nz,foo
414 // // ; -> save 2 bytes and 7 T-states
415 // if(
416 // match( buf[0], " AND $*", v1 ) &&
417 // match( buf[1], " CP $*", v2 ) &&
418 // match( buf[2], " JR Z, *", v3 ) &&
419 // _strcmp( v1, v2 ) == 0
420 // ) {
421 // optim( buf[1], NULL, NULL );
422 // optim( buf[2], RULE "(AND+CP+JZ)->(AND+JNZ)", " JR NZ, %s", v3->str );
423 // }
424
425 // // ;Instead of
426 // // call xxxx
427 // // ret
428 // // ;try this
429 // // jp xxxx
430 // // ;only do this if the pushed pc to stack is not passed to the call. Example: some kind of inline vputs.
431 // // ; -> save 1 byte and 17 T-states
432 // if(
433 // match( buf[0], " CALL *", v1 ) &&
434 // match( buf[1], " RET" )
435 // ) {
436 // optim( buf[0], RULE "(CALL+RET)->(JP)", "\tJP %s", v1->str );
437 // optim( buf[1], NULL, NULL );
438 // }
439
440 // // ;Never use:
441 // // dec B
442 // // jr NZ,loop ;I have seen this...
443 // // ;Use:
444 // // djnz loop
445 // // ; save 1 byte and 3 T-states
446 // if(
447 // match( buf[0], " DEC B" ) &&
448 // match( buf[1], " JR NZ, *", v1 )
449 // ) {
450 // optim( buf[0], RULE "(DEC B+JR NZ)->(DJNZ)", "\tDJNZ %s", v1->str );
451 // optim( buf[1], NULL, NULL );
452 // }
453
454 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
455 po_buf_match( buf[0], " LDA *", v1 ) && po_buf_match( buf[1], " LDA *", v2 )
456 && strstr( v1->str, "$" ) == NULL
457 ) {
458 optim( buf[0], RULE "(LDA x, LDA x)->(LDA x) [1]", NULL );
459 ++_environment->removedAssemblyLines;
460 }
461 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
462 po_buf_match( buf[0], " LD* *", v1, v2 ) &&
463 chg_write( buf[1], v1->str) &&
464 po_buf_match( buf[2], " LD* *", v3, v4 )
465 && strcmp( v1->str, v3->str ) == 0 && strcmp( v2->str, v4->str ) == 0
466 && strchr( v4->str, '+' ) == NULL ) {
467 optim( buf[2], RULE "(LD x, |STx, LD y)->(LD y)", NULL );
468 ++_environment->removedAssemblyLines;
469 }
470 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
471 po_buf_match( buf[0], " LD* *", v1, v2 ) &&
472 chg_write( buf[1], v1->str) &&
473 chg_write( buf[2], v1->str) &&
474 po_buf_match( buf[3], " LD* *", v3, v4 )
475 && strcmp( v1->str, v3->str ) == 0 && strcmp( v2->str, v4->str ) == 0 ) {
476 optim( buf[3], RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
477 ++_environment->removedAssemblyLines;
478 }
479 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
480 po_buf_match( buf[0], " LD* *", v1, v2 ) &&
481 chg_write( buf[1], v1->str) &&
482 chg_write( buf[2], v1->str) &&
483 chg_write( buf[3], v1->str) &&
484 po_buf_match( buf[4], " LD* *", v3, v4 )
485 && strcmp( v1->str, v3->str ) == 0 && strcmp( v2->str, v4->str ) == 0 ) {
486 optim( buf[4], RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
487 ++_environment->removedAssemblyLines;
488 }
489 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
490 po_buf_match( buf[0], " LD* *", v1, v2 ) &&
491 chg_write( buf[1], v1->str) &&
492 chg_write( buf[2], v1->str) &&
493 chg_write( buf[3], v1->str) &&
494 chg_write( buf[4], v1->str) &&
495 po_buf_match( buf[5], " LD* *", v3, v4 )
496 && strcmp( v1->str, v3->str ) == 0 && strcmp( v2->str, v4->str ) == 0 ) {
497 optim( buf[5], RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
498 ++_environment->removedAssemblyLines;
499 }
500 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
501 po_buf_match( buf[0], " LD* *", v1, v2 ) &&
502 chg_write( buf[1], v1->str) &&
503 chg_write( buf[2], v1->str) &&
504 chg_write( buf[3], v1->str) &&
505 chg_write( buf[4], v1->str) &&
506 chg_write( buf[5], v1->str) &&
507 po_buf_match( buf[6], " LD* *", v3, v4 )
508 && strcmp( v1->str, v3->str ) == 0 && strcmp( v2->str, v4->str ) == 0 ) {
509 optim( buf[6], RULE "(2) (LD x, |STx, LD y)->(LD y)", NULL );
510 ++_environment->removedAssemblyLines;
511 }
512
513 if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
514 po_buf_match( buf[0], " ST* *", v1, v2 ) && po_buf_match( buf[1], " LD* *", v3, v4 )
515 && strcmp( v1->str, v3->str ) == 0 && strcmp( v2->str, v4->str ) == 0 &&
516 strstr( v2->str, "$FF" ) == NULL ) {
517 optim( buf[1], RULE "(STx y, LDx y)->()", NULL );
518 ++_environment->removedAssemblyLines;
519 ++_environment->removedAssemblyLines;
520 }
521
522 //
523
524 if( po_buf_match( buf[0], " LDA *", v1 ) &&
525 po_buf_match( buf[1], " STA *", v2 ) &&
526 po_buf_match( buf[2], " LDA *", v3 ) &&
527 po_buf_match( buf[3], " STA *", v4 ) &&
528 strcmp( v2->str, v3->str ) == 0 ) {
529 optim( buf[2], RULE "(LDA x, STA y, LDA y, STz)->(LDA x, STA z)", NULL );
530 ++_environment->removedAssemblyLines;
531 }
532
533 // if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
534 // po_buf_match( buf[0], " LDA *", v1 ) && po_buf_match( buf[2], " LDA *", v2 ) &&
535 // ! chg_reg(buf[1], "A") &&
536 // ! po_buf_match( buf[1], "*:", v3 )
537 // && strcmp( v1->str, v2->str ) == 0 ) {
538 // optim( buf[2], RULE "(LDA x, LDA x)->(LDA x) [2]", NULL );
539 // ++_environment->removedAssemblyLines;
540 // }
541
542 // if( ! po_buf_match( buf[0], " LDA *,Y", v3 ) &&
543 // po_buf_match( buf[0], " LDA *", v1 ) && po_buf_match( buf[3], " LDA *", v2 ) &&
544 // ! chg_reg(buf[1], "A") &&
545 // ! chg_reg(buf[2], "A") &&
546 // ! po_buf_match( buf[1], "*:", v3 ) &&
547 // ! po_buf_match( buf[2], "*:", v3 )
548 // && strcmp( v1->str, v2->str ) == 0 ) {
549 // optim( buf[3], RULE "(LDA x, LDA x)->(LDA x) [3]", NULL );
550 // ++_environment->removedAssemblyLines;
551 // }
552
553// 0: LDA #$06
554// 1: 000DC8r 1 8D rr rr STA _printScore_Ttmp13
555// 2: 000DCBr 1 A9 00 LDA #$00
556// 3: 000DCDr 1 8D rr rr STA _printScore_Ttmp16
557// 4: 000DD0r 1 AD rr rr LDA _printScore_Ttmp13
558// 5: 000DD3r 1 85 A7 STA XCURSYS
559// 6: 000DD5r 1 AD rr rr LDA _printScore_Ttmp16
560// 7: 000DD8r 1 85 A8 STA YCURSYS
561
562 // if(
563 // po_buf_match( buf[0], " LDA *", v1 ) &&
564 // po_buf_match( buf[1], " STA *", v2 ) &&
565 // po_buf_match( buf[2], " LDA *", v3 ) &&
566 // po_buf_match( buf[3], " STA *", v4 ) &&
567 // ( strcmp( v2->str, v3->str ) == 0 ) &&
568 // ( strstr( v2->str,"_Ttmp" ) != NULL )
569 // ) {
570
571 // // printf( "*******************\n" );
572 // // printf( "v2 = %s, v3 = %s\n", v2->str, v3->str );
573 // // printf( "-------------------\n" );
574 // // printf(" %s\n", buf[0]->str );
575 // // printf(" %s\n", buf[1]->str );
576 // // printf(" %s\n", buf[2]->str );
577 // // printf(" %s\n", buf[3]->str );
578 // // printf(" -> \n" );
579 // // printf(" %s\n", buf[0]->str );
580 // // printf(" %s\n", buf[3]->str );
581 // // printf( "-------------------\n" );
582
583 // optim( buf[1], RULE "(LDA x, STA v1, LDA v1, STA v2)->(..., LDA x, STA v2)", NULL );
584 // optim( buf[2], RULE "(LDA x, STA v1, LDA v1, STA v2)->(..., LDA x, STA v2)", NULL );
585 // ++_environment->removedAssemblyLines;
586 // ++_environment->removedAssemblyLines;
587
588 // // printf( "-------------------\n" );
589 // // printf(" %s\n", buf[0]->str );
590 // // printf(" %s\n", buf[1]->str );
591 // // printf(" %s\n", buf[2]->str );
592 // // printf(" %s\n", buf[3]->str );
593 // // printf(" -> \n" );
594 // // printf(" %s\n", buf[0]->str );
595 // // printf(" %s\n", buf[3]->str );
596 // // printf( "-------------------\n" );
597 // // printf( "*******************\n\n" );
598
599 // }
600
601 // if(
602 // po_buf_match( buf[0], " LDA *", v1 ) &&
603 // po_buf_match( buf[1], " STA ", v2 ) &&
604 // po_buf_match( buf[4], " LDA *", v3 ) &&
605 // po_buf_match( buf[5], " STA ", v4 ) &&
606 // ( strcmp( v2->str, v3->str ) == 0 ) &&
607 // ( strstr( v2->str,"_Ttmp" ) != NULL )
608 // ) {
609 // printf("**** %s\n", v2->str );
610 // optim( buf[0], RULE "(LDA x, STA v1, ..., LDA v1, STA v2)->(..., LDA x, STA v2)", NULL );
611 // optim( buf[1], RULE "(LDA x, STA v1, ..., LDA v1, STA v2)->(..., LDA x, STA v2)", NULL );
612 // optim( buf[4], RULE "(LDA x, STA v1, ..., LDA v1, STA v2)->(..., LDA x, STA v2)", "LDA %s", v1->str );
613 // ++_environment->removedAssemblyLines;
614 // }
615
616}
617
618/* optimizations related to variables */
619
620/* variables database */
621static struct {
622 struct var {
623 char *name;
624#define NO_REORG 1
625#define NO_DP 2
626#define NO_INLINE 4
627#define NO_REMOVE 8
628 int flags;
629 int size;
630 int nb_rd;
631 int nb_wr;
632 int offset; /* 0=unchanged, >0 offset to page 0; -1 = candidate for inlining, -2 = inlined */
633 char *init;
634 } *tab;
636 int size;
638} vars;
639
640/* clears the database */
641static void vars_clear(void) {
642 int i;
643 for(i=0; i<vars.size; ++i) {
644 struct var *v = &vars.tab[i];
645 free(v->name);
646 if(v->init) free(v->init);
647 }
648 vars.size = 0;
649 vars.page0_max = 0;
650}
651
652/* gets (or creates) an entry for a variable from the data-base */
653struct var *vars_get(POBuffer _name) {
654 char *name = _name->str;
655 struct var *ret = NULL;
656 int i;
657
658 char *s=strchr(name,'+');
659 if(s) *s='\0';
660
661 s=strstr(name,"#<");
662 if(s) {
663 memmove( s, s+2, strlen(name)-2);
664 *(name+strlen(name)-2) = 0;
665 }
666
667 s=strstr(name,"#>");
668 if(s) {
669 memmove( s, s+2, strlen(name)-2);
670 *(name+strlen(name)-2) = 0;
671 }
672
673 for(i=0; i<vars.size ; ++i) {
674 if(strcmp(vars.tab[i].name, name)==0) {
675 ret = &vars.tab[i];
676 }
677 }
678 if(ret == NULL) {
679 if(vars.size == vars.capacity) {
680 vars.capacity += 16;
681 vars.tab = realloc(vars.tab, sizeof(*vars.tab)*vars.capacity);
682 }
683 ret = &vars.tab[vars.size++];
684 ret->name = strdup(name);
685 ret->flags = 0;
686 ret->size = 0;
687 ret->nb_rd = 0;
688 ret->nb_wr = 0;
689 ret->offset = 0;
690 ret->init = NULL;
691 }
692 if(s) *s='+';
693
694 return ret;
695}
696
697static int vars_ok(POBuffer name) {
698 if(po_buf_match(name, "REU^")) return 0;
699 if(po_buf_match(name, "MSPRITE^")) return 0;
700 if(po_buf_match(name, "IC^")) return 0;
701 if(po_buf_match(name, "FUJINET^")) return 0;
702 if(po_buf_match(name, "SERIAL^")) return 0;
703 if(po_buf_match(name, "PUTIMAGE^")) return 0;
704 if(po_buf_match(name, "GETIMAGE^")) return 0;
705 if(po_buf_match(name, "BANK^")) return 0;
706 if(po_buf_match(name, "SID^")) return 0;
707 if(po_buf_match(name, "SIO^")) return 0;
708 if(po_buf_match(name, "DOJO^")) return 0;
709 if(po_buf_match(name, "BLIT^")) return 0;
710 if(po_buf_match(name, "FADE^")) return 0;
711 if(po_buf_match(name, "TIMER^")) return 0;
712 if(po_buf_match(name, "ANTIC^")) return 0;
713 if(po_buf_match(name, "COPPER^")) return 0;
714 if(po_buf_match(name, "^_Tstr")) return 0;
715 if(po_buf_match(name, "_^_Tstr")) return 0;
716 if(po_buf_match(name, "_label")) return 0;
717 if(po_buf_match(name, "$^")) return 0;
718 if(po_buf_match(name, "(^")) return 0;
719
720 // if(name->str[0]=='_') return 1;
721 // if(po_buf_match(name, "CLIP")) return 1;
722 // if(po_buf_match(name, "XCUR")) return 1;
723 // if(po_buf_match(name, "YCUR")) return 1;
724 // if(po_buf_match(name, "CURRENT")) return 1;
725 // if(po_buf_match(name, "FONT")) return 1;
726 // if(po_buf_match(name, "TEXT")) return 1;
727 // if(po_buf_match(name, "LAST")) return 1;
728 // if(po_buf_match(name, "XGR")) return 1;
729 // if(po_buf_match(name, "YGR")) return 1;
730 // if(po_buf_match(name, "FREE_")) return 1;
731
732 return 1;
733}
734
735/* look for variable uses and collect data about he variables */
736static void vars_scan(POBuffer buf[LOOK_AHEAD]) {
737 POBuffer tmp = TMP_BUF;
738 POBuffer arg = TMP_BUF;
739 POBuffer cmd = TMP_BUF;
740 POBuffer arg2 = TMP_BUF;
741
742 // if( match( buf[0], " * _*+", NULL, buf) ) {
743 // struct var *v = vars_get(buf);
744 // v->flags |= NO_INLINE;
745 // }
746
747
748 if(
749 po_buf_match( buf[0], " JMP (*)", arg )
750 ) if(vars_ok(arg)) {
751 struct var *v = vars_get(arg);
752 v->nb_rd++;
753 };
754
755 if(
756 po_buf_match( buf[0], " INC *", arg )
757 ) if(vars_ok(arg)) {
758 struct var *v = vars_get(arg);
759 v->nb_rd++;
760 v->nb_wr++;
761 };
762
763 if(
764 po_buf_match( buf[0], " ROR *", arg )
765 ) if(vars_ok(arg)) {
766 struct var *v = vars_get(arg);
767 v->nb_rd++;
768 v->nb_wr++;
769 };
770
771 if(
772 po_buf_match( buf[0], " LD* *", tmp, arg ) &&
773 strstr("A X Y", tmp->str)!=NULL
774 ){
775 if(vars_ok(arg)) {
776 struct var *v = vars_get(arg);
777 v->nb_rd++;
778 };
779 }
780
781 if(
782 po_buf_match( buf[0], " LD* (*)", tmp, arg ) &&
783 strstr("A X Y", tmp->str)!=NULL
784 ) if(vars_ok(arg)) {
785 struct var *v = vars_get(arg);
786 v->nb_rd++;
787 };
788
789 if(
790 po_buf_match( buf[0], " CP* *", tmp, arg ) &&
791 strstr("A X Y", tmp->str)!=NULL
792 ) if(vars_ok(arg)) {
793 struct var *v = vars_get(arg);
794 v->nb_rd++;
795 };
796
797 if(
798 po_buf_match( buf[0], " CMP *", arg )
799 ) if(vars_ok(arg)) {
800 struct var *v = vars_get(arg);
801 v->nb_rd++;
802 };
803
804 if(
805 po_buf_match( buf[0], " CMP (*)", arg )
806 ) if(vars_ok(arg)) {
807 struct var *v = vars_get(arg);
808 v->nb_rd++;
809 };
810
811 if(
812 po_buf_match( buf[0], " ADC *", arg )
813 ) if(vars_ok(arg)) {
814 struct var *v = vars_get(arg);
815 v->nb_rd++;
816 };
817
818 if(
819 po_buf_match( buf[0], " LD* #<(*)", tmp, arg ) &&
820 strstr("A X Y", tmp->str)!=NULL
821 ) if(vars_ok(arg)) {
822 struct var *v = vars_get(arg);
823 v->nb_rd++;
824 };
825
826 if(
827 po_buf_match( buf[0], " LD* #>*", tmp, arg ) &&
828 strstr("A X Y", tmp->str)!=NULL
829 ) if(vars_ok(arg)) {
830 struct var *v = vars_get(arg);
831 v->nb_rd++;
832 };
833
834 if(
835 po_buf_match( buf[0], " LD* #>(*)", tmp, arg ) &&
836 strstr("A X Y", tmp->str)!=NULL
837 ) if(vars_ok(arg)) {
838 struct var *v = vars_get(arg);
839 v->nb_rd++;
840 };
841
842 if( po_buf_match( buf[0], " * *", cmd, arg ) &&
843 chg_read(cmd)
844 ) if(vars_ok(arg)) {
845 struct var *v = vars_get(arg);
846 v->nb_rd++;
847 };
848
849 if( po_buf_match( buf[0], " * (*)", cmd, arg ) &&
850 chg_read(cmd)
851 ) if(vars_ok(arg)) {
852 struct var *v = vars_get(arg);
853 v->nb_rd++;
854 };
855
856 if( po_buf_match( buf[0], " * (*),Y", cmd, arg ) &&
857 chg_read(cmd)
858 ) if(vars_ok(arg)) {
859 struct var *v = vars_get(arg);
860 v->nb_rd++;
861 };
862
863 if( po_buf_match( buf[0], " * *,X", cmd, arg ) &&
864 chg_read(cmd)
865 ) if(vars_ok(arg)) {
866 struct var *v = vars_get(arg);
867 v->nb_rd++;
868 };
869
870 if( po_buf_match( buf[0], " * *, X", cmd, arg ) &&
871 chg_read(cmd)
872 ) if(vars_ok(arg)) {
873 struct var *v = vars_get(arg);
874 v->nb_rd++;
875 };
876
877 if( po_buf_match( buf[0], " ST* *", tmp, arg ) && strstr("A X Y", tmp->str)!=NULL )
878 if(vars_ok(arg)) {
879 struct var *v = vars_get(arg);
880 v->nb_wr++;
881 };
882
883 if( po_buf_match( buf[0], " STA (*),Y", arg ) )
884 if(vars_ok(arg)) {
885 struct var *v = vars_get(arg);
886 v->nb_rd++;
887 v->nb_wr++;
888 };
889
890 if( po_buf_match( buf[0], " STA (*), Y", arg ) )
891 if(vars_ok(arg)) {
892 struct var *v = vars_get(arg);
893 v->nb_rd++;
894 v->nb_wr++;
895 };
896
897 if( po_buf_match( buf[0], " STA *,X", arg ) )
898 if(vars_ok(arg)) {
899 struct var *v = vars_get(arg);
900 v->nb_wr++;
901 v->nb_rd++;
902 };
903
904 if( po_buf_match( buf[0], " STA *, X", arg ) )
905 if(vars_ok(arg)) {
906 struct var *v = vars_get(arg);
907 v->nb_wr++;
908 v->nb_rd++;
909 };
910
911 if( po_buf_match( buf[0], " STA *,Y", arg ) )
912 if(vars_ok(arg)) {
913 struct var *v = vars_get(arg);
914 v->nb_wr++;
915 v->nb_rd++;
916 };
917
918 if( po_buf_match( buf[0], " STA *, Y", arg ) )
919 if(vars_ok(arg)) {
920 struct var *v = vars_get(arg);
921 v->nb_wr++;
922 v->nb_rd++;
923 };
924
925 if( po_buf_match( buf[0], "*: .byte *", tmp, arg) && vars_ok(tmp) && strchr(arg->str,',')==NULL ) {
926 struct var *v = vars_get(tmp);
927 v->size = 1;
928 v->init = strdup(isZero(arg->str) ? "1-1" : arg->str);
929 //printf( "%s detecting (size=%d)\n", v->name, v->size);
930 }
931
932 if( po_buf_match(buf[0], "*: .word *", tmp, arg) && vars_ok(tmp) && strchr(arg->str,',')==NULL ) {
933 struct var *v = vars_get(tmp);
934 v->size = 2;
935 v->init = strdup(arg->str);
936 }
937
938 if( po_buf_match(buf[0], "*: .res *,*", tmp, arg, arg2) && vars_ok(tmp) ) {
939 struct var *v = vars_get(tmp);
940 v->size = atoi( arg->str );
941 v->init = strdup( arg2->str );
942 //printf( "sizing %s size = %d\n", v->name, v->size );
943 } else if( po_buf_match(buf[0], "*: .res *,*", tmp, arg, arg2) && vars_ok(tmp) ) {
944 struct var *v = vars_get(tmp);
945 v->size = atoi( arg->str );
946 v->init = strdup( arg2->str );
947 //printf( "sizing %s size = %d\n", v->name, v->size );
948 } else if( po_buf_match(buf[0], "*: .res *", tmp, arg) && vars_ok(tmp) ) {
949 struct var *v = vars_get(tmp);
950 v->size = atoi( arg->str );
951 v->init = NULL;
952 //printf( "sizing %s size = %d\n", v->name, v->size );
953 }
954
955 if( po_buf_match(buf[0], " * *", tmp, arg) ) if(vars_ok(arg)) {
956 struct var *v = vars_get(arg);
957 // printf( "%s checking (%d:%d)\n", v->name, v->offset, v->size);
958 if ( (v->offset > -2) ) {
959 // printf( "%s candidate for inlining\n", v->name);
960 v->offset = -1; /* candidate for inlining */
961 }
962 }
963
964 // if( po_buf_match(buf[0], "*: .word *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
965 // struct var *v = vars_get(tmp);
966 // v->size = 2;
967 // v->init = strdup(arg->str);
968 // }
969
970 /* variable in RAMs are not eligibile to inlining */
971 if(
972 po_buf_match(buf[0], " * = *+*", tmp, arg2, arg) ||
973 po_buf_match(buf[0], "* = *+*", tmp, arg2, arg)
974 ) {
975 struct var *v = vars_get(arg2);
976 if ( v ) {
977 v->nb_rd = 1;
978 }
979 struct var *v2 = vars_get(tmp);
980 if ( v2 ) {
981 v2->nb_rd = 1;
982 }
983 } else if(
984 po_buf_match(buf[0], " * = *", tmp, arg) ||
985 po_buf_match(buf[0], "* = *", tmp, arg)
986 ) {
987 struct var *v = vars_get(tmp);
988 if ( v ) {
989 // printf( "%s checking\n", v->name);
990 if ( v->offset == -1 ) {
991 // printf( "%s excluding for inlining\n", v->name);
992 v->offset = -3;
993 }
994 }
995 struct var *v2 = vars_get(arg);
996 if ( v2 ) {
997 v2->nb_rd = 1;
998 }
999 }
1000
1001
1002}
1003
1004/* compares two variables according to their access-count */
1005static int vars_cmp(const void *_a, const void *_b) {
1006 const struct var *a = _a;
1007 const struct var *b = _b;
1008
1009 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
1010
1011 return -(diff!=0 ? diff : strcmp(a->name, b->name)); // Ttmp < Tstr
1012}
1013
1014/* removes unread variables */
1015static void vars_remove(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
1016 POBuffer var = TMP_BUF;
1017 POBuffer op = TMP_BUF;
1018 POBuffer var2 = TMP_BUF;
1019 POBuffer op2 = TMP_BUF;
1020 POBuffer tmp = TMP_BUF;
1021
1022 if(!DO_UNREAD) return;
1023
1024 /* unread */
1025 if(po_buf_match( buf[1], " ST* *, *", op, var, tmp) && vars_ok(var)) {
1026 struct var *v = vars_get(var);
1027 if(v->nb_rd == 0 && v->offset!=-2 && strchr(v->name, '+') == NULL && strchr(v->name, '-') == NULL) {
1028 v->offset = 0;
1029 optim(buf[1], "unread", NULL);
1030 ++_environment->removedAssemblyLines;
1031 }
1032 } else if(po_buf_match( buf[1], " ST* *", op, var) && vars_ok(var)) {
1033 struct var *v = vars_get(var);
1034 if(v->nb_rd == 0 && v->offset!=-2 && strchr(v->name, '+') == NULL && strchr(v->name, '-') == NULL) {
1035 v->offset = 0;
1036 optim(buf[1], "unread", NULL);
1037 ++_environment->removedAssemblyLines;
1038 }
1039 }
1040
1041 /* remove changed variables */
1042 if(po_buf_match( buf[0], " *: .byte ", var)
1043 || po_buf_match( buf[0], " *: .word ", var)
1044 || po_buf_match( buf[0], " *: .res ", var)
1045 || po_buf_match( buf[0], "*: .byte ", var)
1046 || po_buf_match( buf[0], "*: .word ", var)
1047 || po_buf_match( buf[0], "*: .res ", var)
1048 ) if(vars_ok(var)) {
1049 struct var *v = vars_get(var);
1050 //printf( "try inlined: %s\n", v->name );
1051 //printf( " offset: %d\n", v->offset );
1052 if ( v->offset==-2 ) {
1053 //printf( " INLINED!\n" );
1054 // printf( "%s inlining (offset=%d, size=%d)\n", v->name, v->offset, v->size );
1055 optim(buf[0], "inlined",NULL);
1056 v->offset=-2;
1057 } else {
1058 if(v->nb_rd==0 && 0<v->size /*&& v->size<=4*/ && 0==(v->flags & NO_REMOVE)) {
1059 optim(buf[0], "unread",NULL);
1060 ++_environment->removedAssemblyLines;
1061 ++num_unread;
1062 }
1063 }
1064 }
1065}
1066
1067/* collapse all heading spaces into a single tabulation */
1068static void out(FILE *f, POBuffer _buf) {
1069 char *s = _buf->str;
1070 int tab = 0;
1071 while(*s==' ' || *s=='\t') {tab = 1; ++s;}
1072 if(tab) fputs("\t", f);
1073 fputs(s, f);
1074}
1075
1076/* remove space that is sometimes used in indexing mode and makes the optimized produce bad dcode */
1077static void fixes_indexed_syntax(POBuffer buf) {
1078 char *s = buf->str;
1079
1080 /* not an instruction */
1081 if(!_eq(' ', *s)) return;
1082
1083 /* skip over spaces */
1084 do ++s; while(*s && _eq(' ', *s));
1085
1086 /* comment */
1087 if(*s==';') return;
1088
1089 /* skip over instruction */
1090 while(*s && !_eq(' ', *s)) ++s;
1091 if(!*s) return;
1092
1093 /* skip over spaces */
1094 do ++s; while(*s && _eq(' ', *s));
1095 if(!*s) return;
1096
1097 /* process argment */
1098 do ++s; while(*s && !_eq(' ', *s));
1099 if(!*s) return;
1100
1101}
1102
1103/* returns true if buf matches any op using the ALU between memory and a register */
1104static int chg_reg2(POBuffer buf) {
1105 if(po_buf_match(buf, "ADD")) return 1;
1106 if(po_buf_match(buf, "AND")) return 1;
1107 if(po_buf_match(buf, "CMP")) return 1;
1108 if(po_buf_match(buf, "EOR")) return 1;
1109 if(po_buf_match(buf, "LDA")) return 1;
1110 if(po_buf_match(buf, "LDX")) return 1;
1111 if(po_buf_match(buf, "LDY")) return 1;
1112 if(po_buf_match(buf, "CPX")) return 1;
1113 if(po_buf_match(buf, "CPY")) return 1;
1114 if(po_buf_match(buf, "ORA")) return 1;
1115 if(po_buf_match(buf, "SBC")) return 1;
1116 if(po_buf_match(buf, "ADC")) return 1;
1117 if(po_buf_match(buf, "SUB")) return 1;
1118
1119 return 0;
1120}
1121
1122/* performs optimizations related to variables relocation */
1123static void vars_relocate(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
1124 POBuffer REG = TMP_BUF;
1125 POBuffer var = TMP_BUF;
1126 POBuffer op = TMP_BUF;
1127
1128 /* inlined */
1129 if(po_buf_match( buf[0], " * *", op, var) && vars_ok(var) && strstr( buf[0]->str, "#<") == NULL && strstr( buf[0]->str, "#>") == NULL ) {
1130 struct var *v = vars_get(var);
1131 //printf( "%s rechecking (offset=%d, size=%d, chg_reg2=%d)\n", v->name, v->offset, v->size, chg_reg2(buf[0]) );
1132 if( v->offset == -1 && v->size == 1 && chg_reg2(op) ) {
1133 //printf( "%s trying to inline\n", v->name);
1134 if ( strstr( var->str, "+" ) == NULL ) {
1135 v->offset = -2;
1136 v->flags |= NO_REMOVE;
1137 optim(buf[0], "inlined1", "\t%s #%s%s\n%s = *-%d", op->str,
1138 v->init==NULL ? "*" : v->init,
1139 v->init==NULL ? (v->size==2 ? "" : "&255") : "",
1140 var->str, v->size);
1141 }
1142 }
1143 }
1144
1145 /* remove changed variables */
1146 if(po_buf_match( buf[0], "*: .res ", var)
1147 || po_buf_match( buf[0], "*: .byte ", var)
1148 || po_buf_match( buf[0], "*: .word ", var) ) if(vars_ok(var)) {
1149 struct var *v = vars_get(var);
1150 if(v->offset == -2) {
1151 optim(buf[0], "inlined3", NULL);
1152 ++_environment->removedAssemblyLines;
1153 ++num_inlined;
1154 }
1155 }
1156}
1157
1158/* decide which variable goes in direct-page, which will be inlined */
1159static void vars_prepare_relocation(void) {
1160 int i;
1161
1162 num_dp = 0;
1163 num_inlined = 0;
1164
1165 qsort(vars.tab, vars.size, sizeof(*vars.tab), vars_cmp);
1166
1167 for(i = 0; i<vars.size; ++i) {
1168 struct var *v = &vars.tab[i];
1169
1170 /* skip over unknown size var */
1171 if(v->size == 0) continue;
1172
1173 /* skip over unread variables */
1174 if(v->nb_rd == 0) continue;
1175
1176 /* flagged as not inline */
1177 if(v->flags & NO_INLINE) v->offset = 0;
1178 if(!DO_INLINE) v->offset = 0;
1179
1180 /* can't inline > 1 byte */
1181 if(v->offset == -1 && v->size>2) v->offset = 0;
1182
1183 // /* check if inlining is good */
1184 // if(v->offset == -1) {
1185 // /* LDA: imm=2, dp=4, extended=5
1186 // LDD: imm=3, dp=5, extended=6 */
1187 // int dp_cost = (3+v->size)*(v->nb_rd + v->nb_wr);
1188 // int inline_cost = (4+v->size)*(v->nb_rd + v->nb_wr - 1)+(1+v->size);
1189
1190 // if( (v->init==NULL || isZero(v->init) || 0==strcmp("1-1", v->init)) && dp_cost < inline_cost ) {
1191 // if(DO_DIRECT_PAGE) v->offset = 0;
1192 // }
1193 // }
1194 // if(DO_DIRECT_PAGE
1195 // && 0==v->offset
1196 // && 0==(v->flags && NO_DP)
1197 // && v->size<=4 /* not too big to let room for others */
1198 // && vars.page0_max + v->size <= 256
1199 // ) {
1200
1201 // if ( vars.page0_max == 0xd8 )
1202 // ++vars.page0_max;
1203 // if ( vars.page0_max == 0xa3 )
1204 // ++vars.page0_max;
1205 // if ( vars.page0_max == 0xd5 )
1206 // ++vars.page0_max;
1207 // if ( vars.page0_max == 0xe3 )
1208 // ++vars.page0_max;
1209 // if ( vars.page0_max == 0xef )
1210 // ++vars.page0_max;
1211 // while ( vars.page0_max < 0xf0 )
1212 // ++vars.page0_max;
1213 // if ( vars.page0_max == 0xf0 )
1214 // ++vars.page0_max;
1215 // if ( vars.page0_max == 0xf1 )
1216 // ++vars.page0_max;
1217 // if ( vars.page0_max == 0xf2 )
1218 // ++vars.page0_max;
1219 // if ( vars.page0_max == 0xf6 )
1220 // ++vars.page0_max;
1221
1222 // v->offset = vars.page0_max;
1223 // vars.page0_max += v->size;
1224 // }
1225
1226 // printf("%s %d/%d %d %d %d\n", v->name, v->nb_rd, v->nb_wr, v->offset, v->size, vars.page0_max);
1227 }
1228}
1229
1230/* various kind of optimization */
1231static int optim_pass( Environment * _environment, POBuffer buf[LOOK_AHEAD], PeepHoleOptimizationKind kind) {
1232 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1233 FILE * fileAsm;
1234 FILE * fileOptimized;
1235 int i;
1236 int still_to_go = LOOK_AHEAD;
1237
1238 int line = 0;
1239 int zA = 0, zB = 0;
1240
1241 int sourceLine = -1;
1242
1243 _environment->currentSourceLineAnalyzed = 0;
1244 _environment->removedAssemblyLines = 0;
1245
1246 adiline2( "POP:0:%d:%d", peephole_pass, kind );
1247
1248 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1249
1250 /* prepare for phase */
1251 switch(kind) {
1252 case DEADVARS:
1253 ++peephole_pass;
1254 num_unread = 0;
1255 break;
1256
1257 case RELOCATION1:
1258 ++peephole_pass;
1259 vars_prepare_relocation();
1260 break;
1261
1262 case RELOCATION2:
1263 break;
1264
1265 case PEEPHOLE:
1266 ++peephole_pass;
1267 vars_clear();
1268 break;
1269 }
1270
1271 fileAsm = fopen( _environment->asmFileName, "rt" );
1272 if(fileAsm == NULL) {
1273 perror(_environment->asmFileName);
1274 exit(-1);
1275 }
1276
1277 fileOptimized = fopen( fileNameOptimized, "wt" );
1278 if(fileOptimized == NULL) {
1279 perror(fileNameOptimized);
1280 exit(-1);
1281 }
1282
1283 /* clears our look-ahead buffers */
1284 for(i = 0; i<LOOK_AHEAD; ++i) po_buf_cpy(buf[i], "");
1285
1286 /* global change flag */
1287 change = 0;
1288
1289 while( still_to_go ) {
1290 /* print out oldest buffer */
1291 if ( line >= LOOK_AHEAD ) out(fileOptimized, buf[0]);
1292
1293 /* shift the buffers */
1294 for(i=0; i<LOOK_AHEAD-1; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
1295
1296 /* read next line, merging adjacent comments */
1297 if(feof(fileAsm)) {
1298 --still_to_go;
1299 po_buf_cpy(buf[LOOK_AHEAD-1], "");
1300 } else do {
1301 /* read next line */
1302 po_buf_fgets( buf[LOOK_AHEAD-1], fileAsm );
1303 fixes_indexed_syntax(buf[LOOK_AHEAD-1]);
1304 /* merge comment with previous line if we do not overflow the buffer */
1305 if(isAComment(buf[LOOK_AHEAD-1])) {
1306 POBuffer ln = TMP_BUF;
1307 if (po_buf_match( buf[LOOK_AHEAD-1], " ; L:*", ln ) ) {
1308 sourceLine = atoi( ln->str );
1309 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
1310 if ( _environment->currentSourceLineAnalyzed ) {
1311 adiline3( "POL:0:%d:%d:%d",
1312 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
1313 }
1314 _environment->currentSourceLineAnalyzed = sourceLine;
1315 _environment->removedAssemblyLines = 0;
1316 }
1317 }
1318 if(KEEP_COMMENTS) po_buf_cat(buf[LOOK_AHEAD-2], buf[LOOK_AHEAD-1]->str);
1319 po_buf_cpy(buf[LOOK_AHEAD-1], "");
1320 } else break;
1321 } while(!feof(fileAsm));
1322
1323 switch(kind) {
1324 case PEEPHOLE:
1325 basic_peephole(_environment, buf, zA, zB);
1326
1327 /* only look fo variable when no peephole has been performed */
1328 if(change == 0) vars_scan(buf);
1329 break;
1330
1331 case DEADVARS:
1332 vars_remove(_environment, buf);
1333 break;
1334
1335 case RELOCATION1:
1336 case RELOCATION2:
1337 vars_relocate(_environment, buf);
1338 break;
1339 }
1340
1341 ++line;
1342 }
1343
1344 adiline3( "POL:0:%d:%d:%d",
1345 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
1346
1347 /* log info at the end of the file */
1348 switch(kind) {
1349 case PEEPHOLE:
1350 fprintf(fileOptimized, "; peephole: pass %d, %d change%s.\n", peephole_pass,
1351 change, change>1 ?"s":"");
1352 break;
1353
1354 case DEADVARS:
1355 fprintf(fileOptimized, "; peephole: pass %d, %d var%s removed.\n", peephole_pass,
1356 num_unread, num_unread>1 ?"s":"");
1357 break;
1358
1359 case RELOCATION2:
1360 fprintf(fileOptimized, "; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
1361 num_dp, num_dp>1 ?"s":"",
1362 num_inlined, num_inlined>1 ? "s":"");
1363 break;
1364
1365 default:
1366 break;
1367 }
1368
1369 (void)fclose(fileAsm);
1370 (void)fclose(fileOptimized);
1371
1372 /* makes our generated file the new asm file */
1373 remove(_environment->asmFileName);
1374 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1375
1376 return change;
1377}
1378
1379typedef struct _UnusedSymbol {
1380
1381 char * realName;
1382
1383 struct _UnusedSymbol * next;
1384
1386
1387static void optim_remove_unused_temporary( Environment * _environment ) {
1388
1389 int i;
1390
1391 POBuffer bufLine = TMP_BUF;
1392 POBuffer v1 = TMP_BUF;
1393 POBuffer v2 = TMP_BUF;
1394 POBuffer v3 = TMP_BUF;
1395 POBuffer v4 = TMP_BUF;
1396 POBuffer v5 = TMP_BUF;
1397 POBuffer v6 = TMP_BUF;
1398 POBuffer buf[5];
1399
1400 for(i=0; i<5; ++i) buf[i] = po_buf_new(0);
1401
1402 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1403 FILE * fileAsm;
1404 FILE * fileOptimized;
1405
1406 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1407
1408 fileAsm = fopen( _environment->asmFileName, "rt" );
1409 if(fileAsm == NULL) {
1410 perror(_environment->asmFileName);
1411 exit(-1);
1412 }
1413
1414 fileOptimized = fopen( fileNameOptimized, "wt" );
1415 if(fileOptimized == NULL) {
1416 perror(fileNameOptimized);
1417 exit(-1);
1418 }
1419
1420 UnusedSymbol * currentlySymbols = NULL;
1421 UnusedSymbol * currentlySymbolsQ = NULL;
1422 UnusedSymbol * currentlyUnusedSymbols = NULL;
1423 UnusedSymbol * currentlyUnusedSymbolsQ = NULL;
1424
1425 int vspPointer = 0;
1426
1427 while( !feof(fileAsm) ) {
1428
1429 po_buf_fgets( bufLine, fileAsm );
1430
1431 // printf( "### %s\n", bufLine->str );
1432
1433 if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
1434 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1435 memset( s, 0, sizeof( UnusedSymbol ) );
1436 s->realName = strdup( v1->str );
1437 s->next = currentlyUnusedSymbols;
1438 currentlyUnusedSymbols = s;
1439
1440 s = malloc( sizeof( UnusedSymbol ) );
1441 memset( s, 0, sizeof( UnusedSymbol ) );
1442 s->realName = strdup( v1->str );
1443 s->next = currentlySymbols;
1444 currentlySymbols = s;
1445 } else if ( po_buf_match( bufLine, " ; Q *", v1 ) ) {
1446 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1447 memset( s, 0, sizeof( UnusedSymbol ) );
1448 s->realName = strdup( v1->str );
1449 s->next = currentlyUnusedSymbolsQ;
1450 currentlyUnusedSymbolsQ = s;
1451
1452 s = malloc( sizeof( UnusedSymbol ) );
1453 memset( s, 0, sizeof( UnusedSymbol ) );
1454 s->realName = strdup( v1->str );
1455 s->next = currentlySymbolsQ;
1456 currentlySymbolsQ = s;
1457 } else if ( po_buf_match( bufLine, " ; VSP" ) ) {
1458
1459 // printf( "SYMBOLS COMPLETE: " );
1460 // UnusedSymbol * s = currentlyUnusedSymbols;
1461 // while( s ) {
1462 // printf( "%s, ", s->realName );
1463 // s = s->next;
1464 // }
1465 // printf( "\n\n" );
1466
1467 fseek( fileAsm, vspPointer, SEEK_SET );
1468
1469 while( !feof(fileAsm) ) {
1470
1471 po_buf_fgets( bufLine, fileAsm );
1472
1473 POBuffer result = po_buf_match(bufLine, " ADC *", v1 );
1474 if ( ! result ) result = po_buf_match(bufLine, " AND *", v1 );
1475 if ( ! result ) result = po_buf_match(bufLine, " EOR *", v1 );
1476 if ( ! result ) result = po_buf_match(bufLine, " LD* *", v2, v1 );
1477 if ( ! result ) result = po_buf_match(bufLine, " ORA *", v1 );
1478 if ( ! result ) result = po_buf_match(bufLine, " SBC *", v1 );
1479 if ( ! result ) result = po_buf_match(bufLine, " CMP *", v1 );
1480 if ( ! result ) result = po_buf_match(bufLine, " CPX *", v1 );
1481 if ( ! result ) result = po_buf_match(bufLine, " CPY *", v1 );
1482 if ( result ) {
1483 char * realVarName = strdup( v1->str );
1484 char * c = strstr( realVarName, "+" );
1485 if ( c ) {
1486 *c = 0;
1487 }
1488 c = strstr( realVarName, "#" );
1489 if ( c ) {
1490 strcopy( c, c+1 );
1491 }
1492 UnusedSymbol * tmp = currentlyUnusedSymbols;
1493 UnusedSymbol * previous = NULL;
1494 while( tmp ) {
1495 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1496 if ( previous ) {
1497 previous->next = tmp->next;
1498 } else {
1499 currentlyUnusedSymbols = tmp->next;
1500 }
1501 break;
1502 }
1503 previous = tmp;
1504 tmp = tmp->next;
1505 }
1506
1507 tmp = currentlyUnusedSymbolsQ;
1508 previous = NULL;
1509 while( tmp ) {
1510 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1511 if ( previous ) {
1512 previous->next = tmp->next;
1513 } else {
1514 currentlyUnusedSymbolsQ = tmp->next;
1515 }
1516 break;
1517 }
1518 previous = tmp;
1519 tmp = tmp->next;
1520 }
1521 }
1522
1523 if ( po_buf_match( bufLine, " ; VSP" ) ) {
1524 break;
1525 }
1526
1527 }
1528
1529 // printf( "REALLY UNUSED SYMBOLS: " );
1530 // s = currentlyUnusedSymbols;
1531 // while( s ) {
1532 // printf( "%s, ", s->realName );
1533 // s = s->next;
1534 // }
1535 // printf( "\n\n" );
1536
1537 fseek( fileAsm, vspPointer, SEEK_SET );
1538
1539 int line = 0;
1540
1541 po_buf_cpy(buf[0], "");
1542 po_buf_cpy(buf[1], "");
1543 po_buf_cpy(buf[2], "");
1544 po_buf_cpy(buf[3], "");
1545 po_buf_cpy(buf[4], "");
1546
1547 while( !feof(fileAsm) ) {
1548
1549 int endOfSection = 0;
1550
1551 if ( line >= 2 ) out(fileOptimized, buf[0]);
1552 po_buf_cpy(buf[0], buf[1]->str);
1553 po_buf_cpy(buf[1], buf[2]->str);
1554 po_buf_cpy(buf[2], buf[3]->str);
1555 po_buf_cpy(buf[3], buf[4]->str);
1556 po_buf_fgets( buf[4], fileAsm );
1557 // printf("(4): %s\n", buf[4]->str );
1558 while( isAComment( buf[4] ) && !endOfSection && !feof( fileAsm ) ) {
1559 // printf( " > comment: %s\n", buf[4]->str );
1560 if ( po_buf_match( buf[4], " ; VSP" ) ) {
1561 endOfSection = 1;
1562 }
1563 if(KEEP_COMMENTS) po_buf_cat(buf[3], buf[4]->str);
1564 po_buf_fgets( buf[4], fileAsm );
1565 }
1566 ++line;
1567
1568 // printf("Checking: - - - - - - - - - - -\n");
1569 // printf("0: %s\n", buf[0]->str );
1570 // printf("1: %s\n", buf[1]->str );
1571 // printf("2: %s\n", buf[2]->str );
1572 // printf("3: %s\n", buf[3]->str );
1573 // printf("4: %s\n", buf[4]->str );
1574 // printf("- - - - - - - - - - - checking\n");
1575
1576 if (
1577 po_buf_match( buf[0], " LDA #$*", v1 ) &&
1578 po_buf_match( buf[1], " STA *", v2 ) &&
1579 po_buf_match( buf[2], " LDA *", v3 ) &&
1580 po_buf_match( buf[3], " CMP *", v4 ) &&
1581 po_buf_cmp( v2, v4 ) == 0
1582 ) {
1583
1584 // printf("2: %s\n", buf[2]->str );
1585 // printf("3: %s\n", buf[3]->str );
1586 // printf("4: %s\n", buf[4]->str );
1587
1588 // printf(" RULE #2\n");
1589
1590 char * realVarName = strdup( v2->str );
1591 char * c = strstr( realVarName, "+" );
1592 if ( c ) {
1593 *c = 0;
1594 }
1595
1596 UnusedSymbol * tmp = currentlySymbols;
1597 while( tmp ) {
1598 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1599 break;
1600 }
1601 tmp = tmp->next;
1602 }
1603 if ( tmp ) {
1604 // printf( "found!\n\n" );
1605 // printf(" APPLIED #1\n");
1606 // optim( buf[0], RULE "unused temporary", NULL );
1607 optim( buf[0], RULE "unused temporary", NULL );
1608 optim( buf[1], RULE "unused temporary", NULL );
1609 optim( buf[3], RULE "unused temporary", "\tCMP #$%s", v1->str );
1610 ++_environment->removedAssemblyLines;
1611 ++_environment->removedAssemblyLines;
1612 }
1613
1614 } else if (
1615 po_buf_match( buf[0], " LDA *", v1 ) &&
1616 po_buf_match( buf[1], " STA *", v2 ) &&
1617 po_buf_match( buf[2], " LDA *", v3 ) &&
1618 po_buf_match( buf[3], " STA *", v4 ) &&
1619 po_buf_cmp( v2, v3 ) == 0
1620 ) {
1621
1622 // printf("2: %s\n", buf[2]->str );
1623 // printf("3: %s\n", buf[3]->str );
1624 // printf("4: %s\n", buf[4]->str );
1625
1626 // printf(" RULE #2\n");
1627
1628 char * realVarName = strdup( v2->str );
1629 char * c = strstr( realVarName, "+" );
1630 if ( c ) {
1631 *c = 0;
1632 }
1633
1634 UnusedSymbol * tmp = currentlySymbolsQ;
1635 while( tmp ) {
1636 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1637 break;
1638 }
1639 tmp = tmp->next;
1640 }
1641 if ( tmp ) {
1642 // printf( "found!\n\n" );
1643 // printf(" APPLIED #1\n");
1644 // optim( buf[0], RULE "unused temporary", NULL );
1645 // optim( buf[2], RULE "unused temporary", NULL );
1646 optim( buf[1], RULE "unused temporary", NULL );
1647 optim( buf[2], RULE "unused temporary", NULL );
1648 ++_environment->removedAssemblyLines;
1649 ++_environment->removedAssemblyLines;
1650 }
1651
1652 } else if (
1653 po_buf_match( buf[0], " LDA *", v1 ) &&
1654 po_buf_match( buf[1], " STA *", v2 ) &&
1655 po_buf_match( buf[2], " LDA *", v3 ) &&
1656 po_buf_cmp( v2, v3 ) == 0
1657 ) {
1658
1659 // printf(" RULE #1\n");
1660
1661 char * realVarName = strdup( v2->str );
1662 char * c = strstr( realVarName, "+" );
1663 if ( c ) {
1664 *c = 0;
1665 }
1666
1667 UnusedSymbol * tmp = currentlySymbolsQ;
1668 while( tmp ) {
1669 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1670 break;
1671 }
1672 tmp = tmp->next;
1673 }
1674 if ( tmp ) {
1675 // printf( "found!\n\n" );
1676 // printf(" APPLIED #1\n");
1677 // optim( buf[0], RULE "unused temporary", NULL );
1678 //optim( buf[1], RULE "unused temporary", NULL );
1679 optim( buf[2], RULE "unused temporary", NULL );
1680 ++_environment->removedAssemblyLines;
1681 }
1682
1683 // 001DE9r 1 8D rr rr STA _extractLetters_Ttmp34
1684 // 001DECr 1 AD rr rr LDA _extractLetters_Ttmp34
1685 // 001DEFr 1 8D rr rr STA _extractLetters_b2
1686
1687 } else if (
1688 po_buf_match( buf[2], " STA *", v1 ) && po_buf_match( buf[3], " LDA *", v2 ) && po_buf_match( buf[4], " STA *", v3 ) &&
1689 po_buf_cmp( v1, v2 ) == 0
1690 ) {
1691
1692 // printf("2: %s\n", buf[2]->str );
1693 // printf("3: %s\n", buf[3]->str );
1694 // printf("4: %s\n", buf[4]->str );
1695
1696 // printf(" RULE #2\n");
1697
1698 char * realVarName = strdup( v1->str );
1699 char * c = strstr( realVarName, "+" );
1700 if ( c ) {
1701 *c = 0;
1702 }
1703
1704 UnusedSymbol * tmp = currentlySymbolsQ;
1705 while( tmp ) {
1706 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1707 break;
1708 }
1709 tmp = tmp->next;
1710 }
1711 if ( tmp ) {
1712 // printf( "found!\n\n" );
1713 // printf(" APPLIED #1\n");
1714 // optim( buf[0], RULE "unused temporary", NULL );
1715 // optim( buf[2], RULE "unused temporary", NULL );
1716 optim( buf[3], RULE "unused temporary", NULL );
1717 ++_environment->removedAssemblyLines;
1718 }
1719
1720 }
1721
1722 if ( endOfSection ) {
1723 // printf("--------------------- endOfSection\n");
1724
1725 out(fileOptimized, buf[0]);
1726 out(fileOptimized, buf[1]);
1727 out(fileOptimized, buf[2]);
1728 out(fileOptimized, buf[3]);
1729 out(fileOptimized, buf[4]);
1730 break;
1731 }
1732
1733 // if ( po_buf_match( buf[1], " ; VSP" ) ) {
1734 // out(fileOptimized, buf[0]);
1735 // break;
1736 // }
1737
1738 }
1739
1740 vspPointer = ftell( fileAsm );
1741
1742 // printf( "vspPointer = %d\n", vspPointer );
1743
1744 currentlyUnusedSymbols = NULL;
1745 currentlyUnusedSymbolsQ = NULL;
1746
1747 }
1748
1749 }
1750
1751 fseek( fileAsm, vspPointer, SEEK_SET );
1752
1753 while( !feof(fileAsm) ) {
1754
1755 po_buf_fgets( bufLine, fileAsm );
1756
1757 out(fileOptimized, bufLine);
1758
1759 }
1760
1761 (void)fclose(fileAsm);
1762 (void)fclose(fileOptimized);
1763
1764 /* makes our generated file the new asm file */
1765 remove(_environment->asmFileName);
1766 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1767
1768}
1769
1770// static void optim_remove_unused_temporary( Environment * _environment ) {
1771
1772// int i;
1773
1774// POBuffer bufLine = TMP_BUF;
1775// POBuffer v1 = TMP_BUF;
1776// POBuffer v2 = TMP_BUF;
1777// POBuffer buf[2];
1778
1779// for(i=0; i<2; ++i) buf[i] = po_buf_new(0);
1780
1781// char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1782// FILE * fileAsm;
1783// FILE * fileOptimized;
1784
1785// sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1786
1787// fileAsm = fopen( _environment->asmFileName, "rt" );
1788// if(fileAsm == NULL) {
1789// perror(_environment->asmFileName);
1790// exit(-1);
1791// }
1792
1793// fileOptimized = fopen( fileNameOptimized, "wt" );
1794// if(fileOptimized == NULL) {
1795// perror(fileNameOptimized);
1796// exit(-1);
1797// }
1798
1799// UnusedSymbol * currentlyUnusedSymbols = NULL;
1800
1801// int vspPointer = 0;
1802
1803// while( !feof(fileAsm) ) {
1804
1805// po_buf_fgets( bufLine, fileAsm );
1806
1807// if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
1808// UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1809// memset( s, 0, sizeof( UnusedSymbol ) );
1810// s->realName = strdup( v1->str );
1811// s->next = currentlyUnusedSymbols;
1812// currentlyUnusedSymbols = s;
1813// } else if ( po_buf_match( bufLine, " ; VSP" ) ) {
1814
1815// // printf( "SYMBOLS COMPLETE: " );
1816// // UnusedSymbol * s = currentlyUnusedSymbols;
1817// // while( s ) {
1818// // printf( "%s, ", s->realName );
1819// // s = s->next;
1820// // }
1821// // printf( "\n\n" );
1822
1823// fseek( fileAsm, vspPointer, SEEK_SET );
1824
1825// while( !feof(fileAsm) ) {
1826
1827// po_buf_fgets( bufLine, fileAsm );
1828
1829// POBuffer result = po_buf_match(bufLine, " ADC *", v1 );
1830// if ( ! result ) result = po_buf_match(bufLine, " AND *", v1 );
1831// if ( ! result ) result = po_buf_match(bufLine, " EOR *", v1 );
1832// if ( ! result ) result = po_buf_match(bufLine, " LD* *", v2, v1 );
1833// if ( ! result ) result = po_buf_match(bufLine, " ORA *", v1 );
1834// if ( ! result ) result = po_buf_match(bufLine, " SBC *", v1 );
1835// if ( ! result ) result = po_buf_match(bufLine, " CMP *", v1 );
1836// if ( ! result ) result = po_buf_match(bufLine, " CPX *", v1 );
1837// if ( ! result ) result = po_buf_match(bufLine, " CPY *", v1 );
1838// if ( result ) {
1839// char * realVarName = strdup( v1->str );
1840// char * c = strstr( realVarName, "+" );
1841// if ( c ) {
1842// *c = 0;
1843// }
1844// c = strstr( realVarName, "#<" );
1845// if ( c ) {
1846// strcopy( c, c+2 );
1847// }
1848// c = strstr( realVarName, "#>" );
1849// if ( c ) {
1850// strcopy( c, c+2 );
1851// }
1852// c = strstr( realVarName, "#" );
1853// if ( c ) {
1854// strcopy( c, c+1 );
1855// }
1856// UnusedSymbol * tmp = currentlyUnusedSymbols;
1857// UnusedSymbol * previous = NULL;
1858// while( tmp ) {
1859// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1860// if ( previous ) {
1861// previous->next = tmp->next;
1862// } else {
1863// currentlyUnusedSymbols = tmp->next;
1864// }
1865// break;
1866// }
1867// previous = tmp;
1868// tmp = tmp->next;
1869// }
1870
1871// }
1872
1873// if ( po_buf_match( bufLine, " ; VSP" ) ) {
1874// break;
1875// }
1876
1877// }
1878
1879// // printf( "REALLY UNUSED SYMBOLS: " );
1880// // s = currentlyUnusedSymbols;
1881// // while( s ) {
1882// // printf( "%s, ", s->realName );
1883// // s = s->next;
1884// // }
1885// // printf( "\n\n" );
1886// fseek( fileAsm, vspPointer, SEEK_SET );
1887
1888// int line = 0;
1889
1890// while( !feof(fileAsm) ) {
1891
1892// if ( line >= 1 ) out(fileOptimized, buf[0]);
1893// po_buf_cpy(buf[0], buf[1]->str);
1894// po_buf_fgets( buf[1], fileAsm );
1895// ++line;
1896
1897// if( po_buf_match( buf[0], " LDA *", v1 ) && po_buf_match( buf[1], " STA *", v2 ) ) {
1898// char * realVarName = strdup( v2->str );
1899// char * c = strstr( realVarName, "+" );
1900// if ( c ) {
1901// *c = 0;
1902// }
1903// UnusedSymbol * tmp = currentlyUnusedSymbols;
1904// while( tmp ) {
1905// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1906// break;
1907// }
1908// tmp = tmp->next;
1909// }
1910// if ( tmp ) {
1911// optim( buf[0], RULE "unused temporary", NULL );
1912// optim( buf[1], RULE "unused temporary", NULL );
1913// ++_environment->removedAssemblyLines;
1914// ++_environment->removedAssemblyLines;
1915// }
1916// } else if( po_buf_match( buf[0], " STA *", v2 ) ) {
1917// char * realVarName = strdup( v2->str );
1918// char * c = strstr( realVarName, "+" );
1919// if ( c ) {
1920// *c = 0;
1921// }
1922// UnusedSymbol * tmp = currentlyUnusedSymbols;
1923// while( tmp ) {
1924// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1925// break;
1926// }
1927// tmp = tmp->next;
1928// }
1929// if ( tmp ) {
1930// optim( buf[0], RULE "unused temporary", NULL );
1931// ++_environment->removedAssemblyLines;
1932// }
1933// }
1934
1935// if ( po_buf_match( buf[1], " ; VSP" ) ) {
1936// out(fileOptimized, buf[0]);
1937// break;
1938// }
1939
1940// }
1941
1942// vspPointer = ftell( fileAsm );
1943
1944// // printf( "vspPointer = %d\n", vspPointer );
1945
1946// currentlyUnusedSymbols = NULL;
1947
1948// }
1949
1950// }
1951
1952// fseek( fileAsm, vspPointer, SEEK_SET );
1953
1954// while( !feof(fileAsm) ) {
1955
1956// po_buf_fgets( bufLine, fileAsm );
1957
1958// out(fileOptimized, bufLine);
1959
1960// }
1961
1962// (void)fclose(fileAsm);
1963// (void)fclose(fileOptimized);
1964
1965// /* makes our generated file the new asm file */
1966// remove(_environment->asmFileName);
1967// BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1968
1969// }
1970
1971static void optim_remove_comments( Environment * _environment ) {
1972
1973 int i;
1974
1975 POBuffer bufLine = TMP_BUF;
1976
1977 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1978 FILE * fileAsm;
1979 FILE * fileOptimized;
1980
1981 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1982
1983 fileAsm = fopen( _environment->asmFileName, "rt" );
1984 if(fileAsm == NULL) {
1985 perror(_environment->asmFileName);
1986 exit(-1);
1987 }
1988
1989 fileOptimized = fopen( fileNameOptimized, "wt" );
1990 if(fileOptimized == NULL) {
1991 perror(fileNameOptimized);
1992 exit(-1);
1993 }
1994
1995 while( !feof(fileAsm) ) {
1996
1997 po_buf_fgets( bufLine, fileAsm );
1998
1999 if ( !isAComment( bufLine ) ) {
2000 out( fileOptimized, bufLine );
2001 }
2002
2003 }
2004
2005 (void)fclose(fileAsm);
2006 (void)fclose(fileOptimized);
2007
2008 /* makes our generated file the new asm file */
2009 remove(_environment->asmFileName);
2010 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
2011
2012}
2013
2014/* main entry-point for this service */
2016 optim_remove_unused_temporary( _environment );
2017 //_environment->peepholeOptimizationLimit = 0;
2018 if ( _environment->peepholeOptimizationLimit > 0 ) {
2019 POBuffer buf[LOOK_AHEAD];
2020 int i;
2021
2022 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_new(0);
2023
2024 int optimization_limit_count = _environment->peepholeOptimizationLimit;
2025
2026 do {
2027 while(optim_pass(_environment, buf, PEEPHOLE)&&optimization_limit_count) {
2028 --optimization_limit_count;
2029 };
2030 optim_pass(_environment, buf, DEADVARS);
2031 } while(change&&optimization_limit_count);
2032 optim_pass(_environment, buf, RELOCATION1);
2033 optim_pass(_environment, buf, RELOCATION2);
2034
2035 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_del(buf[i]);
2037 }
2038 optim_remove_unused_temporary( _environment );
2039 if ( _environment->removeComments ) {
2040 optim_remove_comments(_environment);
2041 }
2042}
2043
2044void target_finalize( Environment * _environment ) {
2045
2046 if ( _environment->additionalInfoFile ) {
2047
2048 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
2049 FILE * fileAsm;
2050 FILE * fileListing;
2051 POBuffer bufferAsm = TMP_BUF;
2052 POBuffer bufferListing = TMP_BUF;
2053
2054 POBuffer bufferAddress = TMP_BUF;
2055 POBuffer bufferVersion = TMP_BUF;
2056 POBuffer bufferA = TMP_BUF;
2057 POBuffer bufferB = TMP_BUF;
2058 POBuffer bufferC = TMP_BUF;
2059 POBuffer bufferD = TMP_BUF;
2060 POBuffer bufferE = TMP_BUF;
2061
2062 int sourceLine = -1;
2063
2064 _environment->currentSourceLineAnalyzed = 0;
2065 _environment->bytesProduced = 0;
2066
2067 adiline0( "A:0" );
2068
2069 fileAsm = fopen( _environment->asmFileName, "rb" );
2070 if(fileAsm == NULL) {
2071 perror(_environment->asmFileName);
2072 exit(-1);
2073 }
2074
2075 fileListing = fopen( _environment->listingFileName, "rb" );
2076 if(fileListing == NULL) {
2077 perror(_environment->listingFileName);
2078 exit(-1);
2079 }
2080
2081 int posUpdated = 0;
2082 int pos = 0;
2083
2084 while( !feof(fileAsm) && !feof(fileListing)) {
2085
2086 po_buf_fgets( bufferAsm, fileAsm );
2087 int leftPadding = po_buf_trim( bufferAsm );
2088
2089 if ( isAComment( bufferAsm ) ) {
2090 POBuffer ln = TMP_BUF;
2091 if (po_buf_match( bufferAsm, "; L:*", ln ) ) {
2092 sourceLine = atoi( ln->str );
2093 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
2094 adiline2( "AB:0:%d:%d",
2095 _environment->currentSourceLineAnalyzed, _environment->bytesProduced );
2096 _environment->currentSourceLineAnalyzed = sourceLine;
2097 _environment->bytesProduced = 0;
2098 }
2099 }
2100 continue;
2101 }
2102
2103 *bufferListing->str = 0;
2104 pos = ftell( fileListing );
2105 posUpdated = 0;
2106 po_buf_trim( bufferAsm );
2107 while( !feof(fileListing) && (strstr( bufferListing->str, bufferAsm->str ) == NULL) ) {
2108 po_buf_fgets( bufferListing, fileListing );
2109 if ( ! posUpdated ) {
2110 posUpdated = 1;
2111 pos = ftell( fileListing );
2112 }
2113 po_buf_trim( bufferListing );
2114 }
2115
2116 if ( feof(fileListing) ) {
2117
2118 } else {
2119 pos = ftell( fileListing );
2120 char * bufferAsmEscaped = strdup( bufferAsm->str );
2121 for( int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
2122 if ( bufferAsmEscaped[i] == ':' ) {
2123 bufferAsmEscaped[i] = 6;
2124 }
2125 if ( bufferAsmEscaped[i] == 9 ) {
2126 bufferAsmEscaped[i] = ' ';
2127 }
2128 }
2129
2130 if ( po_buf_match( bufferListing, "* * * * * *", bufferAddress, bufferVersion,
2131 bufferA, bufferB, bufferC, bufferD ) ) {
2132 if ( bufferAddress->len == 7 ) {
2133 if ( bufferA->len == 2 &&
2134 ( ( isxdigit( bufferA->str[0] ) && isxdigit( bufferA->str[1] ) ) || strcmp( bufferA->str, "rr" ) == 0 )
2135 ) _environment->bytesProduced += 1;
2136 if ( bufferB->len == 2 &&
2137 ( ( isxdigit( bufferB->str[0] ) && isxdigit( bufferB->str[1] ) ) || strcmp( bufferB->str, "rr" ) == 0 )
2138 ) _environment->bytesProduced += 1;
2139 if ( bufferC->len == 2 &&
2140 ( ( isxdigit( bufferC->str[0] ) && isxdigit( bufferC->str[1] ) ) || strcmp( bufferC->str, "rr" ) == 0 )
2141 ) _environment->bytesProduced += 1;
2142 if ( bufferD->len == 2 &&
2143 ( ( isxdigit( bufferD->str[0] ) && isxdigit( bufferD->str[1] ) ) || strcmp( bufferD->str, "rr" ) == 0 )
2144 ) _environment->bytesProduced += 1;
2145 }
2146 } else if ( po_buf_match( bufferListing, "* * * * *", bufferAddress, bufferVersion,
2147 bufferA, bufferB, bufferC ) ) {
2148 if ( bufferAddress->len == 7 ) {
2149 if ( bufferA->len == 2 &&
2150 ( ( isxdigit( bufferA->str[0] ) && isxdigit( bufferA->str[1] ) ) || strcmp( bufferA->str, "rr" ) == 0 )
2151 ) _environment->bytesProduced += 1;
2152 if ( bufferB->len == 2 &&
2153 ( ( isxdigit( bufferB->str[0] ) && isxdigit( bufferB->str[1] ) ) || strcmp( bufferB->str, "rr" ) == 0 )
2154 ) _environment->bytesProduced += 1;
2155 if ( bufferC->len == 2 &&
2156 ( ( isxdigit( bufferC->str[0] ) && isxdigit( bufferC->str[1] ) ) || strcmp( bufferC->str, "rr" ) == 0 )
2157 ) _environment->bytesProduced += 1;
2158 }
2159 } else if ( po_buf_match( bufferListing, "* * * *", bufferAddress, bufferVersion,
2160 bufferA, bufferB ) ) {
2161 if ( bufferAddress->len == 7 ) {
2162 if ( bufferA->len == 2 &&
2163 ( ( isxdigit( bufferA->str[0] ) && isxdigit( bufferA->str[1] ) ) || strcmp( bufferA->str, "rr" ) == 0 )
2164 ) _environment->bytesProduced += 1;
2165 if ( bufferB->len == 2 &&
2166 ( ( isxdigit( bufferB->str[0] ) && isxdigit( bufferB->str[1] ) ) || strcmp( bufferB->str, "rr" ) == 0 )
2167 ) _environment->bytesProduced += 1;
2168 }
2169 } else if ( po_buf_match( bufferListing, "* * *", bufferAddress, bufferVersion,
2170 bufferA ) ) {
2171 if ( bufferAddress->len == 7 ) {
2172 if ( bufferA->len == 2 &&
2173 ( ( isxdigit( bufferA->str[0] ) && isxdigit( bufferA->str[1] ) ) || strcmp( bufferA->str, "rr" ) == 0 )
2174 ) _environment->bytesProduced += 1;
2175 }
2176 }
2177 adiline4( "AL:0:%d:%*s%s",
2178 _environment->currentSourceLineAnalyzed, leftPadding, "", bufferAsmEscaped );
2179 }
2180
2181 fseek( fileListing, pos, SEEK_SET );
2182
2183 }
2184
2185 if ( _environment->currentSourceLineAnalyzed ) {
2186 adiline1( "AF:0:%d", _environment->bytesProduced );
2187 }
2188
2189 (void)fclose(fileListing);
2190 (void)fclose(fileAsm);
2191
2192 }
2193
2194}
char * get_temporary_filename(Environment *_environment)
#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_INLINE
Definition _optimizer.c:675
int nb_wr
Definition _optimizer.c:680
#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
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
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
char * str
Definition ugbc.h:293
int len
Definition ugbc.h:294
struct _UnusedSymbol * next
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)