xref: /original-bsd/old/pcc/mip/allo.c (revision bff54947)
1 #ifndef lint
2 static char *sccsid ="@(#)allo.c	4.10 (Berkeley) 12/09/87";
3 #endif lint
4 
5 # include "pass2.h"
6 
7 NODE resc[3];
8 
9 int busy[REGSZ];
10 
11 int maxa, mina, maxb, minb;
12 
13 # ifndef ALLO0
14 allo0(){ /* free everything */
15 
16 	register i;
17 
18 	maxa = maxb = -1;
19 	mina = minb = 0;
20 
21 	REGLOOP(i){
22 		busy[i] = 0;
23 		if( rstatus[i] & STAREG ){
24 			if( maxa<0 ) mina = i;
25 			maxa = i;
26 			}
27 		if( rstatus[i] & STBREG ){
28 			if( maxb<0 ) minb = i;
29 			maxb = i;
30 			}
31 		}
32 	}
33 # endif
34 
35 # ifndef ALLO
36 allo( p, q ) NODE *p; struct optab *q; {
37 
38 	register n, i, j;
39 	int either;
40 
41 	n = q->needs;
42 	either = ( EITHER & n );
43 	i = 0;
44 
45 	while( n & NACOUNT ){
46 		resc[i].in.op = REG;
47 		resc[i].tn.rval = freereg( p, n&(NAMASK|NEVEN) );
48 		resc[i].tn.lval = 0;
49 #ifdef FLEXNAMES
50 		resc[i].in.name = "";
51 #else
52 		resc[i].in.name[0] = '\0';
53 #endif
54 		n &= ~NEVEN;		/* only used for first need */
55 		n -= NAREG;
56 		++i;
57 		}
58 
59 	if (either) { /* all or nothing at all */
60 		for( j = 0; j < i; j++ )
61 			if( resc[j].tn.rval < 0 ) { /* nothing */
62 				i = 0;
63 				break;
64 				}
65 		if( i != 0 ) goto ok; /* all */
66 		}
67 
68 	while( n & NBCOUNT ){
69 		resc[i].in.op = REG;
70 		resc[i].tn.rval = freereg( p, n&NBMASK );
71 		resc[i].tn.lval = 0;
72 #ifdef FLEXNAMES
73 		resc[i].in.name = "";
74 #else
75 		resc[i].in.name[0] = '\0';
76 #endif
77 		n -= NBREG;
78 		++i;
79 		}
80 	if (either) { /* all or nothing at all */
81 		for( j = 0; j < i; j++ )
82 			if( resc[j].tn.rval < 0 ) { /* nothing */
83 				i = 0;
84 				break;
85 				}
86 		if( i != 0 ) goto ok; /* all */
87 		}
88 
89 	if( n & NTMASK ){
90 		resc[i].in.op = OREG;
91 		resc[i].tn.rval = TMPREG;
92 		if( p->in.op == STCALL || p->in.op == STARG || p->in.op == UNARY STCALL || p->in.op == STASG ){
93 			resc[i].tn.lval = freetemp( (SZCHAR*p->stn.stsize + (SZINT-1))/SZINT );
94 			}
95 		else {
96 			resc[i].tn.lval = freetemp( (n&NTMASK)/NTEMP );
97 			}
98 #ifdef FLEXNAMES
99 		resc[i].in.name = "";
100 #else
101 		resc[i].in.name[0] = '\0';
102 #endif
103 
104 		resc[i].tn.lval = BITOOR(resc[i].tn.lval);
105 		++i;
106 		}
107 
108 	/* turn off "temporarily busy" bit */
109 
110 	ok:
111 	REGLOOP(j){
112 		busy[j] &= ~TBUSY;
113 		}
114 
115 	for( j=0; j<i; ++j ) if( resc[j].tn.rval < 0 ) return(0);
116 	return(1);
117 
118 	}
119 # endif
120 
121 extern unsigned int offsz;
122 freetemp( k ){ /* allocate k integers worth of temp space */
123 	/* we also make the convention that, if the number of words is more than 1,
124 	/* it must be aligned for storing doubles... */
125 
126 # ifndef BACKTEMP
127 	int t;
128 
129 	if( k>1 ){
130 		SETOFF( tmpoff, ALDOUBLE );
131 		}
132 
133 	t = tmpoff;
134 	tmpoff += k*SZINT;
135 	if( tmpoff > maxoff ) maxoff = tmpoff;
136 	if( tmpoff >= offsz )
137 		cerror( "stack overflow" );
138 	if( tmpoff-baseoff > maxtemp ) maxtemp = tmpoff-baseoff;
139 	return(t);
140 
141 # else
142 	tmpoff += k*SZINT;
143 	if( k>1 ) {
144 		SETOFF( tmpoff, ALDOUBLE );
145 		}
146 	if( tmpoff > maxoff ) maxoff = tmpoff;
147 	if( tmpoff >= offsz )
148 		cerror( "stack overflow" );
149 	if( tmpoff-baseoff > maxtemp ) maxtemp = tmpoff-baseoff;
150 	return( -tmpoff );
151 # endif
152 	}
153 
154 freereg( p, n ) NODE *p; {
155 	/* allocate a register of type n */
156 	/* p gives the type, if floating */
157 
158 	register j;
159 
160 	/* not general; means that only one register (the result) OK for call */
161 	if( callop(p->in.op) ){
162 		j = callreg(p);
163 		if( usable( p, n, j ) ) return( j );
164 		/* have allocated callreg first */
165 		}
166 	j = p->in.rall & ~MUSTDO;
167 	if( j!=NOPREF && usable(p,n,j) ){ /* needed and not allocated */
168 		return( j );
169 		}
170 	if( n&NAMASK ){
171 		for( j=mina; j<=maxa; ++j ) if( rstatus[j]&STAREG ){
172 			if( usable(p,n,j) ){
173 				return( j );
174 				}
175 			}
176 		}
177 	else if( n &NBMASK ){
178 		for( j=minb; j<=maxb; ++j ) if( rstatus[j]&STBREG ){
179 			if( usable(p,n,j) ){
180 				return(j);
181 				}
182 			}
183 		}
184 
185 	return( -1 );
186 	}
187 
188 # ifndef USABLE
189 usable( p, n, r ) NODE *p; {
190 	/* decide if register r is usable in tree p to satisfy need n */
191 
192 	/* checks, for the moment */
193 	if( !istreg(r) ) cerror( "usable asked about nontemp register" );
194 
195 	if( ISBUSY(r) ) return(0);
196 	if( isbreg(r) ){
197 		if( n&NAMASK ) return(0);
198 		}
199 	else {
200 		if( n & NBMASK ) return(0);
201 		}
202 	/*
203 	 * Some special cases that require register pairs...
204 	 * Have to check for ==, <=, etc. because the result is type int
205 	 * but need a register pair temp if either side is wide.
206 	 * For +=, *= etc. where lhs is narrow and rhs is wide, the temp
207 	 * register must be wide.
208 	 */
209 	if( (n&NAMASK) &&
210 	    (szty(p->in.type) == 2 || (n&NEVEN) ||
211 	     (logop(p->in.op) && (szty(p->in.left->in.type) == 2 ||
212 	      szty(p->in.right->in.type) == 2)) ||
213 	     (asgop(p->in.op) && szty(p->in.right->in.type) == 2 &&
214 	      szty(p->in.left->in.type) == 1))
215 	){
216 #ifndef NOEVENODD
217 		if( r&01 ) return(0);
218 #endif
219 		if( !istreg(r+1) ) return( 0 );
220 		if( busy[r+1] > 1 ) return( 0 );
221 		if( busy[r] == 0 && busy[r+1] == 0  ||
222 		    (busy[r+1] == 0 || (busy[r] & PBUSY)) &&
223 			shareit( p, r, n ) ||
224 		    busy[r] == 0 && shareit( p, r+1, n ) ){
225 			busy[r] |= TBUSY;
226 			busy[r+1] |= TBUSY;
227 			return(1);
228 			}
229 		else return(0);
230 		}
231 	if( busy[r] == 0 ) {
232 		busy[r] |= TBUSY;
233 		return(1);
234 		}
235 
236 	/* busy[r] is 1: is there chance for sharing */
237 	return( shareit( p, r, n ) );
238 
239 	}
240 # endif
241 
242 shareit( p, r, n ) NODE *p; {
243 	/* can we make register r available by sharing from p
244 	   given that the need is n */
245 	if( (n&(NASL|NBSL)) && ushare( p, 'L', r ) ) return(1);
246 	if( (n&(NASR|NBSR)) && ushare( p, 'R', r ) ) return(1);
247 	return(0);
248 	}
249 
250 ushare( p, f, r ) NODE *p; {
251 	/* can we find a register r to share on the left or right
252 		(as f=='L' or 'R', respectively) of p */
253 	p = getlr( p, f );
254 	if( p->in.op == UNARY MUL ) p = p->in.left;
255 	if( p->in.op == OREG ){
256 		if( R2TEST(p->tn.rval) ){
257 			return( r==R2UPK1(p->tn.rval) || r==R2UPK2(p->tn.rval) );
258 			}
259 		else return( r == p->tn.rval );
260 		}
261 	if( p->in.op == REG ){
262 		return( r == p->tn.rval || ( szty(p->in.type) == 2 && r==p->tn.rval+1 ) );
263 		}
264 	return(0);
265 	}
266 
267 recl2( p ) register NODE *p; {
268 	register r = p->tn.rval;
269 #ifndef OLD
270 	int op = p->in.op;
271 	if (op == REG && r >= REGSZ)
272 		op = OREG;
273 	if( op == REG ) rfree( r, p->in.type );
274 	else if( op == OREG ) {
275 		if( R2TEST( r ) ) {
276 			if( R2UPK1( r ) != 100 ) rfree( R2UPK1( r ), PTR+INT );
277 			rfree( R2UPK2( r ), INT );
278 			}
279 		else {
280 			rfree( r, PTR+INT );
281 			}
282 		}
283 #else
284 	if( p->in.op == REG ) rfree( r, p->in.type );
285 	else if( p->in.op == OREG ) {
286 		if( R2TEST( r ) ) {
287 			if( R2UPK1( r ) != 100 ) rfree( R2UPK1( r ), PTR+INT );
288 			rfree( R2UPK2( r ), INT );
289 			}
290 		else {
291 			rfree( r, PTR+INT );
292 			}
293 		}
294 #endif
295 	}
296 
297 int rdebug = 0;
298 
299 # ifndef RFREE
300 rfree( r, t ) TWORD t; {
301 	/* mark register r free, if it is legal to do so */
302 	/* t is the type */
303 
304 # ifndef BUG3
305 	if( rdebug ){
306 		printf( "rfree( %s ), size %d\n", rnames[r], szty(t) );
307 		}
308 # endif
309 
310 	if( istreg(r) ){
311 		if( --busy[r] < 0 ) cerror( "register overfreed");
312 		if( busy[r] == PBUSY )
313 			busy[r] = 0;
314 		if( szty(t) == 2 ){
315 #ifdef NOEVENODD
316 			if( istreg(r) ^ istreg(r+1) ) cerror( "illegal free" );
317 #else
318 			if( (r&01) || (istreg(r)^istreg(r+1)) ) cerror( "illegal free" );
319 #endif
320 			if( --busy[r+1] < 0 ) cerror( "register overfreed" );
321 			}
322 		}
323 	}
324 # endif
325 
326 # ifndef RBUSY
327 rbusy(r,t) TWORD t; {
328 	/* mark register r busy */
329 	/* t is the type */
330 
331 # ifndef BUG3
332 	if( rdebug ){
333 		printf( "rbusy( %s ), size %d\n", rnames[r], szty(t) );
334 		}
335 # endif
336 
337 	if( istreg(r) ) ++busy[r];
338 	if( szty(t) == 2 ){
339 		if( istreg(r+1) ) {
340 			++busy[r+1];
341 			busy[r] |= PBUSY;
342 			}
343 #ifdef NOEVENODD
344 		if( istreg(r) ^ istreg(r+1) ) cerror( "illegal register pair freed" );
345 #else
346 		if( (r&01) || (istreg(r)^istreg(r+1)) ) cerror( "illegal register pair freed" );
347 #endif
348 		}
349 	}
350 # endif
351 
352 # ifndef BUG3
353 rwprint( rw ){ /* print rewriting rule */
354 	register i, flag;
355 	static char * rwnames[] = {
356 
357 		"RLEFT",
358 		"RRIGHT",
359 		"RESC1",
360 		"RESC2",
361 		"RESC3",
362 		0,
363 		};
364 
365 	if( rw == RNULL ){
366 		printf( "RNULL" );
367 		return;
368 		}
369 
370 	if( rw == RNOP ){
371 		printf( "RNOP" );
372 		return;
373 		}
374 
375 	flag = 0;
376 	for( i=0; rwnames[i]; ++i ){
377 		if( rw & (1<<i) ){
378 			if( flag ) printf( "|" );
379 			++flag;
380 			printf( rwnames[i] );
381 			}
382 		}
383 	}
384 # endif
385 
386 reclaim( p, rw, cookie ) NODE *p; {
387 	register NODE **qq;
388 	register NODE *q;
389 	register i;
390 	NODE *recres[5];
391 	struct respref *r;
392 
393 	/* get back stuff */
394 
395 # ifndef BUG3
396 	if( rdebug ){
397 		printf( "reclaim( %o, ", p );
398 		rwprint( rw );
399 		printf( ", " );
400 		prcook( cookie );
401 		printf( " )\n" );
402 		}
403 # endif
404 
405 	if( rw == RNOP || ( p->in.op==FREE && rw==RNULL ) ) return;  /* do nothing */
406 
407 	walkf( p, recl2 );
408 
409 	if( callop(p->in.op) ){
410 		/* check that all scratch regs are free */
411 		callchk(p);  /* ordinarily, this is the same as allchk() */
412 		}
413 
414 	if( rw == RNULL || (cookie&FOREFF) ){ /* totally clobber, leaving nothing */
415 		tfree(p);
416 		return;
417 		}
418 
419 	/* handle condition codes specially */
420 
421 	if( (cookie & FORCC) && (rw&RESCC)) {
422 		/* result is CC register */
423 		tfree(p);
424 		p->in.op = CCODES;
425 		p->tn.lval = 0;
426 		p->tn.rval = 0;
427 		return;
428 		}
429 
430 	/* locate results */
431 
432 	qq = recres;
433 
434 	if( rw&RLEFT) *qq++ = getlr( p, 'L' );;
435 	if( rw&RRIGHT ) *qq++ = getlr( p, 'R' );
436 	if( rw&RESC1 ) *qq++ = &resc[0];
437 	if( rw&RESC2 ) *qq++ = &resc[1];
438 	if( rw&RESC3 ) *qq++ = &resc[2];
439 
440 	if( qq == recres ){
441 		cerror( "illegal reclaim");
442 		}
443 
444 	*qq = NIL;
445 
446 	/* now, select the best result, based on the cookie */
447 
448 	for( r=respref; r->cform; ++r ){
449 		if( cookie & r->cform ){
450 			for( qq=recres; (q= *qq) != NIL; ++qq ){
451 				if( tshape( q, r->mform ) ) goto gotit;
452 				}
453 			}
454 		}
455 
456 	/* we can't do it; die */
457 	cerror( "cannot reclaim");
458 
459 	gotit:
460 
461 	if( p->in.op == STARG ) p = p->in.left;  /* STARGs are still STARGS */
462 
463 	q->in.type = p->in.type;  /* to make multi-register allocations work */
464 		/* maybe there is a better way! */
465 	q = tcopy(q);
466 
467 	tfree(p);
468 
469 	p->in.op = q->in.op;
470 	p->tn.lval = q->tn.lval;
471 	p->tn.rval = q->tn.rval;
472 #ifdef FLEXNAMES
473 	p->in.name = q->in.name;
474 #ifdef ONEPASS
475 	p->in.stalign = q->in.stalign;
476 #endif
477 #else
478 	for( i=0; i<NCHNAM; ++i )
479 		p->in.name[i] = q->in.name[i];
480 #endif
481 
482 	q->in.op = FREE;
483 
484 	/* if the thing is in a register, adjust the type */
485 
486 	switch( p->in.op ){
487 
488 	case REG:
489 		if( !rtyflg ){
490 			/* the C language requires intermediate results to change type */
491 			/* this is inefficient or impossible on some machines */
492 			/* the "T" command in match supresses this type changing */
493 			if( p->in.type == CHAR || p->in.type == SHORT ) p->in.type = INT;
494 			else if( p->in.type == UCHAR || p->in.type == USHORT ) p->in.type = UNSIGNED;
495 #if !defined(FORT) && !defined(SPRECC)
496 			else if( p->in.type == FLOAT ) p->in.type = DOUBLE;
497 #endif
498 			}
499 		if( ! (p->in.rall & MUSTDO ) ) return;  /* unless necessary, ignore it */
500 		i = p->in.rall & ~MUSTDO;
501 		if( i & NOPREF ) return;
502 		if( i != p->tn.rval ){
503 			if( busy[i] || ( szty(p->in.type)==2 && busy[i+1] ) ){
504 				cerror( "faulty register move" );
505 				}
506 			rbusy( i, p->in.type );
507 			rfree( p->tn.rval, p->in.type );
508 			rmove( i, p->tn.rval, p->in.type );
509 			p->tn.rval = i;
510 			}
511 
512 	case OREG:
513 		if( p->in.op == REG || !R2TEST(p->tn.rval) ) {
514 			if( ISBUSY(p->tn.rval) && istreg(p->tn.rval) ) cerror( "potential register overwrite");
515 			}
516 		else
517 			if( (R2UPK1(p->tn.rval) != 100 && ISBUSY(R2UPK1(p->tn.rval)) && istreg(R2UPK1(p->tn.rval)) )
518 				|| (ISBUSY(R2UPK2(p->tn.rval)) && istreg(R2UPK2(p->tn.rval)) ) )
519 			   cerror( "potential register overwrite");
520 		}
521 
522 	}
523 
524 #ifndef ncopy
525 ncopy( q, p ) NODE *p, *q; {
526 	/* copy the contents of p into q, without any feeling for
527 	   the contents */
528 	/* this code assume that copying rval and lval does the job;
529 	   in general, it might be necessary to special case the
530 	   operator types */
531 	register i;
532 
533 	q->in.op = p->in.op;
534 	q->in.rall = p->in.rall;
535 	q->in.type = p->in.type;
536 	q->tn.lval = p->tn.lval;
537 	q->tn.rval = p->tn.rval;
538 #ifdef FLEXNAMES
539 	q->in.name = p->in.name;
540 #ifdef ONEPASS
541 	q->in.stalign = p->in.stalign;
542 #endif
543 #else
544 	for( i=0; i<NCHNAM; ++i ) q->in.name[i]  = p->in.name[i];
545 #endif
546 
547 	}
548 #endif
549 
550 NODE *
551 tcopy( p ) register NODE *p; {
552 	/* make a fresh copy of p */
553 
554 	register NODE *q;
555 	register r;
556 
557 	ncopy( q=talloc(), p );
558 
559 	r = p->tn.rval;
560 	if( p->in.op == REG ) rbusy( r, p->in.type );
561 	else if( p->in.op == OREG ) {
562 		if( R2TEST(r) ){
563 			if( R2UPK1(r) != 100 ) rbusy( R2UPK1(r), PTR+INT );
564 			rbusy( R2UPK2(r), INT );
565 			}
566 		else {
567 			rbusy( r, PTR+INT );
568 			}
569 		}
570 
571 	switch( optype(q->in.op) ){
572 
573 	case BITYPE:
574 		q->in.right = tcopy(p->in.right);
575 	case UTYPE:
576 		q->in.left = tcopy(p->in.left);
577 		}
578 
579 	return(q);
580 	}
581 
582 allchk(){
583 	/* check to ensure that all register are free */
584 
585 	register i;
586 
587 	REGLOOP(i){
588 		if( istreg(i) && busy[i] ){
589 			cerror( "register allocation error");
590 			}
591 		}
592 
593 	}
594