|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)register.c 1.1 86/02/03 Copyr 1985 Sun Micro";
3: #endif
4:
5: /*
6: * Copyright (c) 1985 by Sun Microsystems, Inc.
7: */
8:
9: #include "as.h"
10: #include "c2.h"
11:
12: extern struct ins_bkt *sopcode();
13: extern NODE *insert_label();
14: extern struct oper *newoperand();
15: extern unsigned short make_touchop();
16: int fortranprog = 0;
17: static struct sym_bkt *skyname;
18: #if TRACKSP
19: extern int spoffset; /* track a6-a7 distance */
20: #endif TRACKSP
21:
22: extern struct ins_bkt *moveq, *subql, *addql;
23:
24: #define NREG (FP7REG-D0REG+1)
25: #define CONSRC 0
26: #define CONDST 1
27: struct regcon {
28: struct oper con;
29: subop_t size;
30: } regcon[ NREG ][2];
31:
32: #define NMEM 100 /* totally arbitrary number */
33: static struct memcon {
34: struct oper addr;
35: subop_t size;
36: struct oper value;
37: } memcon[ NMEM ];
38: int nmem = 0; /* max memcon slot taken */
39:
40: int bytesize[] = {
41: 1, /* SUBOP_B */
42: 2, /* SUBOP_W */
43: 4, /* SUBOP_L */
44: 4, /* SUBOP_S */
45: 8, /* SUBOP_D */
46: 12, /* SUBOP_X */
47: 12 /* SUBOP_P */
48: };
49:
50: #define BYTESIZE( s ) (bytesize[ (int)(s)])
51:
52: int
53: dead_areg( p )
54: NODE *p;
55: {
56: register i;
57: regmask m; m = p->rlive;
58: for (i=A6REG-1; i>=A0REG; i--)
59: if (!inmask(i, m ))
60: return i;
61: return -1;
62: }
63:
64: int
65: dead_dreg( p )
66: NODE *p;
67: {
68: register i;
69: regmask m; m = p->rlive;
70: for (i=A0REG-1; i>=D0REG; i--)
71: if (!inmask(i, m ))
72: return i;
73: return -1;
74: }
75:
76:
77: int
78: cancache( o ) register struct oper *o;
79: {
80: /*
81: * currently, the only memory references we can cache are stack
82: * bound variables (and FORTRAN locals)
83: */
84: extern int Xperimental;
85:
86: if (Xperimental)
87: switch (o->type_o){
88: case T_REG:
89: case T_IMMED:
90: case T_PREDEC:
91: case T_POSTINC: return 0;
92: default: return 1; /* slut */
93: }
94: if (o->type_o == T_DEFER || o->type_o == T_DISPL)
95: if (o->reg_o == FPREG || fortranprog && (o->reg_o==A0REG+4 || o->reg_o==A0REG+5))
96: return 1;
97: return 0;
98: }
99:
100: static int
101: istmp( o ) register struct oper *o;
102: {
103: if ((o->type_o==T_DEFER && o->reg_o==FPREG)
104: || (o->type_o==T_DISPL && o->reg_o==FPREG && o->value_o>=0))
105: return 1;
106: return 0;
107: }
108:
109: static int
110: isindir( o ) struct oper *o;
111: {
112: switch (o->type_o){
113: case T_DEFER :
114: if (o->value_o == A6REG) return 0;
115: else return 1;
116: case T_DISPL:
117: if (o->reg_o == A6REG) return 0;
118: else return 1;
119: case T_INDEX:
120: return 1;
121: default:
122: return 0;
123: }
124: }
125:
126: struct oper *
127: get_regcon( regno )
128: int regno;
129: {
130: return ®con[regno][CONSRC].con;
131: }
132:
133: void
134: forgetall()
135: {
136: register regno;
137: for (regno=0; regno< NREG ; regno++){
138: regcon[regno][CONSRC].con.type_o = T_NULL;
139: regcon[regno][CONDST].con.type_o = T_NULL;
140: }
141: nmem = 0;
142: }
143:
144: static void
145: forgetlocals(forgetsky)
146: {
147: register regno;
148: register struct sym_bkt *sk;
149: register struct oper *sp;
150: sk = (forgetsky) ? (struct sym_bkt *)-1 : skyname ;
151: for (regno=0; regno< NREG ; regno++){
152: if ( (sp= ®con[regno][CONSRC].con)->type_o!=T_NULL
153: && sp->type_o!=T_IMMED && sp->sym_o != sk)
154: sp->type_o = T_NULL;
155: regcon[regno][CONDST].con.type_o = T_NULL; /* always */
156: }
157: nmem = 0;
158: }
159:
160: static struct memcon *
161: memfind( o, l, inexact, startaddr, startn )
162: register struct oper *o;
163: subop_t l;
164: int *inexact;
165: struct memcon *startaddr;
166: int *startn;
167: {
168: /*
169: * lookup this operand at this length in the memory/constant
170: * table. Return pointer to the slot where we find it. If
171: * the address-length correspondence is inexact, set *inexact.
172: * Assume cancache(o).
173: * Assume there is no aliasing problem in the memory table.
174: */
175: register i;
176: register struct memcon *mo;
177: register operand_t t=o->type_o;
178: int membegin = 0, memend, conbegin, conend;
179: int r;
180: switch (t){
181: case T_DISPL:
182: r = o->reg_o;
183: /* FALL THROUGH */
184: case T_ABSS:
185: case T_ABSL:
186: case T_NORMAL:
187: membegin = o->value_o;
188: memend = membegin + BYTESIZE(l)-1;
189: break;
190: case T_DEFER:
191: r = o->value_o;
192: memend = membegin + BYTESIZE(l)-1;
193: }
194: for (i= *startn, mo = startaddr; --i >= 0; mo++ )
195: if (mo->addr.type_o != T_NULL && t == mo->addr.type_o ){
196: switch ( t ){
197: case T_ABSS:
198: case T_ABSL:
199: case T_NORMAL:
200: if (o->sym_o != mo->addr.sym_o) continue;
201: conbegin = mo->addr.value_o;
202: goto compare;
203: case T_DISPL:
204: if (mo->addr.reg_o != r) continue;
205: conbegin = mo->addr.value_o;
206: goto compare;
207: case T_DEFER:
208: if (mo->addr.value_o != r) continue;
209: conbegin = 0;
210: compare:
211: conend = conbegin + BYTESIZE(mo->size)-1;
212: if ( membegin< conend && conbegin < memend ){
213: *inexact = ! (membegin==conbegin && l==mo->size);
214: *startn = i;
215: return mo;
216: }
217: }
218: }
219: *startn = 0;
220: return NULL;
221: }
222:
223: struct oper *
224: memlookup( o, l )
225: {
226: /* abstract away the "inexact" problem from memfind() */
227: int inexact;
228: int ntable = nmem;
229: struct memcon *m = &memcon[-1];
230:
231: while ( (m=memfind( o, l, &inexact, m+1, &ntable)) != NULL )
232: if ( !inexact ) return (&m->value);
233: return NULL;
234: }
235:
236: int
237: regfind( o, l, inexact, firstreg, firstpart, part )
238: register struct oper *o;
239: subop_t l;
240: int *inexact;
241: register firstpart;
242: int *part;
243: {
244: /*
245: * lookup this operand at this length in the register
246: * table. Return the register number that matched. If
247: * the address-length correspondence is inexact, set *inexact.
248: * Assume cancache(o) or o->type_o==T_IMMED.
249: */
250: register i,j;
251: register struct regcon *mo;
252: register operand_t t=o->type_o;
253: int membegin , memend, conbegin, conend;
254: int r;
255: switch (t){
256: case T_DISPL:
257: r = o->reg_o;
258: /* FALL THROUGH */
259: case T_ABSS:
260: case T_ABSL:
261: case T_NORMAL:
262: membegin = o->value_o;
263: memend = membegin + BYTESIZE(l);
264: break;
265: case T_DEFER:
266: r = o->value_o;
267: membegin = 0;
268: memend = BYTESIZE(l);
269: }
270: for (i=firstreg ; i<NREG; i++ ){
271: for (j=firstpart; j<=CONDST; j++){
272: mo = & regcon[i][j];
273: if (mo->con.type_o != T_NULL && t == mo->con.type_o ){
274: switch ( t ){
275: case T_IMMED:
276: if ((mo->con.flags_o & O_FLOAT) != (o->flags_o & O_FLOAT)){
277: break;
278: } else if (mo->con.flags_o & O_FLOAT ){
279: if (mo->con.fval_o == o->fval_o){
280: *inexact = 0;
281: return i;
282: }
283: } else if (mo->con.value_o == o->value_o
284: && mo->con.sym_o == o->sym_o ){
285: *inexact = 0;
286: return i;
287: }
288: break;
289: case T_ABSS:
290: case T_ABSL:
291: case T_NORMAL:
292: if (o->sym_o != mo->con.sym_o) continue;
293: conbegin = mo->con.value_o;
294: goto compare;
295: case T_DISPL:
296: conbegin = mo->con.value_o;
297: if (mo->con.reg_o != r) continue;
298: goto compare;
299: case T_DEFER:
300: conbegin = 0;
301: if (mo->con.value_o != r) continue;
302: compare:
303: conend = conbegin + BYTESIZE(mo->size);
304: if ( membegin< conend && conbegin < memend ){
305: *inexact = ! (membegin==conbegin && l==mo->size);
306: *part = j;
307: return i;
308: }
309: }
310: }
311: }
312: firstpart = CONSRC;
313: }
314: return -1;
315: }
316:
317: int
318: reglookup( o, l )
319: struct oper *o;
320: subop_t l;
321: {
322: /* abstract away the "inexact" problem from regfind() */
323: int inexact, part;
324: int r;
325: r = regfind( o, l, &inexact, D0REG, CONSRC, &part );
326: if ( inexact ) return -1;
327: else return r;
328: }
329:
330: static void
331: meminsert( o , v, l )
332: struct oper *o;
333: struct oper *v;
334: subop_t l;
335: {
336: /*
337: * look for a free slot in the memcon table to insert an entry.
338: * try to add at the end, but if the table is complete, then look
339: * for holes. If we still cannot find anything, just forget it.
340: * Assume that our caller already tried for an address match
341: * and would have inserted by easier means if possible.
342: */
343: struct memcon *m;
344: if (nmem < NMEM){
345: /* regular case */
346: m = &memcon[nmem++];
347: } else {
348: /* have to search */
349: for (m= &memcon[0]; m > &memcon[NMEM-1]; m++){
350: if (m->addr.type_o == T_NULL) goto gotone;
351: }
352: return ; /* oh, just forget it */
353: }
354: gotone:
355: m->addr = *o;
356: m->size = l;
357: m->value = *v;
358: }
359:
360: static void
361: put_in_mem_table( o, v, l)
362: struct oper *o;
363: struct oper *v;
364: subop_t l;
365: {
366: /*
367: * put this address/value in the memcon table
368: * deal with aliasing. This is tricky.
369: */
370: int nalias = 0, nexact = 0;
371: int inexact, ntabl = nmem;
372: struct memcon * m;
373: int src, dest, nbytes ;
374: union stuff{ /* KNOWS ABOUT 68000 MEMORY LAYOUT !!! */
375: char bytes[4];
376: short words[2];
377: long longword;
378: } mine, his;
379: int sympart = v->sym_o!=NULL;
380:
381:
382: /* initialize my equivalencing structure */
383: mine.longword = 0L;
384: if (!sympart)
385: switch (l){
386: case SUBOP_B: mine.bytes[0] = v->value_o; break;
387: case SUBOP_W: mine.words[0] = v->value_o; break;
388: default: mine.longword = v->value_o; break;
389: }
390:
391: m = &memcon[-1];
392: while( (m=memfind( o, l, &inexact, m+1, &ntabl )) != NULL ){
393: if (inexact) {
394: /*
395: * either the address or the length don't agree.
396: * fix up the current entry as appropriate, then continue.
397: */
398: if (sympart || m->value.sym_o != NULL){
399: /*
400: * had or will have symbolic part
401: * cannot deal with inexact matches
402: */
403: m->addr.type_o = T_NULL; /* forget it */
404: continue;
405: }
406: /* fill in his equivalencing structure */
407: his.longword = 0L;
408: switch (m->size){
409: case SUBOP_B: his.bytes[0] = m->value.value_o; break;
410: case SUBOP_W: his.words[0] = m->value.value_o; break;
411: default: his.longword = m->value.value_o; break;
412: }
413: if (o->value_o >= m->addr.value_o){
414: /* new starts after old */
415: src = 0;
416: dest = o->value_o - m->addr.value_o;
417: } else {
418: src = m->addr.value_o - o->value_o ;
419: dest = 0;
420: }
421: nbytes = BYTESIZE( l );
422: if (nbytes > BYTESIZE( m->size )-dest )
423: nbytes = BYTESIZE(m->size)-dest;
424: while (nbytes--){
425: his.bytes[dest++] = mine.bytes[src++];
426: }
427: /* shovel back */
428: switch (m->size){
429: case SUBOP_B: m->value.value_o = his.bytes[0]; break;
430: case SUBOP_W: m->value.value_o = his.words[0]; break;
431: default: m->value.value_o = his.longword; break;
432: }
433: nalias++;
434: } else {
435: m->value = *v;
436: nexact++;
437: }
438: }
439: if ((nalias && nexact) || (nalias>4))
440: sys_error("Multiple aliasing in memory table\n");
441: if (nalias==0 && nexact==0){
442: /* new entry -- stick it in. */
443: meminsert( o , v, l );
444: }
445: }
446:
447:
448: static void
449: forgetop( o, l )
450: struct oper *o;
451: subop_t l;
452: {
453: int r, inexact, part;
454: int ntable = nmem;
455: struct memcon *m = &memcon[-1];
456:
457: r = D0REG;
458: part = CONSRC;
459: while( (r = regfind( o, l, &inexact, r, part, &part )) >= D0REG){
460: regcon[ r ][ part ].con.type_o = T_NULL;
461: if ( ++part > CONDST ){
462: r++;
463: part = CONSRC;
464: }
465: }
466:
467: while ( (m=memfind( o, l, &inexact, m+1, &ntable)) != NULL )
468: m->addr.type_o = T_NULL;
469: }
470:
471: static void
472: substitute( p, op, new )
473: NODE *p;
474: struct oper *op, *new;
475: {
476: /*
477: * p is an instruction.
478: * op points to an operand of that instruction.
479: * new points to a (register) operand structure that we want to
480: * substitute for the one op addresses.
481: * Do the substitution and calculate the new properties of p
482: */
483: *op = *new;
484: installinstruct( p, p->instr );
485: p->rlive = compute_normal( p, p->forw->rlive);
486: }
487:
488: static int
489: track_cc( n )
490: NODE *n;
491: {
492: /*
493: * we just moved a constant into a register.
494: * look for subsequent compares/ tests of
495: * the register, followed by jumps, even after cc is kilt
496: */
497: register struct oper *op2, *comperand;
498: struct oper *o;
499: register NODE *p;
500: NODE *target;
501: subop_t so;
502: long v, compval;
503: static struct oper conz = { T_IMMED, 0, 0, NULL, 0, 0, 0 };
504: int didchange = 0;
505:
506: if (n->op==OP_MOVE){
507: op2 = n->ref[1];
508: comperand = n->ref[0];
509: if (comperand->type_o != T_IMMED) return 0;
510: } else {
511: /* CLR */
512: op2 = n->ref[0];
513: comperand = &conz;
514: }
515: if (!deladdr(op2)) return 0;
516: so = n->subop;
517: v = comperand->value_o;
518: for (p = n->forw; p->op!=OP_FIRST ; p = p->forw){
519: switch (p->op){
520: case OP_LABEL:
521: continue;
522: case OP_JUMP:
523: if (p->subop==JALL){
524: if (p->luse == p->back){
525: /* selfloop */
526: break;
527: }
528: /* follow! */
529: p = p->luse->back;
530: continue;
531: }
532: break;
533: case OP_TST:
534: if ( sameops( p->ref[0], op2 ) && p->subop==so){
535: if (comperand->sym_o!=NULL) break;
536: compval = 0;
537: goto regcmp;
538: }
539: break;
540: case OP_CMP:
541: if ( !sameops(p->ref[1], op2 ) ) break;
542: if ( (o=p->ref[0])->type_o != T_IMMED ) break;
543: if ( o->sym_o != comperand->sym_o ) break;
544: compval = o->value_o;
545: regcmp:
546: p=p->forw;
547: if (p->op==OP_JUMP){
548: /* this is it */
549: if (inmask( CCREG, p->luse->rlive ) ||
550: (p->subop!=JALL && inmask( CCREG, p->forw->rlive)))
551: break; /* too hard -- must do the cmp */
552: switch(p->subop){
553: case JEQ: compval = v==compval; break;
554: case JNE: compval = v!=compval; break;
555: case JLE: compval = v<=compval; break;
556: case JGE: compval = v>=compval; break;
557: case JLT: compval = v< compval; break;
558: case JGT: compval = v> compval; break;
559: case JCC: compval = ((unsigned)v) >= ((unsigned)compval); break;
560: case JLS: compval = ((unsigned)v) <= ((unsigned)compval); break;
561: case JHI: compval = ((unsigned)v) > ((unsigned)compval); break;
562: case JCS: compval = ((unsigned)v) < ((unsigned)compval); break;
563: case JALL: compval = 1; break;
564: case JNONE: compval = 0; break;
565: default: goto nojmp;
566: }
567: if (compval) target = p->luse;
568: else{
569: target = p->forw;
570: if (target->op!=OP_LABEL)
571: target = insert_label(target);
572: }
573: cannibalize( p=new(), "jra" );
574: p->op = OP_JUMP;
575: newreference( target, p);
576: p->ruse = p->rset = regmask0;
577: p->rlive = target->rlive;
578: insert( p, n );
579: didchange++;
580: meter.nxjump++;
581: /*
582: * we just created an unconditional jump.
583: * Follow it, just like jumps we find in code.
584: */
585: p = p->luse->back;
586: continue;
587: }
588: }
589: nojmp:
590: break;
591: }
592: return didchange;
593: }
594:
595: static int
596: addrlookup( o )
597: register struct oper *o;
598: {
599: struct oper q;
600: int regname;
601: /*
602: * assume that o points to an index mode, indirect address node.
603: * find the memory address through which we are indirecting
604: * and see if we already have it in an address register. If so, we
605: * can simplify the addressing mode in disindex().
606: */
607: if (o->flags_o&O_PREINDEX) return -1;
608: if (o->flags_o&O_BSUPRESS){
609: q.type_o = T_NORMAL;
610: q.value_o = o->disp_o;
611: q.sym_o = o->sym_o;
612: q.flags_o = o->flags_o&O_COMPLEX;
613: } else {
614: q.type_o = T_DISPL;
615: q.reg_o = o->reg_o;
616: q.value_o = o->disp_o;
617: q.sym_o = o->sym_o;
618: q.flags_o = o->flags_o&O_COMPLEX;
619: if (q.value_o == 0 && q.sym_o == NULL)
620: q.type_o = T_DEFER;
621: }
622: if (!cancache( &q)) return -1;
623: regname = reglookup( &q, SUBOP_L );
624: if (areg(regname)) return regname;
625: return -1;
626: }
627:
628: static void
629: disindex( o, regname )
630: register struct oper *o;
631: int regname;
632: {
633: register flags;
634: /*
635: * o points to an operand of type T_INDEX with the O_INDIRECT flag set.
636: * o is not preindexed. The memory cell through which o indirects is
637: * also contained in the A register named by regname. o can be simplified
638: * because of this: secondary displacement becomes primary displacement,
639: * post indexing becomes pre indexing, and the operand is no longer indirect.
640: * it may be simplified to T_DEFER, T_DISPL, or T_INDEX.
641: */
642: flags = o->flags_o & ~O_INDIRECT;
643: o->reg_o = regname;
644: o->disp_o = o->disp2_o;
645: o->sym_o = o->sym2_o;
646: if (flags&O_COMPLEX2)
647: flags = (flags & ~O_COMPLEX2) | O_COMPLEX;
648: if (flags&O_WDISP2)
649: flags = (flags & ~O_WDISP2)|O_WDISP;
650: else if (flags&O_LDISP2)
651: flags = (flags & ~O_LDISP2)|O_LDISP;
652: if ((flags & O_POSTINDEX) == 0){
653: if (o->disp_o == 0 && o->sym_o == NULL){
654: o->type_o = T_DEFER;
655: } else {
656: o->type_o = T_DISPL;
657: }
658: } else {
659: o->type_o = T_INDEX;
660: flags = (flags& ~O_POSTINDEX)|O_PREINDEX;
661: }
662: o->flags_o = flags;
663: }
664:
665: static void
666: kill_uses( regno )
667: register int regno;
668: {
669: register struct regcon *r;
670: register struct memcon *m, *l;
671: for (r = ®con[0][CONSRC]; r <= ®con[NREG-1][CONDST]; r++)
672: if (r->con.type_o != T_NULL && operand_uses( &r->con, regno )){
673: r->con.type_o = T_NULL;
674: }
675: for (m = &memcon[0], l = &memcon[nmem]; m < l; m++)
676: if (m->addr.type_o != T_NULL && operand_uses( &m->addr, regno)){
677: m->addr.type_o = T_NULL;
678: }
679: }
680:
681: void
682: con_to_reg( regno, o, size )
683: struct oper *o;
684: subop_t size;
685: {
686: struct regcon *r = ®con[regno][CONSRC];
687:
688: regcon[regno][CONDST].con.type_o = T_NULL;
689: r->con = *o;
690: if (dreg(regno))
691: r->size = size;
692: else if (areg(regno))
693: r->size = SUBOP_L;
694: else
695: r->size = SUBOP_X;
696: if (Xperimental)
697: kill_uses( regno );
698: }
699:
700: static int
701: use_moveq( n )
702: register NODE *n;
703: {
704: NODE *p;
705: static struct oper reg = { T_REG, 0, 0, NULL, 0, 0, 0 };
706: /*
707: * doing an immediate operation with a small constant.
708: * we can moveq the constant into a dead D register,
709: * then do operations from that register. As a bonus,
710: * we'll have the value around.
711: * Avoid the case of "movl #3,d3". This will get fixed
712: * in quicken() later on.
713: */
714:
715: if (!long_immediate(n->op)
716: || n->subop != SUBOP_L
717: || (reg.value_o=dead_dreg(n))<0
718: || !operand_ok(n->instr, ®, n->ref[1], 0)
719: || (n->op==OP_MOVE && dreg_addr( n->ref[1] ) )){
720: return 0;
721: }
722: p = new();
723: p->nref = 2;
724: p->ref[0] = newoperand( n->ref[0] );
725: p->ref[1] = newoperand( ® );
726: insert( p, n->back );
727: con_to_reg( reg.value_o, n->ref[0], SUBOP_L );
728: substitute( n, n->ref[0], ® );
729: installinstruct( p, moveq );
730: p->rlive = compute_normal( p, n->rlive );
731: return 1;
732: }
733:
734: static void
735: kill_cached_mem( n, touchop )
736: register NODE *n;
737: register touchop;
738: {
739: register i;
740: /* if a local is modified, invalidate our cached value */
741: for (i=0;i<n->nref;i++){
742: if (touchop&(BW|LW|WW))
743: if (isindir(n->ref[i]))
744: forgetlocals(0);
745: else if ( cancache(n->ref[i]))
746: forgetop( n->ref[i], n->subop );
747: touchop >>= TOUCHWIDTH;
748: }
749: }
750:
751: dumpmem(){
752: int i,j;
753: extern char *rnames[];
754: static char sizes[] = "bwlsdxp";
755: for (i=0; i<NREG; i++){
756: printf("%s : ", rnames[i]);
757: for (j=0; j <= 1; j++)
758: if (regcon[i][j].con.type_o == T_NULL)
759: printf("XXXX ");
760: else{
761: printoperand( ®con[i][j].con );
762: printf("{%c} ", sizes[(int)regcon[i][j].size]);
763: }
764: printf("\n");
765: }
766: printf("\n");
767: for (i=0; i<nmem; i++){
768: if (memcon[i].addr.type_o != T_NULL){
769: printoperand( &memcon[i].addr );
770: printf("{%c}: ", sizes[(int)memcon[i].size]);
771: printoperand( &memcon[i].value );
772: printf("\n");
773: }
774: }
775: }
776:
777: static int
778: substitute_move( n, o, reg, saveop )
779: register NODE *n;
780: struct oper *o, *reg, *saveop;
781: {
782: if (n->instr == moveq)
783: return 0;
784: substitute( n, o, reg );
785: if (saveop->type_o==T_IMMED && cancache(n->ref[1]))
786: put_in_mem_table( n->ref[1], saveop, n->subop );
787: meter.nsaddr++;
788: return 1;
789: }
790:
791: /*
792: * we really should be doing flow analysis here.
793: * lacking that, recognize special case SKY code:
794: * 1: tstw a1@(-4)
795: * bge 1b
796: */
797: # define CHECK_LABEL(n) \
798: if (n->op==OP_LABEL){ \
799: if (!(n->nref==1 && n->luse==n->forw->forw && emptymask(n->forw->rset) && n->forw->forw->op==OP_JUMP)) forgetall(); \
800: continue; }
801:
802: # define IMMED_OR_SKY( o ) \
803: (o->type_o==T_IMMED || (o->type_o==T_NORMAL && o->value_o==0 && o->sym_o==skyname))
804:
805: /* move to self: kill unless cc live */
806: # define DELETE_SELFMOVES( n ) \
807: if ( n->ref[1]->value_o==regno && (!inmask( CCREG, n->forw->rlive) || areg(regno))){ \
808: n = deletenode( n ); meter.redunm++; didchange++; continue; }
809:
810: # define SMALL_IMMED( o ) \
811: ((o)->type_o==T_IMMED && (o)->sym_o==NULL && !((o)->flags_o&O_FLOAT) && (v=(o)->value_o)>=-128 && v<=127)
812:
813: int
814: content()
815: {
816: /*
817: * Follow the flow of control (roughly). Look at loads into
818: * registers. When a constant is loaded we know:
819: * 1) how the CC is set.
820: * 2) a cheap source of that constant.
821: * Special case if the same register is reloaded with that constant.
822: * SPECIAL HACK: Assume that the contents of the global var named
823: * "__skybase" are constant!!
824: */
825: register NODE *n;
826: register v, regno;
827: register struct oper *o;
828: struct oper *op2, *op3;
829: int didchange=0;
830: int local_read, dest_reg;
831: int i;
832: struct oper saveop;
833:
834:
835: static struct oper reg = { T_REG, 0, 0, NULL, 0, 0, 0 };
836:
837: /* initialize constant table to empty. Find __skybase */
838: forgetall();
839: if (skyname==NULL) skyname = lookup("__skybase");
840: #if TRACKSP
841: spoffset=0;
842: #endif TRACKSP
843:
844: for (n=first.forw; n!=&first; n=n->forw){
845: CHECK_LABEL(n);
846: if (!ISINSTRUC(n->op)) continue;
847: dest_reg = -1;
848: if (n->nref){
849: v = make_touchop( n, n->instr->touchop_i);
850: kill_cached_mem( n, v );
851: o = n->ref[0];
852: local_read = cancache(o) && (v&(BW|LW|WW))==0;
853: if (IMMED_OR_SKY( o ) || local_read ){
854: /* do lookup -- do we already have it */
855: regno = reglookup( o, n->subop );
856: if (regno>=0 ){
857: /* try to substitute */
858: reg.value_o = regno;
859: saveop = *o;
860: if (operand_ok(n->instr, ®, n->ref[1], 0)){
861: if (n->op==OP_MOVE){
862: didchange += substitute_move( n, o, ®, &saveop );
863: if ( datareg_addr( n->ref[1] ) ){
864: DELETE_SELFMOVES( n );
865: con_to_reg( n->ref[1]->value_o, &saveop, n->subop );
866: didchange += track_cc(n);
867: dest_reg = n->ref[1]->value_o;
868: }
869: } else {
870: /* not a move -- don't think, just do it */
871: substitute( n, o, ® );
872: meter.nsaddr++;
873: didchange++;
874: }
875: }
876: }
877: if (n->nref==2 && SMALL_IMMED( o )){
878: didchange+= use_moveq( n );
879: }
880: if (local_read && (op2=memlookup(o, n->subop))!= NULL){
881: /*
882: * this is a local that contains an immediate at this
883: * time. substitute the immediate value for the mem-op,
884: * if we may.
885: */
886: if (operand_ok(n->instr, op2, n->ref[1], 0)){
887: substitute( n, o, op2 );
888: meter.nsaddr++;
889: didchange++;
890: }
891: }
892: if (n->op==OP_MOVE){
893: op2 = n->ref[1];
894: if (datareg_addr(op2)){
895: /* move to a register */
896: con_to_reg( op2->value_o, o, n->subop );
897: } else if (cancache( op2)){
898: if(o->type_o==T_IMMED )
899: put_in_mem_table( op2, o, n->subop );
900: else if (o->type_o==T_REG && datareg( regno=o->value_o )
901: && (op3= ®con[regno][CONSRC].con)->type_o == T_IMMED)
902: put_in_mem_table( op2, op3, n->subop );
903: }
904: /*
905: * we may have moved a constant into a register.
906: * look for subsequent compares/ tests of
907: * the register, followed by jumps, even after cc is kilt
908: */
909: didchange += track_cc(n);
910: if (op2->type_o == T_REG)
911: dest_reg = op2->value_o;
912: }
913: } else if (n->op==OP_MOVE && n->ref[0]->type_o==T_REG
914: && cancache( n->ref[1] )){
915: /* movl d0,a6@(4) ; movl a6@(4),d1 */
916: regcon[v=n->ref[0]->value_o][CONDST].con = *(n->ref[1]);
917: regcon[v][CONDST].size = n->subop;
918: dest_reg = v;
919: } else if (n->op==OP_CALL){
920: forgetlocals(1);
921: } else if (n->op==OP_CLR){
922: didchange += track_cc(n);
923: if (n->ref[0]->type_o == T_REG)
924: dest_reg = n->ref[0]->value_o;
925: }
926: /*
927: * try to avoid indirecting through things
928: * of which we already know the value
929: */
930: for (i=n->nref, v=0; v<i; v++){
931: if ((o = n->ref[v])->type_o == T_INDEX && (o->flags_o&O_INDIRECT))
932: if ((regno = addrlookup( o )) >= 0 ){
933: disindex( o, regno );
934: substitute( n, o, o );
935: meter.nsaddr++;
936: }
937: }
938: }
939: if (!emptymask(n->rset) ){
940: /* kill a constant value */
941: register sets = n->rset.da;
942: while (sets){
943: v = ffs(sets)-1;
944: sets ^= 1<<v;
945: if (v<24)
946: v /=3;
947: else
948: v -=(24-A0REG);
949: if ( v == dest_reg )
950: continue;
951: regcon[v][CONSRC].con.type_o = T_NULL;
952: regcon[v][CONDST].con.type_o = T_NULL;
953: if (Xperimental)
954: kill_uses( v );
955: #ifdef TRACKSP
956: if (v==SPREG){
957: /* try to keep track of distance from a6 to a7 */
958: track_sp( n );
959: }
960: #endif TRACKSP
961: }
962: sets = n->rset.f & 0377; /* registers only, no cc */
963: while (sets){
964: v = ffs(sets)-1;
965: sets ^= 1<<v;
966: v += FP0REG;
967: if ( v == dest_reg )
968: continue;
969: regcon[v][CONSRC].con.type_o = T_NULL;
970: regcon[v][CONDST].con.type_o = T_NULL;
971: }
972: }
973: }
974: return didchange;
975: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.