new version from Chris Torek
[unix-history] / usr / src / old / pcc / mip / allo.c
CommitLineData
262eaf56 1#ifndef lint
b401968b 2static char *sccsid ="@(#)allo.c 4.10 (Berkeley) %G%";
262eaf56
RC
3#endif lint
4
69023ebb 5# include "pass2.h"
e91423bb
RC
6
7NODE resc[3];
8
9int busy[REGSZ];
10
11int maxa, mina, maxb, minb;
12
13# ifndef ALLO0
14allo0(){ /* 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
e91423bb
RC
35# ifndef ALLO
36allo( 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;
e052b160 47 resc[i].tn.rval = freereg( p, n&(NAMASK|NEVEN) );
e91423bb
RC
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
e052b160 54 n &= ~NEVEN; /* only used for first need */
e91423bb
RC
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
121extern unsigned int offsz;
122freetemp( 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
154freereg( 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
189usable( 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
11f459b9 195 if( ISBUSY(r) ) return(0);
e91423bb
RC
196 if( isbreg(r) ){
197 if( n&NAMASK ) return(0);
198 }
199 else {
200 if( n & NBMASK ) return(0);
201 }
a380d75d 202 /*
57b6b508
DS
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.
a380d75d 208 */
57b6b508 209 if( (n&NAMASK) &&
e052b160 210 (szty(p->in.type) == 2 || (n&NEVEN) ||
57b6b508
DS
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 ){
bd4e35d4 216#ifndef NOEVENODD
e91423bb 217 if( r&01 ) return(0);
bd4e35d4 218#endif
e91423bb
RC
219 if( !istreg(r+1) ) return( 0 );
220 if( busy[r+1] > 1 ) return( 0 );
221 if( busy[r] == 0 && busy[r+1] == 0 ||
11f459b9
DS
222 (busy[r+1] == 0 || (busy[r] & PBUSY)) &&
223 shareit( p, r, n ) ||
e91423bb
RC
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
242shareit( 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
250ushare( 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
267recl2( 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
297int rdebug = 0;
298
299# ifndef RFREE
300rfree( 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");
11f459b9
DS
312 if( busy[r] == PBUSY )
313 busy[r] = 0;
e91423bb 314 if( szty(t) == 2 ){
bd4e35d4
RC
315#ifdef NOEVENODD
316 if( istreg(r) ^ istreg(r+1) ) cerror( "illegal free" );
317#else
e91423bb 318 if( (r&01) || (istreg(r)^istreg(r+1)) ) cerror( "illegal free" );
bd4e35d4 319#endif
e91423bb
RC
320 if( --busy[r+1] < 0 ) cerror( "register overfreed" );
321 }
322 }
323 }
324# endif
325
326# ifndef RBUSY
327rbusy(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 ){
11f459b9
DS
339 if( istreg(r+1) ) {
340 ++busy[r+1];
341 busy[r] |= PBUSY;
342 }
bd4e35d4
RC
343#ifdef NOEVENODD
344 if( istreg(r) ^ istreg(r+1) ) cerror( "illegal register pair freed" );
345#else
e91423bb 346 if( (r&01) || (istreg(r)^istreg(r+1)) ) cerror( "illegal register pair freed" );
bd4e35d4 347#endif
e91423bb
RC
348 }
349 }
350# endif
351
352# ifndef BUG3
353rwprint( 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
386reclaim( 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;
262eaf56 495#if !defined(FORT) && !defined(SPRECC)
e91423bb 496 else if( p->in.type == FLOAT ) p->in.type = DOUBLE;
bd4e35d4 497#endif
e91423bb
RC
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) ) {
11f459b9 514 if( ISBUSY(p->tn.rval) && istreg(p->tn.rval) ) cerror( "potential register overwrite");
e91423bb
RC
515 }
516 else
11f459b9
DS
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)) ) )
e91423bb
RC
519 cerror( "potential register overwrite");
520 }
521
522 }
523
3464f46e 524#ifndef ncopy
e91423bb
RC
525ncopy( 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 }
3464f46e 548#endif
e91423bb
RC
549
550NODE *
551tcopy( 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
582allchk(){
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 }