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