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