xref: /csrg-svn/old/pcc/ccom.vax/code.c (revision 32910)
1 #ifndef lint
2 static char *sccsid ="@(#)code.c	1.6 (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 ejobcode( flag ){
242 	/* called just before final exit */
243 	/* flag is 1 if errors, 0 if none */
244 	}
245 
246 #ifndef aobeg
247 aobeg(){
248 	/* called before removing automatics from stab */
249 	}
250 #endif aobeg
251 
252 #ifndef aocode
253 aocode(p) struct symtab *p; {
254 	/* called when automatic p removed from stab */
255 	}
256 #endif aocode
257 
258 #ifndef aoend
259 aoend(){
260 	/* called after removing all automatics from stab */
261 	}
262 #endif aoend
263 
264 defnam( p ) register struct symtab *p; {
265 	/* define the current location as the name p->sname */
266 
267 	if( p->sclass == EXTDEF ){
268 		printf( "	.globl	%s\n", exname( p->sname ) );
269 		}
270 	if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
271 	else printf( "%s:\n", exname( p->sname ) );
272 
273 	}
274 
275 bycode( t, i ){
276 #ifdef ASSTRINGS
277 static	int	lastoctal = 0;
278 #endif
279 
280 	/* put byte i+1 in a string */
281 
282 	if ( nerrors ) return;
283 #ifdef ASSTRINGS
284 
285 	i &= 077;
286 	if ( t < 0 ){
287 		if ( i != 0 )	putstr( "\"\n" );
288 	} else {
289 		if ( i == 0 ) putstr("\t.ascii\t\"");
290 		if ( t == '\\' || t == '"'){
291 			lastoctal = 0;
292 			printf("\\%c", t);
293 		}
294 			/*
295 			 *	We escape the colon in strings so that
296 			 *	c2 will, in its infinite wisdom, interpret
297 			 *	the characters preceding the colon as a label.
298 			 *	If we didn't escape the colon, c2 would
299 			 *	throw away any trailing blanks or tabs after
300 			 *	the colon, but reconstruct a assembly
301 			 *	language semantically correct program.
302 			 *	C2 hasn't been taught about strings.
303 			 */
304 		else if ( t == ':' || t < 040 || t >= 0177 ){
305 			lastoctal++;
306 			printf("\\%o",t);
307 		}
308 		else if ( lastoctal && '0' <= t && t <= '9' ){
309 			lastoctal = 0;
310 			printf("\"\n\t.ascii\t\"%c", t );
311 		}
312 		else
313 		{
314 			lastoctal = 0;
315 			putchar(t);
316 		}
317 		if ( i == 077 ) putstr("\"\n");
318 	}
319 #else
320 
321 	i &= 07;
322 	if( t < 0 ){ /* end of the string */
323 		if( i != 0 ) putchar( '\n' );
324 		}
325 
326 	else { /* stash byte t into string */
327 		if( i == 0 ) putstr( "	.byte	" );
328 		else putchar( ',' );
329 		printf( "0x%x", t );
330 		if( i == 07 ) putchar( '\n' );
331 		}
332 #endif
333 	}
334 
335 zecode( n ){
336 	/* n integer words of zeros */
337 	OFFSZ temp;
338 	if( n <= 0 ) return;
339 	printf( "	.space	%d\n", (SZINT/SZCHAR)*n );
340 	temp = n;
341 	inoff += temp*SZINT;
342 	}
343 
344 fldal( t ) unsigned t; { /* return the alignment of field of type t */
345 	uerror( "illegal field type" );
346 	return( ALINT );
347 	}
348 
349 fldty( p ) struct symtab *p; { /* fix up type of field p */
350 	;
351 	}
352 
353 where(c){ /* print location of error  */
354 	/* c is either 'u', 'c', or 'w' */
355 	/* GCOS version */
356 	fprintf( stderr, "%s, line %d: ", ftitle, lineno );
357 	}
358 
359 
360 /* tbl - toreg() returns a pointer to a char string
361 		  which is the correct  "register move" for the passed type
362  */
363 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
364 	{
365 	CHAR, "cvtbl",
366 	SHORT, "cvtwl",
367 	INT, "movl",
368 	LONG, "movl",
369 	FLOAT, "movf",
370 	DOUBLE, "movd",
371 	UCHAR,	"movzbl",
372 	USHORT,	"movzwl",
373 	UNSIGNED,	"movl",
374 	ULONG,	"movl",
375 	0, ""
376 	};
377 
378 char
379 *toreg(type)
380 	TWORD type;
381 {
382 	struct type_move *p;
383 
384 	for ( p=toreg_strs; p->fromtype != 0; p++)
385 		if (p->fromtype == type) return(p->tostrng);
386 
387 	/* type not found, must be a pointer type */
388 	return("movl");
389 }
390 /* tbl */
391 
392 
393 main( argc, argv ) char *argv[]; {
394 #ifdef BUFSTDERR
395 	char errbuf[BUFSIZ];
396 	setbuf(stderr, errbuf);
397 #endif
398 	return(mainp1( argc, argv ));
399 	}
400 
401 struct sw heapsw[SWITSZ];	/* heap for switches */
402 
403 genswitch(p,n) register struct sw *p;{
404 	/*	p points to an array of structures, each consisting
405 		of a constant value and a label.
406 		The first is >=0 if there is a default label;
407 		its value is the label number
408 		The entries p[1] to p[n] are the nontrivial cases
409 		*/
410 	register i;
411 	register CONSZ j, range;
412 	register dlab, swlab;
413 
414 	if( nerrors ) return;
415 	range = p[n].sval-p[1].sval;
416 
417 	if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
418 
419 		swlab = getlab();
420 		dlab = p->slab >= 0 ? p->slab : getlab();
421 
422 		/* already in r0 */
423 		printf("	casel	r0,$%ld,$%ld\n", p[1].sval, range);
424 		printf("L%d:\n", swlab);
425 		for( i=1,j=p[1].sval; i<=n; j++) {
426 			printf("	.word	L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
427 				swlab);
428 			}
429 
430 		if( p->slab >= 0 ) branch( dlab );
431 		else printf("L%d:\n", dlab);
432 		return;
433 
434 		}
435 
436 	if( n>8 ) {	/* heap switch */
437 
438 		heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
439 		makeheap(p, n, 1);	/* build heap */
440 
441 		walkheap(1, n);	/* produce code */
442 
443 		if( p->slab >= 0 )
444 			branch( dlab );
445 		else
446 			printf("L%d:\n", dlab);
447 		return;
448 	}
449 
450 	/* debugging code */
451 
452 	/* out for the moment
453 	if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
454 	*/
455 
456 	/* simple switch code */
457 
458 	for( i=1; i<=n; ++i ){
459 		/* already in r0 */
460 
461 		putstr( "	cmpl	r0,$" );
462 		printf( CONFMT, p[i].sval );
463 		printf( "\n	jeql	L%d\n", p[i].slab );
464 		}
465 
466 	if( p->slab>=0 ) branch( p->slab );
467 	}
468 
469 makeheap(p, m, n)
470 register struct sw *p;
471 {
472 	register int q;
473 
474 	q = select(m);
475 	heapsw[n] = p[q];
476 	if( q>1 ) makeheap(p, q-1, 2*n);
477 	if( q<m ) makeheap(p+q, m-q, 2*n+1);
478 }
479 
480 select(m) {
481 	register int l,i,k;
482 
483 	for(i=1; ; i*=2)
484 		if( (i-1) > m ) break;
485 	l = ((k = i/2 - 1) + 1)/2;
486 	return( l + (m-k < l ? m-k : l));
487 }
488 
489 walkheap(start, limit)
490 {
491 	int label;
492 
493 
494 	if( start > limit ) return;
495 	printf("	cmpl	r0,$%d\n",  heapsw[start].sval);
496 	printf("	jeql	L%d\n", heapsw[start].slab);
497 	if( (2*start) > limit ) {
498 		printf("	jbr 	L%d\n", heapsw[0].slab);
499 		return;
500 	}
501 	if( (2*start+1) <= limit ) {
502 		label = getlab();
503 		printf("	jgtr	L%d\n", label);
504 	} else
505 		printf("	jgtr	L%d\n", heapsw[0].slab);
506 	walkheap( 2*start, limit);
507 	if( (2*start+1) <= limit ) {
508 		printf("L%d:\n", label);
509 		walkheap( 2*start+1, limit);
510 	}
511 }
512