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