xref: /csrg-svn/old/pcc/ccom.vax/code.c (revision 32913)
117737Sralph #ifndef lint
2*32913Sdonn static char *sccsid ="@(#)code.c	1.9 (Berkeley) 12/11/87";
317737Sralph #endif lint
417737Sralph 
518556Sralph # include "pass1.h"
69700Slinton # include <sys/types.h>
79700Slinton # include <a.out.h>
89700Slinton # include <stab.h>
99700Slinton 
109700Slinton int proflg = 0;	/* are we generating profiling code? */
119700Slinton int strftn = 0;  /* is the current function one which returns a value */
129700Slinton int gdebug;
139700Slinton int fdefflag;  /* are we within a function definition ? */
1432912Sdonn #ifndef STABDOT
159700Slinton char NULLNAME[8];
1632912Sdonn #endif
179700Slinton int labelno;
189700Slinton 
1924416Smckusick # define putstr(s)	fputs((s), stdout)
2024416Smckusick 
219700Slinton branch( n ){
229700Slinton 	/* output a branch to label n */
239700Slinton 	/* exception is an ordinary function branching to retlab: then, return */
2432910Sdonn 	if( nerrors ) return;
259700Slinton 	if( n == retlab && !strftn ){
2624416Smckusick 		putstr( "	ret\n" );
279700Slinton 		}
289700Slinton 	else printf( "	jbr 	L%d\n", n );
299700Slinton 	}
309700Slinton 
319700Slinton int lastloc = { -1 };
329700Slinton 
339700Slinton short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
349700Slinton #define LOG2SZ 9
359700Slinton 
369700Slinton defalign(n) {
379700Slinton 	/* cause the alignment to become a multiple of n */
389700Slinton 	n /= SZCHAR;
399700Slinton 	if( lastloc != PROG && n > 1 ) printf( "	.align	%d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
409700Slinton 	}
419700Slinton 
429700Slinton locctr( l ){
439700Slinton 	register temp;
449700Slinton 	/* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
459700Slinton 
469700Slinton 	if( l == lastloc ) return(l);
479700Slinton 	temp = lastloc;
489700Slinton 	lastloc = l;
4932910Sdonn 	if( nerrors ) return(temp);
509700Slinton 	switch( l ){
519700Slinton 
529700Slinton 	case PROG:
5324416Smckusick 		putstr( "	.text\n" );
549700Slinton 		psline();
559700Slinton 		break;
569700Slinton 
579700Slinton 	case DATA:
589700Slinton 	case ADATA:
5924416Smckusick 		putstr( "	.data\n" );
609700Slinton 		break;
619700Slinton 
629700Slinton 	case STRNG:
6324416Smckusick 		putstr( "	.data	1\n" );
649700Slinton 		break;
659700Slinton 
669700Slinton 	case ISTRNG:
6724416Smckusick 		putstr( "	.data	2\n" );
689700Slinton 		break;
699700Slinton 
709700Slinton 	case STAB:
7124416Smckusick 		putstr( "	.stab\n" );
729700Slinton 		break;
739700Slinton 
749700Slinton 	default:
759700Slinton 		cerror( "illegal location counter" );
769700Slinton 		}
779700Slinton 
789700Slinton 	return( temp );
799700Slinton 	}
809700Slinton 
8132910Sdonn #ifndef deflab
829700Slinton deflab( n ){
839700Slinton 	/* output something to define the current position as label n */
849700Slinton 	printf( "L%d:\n", n );
859700Slinton 	}
86*32913Sdonn #endif
879700Slinton 
889700Slinton int crslab = 10;
899700Slinton 
909700Slinton getlab(){
919700Slinton 	/* return a number usable for a label */
929700Slinton 	return( ++crslab );
939700Slinton 	}
949700Slinton 
959700Slinton 
969700Slinton int ent_mask[] = {
979700Slinton 	0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
989700Slinton 
999700Slinton int reg_use = 11;
1009700Slinton 
1019700Slinton efcode(){
1029700Slinton 	/* code for the end of a function */
1039700Slinton 
1049700Slinton 	if( strftn ){  /* copy output (in R2) to caller */
1059700Slinton 		register NODE *l, *r;
1069700Slinton 		register struct symtab *p;
1079700Slinton 		register TWORD t;
1089700Slinton 		int i;
1099700Slinton 
1109700Slinton 		p = &stab[curftn];
1119700Slinton 		t = p->stype;
1129700Slinton 		t = DECREF(t);
1139700Slinton 
1149700Slinton 		deflab( retlab );
1159700Slinton 
1169700Slinton 		i = getlab();	/* label for return area */
1179700Slinton #ifndef LCOMM
11824416Smckusick 		putstr("	.data\n" );
11924416Smckusick 		putstr("	.align	2\n" );
1209700Slinton 		printf("L%d:	.space	%d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
12124416Smckusick 		putstr("	.text\n" );
1229700Slinton #else
1239700Slinton 		{ int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
124*32913Sdonn 		if (sz % (SZINT/SZCHAR))
125*32913Sdonn 			sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
1269700Slinton 		printf("	.lcomm	L%d,%d\n", i, sz);
1279700Slinton 		}
1289700Slinton #endif
1299700Slinton 		psline();
1309700Slinton 		printf("	movab	L%d,r1\n", i);
1319700Slinton 
1329700Slinton 		reached = 1;
1339700Slinton 		l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
1349700Slinton 		l->tn.rval = 1;  /* R1 */
1359700Slinton 		l->tn.lval = 0;  /* no offset */
1369700Slinton 		r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
1379700Slinton 		r->tn.rval = 0;  /* R0 */
1389700Slinton 		r->tn.lval = 0;
1399700Slinton 		l = buildtree( UNARY MUL, l, NIL );
1409700Slinton 		r = buildtree( UNARY MUL, r, NIL );
1419700Slinton 		l = buildtree( ASSIGN, l, r );
1429700Slinton 		l->in.op = FREE;
1439700Slinton 		ecomp( l->in.left );
1449700Slinton 		printf( "	movab	L%d,r0\n", i );
1459700Slinton 		/* turn off strftn flag, so return sequence will be generated */
1469700Slinton 		strftn = 0;
1479700Slinton 		}
1489700Slinton 	branch( retlab );
1499700Slinton #ifndef VMS
1509700Slinton 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask[reg_use] );
1519700Slinton #else
1529700Slinton 	printf( "	.set	L%d,%d	# Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use]  );
1539700Slinton 	/* KLS kludge, under VMS if you use regs 2-5, you must save them. */
1549700Slinton #endif
1559700Slinton 	reg_use = 11;
1569700Slinton 	p2bend();
1579700Slinton 	fdefflag = 0;
1589700Slinton 	}
1599700Slinton 
1609700Slinton int ftlab1, ftlab2;
1619700Slinton 
1629700Slinton bfcode( a, n ) int a[]; {
1639700Slinton 	/* code for the beginning of a function; a is an array of
1649700Slinton 		indices in stab for the arguments; n is the number */
1659700Slinton 	register i;
1669700Slinton 	register temp;
1679700Slinton 	register struct symtab *p;
1689700Slinton 	int off;
169*32913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT
1709700Slinton 	char *toreg();
171*32913Sdonn #endif
1729700Slinton 
17332910Sdonn 	if( nerrors ) return;
17432912Sdonn 	(void) locctr( PROG );
1759700Slinton 	p = &stab[curftn];
17624416Smckusick 	putstr( "	.align	1\n");
1779700Slinton 	defnam( p );
1789700Slinton 	temp = p->stype;
1799700Slinton 	temp = DECREF(temp);
1809700Slinton 	strftn = (temp==STRTY) || (temp==UNIONTY);
1819700Slinton 
1829700Slinton 	retlab = getlab();
1839700Slinton 
1849700Slinton 	/* routine prolog */
1859700Slinton 
1869700Slinton 	printf( "	.word	L%d\n", ftnno);
1879700Slinton 	ftlab1 = getlab();
1889700Slinton 	ftlab2 = getlab();
1899700Slinton 	printf( "	jbr 	L%d\n", ftlab1);
1909700Slinton 	printf( "L%d:\n", ftlab2);
1919700Slinton 	if( proflg ) {	/* profile code */
1929700Slinton 		i = getlab();
1939700Slinton 		printf("	movab	L%d,r0\n", i);
19424416Smckusick 		putstr("	jsb 	mcount\n");
19524416Smckusick 		putstr("	.data\n");
19624416Smckusick 		putstr("	.align	2\n");
1979700Slinton 		printf("L%d:	.long	0\n", i);
19824416Smckusick 		putstr("	.text\n");
1999700Slinton 		psline();
2009700Slinton 		}
2019700Slinton 
2029700Slinton 	off = ARGINIT;
2039700Slinton 
2049700Slinton 	for( i=0; i<n; ++i ){
2059700Slinton 		p = &stab[a[i]];
2069700Slinton 		if( p->sclass == REGISTER ){
2079700Slinton 			temp = p->offset;  /* save register number */
2089700Slinton 			p->sclass = PARAM;  /* forget that it is a register */
2099700Slinton 			p->offset = NOOFFSET;
21032912Sdonn 			(void) oalloc( p, &off );
211*32913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */
2129700Slinton /*tbl*/		printf( "	%s	%d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
213*32913Sdonn #else
214*32913Sdonn /*tbl*/		printf( "	movl	%d(ap),r%d\n", p->offset/SZCHAR, temp );
215*32913Sdonn #endif
2169700Slinton 			p->offset = temp;  /* remember register number */
2179700Slinton 			p->sclass = REGISTER;   /* remember that it is a register */
2189700Slinton 			}
2199700Slinton 		else if( p->stype == STRTY || p->stype == UNIONTY ) {
2209700Slinton 			p->offset = NOOFFSET;
2219700Slinton 			if( oalloc( p, &off ) ) cerror( "bad argument" );
2229700Slinton 			SETOFF( off, ALSTACK );
2239700Slinton 			}
2249700Slinton 		else {
2259700Slinton 			if( oalloc( p, &off ) ) cerror( "bad argument" );
2269700Slinton 			}
2279700Slinton 
2289700Slinton 		}
22932910Sdonn 	if (gdebug && !nerrors) {
23015896Ssam #ifdef STABDOT
23115896Ssam 		pstabdot(N_SLINE, lineno);
23215896Ssam #else
23315896Ssam 		pstab(NULLNAME, N_SLINE);
23415896Ssam 		printf("0,%d,LL%d\n", lineno, labelno);
23515896Ssam 		printf("LL%d:\n", labelno++);
23615896Ssam #endif
23715896Ssam 	}
2389700Slinton 	fdefflag = 1;
2399700Slinton 	}
2409700Slinton 
2419700Slinton bccode(){ /* called just before the first executable statment */
2429700Slinton 		/* by now, the automatics and register variables are allocated */
2439700Slinton 	SETOFF( autooff, SZINT );
2449700Slinton 	/* set aside store area offset */
2459700Slinton 	p2bbeg( autooff, regvar );
2469700Slinton 	reg_use = (reg_use > regvar ? regvar : reg_use);
2479700Slinton 	}
2489700Slinton 
24932911Sdonn /*ARGSUSED*/
2509700Slinton ejobcode( flag ){
2519700Slinton 	/* called just before final exit */
2529700Slinton 	/* flag is 1 if errors, 0 if none */
2539700Slinton 	}
2549700Slinton 
25532910Sdonn #ifndef aobeg
2569700Slinton aobeg(){
2579700Slinton 	/* called before removing automatics from stab */
2589700Slinton 	}
25932910Sdonn #endif aobeg
2609700Slinton 
26132910Sdonn #ifndef aocode
26232911Sdonn /*ARGSUSED*/
2639700Slinton aocode(p) struct symtab *p; {
2649700Slinton 	/* called when automatic p removed from stab */
2659700Slinton 	}
26632910Sdonn #endif aocode
2679700Slinton 
26832910Sdonn #ifndef aoend
2699700Slinton aoend(){
2709700Slinton 	/* called after removing all automatics from stab */
2719700Slinton 	}
27232910Sdonn #endif aoend
2739700Slinton 
2749700Slinton defnam( p ) register struct symtab *p; {
2759700Slinton 	/* define the current location as the name p->sname */
2769700Slinton 
2779700Slinton 	if( p->sclass == EXTDEF ){
2789700Slinton 		printf( "	.globl	%s\n", exname( p->sname ) );
2799700Slinton 		}
2809700Slinton 	if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
2819700Slinton 	else printf( "%s:\n", exname( p->sname ) );
2829700Slinton 
2839700Slinton 	}
2849700Slinton 
2859700Slinton bycode( t, i ){
2869700Slinton #ifdef ASSTRINGS
2879700Slinton static	int	lastoctal = 0;
2889700Slinton #endif
2899700Slinton 
2909700Slinton 	/* put byte i+1 in a string */
2919700Slinton 
29232910Sdonn 	if ( nerrors ) return;
2939700Slinton #ifdef ASSTRINGS
2949700Slinton 
2959700Slinton 	i &= 077;
2969700Slinton 	if ( t < 0 ){
29724416Smckusick 		if ( i != 0 )	putstr( "\"\n" );
2989700Slinton 	} else {
29924416Smckusick 		if ( i == 0 ) putstr("\t.ascii\t\"");
3009700Slinton 		if ( t == '\\' || t == '"'){
3019700Slinton 			lastoctal = 0;
3029700Slinton 			printf("\\%c", t);
3039700Slinton 		}
3049700Slinton 			/*
3059700Slinton 			 *	We escape the colon in strings so that
3069700Slinton 			 *	c2 will, in its infinite wisdom, interpret
3079700Slinton 			 *	the characters preceding the colon as a label.
3089700Slinton 			 *	If we didn't escape the colon, c2 would
3099700Slinton 			 *	throw away any trailing blanks or tabs after
3109700Slinton 			 *	the colon, but reconstruct a assembly
3119700Slinton 			 *	language semantically correct program.
3129700Slinton 			 *	C2 hasn't been taught about strings.
3139700Slinton 			 */
3149700Slinton 		else if ( t == ':' || t < 040 || t >= 0177 ){
3159700Slinton 			lastoctal++;
3169700Slinton 			printf("\\%o",t);
3179700Slinton 		}
3189700Slinton 		else if ( lastoctal && '0' <= t && t <= '9' ){
3199700Slinton 			lastoctal = 0;
3209700Slinton 			printf("\"\n\t.ascii\t\"%c", t );
3219700Slinton 		}
3229700Slinton 		else
3239700Slinton 		{
3249700Slinton 			lastoctal = 0;
3259700Slinton 			putchar(t);
3269700Slinton 		}
32724416Smckusick 		if ( i == 077 ) putstr("\"\n");
3289700Slinton 	}
3299700Slinton #else
3309700Slinton 
3319700Slinton 	i &= 07;
3329700Slinton 	if( t < 0 ){ /* end of the string */
33324416Smckusick 		if( i != 0 ) putchar( '\n' );
3349700Slinton 		}
3359700Slinton 
3369700Slinton 	else { /* stash byte t into string */
33724416Smckusick 		if( i == 0 ) putstr( "	.byte	" );
33824416Smckusick 		else putchar( ',' );
3399700Slinton 		printf( "0x%x", t );
34024416Smckusick 		if( i == 07 ) putchar( '\n' );
3419700Slinton 		}
3429700Slinton #endif
3439700Slinton 	}
3449700Slinton 
3459700Slinton zecode( n ){
3469700Slinton 	/* n integer words of zeros */
3479700Slinton 	OFFSZ temp;
3489700Slinton 	if( n <= 0 ) return;
3499700Slinton 	printf( "	.space	%d\n", (SZINT/SZCHAR)*n );
3509700Slinton 	temp = n;
3519700Slinton 	inoff += temp*SZINT;
3529700Slinton 	}
3539700Slinton 
35432911Sdonn /*ARGSUSED*/
3559700Slinton fldal( t ) unsigned t; { /* return the alignment of field of type t */
3569700Slinton 	uerror( "illegal field type" );
3579700Slinton 	return( ALINT );
3589700Slinton 	}
3599700Slinton 
36032911Sdonn /*ARGSUSED*/
3619700Slinton fldty( p ) struct symtab *p; { /* fix up type of field p */
3629700Slinton 	;
3639700Slinton 	}
3649700Slinton 
36532911Sdonn /*ARGSUSED*/
3669700Slinton where(c){ /* print location of error  */
3679700Slinton 	/* c is either 'u', 'c', or 'w' */
3689700Slinton 	/* GCOS version */
3699700Slinton 	fprintf( stderr, "%s, line %d: ", ftitle, lineno );
3709700Slinton 	}
3719700Slinton 
3729700Slinton 
373*32913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT
3749700Slinton /* tbl - toreg() returns a pointer to a char string
3759700Slinton 		  which is the correct  "register move" for the passed type
3769700Slinton  */
3779700Slinton struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
3789700Slinton 	{
379*32913Sdonn 	INT, "movl",
380*32913Sdonn 	UNSIGNED,	"movl",
381*32913Sdonn 	DOUBLE, "movq",
3829700Slinton 	CHAR, "cvtbl",
3839700Slinton 	SHORT, "cvtwl",
3849700Slinton 	UCHAR,	"movzbl",
3859700Slinton 	USHORT,	"movzwl",
38617737Sralph 	0, ""
3879700Slinton 	};
3889700Slinton 
3899700Slinton char
3909700Slinton *toreg(type)
3919700Slinton 	TWORD type;
3929700Slinton {
3939700Slinton 	struct type_move *p;
3949700Slinton 
39517737Sralph 	for ( p=toreg_strs; p->fromtype != 0; p++)
3969700Slinton 		if (p->fromtype == type) return(p->tostrng);
3979700Slinton 
3989700Slinton 	/* type not found, must be a pointer type */
3999700Slinton 	return("movl");
4009700Slinton }
4019700Slinton /* tbl */
402*32913Sdonn #endif
4039700Slinton 
4049700Slinton 
4059700Slinton main( argc, argv ) char *argv[]; {
4069700Slinton #ifdef BUFSTDERR
4079700Slinton 	char errbuf[BUFSIZ];
4089700Slinton 	setbuf(stderr, errbuf);
4099700Slinton #endif
4109700Slinton 	return(mainp1( argc, argv ));
4119700Slinton 	}
4129700Slinton 
4139700Slinton struct sw heapsw[SWITSZ];	/* heap for switches */
4149700Slinton 
4159700Slinton genswitch(p,n) register struct sw *p;{
4169700Slinton 	/*	p points to an array of structures, each consisting
4179700Slinton 		of a constant value and a label.
4189700Slinton 		The first is >=0 if there is a default label;
4199700Slinton 		its value is the label number
4209700Slinton 		The entries p[1] to p[n] are the nontrivial cases
4219700Slinton 		*/
4229700Slinton 	register i;
4239700Slinton 	register CONSZ j, range;
4249700Slinton 	register dlab, swlab;
4259700Slinton 
42632910Sdonn 	if( nerrors ) return;
4279700Slinton 	range = p[n].sval-p[1].sval;
4289700Slinton 
4299700Slinton 	if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
4309700Slinton 
4319700Slinton 		swlab = getlab();
4329700Slinton 		dlab = p->slab >= 0 ? p->slab : getlab();
4339700Slinton 
4349700Slinton 		/* already in r0 */
4359700Slinton 		printf("	casel	r0,$%ld,$%ld\n", p[1].sval, range);
4369700Slinton 		printf("L%d:\n", swlab);
4379700Slinton 		for( i=1,j=p[1].sval; i<=n; j++) {
4389700Slinton 			printf("	.word	L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
4399700Slinton 				swlab);
4409700Slinton 			}
4419700Slinton 
4429700Slinton 		if( p->slab >= 0 ) branch( dlab );
4439700Slinton 		else printf("L%d:\n", dlab);
4449700Slinton 		return;
4459700Slinton 
4469700Slinton 		}
4479700Slinton 
4489700Slinton 	if( n>8 ) {	/* heap switch */
4499700Slinton 
4509700Slinton 		heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
4519700Slinton 		makeheap(p, n, 1);	/* build heap */
4529700Slinton 
4539700Slinton 		walkheap(1, n);	/* produce code */
4549700Slinton 
4559700Slinton 		if( p->slab >= 0 )
4569700Slinton 			branch( dlab );
4579700Slinton 		else
4589700Slinton 			printf("L%d:\n", dlab);
4599700Slinton 		return;
4609700Slinton 	}
4619700Slinton 
4629700Slinton 	/* debugging code */
4639700Slinton 
4649700Slinton 	/* out for the moment
4659700Slinton 	if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
4669700Slinton 	*/
4679700Slinton 
4689700Slinton 	/* simple switch code */
4699700Slinton 
4709700Slinton 	for( i=1; i<=n; ++i ){
4719700Slinton 		/* already in r0 */
4729700Slinton 
47324416Smckusick 		putstr( "	cmpl	r0,$" );
4749700Slinton 		printf( CONFMT, p[i].sval );
4759700Slinton 		printf( "\n	jeql	L%d\n", p[i].slab );
4769700Slinton 		}
4779700Slinton 
4789700Slinton 	if( p->slab>=0 ) branch( p->slab );
4799700Slinton 	}
4809700Slinton 
4819700Slinton makeheap(p, m, n)
4829700Slinton register struct sw *p;
4839700Slinton {
4849700Slinton 	register int q;
4859700Slinton 
48632912Sdonn 	q = selectheap(m);
4879700Slinton 	heapsw[n] = p[q];
4889700Slinton 	if( q>1 ) makeheap(p, q-1, 2*n);
4899700Slinton 	if( q<m ) makeheap(p+q, m-q, 2*n+1);
4909700Slinton }
4919700Slinton 
49232912Sdonn selectheap(m) {
4939700Slinton 	register int l,i,k;
4949700Slinton 
4959700Slinton 	for(i=1; ; i*=2)
4969700Slinton 		if( (i-1) > m ) break;
4979700Slinton 	l = ((k = i/2 - 1) + 1)/2;
4989700Slinton 	return( l + (m-k < l ? m-k : l));
4999700Slinton }
5009700Slinton 
5019700Slinton walkheap(start, limit)
5029700Slinton {
5039700Slinton 	int label;
5049700Slinton 
5059700Slinton 
5069700Slinton 	if( start > limit ) return;
5079700Slinton 	printf("	cmpl	r0,$%d\n",  heapsw[start].sval);
5089700Slinton 	printf("	jeql	L%d\n", heapsw[start].slab);
5099700Slinton 	if( (2*start) > limit ) {
5109700Slinton 		printf("	jbr 	L%d\n", heapsw[0].slab);
5119700Slinton 		return;
5129700Slinton 	}
5139700Slinton 	if( (2*start+1) <= limit ) {
5149700Slinton 		label = getlab();
5159700Slinton 		printf("	jgtr	L%d\n", label);
5169700Slinton 	} else
5179700Slinton 		printf("	jgtr	L%d\n", heapsw[0].slab);
5189700Slinton 	walkheap( 2*start, limit);
5199700Slinton 	if( (2*start+1) <= limit ) {
5209700Slinton 		printf("L%d:\n", label);
5219700Slinton 		walkheap( 2*start+1, limit);
5229700Slinton 	}
5239700Slinton }
524