7c20410fe9c91722d480ccd177a9d0d1dd3ea7a6
[43bsd.git] / lib / pcc / code.c
1 #include <stab.h>
2 #include <stdio.h>
3 /*#include "config.h" manifest.h*/
4 /*#include "macdefs.h" manifest.h*/
5 /*#include "manifest.h" pass1.h*/
6 /*#include "ndu.h" manifest.h*/
7 #include "pass1.h"
8 /*#include "pcclocal.h" macdefs.h*/
9
10 #if defined(DOSCCS) && !defined(lint)
11 static char *sccsid ="@(#)code.c        1.5 (Berkeley) 8/23/85";
12 #endif
13
14 /*# include "pass1.h"*/
15 /*# include <sys/types.h>*/
16 /*# include <a.out.h>*/
17 /*# include <stab.h>*/
18
19 int proflg = 0; /* are we generating profiling code? */
20 int strftn = 0;  /* is the current function one which returns a value */
21 int gdebug;
22 int fdefflag;  /* are we within a function definition ? */
23 char NULLNAME[8];
24 int labelno;
25
26 # define putstr(s)      fputs((s), stdout)
27
28 int branch(n) int n; {
29         /* output a branch to label n */
30         /* exception is an ordinary function branching to retlab: then, return */
31         if( n == retlab && !strftn ){
32                 putstr( "       ret\n" );
33                 }
34         else printf( "  jbr     L%d\n", n );
35         }
36
37 int lastloc = { -1 };
38
39 short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
40 #define LOG2SZ 9
41
42 int defalign(n) int n; {
43         /* cause the alignment to become a multiple of n */
44         n /= SZCHAR;
45         if( lastloc != PROG && n > 1 ) printf( "        .align  %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
46         }
47
48 int locctr(l) int l; {
49         register temp;
50         /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
51
52         if( l == lastloc ) return(l);
53         temp = lastloc;
54         lastloc = l;
55         switch( l ){
56
57         case PROG:
58                 putstr( "       .text\n" );
59                 psline();
60                 break;
61
62         case DATA:
63         case ADATA:
64                 putstr( "       .data\n" );
65                 break;
66
67         case STRNG:
68                 putstr( "       .data   1\n" );
69                 break;
70
71         case ISTRNG:
72                 putstr( "       .data   2\n" );
73                 break;
74
75         case STAB:
76                 putstr( "       .stab\n" );
77                 break;
78
79         default:
80                 cerror( "illegal location counter" );
81                 }
82
83         return( temp );
84         }
85
86 int deflab(n) int n; {
87         /* output something to define the current position as label n */
88         printf( "L%d:\n", n );
89         }
90
91 int crslab = 10;
92
93 int getlab() {
94         /* return a number usable for a label */
95         return( ++crslab );
96         }
97
98 int ent_mask[] = {
99         0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
100
101 int reg_use = 11;
102
103 int efcode() {
104         /* code for the end of a function */
105
106         if( strftn ){  /* copy output (in R2) to caller */
107                 register NODE *l, *r;
108                 register struct symtab *p;
109                 register TWORD t;
110                 int i;
111
112                 p = &stab[curftn];
113                 t = p->stype;
114                 t = DECREF(t);
115
116                 deflab( retlab );
117
118                 i = getlab();   /* label for return area */
119 #ifndef LCOMM
120                 putstr("        .data\n" );
121                 putstr("        .align  2\n" );
122                 printf("L%d:    .space  %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
123                 putstr("        .text\n" );
124 #else
125                 { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
126                 if (sz % sizeof (int))
127                         sz += sizeof (int) - (sz % sizeof (int));
128                 printf("        .lcomm  L%d,%d\n", i, sz);
129                 }
130 #endif
131                 psline();
132                 printf("        movab   L%d,r1\n", i);
133
134                 reached = 1;
135                 l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
136                 l->tn.rval = 1;  /* R1 */
137                 l->tn.lval = 0;  /* no offset */
138                 r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
139                 r->tn.rval = 0;  /* R0 */
140                 r->tn.lval = 0;
141                 l = buildtree( UNARY MUL, l, NIL );
142                 r = buildtree( UNARY MUL, r, NIL );
143                 l = buildtree( ASSIGN, l, r );
144                 l->in.op = FREE;
145                 ecomp( l->in.left );
146                 printf( "       movab   L%d,r0\n", i );
147                 /* turn off strftn flag, so return sequence will be generated */
148                 strftn = 0;
149                 }
150         branch( retlab );
151 #ifndef VMS
152         printf( "       .set    L%d,0x%x\n", ftnno, ent_mask[reg_use] );
153 #else
154         printf( "       .set    L%d,%d  # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use]  );
155         /* KLS kludge, under VMS if you use regs 2-5, you must save them. */
156 #endif
157         reg_use = 11;
158         p2bend();
159         fdefflag = 0;
160         }
161
162 int ftlab1, ftlab2;
163
164 int bfcode(a, n) int a[]; int n; {
165         /* code for the beginning of a function; a is an array of
166                 indices in stab for the arguments; n is the number */
167         register i;
168         register temp;
169         register struct symtab *p;
170         int off;
171         char *toreg();
172
173         locctr( PROG );
174         p = &stab[curftn];
175         putstr( "       .align  1\n");
176         defnam( p );
177         temp = p->stype;
178         temp = DECREF(temp);
179         strftn = (temp==STRTY) || (temp==UNIONTY);
180
181         retlab = getlab();
182
183         /* routine prolog */
184
185         printf( "       .word   L%d\n", ftnno);
186         ftlab1 = getlab();
187         ftlab2 = getlab();
188         printf( "       jbr     L%d\n", ftlab1);
189         printf( "L%d:\n", ftlab2);
190         if( proflg ) {  /* profile code */
191                 i = getlab();
192                 printf("        movab   L%d,r0\n", i);
193                 putstr("        jsb     mcount\n");
194                 putstr("        .data\n");
195                 putstr("        .align  2\n");
196                 printf("L%d:    .long   0\n", i);
197                 putstr("        .text\n");
198                 psline();
199                 }
200
201         off = ARGINIT;
202
203         for( i=0; i<n; ++i ){
204                 p = &stab[a[i]];
205                 if( p->sclass == REGISTER ){
206                         temp = p->offset;  /* save register number */
207                         p->sclass = PARAM;  /* forget that it is a register */
208                         p->offset = NOOFFSET;
209                         oalloc( p, &off );
210 /*tbl*/         printf( "       %s      %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
211                         p->offset = temp;  /* remember register number */
212                         p->sclass = REGISTER;   /* remember that it is a register */
213                         }
214                 else if( p->stype == STRTY || p->stype == UNIONTY ) {
215                         p->offset = NOOFFSET;
216                         if( oalloc( p, &off ) ) cerror( "bad argument" );
217                         SETOFF( off, ALSTACK );
218                         }
219                 else {
220                         if( oalloc( p, &off ) ) cerror( "bad argument" );
221                         }
222
223                 }
224         if (gdebug) {
225 #ifdef STABDOT
226                 pstabdot(N_SLINE, lineno);
227 #else
228                 pstab(NULLNAME, N_SLINE);
229                 printf("0,%d,LL%d\n", lineno, labelno);
230                 printf("LL%d:\n", labelno++);
231 #endif
232         }
233         fdefflag = 1;
234         }
235
236 int bccode() { /* called just before the first executable statment */
237                 /* by now, the automatics and register variables are allocated */
238         SETOFF( autooff, SZINT );
239         /* set aside store area offset */
240         p2bbeg( autooff, regvar );
241         reg_use = (reg_use > regvar ? regvar : reg_use);
242         }
243
244 int ejobcode(flag) int flag; {
245         /* called just before final exit */
246         /* flag is 1 if errors, 0 if none */
247         }
248
249 int aobeg() {
250         /* called before removing automatics from stab */
251         }
252
253 int aocode(p) struct symtab *p; {
254         /* called when automatic p removed from stab */
255         }
256
257 int aoend() {
258         /* called after removing all automatics from stab */
259         }
260
261 int defnam(p) register struct symtab *p; {
262         /* define the current location as the name p->sname */
263
264         if( p->sclass == EXTDEF ){
265                 printf( "       .globl  %s\n", exname( p->sname ) );
266                 }
267         if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
268         else printf( "%s:\n", exname( p->sname ) );
269
270         }
271
272 int bycode(t, i) int t; int i; {
273 #ifdef ASSTRINGS
274 static  int     lastoctal = 0;
275 #endif
276
277         /* put byte i+1 in a string */
278
279 #ifdef ASSTRINGS
280
281         i &= 077;
282         if ( t < 0 ){
283                 if ( i != 0 )   putstr( "\"\n" );
284         } else {
285                 if ( i == 0 ) putstr("\t.ascii\t\"");
286                 if ( t == '\\' || t == '"'){
287                         lastoctal = 0;
288                         printf("\\%c", t);
289                 }
290                         /*
291                          *      We escape the colon in strings so that
292                          *      c2 will, in its infinite wisdom, interpret
293                          *      the characters preceding the colon as a label.
294                          *      If we didn't escape the colon, c2 would
295                          *      throw away any trailing blanks or tabs after
296                          *      the colon, but reconstruct a assembly
297                          *      language semantically correct program.
298                          *      C2 hasn't been taught about strings.
299                          */
300                 else if ( t == ':' || t < 040 || t >= 0177 ){
301                         lastoctal++;
302                         printf("\\%o",t);
303                 }
304                 else if ( lastoctal && '0' <= t && t <= '9' ){
305                         lastoctal = 0;
306                         printf("\"\n\t.ascii\t\"%c", t );
307                 }
308                 else {
309                         lastoctal = 0;
310                         putchar(t);
311                 }
312                 if ( i == 077 ) putstr("\"\n");
313         }
314 #else
315
316         i &= 07;
317         if( t < 0 ){ /* end of the string */
318                 if( i != 0 ) putchar( '\n' );
319                 }
320
321         else { /* stash byte t into string */
322                 if( i == 0 ) putstr( "  .byte   " );
323                 else putchar( ',' );
324                 printf( "0x%x", t );
325                 if( i == 07 ) putchar( '\n' );
326                 }
327 #endif
328         }
329
330 int zecode(n) int n; {
331         /* n integer words of zeros */
332         OFFSZ temp;
333         if( n <= 0 ) return;
334         printf( "       .space  %d\n", (SZINT/SZCHAR)*n );
335         temp = n;
336         inoff += temp*SZINT;
337         }
338
339 int fldal(t) unsigned t; { /* return the alignment of field of type t */
340         uerror( "illegal field type" );
341         return( ALINT );
342         }
343
344 int fldty(p) struct symtab *p; { /* fix up type of field p */
345         ;
346         }
347
348 int where(c) int c; { /* print location of error  */
349         /* c is either 'u', 'c', or 'w' */
350         /* GCOS version */
351         fprintf( stderr, "%s, line %d: ", ftitle, lineno );
352         }
353
354 /* tbl - toreg() returns a pointer to a char string
355                   which is the correct  "register move" for the passed type 
356  */
357 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = {
358         CHAR, "cvtbl",
359         SHORT, "cvtwl",
360         INT, "movl",
361         LONG, "movl",
362         FLOAT, "movf",
363         DOUBLE, "movd",
364         UCHAR,  "movzbl",
365         USHORT, "movzwl",
366         UNSIGNED,       "movl",
367         ULONG,  "movl",
368         0, ""
369         };
370
371 char *toreg(type) TWORD type; {
372         struct type_move *p;
373
374         for ( p=toreg_strs; p->fromtype != 0; p++)
375                 if (p->fromtype == type) return(p->tostrng);
376
377         /* type not found, must be a pointer type */
378         return("movl");
379 }
380 /* tbl */
381
382 int main(argc, argv) int argc; char *argv[]; {
383 #ifdef BUFSTDERR
384         char errbuf[BUFSIZ];
385         setbuf(stderr, errbuf);
386 #endif
387         return(mainp1( argc, argv ));
388         }
389
390 struct sw heapsw[SWITSZ];       /* heap for switches */
391
392 int genswitch(p, n) register struct sw *p; int n; {
393         /*      p points to an array of structures, each consisting
394                 of a constant value and a label.
395                 The first is >=0 if there is a default label;
396                 its value is the label number
397                 The entries p[1] to p[n] are the nontrivial cases
398                 */
399         register i;
400         register CONSZ j, range;
401         register dlab, swlab;
402
403         range = p[n].sval-p[1].sval;
404
405         if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
406
407                 swlab = getlab();
408                 dlab = p->slab >= 0 ? p->slab : getlab();
409
410                 /* already in r0 */
411                 printf("        casel   r0,$%ld,$%ld\n", p[1].sval, range);
412                 printf("L%d:\n", swlab);
413                 for( i=1,j=p[1].sval; i<=n; j++) {
414                         printf("        .word   L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
415                                 swlab);
416                         }
417
418                 if( p->slab >= 0 ) branch( dlab );
419                 else printf("L%d:\n", dlab);
420                 return;
421
422                 }
423
424         if( n>8 ) {     /* heap switch */
425
426                 heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
427                 makeheap(p, n, 1);      /* build heap */
428
429                 walkheap(1, n); /* produce code */
430
431                 if( p->slab >= 0 )
432                         branch( dlab );
433                 else
434                         printf("L%d:\n", dlab);
435                 return;
436         }
437
438         /* debugging code */
439
440         /* out for the moment
441         if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
442         */
443
444         /* simple switch code */
445
446         for( i=1; i<=n; ++i ){
447                 /* already in r0 */
448
449                 putstr( "       cmpl    r0,$" );
450                 printf( CONFMT, p[i].sval );
451                 printf( "\n     jeql    L%d\n", p[i].slab );
452                 }
453
454         if( p->slab>=0 ) branch( p->slab );
455         }
456
457 int makeheap(p, m, n) register struct sw *p; int m; int n; {
458         register int q;
459
460         q = select(m);
461         heapsw[n] = p[q];
462         if( q>1 ) makeheap(p, q-1, 2*n);
463         if( q<m ) makeheap(p+q, m-q, 2*n+1);
464 }
465
466 int select(m) int m; {
467         register int l,i,k;
468
469         for(i=1; ; i*=2)
470                 if( (i-1) > m ) break;
471         l = ((k = i/2 - 1) + 1)/2;
472         return( l + (m-k < l ? m-k : l));
473 }
474
475 int walkheap(start, limit) int start; int limit; {
476         int label;
477
478         if( start > limit ) return;
479         printf("        cmpl    r0,$%d\n",  heapsw[start].sval);
480         printf("        jeql    L%d\n", heapsw[start].slab);
481         if( (2*start) > limit ) {
482                 printf("        jbr     L%d\n", heapsw[0].slab);
483                 return;
484         }
485         if( (2*start+1) <= limit ) {
486                 label = getlab();
487                 printf("        jgtr    L%d\n", label);
488         } else
489                 printf("        jgtr    L%d\n", heapsw[0].slab);
490         walkheap( 2*start, limit);
491         if( (2*start+1) <= limit ) {
492                 printf("L%d:\n", label);
493                 walkheap( 2*start+1, limit);
494         }
495 }