Commit | Line | Data |
---|---|---|
262eaf56 | 1 | #ifndef lint |
b401968b | 2 | static char *sccsid ="@(#)allo.c 4.10 (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; | |
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 | ||
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 | ||
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 | ||
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"); | |
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 | |
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 ){ | |
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 | |
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; | |
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 |
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 | } | |
3464f46e | 548 | #endif |
e91423bb RC |
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 | } |