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)", "\tJMP %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
490 if(name->str[0]=='_') return 1;
491 if(po_buf_match(name, "CLIP")) return 1;
492 if(po_buf_match(name, "XCUR")) return 1;
493 if(po_buf_match(name, "YCUR")) return 1;
494 if(po_buf_match(name, "CURRENT")) return 1;
495 if(po_buf_match(name, "FONT")) return 1;
496 if(po_buf_match(name, "TEXT")) return 1;
497 if(po_buf_match(name, "LAST")) return 1;
498 if(po_buf_match(name, "XGR")) return 1;
499 if(po_buf_match(name, "YGR")) return 1;
500 if(po_buf_match(name, "FREE_")) return 1;
501
502 return 0;
503}
504
505/* look for variable uses and collect data about he variables */
506static void vars_scan(POBuffer buf[LOOK_AHEAD]) {
507 POBuffer tmp = TMP_BUF;
508 POBuffer arg = TMP_BUF;
509 POBuffer ofs = TMP_BUF;
510
511 // if( match( buf[0], " * _*+", NULL, buf) ) {
512 // struct var *v = vars_get(buf);
513 // v->flags |= NO_INLINE;
514 // }
515
516 if( po_buf_match( buf[0], " LD *, (*+*)", tmp, arg, ofs ) ) { if(vars_ok(arg)) {
517 struct var *v = vars_get(arg);
518 v->nb_rd++;
519 } } else if( po_buf_match( buf[0], " LD *, (*+*)", tmp, arg, ofs ) ) { if(vars_ok(arg)) {
520 struct var *v = vars_get(arg);
521 v->nb_rd++;
522 } } else if( po_buf_match( buf[0], " LD *, (*)", tmp, arg ) ) { if(vars_ok(arg)) {
523 struct var *v = vars_get(arg);
524 v->nb_rd++;
525 } } else if( po_buf_match( buf[0], " LD *,(*)", tmp, arg ) ) { if(vars_ok(arg)) {
526 struct var *v = vars_get(arg);
527 v->nb_rd++;
528 } }
529
530 if (po_buf_match( buf[0], " LD (*+*), *", arg, ofs, tmp) ) { if(vars_ok(arg)) {
531 struct var *v = vars_get(arg);
532 v->nb_wr++;
533 } } else if (po_buf_match( buf[0], " LD (*+*),*", arg, ofs, tmp) ) { if(vars_ok(arg)) {
534 struct var *v = vars_get(arg);
535 v->nb_wr++;
536 } } else if (po_buf_match( buf[0], " LD (*), *", arg, tmp) ) { if(vars_ok(arg)) {
537 struct var *v = vars_get(arg);
538 v->nb_wr++;
539 } } else if (po_buf_match( buf[0], " LD (*),*", arg, tmp) ) { if(vars_ok(arg)) {
540 struct var *v = vars_get(arg);
541 v->nb_wr++;
542 } }
543
544 if (po_buf_match( buf[0], " LD *, *", arg, tmp) &&
545 strstr("A B C D E AD BC DE HL IX IY", strtoupper(arg->str))!=NULL
546 ) {
547 if(vars_ok(tmp)) {
548 struct var *v = vars_get(tmp);
549 v->nb_rd++;
550 }
551 }
552
553 if (po_buf_match( buf[0], " LD *,*", arg, tmp) &&
554 strstr("A B C D E AD BC DE HL IX IY", strtoupper(arg->str))!=NULL
555 ) {
556 if(vars_ok(tmp)) {
557 struct var *v = vars_get(tmp);
558 v->nb_rd++;
559 }
560 }
561
562 if( po_buf_match( buf[0], " *: defs *", tmp, arg) && vars_ok(tmp)) {
563 struct var *v = vars_get(tmp);
564 v->size = atoi(arg->str);
565 v->init = strdup("1-1");
566 }
567
568 if( po_buf_match(buf[0], " *: defb *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
569 struct var *v = vars_get(tmp);
570 v->size = 1;
571 v->init = strdup(isZero(arg->str) ? "1-1" : arg->str);
572 }
573
574 if( po_buf_match(buf[0], " *: defw *", tmp, arg) && vars_ok(tmp) && strchr(buf[0]->str,',')==NULL) {
575 struct var *v = vars_get(tmp);
576 v->size = 2;
577 v->init = strdup(arg->str);
578 }
579
580 if( po_buf_match(buf[0], " * = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
581 struct var *v1 = vars_get(tmp);
582 if ( v1 ) {
583 v1->nb_rd++;
584 }
585 struct var *v2 = vars_get(arg);
586 if ( v2 ) {
587 v2->nb_rd++;
588 }
589 } else if( po_buf_match(buf[0], "* = *+$*", tmp, arg, ofs) && vars_ok(arg) ) {
590 struct var *v1 = vars_get(tmp);
591 if ( v1 ) {
592 v1->nb_rd++;
593 }
594 struct var *v2 = vars_get(arg);
595 if ( v2 ) {
596 v2->nb_rd++;
597 }
598 }
599
600}
601
602/* compares two variables according to their access-count */
603static int vars_cmp(const void *_a, const void *_b) {
604 const struct var *a = _a;
605 const struct var *b = _b;
606
607 int diff = ((a->nb_rd + a->nb_wr) - (b->nb_rd + b->nb_wr));
608
609 return -(diff!=0 ? diff : strcmp(a->name, b->name)); // Ttmp < Tstr
610}
611
612/* removes unread variables */
613static void vars_remove(Environment * _environment, POBuffer buf[LOOK_AHEAD]) {
614 POBuffer var = TMP_BUF;
615 POBuffer op = TMP_BUF;
616 POBuffer ofs = TMP_BUF;
617
618 if(!DO_UNREAD) return;
619
620 /* unread */
621 if(po_buf_match( buf[0], " LD (*+*), *", var, ofs, op) && vars_ok(var)) {
622 struct var *v = vars_get(var);
623 if(v->nb_rd == 0 && v->offset!=-2) {
624 v->offset = 0;
625 optim(buf[0], "unread", NULL);
626 ++_environment->removedAssemblyLines;
627 }
628 } else if(po_buf_match( buf[0], " LD (*), *", var, op) && vars_ok(var)) {
629 struct var *v = vars_get(var);
630 if(v->nb_rd == 0 && v->offset!=-2) {
631 v->offset = 0;
632 optim(buf[0], "unread", NULL);
633 ++_environment->removedAssemblyLines;
634 }
635 }
636
637 /* remove changed variables */
638 if(po_buf_match( buf[0], " *: DEFS ", var)
639 || po_buf_match( buf[0], " *: DEFB ", var)
640 || po_buf_match( buf[0], " *: DEFW ", var) ) if(vars_ok(var)) {
641 struct var *v = vars_get(var);
642 if(v->nb_rd==0 && 0<v->size && v->size<=4 && 0==(v->flags & NO_REMOVE) && v->offset!=-2) {
643 optim(buf[0], "unread",NULL);
644 ++num_unread;
645 ++_environment->removedAssemblyLines;
646 }
647 }
648}
649
650/* collapse all heading spaces into a single tabulation */
651static void out(FILE *f, POBuffer _buf) {
652 char *s = _buf->str;
653 int tab = 0;
654 while(*s==' ' || *s=='\t') {tab = 1; ++s;}
655 if(tab) fputs("\t", f);
656 fputs(s, f);
657}
658
659/* remove space that is sometimes used in indexing mode and makes the optimized produce bad dcode */
660static void fixes_indexed_syntax(POBuffer buf) {
661 char *s = buf->str;
662
663 /* not an instruction */
664 if(!_eq(' ', *s)) return;
665
666 /* skip over spaces */
667 do ++s; while(*s && _eq(' ', *s));
668
669 /* comment */
670 if(*s==';') return;
671
672 /* skip over instruction */
673 while(*s && !_eq(' ', *s)) ++s;
674 if(!*s) return;
675
676 /* skip over spaces */
677 do ++s; while(*s && _eq(' ', *s));
678 if(!*s) return;
679
680 /* process argment */
681 do ++s; while(*s && !_eq(' ', *s));
682 if(!*s) return;
683
684}
685
686/* various kind of optimization */
687static int optim_pass( Environment * _environment, POBuffer buf[LOOK_AHEAD], PeepHoleOptimizationKind kind) {
688 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
689 FILE * fileAsm;
690 FILE * fileOptimized;
691 int i;
692 int still_to_go = LOOK_AHEAD;
693
694 int line = 0;
695 int zA = 0, zB = 0;
696
697 int sourceLine = -1;
698
699 _environment->currentSourceLineAnalyzed = 0;
700 _environment->removedAssemblyLines = 0;
701
702 adiline2( "POP:0:%d:%d", peephole_pass, kind );
703
704 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
705
706 /* prepare for phase */
707 switch(kind) {
708 case DEADVARS:
709 ++peephole_pass;
710 num_unread = 0;
711 break;
712
713 case RELOCATION1:
714 ++peephole_pass;
715 // vars_prepare_relocation();
716 break;
717
718 case RELOCATION2:
719 break;
720
721 case PEEPHOLE:
722 ++peephole_pass;
723 // vars_clear();
724 break;
725 }
726
727 fileAsm = fopen( _environment->asmFileName, "rt" );
728 if(fileAsm == NULL) {
729 perror(_environment->asmFileName);
730 exit(-1);
731 }
732
733 fileOptimized = fopen( fileNameOptimized, "wt" );
734 if(fileOptimized == NULL) {
735 perror(fileNameOptimized);
736 exit(-1);
737 }
738
739 /* clears our look-ahead buffers */
740 for(i = 0; i<LOOK_AHEAD; ++i) po_buf_cpy(buf[i], "");
741
742 /* global change flag */
743 change = 0;
744
745 while( still_to_go ) {
746 /* print out oldest POBuffer */
747 if ( line >= LOOK_AHEAD ) out(fileOptimized, buf[0]);
748
749 /* shift the buffers */
750 for(i=0; i<LOOK_AHEAD-1; ++i) po_buf_cpy(buf[i], buf[i+1]->str);
751
752 /* read next line, merging adjacent comments */
753 if(feof(fileAsm)) {
754 --still_to_go;
755 po_buf_cpy(buf[LOOK_AHEAD-1], "");
756 } else do {
757 /* read next line */
758 po_buf_fgets( buf[LOOK_AHEAD-1], fileAsm );
759 fixes_indexed_syntax(buf[LOOK_AHEAD-1]);
760 /* merge comment with previous line if we do not overflow the POBuffer */
761 if(isAComment(buf[LOOK_AHEAD-1])) {
762 POBuffer ln = TMP_BUF;
763 if (po_buf_match( buf[LOOK_AHEAD-1], " ; L:*", ln ) ) {
764 sourceLine = atoi( ln->str );
765 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
766 adiline3( "POL:0:%d:%d:%d",
767 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
768 _environment->currentSourceLineAnalyzed = sourceLine;
769 _environment->removedAssemblyLines = 0;
770 }
771 }
772 if(KEEP_COMMENTS) po_buf_cat(buf[LOOK_AHEAD-2], buf[LOOK_AHEAD-1]->str);
773 po_buf_cpy(buf[LOOK_AHEAD-1], "");
774 } else break;
775 } while(!feof(fileAsm));
776
777 switch(kind) {
778 case PEEPHOLE:
779 basic_peephole(buf, zA, zB);
780
781 /* only look fo variable when no peephole has been performed */
782 if(change == 0) vars_scan(buf);
783 break;
784
785 case DEADVARS:
786 vars_remove(_environment, buf);
787 break;
788
789 case RELOCATION1:
790 case RELOCATION2:
791 // vars_relocate(buf);
792 break;
793 }
794
795 ++line;
796 }
797
798 adiline3( "POL:0:%d:%d:%d",
799 peephole_pass, _environment->currentSourceLineAnalyzed, _environment->removedAssemblyLines );
800
801 /* log info at the end of the file */
802 switch(kind) {
803 case PEEPHOLE:
804 fprintf(fileOptimized, "; peephole: pass %d, %d change%s.\n", peephole_pass,
805 change, change>1 ?"s":"");
806 break;
807
808 case DEADVARS:
809 fprintf(fileOptimized, "; peephole: pass %d, %d var%s removed.\n", peephole_pass,
810 num_unread, num_unread>1 ?"s":"");
811 break;
812
813 case RELOCATION2:
814 fprintf(fileOptimized, "; peephole: pass %d, %d var%s moved to dp, %d var%s inlined.\n", peephole_pass,
815 num_dp, num_dp>1 ?"s":"",
816 num_inlined, num_inlined>1 ? "s":"");
817 break;
818
819 default:
820 break;
821 }
822
823 (void)fclose(fileAsm);
824 (void)fclose(fileOptimized);
825
826 /* makes our generated file the new asm file */
827 remove(_environment->asmFileName);
828 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
829
830 return change;
831}
832
833typedef struct _UnusedSymbol {
834
835 char * realName;
836
837 struct _UnusedSymbol * next;
838
840
841// static int optim_remove_unused_temporary( Environment * _environment ) {
842
843// int i;
844// POBuffer bufLine = TMP_BUF;
845// POBuffer v1 = TMP_BUF;
846// POBuffer v2 = TMP_BUF;
847// POBuffer buf[2];
848
849// for(i=0; i<2; ++i) buf[i] = po_buf_new(0);
850
851// char fileNameOptimized[MAX_TEMPORARY_STORAGE];
852// FILE * fileAsm;
853// FILE * fileOptimized;
854
855// sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
856
857// fileAsm = fopen( _environment->asmFileName, "rt" );
858// if(fileAsm == NULL) {
859// perror(_environment->asmFileName);
860// exit(-1);
861// }
862
863// fileOptimized = fopen( fileNameOptimized, "wt" );
864// if(fileOptimized == NULL) {
865// perror(fileNameOptimized);
866// exit(-1);
867// }
868
869// while( !feof(fileAsm) ) {
870
871// po_buf_fgets(bufLine,fileAsm );
872// if ( po_buf_match( bufLine, " ; VRP" ) ) {
873
874// int beginVrpSection = ftell( fileAsm );
875// int done = 0;
876
877// UnusedSymbol * unusedSymbol = NULL;
878
879// while( !feof(fileAsm) && !done ) {
880
881// po_buf_fgets(bufLine,fileAsm );
882
883// if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
884// UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
885// memset( s, 0, sizeof( UnusedSymbol ) );
886// s->realName = strdup( v1->str );
887// s->next = unusedSymbol;
888// unusedSymbol = s;
889// }
890
891// if ( po_buf_match( bufLine, " ; VSP" ) ) {
892// done = 1;
893// }
894
895// }
896
897// int endVrpSection = ftell( fileAsm );
898
899// fseek( fileAsm, beginVrpSection, SEEK_SET );
900
901// done = 0;
902
903// int line = 0;
904
905// while( !feof(fileAsm) && !done ) {
906
907// /* shift the buffers */
908// po_buf_cpy(buf[0], buf[1]->str);
909
910// po_buf_fgets( buf[1], fileAsm );
911
912// if ( po_buf_match( buf[0], " ; VSP" ) ) {
913// done = 1;
914// }
915
916// POBuffer result = po_buf_match(buf[0], " ADC (*)", v1 );
917// if ( ! result ) result = po_buf_match(buf[0], " ADD (*)", v1 );
918// if ( ! result ) result = po_buf_match(buf[0], " AND (*)", v1 );
919// if ( ! result ) result = po_buf_match(buf[0], " BIT (*)", v1 );
920// if ( ! result ) result = po_buf_match(buf[0], " CP (*)", v1 );
921// if ( ! result ) result = po_buf_match(buf[0], " CPL (*)", v1 );
922// if ( ! result ) result = po_buf_match(buf[0], " LD *, (*)", v2, v1 );
923// if ( ! result ) result = po_buf_match(buf[0], " OR (*)", v1 );
924// if ( ! result ) result = po_buf_match(buf[0], " SBC (*)", v1 );
925// if ( ! result ) result = po_buf_match(buf[0], " XOR (*)", v1 );
926
927// if ( ! result ) result = po_buf_match(buf[0], " ADC *", v1 );
928// if ( ! result ) result = po_buf_match(buf[0], " ADD *", v1 );
929// if ( ! result ) result = po_buf_match(buf[0], " AND *", v1 );
930// if ( ! result ) result = po_buf_match(buf[0], " BIT *", v1 );
931// if ( ! result ) result = po_buf_match(buf[0], " CP *", v1 );
932// if ( ! result ) result = po_buf_match(buf[0], " CPL *", v1 );
933// if ( ! result ) result = po_buf_match(buf[0], " LD *, *", v2, v1 );
934// if ( ! result ) result = po_buf_match(buf[0], " OR *", v1 );
935// if ( ! result ) result = po_buf_match(buf[0], " SBC *", v1 );
936// if ( ! result ) result = po_buf_match(buf[0], " XOR *", v1 );
937
938// if ( result ) {
939// char * realVarName = strdup( v1->str );
940// char * c = strstr( realVarName, "+" );
941// if ( c ) {
942// *c = 0;
943// }
944// UnusedSymbol * tmp = unusedSymbol;
945// UnusedSymbol * previous = NULL;
946// while( tmp ) {
947// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
948// if ( previous ) {
949// previous->next = tmp->next;
950// } else {
951// unusedSymbol = tmp->next;
952// }
953// break;
954// }
955// previous = tmp;
956// tmp = tmp->next;
957// }
958
959// }
960
961// }
962
963// fseek( fileAsm, beginVrpSection, SEEK_SET );
964
965// done = 0;
966
967// line = 0;
968
969// while( !feof(fileAsm) && !done ) {
970
971// if ( line >= 2 ) out(fileOptimized, buf[0]);
972
973// /* shift the buffers */
974// po_buf_cpy(buf[0], buf[1]->str);
975
976// po_buf_fgets( buf[1], fileAsm );
977
978// if ( po_buf_match( buf[0], " ; VSP" ) ) {
979// done = 1;
980// } else if( ( ( po_buf_match( buf[0], " LD A, *", v2 ) && po_buf_match( buf[1], " LD (*), A", v2 ) ) ||
981// ( po_buf_match( buf[0], " LD HL, *", v2 ) && po_buf_match( buf[1], " LD (*), HL", v2 ) ) )
982// )
983// {
984// char * realVarName = strdup( v2->str );
985// char * c = strstr( realVarName, "+" );
986// if ( c ) {
987// *c = 0;
988// }
989// UnusedSymbol * tmp = unusedSymbol;
990// while( tmp ) {
991// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
992// break;
993// }
994// tmp = tmp->next;
995// }
996// if ( tmp ) {
997// optim( buf[0], RULE "unused temporary", NULL );
998// optim( buf[1], RULE "unused temporary", NULL );
999// }
1000// ++_environment->removedAssemblyLines;
1001// ++_environment->removedAssemblyLines;
1002// } else if( ( po_buf_match( buf[0], " LD (*), A", v2 ) ) ||
1003// po_buf_match( buf[0], " LD (*), HL", v2 ) ) {
1004// char * realVarName = strdup( v2->str );
1005// char * c = strstr( realVarName, "+" );
1006// if ( c ) {
1007// *c = 0;
1008// }
1009// UnusedSymbol * tmp = unusedSymbol;
1010// while( tmp ) {
1011// if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1012// break;
1013// }
1014// tmp = tmp->next;
1015// }
1016// if ( tmp ) {
1017// optim( buf[0], RULE "unused temporary", NULL );
1018// }
1019// ++_environment->removedAssemblyLines;
1020// }
1021
1022
1023// ++line;
1024
1025// }
1026
1027// unusedSymbol = NULL;
1028
1029// }
1030
1031// out(fileOptimized, bufLine);
1032
1033// }
1034
1035// (void)fclose(fileAsm);
1036// (void)fclose(fileOptimized);
1037
1038// /* makes our generated file the new asm file */
1039// remove(_environment->asmFileName);
1040// (void)rename( fileNameOptimized, _environment->asmFileName );
1041
1042// }
1043
1044static void optim_remove_unused_temporary( Environment * _environment ) {
1045
1046 int i;
1047
1048 POBuffer bufLine = TMP_BUF;
1049 POBuffer v1 = TMP_BUF;
1050 POBuffer v2 = TMP_BUF;
1051 POBuffer buf[2];
1052
1053 for(i=0; i<2; ++i) buf[i] = po_buf_new(0);
1054
1055 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1056 FILE * fileAsm;
1057 FILE * fileOptimized;
1058
1059 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1060
1061 fileAsm = fopen( _environment->asmFileName, "rt" );
1062 if(fileAsm == NULL) {
1063 perror(_environment->asmFileName);
1064 exit(-1);
1065 }
1066
1067 fileOptimized = fopen( fileNameOptimized, "wt" );
1068 if(fileOptimized == NULL) {
1069 perror(fileNameOptimized);
1070 exit(-1);
1071 }
1072
1073 UnusedSymbol * currentlyUnusedSymbols = NULL;
1074
1075 int vspPointer = 0;
1076
1077 while( !feof(fileAsm) ) {
1078
1079 po_buf_fgets( bufLine, fileAsm );
1080
1081 if ( po_buf_match( bufLine, " ; V *", v1 ) ) {
1082 UnusedSymbol * s = malloc( sizeof( UnusedSymbol ) );
1083 memset( s, 0, sizeof( UnusedSymbol ) );
1084 s->realName = strdup( v1->str );
1085 s->next = currentlyUnusedSymbols;
1086 currentlyUnusedSymbols = s;
1087 } else if ( po_buf_match( bufLine, " ; VSP" ) ) {
1088
1089 // printf( "SYMBOLS COMPLETE: " );
1090 // UnusedSymbol * s = currentlyUnusedSymbols;
1091 // while( s ) {
1092 // printf( "%s, ", s->realName );
1093 // s = s->next;
1094 // }
1095 // printf( "\n\n" );
1096
1097 fseek( fileAsm, vspPointer, SEEK_SET );
1098
1099 while( !feof(fileAsm) ) {
1100
1101 po_buf_fgets( bufLine, fileAsm );
1102
1103 POBuffer result = po_buf_match(bufLine, " ADC (*)", v1 );
1104 if ( ! result ) result = po_buf_match(bufLine, " ADD (*)", v1 );
1105 if ( ! result ) result = po_buf_match(bufLine, " AND (*)", v1 );
1106 if ( ! result ) result = po_buf_match(bufLine, " BIT (*)", v1 );
1107 if ( ! result ) result = po_buf_match(bufLine, " CP (*)", v1 );
1108 if ( ! result ) result = po_buf_match(bufLine, " CPL (*)", v1 );
1109 if ( ! result ) result = po_buf_match(bufLine, " LD *, (*)", v2, v1 );
1110 if ( ! result ) result = po_buf_match(bufLine, " OR (*)", v1 );
1111 if ( ! result ) result = po_buf_match(bufLine, " SBC (*)", v1 );
1112 if ( ! result ) result = po_buf_match(bufLine, " XOR (*)", v1 );
1113
1114 if ( ! result ) result = po_buf_match(bufLine, " ADC *", v1 );
1115 if ( ! result ) result = po_buf_match(bufLine, " ADD *", v1 );
1116 if ( ! result ) result = po_buf_match(bufLine, " AND *", v1 );
1117 if ( ! result ) result = po_buf_match(bufLine, " BIT *", v1 );
1118 if ( ! result ) result = po_buf_match(bufLine, " CP *", v1 );
1119 if ( ! result ) result = po_buf_match(bufLine, " CPL *", v1 );
1120 if ( ! result ) result = po_buf_match(bufLine, " LD *, *", v2, v1 );
1121 if ( ! result ) result = po_buf_match(bufLine, " OR *", v1 );
1122 if ( ! result ) result = po_buf_match(bufLine, " SBC *", v1 );
1123 if ( ! result ) result = po_buf_match(bufLine, " XOR *", v1 );
1124
1125 if ( result ) {
1126 char * realVarName = strdup( v1->str );
1127 char * c = strstr( realVarName, "+" );
1128 if ( c ) {
1129 *c = 0;
1130 }
1131 UnusedSymbol * tmp = currentlyUnusedSymbols;
1132 UnusedSymbol * previous = NULL;
1133 while( tmp ) {
1134 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1135 if ( previous ) {
1136 previous->next = tmp->next;
1137 } else {
1138 currentlyUnusedSymbols = tmp->next;
1139 }
1140 break;
1141 }
1142 previous = tmp;
1143 tmp = tmp->next;
1144 }
1145
1146 }
1147
1148 if ( po_buf_match( bufLine, " ; VSP" ) ) {
1149 break;
1150 }
1151
1152 }
1153
1154 // printf( "REALLY UNUSED SYMBOLS: " );
1155 // s = currentlyUnusedSymbols;
1156 // while( s ) {
1157 // printf( "%s, ", s->realName );
1158 // s = s->next;
1159 // }
1160 // printf( "\n\n" );
1161 fseek( fileAsm, vspPointer, SEEK_SET );
1162
1163 int line = 0;
1164
1165 while( !feof(fileAsm) ) {
1166
1167 if ( line >= 1 ) out(fileOptimized, buf[0]);
1168 po_buf_cpy(buf[0], buf[1]->str);
1169 po_buf_fgets( buf[1], fileAsm );
1170 ++line;
1171
1172 if( ( ( po_buf_match( buf[0], " LD A, *", v2 ) && po_buf_match( buf[1], " LD (*), A", v2 ) ) ||
1173 ( po_buf_match( buf[0], " LD HL, *", v2 ) && po_buf_match( buf[1], " LD (*), HL", v2 ) ) )
1174 )
1175 {
1176 char * realVarName = strdup( v2->str );
1177 char * c = strstr( realVarName, "+" );
1178 if ( c ) {
1179 *c = 0;
1180 }
1181 UnusedSymbol * tmp = currentlyUnusedSymbols;
1182 while( tmp ) {
1183 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1184 break;
1185 }
1186 tmp = tmp->next;
1187 }
1188 if ( tmp ) {
1189 optim( buf[0], RULE "unused temporary", NULL );
1190 optim( buf[1], RULE "unused temporary", NULL );
1191 ++_environment->removedAssemblyLines;
1192 ++_environment->removedAssemblyLines;
1193 }
1194 } else if( ( po_buf_match( buf[0], " LD (*), A", v2 ) ) ||
1195 po_buf_match( buf[0], " LD (*), HL", v2 ) ) {
1196 char * realVarName = strdup( v2->str );
1197 char * c = strstr( realVarName, "+" );
1198 if ( c ) {
1199 *c = 0;
1200 }
1201 UnusedSymbol * tmp = currentlyUnusedSymbols;
1202 while( tmp ) {
1203 if ( strcmp( realVarName, tmp->realName ) == 0 ) {
1204 break;
1205 }
1206 tmp = tmp->next;
1207 }
1208 if ( tmp ) {
1209 optim( buf[0], RULE "unused temporary", NULL );
1210 ++_environment->removedAssemblyLines;
1211 }
1212 }
1213
1214 if ( po_buf_match( buf[1], " ; VSP" ) ) {
1215 out(fileOptimized, buf[0]);
1216 break;
1217 }
1218
1219 }
1220
1221 vspPointer = ftell( fileAsm );
1222
1223 // printf( "vspPointer = %d\n", vspPointer );
1224
1225 currentlyUnusedSymbols = NULL;
1226
1227 }
1228
1229 }
1230
1231 fseek( fileAsm, vspPointer, SEEK_SET );
1232
1233 while( !feof(fileAsm) ) {
1234
1235 po_buf_fgets( bufLine, fileAsm );
1236
1237 out(fileOptimized, bufLine);
1238
1239 }
1240
1241 (void)fclose(fileAsm);
1242 (void)fclose(fileOptimized);
1243
1244 /* makes our generated file the new asm file */
1245 remove(_environment->asmFileName);
1246 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1247
1248}
1249
1250static void optim_remove_comments( Environment * _environment ) {
1251
1252 int i;
1253
1254 POBuffer bufLine = TMP_BUF;
1255
1256 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1257 FILE * fileAsm;
1258 FILE * fileOptimized;
1259
1260 sprintf( fileNameOptimized, "%s.asm", get_temporary_filename( _environment ) );
1261
1262 fileAsm = fopen( _environment->asmFileName, "rt" );
1263 if(fileAsm == NULL) {
1264 perror(_environment->asmFileName);
1265 exit(-1);
1266 }
1267
1268 fileOptimized = fopen( fileNameOptimized, "wt" );
1269 if(fileOptimized == NULL) {
1270 perror(fileNameOptimized);
1271 exit(-1);
1272 }
1273
1274 while( !feof(fileAsm) ) {
1275
1276 po_buf_fgets( bufLine, fileAsm );
1277
1278 if ( !isAComment( bufLine ) ) {
1279 out( fileOptimized, bufLine );
1280 }
1281
1282 }
1283
1284 (void)fclose(fileAsm);
1285 (void)fclose(fileOptimized);
1286
1287 /* makes our generated file the new asm file */
1288 remove(_environment->asmFileName);
1289 BUILD_SAFE_MOVE( _environment, fileNameOptimized, _environment->asmFileName );
1290
1291}
1292
1293/* main entry-point for this service */
1295
1296 optim_remove_unused_temporary( _environment );
1297
1298 if ( _environment->peepholeOptimizationLimit > 0 ) {
1299 POBuffer buf[LOOK_AHEAD];
1300 int i;
1301
1302 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_new(0);
1303
1304 int optimization_limit_count = _environment->peepholeOptimizationLimit;
1305
1306 do {
1307 while(optim_pass(_environment, buf, PEEPHOLE)&&optimization_limit_count) {
1308 --optimization_limit_count;
1309 };
1310 optim_pass(_environment, buf, DEADVARS);
1311 } while(change&&optimization_limit_count);
1312 optim_pass(_environment, buf, RELOCATION1);
1313 optim_pass(_environment, buf, RELOCATION2);
1314
1315 for(i=0; i<LOOK_AHEAD; ++i) buf[i] = po_buf_del(buf[i]);
1317 }
1318 if ( _environment->removeComments ) {
1319 optim_remove_comments(_environment);
1320 }
1321}
1322
1323void target_finalize( Environment * _environment ) {
1324
1325 if ( _environment->additionalInfoFile ) {
1326
1327 char fileNameOptimized[MAX_TEMPORARY_STORAGE];
1328 FILE * fileAsm;
1329 FILE * fileListing;
1330 POBuffer bufferAsm = TMP_BUF;
1331 POBuffer bufferListing = TMP_BUF;
1332 POBuffer bufferLine = TMP_BUF;
1333 POBuffer bufferAddress = TMP_BUF;
1334 POBuffer bufferBytes = TMP_BUF;
1335
1336 int sourceLine = -1;
1337
1338 _environment->currentSourceLineAnalyzed = 0;
1339 _environment->bytesProduced = 0;
1340
1341 adiline0( "A:0" );
1342
1343 fileAsm = fopen( _environment->asmFileName, "rb" );
1344 if(fileAsm == NULL) {
1345 perror(_environment->asmFileName);
1346 exit(-1);
1347 }
1348
1349 fileListing = fopen( _environment->listingFileName, "rb" );
1350 if(fileListing == NULL) {
1351 perror(_environment->listingFileName);
1352 exit(-1);
1353 }
1354
1355 while( !feof(fileAsm) && !feof(fileListing)) {
1356
1357 po_buf_fgets( bufferAsm, fileAsm );
1358 int leftPadding = po_buf_trim( bufferAsm );
1359
1360 if ( isAComment( bufferAsm ) ) {
1361 POBuffer ln = TMP_BUF;
1362 if (po_buf_match( bufferAsm, "; L:*", ln ) ) {
1363 sourceLine = atoi( ln->str );
1364 if ( ( sourceLine != _environment->currentSourceLineAnalyzed ) ) {
1365 adiline2( "AB:0:%d:%d",
1366 _environment->currentSourceLineAnalyzed, _environment->bytesProduced );
1367 _environment->currentSourceLineAnalyzed = sourceLine;
1368 _environment->bytesProduced = 0;
1369 }
1370 }
1371 continue;
1372 }
1373
1374 *bufferListing->str = 0;
1375 int pos = ftell( fileListing );
1376 po_buf_trim( bufferAsm );
1377 while( !feof(fileListing) && (strstr( bufferListing->str, bufferAsm->str ) == NULL) ) {
1378 po_buf_fgets( bufferListing, fileListing );
1379 po_buf_trim( bufferListing );
1380 }
1381
1382 if ( feof(fileListing) ) {
1383
1384 } else {
1385 pos = ftell( fileListing );
1386 char * bufferAsmEscaped = strdup( bufferAsm->str );
1387 for( int i=0, c=strlen(bufferAsmEscaped); i<c; ++i ) {
1388 if ( bufferAsmEscaped[i] == ':' ) {
1389 bufferAsmEscaped[i] = 6;
1390 }
1391 if ( bufferAsmEscaped[i] == 9 ) {
1392 bufferAsmEscaped[i] = ' ';
1393 }
1394 }
1395 if ( po_buf_match( bufferListing, "* * * ", bufferLine, bufferAddress, bufferBytes ) ) {
1396 _environment->bytesProduced += bufferBytes->len >> 1;
1397 }
1398 adiline4( "AL:0:%d:%*s%s",
1399 _environment->currentSourceLineAnalyzed, leftPadding, "", bufferAsmEscaped );
1400 }
1401
1402 fseek( fileListing, pos, SEEK_SET );
1403
1404 }
1405
1406 if ( _environment->currentSourceLineAnalyzed ) {
1407 adiline1( "AF:0:%d",
1408 _environment->bytesProduced );
1409 }
1410
1411 (void)fclose(fileListing);
1412 (void)fclose(fileAsm);
1413
1414 }
1415
1416}
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