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