xref: /original-bsd/old/pcc/ccom.vax/code.c (revision e877e4b2)
1 #ifndef lint
2 static char *sccsid ="@(#)code.c	1.9 (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
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 % (SZINT/SZCHAR))
125 			sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
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 #ifdef TRUST_REG_CHAR_AND_REG_SHORT
170 	char *toreg();
171 #endif
172 
173 	if( nerrors ) return;
174 	(void) locctr( PROG );
175 	p = &stab[curftn];
176 	putstr( "	.align	1\n");
177 	defnam( p );
178 	temp = p->stype;
179 	temp = DECREF(temp);
180 	strftn = (temp==STRTY) || (temp==UNIONTY);
181 
182 	retlab = getlab();
183 
184 	/* routine prolog */
185 
186 	printf( "	.word	L%d\n", ftnno);
187 	ftlab1 = getlab();
188 	ftlab2 = getlab();
189 	printf( "	jbr 	L%d\n", ftlab1);
190 	printf( "L%d:\n", ftlab2);
191 	if( proflg ) {	/* profile code */
192 		i = getlab();
193 		printf("	movab	L%d,r0\n", i);
194 		putstr("	jsb 	mcount\n");
195 		putstr("	.data\n");
196 		putstr("	.align	2\n");
197 		printf("L%d:	.long	0\n", i);
198 		putstr("	.text\n");
199 		psline();
200 		}
201 
202 	off = ARGINIT;
203 
204 	for( i=0; i<n; ++i ){
205 		p = &stab[a[i]];
206 		if( p->sclass == REGISTER ){
207 			temp = p->offset;  /* save register number */
208 			p->sclass = PARAM;  /* forget that it is a register */
209 			p->offset = NOOFFSET;
210 			(void) oalloc( p, &off );
211 #ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */
212 /*tbl*/		printf( "	%s	%d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
213 #else
214 /*tbl*/		printf( "	movl	%d(ap),r%d\n", p->offset/SZCHAR, temp );
215 #endif
216 			p->offset = temp;  /* remember register number */
217 			p->sclass = REGISTER;   /* remember that it is a register */
218 			}
219 		else if( p->stype == STRTY || p->stype == UNIONTY ) {
220 			p->offset = NOOFFSET;
221 			if( oalloc( p, &off ) ) cerror( "bad argument" );
222 			SETOFF( off, ALSTACK );
223 			}
224 		else {
225 			if( oalloc( p, &off ) ) cerror( "bad argument" );
226 			}
227 
228 		}
229 	if (gdebug && !nerrors) {
230 #ifdef STABDOT
231 		pstabdot(N_SLINE, lineno);
232 #else
233 		pstab(NULLNAME, N_SLINE);
234 		printf("0,%d,LL%d\n", lineno, labelno);
235 		printf("LL%d:\n", labelno++);
236 #endif
237 	}
238 	fdefflag = 1;
239 	}
240 
241 bccode(){ /* called just before the first executable statment */
242 		/* by now, the automatics and register variables are allocated */
243 	SETOFF( autooff, SZINT );
244 	/* set aside store area offset */
245 	p2bbeg( autooff, regvar );
246 	reg_use = (reg_use > regvar ? regvar : reg_use);
247 	}
248 
249 /*ARGSUSED*/
250 ejobcode( flag ){
251 	/* called just before final exit */
252 	/* flag is 1 if errors, 0 if none */
253 	}
254 
255 #ifndef aobeg
256 aobeg(){
257 	/* called before removing automatics from stab */
258 	}
259 #endif aobeg
260 
261 #ifndef aocode
262 /*ARGSUSED*/
263 aocode(p) struct symtab *p; {
264 	/* called when automatic p removed from stab */
265 	}
266 #endif aocode
267 
268 #ifndef aoend
269 aoend(){
270 	/* called after removing all automatics from stab */
271 	}
272 #endif aoend
273 
274 defnam( p ) register struct symtab *p; {
275 	/* define the current location as the name p->sname */
276 
277 	if( p->sclass == EXTDEF ){
278 		printf( "	.globl	%s\n", exname( p->sname ) );
279 		}
280 	if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
281 	else printf( "%s:\n", exname( p->sname ) );
282 
283 	}
284 
285 bycode( t, i ){
286 #ifdef ASSTRINGS
287 static	int	lastoctal = 0;
288 #endif
289 
290 	/* put byte i+1 in a string */
291 
292 	if ( nerrors ) return;
293 #ifdef ASSTRINGS
294 
295 	i &= 077;
296 	if ( t < 0 ){
297 		if ( i != 0 )	putstr( "\"\n" );
298 	} else {
299 		if ( i == 0 ) putstr("\t.ascii\t\"");
300 		if ( t == '\\' || t == '"'){
301 			lastoctal = 0;
302 			printf("\\%c", t);
303 		}
304 			/*
305 			 *	We escape the colon in strings so that
306 			 *	c2 will, in its infinite wisdom, interpret
307 			 *	the characters preceding the colon as a label.
308 			 *	If we didn't escape the colon, c2 would
309 			 *	throw away any trailing blanks or tabs after
310 			 *	the colon, but reconstruct a assembly
311 			 *	language semantically correct program.
312 			 *	C2 hasn't been taught about strings.
313 			 */
314 		else if ( t == ':' || t < 040 || t >= 0177 ){
315 			lastoctal++;
316 			printf("\\%o",t);
317 		}
318 		else if ( lastoctal && '0' <= t && t <= '9' ){
319 			lastoctal = 0;
320 			printf("\"\n\t.ascii\t\"%c", t );
321 		}
322 		else
323 		{
324 			lastoctal = 0;
325 			putchar(t);
326 		}
327 		if ( i == 077 ) putstr("\"\n");
328 	}
329 #else
330 
331 	i &= 07;
332 	if( t < 0 ){ /* end of the string */
333 		if( i != 0 ) putchar( '\n' );
334 		}
335 
336 	else { /* stash byte t into string */
337 		if( i == 0 ) putstr( "	.byte	" );
338 		else putchar( ',' );
339 		printf( "0x%x", t );
340 		if( i == 07 ) putchar( '\n' );
341 		}
342 #endif
343 	}
344 
345 zecode( n ){
346 	/* n integer words of zeros */
347 	OFFSZ temp;
348 	if( n <= 0 ) return;
349 	printf( "	.space	%d\n", (SZINT/SZCHAR)*n );
350 	temp = n;
351 	inoff += temp*SZINT;
352 	}
353 
354 /*ARGSUSED*/
355 fldal( t ) unsigned t; { /* return the alignment of field of type t */
356 	uerror( "illegal field type" );
357 	return( ALINT );
358 	}
359 
360 /*ARGSUSED*/
361 fldty( p ) struct symtab *p; { /* fix up type of field p */
362 	;
363 	}
364 
365 /*ARGSUSED*/
366 where(c){ /* print location of error  */
367 	/* c is either 'u', 'c', or 'w' */
368 	/* GCOS version */
369 	fprintf( stderr, "%s, line %d: ", ftitle, lineno );
370 	}
371 
372 
373 #ifdef TRUST_REG_CHAR_AND_REG_SHORT
374 /* tbl - toreg() returns a pointer to a char string
375 		  which is the correct  "register move" for the passed type
376  */
377 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
378 	{
379 	INT, "movl",
380 	UNSIGNED,	"movl",
381 	DOUBLE, "movq",
382 	CHAR, "cvtbl",
383 	SHORT, "cvtwl",
384 	UCHAR,	"movzbl",
385 	USHORT,	"movzwl",
386 	0, ""
387 	};
388 
389 char
390 *toreg(type)
391 	TWORD type;
392 {
393 	struct type_move *p;
394 
395 	for ( p=toreg_strs; p->fromtype != 0; p++)
396 		if (p->fromtype == type) return(p->tostrng);
397 
398 	/* type not found, must be a pointer type */
399 	return("movl");
400 }
401 /* tbl */
402 #endif
403 
404 
405 main( argc, argv ) char *argv[]; {
406 #ifdef BUFSTDERR
407 	char errbuf[BUFSIZ];
408 	setbuf(stderr, errbuf);
409 #endif
410 	return(mainp1( argc, argv ));
411 	}
412 
413 struct sw heapsw[SWITSZ];	/* heap for switches */
414 
415 genswitch(p,n) register struct sw *p;{
416 	/*	p points to an array of structures, each consisting
417 		of a constant value and a label.
418 		The first is >=0 if there is a default label;
419 		its value is the label number
420 		The entries p[1] to p[n] are the nontrivial cases
421 		*/
422 	register i;
423 	register CONSZ j, range;
424 	register dlab, swlab;
425 
426 	if( nerrors ) return;
427 	range = p[n].sval-p[1].sval;
428 
429 	if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
430 
431 		swlab = getlab();
432 		dlab = p->slab >= 0 ? p->slab : getlab();
433 
434 		/* already in r0 */
435 		printf("	casel	r0,$%ld,$%ld\n", p[1].sval, range);
436 		printf("L%d:\n", swlab);
437 		for( i=1,j=p[1].sval; i<=n; j++) {
438 			printf("	.word	L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
439 				swlab);
440 			}
441 
442 		if( p->slab >= 0 ) branch( dlab );
443 		else printf("L%d:\n", dlab);
444 		return;
445 
446 		}
447 
448 	if( n>8 ) {	/* heap switch */
449 
450 		heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
451 		makeheap(p, n, 1);	/* build heap */
452 
453 		walkheap(1, n);	/* produce code */
454 
455 		if( p->slab >= 0 )
456 			branch( dlab );
457 		else
458 			printf("L%d:\n", dlab);
459 		return;
460 	}
461 
462 	/* debugging code */
463 
464 	/* out for the moment
465 	if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
466 	*/
467 
468 	/* simple switch code */
469 
470 	for( i=1; i<=n; ++i ){
471 		/* already in r0 */
472 
473 		putstr( "	cmpl	r0,$" );
474 		printf( CONFMT, p[i].sval );
475 		printf( "\n	jeql	L%d\n", p[i].slab );
476 		}
477 
478 	if( p->slab>=0 ) branch( p->slab );
479 	}
480 
481 makeheap(p, m, n)
482 register struct sw *p;
483 {
484 	register int q;
485 
486 	q = selectheap(m);
487 	heapsw[n] = p[q];
488 	if( q>1 ) makeheap(p, q-1, 2*n);
489 	if( q<m ) makeheap(p+q, m-q, 2*n+1);
490 }
491 
492 selectheap(m) {
493 	register int l,i,k;
494 
495 	for(i=1; ; i*=2)
496 		if( (i-1) > m ) break;
497 	l = ((k = i/2 - 1) + 1)/2;
498 	return( l + (m-k < l ? m-k : l));
499 }
500 
501 walkheap(start, limit)
502 {
503 	int label;
504 
505 
506 	if( start > limit ) return;
507 	printf("	cmpl	r0,$%d\n",  heapsw[start].sval);
508 	printf("	jeql	L%d\n", heapsw[start].slab);
509 	if( (2*start) > limit ) {
510 		printf("	jbr 	L%d\n", heapsw[0].slab);
511 		return;
512 	}
513 	if( (2*start+1) <= limit ) {
514 		label = getlab();
515 		printf("	jgtr	L%d\n", label);
516 	} else
517 		printf("	jgtr	L%d\n", heapsw[0].slab);
518 	walkheap( 2*start, limit);
519 	if( (2*start+1) <= limit ) {
520 		printf("L%d:\n", label);
521 		walkheap( 2*start+1, limit);
522 	}
523 }
524