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