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