xref: /original-bsd/old/pcc/ccom.tahoe/code.c (revision e188a54c)
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 
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 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 
102 getlab(){
103 	/* return a number usable for a label */
104 	return( ++crslab );
105 	}
106 
107 
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 
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 
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*/
258 ejobcode( flag ){
259 	/* called just before final exit */
260 	/* flag is 1 if errors, 0 if none */
261 	}
262 
263 #ifndef 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
277 aoend(){
278 	/* called after removing all automatics from stab */
279 	}
280 #endif aoend
281 
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 
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 
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*/
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*/
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
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 
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 
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 
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 
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 
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