|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)instruction.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 char *malloc();
13: struct oper *newoperand();
14: struct oper operands[OPERANDS_MAX];
15: int numops;
16: void new_csect(), save_stabs();
17:
18: NODE first = { OP_FIRST, SUBOP_Z, &first, &first };
19:
20: #define nexti( p ) { do p=p->forw; while( ISDIRECTIVE(p->op) ); }
21: #define previ( p ) { do p=p->back; while( ISDIRECTIVE(p->op) ); }
22:
23: extern int bytesize[];
24: #define BYTESIZE( s ) (bytesize[ (int)(s)])
25:
26: /* does this branch read the c or v bit of the condition code? */
27: char read_cc_cv[]={ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 };
28: static struct ins_bkt * moveq = NULL;
29: static err_code operand_error = E_NOERROR;
30:
31: extern struct ins_bkt *tstw, *tstl;
32: extern int ext_instruction_set;
33:
34: static int
35: numeric_immediate( op )
36: struct oper *op;
37: {
38: if (op->type_o != T_IMMED || op->sym_o != NULL )
39: return 0;
40: return 1;
41: }
42:
43: static int
44: immediate_value( op, value )
45: struct oper *op;
46: int value;
47: {
48: if (op->type_o != T_IMMED || op->sym_o != NULL || op->flags_o&O_FLOAT || op->value_o != value)
49: return 0;
50: return 1;
51: }
52:
53: instruction( ip )
54: struct ins_bkt *ip;
55: {
56: register NODE *np;
57: register i;
58:
59: if (ip->noper_i != numops && ip->noper_i <= OPERANDS_MAX){
60: /* shifts are a special case...*/
61: if ((ip->touchop_i&TOUCHMASK) == SPEC(2) || numops==1 || ip->subop_i==SUBOP_W)
62: i = 0;
63: else if ( (ip->touchop_i&TOUCH1(TOUCHMASK)) == TOUCH1(SPEC(7)) && numops==0 )
64: /* so is rts */
65: i = 0;
66: else
67: prog_error(E_NUMOPS);
68: }
69: if ( ISINSTRUC(ip->op_i) ){
70: if (cur_csect_name != C_TEXT){
71: /* non-text is not delt with -- echo it out directly */
72: putinstr( ip );
73: /* instruction in data space -- punt addressing */
74: bc = 0x80000000; /* magic, negative number */
75: return;
76: }
77: switch (numops){
78: case 0: i = 1; break;
79: case 1: i = operand_ok( ip, &operands[0], (struct oper *)NULL, (struct oper *)NULL ); break;
80: case 2: i = operand_ok( ip, &operands[0], &operands[1], (struct oper *)NULL );break;
81: case 3: i = operand_ok( ip, &operands[0], &operands[1], &operands[2] );break;
82: }
83: if (!i)
84: prog_warning(operand_error);
85: } else {
86: switch ( ip->op_i ){
87: case OP_TEXT: cur_csect_name = C_TEXT; new_csect(); return;
88: case OP_DATA: cur_csect_name = C_DATA; new_csect(); break;
89: case OP_DATA1: cur_csect_name = C_DATA1; new_csect(); break;
90: case OP_DATA2: cur_csect_name = C_DATA2; new_csect(); break;
91: case OP_BSS: cur_csect_name = C_BSS; new_csect(); break;
92: case OP_ASCII:
93: case OP_ASCIZ: bc += ascii(cur_csect_name)+(ip->op_i==OP_ASCIZ); break;
94: case OP_STABS: save_stabs(cur_csect_name); break;
95: default: bc += pseudo_size( ip ); break;
96: }
97: if (cur_csect_name != C_TEXT){
98: /* non-text is not delt with -- echo it out directly */
99: putinstr( ip );
100: return;
101: }
102: }
103: np = new();
104: np->nref = numops;
105: for (i=0; i<numops; i++){
106: np->ref[i] = newoperand( &operands[i] );
107: }
108: installinstruct( np, ip );
109: addnode( np );
110: }
111:
112: unsigned short
113: make_touchop( np, to )
114: NODE *np;
115: unsigned short to;
116: {
117: /* ripped off from installinstruct, but not yet used by it */
118: int i;
119: unsigned short tfield, tretval;
120: struct oper *o;
121:
122: tretval = 0;
123: for (i=np->nref-1; i >= 0; i--){
124: o = np->ref[i];
125: switch(tfield = (to>>(TOUCHWIDTH*i))&TOUCHMASK){
126: case SPEC(0): /* bset, bclr, bcng */
127: if (o->type_o==T_REG){
128: tfield = touchselect(np->ref[0], BR+BW, WR+WW, LR+LW);
129: } else{
130: tfield = (BR+BW);
131: }
132: break;
133: case SPEC(1): /* btst */
134: if (o->type_o==T_REG){
135: tfield = touchselect(np->ref[0], BR, WR, LR);
136: } else {
137: tfield = (BR);
138: }
139: break;
140: case SPEC(2): /* shifts */
141: if (np->nref==1)
142: tfield = (WR+WW);
143: else
144: tfield = (WR);
145: break;
146: case SPEC(3): /* pea, link, unlk */
147: tfield = 0;
148: break;
149: case SPEC(4): /* bfset bfins */
150: tfield = (LW);
151: break;
152: case SPEC(5): /* bfext? bftst */
153: tfield = (LR);
154: break;
155: case SPEC(6): /* mulsl, divsll */
156: tfield = (LR+LW);
157: break;
158: }
159: tretval <<= TOUCHWIDTH;
160: tretval |= tfield;
161: }
162: return tretval;
163: }
164:
165: static int
166: touchselect( operand, b, w, l )
167: struct oper *operand;
168: {
169: register v;
170: if (!numeric_immediate( operand )) return l;
171: v = operand->value_o;
172: if ( v >=0 && v < 16 )
173: if (v < 8 ) return b;
174: else return w;
175: else return l;
176: }
177:
178: static subop_t
179: subopselect( touchword )
180: {
181: switch (touchword&TOUCHMASK) {
182: case BR:
183: case BW:
184: case BR+BW:
185: return SUBOP_B;
186: case WR:
187: case WW:
188: case WR+WW:
189: return SUBOP_W;
190: }
191: return SUBOP_L;
192: }
193:
194: void
195: cannibalize( np, sp )
196: NODE *np;
197: char *sp;
198: {
199: installinstruct( np, sopcode(sp) );
200: }
201:
202: installinstruct( np, ip )
203: register NODE *np;
204: register struct ins_bkt *ip;
205: {
206: register struct oper *o;
207: register unsigned short touchop;
208: regmask smask, umask;
209: register i;
210: static int regnames[] = {
211: D0REG, D0REG+1,
212: A0REG, A0REG+1,
213: FP0REG, FP0REG+1
214: };
215:
216: np->instr = ip;
217: np->op = ip->op_i;
218: np->subop = ip->subop_i;
219: umask = MAKERMASK( CCREG, (ip->cc_i&CCR)?BR:0);
220: smask = MAKEWMASK( CCREG, (ip->cc_i&CCX)?BW:0);
221: if (ip->cc_i&FCCR) umask = addmask( umask, MAKERMASK( FPCCREG, BR));
222: if (ip->cc_i&FCC) smask = addmask( smask, MAKEWMASK( FPCCREG, BW));
223: switch (np->op){
224: case OP_CALL: /* writes d0,d1,a0,a1 except with exceptions */
225: o = np->ref[0];
226: if ( o->type_o == T_NORMAL && o->value_o==0 ){
227: struct sym_bkt *s;
228: s = o->sym_o;
229: if (s->attr_s & S_CRT){
230: /*
231: * c- runtime support routine -- some of these may touch
232: * the floating point registers, but as of 3.0 they are
233: * not called by programs that use them.
234: */
235: for (i=0; i<4; i++ ){
236: umask = addmask( umask, MAKERMASK( regnames[i], s->builtin_s[i] ));
237: smask = addmask( smask, MAKEWMASK( regnames[i], s->builtin_s[i] ));
238: }
239: break;
240: }
241: }
242: /* normal routine -- write d0,d1,a0,a1,fp0,fp1 */
243: for (i=0; i<6; i++){
244: smask = addmask(smask,MAKEWMASK( regnames[i], LW ));
245: }
246: break;
247: case OP_EXIT: /* reads some registers, writes all */
248: umask = addmask(exitmask, regmask_nontemp);
249: smask = regmask_all;
250: break;
251: }
252: touchop = ip->touchop_i;
253: for (i=0; i<np->nref; i++, touchop >>= TOUCHWIDTH ){
254: o = np->ref[i];
255: switch(touchop&TOUCHMASK){
256: case SPEC(0): /* bset, bclr, bcng */
257: if (o->type_o==T_REG){
258: touchop = (touchop&~TOUCHMASK)|touchselect(np->ref[0], BR+BW, WR+WW, LR+LW);
259: } else{
260: touchop = (touchop&~TOUCHMASK)|(BR+BW);
261: }
262: np->subop = subopselect( touchop );
263: break;
264: case SPEC(1): /* btst */
265: if (o->type_o==T_REG){
266: touchop = (touchop&~TOUCHMASK)|touchselect(np->ref[0], BR, WR, LR);
267: } else {
268: touchop = (touchop&~TOUCHMASK)|(BR);
269: }
270: np->subop = subopselect( touchop );
271: break;
272: case SPEC(2): /* shifts */
273: if (np->nref==1)
274: touchop = (touchop&~TOUCHMASK)|(WR+WW);
275: else
276: touchop = (touchop&~TOUCHMASK)|(WR);
277: break;
278: case SPEC(3): /* pea, link, unlk */
279: smask = MAKEWMASK( SPREG, LW );
280: /* umask = MAKERMASK( SPREG, LR ); */
281: /* the unlk instruction does not read sp before setting it */
282: umask = (ip->op_i == OP_UNLK) ? regmask0 : smask;
283: touchop = LR+LW; /* link and unlk use this */
284: break;
285: case SPEC(4): /* bfset bfins */
286: touchop = (touchop&~TOUCHMASK)|(LW);
287: break;
288: case SPEC(5): /* bfext? bftst */
289: touchop = (touchop&~TOUCHMASK)|(LR);
290: break;
291: case SPEC(6): /* mulsl, divsll */
292: if (o->type_o != T_REGPAIR){
293: touchop = (touchop&~TOUCHMASK)|(LR+LW);
294: break;
295: } else {
296: /* 1st register of pair written only */
297: smask = addmask( smask, MAKEWMASK( o->value_o, LW ));
298: /* 2nd register of pair read+written */
299: umask = addmask( umask, MAKERMASK( o->reg_o, LR ));
300: smask = addmask( smask, MAKEWMASK( o->reg_o, LW ));
301: continue;
302: }
303: }
304: switch (o->type_o ){
305: case T_REGPAIR:
306: umask = addmask( umask, MAKERMASK( o->reg_o, touchop ));
307: smask = addmask( smask, MAKEWMASK( o->reg_o, touchop ));
308: /* FALL THROUGH */
309: case T_REG:
310: if (dareg( o->value_o ) || srreg( o->value_o) || freg( o->value_o)){
311: umask = addmask( umask, MAKERMASK( o->value_o, touchop ));
312: smask = addmask( smask, MAKEWMASK( o->value_o, touchop ));
313: }
314: break;
315: case T_POSTINC:
316: case T_PREDEC:
317: smask = addmask( smask, MAKEWMASK( o->value_o, LW ));
318: /* FALL THROUGH */
319: case T_DEFER:
320: umask = addmask( umask, MAKERMASK( o->value_o, LR ));
321: break;
322: case T_DISPL:
323: umask = addmask( umask, MAKERMASK( o->reg_o, LR ));
324: break;
325: case T_INDEX:
326: if (! (o->flags_o & O_BSUPRESS))
327: umask = addmask( umask, MAKERMASK( o->reg_o, LR ));
328: if ( o->flags_o & (O_PREINDEX|O_POSTINDEX))
329: umask = addmask( umask, MAKERMASK( o->value_o,
330: o->flags_o&O_LINDEX ? LR : WR ));
331: break;
332: }
333: if (o->flags_o & O_BFLD){
334: if (o->flags_o & O_BFOREG)
335: umask = addmask( umask, MAKERMASK( o->bfoffset_o, BR ));
336: if (o->flags_o & O_BFWREG)
337: umask = addmask( umask, MAKERMASK( o->bfwidth_o, BR ));
338: }
339: }
340: np->ruse = umask;
341: np->rset = smask;
342: }
343:
344: static unsigned
345: op_to_bits( op )
346: register struct oper *op;
347: {
348: /* return the address-mode bits for operand *op */
349: register unsigned s;
350: static unsigned bits[] = {
351: 0,
352: AM_REG, AM_DEFER, AM_POSTINC, AM_PREDEC, AM_DISPL,
353: AM_INDEX, AM_ABSS, AM_ABSL, AM_IMMED, AM_NORMAL,
354: AM_REGPAIR, -1, -1
355: };
356: switch ( s = bits[(int)op->type_o]){
357: case AM_REG:
358: s = reg_access[op->value_o]; break;
359: case AM_DISPL:
360: if (op->reg_o == PCREG) s = AM_PCDISPL; break;
361: case AM_INDEX:
362: if (op->reg_o == PCREG) s = AM_PCINDEX; break;
363: }
364: return s;
365: }
366:
367: int
368: operand_ok( ip, op1, op2, op3 )
369: struct ins_bkt *ip;
370: struct oper *op1, *op2, *op3;
371: {
372: /*
373: * this routine answers the eternal question:
374: * are operands *op1 and *op2 ok to use as the operands of instruction *ip?
375: * it does it by looking at the optype_i bit fields in the instruction
376: * description.
377: */
378: register i;
379: register unsigned opbits1, opbits2, opbits3;
380: register noperands = ip->noper_i;
381:
382: opbits1 = op_to_bits( op1 );
383: if (op2)
384: opbits2 = op_to_bits( op2 );
385: else
386: opbits2 = 0;
387: if (op3)
388: opbits3 = op_to_bits( op3 );
389: else
390: opbits3 = 0;
391: switch (ip->touchop_i&TOUCH2(TOUCHMASK)){
392: case TOUCH2(SPEC(0)):
393: case TOUCH2(SPEC(1)):
394: /* special hackery for bit ops */
395: if (opbits1 == AM_IMMED){
396: i = op1->value_o;
397: if (op1->sym_o) { operand_error = E_CONSTANT; return 0;}
398: if (opbits2 == AM_DREG){
399: if (i < 0 || i > 31 ) { operand_error = E_CONSTANT; return 0;}
400: } else
401: if (i < 0 || i > 7 ) { operand_error = E_CONSTANT; return 0;}
402: }
403: break;
404: }
405: switch (ip->touchop_i&TOUCH1(TOUCHMASK)){
406: case TOUCH1(SPEC(2)):
407: /* special hackery for shifts */
408: if (opbits1 == AM_IMMED && ((i=op1->value_o)<1 || i>8 || op1->sym_o)){
409: operand_error = E_CONSTANT;
410: return 0;
411: }
412: break;
413: }
414: switch (noperands){
415: case 0: return 1;
416: case 1:
417: if ((ip == tstw || ip == tstl) && areg_addr(op1)
418: && !ext_instruction_set)
419: break;
420: for (i=0; i<N_OPTYPES; i+=1)
421: if ((opbits1&ip->optype_i[i])==opbits1) return 1;
422: break;
423: case 2:
424: for (i=0; i<N_OPTYPES; i+=2)
425: if (((opbits1&ip->optype_i[i])==opbits1) && ((opbits2&ip->optype_i[i+1])==opbits2) ) return 1;
426: break;
427: case 3:
428: for (i=0; i<N_OPTYPES; i+=3)
429: if (((opbits1&ip->optype_i[i])==opbits1) && ((opbits2&ip->optype_i[i+1])==opbits2) && ((opbits3&ip->optype_i[i+2])==opbits3) ) return 1;
430: break;
431: }
432: operand_error = E_OPERAND;
433: return 0;
434: }
435: onceonly()
436: {
437: /*
438: * A collection of context-free, compiler specific hacks
439: * we need only do once, as circumstances will not change
440: * during the course of our work. These include:
441: * - moveml's: deleting those that do nothing, replacing the degenerate
442: * cases with movl's.
443: * - link a6,#0 ... addl #X,sp: combine if X in range of the link.
444: * - pea 0 : becomes clrl sp@-
445: * - cmpX #0,Y : becomes tstX Y, for Y not an address register.
446: * - movX #0,Y : becomes clrX Y, for Y not a register, or
447: * moveq #0,Y, for type long data register, or
448: * subl Y,Y for Y an address register.
449: */
450:
451: register NODE * n;
452: register NODE *f;
453: register i, v;
454: register struct oper *o;
455: int regno;
456: extern NODE *deletenode();
457:
458: for (n=first.forw; n != &first; n=n->forw){
459: switch( n->op){
460: case OP_MOVEM:
461: if (n->subop==SUBOP_L || n->subop==SUBOP_X) {
462: /* i get the index of the immediate operand */
463: i = (n->ref[1]->type_o==T_IMMED);
464: /* o get the pointer to the immediate operand */
465: o = n->ref[i];
466: if (o->sym_o || o->type_o!=T_IMMED) continue;
467: /* v gets the register mask -- how many bits set here? */
468: switch( cntbits( v=o->value_o ) ){
469: case 0:
470: if (deladdr(n->ref[1-i])){
471: n = deletenode( n );
472: meter.nrmtfr++;
473: }
474: break;
475: case 1: /* replace with a moveml, same "other" operand */
476: v = ffs(v); /* find first bit set -- "1" on littleend */
477: /* if mode of "other" operand is predecrement, bits work backwards */
478: o->type_o=T_REG;
479: if (n->subop==SUBOP_L){
480: if (n->ref[1-i]->type_o==T_PREDEC)
481: v = 16 - v;
482: o->value_o = v-1;
483: cannibalize( n, "movl" );
484: }else{
485: o->value_o = FP0REG + 8 - v;
486: cannibalize( n, "fmovex" );
487: }
488: meter.nmmtmo++;
489: break;
490: }
491: }
492: continue;
493: case OP_LINK:
494: /* make sure we understand this instruction */
495: o = n->ref[1];
496: if (!numeric_immediate(o)) continue;
497: v = o->value_o;
498: /* see if next instruction is of form: addl #nnn,sp */
499: f = n;
500: nexti(f);
501: if (f->op!=OP_ADD) continue;
502: o = f->ref[0];
503: if (!numeric_immediate(o)) continue;
504: v += o->value_o;
505: o = f->ref[1];
506: if (!(o->type_o==T_REG && o->value_o==SPREG)) continue;
507: /* make sure sum of immediates is in range */
508: if (v <-32768 || v > 32767) continue;
509: /* got it! */
510: n->ref[1]->value_o = v;
511: n = deletenode( f );
512: meter.namwl++;
513: continue;
514: case OP_PEA:
515: /* if operand is a "normal" 0, change the opcode */
516: o = n->ref[0];
517: if (o->type_o==T_NORMAL && o->sym_o==NULL && o->value_o==0){
518: o->type_o = T_PREDEC;
519: o->value_o = SPREG;
520: cannibalize( n, "clrl" );
521: meter.nmtoc++;
522: }
523: continue;
524: case OP_CMP:
525: /* compares to zero are degenerate */
526: o = n->ref[0];
527: if (immediate_value( o, 0)){
528: if (areg_addr(n->ref[1])){
529: /* "A" register
530: * may be able to do something about this later on,
531: * after we gain some context.
532: */
533: continue;
534: } else {
535: n->ref[0] = n->ref[1];
536: n->nref--;
537: freeoperand( o );
538: cannibalize( n, (n->subop==SUBOP_L)?"tstl"
539: :(n->subop==SUBOP_W)?"tstw"
540: : "tstb");
541: meter.nctot++;
542: }
543: }
544: continue;
545: case OP_MOVE:
546: /* moves of zero can often be simplified */
547: o = n->ref[0];
548: if (immediate_value(o, 0)){
549: switch (n->ref[1]->type_o){
550: case T_REG:
551: v = n->ref[1]->value_o;
552: if (dreg(v) ){
553: if (n->subop != SUBOP_L) goto mkclr;
554: /* use moveq */
555: cannibalize( n, "moveq" );
556: meter.nwmov++;
557: } else if (areg(v)){
558: /* subtract from self */
559: o->type_o = T_REG;
560: o->value_o = v;
561: cannibalize( n , "subl" );
562: meter.nmtos++;
563: }
564: break;
565: default:
566: mkclr:
567: /* use the clear instruction */
568: n->ref[0] = n->ref[1];
569: n->nref--;
570: freeoperand( o );
571: cannibalize( n, (n->subop==SUBOP_L)?"clrl"
572: :(n->subop==SUBOP_W)?"clrw"
573: : "clrb");
574: meter.nmtoc++;
575: break;
576: }
577: }
578: continue;
579: case OP_AND:
580: /*
581: * if this looks like a mask of the lower bits,
582: * then it kill the rest of the register without
583: * reading it: i.e.
584: * andl #255,d0
585: * only uses the low-order 8bits anyway, so we can
586: * change our usage mask.
587: */
588: if (numeric_immediate(o=n->ref[0])){
589: v = o->value_o;
590: if ((o=n->ref[1])->type_o==T_REG){
591: regno = o->value_o;
592: if ( v>= 0 && v <= 0xffff && dreg(regno) ){
593: n->ruse = submask( n->ruse, MAKERMASK( regno, LR ));
594: n->ruse = addmask( n->ruse, MAKERMASK( regno, v<=0xff ? BR : WR ));
595: n->rlive = compute_normal( n, n->forw->rlive);
596: }
597: }
598: }
599: continue;
600: }
601: }
602: }
603:
604: int
605: addr_delt( old, new )
606: subop_t old, new;
607: {
608: #define NO_WAY -32768
609: /*
610: * if an operand was addressed using subop "old", and will be
611: * addressed by "new", what is the address increment?
612: */
613: static char deltsize[7][7] = {
614: /* new is ... B W L S D X P */
615: /* old is ... */
616: /* B */ { 0, -1, -3, -3, -7, -11, -11 },
617: /* W */ { 1, 0, -2, -2, -6, -10, -10 },
618: /* L */ { 3, 2, 0, 0, -4, -8, -8 },
619: /* S */ { 3, 2, 0, 0, -4, -8, -8 },
620: /* D */ { 7, 6, 4, 4, 0, -4, -4 },
621: /* X */ { 11, 10, 8, 8, 4, 0, 0 },
622: /* P */ { 11, 10, 8, 8, 4, 0, 0 },
623: };
624:
625: switch ( old ){
626: case SUBOP_B:
627: case SUBOP_W:
628: case SUBOP_L:
629: break;
630: default: return NO_WAY;
631: }
632: switch ( new ){
633: case SUBOP_B:
634: case SUBOP_W:
635: case SUBOP_L:
636: break;
637: default: return NO_WAY;
638: }
639: return deltsize[(int)old - (int)SUBOP_B][(int)new - (int)SUBOP_B];
640: #undef NO_WAY
641: }
642:
643: int
644: long_immediate( opcode )
645: opcode_t opcode;
646: {
647: /*
648: * list some of the opcodes in which immediate operands are long (addl),
649: * as opposed to those in which this is not the case (asrl).
650: */
651: switch ( opcode ){
652: case OP_ADD:
653: case OP_AND:
654: case OP_SUB:
655: case OP_MOVE:
656: case OP_CMP:
657: case OP_OR:
658: return 1;
659: }
660: return 0;
661: }
662:
663: static int
664: exception( p, pnext )
665: NODE *p, *pnext;
666: {
667: if (p->instr==moveq && long_immediate(pnext->op ))
668: return 1; /* don't elide moveq's */
669: if (pnext->op == OP_BOP){
670: if (!numeric_immediate(pnext->ref[0])) return 1; /* be careful here */
671: if (p->subop!=SUBOP_B)
672: if (p->ref[0]->type_o != T_REG && !cancache(p->ref[0]))
673: return 1; /* don't mess up memory references */
674: }
675: return 0;
676: }
677:
678: /*
679: * have the pattern
680: * movX Y,d0
681: * opZ d0,...
682: * where the second instruction only reads the operand, and we could
683: * have done
684: * opZ Y',...
685: * instead.
686: */
687: static NODE *
688: elide_move( p, pnext, opset )
689: register NODE *p;
690: register NODE *pnext;
691: int opset;
692: {
693: register i;
694:
695: for ( i=0 ; i<pnext->nref; i++)
696: if (opset & (1<<i))
697: *pnext->ref[i] = *p->ref[0];
698: installinstruct( pnext, pnext->instr );
699: pnext->rlive = compute_normal(pnext,pnext->forw->rlive);
700: meter.redunm++;
701: return( deletenode( p ));
702: }
703:
704: /*
705: * look for dbra-equivalent sequence. The compiler
706: * already makes some assumptions about 16-bit reachability
707: * (word offsets in case-jumps), so we don't worry about that
708: * here. We're going to be rather strict about what we recognize,
709: * because we don't have the information to determine whether,
710: * for instance, an index begins positive, in which case we
711: * could recognize the condition " > 0 " as being equivalent
712: * to " != -1". Someday, perhaps.
713: * We will also be just a little adventuresome and try to
714: * handle the "long dbra" case, too. (Long is the data type,
715: * not the jump offset!)
716: */
717: static NODE *
718: make_dbra( p, didchange )
719: register NODE *p;
720: int *didchange;
721: {
722: register NODE *pnext;
723: NODE *p3;
724: register struct oper *o;
725: subop_t length;
726: static struct oper immed = { T_IMMED, 0,0,0, NULL, NULL, NULL, 0 };
727:
728: /* recognize subqZ #1,dX */
729: length = p->subop;
730: if (length == SUBOP_B) return p;
731: if ( !immediate_value((o=p->ref[0]), 1))
732: return p;
733: o=p->ref[1];
734: if (!dreg_addr(o)) return p;
735: pnext = p->forw;
736: switch (pnext->op){
737: case OP_CMP:
738: /* recognize cmpZ #-1,dX */
739: if (pnext->subop != length ||
740: !immediate_value( pnext->ref[0], -1) ||
741: !sameops( o, pnext->ref[1]))
742: return p;
743: /* recognize jne Y */
744: pnext = pnext->forw;
745: if (pnext->op != OP_JUMP || pnext->subop != JNE ) return p;
746: if (inmask( CCREG, pnext->forw->rlive) || inmask( CCREG, pnext->luse->rlive)) return p;
747: /*
748: * found the pattern:
749: * subqX #1,dY <== p
750: * cmpX #-1,dY
751: * jne Z <== pnext
752: */
753: /* save one copy of the operand register, delete much */
754: p->nref --;
755: p = deletenode( p)->forw;
756: p = deletenode( p)->forw;
757: /* p == pnext */
758: break;
759: case OP_TST:
760: /* try a different pattern */
761: p3 = p->back;
762: if (p3->op != OP_MOVE || p3->subop != length ||
763: !sameops( p3->ref[0], o) || !dreg_addr( p3->ref[1]))
764: return p;
765: if (pnext->subop != length || !sameops( p3->ref[1], pnext->ref[0]))
766: return p;
767: /* recognize jne Y */
768: pnext = pnext->forw;
769: if (pnext->op != OP_JUMP || pnext->subop != JNE ) return p;
770: if (inmask( CCREG, pnext->forw->rlive) || inmask( CCREG, pnext->luse->rlive)) return p;
771: if (inmask( p3->ref[1]->value_o, pnext->rlive )) return p;
772: /*
773: * found the pattern:
774: * movX dY,dW <== p3
775: * subqX #1,dY <== p
776: * tstX dW
777: * jne Y <== pnext
778: */
779: /* save one copy of the operand register, delete much */
780: (void) deletenode( p3 );
781: p->nref --;
782: p = deletenode( p)->forw;
783: p = deletenode( p)->forw;
784: /* p == pnext */
785: break;
786: default:
787: return p;
788: }
789: /*
790: * now: two cases here: simple and long:
791: *
792: * simple case: move operand o to the jump instruction;
793: * cannibalize it as a dbra;
794: *
795: * long case: as simple case, then add the long-dbra
796: * tail: clrw , cmpl, jcc.
797: */
798: pnext->ref[0] = o;
799: pnext->nref++;
800: cannibalize( pnext, "dbra" );
801: pnext->op = OP_DJMP;
802: if (length == SUBOP_L){
803: /* add clrw dX instruction after that */
804: pnext = new();
805: pnext->nref = 1;
806: pnext->ref[0] = newoperand( o );
807: insert( pnext, p);
808: cannibalize( pnext, "clrw" );
809: /* add subql #1 instruction next */
810: p3 = pnext;
811: pnext = new();
812: pnext->nref = 2;
813: immed.value_o = 1;
814: pnext->ref[0] = newoperand( &immed );
815: pnext->ref[1] = newoperand( o );
816: insert( pnext, p3);
817: cannibalize( pnext, "subql" );
818: /* finally, add jcc Y instruction */
819: p3 = pnext;
820: pnext = new();
821: insert( pnext, p3);
822: newreference( p->luse, pnext );
823: cannibalize( pnext, "jcc" );
824: pnext->op = OP_JUMP;
825: }
826: meter.ndbra++;
827: (*didchange)++;
828: return p;
829: }
830:
831: /*
832: * find out if operand *o uses the register r
833: */
834: int
835: operand_uses( o, r )
836: struct oper *o;
837: int r;
838: {
839: int t;
840: switch (o->type_o){
841: case T_REG:
842: case T_DEFER:
843: case T_POSTINC:
844: case T_PREDEC:
845: return (o->value_o == r);
846: case T_DISPL:
847: return (o->reg_o == r);
848: case T_INDEX:
849: t = (o->flags_o & O_BSUPRESS)?0 : (o->reg_o == r);
850: t |= (o->flags_o & (O_PREINDEX|O_POSTINDEX))? (o->value_o == r) : 0;
851: return t;
852: case T_REGPAIR:
853: return (o->value_o == r || o->reg_o == r);
854: }
855: return 0; /* others don't use registers */
856: }
857:
858: /*
859: * Look for arithmetic on an A register. Look for nearby uses of
860: * the same register using deferred addressing. See if we can combine
861: * them into postincrement or predecrement mode addressing.
862: */
863: NODE *
864: plus_minus( p, didchange )
865: register NODE *p;
866: int *didchange;
867: {
868: int incrval;
869: register int reg;
870: register NODE *q;
871: int found;
872: int i;
873: operand_t substitute;
874: register struct oper *o;
875:
876: if ( numeric_immediate( p->ref[0] ) && areg_addr( p->ref[1] ) ){
877: incrval = p->ref[0]->value_o;
878: reg = p->ref[1]->value_o;
879: q = p;
880: found = 0;
881: if ( p->op == OP_ADD ){
882: /* search backwards */
883: substitute = T_POSTINC;
884: while ( (q=q->back)->op != OP_FIRST && q->op != OP_LABEL
885: && !ISBRANCH(q->op) && ! inmask( reg, q->rset)){
886: if (inmask( reg, q->ruse)){
887: found = 1;
888: break;
889: }
890: }
891: } else {
892: /* search forwards */
893: substitute = T_PREDEC;
894: while ( (q=q->forw)->op != OP_FIRST && q->op != OP_LABEL
895: && !ISBRANCH(q->op) && ! inmask( reg, q->rset)){
896: if (inmask( reg, q->ruse)){
897: found = 1;
898: break;
899: }
900: }
901: }
902: if (found){
903: /*
904: * we've found a nearby node that reads our register.
905: * it must now meet these criteria:
906: * -- the size of the access must agree with the size of the
907: * increment/decrement operation
908: * -- must not change the register (already checked)
909: * -- must use the register exactly once
910: * -- must use the register in a type T_DEFER operand
911: * -- must be able to take the substituted operand type
912: */
913: switch (q->subop){
914: case SUBOP_B: found = incrval==1; break;
915: case SUBOP_W: found = incrval==2; break;
916: case SUBOP_L: found = incrval==4; break;
917: case SUBOP_S: found = incrval==4; break;
918: case SUBOP_D: found = incrval==8; break;
919: case SUBOP_X: found = incrval==12; break;
920: default: found = 0; break;
921: }
922: if (found){
923: found = 0;
924: for (i=0; i < q->nref; i++)
925: if (operand_uses( q->ref[i], reg)){
926: found++;
927: o = q->ref[i];
928: }
929: if (found == 1 && o->type_o == T_DEFER){
930: o->type_o = substitute;
931: if (operand_ok(q->instr, q->ref[0], q->ref[1], q->ref[2] )){
932: /* got it */
933: p = deletenode( p );
934: q->rset = addmask( q->rset, MAKEWMASK( reg, LW ) );
935: *didchange++;
936: meter.nplusminus++;
937: } else {
938: /* blew it */
939: o->type_o = T_DEFER; /* restore operand, go home */
940: }
941: }
942: }
943: }
944: }
945: return p;
946: }
947:
948: int
949: shorten()
950: {
951: int nchanged = 0;
952: register NODE *p, *pnext;
953: NODE *pprev, *p3;
954: register struct oper *o;
955: register regno, t;
956: int didchange;
957: char *newname;
958: int i, newcc, opset;
959: int otherreg;
960: regmask m;
961: struct oper *trialops[OPERANDS_MAX];
962:
963: /*
964: * delete instructions that do useless things:
965: * moves to registers or parts of registers that are dead;
966: * extends to parts of registers that are dead;
967: * reset the condition codes to its current value.
968: * also, anything that depends on context which might
969: * be changed by rearranging branchs:
970: * resetting condition codes, multiple shifts in a row,
971: * changing a "cmpl #0,A0" into a "movl A0,Di", where Di is dead.
972: * and the transformation
973: * - subqw #1,dX; cmpw #-1,dX; jne Y: becomes dbra dX,Y
974: * (most often requested hack).
975: */
976: if (moveq==NULL) moveq = sopcode( "moveq" );
977: didchange = 1;
978: while(didchange){
979: didchange = 0;
980: for (p=first.forw; p != &first; p=p->forw){
981: if (!ISINSTRUC(p->op)) continue;
982: if (!emptymask( submask(p->rset , addmask( p->forw->rlive, MAKERMASK( CCREG, LR)))) ){
983: switch (p->op){
984: case OP_CALL:
985: case OP_DBRA:
986: case OP_DJMP:
987: case OP_BRANCH:
988: case OP_JUMP:
989: break;
990: case OP_EXT:
991: /* ext's also set condition codes */
992: if (!inmask( CCREG, p->forw->rlive)){
993: /* useless extend -- simply delete it */
994: p = deletenode( p );
995: didchange++;
996: meter.nredext++;
997: }
998: break;
999: case OP_MOVE:
1000: /* be careful here -- useless set must be to a register */
1001: /* for instance: movl #0,a0@+ sets a0, but we cannot change it */
1002: o = p->ref[1]; /* object of move */
1003: if (o->type_o != T_REG) break;
1004: if (!datareg(regno = o->value_o)) break;
1005: /* TEST FOR CC USAGE */
1006: if ( dreg(regno) && inmask( CCREG, p->forw->rlive)) break;
1007: if ( freg(regno) && inmask( FPCCREG, p->forw->rlive)) break;
1008: switch (inmask(regno, p->forw->rlive)) {
1009: case 0:
1010: if (!deladdr( p->ref[0])) continue; /* side effects? */
1011: /* totally useless -- fugg it */
1012: p = deletenode( p );
1013: didchange++;
1014: meter.redunm++;
1015: continue;
1016: case 1: /* BYTE ONLY */
1017: newname = "movb";
1018: t = (p->subop ==SUBOP_L )?3 : 1; /* could have been movw */
1019: break;
1020: case 2:
1021: case 3: /* WORD ONLY */
1022: newname = "movw";
1023: t = 2;
1024: break;
1025: default: continue;
1026: }
1027: if ( freg(regno) ) break; /* don't rewrite fp moves */
1028: if (incraddr( p->ref[0], t)) break;/* not ok */
1029: if (p->instr == moveq) break; /* already moveq */
1030: cannibalize( p, newname );
1031: p->rlive = compute_normal( p, p->forw->rlive );
1032: didchange++;
1033: meter.nwmov++;
1034: continue;
1035: case OP_AND:
1036: /*
1037: * if we're doing an AND to a dead register, it must be
1038: * for condition-code only (don't even bother to check).
1039: * if its only a single bit, change this to a btst.
1040: */
1041: if ((o=p->ref[1])->type_o!=T_REG || !dreg(regno=o->value_o))
1042: break;
1043: if (inmask(regno, p->forw->rlive)!=0)
1044: break;
1045: if (!numeric_immediate(o=p->ref[0]))
1046: break;
1047: if (cntbits( t = o->value_o ) == 1){
1048: o->value_o = ffs(t)-1;
1049: cannibalize( p, "btst" );
1050: p->rlive = compute_normal( p, p->forw->rlive );
1051: didchange++;
1052: meter.nwop++;
1053: }
1054: break;
1055: }
1056: }
1057: switch (p->op){
1058: case OP_MOVE:
1059: /*
1060: * If this is a move to a register which is only read once
1061: * by a following instruction, see if we can elide a move.
1062: * If this is a move to a register which is changed once
1063: * in the next instruction, then written back whence it
1064: * came, try doing the modify directly to the source
1065: * of it all.
1066: * If this is a move of a register to itself, and condition
1067: * codes are dead, elide the move.
1068: * SPECIAL HACK: the sequence
1069: * moveq #n, d0
1070: * movl d0, XXX
1071: * is FASTER and shorter than the instruction
1072: * movl #n, XXX
1073: * DO NOT UNDO THIS OPTIMIZATION!
1074: */
1075: if ((o=p->ref[1])->type_o != T_REG) break;
1076: regno = o->value_o;
1077: if ( p->ref[0]->type_o ==T_REG && p->ref[0]->value_o == regno){
1078: /* either:
1079: * its a Dreg or Freg, and the condition code is useless,
1080: * or its an Areg, and we're not doing some funny
1081: * sign extension.
1082: */
1083: if ( ((dreg(regno)||freg(regno)) && !inmask( CCREG, p->forw->rlive))
1084: || (areg(regno) && p->subop == SUBOP_L)){
1085: p = deletenode( p );
1086: didchange++;
1087: meter.redunm++;
1088: break;
1089: }
1090: }
1091: newcc = 0;
1092: p3 = p;
1093: nexti(p3);
1094: for (pnext=p3; ISINSTRUC(pnext->op)||ISDIRECTIVE(pnext->op); pnext=pnext->forw){
1095: if (ISDIRECTIVE(pnext->op)) continue;
1096: newcc = inmask( CCREG, pnext->rset );
1097: if (inmask( regno, pnext->ruse)) break;
1098: if ((!newcc && inmask(CCREG, pnext->ruse )) || inmask( regno, pnext->rset))
1099: goto no_cookie;
1100: if (!emptymask( andmask( pnext->rset,p->ruse)) || !emptymask( andmask( p->rset,pnext->ruse)) )
1101: goto no_cookie;
1102: switch (pnext->op){
1103: case OP_BRANCH:
1104: case OP_DBRA:
1105: case OP_JUMP:
1106: case OP_DJMP:
1107: goto no_cookie;
1108: }
1109: }
1110: if (!ISINSTRUC(pnext->op)) break;
1111: /* see if operands the same */
1112: /* for each operand #i that is the same, opset gets bit 1<<i set */
1113: opset = 0;
1114: for ( i=0 ; i<pnext->nref; i++)
1115: if (sameops( o, pnext->ref[i])) opset |= 1<<i;
1116: if (!opset) break;
1117: /*
1118: * We have only two cases we are smart enough to understand.
1119: * Either the two instructions are ajacent, in which case
1120: * there can have been no side effects in the intervening
1121: * (null) instructions, OR we're looking at this pattern:
1122: * movX Y,d0; ... ; opX d0,dZ
1123: * where dZ is not used between the moves. The reason for
1124: * this restriction is that it's too easy to break subtile
1125: * C constructs like post-incrementing, and too hard to detect
1126: * the general case.
1127: */
1128: if (pnext==p3){
1129: /*
1130: * see if register used after that instruction
1131: * make sure its a read-only access, and same size
1132: */
1133: if (!inmask(regno, pnext->forw->rlive) && !inmask( regno, pnext->rset ) ){
1134: t = addr_delt(p->subop, pnext->subop);
1135: for ( i=0 ; i<pnext->nref; i++)
1136: trialops[i] = (opset & (1<<i) ) ? p->ref[0] : pnext->ref[i];
1137: for ( i ; i<OPERANDS_MAX; i++)
1138: trialops[i] = NULL;
1139: if (operand_ok(pnext->instr, trialops[0], trialops[1], trialops[2])){
1140: int ok = 0;
1141: if (t==0) {
1142: /* both instructions use same size data */
1143: ok = 1;
1144: } else if (t>0 && !areg(regno)) {
1145: /*
1146: * second inst uses smaller data, and
1147: * doesn't depend on sign-extension. The
1148: * check on regno prevents us from changing
1149: * movl a6@(8),a0; cmpw #0,a0 | RIGHT
1150: * into
1151: * cmpw #0,a6@(10) | WRONG
1152: */
1153: ok = !incraddr(p->ref[0],t);
1154: }
1155: if (ok && !exception( p, pnext)){
1156: p = elide_move(p, pnext, opset);
1157: didchange++;
1158: break;
1159: }
1160: } else if (pnext->op == OP_BOP &&
1161: numeric_immediate( pnext->ref[0] )){
1162: /*
1163: * btst #t,d0
1164: * take t modulo 8
1165: */
1166: t = pnext->ref[0]->value_o;
1167: pnext->ref[0]->value_o = t%8;
1168: if (operand_ok(pnext->instr, trialops[0], trialops[1], trialops[2]) &&
1169: !incraddr( p->ref[0], BYTESIZE(p->subop)-1-t/8 )){
1170: /* it worked */
1171: p = elide_move(p, pnext, opset);
1172: didchange++;
1173: break;
1174: } else {
1175: /* didn't work; put it back */
1176: pnext->ref[0]->value_o = t;
1177: }
1178:
1179: }
1180: }
1181: }else{
1182: if (pnext->nref!=2 || !dareg_addr(pnext->ref[1])) break;
1183: otherreg = pnext->ref[1]->value_o;
1184: for (p3=p->forw; p3!=pnext; p3=p3->forw){
1185: if (inmask( otherreg, addmask(p3->ruse,p3->rset) )) break;
1186: }
1187: if (p3!=pnext ) break;
1188: if (!inmask( regno, pnext->forw->rlive ) && !inmask( CCREG, pnext->forw->rlive)
1189: && ! (inmask( regno, pnext->rset) || p->subop != pnext->subop )){
1190: if ( operand_ok(pnext->instr,p->ref[0],pnext->ref[1], 0 )){
1191: freeoperand( p->ref[1] );
1192: p->ref[1] = pnext->ref[1];
1193: installinstruct( p, pnext->instr );
1194: pnext->nref=1;
1195: m = pnext->forw->rlive;
1196: for (p3=pnext->back; p3!=p; p3=p3->back)
1197: p3->rlive = m = compute_normal( p3, m);
1198: p->rlive = compute_normal(p, m );
1199: (void) deletenode(pnext);
1200: didchange++;
1201: meter.redunm++;
1202: }
1203: }
1204: break;
1205: }
1206:
1207: /* see if the operand is written in the next instruction,
1208: * then moved back in the following, and dead thereafter
1209: */
1210: no_cookie:
1211: if (inmask( regno, pnext->rset ) && (p3=pnext->forw)->op==OP_MOVE
1212: && sameops( o, p3->ref[0] )
1213: && (pnext->nref== 1 || !sameops( o, pnext->ref[0] ) )
1214: && sameops( p->ref[0], p3->ref[1] ) && !inmask(regno , p3->forw->rlive)
1215: && p->subop==pnext->subop && pnext->subop==p3->subop )
1216: {
1217: if (pnext->nref==1 && operand_ok( pnext->instr, p->ref[0], NULL, 0 )){
1218: /* looks like a negX d0 or notX d0 */
1219: /* move p's operand to pnext */
1220: freeoperand( pnext->ref[0] );
1221: pnext->ref[0] = p->ref[0];
1222: p->ref[0] = NULL;
1223: /* delete p and p3 */
1224: p = deletenode( p );
1225: (void )deletenode( p3 );
1226: /* recompute register info */
1227: installinstruct( pnext, pnext->instr );
1228: pnext->rlive = compute_normal(pnext, pnext->forw->rlive );
1229: didchange++;
1230: meter.redunm += 2;
1231: break;
1232: } else if (pnext->nref==2 && operand_ok( pnext->instr, pnext->ref[0], p->ref[0], 0 )){
1233: /* looks like a addX #Y,d0 */
1234: /* move p's operand to pnext */
1235: freeoperand( pnext->ref[1] );
1236: pnext->ref[1] = p->ref[0];
1237: p->ref[0] = NULL;
1238: /* delete p and p3 */
1239: p = deletenode( p );
1240: (void )deletenode( p3 );
1241: /* recompute register info */
1242: installinstruct( pnext, pnext->instr );
1243: pnext->rlive = compute_normal(pnext, pnext->forw->rlive );
1244: didchange++;
1245: meter.redunm += 2;
1246: break;
1247: } else if (pnext->nref==2 && !inmask(regno , p3->forw->rlive)
1248: && operand_ok( pnext->instr, o, p->ref[0], 0 )){
1249: /*
1250: * change:
1251: * movX A,d0 <== p
1252: * opX B,d0 <== pnext
1253: * movX d0,A <== p3
1254: * into:
1255: * movX B,d0 <== p
1256: * opX d0,A <== pnext
1257: */
1258: p->ref[0] = pnext->ref[0];
1259: installinstruct( p, p->instr );
1260: pnext->ref[0] = pnext->ref[1];
1261: pnext->ref[1] = p3->ref[1];
1262: p3->nref=1;
1263: (void)deletenode( p3 );
1264: installinstruct( pnext, pnext->instr );
1265: pnext->rlive = m = compute_normal( pnext, pnext->forw->rlive);
1266: p->rlive = compute_normal( p, m );
1267: didchange++;
1268: meter.redunm ++;
1269: break;
1270: }
1271: }
1272: break;
1273:
1274: case OP_TST:
1275: /*
1276: * if a previous instruction touched this as an operand
1277: * AND set cc on it in a way we appreciate, then delete this
1278: * EXTRA HACKERY:
1279: * some instructions (e.g.: lsrl) set the condition codes
1280: * in a way that we can use MOST of the time. others
1281: * (esp moves) set the cond codes in a way that is ok
1282: * all of the time. If the previous instruction is not
1283: * a move, we will try to find the instruction checking
1284: * the cc, and decide if this is an extraordinary case.
1285: */
1286: pprev = p;
1287: do{
1288: previ( pprev );
1289: } while ( !ISBRANCH(pprev->op) && !(pprev->op==OP_LABEL) &&
1290: !inmask(CCREG, p->rset));
1291: if (!ISINSTRUC(pprev->op) || pprev->nref<1 || pprev->subop != p->subop) break;
1292: /* integer cc is very funny -- floating cc very regular */
1293: if (pprev->op!=OP_MOVE){
1294: for( p3 = p->forw; p3->op != OP_FIRST; ){
1295: switch (p3->op){
1296: case OP_LABEL:
1297: nexti(p3);
1298: continue;
1299: case OP_JUMP:
1300: case OP_BRANCH:
1301: case OP_DBRA:
1302: case OP_DJMP:
1303: break;
1304: default:
1305: if (inmask( CCREG, p3->ruse))
1306: break;
1307: nexti(p3);
1308: continue;
1309: }
1310: break;
1311: }
1312: if (!inmask( CCREG, p3->ruse)) break;/* cannot find user */
1313: if (p3->op == OP_BRANCH || p3->op == OP_DBRA)
1314: break; /* too hard */
1315: if (p3->op == OP_JUMP || p3->op == OP_DJMP){
1316: if (inmask( CCREG, p3->luse->rlive)) break; /* double use */
1317: if (p3->subop != JALL)
1318: if (inmask( CCREG, p3->forw->rlive)) break; /* double use */
1319: }
1320: if (read_cc_cv[(int)p3->subop - (int)JEQ]) break; /* untrustworthy */
1321: }
1322: o = p->ref[0];
1323: if (!deladdr( o )) break; /* not ok to remove this reference */
1324: /*
1325: * if we set condition codes on this, AND its not an
1326: * Areg (on which condition codes are never set, then
1327: * its ok to delete the test
1328: */
1329: if (pprev->nref>=1 && sameops( pprev->ref[0], o)){
1330: if (((pprev->instr->cc_i&CCX) == CC1) ||
1331: ( pprev->op == OP_MOVE && !areg_addr( pprev->ref[1])) ){
1332: p = deletenode( p );
1333: didchange++;
1334: meter.nrtst++;
1335: }
1336: } else if (pprev->nref==2 && sameops( pprev->ref[1], o)){
1337: if (((pprev->instr->cc_i&CCX) == CC2) && !areg_addr(o) ){
1338: p = deletenode( p );
1339: didchange++;
1340: meter.nrtst++;
1341: }
1342: }
1343: break;
1344: case OP_FTST:
1345: /*
1346: * Floating-point instructions always set their condition codes
1347: * on the result. The exception is that a move from the
1348: * coprocessor does not set the condition codes at all.
1349: */
1350: /* see if we can find an instruction that sets fpcc */
1351: pprev = p;
1352: do{
1353: previ( pprev );
1354: } while ( !ISBRANCH(pprev->op) && !(pprev->op==OP_LABEL) &&
1355: !inmask(FPCCREG, p->rset));
1356: if (!ISINSTRUC(pprev->op) || pprev->nref<1 || pprev->subop != p->subop) break;
1357: o = p->ref[0];
1358: if ((pprev->op ==OP_MOVE && sameops( o, pprev->ref[0] ))||
1359: (pprev->op !=OP_MOVE && sameops( o, pprev->ref[pprev->nref-1] ))){
1360: p = deletenode( p );
1361: didchange++;
1362: meter.nrtst++;
1363: }
1364: break;
1365: case OP_OR:
1366: /*
1367: * if what we're or-ing will fit into a byte or word, then
1368: * there's no excuse for using a longer immediate.
1369: * unless condition codes are live.
1370: */
1371: if ( inmask( CCREG, p->forw->rlive)) break;
1372: if (numeric_immediate(o=p->ref[0])){
1373: t = o->value_o;
1374: if (t==0 && deladdr(p->ref[1] )){
1375: p = deletenode(p);
1376: didchange++;
1377: break;
1378: }
1379: if (t>0 && t<0xffff){
1380: i = (p->subop==SUBOP_L)?2:0;
1381: newname = "orw";
1382: if (t<0xff){
1383: i = (p->subop==SUBOP_L)?3:(p->subop==SUBOP_W)?1:0;
1384: newname = "orb";
1385: }
1386: if (i && !incraddr( p->ref[1], i)){
1387: cannibalize( p, newname);
1388: meter.nwop++;
1389: didchange++;
1390: }
1391: }
1392:
1393: }
1394: break;
1395: case OP_ASL:
1396: /* look for multiple shifts in a row */
1397: if (!numeric_immediate(o=p->ref[0])) continue;
1398: t = o->value_o;
1399: o = p->ref[1];
1400: while ((pnext=p->forw)->op==OP_ASL){
1401: register struct oper *iop;
1402: if (!numeric_immediate(iop=pnext->ref[0])
1403: || !sameops( pnext->ref[1], o))
1404: break;
1405: if ( t + iop->value_o > 8){
1406: p->ref[0]->value_o = t;
1407: t = iop->value_o;
1408: p = pnext;
1409: o = p->ref[1];
1410: continue;
1411: }
1412: t += iop->value_o;
1413: (void)deletenode( pnext );
1414: meter.nredshf++;
1415: didchange++;
1416: }
1417: p->ref[0]->value_o = t;
1418: break;
1419: case OP_CMP:
1420: /* compares to zero are degenerate */
1421: o = p->ref[0];
1422: if (immediate_value(o, 0) && areg_addr(p->ref[1])){
1423: /* "A" register */
1424: /* look for a dead D register. Make this a movl */
1425: if ((i=dead_dreg(p)) >= 0){
1426: /* change cmpx #0,ay => movl ay,di */
1427: /* reuse the #0 operand as the di operand */
1428: p->ref[0] = p->ref[1];
1429: o->type_o = T_REG;
1430: o->value_o = i;
1431: p->ref[1] = o;
1432: cannibalize( p, "movl" );
1433: p->rlive = compute_normal( p, p->forw->rlive );
1434: meter.nttomo++;
1435: didchange++;
1436: }
1437: }
1438: break;
1439: case OP_LEA:
1440: /*
1441: * this form seems to occur rather often:
1442: * lea XXX,a0
1443: * movl a0,aN
1444: * with a0 dead beyond this point. Change this into
1445: * lea XXX,aN
1446: * then, look for the case
1447: * lea aN@(0,dM:Z),aN
1448: * and simplify it into
1449: * addZ dM,aN
1450: */
1451: if ((pnext=p->forw)->op == OP_MOVE
1452: && pnext->subop == SUBOP_L
1453: && sameops( p->ref[1], pnext->ref[0])
1454: && emptymask( andmask(p->rset,pnext->forw->rlive))) {
1455: /* if the move is to an A register, we're set */
1456: o=pnext->ref[1];
1457: if (areg_addr(o)){
1458: pnext->ref[1] = p->ref[1]; /* give away our 2nd operand */
1459: p->ref[1] = o; /* gain a new operand */
1460: (void) deletenode( pnext ); /* get rid of next, with operands */
1461: p->rset = MAKEWMASK( o->value_o, LW );
1462: p->rlive = compute_normal( p, p->forw->rlive);
1463: didchange++;
1464: meter.redunm++;
1465: }
1466: }
1467: if ((o=p->ref[0])->type_o == T_INDEX
1468: && o->reg_o == p->ref[1]->value_o
1469: && o->scale_o == 1
1470: && !(o->flags_o&(O_BSUPRESS|O_INDIRECT|O_POSTINDEX))
1471: && o->disp_o == 0){
1472: o->type_o = T_REG;
1473: newname = (o->flags_o&O_WINDEX) ? "addw" : "addl";
1474: o->flags_o &= ~(O_WINDEX|O_LINDEX);
1475: cannibalize( p, newname );
1476: meter.nsaddr++;
1477: didchange++;
1478: }
1479: break;
1480:
1481: case OP_SUB:
1482: p = make_dbra( p, &didchange );
1483: if (p->op != OP_SUB) break;
1484: /* FALL THROUGH */
1485: case OP_ADD:
1486: p = plus_minus( p, &didchange );
1487: break;
1488: }
1489: }
1490: nchanged += didchange;
1491: }
1492: return nchanged;
1493: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.