|
|
1.1 root 1: /* @(#) w1opt.c: 1.4 3/27/84 */
2: /* w1opt.c
3: **
4: ** 3B20S optimizer: for one-instruction window
5: **
6: **
7: */
8:
9: /* #include "defs" -- optim.h takes care of this */
10: #include "optim.h"
11: #include "optutil.h"
12:
13:
14: /* D A N G E R
15: **
16: ** This definition selects the highest numbered register that we
17: ** can arbitrarily choose as a temporary in the multiply strength
18: ** reduction that is performed below. It should equal the highest
19: ** numbered temporary register used by the compiler (1 less than
20: ** lowest numbered register used for register variables.
21: */
22:
23: #define TEMPREG 3 /* highest temp. reg. to use */
24: /* w1opt -- one-instruction optimizer
25: **
26: ** This routine handles the single-instruction optimization window.
27: ** See individual comments below about what's going on.
28: ** In some cases (which are noted), the optimizations are ordered.
29: */
30:
31: boolean /* true if we make any changes */
32: w1opt(pf,pl)
33: register NODE * pf; /* pointer to first instruction in
34: ** window (and last)
35: */
36: NODE * pl; /* pointer to last instruction in
37: ** window (= pf)
38: */
39: {
40:
41: register int cop = pf->op; /* single instruction's op code # */
42: int opn; /* temporary op code number */
43: char * opst; /* temporary op code string */
44: boolean retval = false; /* return value: in some cases
45: ** we fall through after completing
46: ** an optimization because it could
47: ** lead into others. This variable
48: ** contains the return state for the
49: ** end.
50: */
51: char * dest; /* destination string, used below */
52: long mult; /* multiplier, used below */
53: boolean f; /* random boolean flag, used below */
54: long templ; /* general long temporary */
55: /* eliminate dead code:
56: **
57: ** op2 O1,R or op3 O1,O2,R
58: ** where R is dead
59: */
60:
61: if (
62: isdead(dst(pf),pf) /* we don't really care what the op
63: ** is
64: */
65: && ! isbr(pf) /* but some branches set variables
66: ** and jump: keep them
67: */
68: && isdeadcc( pf ) /* this inst. may have side effects
69: ** relied upon by cond. branch
70: */
71: && isiros( pf->op1 )
72: && isiros( pf->op2 ) /* are operands safe for mmio */
73: )
74: {
75: wchange(); /* Note we're changing the window */
76: ldelin2(pf); /* preserve line number info */
77: mvlivecc(pf); /* preserve condition codes line info */
78: DELNODE(pf); /* discard instruction */
79: return(true); /* announce success */
80: }
81:
82: /*
83: ** cmpw R,&0 -> movw R,R
84: **
85: ** This wins on the 3B20S, but might not on other 3B processors.
86: */
87:
88: /* Although this improvement is a small win, it messes up other
89: ** transformations and generally confuses things. It's probably
90: ** better to leave it turned off.
91: */
92:
93: #ifdef CMPWTOMOVW
94:
95: if (
96: cop == CMPW
97: && isreg(pf->op1)
98: && strcmp(pf->op2,"&0") == 0
99: )
100:
101: {
102: wchange(); /* note change */
103: chgop(pf,MOVW,"movw"); /* change the op code */
104: pf->op2 = pf->op1; /* both operands point at R */
105: makelive(pf->op2,pf); /* make register appear to be live
106: ** hereafter so "compare" isn't thrown
107: ** away. (Otherwise R might be dead
108: ** and we would eliminate the inst.)
109: */
110: return(true); /* made a change */
111: }
112:
113: #endif /* def CMPWTOMOV */
114: /* get rid of useless arithmetic
115: **
116: ** addw2 &0,O -> deleted or cmpw O,&0
117: ** subw2 &0,O -> deleted or cmpw O,&0
118: ** orw2 &0,O -> deleted or cmpw O,&0
119: ** xorw2 &0,O -> deleted or cmpw O,&0
120: ** alsw2 &0,O -> deleted or cmpw O,&0
121: ** arsw2 &0,O -> deleted or cmpw O,&0
122: ** llsw2 &0,O -> deleted or cmpw O,&0
123: ** lrsw2 &0,O -> deleted or cmpw O,&0
124: ** mulw2 &1,O -> deleted or cmpw O,&0
125: ** umulw2 &1,O -> deleted or cmpw O,&0
126: ** divw2 &1,O -> deleted or cmpw O,&0
127: ** udivw2 &1,O -> deleted or cmpw O,&0
128: ** andw2 &-1,O -> deleted or cmpw O,&0
129:
130: ** addw3 &0,O1,O2 -> movw O1,O2
131: ** subw3 &0,O1,O2 -> movw O1,O2
132: ** orw3 &0,O1,O2 -> movw O1,O2
133: ** xorw3 &0,O1,O2 -> movw O1,O2
134: ** alsw3 &0,O1,O2 -> movw O1,O2
135: ** arsw3 &0,O1,O2 -> movw O1,O2
136: ** llsw3 &0,O1,O2 -> movw O1,O2
137: ** lrsw3 &0,O1,O2 -> movw O1,O2
138: ** mulw3 &1,O1,O2 -> movw O1,O2
139: ** umulw3 &1,O1,O2 -> movw O1,O2
140: ** divw3 &1,O1,O2 -> movw O1,O2
141: ** udivw3 &1,O1,O2 -> movw O1,O2
142: ** andw3 &-1,O1,O2 -> movw O1,O2
143: **
144: ** mulw2 &0,O -> movw &0,O
145: ** umulw2 &0,O -> movw &0,O
146: ** andw2 &0,O -> movw &0,O
147: ** mulw3 &0,O1,O2 -> movw &0,O2
148: ** umulw3 &0,O1,O2 -> movw &0,O2
149: ** andw3 &0,O1,O2 -> movw &0,O2
150: **
151: ** xorw2 &-1,O -> mcomw O,O
152: ** xorw3 &-1,O1,O2 -> mcomw O1,O2
153: **
154: ** mulw2 &-1,O -> mnegw O,O
155: ** divw2 &-1,O -> mnegw O,O
156: ** mulw3 &-1,O1,O2 -> mnegw O1,O2
157: ** divw3 &-1,O1,O2 -> mnegw O1,O2
158: **
159: ** Note that since we've already gotten rid of dead code, we won't
160: ** check whether O (O2) is live. However, we must be careful to
161: ** preserve the sense of result indicators if a conditional branch
162: ** follows some of these changes.
163: */
164:
165: /* Define types of changes we will make.... */
166:
167: #define UA_NOP 1 /* no change */
168: #define UA_DEL 2 /* delete instruction */
169: #define UA_MOV 3 /* change to move */
170: #define UA_MOVZ 4 /* change to move zero to ... */
171: #define UA_MCOM 5 /* change to move complemented */
172: #define UA_MNEG 6 /* change to move negated */
173: /* We must have a literal as the first operand, and its value must fit
174: ** in an integer. We check the latter condition by comparing the converted
175: ** value from atol to the same value cast as an int: they must agree.
176: ** (This is a particular problem for DMERT when they run the optimizer
177: ** on a PDP-11/70 to optimize 3B20 code.)
178: */
179: if ( isnumlit(pf->op1)
180: && (templ = atol(pf->op1+1)) == (long)((int) templ)
181: )
182: {
183: int ultype = UA_NOP; /* initial type of change = none */
184:
185: switch((int) templ) /* branch on literal */
186: {
187: case 0: /* handle all instructions with &0
188: ** as first operand
189: */
190: switch (cop)
191: {
192: case ADDW2:
193: case SUBW2:
194: case ORW2:
195: case XORW2:
196: case ALSW2:
197: case ARSW2:
198: case LLSW2:
199: case LRSW2:
200: if( !isiros( pf->op2 ) ) break;
201: ultype = UA_DEL;
202: break;
203: /* if safe from mmio,
204: ** delete all of these */
205:
206: case ADDW3:
207: case SUBW3:
208: case ORW3:
209: case XORW3:
210: case ALSW3:
211: case ARSW3:
212: case LLSW3:
213: case LRSW3:
214: ultype = UA_MOV; /* convert to simple moves */
215: break;
216:
217: case MULW2:
218: case UMULW2:
219: case ANDW2:
220: ultype = UA_MOVZ; /* convert to move zero */
221: break;
222:
223: case MULW3:
224: case UMULW3:
225: case ANDW3:
226: if( !isiros( pf->op2 ) ) break;
227: ultype = UA_MOVZ;
228: break;
229: /* if safe from mmio,
230: ** convert to move zero */
231: }
232: break; /* done &0 case */
233:
234: case 1: /* &1 case */
235: switch( cop ) /* branch on op code */
236: {
237: case DIVW2:
238: case UDIVW2:
239: case MULW2:
240: case UMULW2:
241: if( !isiros( pf->op2 ) ) break;
242: ultype = UA_DEL;
243: break;
244: /* if safe from mmio,
245: ** delete these */
246:
247: case DIVW3:
248: case UDIVW3:
249: case MULW3:
250: case UMULW3:
251: ultype = UA_MOV; /* convert these to moves */
252: break;
253: }
254: break; /* done &1 case */
255:
256: case -1: /* &-1 case */
257: switch ( cop ) /* branch on op code */
258: {
259: case ANDW2:
260: if( !isiros( pf->op2 ) ) break;
261: ultype = UA_DEL;
262: break;
263: /* if safe from mmio,
264: ** delete this */
265:
266: case ANDW3:
267: ultype = UA_MOV; /* change to move */
268: break;
269:
270: case XORW2:
271: if( !isiros( pf->op2 ) ) break;
272: ultype = UA_MCOM;
273: break;
274: /* if safe from mmio,
275: ** change to move complemented */
276:
277: case XORW3:
278: ultype = UA_MCOM; /* change to move complemented */
279: break;
280:
281: case MULW2:
282: case DIVW2:
283: if( !isiros( pf->op2 ) ) break;
284: ultype = UA_MNEG;
285: break;
286: /* if safe from mmio,
287: ** change to move complemented */
288: case MULW3:
289: case DIVW3:
290: ultype = UA_MNEG; /* change to move negated */
291: break;
292: }
293: break; /* end &-1 case */
294: } /* end switch on immediate value */
295: /* Now do something, based on selections made above */
296:
297: switch ( ultype )
298: {
299: case UA_MOV: /* change instruction to move */
300: wchange(); /* changing window */
301: pf->op1 = pf->op2; /* shift operands */
302: pf->op2 = dst(pf);
303: pf->op3 = NULL; /* in case we removed it */
304: chgop(pf,MOVW,"movw"); /* change op code */
305: retval = true; /* made a change */
306: break;
307:
308: case UA_MOVZ: /* change to move zero to operand */
309: wchange();
310: pf->op1 = "&0"; /* first operand is zero */
311: pf->op2 = dst(pf); /* second is ultimate destination */
312: pf->op3 = NULL; /* clean out if there was one */
313: chgop(pf,MOVW,"movw"); /* change op code */
314: retval = true; /* made a change */
315: break;
316:
317: case UA_MCOM: /* change to move complemented */
318: wchange();
319: pf->op1 = pf->op2; /* shift operands */
320: pf->op2 = dst(pf);
321: pf->op3 = NULL;
322: chgop(pf,MCOMW,"mcomw"); /* change op code */
323: retval = true; /* made a change */
324: break;
325:
326: case UA_MNEG: /* change to move negated */
327: wchange();
328: pf->op1 = pf->op2; /* shift operands */
329: pf->op2 = dst(pf);
330: pf->op3 = NULL;
331: chgop(pf,MNEGW,"mnegw"); /* change op code */
332: retval = true; /* made a change */
333: break;
334: /* For this case we must be careful: if a following instruction is a
335: ** conditional branch, it is clearly depending on the result of the
336: ** arithmetic, so we must put in a compare against zero instead of deleting
337: ** the instruction.
338: */
339:
340: case UA_DEL: /* delete instruction */
341:
342: wchange(); /* we will make a change */
343:
344: if ( ! isdeadcc(pf) )
345: {
346: chgop(pf,CMPW,"cmpw");
347: pf->op1 = pf->op2; /* always test second operand */
348: pf->op2 = "&0"; /* compare to zero */
349: pf->op3 = NULL; /* for completeness */
350: retval = true; /* made a change */
351: }
352: else
353: {
354: ldelin2(pf); /* preserve line number info */
355: mvlivecc(pf); /* preserve condition codes line info */
356: DELNODE(pf); /* not conditional; delete node */
357: return(true); /* say we changed something */
358: }
359: break;
360: } /* end case that decides what to do */
361:
362: cop = pf->op; /* reset current op for changed inst. */
363:
364: } /* end useless arithmetic removal */
365: /* discard useless movw's
366: **
367: ** movw O,O -> deleted
368: **
369: ** The movw must not be followed by a conditional jump, since we
370: ** must leave the condition codes set. Note that this improvement
371: ** picks up some strange code generated above, like
372: **
373: ** mulw3 &1,%r0,%r0 -> movw %r0,%r0
374: **
375: */
376:
377: if ( pf->op == MOVW
378: && strcmp(pf->op1,pf->op2) == 0
379: && isdeadcc(pf)
380: && isiros(pf->op1) /* safe from mmio */
381: )
382: {
383: wchange(); /* changing the window */
384: ldelin2(pf); /* preserve line number info */
385: mvlivecc(pf); /* preserve condition codes line info */
386: DELNODE(pf); /* delete the movw */
387: return(true);
388: }
389: /* change triadics to dyadics if possible
390: **
391: ** op3 O1,O2,O2 -> op2 O1,O2
392: **
393: */
394:
395: if (istriadic(pf,&opn,&opst)
396: && strcmp(pf->op2,pf->op3) == 0
397: && isiros(pf->op2) /* safe from mmio */
398: )
399:
400: /* triadic and last two operands match */
401:
402: {
403: wchange(); /* we're making a change */
404: chgop(pf,opn,opst); /* change the op code */
405: pf->op3 = NULL; /* so we don't keep looking at 3rd
406: ** operand
407: */
408: retval = true; /* remember that we made a change,
409: ** but don't exit, as the next
410: ** optimization may also apply.
411: */
412: cop = opn; /* changed op code */
413: }
414: /* falling through either way !! */
415: /* change multiplies and divides to shifts if power of 2 */
416:
417: /*
418: ** udivw2 &2^n,O -> lrsw2 &n,O
419: ** udivw3 &2^n,O1,O2 -> lrsw3 &n,O1,O2
420: ** mulw2 &2^n,O -> arsw2 &n,O
421: ** mulw3 &2^n,O1,O2 -> arsw3 &n,O1,O2
422: ** umulw2 &2^n,O -> llsw2 &n,O
423: ** umulw3 &2^n,O1,O2 -> llsw3 &n,O1,O2
424: **
425: ** Note that signed divide cannot safely be altered with these
426: ** transformations!
427: */
428:
429: switch (cop) /* dispatch on type */
430: {
431: int bit; /* temporary bit number if 2^n */
432:
433: case UDIVW2:
434: case UDIVW3:
435: case MULW2:
436: case MULW3:
437: case UMULW2:
438: case UMULW3:
439:
440: if ( (bit = getbit(pf->op1)) < 0) /* if not power of 2, done this */
441: break;
442:
443: wchange(); /* about to change window */
444: pf->op1 = getspace(1+2+1); /* room for &dd\0 */
445: (void) sprintf(pf->op1,"&%d",bit); /* write shift amount */
446: switch (cop) /* now change op code as needed */
447: {
448: case UDIVW2:
449: chgop(pf,LRSW2,"lrsw2"); break;
450: case UDIVW3:
451: chgop(pf,LRSW3,"lrsw3"); break;
452: case MULW2:
453: chgop(pf,ALSW2,"alsw2"); break;
454: case MULW3:
455: chgop(pf,ALSW3,"alsw3"); break;
456: case UMULW2:
457: chgop(pf,LLSW2,"llsw2"); break;
458: case UMULW3:
459: chgop(pf,LLSW3,"llsw3"); break;
460: }
461: retval = true; /* we changed something */
462: cop = pf->op; /* changed op code, too */
463: }
464:
465: #ifndef M32 /* applies only to 3B20S */
466:
467: /* The 3B20 can do shifts and adds faster than multiplies for small
468: ** integer multipliers where the result ends up in a register. Here
469: ** we pick such multiplies apart, arbitrarily stopping at 10 as an
470: ** upper bound.
471: */
472:
473: if (
474: (
475: cop == MULW2
476: || cop == MULW3
477: )
478: && *pf->op1 == '&' /* multiplier is small literal */
479: && isreg(dest = (cop == MULW2 ? pf->op2 : pf->op3))
480: /* remember dest.; must be reg. */
481: && (mult = atol(pf->op1+1)) > 2/* positive multiplier (exclude
482: ** 0, 1, 2
483: */
484: && mult <= 10 /* arbitrary upper limit */
485: )
486: {
487: static char regstring[] = "%rx";/* boiler-plate register name */
488: char * temp = NULL; /* string representing temp. used
489: ** during "multiply"
490: */
491: NODE * new; /* pointer to new instruction node */
492:
493: /* The approach works like this:
494: **
495: ** 1. Identify destination register and temporary register that
496: ** we will need to use.
497: ** 2. Determine live/dead data for new instructions.
498: ** 3. Add new instructions after the MULW_, but holding on to the
499: ** MULW_ as an anchor (since pf points at it).
500: ** 4. Delete MULW_ when done.
501: **
502: ** Note that the instruction sequences we create always set the
503: ** result indicators the same as if a multiply had been done.
504: */
505:
506: /* Macro to add new instruction:
507: ** ptr points to instruction to add after
508: ** opn op code number of new instruction
509: ** opst op code string of instruction
510: ** opn1 operand 1 for new instruction
511: ** opn2 operand 2 for new instruction
512: ** ld live/dead data for new instruction
513: */
514:
515: #define addinst(ptr,opn,opst,opn1,opn2,ld) \
516: { \
517: last = insert(ptr); /* get new node */ \
518: chgop(last,opn,opst); /* put in op code number, string */ \
519: last->op1 = opn1; /* put in operands */ \
520: last->op2 = opn2; \
521: last->nlive = ld; /* put in live/dead info. */ \
522: }
523: /* Identify temporary and destination registers.
524: **
525: ** Destination is already in 'dest': the destination of the MULW_.
526: ** 'temp' must be chosen for MULW2 or for MULW3 where the second
527: ** operand is not already in a register.
528: */
529:
530: /* f will remember whether we needed to "create" a temporary.
531: ** We must do so for MULW2 or for MULW3 when 2nd operand not a reg.
532: */
533:
534: if ( f = (
535: cop == MULW2 /* inst. is MULW2 */
536: || ! isreg(pf->op2) /* MULW3 2nd operand not reg. */
537: )
538: )
539:
540: {
541: int j; /* register number */
542:
543: /* We're going to loop, trying to find a register to steal.
544: ** Then we save a copy of the appropriate register string for
545: ** the instructions we'll build.
546: */
547:
548: for ( j = '0' + TEMPREG; j >= '0'; j--) /* go down from highest */
549: {
550: regstring[2] = (char) j; /* stick char in string */
551: if (isdead(regstring,pf)) /* if dead, we can use it */
552: {
553: temp = strcpy(getspace(sizeof regstring),regstring);
554: break;
555: }
556: }
557: } /* end if that builds a temp. string */
558: else /* MULW3 had reg. as 2nd operand */
559: temp = pf->op2; /* point at it as suitable temporary */
560:
561: /* 'dest' and 'temp' now point at suitable strings representing registers.
562: ** Although we're not sure about the multiplier value, we know powers of
563: ** 2 have already been handled. Therefore there is no danger of allocating
564: ** a string above without actually using it.
565: */
566: /* Build correct instruction sequence. */
567:
568: if (temp != NULL) /* make sure we got a temporary */
569: {
570: NODE * last = pf; /* remember last node in sequence */
571: int ld; /* current live/dead bits */
572:
573: wchange(); /* tell the world we're changing */
574:
575: /* Set up live/dead data. We want to replicate the information in
576: ** the current multiply node, plus we want to set 'temp' and 'dest'
577: ** registers live.
578: */
579:
580: makelive(dest,pf); /* set destination live */
581: ld = pf->nlive; /* remember data */
582:
583: if (cop == MULW3) /* On MULW3 we must load the dest. */
584: addinst(last,MOVW,"movw",pf->op2,dest,ld);
585:
586: /* Now we change the live/dead information so 'temp' will appear live */
587:
588: makelive(temp,pf);
589: ld = pf->nlive;
590:
591: /* If we created a temp, move the current destination (multiplicand)
592: ** there now.
593: */
594:
595: if (f)
596: addinst(last,MOVW,"movw",dest,temp,ld);
597:
598: /* Now generate instruction sequences based on multiplier. */
599:
600: switch ((int) mult) /* value known to be between 2, 10 */
601: {
602: case 3:
603: addinst(last,LLSW2,"llsw2","&1",dest,ld); /* *2 */
604: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *3 */
605: break;
606: case 5:
607: addinst(last,LLSW2,"llsw2","&2",dest,ld); /* *4 */
608: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *5 */
609: break;
610: case 6:
611: addinst(last,LLSW2,"llsw2","&2",dest,ld); /* *4 */
612: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *5 */
613: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *6 */
614: break;
615: case 7:
616: addinst(last,LLSW2,"llsw2","&3",dest,ld); /* *8 */
617: addinst(last,SUBW2,"subw2",temp,dest,ld); /* *7 */
618: break;
619: case 9:
620: addinst(last,LLSW2,"llsw2","&3",dest,ld); /* *8 */
621: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *9 */
622: break;
623: case 10:
624: addinst(last,LLSW2,"llsw2","&3",dest,ld); /* *8 */
625: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *9 */
626: addinst(last,ADDW2,"addw2",temp,dest,ld); /* *10 */
627: break;
628: }
629: /* Done generating instructions. Now clean up.
630: ** First, fix up live/dead data so temp is dead after last
631: ** instruction. Then kill old node.
632: */
633:
634: makedead(temp,last);
635: ldelin(pf); /* preserve line number info */
636: DELNODE(pf); /* delete the multiply */
637: return(true); /* we-ve changed something */
638: } /* end if, testing for NULL temp */
639: } /* end if, testing for multiply */
640:
641: #endif /* ndef M32 */
642:
643: #ifndef M32 /* 3B20 only */
644:
645: /* The 3B20 has special instructions to move a positive nibble to a
646: ** register. It does less well with negative ones, since it puts
647: ** them in a large immediate value. The following transformation
648: ** runs faster for small negative constants.
649: **
650: ** movw &-n,R -> movw &n,R
651: ** -> mnegw R,R
652: **
653: ** when 1 <= n <= 15
654: */
655:
656: if (
657: cop == MOVW
658: && isreg(pf->op2)
659: && isnegnib(pf->op1)
660: )
661: {
662: NODE * new = insert(pf); /* make new node after pf */
663:
664: wchange(); /* we're making changes */
665: *(pf->op1 = copyopn(pf->op1,-1,1)) = '&';
666: /* copy operand, offset by 1,
667: ** overwrite - with &
668: */
669: chgop(new,MNEGW,"mnegw"); /* fill in new node */
670: new->op1 = new->op2 = pf->op2;
671: new->nlive = pf->nlive; /* replicate live/dead data for new
672: ** node so it won't go away
673: */
674: return(true);
675: }
676:
677: #endif /* ndef M32 */
678:
679: #ifndef M32 /* 3B20 only */
680:
681: /* From empirical studies it appears that triadic instructions should
682: ** not be used on the 3B20S when the destination is a register, because
683: ** an equivalent two-instruction sequence is faster. The same applies
684: ** in another specialized triadic case below.
685: **
686: ** op3 O1,O2,R -> movw O2,R
687: ** -> op2 O1,R
688: **
689: ** if R not used in O1
690: **
691: **
692: ** op3 &n,R,O -> op2 &n,R
693: ** -> movw R,O
694: **
695: ** if R is dead
696: */
697:
698: if (istriadic(pf,&opn,&opst)) /* check triadic, save equiv. op code
699: ** number and string
700: */
701: {
702:
703: /* first case: op3 O1,O2,R */
704:
705: if ( isreg(pf->op3) && ! usesreg(pf->op1,pf->op3) )
706: /* check R not used in O1 */
707: {
708: NODE * new = insert(pf); /* add new node after pf */
709:
710: wchange(); /* changing something */
711:
712: chgop(new,opn,opst); /* set up new node with dyadic */
713: new->op1 = pf->op1; /* set O1 */
714: new->op2 = pf->op3; /* set R */
715: new->nlive = pf->nlive; /* propagate live/dead stuff */
716:
717: chgop(pf,MOVW,"movw"); /* modify original node */
718: pf->op1 = pf->op2; /* make first operand O2 */
719: pf->op2 = pf->op3; /* second is R */
720: pf->op3 = NULL; /* clean up third one */
721: makelive(pf->op2,pf); /* force R live; R may be dead
722: ** after pl if pl is followed by a
723: ** conditional branch. We must make
724: ** it live here.
725: */
726: return(true);
727: }
728: else if (isnib(pf->op1) && isdead(pf->op2,pf))
729: /* (test for register implicit in "isdead") */
730:
731: /* second case: op3 &n,R,O */
732:
733: {
734: NODE * new = insert(pf); /* add new following node */
735:
736: wchange(); /* changing something */
737:
738: chgop(pf,opn,opst); /* put dyadic in first node */
739:
740: chgop(new,MOVW,"movw"); /* second node is MOVW */
741: new->op1 = pf->op2; /* set R */
742: new->op2 = pf->op3; /* set O */
743: new->nlive = pf->nlive; /* propagate live/dead in movw */
744: makelive(pf->op2,pf); /* make R live after op2 */
745:
746: pf->op3 = NULL; /* clean out 3rd operand of original */
747: return(true);
748: }
749: }
750:
751: #endif /* ndef M32 */
752:
753: #ifdef IMPLLSW
754:
755: /* For BELLMAC-32, a shift by one bit is more efficiently
756: ** done as an add.
757: **
758: ** llsw2 &1,O1 -> addw2 O1,O1
759: **
760: ** llsw3 &1,O1,O2 -> addw3 O1,O1,O2
761: **
762: */
763:
764: {
765: if( strcmp( pf->op1, "&1" ) == 0
766: && isiros(pf->op2) /* safe from mmio */
767: ) {
768: if( pf->op == LLSW2 ) {
769: chgop( pf, ADDW2, "addw2" );
770: pf->op1 = pf->op2;
771: return( true );
772: }
773: if( pf->op == LLSW3 ) {
774: chgop( pf, ADDW3, "addw3" );
775: pf->op1 = pf->op2;
776: return( true );
777: }
778: }
779: }
780: #endif /* IMPLLSW */
781:
782: return(retval); /* indicate whether anything changed */
783: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.