|
|
1.1 root 1: /* @(#) w2opt.c: 1.6 4/28/84 */
2: /* w2opt.c
3: **
4: ** 3B20S optimizer -- two instruction peephole window
5: **
6: **
7: ** This module contains the code that improves two-instruction
8: ** sequences. The general scheme is to put those improvements
9: ** first which result in removing code, followed by the others.
10: **
11: ** In some cases we play around with the live/dead information
12: ** to convince the one-instruction window not to throw away
13: ** code we need. This is particularly evident when we remove
14: ** redundant compares: we want to make sure that the instruction
15: ** that calculates the result indicators does not get deleted.
16: */
17:
18: /* Some general caveats (learned the hard way):
19: **
20: ** 1. When instructions get interchanged, we must take care that
21: ** we don't alter the condition codes that would have resulted
22: ** when executing the instructions in their original order.
23: ** 2. We can't move adds to %sp, since we may move them after the
24: ** place which refers to the newly allocated space on the stack.
25: */
26:
27: /* #include "defs" -- optim.h takes care of this */
28: #include "optim.h"
29: #include "optutil.h"
30:
31: extern int sprintf();
32: /* w2opt -- 2-instruction peephole window */
33:
34: boolean /* true if changes made */
35: w2opt(pf,pl)
36: register NODE * pf; /* first instruction node of window */
37: register NODE * pl; /* second instruction node */
38: {
39: int cop1 = pf->op; /* op code number of first inst. */
40: int cop2 = pl->op; /* op code number of second inst. */
41:
42: int opn; /* op code number (for istriadic) */
43: char * opst; /* op code string (for istriadic) */
44:
45: boolean f; /* temporary boolean used to
46: ** distinguish cases below
47: */
48: int temp; /* general integer temporary */
49: long templ; /* general long temporary */
50: int src1, dst1; /* sizes of movX source, destination */
51: int src2, dst2; /* sizes of second such movX */
52: /* merge moves back into triadic
53: **
54: ** opw3 O1,O2,R
55: ** movw R,O3 -> op3 O1,O2,O3
56: **
57: ** if R dead
58: **
59: ** We depend on the 1-instruction peephole to break such instructions
60: ** apart again if appropriate.
61: */
62:
63:
64: if (
65: istriadic(pf,&opn,&opst)
66: && cop2 == MOVW
67: && isdead(pl->op1,pl) /* also tests whether reg. */
68: && strcmp(pf->op3,pl->op1) == 0
69: && ! usesreg(pl->op2,pl->op1) /* register not used in destination */
70: )
71: {
72: wchange(); /* making a change */
73: pf->op3 = pl->op2; /* copy operand pointer */
74: makedead(pl->op1,pf); /* turn off liveness of R in op3 */
75: if (! isdead(pl->op2,pl))
76: makelive(pl->op2,pf); /* turn on liveness of O3, in case
77: ** it's a register
78: */
79: lmrgin1(pf,pl,pf); /* preserve line number info */
80: mvlivecc(pl); /* preserve condition code info */
81: DELNODE(pl); /* delete second node */
82: return(true);
83: }
84: /* Combine two dyadics into a triadic, if possible.
85: **
86: ** This improvement is useful on processors for which triadics are
87: ** better than dyadics.
88: **
89: ** movw O2,O3
90: ** opw2 O1,O3 -> op3 O1,O2,O3
91: **
92: ** if O1 does not use O3 in any way
93: */
94:
95: #ifdef IMPTRIAD
96: #ifdef M32 /* applies only to BELLMAC-32 */
97:
98: if ( cop1 == MOVW
99: && totriadic(pl, &opn, &opst) /* check whether dyadic can go
100: ** to triadic
101: */
102: && strcmp(pf->op2, pl->op2) == 0
103: && ! usesvar(pl->op1, pf->op2)
104: && ( isiros(pf->op1) || isiros(pl->op1) )
105: && isiros(pf->op2) /* safe from mmio */
106: )
107: {
108: wchange(); /* we're changing something */
109:
110: /* make changes to second instruction */
111:
112: pl->op3 = pl->op2; /* make room for new operand */
113: pl->op2 = pf->op1; /* copy from first inst. */
114: chgop(pl, opn, opst); /* change opcode to triadic */
115: lmrgin2(pf,pl,pl); /* preserve line number info */
116: mvlivecc(pf); /* preserve condition code info */
117: DELNODE(pf); /* delete first inst. */
118: return(true);
119: }
120:
121: #endif /* def M32 */
122: #endif /* IMPTRIAD */
123: /* Remove unnecessary movw's before compares.
124: **
125: ** movw O1,R
126: ** cmpw O2,R -> cmpw O2,O1
127: ** or
128: **
129: ** movw O1,R
130: ** cmpw R,O2 -> cmpw O1,O2
131: **
132: ** if R dead after cmpw
133: **/
134:
135: if (
136: cop1 == MOVW
137: && cop2 == CMPW
138: && isdead(pf->op2,pl) /* (implicit isreg test, too) */
139: && (
140: ( (f = samereg(pf->op2,pl->op1))
141: && ! usesreg(pl->op2,pl->op1)
142: && ( isiros(pf->op1) || isiros(pl->op2) )
143: /* safe from mmio */
144: )
145: || ( samereg(pf->op2,pl->op2) && ! usesreg(pl->op1,pl->op2) )
146: )
147: )
148: {
149: wchange(); /* flag changes */
150: if (f) /* true if second case above */
151: pl->op1 = pf->op1;
152: else
153: pl->op2 = pf->op1;
154: lmrgin1(pf,pl,pl); /* preserve line number info */
155: mvlivecc(pf); /* preserve condition code info */
156: DELNODE(pf); /* discard movw */
157: return(true);
158: }
159: /* Eliminate compares against zero if preceded by instruction that
160: ** sets result indicators. Because some 3B20S instructions do not
161: ** set all result indicators, we can only discard compares after
162: ** those instructions that set all of the relevant ones. w3opt
163: ** takes care of those which set a limited range of result indicators,
164: ** but which are followed by a suitable conditional jump.
165: **
166: ** None of the arithmetic operations set the "unsigned" result indicators,
167: ** so we retain compares before any unsigned-conditional jump.
168: **
169: ** op O1,O2[,O3] -> op O1,O2[,O3]
170: ** cmpX O[2|3],&0
171: **
172: **/
173:
174: if (
175: (cop2 == CMPW || cop2 == CMPH || cop2 == CMPB)
176: && strcmp(pl->op2,"&0") == 0
177: && strcmp(dst(pf),pl->op1) == 0
178: && (MOVB <= cop1 && cop1 <= ARSW3)
179: && stype(cop1) == stype(cop2)
180: && (pl->forw->op < JLU || pl->forw->op > JGEU)
181: && isiros(pl->op1) /* safe from mmio */
182: )
183: {
184: wchange(); /* changing window */
185: lmrgin3(pf,pl,pf); /* preserve line number info */
186: mvlivecc(pl); /* preserve condition code info */
187: DELNODE(pl); /* delete the compare */
188: return(true); /* announce success */
189: }
190: /* Eliminate compares against zero if preceding instruction sets condition
191: ** codes (special cases).
192: **
193: ** movw O1,O2
194: ** cmpw O1,&0 -> movw O1,O2
195: **
196: ** or
197: ** call &n,O
198: ** cmpw %r0,&0 -> call &n,O
199: **
200: ** This last improvement is moderately dangerous. It depends on the
201: ** fact that, in C, a function returning a value puts the value in r0
202: ** just before exiting. The return indicators would then be set correctly.
203: ** An assembly coder could blow this assumption to pieces.
204: ** Once again we have to watch out for unsigned tests following the cmpw,
205: ** since a "movw" in the called function would not set the unsigned
206: ** result indicators.
207: */
208:
209:
210: if (
211: cop2 == CMPW
212: && strcmp(pl->op2,"&0") == 0
213: && (
214: (
215: cop1 == MOVW
216: && strcmp(pf->op1,pl->op1) == 0
217: && ! usesvar(pf->op1,pf->op2)
218: /* O1 cannot use O2 in any way */
219: && isiros(pf->op1) /* safe for mmio */
220: )
221: #ifdef CALLCMPW /* make this a selectable option */
222: ||
223: (
224: cop1 == CALL
225: && strcmp(pl->op1,"%r0") == 0
226: )
227: #endif /* def CALLCMPW */
228: )
229: && ! (JLU <= pl->forw->op && pl->forw->op <= JGEU)
230: /* disallow unsigned jump after cmpw */
231: )
232: {
233: wchange();
234: lmrgin3(pf,pl,pf); /* preserve line number info */
235: mvlivecc(pl); /* preserve condition code info */
236: DELNODE(pl);
237: return(true);
238: }
239: /* One of the assumptions about eliminating "cmpw" after a "call"
240: ** is that all functions set result indicators upon returning a value.
241: ** If the value is set by a bit-field extract, this is not so.
242: ** Therefore, we must insert an extra "cmpw" to compensate:
243: **
244: ** extzv O1,O2,O3,%r0 --> extzv O1,O2,O3,%r0
245: ** --> cmpw %r0,&0
246: ** ret --> ret
247: */
248:
249: #ifdef CALLCMPW /* only if this is enabled */
250:
251: if (
252: cop1 == EXTZV
253: && cop2 == RET
254: && strcmp(pf->op4,"%r0") == 0
255: )
256: {
257: NODE * newnode = insert(pf); /* create new node after extzv */
258:
259: wchange(); /* making a change */
260: chgop(newnode,CMPW,"cmpw"); /* set op code number and string */
261: newnode->op1 = "%r0"; /* set up instruction */
262: newnode->op2 = "&0";
263: newnode->nlive = pf->nlive; /* save live/dead as predecessor */
264: pf->nlive &= ~CONCODES; /* killing condition codes */
265: return(true); /* made a change */
266: }
267: #endif /* def CALLCMPW */
268: /* This next set of improvements deals with pairs of move's. */
269:
270: /* case 1: redundant movw
271: **
272: ** movw O1,O2
273: ** movw O2,O1 -> movw O1,O2
274: ** or
275: **
276: ** movw O1,O2
277: ** movw O1,O2 -> movw O1,O2 (second one)
278: **
279: ** Note that, for the second improvement, O2 cannot be used by O1.
280: */
281: if (cop1 == MOVW && cop2 == MOVW)
282: {
283: if ( strcmp(pf->op1,pl->op2) == 0 /* first case */
284: && strcmp(pf->op2,pl->op1) == 0
285: && isiros(pf->op1)
286: && isiros(pf->op2) /* safe from mmio */
287: )
288: {
289: wchange(); /* change window */
290: lmrgin3(pf,pl,pf); /* preserve line number info */
291: mvlivecc(pl); /* perserve conditions codes live info */
292: DELNODE(pl); /* delete second inst. */
293: return(true);
294: }
295:
296: if ( strcmp(pf->op1,pl->op1) == 0 /* second case */
297: && strcmp(pf->op2,pl->op2) == 0
298: && ! usesvar(pl->op1,pf->op2)
299: && isiros(pf->op1)
300: && isiros(pf->op2) /* safe from mmio */
301: )
302: {
303: wchange();
304: lmrgin3(pf,pl,pl); /* preserve line number info */
305: mvlivecc(pf); /* perserve conditions codes live info */
306: DELNODE(pf); /* delete first inst. */
307: return(true);
308: }
309: }
310: /* Case 2: arbitrary size moves with intermediate register
311: **
312: ** The idea here is to collapse pairs of moves, possibly with different
313: ** sized operands, into one correct move. We assume that a register
314: ** is used unnecessarily in the operation. That is, we are looking at
315: **
316: ** movX O1,R
317: ** movY R,O2 -> movZ O1,O2
318: **
319: ** if R dead after movY and O2 doesn't use R
320: ** or O2 is same register as R
321: **
322: ** where X, Y, and Z are things like "twb" (as in, "movtwb"), "h",
323: ** and "bbw". The trick is to choose the correct move based on the
324: ** sizes of the operands. There are 81 (gasp!) combinations of four
325: ** operands, with three choices per operand. The code below is
326: ** correct, but misses one obscure case:
327: **
328: ** movtbh O1,R
329: ** movtwh R,O2 -> movh O1,O2
330: */
331:
332: if (
333: ismove(pf,&src1,&dst1) /* test, get source, dest. sizes */
334: && ismove(pl,&src2,&dst2)
335: && isreg(pf->op2)
336: && samereg(pf->op2, pl->op1)
337: && (
338: ( isdead(pl->op1,pl) && ! usesreg(pl->op2,pl->op1) )
339: || samereg(pl->op1,pl->op2)
340: )
341: )
342: /* fall through to sub-cases */
343: {
344: /* sub-case 1:
345: ** Sizes of movX source and movY destination are equal. Source of
346: ** movX no larger than destination, source of movY no smaller than its
347: ** destination. ("Size" here refers to number of bytes in effective
348: ** operand.) Example:
349: **
350: ** movbbw O1,R s = 1; d = 4
351: ** movthb R,O2 -> movb O1,O2 s = 2; d = 1
352: **
353: ** (More common case...)
354: **
355: ** movw O1,R s = 4; d = 4
356: ** movw R,O2 -> movw O1,O2 s = 4; d = 4
357: */
358:
359: if (
360: src1 == dst2
361: && src1 <= dst1
362: && src2 >= dst2
363: )
364: {
365: wchange();
366: pl->op1 = pf->op1; /* copy down first operand */
367: lmrgin1(pf,pl,pl); /* preserve line number info */
368: mvlivecc(pf); /* perserve conditions codes live info */
369: DELNODE(pf); /* delete first node */
370: switch (src1) /* choose correct new instruction */
371: {
372: case 1: /* byte to byte */
373: chgop(pl,MOVB,"movb"); break;
374:
375: case 2: /* halfword to halfword */
376: chgop(pl,MOVH,"movh"); break;
377:
378: case 4: /* word to word */
379: chgop(pl,MOVW,"movw"); break;
380: }
381: return(true);
382: }
383: /* sub-case 2:
384: ** Both sources are the same size, and either the destinations are
385: ** the same size or destination of movX larger than source.
386: ** Examples:
387: **
388: ** movzbw O1,R s = 1; d = 4
389: ** movb R,O2 -> movb O1,O2 s = 1; d = 1
390: **
391: ** movtwh O1,R s = 4; d = 2
392: ** movtwh R,O2 -> movtwh O1,O2 s = 4; d = 2
393: */
394:
395: if (
396: src1 == src2 /* source sizes equal */
397: && (
398: src1 <= dst1
399: || dst1 == dst2
400: )
401: )
402: {
403: wchange(); /* making a change */
404: pl->op1 = pf->op1; /* copy operand */
405: lmrgin1(pf,pl,pl); /* preserve line number info */
406: mvlivecc(pf); /* perserve conditions codes live info */
407: DELNODE(pf); /* delete first node */
408: return(true);
409: }
410: /* sub-case 3:
411: ** Destination 1, source 2, and destination 2 are all the same size.
412: ** Example:
413: **
414: ** movzhw O1,R s = 2; d = 4
415: ** movw R,O2 -> movzhw O1,O2 s = 4; d = 4
416: */
417:
418: if (
419: dst1 == src2
420: && src2 == dst2
421: )
422: {
423: wchange();
424: pf->op2 = pl->op2; /* copy up second operand */
425: makelive(pf->op2,pf); /* make sure first inst. won't now
426: ** go away
427: */
428: lmrgin1(pf,pl,pf); /* preserve line number info */
429: mvlivecc(pl); /* perserve conditions codes live info */
430: DELNODE(pl); /* delete second node */
431: return(true);
432: }
433: } /* end move-move merging */
434: /* Merge register move into indirect reference.
435: **
436: ** The purpose of this improvement is to eliminate a movw if it is
437: ** used to load a register which is then used exclusively for an
438: ** indirect reference. Examples:
439: **
440: ** movw O1,R
441: ** op2 0(R),O2 -> op2 *O1,O2
442: **
443: ** if R dead after op2
444: ** if R not used in O2, except as 0(R)
445: **
446: ** We use utility routine 'doindirect' to do this in a general way
447: ** for, in fact, any instruction and not just op2.
448: */
449:
450: if ( cop1 == MOVW && isreg(pf->op2))
451: {
452: /* use utility routine to check for feasibility. Replace
453: ** 0(R) with suitable indirection from O1
454: */
455:
456: if (doindirect(pl,pf->op2,pf->op1))
457: {
458: lmrgin1(pf,pl,pl); /* preserve line number info */
459: mvlivecc(pf); /* perserve conditions codes live info */
460: DELNODE(pf); /* success. delete first node */
461: return(true);
462: }
463: }
464: /* Address arithmetic:
465: **
466: ** This transformation merges instructions of the form
467: **
468: ** addw2 &m,R
469: **
470: ** with operands of the form
471: **
472: ** n(R)
473: **
474: ** yielding a replacement operand of the form
475: **
476: ** m+n(R)
477: **
478: ** We do this in a general way, transforming all of the operands in the
479: ** instruction that follows the addw2 (subw2) that can be transformed.
480: ** The transformation cannot be performed if the second instruction uses
481: ** R in any other way. Note that dyadic instructions like
482: **
483: ** addw2 a,R
484: **
485: ** use R implicitly: a + R -> R.
486: ** However, for moves and triadics, the last operand is only a destination,
487: ** not an operand, so having R as the last operand does not impede our
488: ** transformation.
489: **
490: ** In general we don't delete the addw2 (subw2) node but simply move it
491: ** past its successor after transforming the operands. At first this
492: ** would seem to be a waste of time. However, if R is dead after the
493: ** second instruction, we can discard the addw2 (subw2). Thus we
494: ** can propagate the addw2 (subw2) through a series of offsets:
495: **
496: ** addw2 &4,%r0
497: ** movw 0(%r0),0(%r1)
498: ** movw 4(%r0),4(%r1)
499: **
500: ** |
501: ** V
502: ** movw 4(%r0),0(%r1)
503: ** addw2 &4,%r0
504: ** movw 4(%r0),4(%r1)
505: **
506: ** |
507: ** V
508: ** movw 4(%r0),0(%r1)
509: ** movw 8(%r0),4(%r1)
510: ** addw2 &4,%r0
511: **
512: ** and the addw2 could be discarded if %r0 is dead now. Notice that no
513: ** particular performance penalty is incurred by doing this transformation
514: ** if we fail to discard the addw2 (subw2), but we will win if we can
515: ** throw it out. NOTE, however, that we cannot move the add/sub if
516: ** there is a conditional branch or compare following the second instruction,
517: ** since we will provide different condition codes from the original sequence.
518: */
519: /* Begin address arithmetic transformation */
520:
521: if (
522: (cop1 == ADDW2 || cop1 == SUBW2)
523: && isnumlit(pf->op1)
524: && isreg(pf->op2)
525: && strcmp(pf->op2,"%sp") != 0 /* not stack pointer */
526: && ! isbr(pl) /* don't move add/sub past branch! */
527: )
528: {
529: char * reg = pf->op2; /* point at register name (R) */
530: int destreg = 0; /* number of destination operand,
531: ** zero if none
532: */
533: int idxmask = 0; /* bit mask of operands to change */
534: long idxval[MAXOPS+1]; /* current indices for each (indexed
535: ** 1 to MAXOPS, not 0 to MAXOPS-1)
536: */
537: int i; /* loop index */
538: long m = atol(pf->op1+1); /* literal in addw2 &m,R */
539: NODE * nextinst = pl->forw; /* pointer to inst. after window */
540:
541:
542: /* Check for conditional branch or compare following second instruction in
543: ** situation where we can't delete the add/sub. Don't do improvement
544: ** if we find one.
545: */
546:
547: f = ( isdead(reg,pl) || strcmp(dst(pl),reg) == 0 );
548: if ( (! f) && ( ! isdeadcc(pl) || iscompare(nextinst)) )
549: goto noindex; /* won't delete and have cond. br. */
550:
551: if (cop1 == SUBW2)
552: m = -m; /* negate literal if subtract */
553:
554: /* Determine in which instructions we allow ourselves to see R as an
555: ** operand (destination) and remember which operand number it is.
556: */
557:
558: if (istriadic(pl,&opn,&opst))
559: destreg = 3; /* in triadics, is third operand */
560: else if (ismove(pl,&src1,&dst1))
561: destreg = 2; /* in moves, is second */
562: /* in all others, not allowed */
563:
564: /* Now we loop through all possible operands in an instruction, looking
565: ** for indexed uses of R (i.e., n(R) ). If we find, instead, a use of
566: ** R which is not in the "destreg" position, we cannot do the transform.
567: */
568:
569: for (i = MAXOPS; i > 0; i--)
570: {
571: char * t = pl->ops[i]; /* point at new operand */
572:
573: if (t == NULL)
574: continue; /* disregard null operands */
575:
576: if (isindex(t,reg)) /* this is what we seek */
577: {
578: idxmask |= (1<<i); /* remember where we saw it */
579: if(*t == '*')
580: t++;
581: idxval[i] = atol(t); /* remember current index value
582: ** (i.e., n from n(R)
583: */
584: }
585: else if (samereg(t,reg) && i != destreg)
586: goto noindex; /* instruction uses register in
587: ** non-transformable way
588: */
589: }
590: /* We now know there have been only valid uses of R in the second
591: ** instruction. If there are any uses of R at all, transform the
592: ** second instruction.
593: */
594:
595: /* Define maximum size of new operand. */
596:
597: #define NEWSIZE (11+1+3+1+1) /* for "ddddddddddd(%rn)\0" */
598:
599: if (idxmask == 0)
600: goto noindex; /* nothing to do if no uses of R */
601:
602: wchange(); /* we may just move/delete the add */
603: for (i = MAXOPS; i>0; i--) /* find operands to alter */
604: {
605: char * t;
606: if ((idxmask & (1<<i)) == 0)
607: continue; /* ignore this operand: not n(R) */
608:
609: t = pl->ops[i];
610: pl->ops[i] = getspace(NEWSIZE);
611: /* get space for new operand */
612: if(*t == '*')
613: (void) sprintf(pl->ops[i],"*%d(%s)",(int)(m+idxval[i]),reg);
614: else
615: (void) sprintf(pl->ops[i],"%d(%s)",(int)(m+idxval[i]),reg);
616: /* build new operand string */
617: }
618:
619: /* Discard add/sub if R is dead after second instruction, or if that
620: ** instruction set a new value.
621: */
622:
623: if (f) /* conditions permit deleting */
624: {
625: ldelin(pf); /* preserve line number info */
626: mvlivecc(pf); /* perserve conditions codes live info */
627: DELNODE(pf); } /* delete add/sub */
628: else {
629: lexchin(pf,pl); /* preserve line number info */
630: exchange(pf); /* otherwise exchange add/sub and
631: ** second inst.
632: */
633: swplivecc(pf,pl); /* swaping the condition codes live/dead info */
634: }
635: return(true);
636: }
637: noindex:
638: /* Address arithmetic, case 2:
639: **
640: ** addw3 &n,R1,R2
641: ** pushw R2 -> pushaw n(R1)
642: ** or
643: **
644: ** subw3 &n,R1,R2
645: ** pushw R2 -> pushaw -n(R1)
646: **
647: ** if R2 dead after pushw
648: **
649: ** (Sigh! These aren't safe in general, but for the specific cases
650: ** where R2 is sp, fp, or ap, we can be sure we're pushing an
651: ** address and not the result of an integer computation. pushaw
652: ** doesn't do 32 bit arithmetic.)
653: */
654:
655: if (
656: (cop1 == ADDW3 || cop1 == SUBW3)
657: && cop2 == PUSHW
658: && *pf->op1 == '&'
659: && isreg(pf->op2)
660: && (
661: strcmp(pf->op2,"%fp") == 0
662: || strcmp(pf->op2,"%ap") == 0
663: || strcmp(pf->op2,"%sp") == 0
664: )
665: && isreg(pf->op3)
666: && samereg(pf->op3,pl->op1)
667: && isdead(pf->op3,pl)
668: )
669: {
670: /* allocate space for new operand: room for constant, less room
671: ** for &, plus room for possible sign, plus room for parens and
672: ** register declaration, plus room for null.
673: */
674: char * ts = getspace(
675: strlen(pf->op1)-1+1 /* less &, plus sign */
676: + 1 + strlen(pf->op2) + 1 /* ( reg ) */
677: + 1 /* null */
678: );
679:
680: char * operand = pf->op1 + 1; /* point past & at operand */
681:
682: int msign = 0; /* non-zero if minus sign required */
683:
684: wchange();
685:
686: /* create new operand */
687:
688: if (*operand == '-')
689: {
690: msign = 1; /* - sign required */
691: operand++; /* skip past - in operand */
692: }
693: if (cop1 == SUBW3) /* invert sign if op was subtract */
694: msign = 1-msign;
695:
696: (void) sprintf(ts,"%s%s(%s)",
697: (msign != 0 ? "-" : ""),
698: operand, /* string for constant, no & */
699: pf->op2);
700: lmrgin1(pf,pl,pl); /* preserve line number info */
701: mvlivecc(pf); /* perserve conditions codes live info */
702: DELNODE(pf); /* discard add/sub */
703: chgop(pl,PUSHAW,"pushaw"); /* change op code */
704: pl->op1 = ts; /* change operand */
705: return(true);
706: }
707: /* Collapse bit test/branch combination
708: **
709: ** bitw &2^n,O
710: ** je to -> jbc &n,O,to
711: **
712: ** bitw &2^n,O
713: ** jne to -> jbs &n,O,to
714: **
715: ** jz is a synonym for je.
716: ** jnz is a synonym for jne.
717: */
718:
719: /* ----------- FLASH -------------
720: ** It turns out that these "improvements" aren't: they are slower than
721: ** the sequences they would replace. If someday that condition changes,
722: ** remove the conditionals.
723: */
724:
725: #ifdef FASTJBCJBS
726:
727: if (
728: cop1 == BITW
729: && (
730: (f = (cop2 == JE))
731: || (f = (cop2 == JZ))
732: || cop2 == JNE
733: || cop2 == JNZ
734: )
735: && (temp = getbit(pf->op1)) >= 0
736: )
737: {
738: wchange();
739: pl->op3 = pl->op1; /* shift operands */
740: pl->op2 = pf->op2;
741: /* build new operand: &n */
742: pl->op1 = getspace(1+2+1); /* space for "&dd\0" */
743: (void) sprintf(pl->op1,"&%d",temp);
744: if (f) /* f true for je/jz */
745: chgop(pl,JBC,"jbc");
746: else
747: chgop(pl,JBS,"jbs");
748:
749: lmrgin1(pf,pl,pl); /* preserve line number info */
750: mvlivecc(pf); /* perserve conditions codes live info */
751: DELNODE(pf); /* discard bitw */
752: return(true);
753: }
754:
755: #endif /* def FASTJBCJBS */
756:
757: #ifdef UCODE50 /* with 5.0 microcode (3B20) only */
758:
759: /* Increment and test improvement
760: **
761: ** addw2 &n,R
762: ** cmpw R,O -> inctst R,&n-1,O
763: **
764: ** if O doesn't use R (this may be unnecessarily restrictive,
765: ** depending on when the effective address of O is calculated,
766: ** but it would be a strange use, anyway)
767: **
768: */
769:
770: if (
771: cop1 == ADDW2
772: && cop2 == CMPW
773: && isreg(pf->op2)
774: && samereg(pl->op1,pf->op2)
775: && isnumlit(pf->op1)
776: && 1 <= (templ = atol(pf->op1+1)) && templ <= 16
777: /* can't use isnib here: allow for
778: ** 16, disallow 0
779: */
780: && ! usesreg(pl->op2,pf->op2)
781: )
782: {
783: wchange(); /* making a change */
784: chgop(pl,INCTST,"inctst"); /* new op code number, string */
785: pl->op3 = pl->op2; /* shift operand */
786: pl->op2 = getspace(1+2+1); /* for "&dd\0" */
787: (void) sprintf(pl->op2,"&%d",(int)(templ-1));
788: /* literal in inctmp is 1 less */
789: lmrgin3(pf,pl,pl); /* preserve line number info */
790: DELNODE( pf ); /* delete ADDW2 */
791: return(true);
792: }
793: #endif /* def UCODE50 */
794:
795: #ifdef UCODE50 /* if 5.0 microcode (3B20) only */
796:
797: /* Use increment/decrement pointer
798: **
799: ** llsw2 &1,R1
800: ** addw2 R1,R2 -> incpth R2,R1
801: **
802: ** llsw2 &2,R1
803: ** addw2 R1,R2 -> incptw R2,R1
804: **
805: ** llsw2 &1,R1
806: ** subw2 R1,R2 -> decpth R2,R1
807: **
808: ** llsw2 &2,R1
809: ** subw2 R1,R2 -> decptw R2,R1
810: **
811: ** if R1 dead after addw2/subw2
812: ** if R1 and R2 different
813: */
814:
815: if (
816: cop1 == LLSW2
817: && (cop2 == ADDW2 || cop2 == SUBW2)
818: && isreg(pl->op1)
819: && isreg(pl->op2)
820: && isdead(pf->op2,pl)
821: && samereg(pl->op1,pf->op2)
822: && ! samereg(pl->op1,pl->op2)
823: && (
824: (f = (strcmp(pf->op1,"&2") == 0))
825: || strcmp(pf->op1,"&1") == 0
826: )
827: )
828: {
829: wchange();
830: pl->op1 = pl->op2; /* switch operands */
831: pl->op2 = pf->op2;
832:
833: /* select new op code for merged instruction */
834:
835: if (cop2 == ADDW2) /* do incpt cases */
836: {
837: if (f) /* true for word incr. */
838: chgop(pl,INCPTW,"incptw");
839: else
840: chgop(pl,INCPTH,"incpth");
841: }
842: else /* decpt case */
843: {
844: if (f) /* true for word decr. */
845: chgop(pl,DECPTW,"decptw");
846: else
847: chgop(pl,DECPTH,"decpth");
848: }
849:
850: lmrgin1(pf,pl,pl); /* preserve line number info */
851: DELNODE( pf ); /* delete shift */
852: return(true);
853: }
854: #endif /* def UCODE50 */
855: /********************************************************************
856: **
857: ** Begin improvements that alter code, rather than deleting it.
858: **
859: ***********************************************************************
860: */
861:
862: /* Use register in pushw if possible
863: **
864: ** movw R,O -> movw R,O
865: ** pushw O -> pushw R
866: **
867: ** if O is not a register.
868: */
869:
870: if (
871: cop1 == MOVW
872: && cop2 == PUSHW
873: && strcmp(pf->op2,pl->op1) == 0
874: && isreg(pf->op1)
875: && !isreg(pl->op1)
876: && isiros(pf->op2) /* safe from mmio */
877: )
878: {
879: wchange();
880: makelive((pl->op1 = pf->op1),pl); /* propagate liveness of R */
881: return(true);
882: }
883: /* Use register if possible in op2 or op3
884: **
885: ** movw R,O1 -> movw R,O1
886: ** op2 O1,O2 -> op2 R,O2
887: **
888: ** if O1 not a register
889: ** or
890: **
891: ** movw R,O1 -> movw R,O1
892: ** op3 O1,O2,O3 -> op3 R,O2,O3
893: **
894: ** if O1 is not a register
895: ** or
896: **
897: ** movw R,O2 -> movw R,O2
898: ** op3 O1,O2,O3 -> op3 O1,R,O3
899: **
900: ** if O2 is not a register
901: */
902:
903: if (
904: cop1 == MOVW
905: && isreg(pf->op1)
906: && ! isreg(pf->op2)
907: )
908: {
909: if (
910: (
911: isdyadic(pl)
912: && (f = (strcmp(pf->op2,pl->op1) == 0))
913: && (CMPW <= cop2 && cop2 <= UMODW3)
914: && ( ismove( pl, &src2, &dst2 ) && src2 == stype(cop1) ||
915: !ismove( pl, &src2, &dst2 ) && stype(cop2) == stype(cop1)
916: )
917: && isiros(pf->op2) /* safe from mmio */
918: )
919: ||
920: (
921: istriadic(pl,&opn,&opst)
922: && (
923: (f = (strcmp(pf->op2,pl->op1) == 0))
924: || strcmp(pf->op2,pl->op2) == 0
925: )
926: && isiros(pf->op2) /* safe from mmio */
927: )
928: )
929: {
930: wchange();
931: if (f) /* f true if we modify first operand */
932: pl->op1 = pf->op1;
933: else
934: pl->op2 = pf->op1;
935: makelive(pf->op2,pl); /* propagate liveness into op2/3 */
936: return(true);
937: }
938: }
939: /* This transformation propagates a register use back into a triadic.
940: **
941: ** op3 O1,O2,O3 -> op3 O1,O2,R
942: ** movw O3,R -> movw R,O3 (possibly deleted)
943: **
944: ** if R not used by O3
945: **
946: ** If O3 is a register that is dead after movw, we can change
947: ** this to just the op3. If O3 is a register that is not dead,
948: ** we can't do the transformation, because it will oscillate.
949: */
950:
951: if (
952: istriadic(pf,&opn,&opst)
953: && cop2 == MOVW
954: && isreg(pl->op2)
955: && strcmp(pf->op3,pl->op1) == 0
956: && ! usesreg(pf->op3,pl->op2)
957: && ( /* avoid oscillation case */
958: ! ( f = isreg(pl->op1) )
959: || isdead(pl->op1,pl)
960: )
961: && isiros(pf->op3) /* safe from mmio */
962: )
963: {
964: wchange();
965:
966: pf->op3 = pl->op2;
967: makelive(pf->op3,pf); /* make R live after op3 */
968:
969: lmrgin2(pf,pl,pf); /* preserve line number info */
970: /* lmrgin2 works here
971: because it sets the uniqid of the
972: non-result (i.e. pl) to IDVAL */
973: if (f) /* true if O3 was a register */
974: { mvlivecc(pl); /* preserve conditions codes live info */
975: DELNODE(pl); }
976: else /* O3 not a register */
977: {
978: pl->op2 = pl->op1;
979: pl->op1 = pf->op3; /* pf->op3 contains R from first move */
980: }
981: return(true);
982: }
983: /* Use register in second of two moves, if possible.
984: **
985: ** This improvement attempts to propagate a register use, if possible.
986: ** We do this in a general way for pairs of moves. Here's the case
987: ** we're considering:
988: **
989: ** movX R,O1 -> movX R,O1
990: ** movY O1,O2 -> movY R,O2
991: **
992: ** We don't bother with this improvement if O1 is already a register.
993: **
994: ** We can make the identical improvement if "R" is really a nibble.
995: **
996: ** We can do this when (using earlier terminology) the destination
997: ** of movX and the source of movY are the same size. There are three
998: ** sub-cases:
999: **
1000: ** 1. destination1 == source2 == destination2.
1001: ** 2. source1 >= destination1 == source2 .
1002: ** (remember, source1 is register or nibble)
1003: ** 3. source1 >= destination2.
1004: **
1005: ** Examples:
1006: **
1007: ** movbbh R,O1 s = 1; d = 2
1008: ** movthb O1,O2 -> movb R,O2 s = 2; d = 1
1009: **
1010: ** movbbh R,O1 s = 1; d = 2
1011: ** movh O1,O2 -> movbbh R,O2 s = 2; d = 2
1012: **
1013: */
1014:
1015: if (
1016: ismove(pf, &src1, &dst1)
1017: && ismove(pl, &src2, &dst2)
1018: && src2 == dst1
1019: && ( isreg(pf->op1) || isnib(pf->op1) ) /* R can be reg. or nibble */
1020: && ! isreg(pf->op2) /* this is "don't bother" test */
1021: && strcmp(pf->op2, pl->op1) == 0
1022: && isiros(pf->op2) /* safe from mmio */
1023: )
1024: /* fall through to sub-cases */
1025: {
1026:
1027: /* sub-case 1: source2 and destination2 same */
1028:
1029: if (src2 == dst2)
1030: {
1031: wchange();
1032: chgop(pl,pf->op,pf->opcode); /* copy instruction of first node */
1033: pl->op1 = pf->op1; /* propagate register/nibble use */
1034: makelive(pl->op1,pl); /* mark it as live */
1035: return(true);
1036: }
1037:
1038: /* sub-case 2: source1 >= destination1 */
1039:
1040: if (src1 >= dst1)
1041: {
1042: wchange();
1043: pl->op1 = pf->op1; /* propagate register/nibble */
1044: makelive(pl->op1,pl); /* make register live after pl */
1045: return(true);
1046: }
1047:
1048: /* sub-case 3: source1 >= destination2 */
1049:
1050: if (src1 >= dst2)
1051: {
1052: wchange();
1053: switch (dst2) /* choose correct new instruction */
1054: {
1055: case 1:
1056: chgop(pl,MOVB,"movb"); break;
1057: case 2:
1058: chgop(pl,MOVH,"movh"); break;
1059: case 4:
1060: chgop(pl,MOVW,"movw"); break;
1061: }
1062: pl->op1 = pf->op1; /* propagate register/nibble use */
1063: makelive(pl->op1,pl); /* make this register live here */
1064: return(true);
1065: }
1066: }
1067: /* More paired move improvements
1068: **
1069: ** This improvement propagates the use of a register, if possible from
1070: ** one move to a following one. It also has the potential of killing
1071: ** off the liveness of a register. Example:
1072: **
1073: ** movX O,R1 -> movX O,R1
1074: ** movY O,R2 -> movY R1,R2
1075: **
1076: ** Since we are trying to kill registers off early, these special
1077: ** conditions apply if O is a register:
1078: ** 1) O must be dead after movY or be the same as R2.
1079: ** 2) R1 must be live after movY.
1080: ** If O is a register, it must be live after movY or be the same
1081: ** register as R2.
1082: ** O may not use R1.
1083: **
1084: ** The size of source1 must be the same as source2,
1085: ** and destination1 must be at least as large as source2.
1086: */
1087:
1088: if (
1089: ismove(pf,&src1,&src2)
1090: && ismove(pl,&src2,&src2)
1091: && strcmp(pf->op1,pl->op1) == 0
1092: && isreg(pf->op2)
1093: && isreg(pl->op2)
1094: && ! usesreg(pl->op1,pf->op2)
1095: && src1 == src2
1096: && src2 <= dst1
1097: && (
1098: ! isreg(pl->op1) /* O not a register */
1099: || (
1100: (
1101: samereg(pl->op1,pl->op2)/* O same as R2 */
1102: || isdead(pl->op1,pl) /* O dead after movY */
1103: )
1104:
1105: && ! isdead(pf->op2,pl) /* R1 live after movY */
1106: )
1107: )
1108: && isiros(pf->op1) /* safe from mmio */
1109: )
1110: {
1111: wchange();
1112: makelive(pl->op1 = pf->op2,pf); /* copy operand, make register live
1113: ** after movX
1114: */
1115: return(true);
1116: }
1117: /* Re-order pairs of instructions to make better use of registers.
1118: **
1119: ** This improvement reverses a dyadic and a movw to make better use of
1120: ** registers. The canonical sequence is:
1121: **
1122: ** op2 O1,O2 -> movw O1,R
1123: ** movw O1,R -> op2 R,O2
1124: **
1125: ** if O1 and O2 don't use R
1126: ** if R live after movw
1127: ** if instruction following movw is not a conditional branch
1128: ** (since we're changing the instruction that sets codes)
1129: **
1130: ** op2 can also be CMPW
1131: */
1132:
1133: if (
1134: ( cop1 == CMPW
1135: || ( isdyadic(pf)
1136: && ! ismove(pf,&src1,&dst1)
1137: )
1138: )
1139: /* since moves are handled elsewhere
1140: ** and this would tend to undo them
1141: */
1142: && cop2 == MOVW
1143: && strcmp(pf->op1,pl->op1) == 0
1144: && isreg(pl->op2)
1145: && ! isdead(pl->op2,pl)
1146: && ! usesreg(pf->op1,pl->op2)
1147: && ! usesreg(pf->op2,pl->op2)
1148: && ! usesvar(pf->op1,pf->op2) /* O1 cannot use O2 in any way */
1149: && isdeadcc( pl )
1150: && isiros(pf->op1) /* safe from mmio */
1151: )
1152: {
1153: wchange();
1154: pf->op1 = pl->op2; /* copy operand first */
1155: lexchin(pf,pl); /* preserve line number info */
1156: exchange(pf); /* switch the two instructions */
1157: swplivecc(pf,pl); /* switch the live/dead info on condition codes */
1158: makelive(pl->op2,pf); /* show register as live after op2 */
1159: return(true);
1160: }
1161: /* Similar to the above, this transformation reverses a triadic and a
1162: ** movw:
1163: **
1164: ** op3 O1,O2,O3 -> movw [O1 | O2],R
1165: ** movw [O1 | O2],R -> op3 [O1 | R], [O2 | R], O3
1166: **
1167: ** That is, it inserts a register reference into op3.
1168: ** R must not be used in O1, O2, or O3.
1169: ** O3 cannot be the same as R, nor can O1/O2 use O3 in any way.
1170: ** Instruction after movw must not be conditional branch, since we're
1171: ** setting different condition codes.
1172: ** Don't bother if R dead after movw, since the inst. will go away eventually.
1173: */
1174:
1175: if (
1176: istriadic(pf,&opn,&opst)
1177: && cop2 == MOVW
1178: && isreg(pl->op2)
1179: && ! isdead(pl->op2,pl)
1180: && (
1181: (f = (strcmp(pl->op1,pf->op1) == 0))
1182: || strcmp(pl->op1,pf->op2) == 0
1183: )
1184: && ! usesreg(pf->op1,pl->op2)
1185: && ! usesreg(pf->op2,pl->op2)
1186: && ! usesreg(pf->op3,pl->op2)
1187: && ! usesvar(pl->op1,pf->op3)
1188: && ! usesvar(pl->op2,pf->op3)
1189: && isdeadcc( pl )
1190: && isiros(pl->op1) /* safe from mmio */
1191: )
1192: {
1193: wchange();
1194: if (f) /* true if first operand is R ref. */
1195: pf->op1 = pl->op2;
1196: else
1197: pf->op2 = pl->op2; /* second operand refers to R */
1198: makelive(pl->op2,pf); /* R now (will be) live after op3
1199: ** since we knew it was live after movw
1200: */
1201: lexchin(pf,pl); /* preserve line number info */
1202: exchange(pf); /* exchange the instructions */
1203: swplivecc(pf,pl); /* switch the live/dead info on condition codes */
1204: return(true);
1205: }
1206: /* Merge successive adds.
1207: **
1208: ** This improvement occurs in address arithmetic and in some funny
1209: ** expressions.
1210: **
1211: ** addw3 X,Y,R1 -> addw2 X,R2
1212: ** addw2 R1,R2 -> addw2 Y,R2
1213: **
1214: ** if R1 dead after addw2, R1 and R2 are different.
1215: ** neither X nor Y can use R1
1216: **
1217: ** Unfortunately, we learn the hard way of special cases we hadn't
1218: ** thought of earlier, to wit:
1219: **
1220: ** addw3 X,R2,R1 -> addw2 R2,R2
1221: ** addw2 R1,R2 -> addw2 X,R2
1222: **
1223: ** If X is R2, we can't do this at all!
1224: */
1225:
1226: if (
1227: cop1 == ADDW3
1228: && cop2 == ADDW2
1229: && isdead(pf->op3,pl) /* also tests register-ness */
1230: && samereg(pf->op3,pl->op1)
1231: && isreg(pl->op2)
1232: && ! samereg(pl->op1,pl->op2)
1233: && strcmp(pf->op1,pf->op2) != 0 /* different operands */
1234: && ! usesreg(pf->op1,pf->op3)
1235: && ! usesreg(pf->op2,pf->op3)
1236: )
1237: {
1238: wchange();
1239: if (! samereg(pl->op2,pf->op2)) /* check special case */
1240: pl->op1 = pf->op2; /* not special: move Y to 2nd inst. */
1241: else
1242: {
1243: pl->op1 = pf->op1; /* special case: move X to 2nd inst. */
1244: pf->op1 = pf->op2; /* move R2 over in first */
1245: }
1246: pf->op2 = pl->op2; /* move ultimate dest. into 1st inst. */
1247: pf->op3 = NULL; /* clean up 1st inst. */
1248: chgop(pf,ADDW2,"addw2"); /* change op code number and string */
1249: lmrgin2(pf,pl,pf); /* preserve line number info */
1250: /* again this works because pl->uniqid
1251: is set to IDVAL */
1252: return(true);
1253: }
1254: /* Reverse adds/subtracts of literals and other adds/subtracts.
1255: **
1256: ** This transformation facilitates other improvements by bubbling
1257: ** adds/subtracts of literals downward and other adds/subtracts upwards.
1258: **
1259: ** addw2 &n,R -> addw2 O,R
1260: ** addw2 O,R -> addw2 &n,R
1261: **
1262: ** if R not used in O, O not a literal.
1263: */
1264:
1265: if (
1266: (cop1 == ADDW2 || cop1 == SUBW2)
1267: && (cop2 == ADDW2 || cop2 == SUBW2)
1268: && isreg(pf->op2)
1269: && samereg(pf->op2,pl->op2)
1270: && *pf->op1 == '&'
1271: && ! usesreg(pl->op1,pl->op2)
1272: && *pl->op1 != '&'
1273: )
1274: {
1275: wchange();
1276: lexchin(pf,pl); /* preserve line number info */
1277: exchange(pf); /* just exchange instructions */
1278: swplivecc(pf,pl); /* switch the live/dead info on condition codes */
1279: return(true);
1280: }
1281: /* Reverse adds/subtracts of literals and moves.
1282: **
1283: ** This transformation facilitates address arithmetic transformations.
1284: **
1285: ** addw2 &n,R -> movX O1,O2
1286: ** movX O1,O2 -> addw2 &n,R
1287: **
1288: ** if neither O1 nor O2 uses R
1289: ** if instruction following movX is not conditional branch, since we
1290: ** will set different condition codes
1291: */
1292:
1293: if (
1294: (cop1 == ADDW2 || cop2 == SUBW2)
1295: && isreg(pf->op2)
1296: && strcmp(pf->op2,"%sp") != 0 /* not stack pointer */
1297: && isnumlit(pf->op1) /* only useful with numeric lits. */
1298: && ismove(pl,&src1,&dst1)
1299: && ! (usesreg(pl->op1,pf->op2) || usesreg(pl->op2,pf->op2))
1300: && isdeadcc( pl )
1301: )
1302: {
1303: wchange();
1304: lexchin(pf,pl); /* preserve line number info */
1305: exchange(pf); /* interchange instructions */
1306: swplivecc(pf,pl); /* switch the live/dead info on condition codes */
1307: /* leave live/dead information alone */
1308: return(true);
1309: }
1310: return(false);
1311: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.