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 /* Zilog Z80 optimizations for ugBasic by
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 <stdlib.h>
79#include <ctype.h>
80
81/****************************************************************************
82 * CODE SECTION
83 ****************************************************************************/
84
85#define DIRECT_PAGE 0x2100
86#define LOOK_AHEAD 5
87#define ALLOW_UNSAFE 1
88#define KEEP_COMMENTS 1
89
90#define DO_DIRECT_PAGE 1
91#define DO_INLINE 1
92#define DO_UNREAD 1
93
94/* returns an UPPER-cased char */
95static inline char _toUpper(char a) {
96 return (a>='a' && a<='z') ? a-'a'+'A' : a;
97}
98
99/* returns true if char is end of line ? */
100static inline int _eol(char c) {
101 return c=='\0' || c=='\n';
102}
103
104/* returns true if both char matches */
105static inline int _eq(char pat, char txt) {
106 return (pat<=' ') ? (txt<=' ') : (_toUpper(pat)==_toUpper(txt));
107}
108
109/* returns true if the POBuffer matches a comment or and empty line */
111 char * _buffer = buf->str;
112
113 if ( ! *_buffer ) {
114 return 1;
115 }
116 if ( *_buffer == '\r' || *_buffer == '\n' ) {
117 return 1;
118 }
119 while( * _buffer ) {
120 if ( *_buffer == ' ' || *_buffer == '\t' ) {
121 ++_buffer;
122 } else if ( *_buffer == ';' ) {
123 return 1;
124 } else {
125 return 0;
126 }
127 }
128 return 0;
129}
130
131/* number of lines changed */
132static int change = 0;
133static int peephole_pass = 0;
134static int num_dp = 0; /* number of variables relocated to direct-page */
135static int num_inlined = 0; /* number of variables inlined */
136static int num_unread = 0; /* number of variables not read */
137
138#ifdef __GNUC__
139static void optim(POBuffer buf, const char *rule, const char *repl, ...)
140 __attribute__ ((format (printf, 3, 4)));
141#endif
142
143#define R__(X) #X
144#define R_(X) R__(X)
145#define RULE "r" R_(__LINE__) " "
146
147/* replaces the POBuffer with an optimized code */
148/* original POBuffer is kept as comment */
149static void optim(POBuffer buf, const char *rule, const char *repl, ...) {
150 va_list ap;
151 POBuffer tmp = TMP_BUF;
152 char *s;
153
154 va_start(ap, repl);
155 po_buf_cpy(tmp, "");
156
157 /* add our own comment if any */
158 if(rule) po_buf_printf(tmp, "; peephole(%d): %s\n", peephole_pass, rule);
159
160 /* comment out line */
161 po_buf_cat(tmp, ";");
162
163 /* copy upto the end of string or upto end of string */
164 if ( (s = strchr(buf->str, '\n')) != NULL) *s = '\0'; /* cut at \n */
165 po_buf_cat(tmp, buf->str);
166 if( s != NULL ) po_buf_add(tmp, *s++ = '\n'); /* restore \n */
167
168 /* insert replacement if provided */
169 if(repl) {
170 po_buf_vprintf(tmp, repl, ap);
171 po_buf_cat(tmp, "\n");
172 }
173
174 /* copy remaining comments */
175 if(s) po_buf_cat(tmp, s);
176
177 /* write result back into input POBuffer */
178 po_buf_cpy(buf, tmp->str);
179
180 /* one more change */
181 ++change;
182
183 va_end(ap);
184}
185
186/* returns true if the POBuffer matches a zero value */
187static int isZero(char *s) {
188 if(*s == '$') ++s;
189 while(*s == '0') ++s;
190 return _eq(' ', *s);
191}
192static int _isZero(POBuffer buf) {
193 return buf!=NULL && isZero(buf->str);
194}
195static int isNumber(char *s) {
196 for( int i=0, c=strlen(s); i<c; ++i ) {
197 if ( !isdigit( s[i] ) ) {
198 return 0;
199 }
200 }
201 return 1;
202}
203static int _isNumber(POBuffer buf) {
204 return buf!=NULL && isNumber(buf->str);
205}
206
207/* perform basic peephole optimization with a length-4 look-ahead */
208static void basic_peephole(POBuffer buf[LOOK_AHEAD], int zA, int zB) {
209 /* allows presumably safe operations */
210 int unsafe = ALLOW_UNSAFE;
211
212 /* various local buffers */
213 POBuffer v1 = TMP_BUF;
214 POBuffer v2 = TMP_BUF;
215 POBuffer v3 = TMP_BUF;
216 POBuffer v4 = TMP_BUF;
217
218 /* a bunch of rules */
219
220 // ;Instead of:
221 // ld a,0
222 // ;Try this:
223 // xor a ;disadvantages: changes flags
224 // ;or
225 // sub a ;disadvantages: changes flags
226 // ; -> save 1 byte and 3 T-states
227 if( po_buf_match( buf[0], " LD *, *", v1, v2) && strchr( "A", _toUpper(*v1->str) ) && _isNumber( v2 ) && atoi( v2->str ) == 0 ) {
228 optim( buf[0], RULE "(LD A, 0)->(XOR A)", "\tXOR %c", _toUpper(*v1->str) );
229 }
230
231 // ;Instead of
232 // ld b,$20
233 // ld c,$30
234 // ;try this
235 // ld bc,$2030
236 // ;or this
237 // ld bc,(b_num * 256) + c_num ;where b_num goes to b register and c_num to c register
238 // ; -> save 1 byte and 4 T-states
239 if( po_buf_match( buf[0], " LD B, $*", v1) && po_buf_match( buf[1], " LD C, $*", v2) ) {
240 optim( buf[0], RULE "(LD B, x; LD C, x)->(LD BC, xx)", "\tLD BC, ($%s * 256) + $%s", v1->str, v2->str );
241 optim( buf[1], "", NULL );
242 }
243
244 //
245 if( po_buf_match( buf[0], " LD A, *", v1) &&
246 po_buf_match( buf[1], " LD (*), A", v2) &&
247 po_buf_match( buf[2], " LD A, *", v3) &&
248 po_buf_strcmp(v1,v3)==0
249 ) {
250 optim( buf[2], RULE "(LD A, x; LD (x), A; LD A, x)->(LD A, x; LD (x), A)", NULL );
251 }
252
253 // ;Instead of
254 // ld a,$42
255 // ld (hl),a
256 // ;try this
257 // ld (hl),$42
258 // ; -> save 1 byte and 4 T-states
259 // if( po_buf_match( buf[0], " LD A, $*", v1) &&
260 // po_buf_match( buf[1], " LD (HL), A")
261 // ) {
262 // optim( buf[0], RULE "(LD A, x; LD (HL), A)->(LD (HL), x)", "\tLD HL, $%s", v1->str );
263 // optim( buf[1], NULL, NULL );
264 // }
265
266 // ;Instead of
267 // ld A, (var)
268 // inc a
269 // ld (var),a
270 // ;try this ;Note: if hl is not tied up, use indirection:
271 // ld hl,var
272 // inc (hl)
273 // ld A, (hl) ;if you don't need (hl) in a, delete this line
274 // ; -> save 2 bytes and 2 T-states
275 // if( po_buf_match( buf[0], " LD A, (*)", v1) &&
276 // po_buf_match( buf[1], " INC A") &&
277 // po_buf_match( buf[2], " LD (*), A", v2 ) &&
278 // po_buf_strcmp( v1, v2 ) == 0
279 // ) {
280 // optim( buf[0], RULE "(LD A, (x); INC A; LD (x), A)->(LD HL, x; INC (HL); LD A, (HL)", "\tLD HL, %s", v1->str );
281 // optim( buf[1], NULL, "\tINC (HL)" );
282 // optim( buf[2], NULL, "\tLD A, (HL)" );
283 // }
284
285 // ; Instead of :
286 // ld a, (hl)
287 // ld (de), a
288 // inc hl
289 // inc de
290 // ; Use :
291 // ldi
292 // inc bc
293 // ; -> save 1 byte and 4 T-states
294 // if( po_buf_match( buf[0], " LD A, (HL)") &&
295 // po_buf_match( buf[1], " LD (DE), A" ) &&
296 // po_buf_match( buf[2], " INC HL" ) &&
297 // po_buf_match( buf[3], " INC DE" )
298 // ) {
299 // optim( buf[0], RULE "(LD A, (HL); LD (DE), A; INC HL; INC DE)->(LDI; INC BC)", "\tLDI" );
300 // optim( buf[1], NULL, "\tINC BC" );
301 // optim( buf[2], NULL, NULL );
302 // optim( buf[3], NULL, NULL );
303 // }
304
305 // ;Instead of:
306 // cp 0
307 // ;Use
308 // or a
309 // ; -> save 1 byte and 3 T-states
310 // if( po_buf_match( buf[0], " CP 0") ) {
311 // optim( buf[0], RULE "(CP 0)->(OR A)", "\tOR A" );
312 // }
313
314 // xor %11111111
315 // ; >
316 // cpl
317 // ; -> save 1 byte and 3 T-states
318 if( po_buf_match( buf[0], " XOR $FF") ) {
319 optim( buf[0], RULE "(XOR $FF)->(CPL)", "\tCPL" );
320 }
321
322 // ;Instead of
323 // ld de,767
324 // or a ;reset carry so sbc works as a sub
325 // sbc hl,de
326 // ;try this
327 // ld de,-767 ;negation of de
328 // add hl,de
329 // ; -> 2 bytes and 8 T-states !
330 // if(
331 // po_buf_match( buf[0], " LD DE, $*", v1 ) &&
332 // po_buf_match( buf[1], " OR A" ) &&
333 // po_buf_match( buf[2], " SBC HL, DE" )
334 // ) {
335 // optim( buf[0], RULE "(LD DE, x; OR A; SBC HL, DE)->(LD DE, -x; ADD HL, DE)", "\tLD DE, -$%s", v1->str );
336 // optim( buf[1], NULL, "\tADD HL, DE" );
337 // }
338
339 // ;Instead of
340 // sla l
341 // rl h ; I've actually seen this!
342 // ; >
343 // add hl,hl
344 // ; -> save 3 bytes and 5 T-states
345 if(
346 po_buf_match( buf[0], " SLA L" ) &&
347 po_buf_match( buf[1], " RL H" )
348 ) {
349 optim( buf[0], RULE "(SLA+RL)->(ADD)", "\tADD HL, HL" );
350 optim( buf[1], NULL, NULL );
351 }
352
353 // ; Instead of
354 // and 1
355 // cp 1
356 // jr z,foo
357 // ; >
358 // and 1 ;and sets zero flag, no need for cp
359 // jr nz,foo
360 // ; -> save 2 bytes and 7 T-states
361 // if(
362 // po_buf_match( buf[0], " AND $*", v1 ) &&
363 // po_buf_match( buf[1], " CP $*", v2 ) &&
364 // po_buf_match( buf[2], " JR Z, *", v3 ) &&
365 // po_buf_strcmp( v1, v2 ) == 0
366 // ) {
367 // optim( buf[1], NULL, NULL );
368 // optim( buf[2], RULE "(AND+CP+JZ)->(AND+JNZ)", " JR NZ, %s", v3->str );
369 // }
370
371 // ;Instead of
372 // call xxxx
373 // ret
374 // ;try this
375 // jp xxxx
376 // ;only do this if the pushed pc to stack is not passed to the call. Example: some kind of inline vputs.
377 // ; -> save 1 byte and 17 T-states
378 if(
379 po_buf_match( buf[0], " CALL *", v1 ) &&
380 po_buf_match( buf[1], " RET" ) &&
381 !po_buf_match( buf[1], " RETI" ) &&
382 !po_buf_match( buf[1], " RET *", v2 )
383 ) {
384 optim( buf[0], RULE "(CALL+RET)->(JP)", "\tJP %s", v1->str );
385 optim( buf[1], NULL, NULL );
386 }
387
388 // ;Never use:
389 // dec B
390 // jr NZ,loop ;I have seen this...
391 // ;Use:
392 // djnz loop
393 // ; save 1 byte and 3 T-states
394 if(
395 po_buf_match( buf[0], " DEC B" ) &&
396 po_buf_match( buf[1], " JR NZ, *", v1 )
397 ) {
398 optim( buf[0], RULE "(DEC B+JR NZ)->(DJNZ)", "\tDJNZ %s", v1->str );
399 optim( buf[1], NULL, NULL );
400 }
401
402 if(
403 po_buf_match( buf[0], " LD A, *", v1 ) &&
404 !po_buf_match( buf[1], " CALL *", v2 ) &&
405 po_buf_match( buf[1], " LD A, *", v3 ) &&
406 po_buf_strcmp( v1, v3 ) == 0 &&
407 strstr( v1->str, "$FF" ) == NULL
408#if defined(__gb__)
409 && strstr( v1->str, "rP1" ) == NULL
410#endif
411 ) {
412 optim( buf[0], RULE "(LD A, *; LD A, *)->(LD, A)", NULL );
413 }
414
415}
416
417/* optimizations related to variables */
418
419/* variables database */
420static struct {
421 struct var {
422 char *name;
423#define NO_REORG 1
424#define NO_DP 2
425#define NO_INLINE 4
426#define NO_REMOVE 8
427 int flags;
428 int size;
429 int nb_rd;
430 int nb_wr;
431 int offset; /* 0=unchanged, >0 offset to page 0; -1 = candidate for inlining, -2 = inlined */
432 char *init;
433 } *tab;
435 int size;
437} vars;
438
439/* clears the database */
440static void vars_clear(void) {
441 int i;
442 for(i=0; i<vars.size; ++i) {
443 struct var *v = &vars.tab[i];
444 free(v->name);
445 if(v->init) free(v->init);
446 }
447 vars.size = 0;
448 vars.page0_max = 0;
449}
450
451/* gets (or creates) an entry for a variable from the data-base */
452struct var *vars_get(POBuffer _name) {
453 char *name = _name->str;
454 struct var *ret = NULL;
455 int i;
456
457 char *s=strchr(name,'+');
458 if(s) *s='\0';
459
460 for(i=0; i<vars.size ; ++i) {
461 if(strcmp(vars.tab[i].name, name)==0) {
462 ret = &vars.tab[i];
463 }
464 }
465 if(ret == NULL) {
466 if(vars.size == vars.capacity) {
467 vars.capacity += 16;
468 vars.tab = realloc(vars.tab, sizeof(*vars.tab)*vars.capacity);
469 }
470 ret = &vars.tab[vars.size++];
471 ret->name = strdup(name);
472 ret->flags = 0;
473 ret->size = 0;
474 ret->nb_rd = 0;
475 ret->nb_wr = 0;
476 ret->offset = 0;
477 ret->init = NULL;
478 }
479 if(s) *s='+';
480
481 return ret;
482}
483
484static int vars_ok(POBuffer name) {
485
486 if(po_buf_match(name, "^_Tstr")) return 0;
487 if(po_buf_match(name, "_^_Tstr")) return 0;
488 if(po_buf_match(name, "_label")) return 0;
489 if(po_buf_match(name, "BINTO^")) return 0;
490
491 if(name->str[0]=='_') return 1;
492 if(po_buf_match(name, "CLIP")) return 1;
493 if(po_buf_match(name, "XCUR")) return 1;
494 if(po_buf_match(name, "YCUR")) return 1;
495 if(po_buf_match(name, "CURRENT")) return 1;
496 if(po_buf_match(name, "FONT")) return 1;
497 if(po_buf_match(name, "TEXT")) return 1;
498 if(po_buf_match(name, "LAST")) return 1;
499 if(po_buf_match(name, "XGR")) return 1;
500 if(po_buf_match(name, "YGR")) return 1;
501 if(po_buf_match(name, "FREE_")) return 1;
502
503 return 0;
504}
505
506/* look for variable uses and collect data about he variables */
507static void vars_scan(POBuffer buf[LOOK_AHEAD]) {
508 POBuffer tmp = TMP_BUF;
509 POBuffer arg = TMP_BUF;
510 POBuffer ofs = TMP_BUF;
511
512 // if( match( buf[0], " * _*+", NULL, buf) ) {
513 // struct var *v = vars_get(buf);
514 // v->flags |= NO_INLINE;
515 // }
516
517 if( po_buf_match( buf[0], " LD *, (*+*)", tmp, arg, ofs ) ) { if(vars_ok(arg)) {
518 struct var *v = vars_get(arg);
519 v->nb_rd++;
520 } } else if( po_buf_match( buf[0], " LD *, (*+*)", tmp, arg, ofs ) ) { if(vars_ok(arg)) {
521 struct var *v = vars_get(arg);
522 v->nb_rd++;
523 } } else if( po_buf_match( buf[0], " LD *, (*)", tmp, arg ) ) { if(vars_ok(arg)) {
524 struct var *v = vars_get(arg);
525 v->nb_rd++;
526 } } else if( po_buf_match( buf[0], " LD *,(*)", tmp, arg ) ) { if(vars_ok(arg)) {
527 struct var *v = vars_get(arg);
528 v->nb_rd++;
529 } }
530
531 if (po_buf_match( buf[0], " LD (*+*), *", arg, ofs, tmp) ) { if(vars_ok(arg)) {
532 struct var *v = vars_get(arg);
533 v->nb_wr++;
534 } } else if (po_buf_match( buf[0], " LD (*+*),*", arg, ofs, tmp) ) { if(vars_ok(arg)) {
535 struct var *v = vars_get(arg);
536 v->nb_wr++;
537 } } else if (po_buf_match( buf[0], " LD (*), *", arg, tmp) ) { if(vars_ok(arg)) {
538 struct var *v = vars_get(arg);
539 v->nb_wr++;
540 } } else if (po_buf_match( buf[0], " LD (*),*", arg, tmp) ) { if(vars_ok(arg)) {
541 struct var *v = vars_get(arg);
542 v->nb_wr++;
543 } }
544
545 if (po_buf_match( buf[0], " LD *, *", arg, tmp) &&
546 strstr("A B C D E AD BC DE HL IX IY", strtoupper(arg->str))!=NULL
547 ) {
548 if(vars_ok(tmp)) {
549 struct var *v = vars_get(tmp);
550 v->nb_rd++;
551 }
552 }
553
554 if (po_buf_match( buf[0], " LD *,*", arg, tmp) &&
555 strstr("A B C D E AD BC DE HL IX IY", strtoupper(arg->str))!=NULL
556 ) {
557 if(vars_ok(tmp)) {
558 struct var *v = vars_get(tmp);
559 v->nb_rd++;
560 }
561 }
562
563 if( po_buf_match( buf[0], " *: defs *", tmp, arg) && vars_ok(tmp)) {
564 struct var *v = vars_get(tmp);
565 v->size = atoi(arg->str);
566 v->init = strdup("1-1");
567 }
568
569 if( po_buf_match(buf[0], " *: defb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
570 struct var *v = vars_get(tmp);
571 v->size = 1;
572 v->init = strdup(isZero(arg->str) ? "1-1" : arg->str);
573 }
574
575 if( po_buf_match(buf[0], " *: defw *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
576 struct var *v = vars_get(tmp);
577 v->size = 2;
578 v->init = strdup(arg->str);
579 }
580
581 if( po_buf_match(buf[0], " * = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
582 struct var *v1 = vars_get(tmp);
583 if ( v1 ) {
584 v1->nb_rd++;
585 }
586 struct var *v2 = vars_get(arg);
587 if ( v2 ) {
588 v2->nb_rd++;
589 }
590 } else if( po_buf_match(buf[0], "* = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
591 struct var *v1 = vars_get(tmp);
592 if ( v1 ) {
593 v1->nb_rd++;
594 }
595 struct var *v2 = vars_get(arg);
596 if ( v2 ) {
597 v2->nb_rd++;
598 }
599 }
600
601}
602
603/* compares two variables according to their access-count */
604static int vars_cmp(const void *_a, const void *_b) {
605 const struct var *a = _a;
606 const struct var *b = _b;
607
608 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
609
610 return -(diff!=0 ? diff : strcmp(a->name, b->name)); // Ttmp < Tstr
611}
612
613/* removes unread variables */
614static void vars_remove(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
615 POBuffer var = TMP_BUF;
616 POBuffer op = TMP_BUF;
617 POBuffer ofs = TMP_BUF;
618
619 if(!DO_UNREAD) return;
620
621 /* unread */
622 if(po_buf_match( buf[0], " LD (*+*), *", var, ofs, op) && vars_ok(var)) {
623 struct var *v = vars_get(var);
624 if(v->nb_rd == 0 && v->offset!=-2) {
625 v->offset = 0;
626 optim(buf[0], "unread", NULL);
627 ++_environment->removedAssemblyLines;
628 }
629 } else if(po_buf_match( buf[0], " LD (*), *", var, op) && vars_ok(var)) {
630 struct var *v = vars_get(var);
631 if(v->nb_rd == 0 && v->offset!=-2) {
632 v->offset = 0;
633 optim(buf[0], "unread", NULL);
634 ++_environment->removedAssemblyLines;
635 }
636 }
637
638 /* remove changed variables */
639 if(po_buf_match( buf[0], " *: DEFS ", var)
640 || po_buf_match( buf[0], " *: DEFB ", var)
641 || po_buf_match( buf[0], " *: DEFW ", var) ) if(vars_ok(var)) {
642 struct var *v = vars_get(var);
643 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags & NO_REMOVE) && v->offset!=-2) {
644 optim(buf[0], "unread",NULL);
645 ++num_unread;
646 ++_environment->removedAssemblyLines;
647 }
648 }
649}
650
651/* collapse all heading spaces into a single tabulation */
652static void out(FILE *f, POBuffer _buf) {
653 char *s = _buf->str;
654 int tab = 0;
655 while(*s==' ' || *s=='\t') {tab = 1; ++s;}
656 if(tab) fputs("\t", f);
657 fputs(s, f);
658}
659
660/* remove space that is sometimes used in indexing mode and makes the optimized produce bad dcode */
661static void fixes_indexed_syntax(POBuffer buf) {
662 char *s = buf->str;
663
664 /* not an instruction */
665 if(!_eq(' ', *s)) return;
666
667 /* skip over spaces */
668 do ++s; while(*s && _eq(' ', *s));
669
670 /* comment */
671 if(*s==';') return;
672
673 /* skip over instruction */
674 while(*s && !_eq(' ', *s)) ++s;
675 if(!*s) return;
676
677 /* skip over spaces */
678 do ++s; while(*s && _eq(' ', *s));
679 if(!*s) return;
680
681 /* process argment */
682 do ++s; while(*s && !_eq(' ', *s));
683 if(!*s) return;
684
685}
686
687/* various kind of optimization */
688static int optim_pass( Environment * _environment, POBuffer buf[LOOK_AHEAD], PeepHoleOptimizationKind kind) {
689 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
690 FILE * fileAsm;
691 FILE * fileOptimized;
692 int i;
693 int still_to_go = LOOK_AHEAD;
694
695 int line = 0;
696 int zA = 0, zB = 0;
697
698 int sourceLine = -1;
699
700 _environment->currentSourceLineAnalyzed = 0;
701 _environment->removedAssemblyLines = 0;
702
703 adiline2( "POP:0:%d:%d", peephole_pass, kind );
704
705 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
706
707 /* prepare for phase */
708 switch(kind) {
709 case DEADVARS:
710 ++peephole_pass;
711 num_unread = 0;
712 break;
713
714 case RELOCATION1:
715 ++peephole_pass;
716 // vars_prepare_relocation();
717 break;
718
719 case RELOCATION2:
720 break;
721
722 case PEEPHOLE:
723 ++peephole_pass;
724 // vars_clear();
725 break;
726 }
727
728 fileAsm = fopen( _environment->asmFileName, "rt" );
729 if(fileAsm == NULL) {
730 perror(_environment->asmFileName);
731 exit(-1);
732 }
733
734 fileOptimized = fopen( fileNameOptimized, "wt" );
735 if(fileOptimized == NULL) {
736 perror(fileNameOptimized);
737 exit(-1);
738 }
739
740 /* clears our look-ahead buffers */
741 for(i = 0; i<LOOK_AHEAD; ++i) po_buf_cpy(buf[i], "");
742
743 /* global change flag */
744 change = 0;
745
746 while( still_to_go ) {
747 /* print out oldest POBuffer */
748 if ( line >= LOOK_AHEAD ) out(fileOptimized, buf[0]);
749
750 /* shift the buffers */
751 for(i=0; i<LOOK_AHEAD-1; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
752
753 /* read next line, merging adjacent comments */
754 if(feof(fileAsm)) {
755 --still_to_go;
756 po_buf_cpy(buf[LOOK_AHEAD-1], "");
757 } else do {
758 /* read next line */
759 po_buf_fgets( buf[LOOK_AHEAD-1], fileAsm );
760 fixes_indexed_syntax(buf[LOOK_AHEAD-1]);
761 /* merge comment with previous line if we do not overflow the POBuffer */
762 if(isAComment(buf[LOOK_AHEAD-1])) {
763 POBuffer ln = TMP_BUF;
764 if (po_buf_match( buf[LOOK_AHEAD-1], " ; L:*", ln ) ) {
765 sourceLine = atoi( ln->str );
766 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
767 adiline3( "POL:0:%d:%d:%d",
768 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
769 _environment->currentSourceLineAnalyzed = sourceLine;
770 _environment->removedAssemblyLines = 0;
771 }
772 }
773 if(KEEP_COMMENTS) po_buf_cat(buf[LOOK_AHEAD-2], buf[LOOK_AHEAD-1]->str);
774 po_buf_cpy(buf[LOOK_AHEAD-1], "");
775 } else break;
776 } while(!feof(fileAsm));
777
778 switch(kind) {
779 case PEEPHOLE:
780 basic_peephole(buf, zA, zB);
781
782 /* only look fo variable when no peephole has been performed */
783 if(change == 0) vars_scan(buf);
784 break;
785
786 case DEADVARS:
787 vars_remove(_environment, buf);
788 break;
789
790 case RELOCATION1:
791 case RELOCATION2:
792 // vars_relocate(buf);
793 break;
794 }
795
796 ++line;
797 }
798
799 adiline3( "POL:0:%d:%d:%d",
800 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
801
802 /* log info at the end of the file */
803 switch(kind) {
804 case PEEPHOLE:
805 fprintf(fileOptimized, "; peephole: pass %d, %d change%s.\n", peephole_pass,
806 change, change>1 ?"s":"");
807 break;
808
809 case DEADVARS:
810 fprintf(fileOptimized, "; peephole: pass %d, %d var%s removed.\n", peephole_pass,
811 num_unread, num_unread>1 ?"s":"");
812 break;
813
814 case RELOCATION2:
815 fprintf(fileOptimized, "; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
816 num_dp, num_dp>1 ?"s":"",
817 num_inlined, num_inlined>1 ? "s":"");
818 break;
819
820 default:
821 break;
822 }
823
824 (void)fclose(fileAsm);
825 (void)fclose(fileOptimized);
826
827 /* makes our generated file the new asm file */
828 remove(_environment->asmFileName);
829 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
830
831 return change;
832}
833
834typedef struct _UnusedSymbol {
835
836 char * realName;
837
838 struct _UnusedSymbol * next;
839
841
842// static int optim_remove_unused_temporary( Environment * _environment ) {
843
844// int i;
845// POBuffer bufLine = TMP_BUF;
846// POBuffer v1 = TMP_BUF;
847// POBuffer v2 = TMP_BUF;
848// POBuffer buf[2];
849
850// for(i=0; i<2; ++i) buf[i] = po_buf_new(0);
851
852// char fileNameOptimized[MAX_TEMPORARY_STORAGE];
853// FILE * fileAsm;
854// FILE * fileOptimized;
855
856// sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
857
858// fileAsm = fopen( _environment->asmFileName, "rt" );
859// if(fileAsm == NULL) {
860// perror(_environment->asmFileName);
861// exit(-1);
862// }
863
864// fileOptimized = fopen( fileNameOptimized, "wt" );
865// if(fileOptimized == NULL) {
866// perror(fileNameOptimized);
867// exit(-1);
868// }
869
870// while( !feof(fileAsm) ) {
871
872// po_buf_fgets(bufLine,fileAsm );
873// if ( po_buf_match( bufLine, " ; VRP" ) ) {
874
875// int beginVrpSection = ftell( fileAsm );
876// int done = 0;
877
878// UnusedSymbol * unusedSymbol = NULL;
879
880// while( !feof(fileAsm) && !done ) {
881
882// po_buf_fgets(bufLine,fileAsm );
883
884// if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
885// UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
886// memset( s, 0, sizeof( UnusedSymbol ) );
887// s->realName = strdup( v1->str );
888// s->next = unusedSymbol;
889// unusedSymbol = s;
890// }
891
892// if ( po_buf_match( bufLine, " ; VSP" ) ) {
893// done = 1;
894// }
895
896// }
897
898// int endVrpSection = ftell( fileAsm );
899
900// fseek( fileAsm, beginVrpSection, SEEK_SET );
901
902// done = 0;
903
904// int line = 0;
905
906// while( !feof(fileAsm) && !done ) {
907
908// /* shift the buffers */
909// po_buf_cpy(buf[0], buf[1]->str);
910
911// po_buf_fgets( buf[1], fileAsm );
912
913// if ( po_buf_match( buf[0], " ; VSP" ) ) {
914// done = 1;
915// }
916
917// POBuffer result = po_buf_match(buf[0], " ADC (*)", v1 );
918// if ( ! result ) result = po_buf_match(buf[0], " ADD (*)", v1 );
919// if ( ! result ) result = po_buf_match(buf[0], " AND (*)", v1 );
920// if ( ! result ) result = po_buf_match(buf[0], " BIT (*)", v1 );
921// if ( ! result ) result = po_buf_match(buf[0], " CP (*)", v1 );
922// if ( ! result ) result = po_buf_match(buf[0], " CPL (*)", v1 );
923// if ( ! result ) result = po_buf_match(buf[0], " LD *, (*)", v2, v1 );
924// if ( ! result ) result = po_buf_match(buf[0], " OR (*)", v1 );
925// if ( ! result ) result = po_buf_match(buf[0], " SBC (*)", v1 );
926// if ( ! result ) result = po_buf_match(buf[0], " XOR (*)", v1 );
927
928// if ( ! result ) result = po_buf_match(buf[0], " ADC *", v1 );
929// if ( ! result ) result = po_buf_match(buf[0], " ADD *", v1 );
930// if ( ! result ) result = po_buf_match(buf[0], " AND *", v1 );
931// if ( ! result ) result = po_buf_match(buf[0], " BIT *", v1 );
932// if ( ! result ) result = po_buf_match(buf[0], " CP *", v1 );
933// if ( ! result ) result = po_buf_match(buf[0], " CPL *", v1 );
934// if ( ! result ) result = po_buf_match(buf[0], " LD *, *", v2, v1 );
935// if ( ! result ) result = po_buf_match(buf[0], " OR *", v1 );
936// if ( ! result ) result = po_buf_match(buf[0], " SBC *", v1 );
937// if ( ! result ) result = po_buf_match(buf[0], " XOR *", v1 );
938
939// if ( result ) {
940// char * realVarName = strdup( v1->str );
941// char * c = strstr( realVarName, "+" );
942// if ( c ) {
943// *c = 0;
944// }
945// UnusedSymbol * tmp = unusedSymbol;
946// UnusedSymbol * previous = NULL;
947// while( tmp ) {
948// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
949// if ( previous ) {
950// previous->next = tmp->next;
951// } else {
952// unusedSymbol = tmp->next;
953// }
954// break;
955// }
956// previous = tmp;
957// tmp = tmp->next;
958// }
959
960// }
961
962// }
963
964// fseek( fileAsm, beginVrpSection, SEEK_SET );
965
966// done = 0;
967
968// line = 0;
969
970// while( !feof(fileAsm) && !done ) {
971
972// if ( line >= 2 ) out(fileOptimized, buf[0]);
973
974// /* shift the buffers */
975// po_buf_cpy(buf[0], buf[1]->str);
976
977// po_buf_fgets( buf[1], fileAsm );
978
979// if ( po_buf_match( buf[0], " ; VSP" ) ) {
980// done = 1;
981// } else if( ( ( po_buf_match( buf[0], " LD A, *", v2 ) && po_buf_match( buf[1], " LD (*), A", v2 ) ) ||
982// ( po_buf_match( buf[0], " LD HL, *", v2 ) && po_buf_match( buf[1], " LD (*), HL", v2 ) ) )
983// )
984// {
985// char * realVarName = strdup( v2->str );
986// char * c = strstr( realVarName, "+" );
987// if ( c ) {
988// *c = 0;
989// }
990// UnusedSymbol * tmp = unusedSymbol;
991// while( tmp ) {
992// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
993// break;
994// }
995// tmp = tmp->next;
996// }
997// if ( tmp ) {
998// optim( buf[0], RULE "unused temporary", NULL );
999// optim( buf[1], RULE "unused temporary", NULL );
1000// }
1001// ++_environment->removedAssemblyLines;
1002// ++_environment->removedAssemblyLines;
1003// } else if( ( po_buf_match( buf[0], " LD (*), A", v2 ) ) ||
1004// po_buf_match( buf[0], " LD (*), HL", v2 ) ) {
1005// char * realVarName = strdup( v2->str );
1006// char * c = strstr( realVarName, "+" );
1007// if ( c ) {
1008// *c = 0;
1009// }
1010// UnusedSymbol * tmp = unusedSymbol;
1011// while( tmp ) {
1012// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1013// break;
1014// }
1015// tmp = tmp->next;
1016// }
1017// if ( tmp ) {
1018// optim( buf[0], RULE "unused temporary", NULL );
1019// }
1020// ++_environment->removedAssemblyLines;
1021// }
1022
1023
1024// ++line;
1025
1026// }
1027
1028// unusedSymbol = NULL;
1029
1030// }
1031
1032// out(fileOptimized, bufLine);
1033
1034// }
1035
1036// (void)fclose(fileAsm);
1037// (void)fclose(fileOptimized);
1038
1039// /* makes our generated file the new asm file */
1040// remove(_environment->asmFileName);
1041// (void)rename( fileNameOptimized, _environment->asmFileName );
1042
1043// }
1044
1045static void optim_remove_unused_temporary( Environment * _environment ) {
1046
1047 int i;
1048
1049 POBuffer bufLine = TMP_BUF;
1050 POBuffer v1 = TMP_BUF;
1051 POBuffer v2 = TMP_BUF;
1052 POBuffer buf[2];
1053
1054 for(i=0; i<2; ++i) buf[i] = po_buf_new(0);
1055
1056 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1057 FILE * fileAsm;
1058 FILE * fileOptimized;
1059
1060 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1061
1062 fileAsm = fopen( _environment->asmFileName, "rt" );
1063 if(fileAsm == NULL) {
1064 perror(_environment->asmFileName);
1065 exit(-1);
1066 }
1067
1068 fileOptimized = fopen( fileNameOptimized, "wt" );
1069 if(fileOptimized == NULL) {
1070 perror(fileNameOptimized);
1071 exit(-1);
1072 }
1073
1074 UnusedSymbol * currentlyUnusedSymbols = NULL;
1075
1076 int vspPointer = 0;
1077
1078 while( !feof(fileAsm) ) {
1079
1080 po_buf_fgets( bufLine, fileAsm );
1081
1082 if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
1083 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1084 memset( s, 0, sizeof( UnusedSymbol ) );
1085 s->realName = strdup( v1->str );
1086 s->next = currentlyUnusedSymbols;
1087 currentlyUnusedSymbols = s;
1088 } else if ( po_buf_match( bufLine, " ; VSP" ) ) {
1089
1090 // printf( "SYMBOLS COMPLETE: " );
1091 // UnusedSymbol * s = currentlyUnusedSymbols;
1092 // while( s ) {
1093 // printf( "%s, ", s->realName );
1094 // s = s->next;
1095 // }
1096 // printf( "\n\n" );
1097
1098 fseek( fileAsm, vspPointer, SEEK_SET );
1099
1100 while( !feof(fileAsm) ) {
1101
1102 po_buf_fgets( bufLine, fileAsm );
1103
1104 POBuffer result = po_buf_match(bufLine, " ADC (*)", v1 );
1105 if ( ! result ) result = po_buf_match(bufLine, " ADD (*)", v1 );
1106 if ( ! result ) result = po_buf_match(bufLine, " AND (*)", v1 );
1107 if ( ! result ) result = po_buf_match(bufLine, " BIT (*)", v1 );
1108 if ( ! result ) result = po_buf_match(bufLine, " CP (*)", v1 );
1109 if ( ! result ) result = po_buf_match(bufLine, " CPL (*)", v1 );
1110 if ( ! result ) result = po_buf_match(bufLine, " LD *, (*)", v2, v1 );
1111 if ( ! result ) result = po_buf_match(bufLine, " OR (*)", v1 );
1112 if ( ! result ) result = po_buf_match(bufLine, " SBC (*)", v1 );
1113 if ( ! result ) result = po_buf_match(bufLine, " XOR (*)", v1 );
1114
1115 if ( ! result ) result = po_buf_match(bufLine, " ADC *", v1 );
1116 if ( ! result ) result = po_buf_match(bufLine, " ADD *", v1 );
1117 if ( ! result ) result = po_buf_match(bufLine, " AND *", v1 );
1118 if ( ! result ) result = po_buf_match(bufLine, " BIT *", v1 );
1119 if ( ! result ) result = po_buf_match(bufLine, " CP *", v1 );
1120 if ( ! result ) result = po_buf_match(bufLine, " CPL *", v1 );
1121 if ( ! result ) result = po_buf_match(bufLine, " LD *, *", v2, v1 );
1122 if ( ! result ) result = po_buf_match(bufLine, " OR *", v1 );
1123 if ( ! result ) result = po_buf_match(bufLine, " SBC *", v1 );
1124 if ( ! result ) result = po_buf_match(bufLine, " XOR *", v1 );
1125
1126 if ( result ) {
1127 char * realVarName = strdup( v1->str );
1128 char * c = strstr( realVarName, "+" );
1129 if ( c ) {
1130 *c = 0;
1131 }
1132 UnusedSymbol * tmp = currentlyUnusedSymbols;
1133 UnusedSymbol * previous = NULL;
1134 while( tmp ) {
1135 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1136 if ( previous ) {
1137 previous->next = tmp->next;
1138 } else {
1139 currentlyUnusedSymbols = tmp->next;
1140 }
1141 break;
1142 }
1143 previous = tmp;
1144 tmp = tmp->next;
1145 }
1146
1147 }
1148
1149 if ( po_buf_match( bufLine, " ; VSP" ) ) {
1150 break;
1151 }
1152
1153 }
1154
1155 // printf( "REALLY UNUSED SYMBOLS: " );
1156 // s = currentlyUnusedSymbols;
1157 // while( s ) {
1158 // printf( "%s, ", s->realName );
1159 // s = s->next;
1160 // }
1161 // printf( "\n\n" );
1162 fseek( fileAsm, vspPointer, SEEK_SET );
1163
1164 int line = 0;
1165
1166 while( !feof(fileAsm) ) {
1167
1168 if ( line >= 1 ) out(fileOptimized, buf[0]);
1169 po_buf_cpy(buf[0], buf[1]->str);
1170 po_buf_fgets( buf[1], fileAsm );
1171 ++line;
1172
1173 if( ( ( po_buf_match( buf[0], " LD A, *", v2 ) && po_buf_match( buf[1], " LD (*), A", v2 ) ) ||
1174 ( po_buf_match( buf[0], " LD HL, *", v2 ) && po_buf_match( buf[1], " LD (*), HL", v2 ) ) )
1175 )
1176 {
1177 char * realVarName = strdup( v2->str );
1178 char * c = strstr( realVarName, "+" );
1179 if ( c ) {
1180 *c = 0;
1181 }
1182 UnusedSymbol * tmp = currentlyUnusedSymbols;
1183 while( tmp ) {
1184 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1185 break;
1186 }
1187 tmp = tmp->next;
1188 }
1189 if ( tmp ) {
1190 optim( buf[0], RULE "unused temporary", NULL );
1191 optim( buf[1], RULE "unused temporary", NULL );
1192 ++_environment->removedAssemblyLines;
1193 ++_environment->removedAssemblyLines;
1194 }
1195 } else if( ( po_buf_match( buf[0], " LD (*), A", v2 ) ) ||
1196 po_buf_match( buf[0], " LD (*), HL", v2 ) ) {
1197 char * realVarName = strdup( v2->str );
1198 char * c = strstr( realVarName, "+" );
1199 if ( c ) {
1200 *c = 0;
1201 }
1202 UnusedSymbol * tmp = currentlyUnusedSymbols;
1203 while( tmp ) {
1204 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1205 break;
1206 }
1207 tmp = tmp->next;
1208 }
1209 if ( tmp ) {
1210 optim( buf[0], RULE "unused temporary", NULL );
1211 ++_environment->removedAssemblyLines;
1212 }
1213 }
1214
1215 if ( po_buf_match( buf[1], " ; VSP" ) ) {
1216 out(fileOptimized, buf[0]);
1217 break;
1218 }
1219
1220 }
1221
1222 vspPointer = ftell( fileAsm );
1223
1224 // printf( "vspPointer = %d\n", vspPointer );
1225
1226 currentlyUnusedSymbols = NULL;
1227
1228 }
1229
1230 }
1231
1232 fseek( fileAsm, vspPointer, SEEK_SET );
1233
1234 while( !feof(fileAsm) ) {
1235
1236 po_buf_fgets( bufLine, fileAsm );
1237
1238 out(fileOptimized, bufLine);
1239
1240 }
1241
1242 (void)fclose(fileAsm);
1243 (void)fclose(fileOptimized);
1244
1245 /* makes our generated file the new asm file */
1246 remove(_environment->asmFileName);
1247 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1248
1249}
1250
1251static void optim_remove_comments( Environment * _environment ) {
1252
1253 int i;
1254
1255 POBuffer bufLine = TMP_BUF;
1256
1257 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1258 FILE * fileAsm;
1259 FILE * fileOptimized;
1260
1261 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1262
1263 fileAsm = fopen( _environment->asmFileName, "rt" );
1264 if(fileAsm == NULL) {
1265 perror(_environment->asmFileName);
1266 exit(-1);
1267 }
1268
1269 fileOptimized = fopen( fileNameOptimized, "wt" );
1270 if(fileOptimized == NULL) {
1271 perror(fileNameOptimized);
1272 exit(-1);
1273 }
1274
1275 while( !feof(fileAsm) ) {
1276
1277 po_buf_fgets( bufLine, fileAsm );
1278
1279 if ( !isAComment( bufLine ) ) {
1280 out( fileOptimized, bufLine );
1281 }
1282
1283 }
1284
1285 (void)fclose(fileAsm);
1286 (void)fclose(fileOptimized);
1287
1288 /* makes our generated file the new asm file */
1289 remove(_environment->asmFileName);
1290 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1291
1292}
1293
1294/* main entry-point for this service */
1296
1297 optim_remove_unused_temporary( _environment );
1298
1299 if ( _environment->peepholeOptimizationLimit > 0 ) {
1300 POBuffer buf[LOOK_AHEAD];
1301 int i;
1302
1303 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_new(0);
1304
1305 int optimization_limit_count = _environment->peepholeOptimizationLimit;
1306
1307 do {
1308 while(optim_pass(_environment, buf, PEEPHOLE)&&optimization_limit_count) {
1309 --optimization_limit_count;
1310 };
1311 optim_pass(_environment, buf, DEADVARS);
1312 } while(change&&optimization_limit_count);
1313 optim_pass(_environment, buf, RELOCATION1);
1314 optim_pass(_environment, buf, RELOCATION2);
1315
1316 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_del(buf[i]);
1318 }
1319 if ( _environment->removeComments ) {
1320 optim_remove_comments(_environment);
1321 }
1322}
1323
1324void target_finalize( Environment * _environment ) {
1325
1326 if ( _environment->additionalInfoFile ) {
1327
1328 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1329 FILE * fileAsm;
1330 FILE * fileListing;
1331 POBuffer bufferAsm = TMP_BUF;
1332 POBuffer bufferListing = TMP_BUF;
1333 POBuffer bufferLine = TMP_BUF;
1334 POBuffer bufferAddress = TMP_BUF;
1335 POBuffer bufferBytes = TMP_BUF;
1336
1337 int sourceLine = -1;
1338
1339 _environment->currentSourceLineAnalyzed = 0;
1340 _environment->bytesProduced = 0;
1341
1342 adiline0( "A:0" );
1343
1344 fileAsm = fopen( _environment->asmFileName, "rb" );
1345 if(fileAsm == NULL) {
1346 perror(_environment->asmFileName);
1347 exit(-1);
1348 }
1349
1350 fileListing = fopen( _environment->listingFileName, "rb" );
1351 if(fileListing == NULL) {
1352 perror(_environment->listingFileName);
1353 exit(-1);
1354 }
1355
1356 while( !feof(fileAsm) && !feof(fileListing)) {
1357
1358 po_buf_fgets( bufferAsm, fileAsm );
1359 int leftPadding = po_buf_trim( bufferAsm );
1360
1361 if ( isAComment( bufferAsm ) ) {
1362 POBuffer ln = TMP_BUF;
1363 if (po_buf_match( bufferAsm, "; L:*", ln ) ) {
1364 sourceLine = atoi( ln->str );
1365 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
1366 adiline2( "AB:0:%d:%d",
1367 _environment->currentSourceLineAnalyzed, _environment->bytesProduced );
1368 _environment->currentSourceLineAnalyzed = sourceLine;
1369 _environment->bytesProduced = 0;
1370 }
1371 }
1372 continue;
1373 }
1374
1375 *bufferListing->str = 0;
1376 int pos = ftell( fileListing );
1377 po_buf_trim( bufferAsm );
1378 while( !feof(fileListing) && (strstr( bufferListing->str, bufferAsm->str ) == NULL) ) {
1379 po_buf_fgets( bufferListing, fileListing );
1380 po_buf_trim( bufferListing );
1381 }
1382
1383 if ( feof(fileListing) ) {
1384
1385 } else {
1386 pos = ftell( fileListing );
1387 char * bufferAsmEscaped = strdup( bufferAsm->str );
1388 for( int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
1389 if ( bufferAsmEscaped[i] == ':' ) {
1390 bufferAsmEscaped[i] = 6;
1391 }
1392 if ( bufferAsmEscaped[i] == 9 ) {
1393 bufferAsmEscaped[i] = ' ';
1394 }
1395 }
1396 if ( po_buf_match( bufferListing, "* * * ", bufferLine, bufferAddress, bufferBytes ) ) {
1397 _environment->bytesProduced += bufferBytes->len >> 1;
1398 }
1399 adiline4( "AL:0:%d:%*s%s",
1400 _environment->currentSourceLineAnalyzed, leftPadding, "", bufferAsmEscaped );
1401 }
1402
1403 fseek( fileListing, pos, SEEK_SET );
1404
1405 }
1406
1407 if ( _environment->currentSourceLineAnalyzed ) {
1408 adiline1( "AF:0:%d",
1409 _environment->bytesProduced );
1410 }
1411
1412 (void)fclose(fileListing);
1413 (void)fclose(fileAsm);
1414
1415 }
1416
1417}
char * strtoupper(char *_string)
char * get_temporary_filename(Environment *_environment)
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
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
int po_buf_strcmp(POBuffer _s, POBuffer _t)
Definition _optimizer.c:251
POBuffer po_buf_cpy(POBuffer buf, char *string)
Definition _optimizer.c:94
POBuffer po_buf_del(POBuffer buf)
Definition _optimizer.c:49
POBuffer po_buf_add(POBuffer buf, char c)
Definition _optimizer.c:100
int po_buf_trim(POBuffer buf)
Definition _optimizer.c:157
POBuffer po_buf_vprintf(POBuffer buf, const char *fmt, va_list ap)
Definition _optimizer.c:111
POBuffer po_buf_cat(POBuffer buf, char *string)
Definition _optimizer.c:83
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