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