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