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