xref: /csrg-svn/old/pcc/ccom.tahoe/code.c (revision 32866)
1 #ifndef lint
2 static char sccsid[] = "@(#)code.c	1.5 (Berkeley) 12/10/87";
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 
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 
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 
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 
94 #ifndef deflab
95 deflab( n ){
96 	/* output something to define the current position as label n */
97 	printf( "L%d:\n", n );
98 	}
99 #endif
100 
101 int crslab = 10;
102 
103 getlab(){
104 	/* return a number usable for a label */
105 	return( ++crslab );
106 	}
107 
108 
109 efcode(){
110 	/* code for the end of a function */
111 
112 	if( strftn ){  /* copy output (in R2) to caller */
113 		register NODE *l, *r;
114 		register struct symtab *p;
115 		register TWORD t;
116 		register int i;
117 
118 		p = &stab[curftn];
119 		t = p->stype;
120 		t = DECREF(t);
121 
122 		deflab( retlab );
123 
124 		i = getlab();	/* label for return area */
125 #ifndef LCOMM
126 		putstr("	.data\n" );
127 		putstr("	.align	2\n" );
128 		printf("L%d:	.space	%d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
129 		putstr("	.text\n" );
130 #else
131 		{ int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
132 		if (sz % (SZINT/SZCHAR))
133 			sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
134 		printf("	.lcomm	L%d,%d\n", i, sz);
135 		}
136 #endif
137 		psline();
138 		printf("	movab	L%d,r1\n", i);
139 
140 		reached = 1;
141 		l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
142 		l->tn.rval = 1;  /* R1 */
143 		l->tn.lval = 0;  /* no offset */
144 		r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
145 		r->tn.rval = 0;  /* R0 */
146 		r->tn.lval = 0;
147 		l = buildtree( UNARY MUL, l, NIL );
148 		r = buildtree( UNARY MUL, r, NIL );
149 		l = buildtree( ASSIGN, l, r );
150 		l->in.op = FREE;
151 		ecomp( l->in.left );
152 		printf( "	movab	L%d,r0\n", i );
153 		/* turn off strftn flag, so return sequence will be generated */
154 		strftn = 0;
155 		}
156 	branch( retlab );
157 	p2bend();
158 	fdefflag = 0;
159 	}
160 
161 int ftlab1, ftlab2;
162 
163 bfcode( a, n ) int a[]; {
164 	/* code for the beginning of a function; a is an array of
165 		indices in stab for the arguments; n is the number */
166 	register i;
167 	register temp;
168 	register struct symtab *p;
169 	int off;
170 #ifdef REG_CHAR
171 	char *toreg();
172 #endif
173 	char *rname();
174 
175 	if( nerrors ) return;
176 	(void) locctr( PROG );
177 	p = &stab[curftn];
178 	putstr( "	.align	1\n");
179 	defnam( p );
180 	temp = p->stype;
181 	temp = DECREF(temp);
182 	strftn = (temp==STRTY) || (temp==UNIONTY);
183 
184 	retlab = getlab();
185 
186 	/* routine prolog */
187 
188 	printf( "	.word	L%d\n", ftnno);
189 	ftlab1 = getlab();
190 	ftlab2 = getlab();
191 	printf( "	jbr 	L%d\n", ftlab1);
192 	printf( "L%d:\n", ftlab2);
193 	if( proflg ) {	/* profile code */
194 		i = getlab();
195 		printf("	pushl	$L%d\n", i);
196 		putstr("	callf	$8,mcount\n");
197 		putstr("	.data\n");
198 		putstr("	.align	2\n");
199 		printf("L%d:	.long	0\n", i);
200 		putstr("	.text\n");
201 		psline();
202 		}
203 
204 	off = ARGINIT;
205 
206 	for( i=0; i<n; ++i ){
207 		p = &stab[a[i]];
208 		if( p->sclass == REGISTER ){
209 			temp = p->offset;  /* save register number */
210 			p->sclass = PARAM;  /* forget that it is a register */
211 			p->offset = NOOFFSET;
212 			(void) oalloc( p, &off );
213 #ifdef REG_CHAR
214 			printf( "	%s", toreg(p->stype)) );
215 #else
216 			putstr("	movl");
217 #endif
218 			printf( "	%d(fp),%s\n", p->offset/SZCHAR, rname(temp) );
219 			p->offset = temp;  /* remember register number */
220 			p->sclass = REGISTER;   /* remember that it is a register */
221 #ifdef REG_CHAR
222 			temp = p->stype;
223 			if( temp==CHAR || temp==SHORT )
224 				p->stype = INT;
225 			else if( temp==UCHAR || temp==USHORT )
226 				p->stype = UNSIGNED;
227 #endif
228 			}
229 		else if( p->stype == STRTY || p->stype == UNIONTY ) {
230 			p->offset = NOOFFSET;
231 			if( oalloc( p, &off ) ) cerror( "bad argument" );
232 			SETOFF( off, ALSTACK );
233 			}
234 		else {
235 			if( oalloc( p, &off ) ) cerror( "bad argument" );
236 			}
237 
238 		}
239 	if (gdebug && !nerrors) {
240 #ifdef STABDOT
241 		pstabdot(N_SLINE, lineno);
242 #else
243 		pstab(NULLNAME, N_SLINE);
244 		printf("0,%d,LL%d\n", lineno, labelno);
245 		printf("LL%d:\n", labelno++);
246 #endif
247 		}
248 	fdefflag = 1;
249 	}
250 
251 bccode(){ /* called just before the first executable statment */
252 		/* by now, the automatics and register variables are allocated */
253 	SETOFF( autooff, SZINT );
254 	/* set aside store area offset */
255 	p2bbeg( autooff, regvar );
256 	}
257 
258 /*ARGSUSED*/
259 ejobcode( flag ){
260 	/* called just before final exit */
261 	/* flag is 1 if errors, 0 if none */
262 	}
263 
264 #ifndef aobeg
265 aobeg(){
266 	/* called before removing automatics from stab */
267 	}
268 #endif aobeg
269 
270 #ifndef aocode
271 /*ARGSUSED*/
272 aocode(p) struct symtab *p; {
273 	/* called when automatic p removed from stab */
274 	}
275 #endif aocode
276 
277 #ifndef aoend
278 aoend(){
279 	/* called after removing all automatics from stab */
280 	}
281 #endif aoend
282 
283 defnam( p ) register struct symtab *p; {
284 	/* define the current location as the name p->sname */
285 
286 	if( p->sclass == EXTDEF ){
287 		printf( "	.globl	%s\n", exname( p->sname ) );
288 		}
289 	if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
290 	else printf( "%s:\n", exname( p->sname ) );
291 
292 	}
293 
294 bycode( t, i ){
295 #ifdef ASSTRINGS
296 static	int	lastoctal = 0;
297 #endif
298 
299 	/* put byte i+1 in a string */
300 
301 	if ( nerrors ) return;
302 #ifdef ASSTRINGS
303 
304 	i &= 077;
305 	if ( t < 0 ){
306 		if ( i != 0 )	putstr( "\"\n" );
307 	} else {
308 		if ( i == 0 ) putstr("\t.ascii\t\"");
309 		if ( t == '\\' || t == '"'){
310 			lastoctal = 0;
311 			printf("\\%c", t);
312 		}
313 		else if ( 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 
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*/
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*/
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 REG_CHAR
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 	CHAR, "cvtbl",
379 	SHORT, "cvtwl",
380 	UCHAR,	"movzbl",
381 	USHORT,	"movzwl",
382 	0, "movl"
383 	};
384 
385 char
386 *toreg(type)
387 	TWORD type;
388 {
389 	struct type_move *p;
390 
391 	for ( p=toreg_strs; p->fromtype != 0; p++)
392 		if (p->fromtype == type) return(p->tostrng);
393 
394 	/* type not found, must be a word type */
395 	return(p->tostrng);
396 }
397 /* tbl */
398 #endif
399 
400 
401 main( argc, argv ) char *argv[]; {
402 #ifdef BUFSTDERR
403 	char errbuf[BUFSIZ];
404 	setbuf(stderr, errbuf);
405 #endif
406 	return(mainp1( argc, argv ));
407 	}
408 
409 struct sw heapsw[SWITSZ];	/* heap for switches */
410 
411 genswitch(p,n) register struct sw *p;{
412 	/*	p points to an array of structures, each consisting
413 		of a constant value and a label.
414 		The first is >=0 if there is a default label;
415 		its value is the label number
416 		The entries p[1] to p[n] are the nontrivial cases
417 		*/
418 	register i;
419 	register CONSZ j;
420 	register CONSZ unsigned range;
421 	register dlab, swlab;
422 
423 	if( nerrors ) return;
424 	range = p[n].sval-p[1].sval;
425 
426 	if( range <= 3*n && n>=4 ){ /* implement a direct switch */
427 
428 		swlab = getlab();
429 		dlab = p->slab >= 0 ? p->slab : getlab();
430 
431 		/* already in r0 */
432 		putstr( "	casel	r0,$" );
433 		printf( CONFMT, p[1].sval );
434 		putstr(",$");
435 		printf( CONFMT, range);
436 		printf("\n	.align 1\nL%d:\n", swlab);
437 		for( i=1,j=p[1].sval; i<=n; j++) {
438 			printf("	.word	L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
439 				swlab);
440 			}
441 
442 		if( p->slab >= 0 ) branch( dlab );
443 		else printf("L%d:\n", dlab);
444 		return;
445 
446 		}
447 
448 	if( n>8 ) {	/* heap switch */
449 
450 		heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
451 		makeheap(p, n, 1);	/* build heap */
452 
453 		walkheap(1, n);	/* produce code */
454 
455 		if( p->slab >= 0 )
456 			branch( dlab );
457 		else
458 			printf("L%d:\n", dlab);
459 		return;
460 	}
461 
462 	/* debugging code */
463 
464 	/* out for the moment
465 	if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
466 	*/
467 
468 	/* simple switch code */
469 
470 	for( i=1; i<=n; ++i ){
471 		/* already in r0 */
472 
473 		putstr( "	cmpl	r0,$" );
474 		printf( CONFMT, p[i].sval );
475 		printf( "\n	jeql	L%d\n", p[i].slab );
476 		}
477 
478 	if( p->slab>=0 ) branch( p->slab );
479 	}
480 
481 makeheap(p, m, n)
482 register struct sw *p;
483 {
484 	register int q;
485 
486 	q = selectheap(m);
487 	heapsw[n] = p[q];
488 	if( q>1 ) makeheap(p, q-1, 2*n);
489 	if( q<m ) makeheap(p+q, m-q, 2*n+1);
490 }
491 
492 selectheap(m) {
493 	register int l,i,k;
494 
495 	for(i=1; ; i*=2)
496 		if( (i-1) > m ) break;
497 	l = ((k = i/2 - 1) + 1)/2;
498 	return( l + (m-k < l ? m-k : l));
499 }
500 
501 walkheap(start, limit)
502 {
503 	int label;
504 
505 
506 	if( start > limit ) return;
507 	putstr( "	cmpl	r0,$" );
508 	printf( CONFMT, heapsw[start].sval);
509 	printf("\n	jeql	L%d\n", heapsw[start].slab);
510 	if( (2*start) > limit ) {
511 		printf("	jbr 	L%d\n", heapsw[0].slab);
512 		return;
513 	}
514 	if( (2*start+1) <= limit ) {
515 		label = getlab();
516 		printf("	jgtr	L%d\n", label);
517 	} else
518 		printf("	jgtr	L%d\n", heapsw[0].slab);
519 	walkheap( 2*start, limit);
520 	if( (2*start+1) <= limit ) {
521 		printf("L%d:\n", label);
522 		walkheap( 2*start+1, limit);
523 	}
524 }
525