1 #ifndef lint
2 static char *sccsid ="@(#)code.c 1.10 (Berkeley) 05/31/88";
3 #endif lint
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 putstr( " ret\n" );
27 }
28 else printf( " jbr L%d\n", n );
29 }
30
31 int lastloc = { -1 };
32
33 short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
34 #define LOG2SZ 9
35
defalign(n)36 defalign(n) {
37 /* cause the alignment to become a multiple of n */
38 n /= SZCHAR;
39 if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
40 }
41
locctr(l)42 locctr( l ){
43 register temp;
44 /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
45
46 if( l == lastloc ) return(l);
47 temp = lastloc;
48 lastloc = l;
49 if( nerrors ) return(temp);
50 switch( l ){
51
52 case PROG:
53 putstr( " .text\n" );
54 psline();
55 break;
56
57 case DATA:
58 case ADATA:
59 putstr( " .data\n" );
60 break;
61
62 case STRNG:
63 putstr( " .data 1\n" );
64 break;
65
66 case ISTRNG:
67 putstr( " .data 2\n" );
68 break;
69
70 case STAB:
71 putstr( " .stab\n" );
72 break;
73
74 default:
75 cerror( "illegal location counter" );
76 }
77
78 return( temp );
79 }
80
deflab(n)81 deflab( n ){
82 /* output something to define the current position as label n */
83 if (nerrors) return;
84 printf( "L%d:\n", n );
85 }
86
87 int crslab = 10;
88
getlab()89 getlab(){
90 /* return a number usable for a label */
91 return( ++crslab );
92 }
93
94
95 int ent_mask[] = {
96 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
97
98 int reg_use = 11;
99
efcode()100 efcode(){
101 /* code for the end of a function */
102
103 if( strftn ){ /* copy output (in R2) to caller */
104 register NODE *l, *r;
105 register struct symtab *p;
106 register TWORD t;
107 int i;
108
109 p = &stab[curftn];
110 t = p->stype;
111 t = DECREF(t);
112
113 deflab( retlab );
114
115 i = getlab(); /* label for return area */
116 #ifndef LCOMM
117 putstr(" .data\n" );
118 putstr(" .align 2\n" );
119 printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
120 putstr(" .text\n" );
121 #else
122 { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
123 if (sz % (SZINT/SZCHAR))
124 sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
125 printf(" .lcomm L%d,%d\n", i, sz);
126 }
127 #endif
128 psline();
129 printf(" movab L%d,r1\n", i);
130
131 reached = 1;
132 l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
133 l->tn.rval = 1; /* R1 */
134 l->tn.lval = 0; /* no offset */
135 r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
136 r->tn.rval = 0; /* R0 */
137 r->tn.lval = 0;
138 l = buildtree( UNARY MUL, l, NIL );
139 r = buildtree( UNARY MUL, r, NIL );
140 l = buildtree( ASSIGN, l, r );
141 l->in.op = FREE;
142 ecomp( l->in.left );
143 printf( " movab L%d,r0\n", i );
144 /* turn off strftn flag, so return sequence will be generated */
145 strftn = 0;
146 }
147 branch( retlab );
148 #ifndef VMS
149 printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] );
150 #else
151 printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] );
152 /* KLS kludge, under VMS if you use regs 2-5, you must save them. */
153 #endif
154 reg_use = 11;
155 p2bend();
156 fdefflag = 0;
157 }
158
159 int ftlab1, ftlab2;
160
bfcode(a,n)161 bfcode( a, n ) int a[]; {
162 /* code for the beginning of a function; a is an array of
163 indices in stab for the arguments; n is the number */
164 register i;
165 register temp;
166 register struct symtab *p;
167 int off;
168 #ifdef TRUST_REG_CHAR_AND_REG_SHORT
169 char *toreg();
170 #endif
171
172 if( nerrors ) return;
173 (void) 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 (void) oalloc( p, &off );
210 #ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */
211 /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
212 #else
213 /*tbl*/ printf( " movl %d(ap),r%d\n", p->offset/SZCHAR, temp );
214 #endif
215 p->offset = temp; /* remember register number */
216 p->sclass = REGISTER; /* remember that it is a register */
217 }
218 else if( p->stype == STRTY || p->stype == UNIONTY ) {
219 p->offset = NOOFFSET;
220 if( oalloc( p, &off ) ) cerror( "bad argument" );
221 SETOFF( off, ALSTACK );
222 }
223 else {
224 if( oalloc( p, &off ) ) cerror( "bad argument" );
225 }
226
227 }
228 if (gdebug && !nerrors) {
229 #ifdef STABDOT
230 pstabdot(N_SLINE, lineno);
231 #else
232 pstab(NULLNAME, N_SLINE);
233 printf("0,%d,LL%d\n", lineno, labelno);
234 printf("LL%d:\n", labelno++);
235 #endif
236 }
237 fdefflag = 1;
238 }
239
bccode()240 bccode(){ /* called just before the first executable statment */
241 /* by now, the automatics and register variables are allocated */
242 SETOFF( autooff, SZINT );
243 /* set aside store area offset */
244 p2bbeg( autooff, regvar );
245 reg_use = (reg_use > regvar ? regvar : reg_use);
246 }
247
248 /*ARGSUSED*/
ejobcode(flag)249 ejobcode( flag ){
250 /* called just before final exit */
251 /* flag is 1 if errors, 0 if none */
252 }
253
254 #ifndef aobeg
aobeg()255 aobeg(){
256 /* called before removing automatics from stab */
257 }
258 #endif aobeg
259
260 #ifndef aocode
261 /*ARGSUSED*/
262 aocode(p) struct symtab *p; {
263 /* called when automatic p removed from stab */
264 }
265 #endif aocode
266
267 #ifndef aoend
aoend()268 aoend(){
269 /* called after removing all automatics from stab */
270 }
271 #endif aoend
272
defnam(p)273 defnam( p ) register struct symtab *p; {
274 /* define the current location as the name p->sname */
275
276 if( p->sclass == EXTDEF ){
277 printf( " .globl %s\n", exname( p->sname ) );
278 }
279 if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
280 else printf( "%s:\n", exname( p->sname ) );
281
282 }
283
bycode(t,i)284 bycode( t, i ){
285 #ifdef ASSTRINGS
286 static int lastoctal = 0;
287 #endif
288
289 /* put byte i+1 in a string */
290
291 if ( nerrors ) return;
292 #ifdef ASSTRINGS
293
294 i &= 077;
295 if ( t < 0 ){
296 if ( i != 0 ) putstr( "\"\n" );
297 } else {
298 if ( i == 0 ) putstr("\t.ascii\t\"");
299 if ( t == '\\' || t == '"'){
300 lastoctal = 0;
301 printf("\\%c", t);
302 }
303 /*
304 * We escape the colon in strings so that
305 * c2 will, in its infinite wisdom, interpret
306 * the characters preceding the colon as a label.
307 * If we didn't escape the colon, c2 would
308 * throw away any trailing blanks or tabs after
309 * the colon, but reconstruct a assembly
310 * language semantically correct program.
311 * C2 hasn't been taught about strings.
312 */
313 else if ( t == ':' || t < 040 || t >= 0177 ){
314 lastoctal++;
315 printf("\\%o",t);
316 }
317 else if ( lastoctal && '0' <= t && t <= '9' ){
318 lastoctal = 0;
319 printf("\"\n\t.ascii\t\"%c", t );
320 }
321 else
322 {
323 lastoctal = 0;
324 putchar(t);
325 }
326 if ( i == 077 ) putstr("\"\n");
327 }
328 #else
329
330 i &= 07;
331 if( t < 0 ){ /* end of the string */
332 if( i != 0 ) putchar( '\n' );
333 }
334
335 else { /* stash byte t into string */
336 if( i == 0 ) putstr( " .byte " );
337 else putchar( ',' );
338 printf( "0x%x", t );
339 if( i == 07 ) putchar( '\n' );
340 }
341 #endif
342 }
343
zecode(n)344 zecode( n ){
345 /* n integer words of zeros */
346 OFFSZ temp;
347 if( n <= 0 ) return;
348 printf( " .space %d\n", (SZINT/SZCHAR)*n );
349 temp = n;
350 inoff += temp*SZINT;
351 }
352
353 /*ARGSUSED*/
fldal(t)354 fldal( t ) unsigned t; { /* return the alignment of field of type t */
355 uerror( "illegal field type" );
356 return( ALINT );
357 }
358
359 /*ARGSUSED*/
360 fldty( p ) struct symtab *p; { /* fix up type of field p */
361 ;
362 }
363
364 /*ARGSUSED*/
where(c)365 where(c){ /* print location of error */
366 /* c is either 'u', 'c', or 'w' */
367 /* GCOS version */
368 fprintf( stderr, "%s, line %d: ", ftitle, lineno );
369 }
370
371
372 #ifdef TRUST_REG_CHAR_AND_REG_SHORT
373 /* tbl - toreg() returns a pointer to a char string
374 which is the correct "register move" for the passed type
375 */
376 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
377 {
378 INT, "movl",
379 UNSIGNED, "movl",
380 DOUBLE, "movq",
381 CHAR, "cvtbl",
382 SHORT, "cvtwl",
383 UCHAR, "movzbl",
384 USHORT, "movzwl",
385 0, ""
386 };
387
388 char
toreg(type)389 *toreg(type)
390 TWORD type;
391 {
392 struct type_move *p;
393
394 for ( p=toreg_strs; p->fromtype != 0; p++)
395 if (p->fromtype == type) return(p->tostrng);
396
397 /* type not found, must be a pointer type */
398 return("movl");
399 }
400 /* tbl */
401 #endif
402
403
main(argc,argv)404 main( argc, argv ) char *argv[]; {
405 #ifdef BUFSTDERR
406 char errbuf[BUFSIZ];
407 setbuf(stderr, errbuf);
408 #endif
409 return(mainp1( argc, argv ));
410 }
411
412 struct sw heapsw[SWITSZ]; /* heap for switches */
413
genswitch(p,n)414 genswitch(p,n) register struct sw *p;{
415 /* p points to an array of structures, each consisting
416 of a constant value and a label.
417 The first is >=0 if there is a default label;
418 its value is the label number
419 The entries p[1] to p[n] are the nontrivial cases
420 */
421 register i;
422 register CONSZ j, range;
423 register dlab, swlab;
424
425 if( nerrors ) return;
426 range = p[n].sval-p[1].sval;
427
428 if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
429
430 swlab = getlab();
431 dlab = p->slab >= 0 ? p->slab : getlab();
432
433 /* already in r0 */
434 printf(" casel r0,$%ld,$%ld\n", p[1].sval, range);
435 printf("L%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 printf(" cmpl r0,$%d\n", heapsw[start].sval);
507 printf(" jeql L%d\n", heapsw[start].slab);
508 if( (2*start) > limit ) {
509 printf(" jbr L%d\n", heapsw[0].slab);
510 return;
511 }
512 if( (2*start+1) <= limit ) {
513 label = getlab();
514 printf(" jgtr L%d\n", label);
515 } else
516 printf(" jgtr L%d\n", heapsw[0].slab);
517 walkheap( 2*start, limit);
518 if( (2*start+1) <= limit ) {
519 printf("L%d:\n", label);
520 walkheap( 2*start+1, limit);
521 }
522 }
523