/[projet1]/public/pc/tools/osdk/main/compiler/sources/gen.c
Defence Force logotype

Contents of /public/pc/tools/osdk/main/compiler/sources/gen.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1527 - (show annotations)
Sat Sep 7 09:16:40 2019 UTC (3 months, 1 week ago) by dbug
File MIME type: text/plain
File size: 41072 byte(s)
OSDK 1.15

1 /* C compiler: 16 bits 6502 code generator */
2 /* (C) Fabrice Frances 1997-2019 */
3 /*
4 * Implementation notes:
5 *
6 * The general structure of this backend follows the interfacing guidelines of
7 * Hanson & Fraser's Retargetable C Compiler : a number of specified functions
8 * have to be implemented by every backend, and the frontend and backend
9 * communicate information through a few structures (most important ones being
10 * the symbol structure and the node structure).
11 *
12 * Each backend defines specific extensions of these symbol and node structures
13 * in config.h (Xnode and Xsymbol), along with type metrics and a few other
14 * parameters.
15 *
16 * This 6502 backend aims to be kept as simple as possible by introducing an
17 * intermediate language of macros, so that most of the time, there's a one to
18 * one correspondence between the Operator Nodes passed by the frontend and
19 * the macros emitted by the backend. However, lcc's frontend was designed
20 * for working straight forward with backends for RISC processors with
21 * a load/store architecture and many registers so that operations only take
22 * register operands. The 6502 instead has a single register that can be used
23 * in operations whilst the second operand is in memory. So, I designed this
24 * 6502 backend to use pseudo-registers in zero-page (this seems natural),
25 * but also to propagate addressing-mode information in order to exploit
26 * some 6502 addressing modes. This way it becomes possible to optimize the
27 * generated code by combining the load/store operations provided by the
28 * frontend with the operations on pseudo-registers and/or memory.
29 */
30
31
32 char *version="/* 16-bit code V1.38 */\n";
33 #include "c.h"
34 #include <string.h>
35 #include <stdio.h>
36 #ifdef _MSC_VER
37 // http://gel.sourceforge.net/examples/stdbool_8h-source.php
38 #define false 0
39 #define true 1
40 #define bool _Bool
41 typedef int _Bool;
42 #else
43 #include <stdbool.h> // Not available on VS2010
44 #endif
45 extern void exit(int);
46
47 static bool graph_output; /* output forest of dags from frontend */
48 static int localsize; /* max size of locals */
49 static int argoffset; /* current stack position */
50 static int offset; /* current local size */
51 static int tmpsize; /* max size of temporary variables */
52 static int nbregs; /* number of used registers */
53 static unsigned busy; /* busy&(1<<t) == 1 if tmp t is used */
54 static unsigned busy_flt; /* busy_flt&(1<<t) == 1 if tmp t is used */
55 static char *NamePrefix; /* Prefix for all local names */
56 static int omit_frame; /* if no params and no locals */
57 static int optimizelevel=3; /* set by command line option -On */
58 static Symbol temp[32]; /* 32 symbols pointing to temporary variables... */
59 static Symbol flt_temp[32]; /* 32 symbols pointing to temporary floating-point variables... */
60 static char *regname[8]; /* 8 register variables names */
61
62 static char *opcode_names[] = {
63 NULL,"CNST","ARG","ASGN","INDIR","CVC","CVD","CVF","CVI","CVP",
64 "CVS","CVU","NEG","CALL","LOAD","RET","ADDRG","ADDRF","ADDRL","ADD",
65 "SUB","LSH","MOD","RSH","BAND","BCOM","BOR","BXOR","DIV","MUL",
66 "EQ","GE","GT","LE","LT","NE","JUMP","LABEL","MAXOP" };
67 static char type_name[] = " FDCSIUPVB??????";
68 static char *additional_operators[] = {
69 "AND","NOT","OR","COND","RIGHT","FIELD" };
70
71 void print_node(Node p) {
72 fprintf(stderr,"Node %s%c\n",
73 opcode_names[generic(p->op)>>4], type_name[optype(p->op)]);
74 fprintf(stderr,"Node addr: %p\n", p);
75 fprintf(stderr," optimized: %d\n", p->x.optimized);
76 fprintf(stderr," referenced: %d\n", p->count);
77 fprintf(stderr," Operator = %d\n", p->op);
78 fprintf(stderr," link to next dag: %p\n", p->link);
79 fprintf(stderr," next on linearized list: %p\n", p->x.next);
80 fprintf(stderr," syms[0]: %p\n", p->syms[0]);
81 fprintf(stderr," syms[1]: %p\n", p->syms[1]);
82 fprintf(stderr," kids[0]: %p\n", p->kids[0]);
83 fprintf(stderr," kids[1]: %p\n", p->kids[1]);
84 fprintf(stderr," result: %p\n", p->x.result);
85 fprintf(stderr," adrmode: %c\n", p->x.adrmode);
86 fprintf(stderr," name: %s\n", p->x.name);
87 }
88
89 static void print_graph_node(Node p) {
90 Symbol s;
91 Node left, right;
92 if (p == NULL) return;
93 s = p->syms[0];
94 left = p->kids[0];
95 right = p->kids[1];
96
97 if (p->op < MAXOP)
98 printf("\t%s%p [label=\"%s%c\"];\n", fname, p,
99 opcode_names[generic(p->op)>>4], type_name[optype(p->op)]);
100 else printf("\t%s%p [label=\"%s\"];\n", fname, p,
101 additional_operators[p->op - MAXOP]);
102
103 switch (generic(p->op)) {
104 case ADDRF: case ADDRG: case ADDRL: case CNST: case LABEL:
105 /* 1 symbol */
106 printf("\t%s%p [shape=box,label=\"%s\"];\n",fname,s,s->x.name);
107 printf("\t%s%p -> %s%p [style=dotted];\n",fname,p,fname,s);
108 break;
109
110 case EQ: case GE: case GT: case LE: case LT: case NE:
111 /* 1 symbol, 2 kids */
112 printf("\tN%p [shape=box,label=\"%s\"];\n",s,s->x.name);
113 printf("\t%s%p -> N%p [style=dotted,label=\"label\"];\n",fname,p,s);
114
115 case ASGN:
116 case ADD: case SUB: case BAND: case BOR: case BXOR:
117 case DIV: case LSH: case MOD: case MUL: case RSH:
118 /* 2 kids */
119 printf("\t%s%p -> %s%p [label=\"left\"];\n",fname,p,fname,left);
120 printf("\t%s%p -> %s%p;\n",fname,p,fname,right);
121 break;
122
123 case BCOM:
124 case CVC: case CVD: case CVF: case CVI: case CVP: case CVS: case CVU:
125 case INDIR: case NEG:
126 case JUMP:
127 case ARG:
128 /* 1 kid */
129 printf("\t%s%p -> %s%p;\n",fname,p,fname,left);
130 break;
131
132 case RET:
133 /* 0 or 1 kid */
134 if (optype(p->op) != V)
135 printf("\t%s%p -> %s%p;\n",fname,p,fname,left);
136 break;
137
138 case CALL:
139 /* 1 or 2 kids */
140 printf("\t%s%p -> %s%p;\n", fname,p,fname,left);
141 if (optype(p->op) == B)
142 printf("\t%s%p -> %s%p [label=\"res\"];\n",fname,p,fname,right);
143 break;
144 }
145 }
146
147 static Node *linearize(Node p, Node *last, Node next) {
148 if (p && !p->x.visited) {
149 if ( optimizelevel>0 ) {
150 switch (generic(p->op)) {
151 case CNST:
152 case ADDRG: case ADDRL: case ADDRF:
153 p->x.optimized=1;
154 p->x.result=p->syms[0];
155 p->x.adrmode=p->syms[0]->x.adrmode;
156 p->x.name=p->syms[0]->x.name;
157 return last;
158 }
159 }
160 last = linearize(p->kids[0], last, NULL);
161 last = linearize(p->kids[1], last, NULL);
162 p->x.visited = 1;
163 *last = p;
164 last = &p->x.next;
165 }
166 *last = next;
167 return last;
168 }
169
170 void progbeg(int argc,char *argv[]) {
171 int i;
172 for(i=1;i<argc;i++) {
173 if (strncmp(argv[i],"-N",2)==0) {
174 NamePrefix=argv[i]+2;
175 } else if (strcmp(argv[i],"-G")==0) {
176 graph_output=true;
177 } else if (strcmp(argv[i],"-O")==0) {
178 optimizelevel=3;
179 } else if (strcmp(argv[i],"-O0")==0) {
180 optimizelevel=0; /* no optimization */
181 } else if (strcmp(argv[i],"-O1")==0) {
182 optimizelevel=1; /* remove ADDR and CNST leaves */
183 } else if (strcmp(argv[i],"-O2")==0) {
184 optimizelevel=2; /* allocate register variables */
185 /* and do some easy opt. (INC...) */
186 } else if (strcmp(argv[i],"-O3")==0) {
187 optimizelevel=3; /* optimizes INDIR, ASGN ... */
188 } else {
189 fprintf(stderr,"Unknown option %s\n",argv[i]);
190 exit(1);
191 }
192 }
193 if (graph_output) optimizelevel=0;
194 if (graph_output) printf("digraph Frontend_output {\n");
195 else print(version);
196
197 /* 8 virtual registers */
198 for (i=0;i<8;i++) regname[i]=stringf("reg%d",i);
199
200 /* No spilling for simplicity purpose:
201 * 32 temporaries for integer/pointer expressions, 32 for float expresssions.
202 * => it should be nearly impossible to have such a complex expression
203 * that we run out of temporaries (a compilation error will be raised in such
204 * a pathological case).
205 * All 32 integer/pointer temporaries in page zero,
206 * and all 32 floating-point temporaries on stack frame.
207 * => the runtime has to declare enough temporaries in zero page,
208 * previous versions only used tmp0-tmp7...
209 */
210 for (i=0;i<32;i++) {
211 temp[i] = newtemp(STATIC,I);
212 flt_temp[i] = newtemp(STATIC,F);
213 }
214 for (i=0;i<32;i++) {
215 temp[i]->x.name=stringf("tmp%d",i);
216 temp[i]->x.adrmode='Z';
217 }
218 }
219
220 void progend(void) {
221 if (graph_output) printf("}\n");
222 }
223
224 static bool is_temporary(Symbol s) {
225 int i;
226 for (i=0;i<32;i++)
227 if (s==temp[i]) return true;
228 return false;
229 }
230
231 void defsymbol(Symbol p) {
232 if (p->x.name) return;
233 if (p->scope == CONSTANTS) {
234 p->x.name = p->name;
235 if (p->x.name[0]=='0' && p->x.name[1]=='x') {
236 p->x.name[0]=' '; p->x.name[1]='$';
237 }
238 } else if (p->sclass == STATIC)
239 p->x.name = stringf("L%s%d", NamePrefix, genlabel(1));
240 else if (p->generated)
241 p->x.name = stringf("L%s%s", NamePrefix, p->name);
242 else
243 p->x.name = stringf("_%s", p->name);
244 p->x.adrmode = 'C';
245
246 }
247
248 void export(Symbol p) {}
249 void import(Symbol p) {}
250 void segment(int s) {}
251 void global(Symbol p) { if (!graph_output) print("%s\n", p->x.name); }
252
253 void printfloat(double val)
254 {
255 int i,exp=32,negative=0;
256 double two_pow31,two_pow32;
257 unsigned long mantissa;
258
259 if (val==0.0) {
260 print("\tDB(0)\n");
261 print("\tDB(0)\n");
262 print("\tDB(0)\n");
263 print("\tDB(0)\n");
264 print("\tDB(0)\n");
265 return;
266 }
267 if (val<0.0) { negative=1; val= -val; }
268 for (two_pow31=1.0,i=0;i<31;i++) two_pow31*=2;
269 two_pow32=two_pow31*2;
270 while (val>=two_pow32) {
271 val/=2;
272 exp++;
273 }
274 while (val<two_pow31) {
275 val*=2;
276 exp--;
277 }
278 if (!negative) val-=two_pow31;
279 mantissa=val;
280 print("\tDB($%x)\n",exp+128);
281 print("\tDB($%x)\n",(mantissa>>24)&0xFF);
282 print("\tDB($%x)\n",(mantissa>>16)&0xFF);
283 print("\tDB($%x)\n",(mantissa>>8)&0xFF);
284 print("\tDB($%x)\n",mantissa&0xFF);
285 }
286
287
288 void defconst(int ty, Value v) {
289 if (graph_output) return;
290 switch (ty) {
291 case C: print("\tDB(%d)\n", v.uc); break;
292 case S: print("\tDB(%d)\n", v.us); break;
293 case I: print("\tDW(%d)\n", v.i ); break;
294 case U: print("\tDW($%x)\n", v.u ); break;
295 case P: print("\tDW($%x)\n", v.p ); break;
296 case F: printfloat(v.f); break;
297 case D: printfloat(v.d); break;
298 default: assert(0);
299 }
300 }
301
302 void defstring(int len, char *s) {
303 if (graph_output) return;
304 while (len > 0) {
305 print("\tDB($%x)\n",(unsigned char)*s++);
306 len--;
307 }
308 }
309
310 void defaddress(Symbol p) {
311 if (graph_output) return;
312 print("\tDW(%s)\n",p->x.name);
313 }
314
315 void space(int n) {
316 if (graph_output) return;
317 print("\tZERO(%d)\n",n);
318 }
319
320 int allocreg(Symbol p) {
321 if (nbregs==8 || p->type->size==5) return 0;
322 p->x.name=regname[nbregs];
323 p->x.adrmode='R';
324 nbregs++;
325 return 1;
326 }
327
328 void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
329 int i;
330
331 if (graph_output) {
332 printf("subgraph cluster%s {\n", f->x.name);
333 printf("\tlabel=\"%s\";\n",f->x.name);
334 }
335 localsize=offset=tmpsize=nbregs=0; fname=f->x.name;
336
337 for (i=0;i<32;i++) flt_temp[i]->x.name="******";
338 for (i=8;i<32;i++) temp[i]->x.name="******";
339
340 for (i = 0; caller[i] && callee[i]; i++) {
341 caller[i]->x.name=stringf(graph_output?"param(%d)":"(ap),%d",offset);
342 caller[i]->x.adrmode='A';
343 offset+=caller[i]->type->size;
344 if (optimizelevel>1 && callee[i]->sclass==REGISTER && allocreg(callee[i]))
345 ; /* allocreg ok */
346 else {
347 callee[i]->x.adrmode=caller[i]->x.adrmode;
348 callee[i]->x.name=caller[i]->x.name;
349 callee[i]->sclass=AUTO;
350 }
351 }
352 busy=localsize=0; offset=6;
353 gencode(caller,callee);
354
355 omit_frame=(i==0 && localsize==6);
356 if (!graph_output) {
357 print("%s\n",fname);
358 if (optimizelevel>1 && omit_frame && nbregs==0)
359 ;
360 else print("\tENTER(%d,%d)\n",nbregs,localsize);
361 if (isstruct(freturn(f->type)))
362 print("\tMOVW_DY(op1,(fp),6)\n");
363 }
364 emitcode();
365
366 if (graph_output) printf("}\n");
367 }
368
369 void local(Symbol p) {
370 if (optimizelevel>1 && p->sclass==REGISTER && allocreg(p))
371 return; /* allocreg ok */
372 if (p->x.name && p->x.name[0]!='*') return; /* keep previous local (it isn't busy) */
373 p->x.name = stringf(graph_output?"local(%d)":"(fp),%d",offset);
374 p->x.adrmode = 'A';
375 p->sclass = AUTO;
376 offset+=p->type->size;
377 }
378
379 void address(Symbol q, Symbol p, int n) {
380 q->x.name = stringf("%s%s%d", p->x.name, n >= 0 ? "+" : "", n);
381 q->x.adrmode=p->x.adrmode;
382 }
383
384 void blockbeg(Env *e) { e->offset = offset; }
385 void blockend(Env *e) {
386 if (offset > localsize) localsize = offset;
387 offset = e->offset;
388 }
389
390 static void gettmp(Node p) {
391 int t;
392 if ( optype(p->op)!=F && optype(p->op)!=D ) {
393 for (t=0;t<32;t++)
394 if ((busy&(1<<t))==0) {
395 busy |= 1<<t;
396 p->x.result=temp[t];
397 p->x.adrmode='Z';
398
399 p->x.name = temp[t]->x.name;
400 return;
401 }
402 } else
403 for (t=0;t<32;t++)
404 if ((busy_flt&(1<<t))==0) {
405 busy_flt |= 1<<t;
406 p->x.result=flt_temp[t];
407 p->x.adrmode='Y';
408 local(flt_temp[t]);
409 p->x.name = flt_temp[t]->x.name;
410 return;
411 }
412 perror("Too complex expression"); exit(1);
413 }
414
415 static void releasetmp(Node p) {
416 if (!p) return;
417 assert(p->count!=0);
418 p->count--;
419 switch(generic(p->op)) {
420 case ADDRG: case ADDRL: case ADDRF: case CNST:
421 if (optimizelevel>0) return;
422 break;
423 case INDIR:
424 if (p->x.optimized) return;
425 }
426 if (p->count==0) {
427 int i;
428 for (i=0;i<32;i++) {
429 if (p->x.result == temp[i]) busy &= ~(1<<i);
430 if (p->x.result==flt_temp[i]) busy_flt &= ~(1<<i);
431 }
432 }
433 }
434
435 void print_busy() {
436 if (busy) fprintf(stderr,"Busy tmps when calling function: %x\n", busy);
437 if (busy_flt) fprintf(stderr,"Busy flt_tmps when calling function: %x\n", busy_flt);
438 }
439
440 static bool is_dereferenceable(char adrmode)
441 {
442 return adrmode=='C' || adrmode=='R' || adrmode=='A' || adrmode=='Z';
443 }
444
445 static char dereference(char adrmode)
446 {
447 switch (adrmode) {
448 case 'C': return 'D';
449 case 'R': return 'Z';
450 case 'A': return 'Y';
451 case 'Z': return 'I';
452 default:
453 assert(is_dereferenceable(adrmode));
454 return 0;
455 }
456
457 }
458
459 static int needtmp(Node p) {
460 Node left = p->kids[0];
461 if (graph_output) return 0;
462 switch (generic(p->op)) {
463 case ADDRF: case ADDRG: case ADDRL:
464 case CNST:
465 assert(optimizelevel==0);
466 return 1;
467 case INDIR:
468 if (optimizelevel!=0)
469 if (optype(p->op)==B) { /* remove all INDIRB nodes */
470 p->x.optimized = 1;
471 p->x.result = left->x.result;
472 p->x.name = p->x.result->x.name;
473 p->x.adrmode = left->x.adrmode;
474 return 0;
475 }
476
477 if (optimizelevel>=3) {
478 /* these conditions must be true to optimize (=get rid of) an INDIR node:
479 * - this INDIR node is referenced only once
480 * (otherwise by delaying the indirection in parent nodes we would duplicate it,
481 * and hence could have different behavior (TODO: example needed))
482 * - the address mode of the INDIR operand is "de-referenceable"
483 */
484 if (p->count <= 1 && is_dereferenceable(left->x.adrmode)) {
485 p->x.optimized = 1;
486 p->x.result = left->x.result;
487 p->x.name = left->x.result->x.name;
488 p->x.adrmode = dereference(left->x.adrmode);
489 return 0;
490 }
491 }
492 return 1;
493 case ASGN:
494 case ARG:
495 case EQ: case GE: case GT: case LE: case LT: case NE:
496 case RET:
497 case JUMP: case LABEL:
498 return 0;
499 case CALL:
500 if (optype(p->op)==B) return 0;
501 if (p->count==0) p->op=CALLV;
502 if (optype(p->op)==V) return 0;
503 else return 1;
504 default:
505 return 1;
506 }
507 }
508
509 static void tmpalloc(Node p) {
510 Node left = p->kids[0], right = p->kids[1];
511 p->x.optimized=0;
512 p->x.name="*******";
513 p->x.adrmode='*';
514 releasetmp(left); releasetmp(right);
515
516 switch (generic(p->op)) {
517 case ARG:
518 p->x.argoffset = argoffset;
519 argoffset += p->syms[0]->u.c.v.i;
520 break;
521 case CALL:
522 p->x.argoffset = argoffset;
523 p->x.busy = busy;
524 argoffset = 0;
525 break;
526 case ASGN:
527 if (optimizelevel>=3) {
528 /* these conditions must be true to optimize (=get rid of) an ASGN node:
529 * - it gets its value (right child node) from a temporary variable,
530 * - the right child child has not been eliminated (optimized)
531 * - the ASGN node comes just after its right child node
532 * (TODO: could it be more general? => re-ordering ?)
533 * - the left value is de-referenceable,
534 * - and the temporary variable is not used afterwards,
535 *
536 * In this case, we try to directly assign the result inside the right child node
537 * (as the result of this child node)
538 */
539 if (optype(p->op)!=B // no optimization on ASGNB (struct) nodes
540 && !right->x.optimized
541 && p==right->x.next
542 && is_temporary(right->x.result)
543 && is_dereferenceable(left->x.adrmode)
544 && right->count==0
545 )
546 {
547 p->x.optimized = 1;
548 right->x.result = left->x.result;
549 right->x.name = left->x.name;
550 right->x.adrmode = dereference(left->x.adrmode);
551 }
552 }
553 break;
554 }
555 if (needtmp(p)) gettmp(p);
556 }
557
558 Node gen(Node p) {
559 Node head, *last;
560 for (last = &head; p; p = p->link)
561 last = linearize(p, last, 0);
562 for (p = head; p; p = p->x.next) {
563 if (graph_output) print_graph_node(p);
564 else tmpalloc(p);
565 }
566 return head;
567 }
568
569 void asmcode(char *str, Symbol argv[]) {
570 for ( ; *str; str++)
571 if (*str == '%' && str[1] >= 0 && str[1] <= 9)
572 print("%s", argv[(int)*++str]->x.name);
573 else
574 print("%c", *str);
575 print("\n");
576 }
577
578 static Node a,b,r;
579
580 /* avoid some proliferation of macros by rewriting
581 * Zero-Page address mode as Direct address mode,
582 * Register addresses as Constants,
583 * and Indirect address mode as Indirect Y-indexed
584 */
585 static char simple_adrmode(char adrmode) {
586 if (adrmode=='Z') return 'D';
587 else if (adrmode=='R') return 'C';
588 else if (adrmode=='I') return 'Y';
589 else return adrmode;
590 }
591 static char reduced_adrmode(char adrmode) {
592 if (adrmode=='R') return 'C';
593 else if (adrmode=='I') return 'Y';
594 else return adrmode;
595 }
596 static char *output_name(Symbol s) {
597 return s->x.adrmode=='I' ? stringf("(%s),0",s->x.name) : s->x.name;
598 }
599 static char *output_arg(Node n) {
600 if (optimizelevel==0) return n->x.name;
601 return n->x.adrmode=='I' ? stringf("(%s),0",n->x.name) : n->x.name;
602 }
603
604 static void binary(char *inst) {
605 if (optimizelevel==0)
606 print("\t%s(%s,%s,%s)\n"
607 ,inst
608 ,output_arg(a)
609 ,output_arg(b)
610 ,output_arg(r));
611 else
612 print("\t%s_%c%c%c(%s,%s,%s)\n"
613 ,inst
614 ,simple_adrmode(a->x.adrmode)
615 ,simple_adrmode(b->x.adrmode)
616 ,simple_adrmode(r->x.adrmode)
617 ,output_arg(a)
618 ,output_arg(b)
619 ,output_arg(r));
620 }
621
622 static void unary(char *inst) {
623 if (optimizelevel==0)
624 print("\t%s(%s,%s)\n"
625 ,inst
626 ,output_arg(a)
627 ,output_arg(r));
628 else
629 print("\t%s_%c%c(%s,%s)\n"
630 ,inst
631 ,simple_adrmode(a->x.adrmode)
632 ,simple_adrmode(r->x.adrmode)
633 ,output_arg(a)
634 ,output_arg(r));
635 }
636
637 static void compare0(char *inst) {
638 print("\t%s_%c(%s,%s)\n"
639 ,inst
640 ,simple_adrmode(a->x.adrmode)
641 ,output_arg(a)
642 ,r->syms[0]->x.name);
643 }
644
645 static void compare(char *inst) {
646 if (optimizelevel==0)
647 print("\t%s(%s,%s,%s)\n"
648 ,inst
649 ,output_arg(a)
650 ,output_arg(b)
651 ,r->syms[0]->x.name);
652 else
653 print("\t%s_%c%c(%s,%s,%s)\n"
654 ,inst
655 ,simple_adrmode(a->x.adrmode)
656 ,simple_adrmode(b->x.adrmode)
657 ,output_arg(a)
658 ,output_arg(b)
659 ,r->syms[0]->x.name);
660 }
661
662 static void save_busy(Node p) {
663 int i, offset=p->x.argoffset;
664 for (/*int*/ i=0; i<8; i++) {
665 if (p->x.busy & (1<<i)) {
666 // save on stack and increase the argsize
667 print("\tSAVE(tmp%d,(sp),%d)\n", i, offset);
668 offset += 2;
669 }
670 }
671 // update the CALL's argoffset so that it is passed to the callee
672 p->x.argoffset = offset;
673 }
674
675 static void restore_busy(Node p) {
676 int i, offset=p->x.argoffset;
677 for (/*int*/ i=7; i>=0; i--) { // reverse order
678 if (p->x.busy & (1<<i)) {
679 offset -= 2;
680 print("\tRESTORE((sp),%d,tmp%d)\n", offset, i);
681 }
682 }
683 }
684
685 static void emitdag0(Node p) {
686 a = p->kids[0]; b = p->kids[1]; r=p;
687 switch (p->op) {
688 case BANDU: binary("BANDU"); break;
689 case BORU: binary("BORU" ); break;
690 case BXORU: binary("BXORU"); break;
691 case ADDD: binary("ADDD"); break;
692 case ADDF: binary("ADDF"); break;
693 case ADDI: binary("ADDI"); break;
694 case ADDP: binary("ADDP"); break;
695 case ADDU: binary("ADDU"); break;
696 case SUBD: binary("SUBD"); break;
697 case SUBF: binary("SUBF"); break;
698 case SUBI: binary("SUBI"); break;
699 case SUBP: binary("SUBP"); break;
700 case SUBU: binary("SUBU"); break;
701 case MULD: binary("MULD"); break;
702 case MULF: binary("MULF"); break;
703 case MULI: binary("MULI"); break;
704 case MULU: binary("MULU"); break;
705 case DIVD: binary("DIVD"); break;
706 case DIVF: binary("DIVF"); break;
707 case DIVI: binary("DIVI"); break;
708 case DIVU: binary("DIVU"); break;
709 case MODI: binary("MODI"); break;
710 case MODU: binary("MODU"); break;
711 case RSHU: binary("RSHU"); break;
712 case RSHI: binary("RSHI"); break;
713 case LSHI: binary("LSHI"); break;
714 case LSHU: binary("LSHU"); break;
715 case INDIRC: unary("INDIRC"); break;
716 case INDIRS: unary("INDIRS"); break;
717 case INDIRI: unary("INDIRI"); break;
718 case INDIRP: unary("INDIRP"); break;
719 case INDIRD: unary("INDIRD"); break;
720 case INDIRF: unary("INDIRF"); break;
721 case INDIRB: unary("INDIRB"); break;
722 case BCOMU: unary("BCOMU" ); break;
723 case NEGD: unary("NEGD" ); break;
724 case NEGF: unary("NEGF" ); break;
725 case NEGI: unary("NEGI" ); break;
726 case CVCI: unary("CVCI"); break;
727 case CVSI: unary("CVSI"); break;
728 case CVCU: unary("CVCU"); break;
729 case CVSU: unary("CVSU"); break;
730 case CVUC: unary("CVUC"); break;
731 case CVUS: unary("CVUS"); break;
732 case CVIC: unary("CVIC"); break;
733 case CVIS: unary("CVIS"); break;
734 case CVPU: unary("CVPU"); break;
735 case CVUP: unary("CVUP"); break;
736 case CVIU: unary("CVIU"); break;
737 case CVUI: unary("CVUI"); break;
738 case CVID: unary("CVID" ); break;
739 case CVDF: unary("CVDF"); break;
740 case CVFD: unary("CVFD"); break;
741 case CVDI: unary("CVDI" ); break;
742 case RETD: print("\tRETD(%s)\n",output_arg(a)); break;
743 case RETF: print("\tRETF(%s)\n",output_arg(a)); break;
744 case RETI: print("\tRETI(%s)\n",output_arg(a)); break;
745 case RETV: print("\tRETV\n"); break;
746 case ADDRGP: print("\tADDRGP(%s,%s)\n"
747 ,p->syms[0]->x.name
748 ,output_arg(p)); break;
749 case ADDRFP: print("\tADDRFP(%s,%s)\n"
750 ,p->syms[0]->x.name
751 ,output_arg(p)); break;
752 case ADDRLP: print("\tADDRLP(%s,%s)\n"
753 ,p->syms[0]->x.name
754 ,output_arg(p)); break;
755 case CNSTC: print("\tCNSTC(%s,%s)\n" ,output_name(p->syms[0]) ,output_arg(p)); break;
756 case CNSTS: print("\tCNSTS(%s,%s)\n" ,output_name(p->syms[0]) ,output_arg(p)); break;
757 case CNSTI: print("\tCNSTI(%s,%s)\n" ,output_name(p->syms[0]) ,output_arg(p)); break;
758 case CNSTU: print("\tCNSTU(%s,%s)\n" ,output_name(p->syms[0]) ,output_arg(p)); break;
759 case CNSTP: print("\tCNSTP(%s,%s)\n" ,output_name(p->syms[0]) ,output_arg(p)); break;
760 case JUMPV: print("\tJUMPV(%s)\n" , output_arg(a)); break;
761 case ASGNB: print("\tASGNB(%s,%s,%s)\n"
762 ,output_arg(b)
763 ,output_arg(a)
764 ,output_name(p->syms[0])); break;
765 case ASGNC: print("\tASGNC(%s,%s)\n" ,output_arg(b) ,output_arg(a)); break;
766 case ASGNS: print("\tASGNS(%s,%s)\n" ,output_arg(b) ,output_arg(a)); break;
767 case ASGND: print("\tASGND(%s,%s)\n" ,output_arg(b) ,output_arg(a)); break;
768 case ASGNF: print("\tASGNF(%s,%s)\n" ,output_arg(b) ,output_arg(a)); break;
769 case ASGNI: print("\tASGNI(%s,%s)\n" ,output_arg(b) ,output_arg(a)); break;
770 case ASGNP: print("\tASGNP(%s,%s)\n" ,output_arg(b) ,output_arg(a)); break;
771 case ARGB: print("\tARGB(%s,(sp),%d,%s)\n"
772 ,output_arg(a)
773 ,p->x.argoffset
774 ,output_name(p->syms[0])); break;
775 case ARGD: print("\tARGD(%s,%d)\n" ,output_arg(a) ,p->x.argoffset); break;
776 case ARGF: print("\tARGF(%s,%d)\n" ,output_arg(a) ,p->x.argoffset); break;
777 case ARGI: print("\tARGI(%s,%d)\n" ,output_arg(a) ,p->x.argoffset); break;
778 case ARGP: print("\tARGP(%s,%d)\n" ,output_arg(a) ,p->x.argoffset); break;
779 case CALLB:
780 save_busy(p);
781 print("\tMOVW_%cD(%s,op1)\n"
782 ,simple_adrmode(b->x.adrmode)
783 ,output_arg(b));
784 print("\tCALLV(%s,%d)\n"
785 ,output_arg(a)
786 ,p->x.argoffset);
787 restore_busy(p);
788 break;
789 case CALLV:
790 save_busy(p);
791 print("\tCALLV(%s,%d)\n" ,output_arg(a) ,p->x.argoffset);
792 restore_busy(p);
793 break;
794 case CALLD:
795 save_busy(p);
796 print("\tCALLD(%s,%d,%s)\n"
797 ,output_arg(a)
798 ,p->x.argoffset
799 ,output_arg(p));
800 restore_busy(p);
801 break;
802 case CALLF:
803 save_busy(p);
804 print("\tCALLF(%s,%d,%s)\n"
805 ,output_arg(a)
806 ,p->x.argoffset
807 ,output_arg(p));
808 restore_busy(p);
809 break;
810 case CALLI:
811 save_busy(p);
812 print("\tCALLI(%s,%d,%s)\n"
813 ,output_arg(a)
814 ,p->x.argoffset
815 ,output_arg(p));
816 restore_busy(p);
817 break;
818 case EQD: compare("EQD" ); break;
819 case EQF: compare("EQF" ); break;
820 case EQI: compare("EQI" ); break;
821 case GED: compare("GED" ); break;
822 case GEF: compare("GEF" ); break;
823 case GEI: compare("GEI" ); break;
824 case GEU: compare("GEU" ); break;
825 case GTD: compare("GTD" ); break;
826 case GTF: compare("GTF" ); break;
827 case GTI: compare("GTI" ); break;
828 case GTU: compare("GTU" ); break;
829 case LED: compare("LED" ); break;
830 case LEF: compare("LEF" ); break;
831 case LEI: compare("LEI" ); break;
832 case LEU: compare("LEU" ); break;
833 case LTD: compare("LTD" ); break;
834 case LTF: compare("LTF" ); break;
835 case LTI: compare("LTI" ); break;
836 case LTU: compare("LTU" ); break;
837 case NED: compare("NED" ); break;
838 case NEF: compare("NEF" ); break;
839 case NEI: compare("NEI" ); break;
840 case LABELV: print("%s\n", p->syms[0]->x.name); break;
841 default: assert(0);
842 }
843 }
844
845 static void emitdag(Node p) {
846
847 a = p->kids[0]; b = p->kids[1]; r=p;
848
849 switch (p->op) {
850 case BANDU: binary("ANDW"); break;
851 case BORU: binary("ORW" ); break;
852 case BXORU: binary("XORW"); break;
853 case ADDD: case ADDF: binary("ADDF"); break;
854 case ADDI: case ADDP: case ADDU:
855 if (optimizelevel>=2
856 && strcmp(a->x.name,p->x.name)==0
857 && strcmp(b->x.name,"1")==0
858 && (p->x.adrmode=='Z' || p->x.adrmode=='D'))
859 print("\tINCW_%c(%s)\n" ,simple_adrmode(p->x.adrmode) ,output_arg(p));
860 else
861 binary("ADDW");
862 break;
863 case SUBD: case SUBF: binary("SUBF"); break;
864 case SUBI: case SUBP: case SUBU:
865 if (optimizelevel>=2
866 && strcmp(a->x.name,p->x.name)==0
867 && strcmp(b->x.name,"1")==0
868 && (p->x.adrmode=='Z' || p->x.adrmode=='D'))
869 print("\tDECW_%c(%s)\n" ,simple_adrmode(p->x.adrmode) ,output_arg(p));
870 else
871 binary("SUBW");
872 break;
873 case MULD: case MULF: binary("MULF"); break;
874 case MULI: binary("MULI"); break;
875 case MULU: binary("MULU"); break;
876 case DIVD: case DIVF: binary("DIVF"); break;
877 case DIVI: binary("DIVI"); break;
878 case DIVU: binary("DIVU"); break;
879 case MODI: binary("MODI"); break;
880 case MODU: binary("MODU"); break;
881 case RSHU: case RSHI: binary("RSHW"); break;
882 case LSHI: case LSHU:
883 if (optimizelevel>=2 && strcmp(b->x.name,"1")==0) {
884 unary("LSH1W");
885 } else binary("LSHW");
886 break;
887 case INDIRC: case INDIRS:
888 if (!p->x.optimized)
889 print("\tINDIRB_%c%c(%s,%s)\n"
890 ,reduced_adrmode(a->x.adrmode) // keep 'Z' adrmode different from 'D'
891 ,simple_adrmode(r->x.adrmode)
892 ,output_arg(a)
893 ,output_arg(r));
894 break;
895 case INDIRI: case INDIRP:
896 if (!p->x.optimized)
897 print("\tINDIRW_%c%c(%s,%s)\n"
898 ,reduced_adrmode(a->x.adrmode) // keep 'Z' adrmode different from 'D'
899 ,simple_adrmode(r->x.adrmode)
900 ,output_arg(a)
901 ,output_arg(r));
902 break;
903 case INDIRD: case INDIRF:
904 if (!p->x.optimized)
905 unary("INDIRF");
906 break;
907 case INDIRB:
908 if (!p->x.optimized)
909 unary("INDIRS");
910 break;
911 case BCOMU: unary("COMW" ); break;
912 case NEGD: case NEGF: unary("NEGF" ); break;
913 case NEGI: unary("NEGI" ); break;
914 case CVCI: case CVSI: unary("CSBW"); break;
915 case CVCU: case CVSU: unary("CZBW"); break;
916 case CVUC: case CVUS: case CVIC: case CVIS:
917 if (optimizelevel<=1 || strcmp(a->x.name,p->x.name)!=0)
918 unary("CWB");
919 break;
920 case CVPU: case CVUP: case CVIU: case CVUI:
921 if (optimizelevel<=1 || strcmp(a->x.name,p->x.name)!=0)
922 unary("MOVW");
923 break;
924 case CVID: unary("CIF" ); break;
925 case CVDF: case CVFD:
926 if (optimizelevel<=1 || strcmp(a->x.name,p->x.name)!=0)
927 unary("MOVF");
928 break;
929 case CVDI: unary("CFI" ); break;
930 case RETD: case RETF:
931 if (optimizelevel>=2 && omit_frame && nbregs==0)
932 print("\tRETF_%c(%s)\n"
933 ,simple_adrmode(a->x.adrmode)
934 ,output_arg(a));
935 else
936 print("\tLEAVEF_%c(%s)\n"
937 ,simple_adrmode(a->x.adrmode)
938 ,output_arg(a));
939 break;
940 case RETI:
941 if (optimizelevel>=2 && omit_frame && nbregs==0)
942 print("\tRETW_%c(%s)\n"
943 ,simple_adrmode(a->x.adrmode)
944 ,output_arg(a));
945 else
946 print("\tLEAVEW_%c(%s)\n"
947 ,simple_adrmode(a->x.adrmode)
948 ,output_arg(a));
949 break;
950 case RETV:
951 if (optimizelevel>=2 && omit_frame && nbregs==0)
952 print("\tRET\n");
953 else print("\tLEAVE\n");
954 break;
955 case ADDRGP: case ADDRFP: case ADDRLP:
956 if (optimizelevel==0)
957 print("\tADDR_%c%c(%s,%s)\n"
958 ,simple_adrmode(p->syms[0]->x.adrmode)
959 ,simple_adrmode(p->x.adrmode)
960 ,output_name(p->syms[0])
961 ,output_arg(p));
962 break;
963 case CNSTC: case CNSTS:
964 case CNSTI: case CNSTU:
965 case CNSTP:
966 if (optimizelevel==0)
967 print("\tCNST_%c%c(%s,%s)\n"
968 ,simple_adrmode(p->syms[0]->x.adrmode)
969 ,simple_adrmode(p->x.adrmode)
970 ,output_name(p->syms[0])
971 ,output_arg(p));
972 break;
973 case JUMPV:
974 print("\tJUMP_%c(%s)\n" ,simple_adrmode(a->x.adrmode), output_arg(a));
975 break;
976 case ASGNB:
977 print("\tASGNS_%c%c(%s,%s,%s)\n"
978 ,simple_adrmode(b->x.adrmode)
979 ,reduced_adrmode(a->x.adrmode) // keep 'Z' adrmode different from 'D'
980 ,output_arg(b)
981 ,output_arg(a)
982 ,output_name(p->syms[0]));
983 break;
984 case ASGNC: case ASGNS:
985 if (!p->x.optimized)
986 print("\tASGNB_%c%c(%s,%s)\n"
987 ,simple_adrmode(b->x.adrmode)
988 ,reduced_adrmode(a->x.adrmode) // keep 'Z' adrmode different from 'D'
989 ,output_arg(b)
990 ,output_arg(a));
991 break;
992 case ASGND: case ASGNF:
993 if (!p->x.optimized)
994 print("\tASGNF_%c%c(%s,%s)\n"
995 ,simple_adrmode(b->x.adrmode)
996 ,reduced_adrmode(a->x.adrmode) // keep 'Z' adrmode different from 'D'
997 ,output_arg(b)
998 ,output_arg(a));
999 break;
1000 case ASGNI: case ASGNP:
1001 if (!p->x.optimized)
1002 print("\tASGNW_%c%c(%s,%s)\n"
1003 ,simple_adrmode(b->x.adrmode)
1004 ,reduced_adrmode(a->x.adrmode) // keep 'Z' adrmode different from 'D'
1005 ,output_arg(b)
1006 ,output_arg(a));
1007 break;
1008 case ARGB:
1009 print("\tARGS_%c(%s,(sp),%d,%s)\n"
1010 ,simple_adrmode(a->x.adrmode)
1011 ,output_arg(a)
1012 ,p->x.argoffset
1013 ,output_name(p->syms[0]));
1014 break;
1015 case ARGD: case ARGF:
1016 if (!p->x.optimized)
1017 print("\tARGF_%c(%s,(sp),%d)\n"
1018 ,simple_adrmode(a->x.adrmode)
1019 ,output_arg(a)
1020 ,p->x.argoffset);
1021 break;
1022 case ARGI: case ARGP:
1023 if (!p->x.optimized)
1024 print("\tARGW_%c(%s,(sp),%d)\n"
1025 ,simple_adrmode(a->x.adrmode)
1026 ,output_arg(a)
1027 ,p->x.argoffset);
1028 break;
1029 case CALLB:
1030 save_busy(p);
1031 print("\tMOVW_%cD(%s,op1)\n"
1032 ,simple_adrmode(b->x.adrmode)
1033 ,output_arg(b));
1034 print("\tCALLV_%c(%s,%d)\n"
1035 ,simple_adrmode(a->x.adrmode)
1036 ,output_arg(a)
1037 ,p->x.argoffset);
1038 restore_busy(p);
1039 break;
1040 case CALLV:
1041 save_busy(p);
1042 print("\tCALLV_%c(%s,%d)\n"
1043 ,simple_adrmode(a->x.adrmode)
1044 ,output_arg(a)
1045 ,p->x.argoffset);
1046 restore_busy(p);
1047 break;
1048 case CALLD: case CALLF:
1049 save_busy(p);
1050 print("\tCALLF_%c%c(%s,%d,%s)\n"
1051 ,simple_adrmode(a->x.adrmode)
1052 ,simple_adrmode(p->x.adrmode)
1053 ,output_arg(a)
1054 ,p->x.argoffset
1055 ,output_arg(p));
1056 restore_busy(p);
1057 break;
1058 case CALLI:
1059 save_busy(p);
1060 print("\tCALLW_%c%c(%s,%d,%s)\n"
1061 ,simple_adrmode(a->x.adrmode)
1062 ,simple_adrmode(p->x.adrmode)
1063 ,output_arg(a)
1064 ,p->x.argoffset
1065 ,output_arg(p));
1066 restore_busy(p);
1067 break;
1068 case EQD: case EQF: compare("EQF" ); break;
1069 case EQI:
1070 if (optimizelevel>=2 && strcmp(b->x.name,"0")==0)
1071 compare0("EQ0W");
1072 else compare("EQW" );
1073 break;
1074 case GED: case GEF: compare("GEF" ); break;
1075 case GEI: compare("GEI" ); break;
1076 case GEU: compare("GEU" ); break;
1077 case GTD: case GTF: compare("GTF" ); break;
1078 case GTI: compare("GTI" ); break;
1079 case GTU: compare("GTU" ); break;
1080 case LED: case LEF: compare("LEF" ); break;
1081 case LEI: compare("LEI" ); break;
1082 case LEU: compare("LEU" ); break;
1083 case LTD: case LTF: compare("LTF" ); break;
1084 case LTI: compare("LTI" ); break;
1085 case LTU: compare("LTU" ); break;
1086 case NED: case NEF: compare("NEF" ); break;
1087 case NEI:
1088 if (optimizelevel>=2 && strcmp(b->x.name,"0")==0)
1089 compare0("NE0W");
1090 else compare("NEW" );
1091 break;
1092 case LABELV:
1093 print("%s\n", p->syms[0]->x.name); break;
1094 default: assert(0);
1095 }
1096 }
1097
1098 void emit(Node p) {
1099 if (graph_output) return;
1100 for (; p; p=p->x.next)
1101 if (optimizelevel==0) emitdag0(p);
1102 else emitdag(p);
1103 }

  ViewVC Help
Powered by ViewVC 1.1.26