xref: /csrg-svn/old/pcc/ccom.vax/code.c (revision 32911)
117737Sralph #ifndef lint
2*32911Sdonn static char *sccsid ="@(#)code.c	1.7 (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 ? */
149700Slinton char NULLNAME[8];
159700Slinton int labelno;
169700Slinton 
1724416Smckusick # define putstr(s)	fputs((s), stdout)
1824416Smckusick 
199700Slinton branch( n ){
209700Slinton 	/* output a branch to label n */
219700Slinton 	/* exception is an ordinary function branching to retlab: then, return */
2232910Sdonn 	if( nerrors ) return;
239700Slinton 	if( n == retlab && !strftn ){
2424416Smckusick 		putstr( "	ret\n" );
259700Slinton 		}
269700Slinton 	else printf( "	jbr 	L%d\n", n );
279700Slinton 	}
289700Slinton 
299700Slinton int lastloc = { -1 };
309700Slinton 
319700Slinton short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
329700Slinton #define LOG2SZ 9
339700Slinton 
349700Slinton defalign(n) {
359700Slinton 	/* cause the alignment to become a multiple of n */
369700Slinton 	n /= SZCHAR;
379700Slinton 	if( lastloc != PROG && n > 1 ) printf( "	.align	%d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
389700Slinton 	}
399700Slinton 
409700Slinton locctr( l ){
419700Slinton 	register temp;
429700Slinton 	/* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
439700Slinton 
449700Slinton 	if( l == lastloc ) return(l);
459700Slinton 	temp = lastloc;
469700Slinton 	lastloc = l;
4732910Sdonn 	if( nerrors ) return(temp);
489700Slinton 	switch( l ){
499700Slinton 
509700Slinton 	case PROG:
5124416Smckusick 		putstr( "	.text\n" );
529700Slinton 		psline();
539700Slinton 		break;
549700Slinton 
559700Slinton 	case DATA:
569700Slinton 	case ADATA:
5724416Smckusick 		putstr( "	.data\n" );
589700Slinton 		break;
599700Slinton 
609700Slinton 	case STRNG:
6124416Smckusick 		putstr( "	.data	1\n" );
629700Slinton 		break;
639700Slinton 
649700Slinton 	case ISTRNG:
6524416Smckusick 		putstr( "	.data	2\n" );
669700Slinton 		break;
679700Slinton 
689700Slinton 	case STAB:
6924416Smckusick 		putstr( "	.stab\n" );
709700Slinton 		break;
719700Slinton 
729700Slinton 	default:
739700Slinton 		cerror( "illegal location counter" );
749700Slinton 		}
759700Slinton 
769700Slinton 	return( temp );
779700Slinton 	}
789700Slinton 
7932910Sdonn #ifndef deflab
809700Slinton deflab( n ){
819700Slinton 	/* output something to define the current position as label n */
829700Slinton 	printf( "L%d:\n", n );
839700Slinton 	}
8432910Sdonn #endif deflab
859700Slinton 
869700Slinton int crslab = 10;
879700Slinton 
889700Slinton getlab(){
899700Slinton 	/* return a number usable for a label */
909700Slinton 	return( ++crslab );
919700Slinton 	}
929700Slinton 
939700Slinton 
949700Slinton int ent_mask[] = {
959700Slinton 	0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
969700Slinton 
979700Slinton int reg_use = 11;
989700Slinton 
999700Slinton efcode(){
1009700Slinton 	/* code for the end of a function */
1019700Slinton 
1029700Slinton 	if( strftn ){  /* copy output (in R2) to caller */
1039700Slinton 		register NODE *l, *r;
1049700Slinton 		register struct symtab *p;
1059700Slinton 		register TWORD t;
1069700Slinton 		int i;
1079700Slinton 
1089700Slinton 		p = &stab[curftn];
1099700Slinton 		t = p->stype;
1109700Slinton 		t = DECREF(t);
1119700Slinton 
1129700Slinton 		deflab( retlab );
1139700Slinton 
1149700Slinton 		i = getlab();	/* label for return area */
1159700Slinton #ifndef LCOMM
11624416Smckusick 		putstr("	.data\n" );
11724416Smckusick 		putstr("	.align	2\n" );
1189700Slinton 		printf("L%d:	.space	%d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
11924416Smckusick 		putstr("	.text\n" );
1209700Slinton #else
1219700Slinton 		{ int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
1229700Slinton 		if (sz % sizeof (int))
1239700Slinton 			sz += sizeof (int) - (sz % sizeof (int));
1249700Slinton 		printf("	.lcomm	L%d,%d\n", i, sz);
1259700Slinton 		}
1269700Slinton #endif
1279700Slinton 		psline();
1289700Slinton 		printf("	movab	L%d,r1\n", i);
1299700Slinton 
1309700Slinton 		reached = 1;
1319700Slinton 		l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
1329700Slinton 		l->tn.rval = 1;  /* R1 */
1339700Slinton 		l->tn.lval = 0;  /* no offset */
1349700Slinton 		r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
1359700Slinton 		r->tn.rval = 0;  /* R0 */
1369700Slinton 		r->tn.lval = 0;
1379700Slinton 		l = buildtree( UNARY MUL, l, NIL );
1389700Slinton 		r = buildtree( UNARY MUL, r, NIL );
1399700Slinton 		l = buildtree( ASSIGN, l, r );
1409700Slinton 		l->in.op = FREE;
1419700Slinton 		ecomp( l->in.left );
1429700Slinton 		printf( "	movab	L%d,r0\n", i );
1439700Slinton 		/* turn off strftn flag, so return sequence will be generated */
1449700Slinton 		strftn = 0;
1459700Slinton 		}
1469700Slinton 	branch( retlab );
1479700Slinton #ifndef VMS
1489700Slinton 	printf( "	.set	L%d,0x%x\n", ftnno, ent_mask[reg_use] );
1499700Slinton #else
1509700Slinton 	printf( "	.set	L%d,%d	# Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use]  );
1519700Slinton 	/* KLS kludge, under VMS if you use regs 2-5, you must save them. */
1529700Slinton #endif
1539700Slinton 	reg_use = 11;
1549700Slinton 	p2bend();
1559700Slinton 	fdefflag = 0;
1569700Slinton 	}
1579700Slinton 
1589700Slinton int ftlab1, ftlab2;
1599700Slinton 
1609700Slinton bfcode( a, n ) int a[]; {
1619700Slinton 	/* code for the beginning of a function; a is an array of
1629700Slinton 		indices in stab for the arguments; n is the number */
1639700Slinton 	register i;
1649700Slinton 	register temp;
1659700Slinton 	register struct symtab *p;
1669700Slinton 	int off;
1679700Slinton 	char *toreg();
1689700Slinton 
16932910Sdonn 	if( nerrors ) return;
1709700Slinton 	locctr( PROG );
1719700Slinton 	p = &stab[curftn];
17224416Smckusick 	putstr( "	.align	1\n");
1739700Slinton 	defnam( p );
1749700Slinton 	temp = p->stype;
1759700Slinton 	temp = DECREF(temp);
1769700Slinton 	strftn = (temp==STRTY) || (temp==UNIONTY);
1779700Slinton 
1789700Slinton 	retlab = getlab();
1799700Slinton 
1809700Slinton 	/* routine prolog */
1819700Slinton 
1829700Slinton 	printf( "	.word	L%d\n", ftnno);
1839700Slinton 	ftlab1 = getlab();
1849700Slinton 	ftlab2 = getlab();
1859700Slinton 	printf( "	jbr 	L%d\n", ftlab1);
1869700Slinton 	printf( "L%d:\n", ftlab2);
1879700Slinton 	if( proflg ) {	/* profile code */
1889700Slinton 		i = getlab();
1899700Slinton 		printf("	movab	L%d,r0\n", i);
19024416Smckusick 		putstr("	jsb 	mcount\n");
19124416Smckusick 		putstr("	.data\n");
19224416Smckusick 		putstr("	.align	2\n");
1939700Slinton 		printf("L%d:	.long	0\n", i);
19424416Smckusick 		putstr("	.text\n");
1959700Slinton 		psline();
1969700Slinton 		}
1979700Slinton 
1989700Slinton 	off = ARGINIT;
1999700Slinton 
2009700Slinton 	for( i=0; i<n; ++i ){
2019700Slinton 		p = &stab[a[i]];
2029700Slinton 		if( p->sclass == REGISTER ){
2039700Slinton 			temp = p->offset;  /* save register number */
2049700Slinton 			p->sclass = PARAM;  /* forget that it is a register */
2059700Slinton 			p->offset = NOOFFSET;
2069700Slinton 			oalloc( p, &off );
2079700Slinton /*tbl*/		printf( "	%s	%d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
2089700Slinton 			p->offset = temp;  /* remember register number */
2099700Slinton 			p->sclass = REGISTER;   /* remember that it is a register */
2109700Slinton 			}
2119700Slinton 		else if( p->stype == STRTY || p->stype == UNIONTY ) {
2129700Slinton 			p->offset = NOOFFSET;
2139700Slinton 			if( oalloc( p, &off ) ) cerror( "bad argument" );
2149700Slinton 			SETOFF( off, ALSTACK );
2159700Slinton 			}
2169700Slinton 		else {
2179700Slinton 			if( oalloc( p, &off ) ) cerror( "bad argument" );
2189700Slinton 			}
2199700Slinton 
2209700Slinton 		}
22132910Sdonn 	if (gdebug && !nerrors) {
22215896Ssam #ifdef STABDOT
22315896Ssam 		pstabdot(N_SLINE, lineno);
22415896Ssam #else
22515896Ssam 		pstab(NULLNAME, N_SLINE);
22615896Ssam 		printf("0,%d,LL%d\n", lineno, labelno);
22715896Ssam 		printf("LL%d:\n", labelno++);
22815896Ssam #endif
22915896Ssam 	}
2309700Slinton 	fdefflag = 1;
2319700Slinton 	}
2329700Slinton 
2339700Slinton bccode(){ /* called just before the first executable statment */
2349700Slinton 		/* by now, the automatics and register variables are allocated */
2359700Slinton 	SETOFF( autooff, SZINT );
2369700Slinton 	/* set aside store area offset */
2379700Slinton 	p2bbeg( autooff, regvar );
2389700Slinton 	reg_use = (reg_use > regvar ? regvar : reg_use);
2399700Slinton 	}
2409700Slinton 
241*32911Sdonn /*ARGSUSED*/
2429700Slinton ejobcode( flag ){
2439700Slinton 	/* called just before final exit */
2449700Slinton 	/* flag is 1 if errors, 0 if none */
2459700Slinton 	}
2469700Slinton 
24732910Sdonn #ifndef aobeg
2489700Slinton aobeg(){
2499700Slinton 	/* called before removing automatics from stab */
2509700Slinton 	}
25132910Sdonn #endif aobeg
2529700Slinton 
25332910Sdonn #ifndef aocode
254*32911Sdonn /*ARGSUSED*/
2559700Slinton aocode(p) struct symtab *p; {
2569700Slinton 	/* called when automatic p removed from stab */
2579700Slinton 	}
25832910Sdonn #endif aocode
2599700Slinton 
26032910Sdonn #ifndef aoend
2619700Slinton aoend(){
2629700Slinton 	/* called after removing all automatics from stab */
2639700Slinton 	}
26432910Sdonn #endif aoend
2659700Slinton 
2669700Slinton defnam( p ) register struct symtab *p; {
2679700Slinton 	/* define the current location as the name p->sname */
2689700Slinton 
2699700Slinton 	if( p->sclass == EXTDEF ){
2709700Slinton 		printf( "	.globl	%s\n", exname( p->sname ) );
2719700Slinton 		}
2729700Slinton 	if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
2739700Slinton 	else printf( "%s:\n", exname( p->sname ) );
2749700Slinton 
2759700Slinton 	}
2769700Slinton 
2779700Slinton bycode( t, i ){
2789700Slinton #ifdef ASSTRINGS
2799700Slinton static	int	lastoctal = 0;
2809700Slinton #endif
2819700Slinton 
2829700Slinton 	/* put byte i+1 in a string */
2839700Slinton 
28432910Sdonn 	if ( nerrors ) return;
2859700Slinton #ifdef ASSTRINGS
2869700Slinton 
2879700Slinton 	i &= 077;
2889700Slinton 	if ( t < 0 ){
28924416Smckusick 		if ( i != 0 )	putstr( "\"\n" );
2909700Slinton 	} else {
29124416Smckusick 		if ( i == 0 ) putstr("\t.ascii\t\"");
2929700Slinton 		if ( t == '\\' || t == '"'){
2939700Slinton 			lastoctal = 0;
2949700Slinton 			printf("\\%c", t);
2959700Slinton 		}
2969700Slinton 			/*
2979700Slinton 			 *	We escape the colon in strings so that
2989700Slinton 			 *	c2 will, in its infinite wisdom, interpret
2999700Slinton 			 *	the characters preceding the colon as a label.
3009700Slinton 			 *	If we didn't escape the colon, c2 would
3019700Slinton 			 *	throw away any trailing blanks or tabs after
3029700Slinton 			 *	the colon, but reconstruct a assembly
3039700Slinton 			 *	language semantically correct program.
3049700Slinton 			 *	C2 hasn't been taught about strings.
3059700Slinton 			 */
3069700Slinton 		else if ( t == ':' || t < 040 || t >= 0177 ){
3079700Slinton 			lastoctal++;
3089700Slinton 			printf("\\%o",t);
3099700Slinton 		}
3109700Slinton 		else if ( lastoctal && '0' <= t && t <= '9' ){
3119700Slinton 			lastoctal = 0;
3129700Slinton 			printf("\"\n\t.ascii\t\"%c", t );
3139700Slinton 		}
3149700Slinton 		else
3159700Slinton 		{
3169700Slinton 			lastoctal = 0;
3179700Slinton 			putchar(t);
3189700Slinton 		}
31924416Smckusick 		if ( i == 077 ) putstr("\"\n");
3209700Slinton 	}
3219700Slinton #else
3229700Slinton 
3239700Slinton 	i &= 07;
3249700Slinton 	if( t < 0 ){ /* end of the string */
32524416Smckusick 		if( i != 0 ) putchar( '\n' );
3269700Slinton 		}
3279700Slinton 
3289700Slinton 	else { /* stash byte t into string */
32924416Smckusick 		if( i == 0 ) putstr( "	.byte	" );
33024416Smckusick 		else putchar( ',' );
3319700Slinton 		printf( "0x%x", t );
33224416Smckusick 		if( i == 07 ) putchar( '\n' );
3339700Slinton 		}
3349700Slinton #endif
3359700Slinton 	}
3369700Slinton 
3379700Slinton zecode( n ){
3389700Slinton 	/* n integer words of zeros */
3399700Slinton 	OFFSZ temp;
3409700Slinton 	if( n <= 0 ) return;
3419700Slinton 	printf( "	.space	%d\n", (SZINT/SZCHAR)*n );
3429700Slinton 	temp = n;
3439700Slinton 	inoff += temp*SZINT;
3449700Slinton 	}
3459700Slinton 
346*32911Sdonn /*ARGSUSED*/
3479700Slinton fldal( t ) unsigned t; { /* return the alignment of field of type t */
3489700Slinton 	uerror( "illegal field type" );
3499700Slinton 	return( ALINT );
3509700Slinton 	}
3519700Slinton 
352*32911Sdonn /*ARGSUSED*/
3539700Slinton fldty( p ) struct symtab *p; { /* fix up type of field p */
3549700Slinton 	;
3559700Slinton 	}
3569700Slinton 
357*32911Sdonn /*ARGSUSED*/
3589700Slinton where(c){ /* print location of error  */
3599700Slinton 	/* c is either 'u', 'c', or 'w' */
3609700Slinton 	/* GCOS version */
3619700Slinton 	fprintf( stderr, "%s, line %d: ", ftitle, lineno );
3629700Slinton 	}
3639700Slinton 
3649700Slinton 
3659700Slinton /* tbl - toreg() returns a pointer to a char string
3669700Slinton 		  which is the correct  "register move" for the passed type
3679700Slinton  */
3689700Slinton struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
3699700Slinton 	{
3709700Slinton 	CHAR, "cvtbl",
3719700Slinton 	SHORT, "cvtwl",
3729700Slinton 	INT, "movl",
3739700Slinton 	LONG, "movl",
3749700Slinton 	FLOAT, "movf",
3759700Slinton 	DOUBLE, "movd",
3769700Slinton 	UCHAR,	"movzbl",
3779700Slinton 	USHORT,	"movzwl",
3789700Slinton 	UNSIGNED,	"movl",
3799700Slinton 	ULONG,	"movl",
38017737Sralph 	0, ""
3819700Slinton 	};
3829700Slinton 
3839700Slinton char
3849700Slinton *toreg(type)
3859700Slinton 	TWORD type;
3869700Slinton {
3879700Slinton 	struct type_move *p;
3889700Slinton 
38917737Sralph 	for ( p=toreg_strs; p->fromtype != 0; p++)
3909700Slinton 		if (p->fromtype == type) return(p->tostrng);
3919700Slinton 
3929700Slinton 	/* type not found, must be a pointer type */
3939700Slinton 	return("movl");
3949700Slinton }
3959700Slinton /* tbl */
3969700Slinton 
3979700Slinton 
3989700Slinton main( argc, argv ) char *argv[]; {
3999700Slinton #ifdef BUFSTDERR
4009700Slinton 	char errbuf[BUFSIZ];
4019700Slinton 	setbuf(stderr, errbuf);
4029700Slinton #endif
4039700Slinton 	return(mainp1( argc, argv ));
4049700Slinton 	}
4059700Slinton 
4069700Slinton struct sw heapsw[SWITSZ];	/* heap for switches */
4079700Slinton 
4089700Slinton genswitch(p,n) register struct sw *p;{
4099700Slinton 	/*	p points to an array of structures, each consisting
4109700Slinton 		of a constant value and a label.
4119700Slinton 		The first is >=0 if there is a default label;
4129700Slinton 		its value is the label number
4139700Slinton 		The entries p[1] to p[n] are the nontrivial cases
4149700Slinton 		*/
4159700Slinton 	register i;
4169700Slinton 	register CONSZ j, range;
4179700Slinton 	register dlab, swlab;
4189700Slinton 
41932910Sdonn 	if( nerrors ) return;
4209700Slinton 	range = p[n].sval-p[1].sval;
4219700Slinton 
4229700Slinton 	if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
4239700Slinton 
4249700Slinton 		swlab = getlab();
4259700Slinton 		dlab = p->slab >= 0 ? p->slab : getlab();
4269700Slinton 
4279700Slinton 		/* already in r0 */
4289700Slinton 		printf("	casel	r0,$%ld,$%ld\n", p[1].sval, range);
4299700Slinton 		printf("L%d:\n", swlab);
4309700Slinton 		for( i=1,j=p[1].sval; i<=n; j++) {
4319700Slinton 			printf("	.word	L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
4329700Slinton 				swlab);
4339700Slinton 			}
4349700Slinton 
4359700Slinton 		if( p->slab >= 0 ) branch( dlab );
4369700Slinton 		else printf("L%d:\n", dlab);
4379700Slinton 		return;
4389700Slinton 
4399700Slinton 		}
4409700Slinton 
4419700Slinton 	if( n>8 ) {	/* heap switch */
4429700Slinton 
4439700Slinton 		heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
4449700Slinton 		makeheap(p, n, 1);	/* build heap */
4459700Slinton 
4469700Slinton 		walkheap(1, n);	/* produce code */
4479700Slinton 
4489700Slinton 		if( p->slab >= 0 )
4499700Slinton 			branch( dlab );
4509700Slinton 		else
4519700Slinton 			printf("L%d:\n", dlab);
4529700Slinton 		return;
4539700Slinton 	}
4549700Slinton 
4559700Slinton 	/* debugging code */
4569700Slinton 
4579700Slinton 	/* out for the moment
4589700Slinton 	if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
4599700Slinton 	*/
4609700Slinton 
4619700Slinton 	/* simple switch code */
4629700Slinton 
4639700Slinton 	for( i=1; i<=n; ++i ){
4649700Slinton 		/* already in r0 */
4659700Slinton 
46624416Smckusick 		putstr( "	cmpl	r0,$" );
4679700Slinton 		printf( CONFMT, p[i].sval );
4689700Slinton 		printf( "\n	jeql	L%d\n", p[i].slab );
4699700Slinton 		}
4709700Slinton 
4719700Slinton 	if( p->slab>=0 ) branch( p->slab );
4729700Slinton 	}
4739700Slinton 
4749700Slinton makeheap(p, m, n)
4759700Slinton register struct sw *p;
4769700Slinton {
4779700Slinton 	register int q;
4789700Slinton 
4799700Slinton 	q = select(m);
4809700Slinton 	heapsw[n] = p[q];
4819700Slinton 	if( q>1 ) makeheap(p, q-1, 2*n);
4829700Slinton 	if( q<m ) makeheap(p+q, m-q, 2*n+1);
4839700Slinton }
4849700Slinton 
4859700Slinton select(m) {
4869700Slinton 	register int l,i,k;
4879700Slinton 
4889700Slinton 	for(i=1; ; i*=2)
4899700Slinton 		if( (i-1) > m ) break;
4909700Slinton 	l = ((k = i/2 - 1) + 1)/2;
4919700Slinton 	return( l + (m-k < l ? m-k : l));
4929700Slinton }
4939700Slinton 
4949700Slinton walkheap(start, limit)
4959700Slinton {
4969700Slinton 	int label;
4979700Slinton 
4989700Slinton 
4999700Slinton 	if( start > limit ) return;
5009700Slinton 	printf("	cmpl	r0,$%d\n",  heapsw[start].sval);
5019700Slinton 	printf("	jeql	L%d\n", heapsw[start].slab);
5029700Slinton 	if( (2*start) > limit ) {
5039700Slinton 		printf("	jbr 	L%d\n", heapsw[0].slab);
5049700Slinton 		return;
5059700Slinton 	}
5069700Slinton 	if( (2*start+1) <= limit ) {
5079700Slinton 		label = getlab();
5089700Slinton 		printf("	jgtr	L%d\n", label);
5099700Slinton 	} else
5109700Slinton 		printf("	jgtr	L%d\n", heapsw[0].slab);
5119700Slinton 	walkheap( 2*start, limit);
5129700Slinton 	if( (2*start+1) <= limit ) {
5139700Slinton 		printf("L%d:\n", label);
5149700Slinton 		walkheap( 2*start+1, limit);
5159700Slinton 	}
5169700Slinton }
517