|
|
1.1 root 1: /*
2: * C compiler.
3: * Jump and shape optimization.
4: * Jump to jump, etc.
5: * Common sequences.
6: * Cross jumping.
7: */
8: #ifdef vax
9: #include "INC$LIB:cc2.h"
10: #else
11: #include "cc2.h"
12: #endif
13:
14: #define NLHASH 64
15: #define LHMASK 077
16:
17: static INS *labhash[NLHASH];
18:
19: /*
20: * Shuffle segments,
21: * Move all non 'SHRI' segments to the front,
22: * then squash any extra switches out of the stream.
23: * This is necessary to make code that is together in
24: * memory together in the 'ins' lists.
25: */
26: shuffle()
27: {
28: register INS *fp, *ip;
29: register INS *niloc;
30: INS *bep, *bfp;
31: register int curseg;
32:
33: niloc = &ins;
34: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
35: if (ip->i_type != ENTER)
36: continue;
37: bfp = ip;
38: do {
39: ip = ip->i_fp;
40: } while (ip->i_type != ENTER);
41: if (bfp != ins.i_fp) {
42: bep = ip;
43: ip = bfp->i_bp;
44: bfp->i_bp->i_fp = bep->i_fp;
45: bep->i_fp->i_bp = bfp->i_bp;
46: niloc->i_fp->i_bp = bep;
47: bfp->i_bp = niloc;
48: bep->i_fp = niloc->i_fp;
49: niloc->i_fp = bfp;
50: niloc = bep;
51: }
52: }
53: curseg = dotseg;
54: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
55: if (ip->i_type != ENTER)
56: continue;
57: while ((fp=ip->i_fp)!=&ins && fp->i_type==ENTER)
58: ip = deleteins(ip, ip->i_fp)->i_fp;
59: if (ip->i_seg == curseg) {
60: ip = deleteins(ip, ip->i_fp);
61: continue;
62: }
63: curseg = ip->i_seg;
64: }
65: }
66:
67: /*
68: * Delete node ip.
69: * Return a pointer to the previous node.
70: * Merge any line number references onto ip1.
71: */
72: INS *
73: deleteins(ip, ip1)
74: register INS *ip;
75: INS *ip1;
76: {
77: register INS *bp, *fp;
78:
79: mrgdbgt(ip, ip1);
80: if ((ip->i_type==JUMP || ip->i_type==LLLINK) && ((fp=ip->i_ip)!=NULL))
81: decrefc(fp);
82: bp = ip->i_bp;
83: fp = ip->i_fp;
84: bp->i_fp = fp;
85: fp->i_bp = bp;
86: free((char *) ip);
87: return (bp);
88: }
89:
90: /*
91: * Decrement the reference count on a label.
92: * Delete it if the label is now unreferenced.
93: * It is a fatal error to hand this routine a non label.
94: */
95: decrefc(ip)
96: register INS *ip;
97: {
98: if (ip->i_type != LLABEL)
99: cbotch("decrefc passed non label");
100: if (--ip->i_refc == 0)
101: deleteins(ip, ip->i_fp);
102: }
103:
104: /*
105: * Set up label reference counts and delete any unused labels.
106: */
107: labels()
108: {
109: register INS *fp, *ip, *lp;
110: INS *findlab();
111: register int curseg, i;
112:
113: for (i=0; i<NLHASH; ++i)
114: labhash[i] = NULL;
115: curseg = dotseg;
116: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
117: if (ip->i_type == ENTER)
118: curseg = ip->i_seg;
119: else if (ip->i_type == LLABEL) {
120: ip->i_refc = 0;
121: /*
122: * Hack the reference count on the
123: * label if it is the label on a switch
124: * table to prevent it from being deleted
125: * by the next bit of code. Kludgy.
126: */
127: if (curseg != SCODE)
128: ++ip->i_refc;
129: else if ((fp=ip->i_fp) != &ins) {
130: if (fp->i_type == LLLINK)
131: ++ip->i_refc;
132: else if (fp->i_type == CODE
133: && fp->i_op >= ZBYTE
134: && fp->i_op <= ZGPTR)
135: ++ip->i_refc;
136: }
137: labhash[ip->i_labno&LHMASK] = ip;
138: }
139: }
140: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
141: if (ip->i_type!=JUMP && ip->i_type!=LLLINK)
142: continue;
143: if ((lp=findlab(ip->i_labno)) != NULL) {
144: while ((fp=lp->i_fp)!=&ins && fp->i_type==LLABEL)
145: lp = fp;
146: ip->i_labno = lp->i_labno;
147: ++lp->i_refc;
148: }
149: ip->i_ip = lp;
150: }
151: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
152: if (ip->i_type!=LLABEL || ip->i_refc!=0)
153: continue;
154: ip = deleteins(ip, ip->i_fp);
155: ++nlabdel;
156: }
157: }
158:
159: /*
160: * Find label.
161: * Quick test using hashtable.
162: * Long linear search if that fails.
163: */
164: INS *
165: findlab(n)
166: register int n;
167: {
168: register INS *lp;
169:
170: if ((lp=labhash[n&LHMASK])!=NULL && lp->i_labno==n)
171: return (lp);
172: for (lp=ins.i_fp; lp!=&ins; lp=lp->i_fp)
173: if (lp->i_type==LLABEL && lp->i_labno==n)
174: return (lp);
175: return (NULL);
176: }
177:
178: /*
179: * Delete dead code.
180: * Dead code begins after an unconditional jump and continues
181: * until the next label, segment change or the EPILOG.
182: */
183: deadcode()
184: {
185: register INS *fp, *ip;
186: register int t;
187:
188: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
189: t = ip->i_type;
190: if (t == LLLINK) { /* Switch table */
191: while ((fp=ip->i_fp) != &ins && (fp->i_type == LLLINK
192: || (fp->i_type == CODE && opinfo[fp->i_op].op_style
193: == OF_WORD)))
194: ip = fp;
195: } else if (t != JUMP || ip->i_rel != UNCON)
196: continue;
197: fp = ip->i_fp;
198: while (fp != &ins) {
199: t = fp->i_type;
200: if (t==LLABEL || t==EPILOG || t==ENTER)
201: break;
202: fp = deleteins(fp, fp->i_fp)->i_fp;
203: ++ndead;
204: ++changes;
205: }
206: }
207: }
208:
209: /*
210: * Fix some of the more common funny things
211: * associated with jump instructions and labels.
212: * There are more things that could be done.
213: * These five things should get most of the common things.
214: */
215: fixbr()
216: {
217: register INS *ip, *ip1, *ip2;
218: INS *ip3, *ip4;
219: int t;
220:
221: again:
222: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
223: t = ip->i_type;
224: /* Jump to jump. */
225: if ((t==JUMP && ischnrel(ip->i_rel)) || t==LLLINK) {
226: ip1 = ip->i_ip;
227: if (ip1 != NULL) {
228: ip2 = ip1;
229: for (;;) {
230: while (ip2->i_type == LLABEL)
231: ip2 = ip2->i_fp;
232: if (ip2->i_type!=JUMP
233: || ip2->i_rel!=UNCON)
234: break;
235: ip3 = ip2->i_ip;
236: if (ip3==NULL
237: || ip3==ip1
238: || ip3==ip2->i_bp)
239: break;
240: ip2 = ip3;
241: }
242: ip2 = ip2->i_bp;
243: if (ip1 != ip2) {
244: decrefc(ip1);
245: increfc(ip2);
246: ip->i_labno = ip2->i_labno;
247: ip->i_ip = ip2;
248: ++nbrbr;
249: ++changes;
250: }
251: }
252: }
253: /* Reversible jump over unconditional jump. */
254: if (t==JUMP && isrevrel(ip->i_rel)) {
255: ip1 = ip->i_fp;
256: if (ip1->i_type==JUMP && ip1->i_rel==UNCON) {
257: ip2 = ip1->i_fp;
258: if (ip2->i_type==LLABEL && ip->i_ip==ip2) {
259: ip1->i_rel = revrel(ip->i_rel);
260: deleteins(ip, ip1);
261: ++ncbrbr;
262: ++changes;
263: goto again;
264: }
265: }
266: }
267: /* Jump to next instruction. */
268: if (t==JUMP && ip->i_ip==ip->i_fp) {
269: deleteins(ip, ip->i_fp);
270: ++nbrnext;
271: ++changes;
272: goto again;
273: }
274: /*
275: * The preceding optimizations do not change the code order,
276: * so they can be executed even if VNOOPT.
277: * The following optimizations do change the code order,
278: * so they are suppressed if VNOOPT.
279: */
280: if (isvariant(VNOOPT))
281: continue;
282: /*
283: * [ip]JUMP L1; [ip1]L2:...; [ip2]L1:...; [ip3]JUMP L2; ...
284: * becomes [ip2]L1:...; [ip1]L2:...; [ip]JUMP L1; ...
285: * Saves a jump in every for loop.
286: */
287: if (t==JUMP && ip->i_rel==UNCON) {
288: ip1 = ip->i_fp;
289: if (ip1!=&ins && ip1->i_type==LLABEL) {
290: ip2 = NULL;
291: for (ip3=ip1->i_fp; ip3!=&ins; ip3=ip3->i_fp) {
292: if (ip3->i_type==LLABEL
293: && ip->i_ip==ip3)
294: ip2 = ip3;
295: else if (ip2!=NULL
296: && ip3->i_type==JUMP
297: && ip3->i_rel==UNCON
298: && ip3->i_ip==ip1) {
299: ip4 = ip2->i_bp;
300: ip->i_bp->i_fp = ip2;
301: ip3->i_bp->i_fp = ip1;
302: ip4->i_fp = ip;
303: ip->i_fp = ip3;
304: ip2->i_bp = ip->i_bp;
305: ip1->i_bp = ip3->i_bp;
306: ip->i_bp = ip4;
307: ip3->i_bp = ip;
308: deleteins(ip3, ip1);
309: ++nexbr;
310: ++changes;
311: goto again;
312: }
313: }
314: }
315: }
316: /*
317: * [ip] JUMP L1; <code1>; [ip2] JUMP L2; [ip1] L1: <code2>; [ip3] L2:
318: * becomes [ip1] L1: <code2>; [ip] JUMP L2; <code1>; [ip3] L2:
319: * Saves a jump in every switch and restores natural code order.
320: * <code2> often ends in JUMP or LLLINK, in which case JUMP L2
321: * gets optimized out later.
322: */
323: if (t==JUMP && ip->i_rel==UNCON && precedes(ip, ip->i_ip)) {
324: ip1 = ip->i_ip;
325: ip2 = ip1->i_bp;
326: if (ip2->i_type==JUMP && ip2->i_rel==UNCON
327: && precedes(ip1, ip2->i_ip)) {
328: ip3 = ip2->i_ip;
329: /* Rearrange the code. */
330: ip->i_bp->i_fp = ip1;
331: ip3->i_bp->i_fp = ip;
332: ip2->i_fp = ip3;
333: ip1->i_bp = ip->i_bp;
334: ip->i_bp = ip3->i_bp;
335: ip3->i_bp = ip2;
336: /* Change JUMP L1 at ip into JUMP L2. */
337: ip->i_ip = ip3;
338: ip->i_labno = ip3->i_labno;
339: increfc(ip3);
340: decrefc(ip1);
341: /* Delete the now extraneous JUMP. */
342: deleteins(ip2, ip3);
343: ++nexbr;
344: ++changes;
345: goto again;
346: }
347: }
348: }
349: }
350:
351: /*
352: * Return true iff ip1 precedes ip2 in the INS node chain.
353: */
354: static
355: precedes(ip1, ip2)
356: register INS *ip1, *ip2;
357: {
358: while ((ip1 = ip1->i_fp) != &ins)
359: if (ip1 == ip2)
360: return(1);
361: return(0);
362: }
363:
364: /*
365: * Increment the reference count on a label.
366: * It is a fatal error to hand this routine a non label.
367: */
368: increfc(ip)
369: register INS *ip;
370: {
371: if (ip->i_type != LLABEL)
372: cbotch("increfc passed non label");
373: ++ip->i_refc;
374: }
375:
376: /*
377: * Insert a label.
378: * It has been 'increfc'ed.
379: * Return pointer to the new label.
380: */
381: INS *
382: inslab(ip)
383: register INS *ip;
384: {
385: register INS *lp, *bp;
386:
387: if (ip->i_type == LLABEL) {
388: increfc(ip);
389: return (ip);
390: }
391: lp = (INS *) malloc(sizeof(INS));
392: if (lp != NULL) {
393: lp->i_type = LLABEL;
394: lp->i_labno = newlab();
395: lp->i_sp = NULL;
396: lp->i_refc = 1;
397: bp = ip->i_bp;
398: bp->i_fp = lp;
399: lp->i_fp = ip;
400: ip->i_bp = lp;
401: lp->i_bp = bp;
402: }
403: return (lp);
404: }
405:
406: /*
407: * Cross jumps.
408: * If the same code precedes an unconditional jump and
409: * the label to which it jumps, replace the former with
410: * a jump to a new local label.
411: */
412: xjumps()
413: {
414: register INS *ip, *lp;
415:
416: for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
417: if (ip->i_type!=JUMP || ip->i_rel!=UNCON
418: || (lp = ip->i_ip)==NULL)
419: continue;
420: if (!docomseq(lp, ip, &nxjump))
421: return;
422: }
423: }
424:
425: /*
426: * Compare two nodes.
427: * True return if the same.
428: * Never called on strange stuff
429: * or labels.
430: */
431: xeq(ip1, ip2)
432: register INS *ip1, *ip2;
433: {
434: register int t;
435:
436: if ((t=ip1->i_type) != ip2->i_type)
437: return (0);
438: if (t==JUMP || t==LLLINK) {
439: if (ip1->i_labno != ip2->i_labno)
440: return (0);
441: if (t==JUMP && ip1->i_rel!=ip2->i_rel)
442: return (0);
443: return (1);
444: }
445: if (t != CODE)
446: cbotch("xeq");
447: if (ip1->i_op != ip2->i_op)
448: return (0);
449: if (ip1->i_naddr != ip2->i_naddr)
450: return (0);
451: return (cmpfield(ip1, ip2));
452: }
453:
454: /*
455: * Detect common sequences before jumps.
456: * When found, replace the later with a jump to a new
457: * local label preceding the former.
458: */
459: comseq()
460: {
461: register INS *ip, *xp, *yp;
462:
463: for (xp=ins.i_fp; xp!=&ins; xp=xp->i_fp) {
464: if (xp->i_type!=JUMP || xp->i_rel!=UNCON)
465: continue;
466: ip = xp->i_ip;
467: if (ip==NULL || ip->i_type != LLABEL)
468: continue;
469: for (yp=xp->i_fp; yp!=&ins; yp=yp->i_fp) {
470: if (yp->i_type==JUMP && yp->i_rel==UNCON
471: && yp->i_ip==ip) {
472: if (!docomseq(xp, yp, &ncomseq))
473: return;
474: }
475: }
476: }
477: }
478:
479:
480: /*
481: * Back up through the code looking for valid cross jumps.
482: * When found, insert a new local label before the first
483: * and change the second into an unconditional jump to it.
484: * Called from xjumps and comseq.
485: * Returns 0 if the new node allocation fails.
486: */
487: docomseq(xp, yp, countp)
488: register INS *xp, *yp;
489: int *countp;
490: {
491: for (;;) {
492: xp = xp->i_bp;
493: if (xp==&ins || xp->i_type==LLABEL || xp->i_type==LLLINK)
494: break;
495: yp = yp->i_bp;
496: if (yp==&ins || yp->i_type==LLABEL || yp->i_type==LLLINK
497: || xeq(xp, yp)==0)
498: break;
499: xp = inslab(xp);
500: if (xp == NULL)
501: return (0);
502: mrgdbgt(yp, xp->i_fp);
503: if ((yp->i_type==JUMP || yp->i_type==LLLINK) && yp->i_ip!=NULL)
504: decrefc(yp->i_ip);
505: yp->i_type = JUMP;
506: yp->i_labno = xp->i_labno;
507: yp->i_sp = NULL;
508: yp->i_ip = xp;
509: yp->i_rel = UNCON;
510: yp->i_long = 0;
511: ++*countp;
512: ++changes;
513: }
514: return(1);
515: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.