|
|
1.1 root 1: /* @(#) optutil.c: 1.3 3/27/84 */
2: /* optutil.c
3: **
4: ** Optimizer utilities for 3B code improver (PCI).
5: **
6: **
7: ** This module contains utility routines for the various peephole
8: ** window optimizations.
9: */
10:
11: /* #include <ctype.h> -- optim.h takes care of this */
12: /* #include "defs" -- optim.h takes care of this; machine-dependent defs */
13: #include "optim.h" /* machine independent optimizer defs */
14:
15: extern long atol();
16: /* isreg -- is operand string a register reference?
17: **
18: ** This routine tells whether an operand string is a register reference.
19: */
20:
21: boolean
22: isreg(s)
23: char * s; /* operand string */
24: {
25: /* assume operand is a register reference if it begins with a % */
26:
27: return(*s == '%');
28: }
29:
30:
31:
32: /* isnib -- is operand a nibble?
33: **
34: ** This routine tests an operand string and tells whether it is an
35: ** immediate operand that can fit in a nibble (4 bits).
36: */
37:
38: boolean
39: isnib(s)
40: char * s; /* operand string to check */
41: {
42: long x; /* temporary to hold value */
43:
44: /* Return true if the operand begins with a '&', it is numeric,
45: ** and the numeric value is between 0 and 15.
46: */
47:
48: return( *s == '&' /* begins with & */
49: && isdigit(*++s) /* operand is numeric */
50: && (x = atol(s)) >= 0 /* is positive */
51: && x <= 15 /* and <= 15 */
52: );
53: }
54: /* isnegnib -- is operand a negative nibble?
55: **
56: ** This routine tests whether an operand string is an immediate operand
57: ** with a value between -1 and -15. Another condition tested is that
58: ** the minus sign immediately follows an '&'. (This condition is
59: ** important if the operand is overwritten.)
60: */
61:
62: boolean
63: isnegnib(s)
64: char * s; /* operand string */
65: {
66: long n; /* temporary operand value */
67:
68: return(
69: s != NULL
70: && *s++ == '&' /* operand starts with & */
71: && *s++ == '-' /* followed by - */
72: && isdigit(*s) /* operand is numeric */
73: && 1 <= (n = atol(s)) /* (positive) value between 1... */
74: && n <= 15 /* and 15 */
75: );
76: }
77: /* getbit -- get bit number for power of 2
78: **
79: ** This routine tests whether an operand is a power of 2. If not, it
80: ** returns -1. Otherwise it returns a bit number, which is also the
81: ** exponent of 2.
82: */
83:
84: int
85: getbit(s)
86: char * s; /* pointer to operand string */
87: {
88: int bit = 0; /* initialize bit number for later */
89: long n; /* numeric value of operand */
90: boolean isnumlit();
91:
92: if ( (! isnumlit(s)) || (n = atol(s+1)) < 0 )
93: return(-1); /* check for numeric literal with
94: ** good value
95: */
96:
97: /* This test really works, although it looks suspicious. A power of two
98: ** has only one bit set, so that value minus one has all of the bits to
99: ** the right of the original bit set. Anding them together gives zero.
100: ** No other value yields zero.
101: */
102:
103: if ( ( n & (n-1) ) != 0)
104: return(-1); /* not a power of 2 */
105:
106: /* Shift right until the word is zero */
107:
108: while ((n = n>>1) != 0)
109: bit++; /* bump bit number each time */
110:
111: return(bit); /* return bit number */
112: }
113: /* insert -- insert new instruction node
114: **
115: ** This routine inserts a new instruction node after the one pointed
116: ** to. The fields in the node are initialized to null values.
117: */
118:
119: NODE * /* return pointer to the new node */
120: insert(pn)
121: NODE * pn; /* node to add pointer after */
122: {
123: NODE * Saveop(); /* in machine-independent part */
124: NODE * new = Saveop(0,"",0,GHOST); /* create isolated node, init. */
125:
126: APPNODE(new,pn); /* append new node after current */
127:
128: return(new); /* return pointer to the new one */
129: }
130: /* chgop -- change op code number and op code string in node
131: **
132: ** This routine changes the op code information in a node. The
133: ** operand information is unaffected.
134: */
135:
136: void
137: chgop(n,op,op_code)
138: NODE * n; /* pointer to node to change */
139: int op; /* op code number */
140: char * op_code; /* pointer to op code string */
141: {
142: n->op = op; /* set op code number */
143: n->opcode = op_code; /* and string */
144: return;
145: }
146: /* copyopn -- copy operand string
147: **
148: ** This routine duplicates an operand string in a new piece of memory.
149: ** The caller can specify a +/- number of additional bytes required,
150: ** as well as an offset for copying.
151: */
152:
153: char * /* return duplicate string */
154: copyopn(s,extra,offset)
155: char * s; /* original operand string */
156: int extra; /* number of extra (or fewer) chars */
157: int offset; /* offset in original operand from
158: ** which to start copying.
159: */
160: {
161: int len = strlen(s) + extra; /* length of duplicate */
162: char * stemp; /* future duplicate string */
163:
164: if (len <= 0)
165: return(NULL); /* deleted everything */
166:
167: stemp = getspace(len+1); /* get new string (+1 for null byte) */
168: return(strcpy(stemp,s+offset)); /* return copy */
169: }
170: /* isdyadic -- is instruction dyadic
171: **
172: ** This routine tells whether an instruction is dyadic according
173: ** to the following conditions:
174: **
175: ** 1. It takes two operands.
176: ** 2. It reads the first operand, writes the second.
177: ** 3. It sets the condition codes according to the value stored in
178: ** the second operand.
179: ** 4. The operands have normal address mode meanings: disallow,
180: ** for example, MOVAW, which does address arithmetic of op1.
181: */
182:
183: boolean
184: isdyadic(n)
185: NODE * n; /* instruction node to test */
186: {
187: switch(n->op) /* dispatch on op code number */
188: {
189: case MCOMW:
190: case MOVZBH:
191: case MOVZBW:
192: case MOVZHW:
193: case ANDW2:
194: case ORW2:
195: case XORW2:
196: case LLSW2:
197: case LRSW2:
198: case MOVW:
199: case MOVBBH:
200: case MOVBBW:
201: case MOVBHW:
202: case MOVTHB:
203: case MOVTWB:
204: case MOVTWH:
205: case MNEGW:
206: case ADDW2:
207: case SUBW2:
208: case MULW2:
209: case UMULW2:
210: case DIVW2:
211: case UDIVW2:
212: case UMODW2:
213: case ALSW2:
214: case ARSW2:
215: return(true); /* all of these are dyadic */
216: default:
217: return(false); /* others are not */
218: }
219: }
220: /* istriadic -- is instruction triadic?
221: **
222: ** This routine serves a similar function to isdyadic, except that
223: ** it also returns the related dyadic op code number and string.
224: ** The only instructions included here are the obvious ones. They
225: ** are assumed to have integer operands (by callers).
226: */
227:
228: /* define macro to use below */
229:
230: #define CHANGE(op,new,newst) case op: *pnewop=new;*pnewopcode=newst;break;
231:
232:
233: boolean
234: istriadic(n,pnewop,pnewopcode)
235: NODE * n; /* node to test */
236: int * pnewop; /* place to put equiv. dyadic # */
237: char ** pnewopcode; /* place to put equiv. dyadic string */
238: {
239: switch (n->op) /* dispatch on op code number */
240: {
241: CHANGE(ADDW3,ADDW2,"addw2");
242: CHANGE(SUBW3,SUBW2,"subw2");
243: CHANGE(MULW3,MULW2,"mulw2");
244: CHANGE(UMULW3,UMULW2,"umulw2");
245: CHANGE(DIVW3,DIVW2,"divw2");
246: CHANGE(UDIVW3,UDIVW2,"udivw2");
247: CHANGE(MODW3,MODW2,"modw2");
248: CHANGE(UMODW3,UMODW2,"umodw2");
249: CHANGE(ALSW3,ALSW2,"alsw2");
250: CHANGE(ARSW3,ARSW2,"arsw2");
251: CHANGE(ANDW3,ANDW2,"andw2");
252: CHANGE(ORW3,ORW2,"orw2");
253: CHANGE(XORW3,XORW2,"xorw2");
254: CHANGE(LLSW3,LLSW2,"llsw2");
255: CHANGE(LRSW3,LRSW2,"lrsw2");
256: default: /* for op codes not found */
257: return(false);
258: }
259: return(true); /* found op code */
260: }
261: /* totriadic -- can dyadic be made triadic?
262: **
263: ** This routine checks a dyadic instruction to see if it can be
264: ** made triadic. If so, it returns the opcode number and string
265: ** for the corresponding triadic. Totriadic is really the inverse
266: ** of istriadic.
267: */
268:
269: boolean
270: totriadic(n,pnewop,pnewopcode)
271: NODE * n; /* node to test */
272: int * pnewop; /* place to put equiv. triadic # */
273: char ** pnewopcode; /* place to put equiv. triadic string */
274: {
275: switch (n->op) /* dispatch on op code number */
276: {
277: CHANGE(ADDW2,ADDW3,"addw3");
278: CHANGE(SUBW2,SUBW3,"subw3");
279: CHANGE(MULW2,MULW3,"mulw3");
280: CHANGE(UMULW2,UMULW3,"umulw3");
281: CHANGE(DIVW2,DIVW3,"divw3");
282: CHANGE(UDIVW2,UDIVW3,"udivw3");
283: CHANGE(MODW2,MODW3,"modw3");
284: CHANGE(UMODW2,UMODW3,"umodw3");
285: CHANGE(ALSW2,ALSW3,"alsw3");
286: CHANGE(ARSW2,ARSW3,"arsw3");
287: CHANGE(ANDW2,ANDW3,"andw3");
288: CHANGE(ORW2,ORW3,"orw3");
289: CHANGE(XORW2,XORW3,"xorw3");
290: CHANGE(LLSW2,LLSW3,"llsw3");
291: CHANGE(LRSW2,LRSW3,"lrsw3");
292: default: /* for op codes not found */
293: return(false);
294: }
295: return(true); /* found op code */
296: }
297: /* makelive -- make register live
298: **
299: ** This routine marks a register operand as live.
300: */
301:
302: void
303: makelive(s,n)
304: char * s; /* operand string (to %r0) */
305: NODE * n; /* pointer to node to enliven */
306: {
307: n->nlive |= setreg(s);
308: return;
309: }
310:
311:
312:
313: /* makedead -- make register dead
314: **
315: ** This routine marks a register operand as dead.
316: */
317:
318: void
319: makedead(s,n)
320: char * s; /* operand string (to %rn) */
321: NODE * n; /* pointer to node to kill */
322: {
323: n->nlive &= ~ setreg(s);
324: return;
325: }
326: /* isindex -- is operand an index off a register?
327: **
328: ** This routine checks whether an operand string is of the
329: ** form:
330: **
331: ** n(%rn)
332: **
333: ** and whether it uses a designated register.
334: **
335: ** Actually, it cheats: it just checks for an initial digit or sign followed
336: ** by a (. In fact the ( test is a cheat, because we just check to see
337: ** if there's a ( in the string.
338: */
339:
340: boolean
341: isindex(s,r)
342: char * s; /* operand string to test */
343: char * r; /* register operand string to check
344: ** for
345: */
346:
347: {
348: char * strchr();
349:
350: if(*s == '*')
351: s++;
352: return(
353: usesreg(s,r)
354: && (isdigit(*s) || *s == '-') /* could be leading sign, too */
355: && strchr(s,'(') != (char *) 0
356: );
357: }
358: /* ismove -- is instruction a move?
359: **
360: ** This routine determines whether an instruction is a move-type.
361: ** There is a multiplicity of move instructions which copy, zero-
362: ** or sign-extend, and truncate. This routine returns the natural
363: ** size of the source and destination operands.
364: */
365:
366: boolean
367: ismove(n,srcsize,dstsize)
368: NODE * n; /* pointer to instruction node */
369: int * srcsize; /* place to put size of source
370: ** operand (in bytes)
371: */
372: int * dstsize; /* place to put size of destination */
373: {
374: register int srctemp = 1; /* temporary source size */
375: register int dsttemp = 4; /* temporary destination size */
376: /* Initial values chosen on basis of most common value of each. */
377:
378: switch (n->op) /* dispatch on op-code number */
379: {
380: case MOVZBH:
381: dsttemp = 2; break;
382: case MOVZBW:
383: break;
384: case MOVZHW:
385: srctemp = 2; break;
386:
387: case MOVB:
388: dsttemp = 1; break;
389: case MOVH:
390: srctemp = 2; dsttemp = 2; break;
391: case MOVW:
392: srctemp = 4; break;
393:
394: case MOVBBH:
395: dsttemp = 2; break;
396: case MOVBBW:
397: break;
398: case MOVBHW:
399: srctemp = 2; break;
400:
401: case MOVTHB:
402: srctemp = 2; dsttemp = 1; break;
403: case MOVTWB:
404: srctemp = 4; dsttemp = 1; break;
405: case MOVTWH:
406: srctemp = 4; dsttemp = 2; break;
407: default:
408: return(false); /* not a move instruction */
409: }
410: *srcsize = srctemp; /* copy out correct values */
411: *dstsize = dsttemp;
412: return(true); /* found a move */
413: }
414: /* iszoffset -- is operand zero offset from register
415: **
416: ** This routine determines whether a given operand is an indexed
417: ** operation from a designated register, where the index is zero.
418: */
419:
420: boolean
421: iszoffset(operand,reg)
422: register char * operand; /* operand string */
423: char * reg; /* register string */
424: {
425:
426: /* We use a quick and dirty strategy here: we test the operand for
427: ** zero, followed by (, with matching register numbers in the right
428: ** place. We assume register designations are "%rn".
429: */
430:
431: return(
432: *operand == '0'
433: && *(operand+1) == '('
434: && *(operand+4) == *(reg+2)
435: );
436: }
437: /* exchange -- exchange node and successor
438: **
439: ** This routine reverses the linkages of two nodes so the first is
440: ** the second and the second is the first.
441: */
442:
443: void
444: exchange(first)
445: NODE * first; /* pointer to first of two nodes */
446: {
447:
448: /* This can probably be done with fewer temporaries, but it's a lot
449: ** easier to understand what's going on this way....
450: */
451:
452: NODE * prev = first->back; /* predecessor of first node */
453: NODE * second = first->forw; /* second node of pair to exchange */
454: NODE * next = second->forw; /* successor of second node */
455:
456: prev->forw = second; /* second will now be first */
457: second->back = prev;
458:
459: first->forw = next; /* successor of old first is now
460: ** 'next'
461: */
462: next->back=first; /* 'next's' predecessor now 'first' */
463:
464: second->forw = first;
465: first->back = second; /* re-link connection of node pair */
466:
467: return;
468: }
469: /* doindirect -- resolve indirect references
470: **
471: ** This routine changes variable references of the form
472: ** 0(%rn)
473: ** to
474: ** *var
475: ** where possible. Its purpose is to make it possible to discard a
476: ** register load.
477: **
478: ** Here's the scenario: we're handed an instruction, the name of the
479: ** register whose zero-index use we want to change, and the real location
480: ** of the variable. For example, in the sequence
481: **
482: ** movw xyz,%r0
483: ** addw2 0(%r0),%r1
484: **
485: ** the instruction we would be handed is the addw2, the register would be
486: ** %r0, and the real location of the variable is 'xyz'.
487: **
488: ** Complications:
489: ** 1. The register must be dead after the instruction.
490: ** 2. We want to change all such references in the instruction.
491: ** 3. If there are any other uses of the register than a zero
492: ** index, like actually using the register contents or
493: ** using an index other than zero (e.g., 4(%r0)), we
494: ** can't make the transformation, since we're going to
495: ** eliminate the preceding register load.
496: ** 4. ... except that if the destination of a triadic instruction or
497: ** move is the register it's safe to proceed.
498: **
499: ** One, possibly unsafe assumption:
500: ** The algorithm assumes that unused operands in an instruction (like
501: ** operands 3 and 4 in a dyadic) are always NULL. We also assume that
502: ** an instruction has a "destination" (returned by 'dst') if and only
503: ** if it can alter something. We further assume that the destination
504: ** is always the last operand.
505: */
506:
507: boolean /* true if the transformation
508: ** was made
509: */
510: doindirect(n,reg,repl)
511: NODE * n; /* instruction node to examine */
512: char * reg; /* register (string) to look for */
513: char * repl; /* operand string to use */
514: {
515: boolean first = true; /* if examining first real operand */
516: int indmask = 0; /* will have bits set telling which
517: ** operands to change
518: */
519: int i; /* loop index */
520: char * operand; /* current operand */
521: int src,dest; /* for ismove (but unused) */
522: /* Begin: check whether transformation can be made, note which operands
523: ** to change if so.
524: */
525:
526: if (
527: isret(n) /* will show register dead, which
528: ** will confuse us
529: */
530: || ! (
531: isdead(reg,n) /* reg must be dead after n */
532: || ( ismove(n,&src,&dest) && samereg(n->op2,reg) )
533: ) /* unless set by this inst. as move */
534: || *repl == '*' /* can't do it if replacement is
535: ** already an indirect...
536: */
537: || *repl == '&' /* or an immediate */
538: )
539: return(false); /* can't do it */
540:
541: /* Now scan operands for things that can't be transformed. We do this
542: ** backward from higher numbered operands on the assumption that a
543: ** destination, which we treat differently, is the highest numbered
544: ** non-null operand.
545: */
546:
547: for ( i = MAXOPS; i > 0; i-- )
548: {
549: int opn; /* op code number in istriadic */
550: char * opst; /* op code string in istriadic */
551:
552: if ( (operand = n->ops[i]) != NULL )
553: { /* found an operand */
554: if (iszoffset(operand,reg)) /* this is what we want! */
555: indmask |= 1<<i; /* remember where it is */
556:
557: /* otherwise can only use register if this is the last
558: ** operand (but the first we'll find) and the instruction
559: ** is triadic
560: */
561:
562: else if (
563: ! ( samereg(operand,reg)
564: && first
565: && (
566: istriadic(n,&opn,&opst)
567: || ismove(n,&src,&dest)
568: )
569: )
570: && usesreg(operand,reg)
571: )
572: return(false); /* bad use of register */
573:
574: first = false; /* no longer looking at first (last)
575: ** operand
576: */
577: }
578: }
579: /* Reaching here, we have successfully scanned all operands without
580: ** finding any register references that violate the required conditions.
581: */
582:
583: if (indmask == 0) /* if no register references... */
584: return(false); /* say we didn't change anything */
585: if ( !isiros(repl) ) return( false ); /* check for mmio */
586: /* Now we're ready to do the actual transformations. If the replacement
587: ** operand is a register reference, we create a new operand reference
588: ** of the form:
589: ** 0(reg) --> 0(repl)
590: **
591: ** Otherwise we have a vanilla operand. Rewrite it as
592: **
593: ** 0(reg) --> *repl
594: */
595:
596: { /* for some more variables */
597: char * indstring; /* new operand string */
598: int extra; /* number of extra chars in xform */
599: char * format; /* sprintf format string for xform */
600:
601: if (isreg(repl)) /* replacement is also reference */
602: {
603: format = "0(%s)"; /* to form 0(repl) */
604: extra = 3; /* for 0 ( ) */
605: }
606: else
607: {
608: format = "*%s"; /* rewrite as *repl */
609: extra = 1; /* prepend * only */
610: }
611:
612: indstring = getspace(strlen(repl) + extra + 1);
613: /* allocate space + 1 for null */
614: (void) sprintf(indstring,format,repl);
615: /* build replacement */
616:
617: wchange(); /* Finally! About to make changes */
618:
619: /* loop through operands, replacing ones whose bit is set in mask */
620:
621: for ( i = MAXOPS; i > 0; i-- )
622: {
623: if ( (indmask & (1<<i)) != 0)
624: n->ops[i] = indstring; /* stick in replacement string */
625: }
626:
627: return(true); /* say we changed stuff */
628: } /* end extra block */
629: }
630: /* isnumlit -- is operand a numeric literal
631: **
632: ** This routine tests operand strings for the form
633: **
634: ** &[-]n
635: **
636: ** where n is a positive integer.
637: */
638:
639: boolean
640: isnumlit(s)
641: char * s; /* pointer to operand string */
642: {
643: if (*s++ != '&')
644: return(false);
645:
646: if (*s == '-') /* sign okay */
647: s++;
648:
649: while (*s != '\0') /* check for all digits */
650: if ( ! isdigit(*s++) )
651: return(false);
652:
653: return(true); /* passed all tests */
654: }
655: /* usesvar -- does first operand use second?
656: **
657: ** This routine is a generalization of "usesreg": it returns true
658: ** if the first operand uses the second. An example is
659: ** v1 = "*p", v2 = "p". v1 uses the contents of v2.
660: */
661:
662: boolean
663: usesvar(v1,v2)
664: char * v1; /* using operand */
665: char * v2; /* used operand */
666: {
667: if (isreg(v2) && usesreg(v1,v2))
668: return(true); /* handle register case specially */
669:
670: if (*v1 == '*') /* check for initial indirect */
671: v1++;
672:
673: return(strcmp(v1,v2) == 0); /* result is result of compare */
674: }
675:
676:
677: /* These routines try to preserve the line number information.
678: The criterion for saving or discarding line number information is
679: that the state of the machine from a C point of view should be the
680: same at any given line both before and after the optimization.
681: If it would not be then the line number is deleted.
682: The exceptions to the above are that the state of the condition codes
683: and of dead registers is ignored.
684:
685: May 1983 */
686:
687: /* NOTE: All instruction nodes that these routines assume will be tossed
688: have their uniqids set to IDVAL. For example, in the merges,
689: the uniqids of the original instructions are set to IDVAL
690: and then the uniqid of the resultant instruction is computed.
691: This has the effect of setting the uniqid of the instruction
692: not corresponding to the resultant to IDVAL. This fact is used
693: in some instances where lnmrginst2 is called -- see w2opt.c */
694:
695: /* delete instruction -- save line number
696: if the instruction below has no line number or has a line number
697: greater than the present instruction, the present number
698: is transfered down */
699:
700: void
701: ldelin(nodep)
702: NODE * nodep;
703: {
704: if(nodep->uniqid == IDVAL)
705: return;
706:
707: if(nodep->forw != &ntail &&
708: (nodep->forw->uniqid > nodep->uniqid
709: || nodep->forw->uniqid == IDVAL))
710: nodep->forw->uniqid = nodep->uniqid;
711:
712: nodep->uniqid = IDVAL;
713:
714: }
715:
716: /* more conservative version of lndelinst that does not overwrite
717: line numbers below */
718: void
719: ldelin2(nodep)
720: NODE *nodep;
721: {
722: if(nodep == IDVAL)
723: return;
724:
725: if(nodep->forw != &ntail && nodep->forw->uniqid == IDVAL)
726: nodep->forw->uniqid = nodep->uniqid;
727:
728: nodep->uniqid = IDVAL;
729:
730: }
731:
732:
733: /* exchange instructions
734: The line number of the first instruction, if any, is given to the
735: second instruction. The line number of the second instruction is
736: deleted. */
737: void
738: lexchin(nodep1,nodep2)
739: NODE *nodep1, *nodep2;
740: {
741: if(nodep1->uniqid != IDVAL) {
742: nodep2->uniqid = nodep1->uniqid;
743: nodep1->uniqid = IDVAL;
744: }
745: else {
746: nodep2->uniqid = IDVAL;
747: }
748: }
749:
750:
751: /* merge instructions - case 1
752: The result instruction is given the line number of the
753: top instruction, if it exists, or else it is given the line
754: number of the bottom instruction. */
755: void
756: lmrgin1(nodep1,nodep2,resnode)
757: NODE *nodep1, *nodep2, *resnode;
758: {
759: IDTYPE val1, val2;
760:
761: val1 = nodep1->uniqid;
762: val2 = nodep2->uniqid;
763:
764: nodep1->uniqid = nodep2->uniqid = IDVAL;
765:
766: if(val1 != IDVAL)
767: resnode->uniqid = val1;
768: else
769: resnode->uniqid = val2;
770:
771: }
772:
773:
774: /* instruction merge - case 2
775: The resultant instruction is given the line number of the
776: top instruction, if it exists, else it is not given a line number */
777: void
778: lmrgin2(nodep1,nodep2,resnode)
779: NODE *nodep1, *nodep2, *resnode;
780: {
781: IDTYPE val1;
782:
783: val1 = nodep1->uniqid;
784:
785: nodep1->uniqid = nodep2->uniqid = IDVAL;
786:
787: resnode->uniqid = val1;
788:
789: }
790:
791: /* instruction merge - case 3
792: The resultant instruction is given the line number of the first
793: instruction, if it exists. The instruction below the pair to be
794: merged is given the line number of the second instruction,
795: if it exists */
796: void
797: lmrgin3(nodep1,nodep2,resnode)
798: NODE *nodep1, *nodep2, *resnode;
799: {
800: IDTYPE val1;
801:
802: ldelin2(nodep2);
803:
804: val1 = nodep1->uniqid;
805:
806: nodep1->uniqid = nodep2->uniqid = IDVAL;
807:
808: resnode->uniqid = val1;
809: }
810:
811: /* isiros -- is operand either immediate, register or on stack?
812: **
813: ** This routine returns true if the the operand
814: ** pointed to by its argument has address mode
815: **
816: ** immediate,
817: ** register, or
818: ** offset from a stack pointer (fp, ap, or sp).
819: **
820: ** This test is provided for checking operands to see whether they
821: ** can be memory mapped i/o references.
822: */
823:
824: boolean
825: isiros( op )
826: char *op;
827: {
828: return( *op == '&' ||
829: *op == '%' ||
830: ( *op != '*' &&
831: ( usesreg( op, "%fp" ) ||
832: usesreg( op, "%ap" ) ||
833: usesreg( op, "%sp" )
834: )
835: )
836: );
837: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.