|
|
1.1 root 1: /* Optimize jump instructions, for GNU compiler.
2: Copyright (C) 1988 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
6: GNU CC is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU CC General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU CC, but only under the conditions described in the
15: GNU CC General Public License. A copy of this license is
16: supposed to have been given to you along with GNU CC so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: /* This is the jump-optimization pass of the compiler.
23: It is run two or three times: once before cse, sometimes once after cse,
24: and once after reload (before final).
25:
26: jump_optimize deletes unreachable code and labels that are not used.
27: It also deletes jumps that jump to the following insn,
28: and simplifies jumps around unconditional jumps and jumps
29: to unconditional jumps.
30:
31: Each CODE_LABEL has a count of the times it is used
32: stored in the LABEL_NUSES internal field, and each JUMP_INSN
33: has one label that it refers to stored in the
34: JUMP_LABEL internal field. With this we can detect labels that
35: become unused because of the deletion of all the jumps that
36: formerly used them. The JUMP_LABEL info is sometimes looked
37: at by later passes.
38:
39: Optionally, cross-jumping can be done. Currently it is done
40: only the last time (when after reload and before final).
41: In fact, the code for cross-jumping now assumes that register
42: allocation has been done, since it uses `rtx_renumbered_equal_p'.
43:
44: Jump optimization is done after cse when cse's constant-propagation
45: causes jumps to become unconditional or to be deleted.
46:
47: Unreachable loops are not detected here, because the labels
48: have references and the insns appear reachable from the labels.
49: find_basic_blocks in flow.c finds and deletes such loops.
50:
51: The subroutines delete_insn, redirect_jump, invert_jump, next_real_insn
52: and prev_real_insn are used from other passes as well. */
53:
54: #include "config.h"
55: #include "rtl.h"
56: #include "flags.h"
57: #include "regs.h"
58:
59: /* ??? Eventually must record somehow the labels used by jumps
60: from nested functions. */
61: /* Pre-record the next or previous real insn for each label?
62: No, this pass is very fast anyway. */
63: /* Condense consecutive labels?
64: This would make life analysis faster, maybe. */
65: /* Optimize jump y; x: ... y: jumpif... x?
66: Don't know if it is worth bothering with. */
67: /* Optimize two cases of conditional jump to conditional jump?
68: This can never delete any instruction or make anything dead,
69: or even change what is live at any point.
70: So perhaps let combiner do it. */
71:
72: /* Vector indexed by uid.
73: For each CODE_LABEL, index by its uid to get first unconditional jump
74: that jumps to the label.
75: For each JUMP_INSN, index by its uid to get the next unconditional jump
76: that jumps to the same label.
77: Element 0 is the start of a chain of all return insns.
78: (It is safe to use element 0 because insn uid 0 is not used. */
79:
80: rtx *jump_chain;
81:
82: rtx delete_insn ();
83: void redirect_jump ();
84: void invert_jump ();
85: rtx next_real_insn ();
86: rtx prev_real_insn ();
87: rtx next_label ();
88:
89: static void mark_jump_label ();
90: static void delete_jump ();
91: static void invert_exp ();
92: static void redirect_exp ();
93: static rtx follow_jumps ();
94: static int tension_vector_labels ();
95: static void find_cross_jump ();
96: static void do_cross_jump ();
97: static enum rtx_code reverse_condition ();
98: static int jump_back_p ();
99:
100: /* Delete no-op jumps and optimize jumps to jumps
101: and jumps around jumps.
102: Delete unused labels and unreachable code.
103: If CROSS_JUMP is nonzero, detect matching code
104: before a jump and its destination and unify them.
105: If NOOP_MOVES is nonzero, also delete no-op move insns
106: and perform machine-specific peephole optimizations
107: (but flag_no_peephole inhibits the latter).
108:
109: If `optimize' is zero, don't change any code,
110: just determine whether control drops off the end of the function.
111: This case occurs when we have -W and not -O.
112: It works because `delete_insn' checks the value of `optimize'
113: and refrains from actually deleting when that is 0. */
114:
115: void
116: jump_optimize (f, cross_jump, noop_moves)
117: rtx f;
118: {
119: register rtx insn;
120: int changed;
121: int first = 1;
122: int max_uid = 0;
123: rtx last_insn;
124:
125: /* Initialize LABEL_NUSES and JUMP_LABEL fields. */
126:
127: for (insn = f; insn; insn = NEXT_INSN (insn))
128: {
129: if (GET_CODE (insn) == CODE_LABEL)
130: LABEL_NUSES (insn) = 0;
131: if (GET_CODE (insn) == JUMP_INSN)
132: JUMP_LABEL (insn) = 0;
133: if (INSN_UID (insn) > max_uid)
134: max_uid = INSN_UID (insn);
135: }
136:
137: max_uid++;
138:
139: jump_chain = (rtx *) alloca (max_uid * sizeof (rtx));
140: bzero (jump_chain, max_uid * sizeof (rtx));
141:
142: /* Delete insns following barriers, up to next label. */
143:
144: for (insn = f; insn;)
145: {
146: if (GET_CODE (insn) == BARRIER)
147: {
148: insn = NEXT_INSN (insn);
149: while (insn != 0 && GET_CODE (insn) != CODE_LABEL)
150: {
151: if (GET_CODE (insn) == NOTE
152: && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
153: insn = NEXT_INSN (insn);
154: else
155: insn = delete_insn (insn);
156: }
157: /* INSN is now the code_label. */
158: }
159: else
160: insn = NEXT_INSN (insn);
161: }
162:
163: /* Mark the label each jump jumps to.
164: Combine consecutive labels, and count uses of labels.
165:
166: For each label, make a chain (using `jump_chain')
167: of all the *unconditional* jumps that jump to it;
168: also make a chain of all returns. */
169:
170: for (insn = f; insn; insn = NEXT_INSN (insn))
171: if (GET_CODE (insn) == JUMP_INSN && !insn->volatil)
172: {
173: mark_jump_label (PATTERN (insn), insn, cross_jump);
174: if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
175: {
176: jump_chain[INSN_UID (insn)]
177: = jump_chain[INSN_UID (JUMP_LABEL (insn))];
178: jump_chain[INSN_UID (JUMP_LABEL (insn))] = insn;
179: }
180: if (GET_CODE (PATTERN (insn)) == RETURN)
181: {
182: jump_chain[INSN_UID (insn)] = jump_chain[0];
183: jump_chain[0] = insn;
184: }
185: }
186:
187: /* Delete all labels already not referenced.
188: Also find the last insn. */
189:
190: last_insn = 0;
191: for (insn = f; insn; )
192: {
193: if (GET_CODE (insn) == CODE_LABEL && LABEL_NUSES (insn) == 0)
194: insn = delete_insn (insn);
195: else
196: {
197: last_insn = insn;
198: insn = NEXT_INSN (insn);
199: }
200: }
201:
202: if (!optimize)
203: {
204: /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
205: If so record that this function can drop off the end. */
206:
207: insn = last_insn;
208: while (insn && (GET_CODE (insn) == CODE_LABEL
209: /* If machine uses explicit RETURN insns, no epilogue,
210: then this note precedes the drop-through RETURN. */
211: || (GET_CODE (insn) == JUMP_INSN
212: && GET_CODE (PATTERN (insn)) == RETURN)))
213: insn = PREV_INSN (insn);
214:
215: if (GET_CODE (insn) == NOTE
216: && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
217: && ! insn->volatil)
218: {
219: extern int current_function_returns_null;
220: current_function_returns_null = 1;
221: }
222: /* Zero the "deleted" flag of all the "deleted" insns. */
223: for (insn = f; insn; insn = NEXT_INSN (insn))
224: insn->volatil = 0;
225: return;
226: }
227:
228: #if 0
229: #ifdef EXIT_IGNORE_STACK
230: /* If the last insn just adjusts the stack,
231: we can delete it on certain machines,
232: provided we have a frame pointer. */
233:
234: if (frame_pointer_needed && EXIT_IGNORE_STACK)
235: {
236: insn = last_insn;
237: while (insn)
238: {
239: rtx prev;
240: /* Back up to a real insn. */
241: if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN
242: && GET_CODE (insn) != CALL_INSN)
243: insn = prev_real_insn (insn);
244: if (insn == 0)
245: break;
246: prev = PREV_INSN (insn);
247: /* If this insn is a stack adjust, delete it. */
248: if (GET_CODE (insn) == INSN
249: && GET_CODE (PATTERN (insn)) == SET
250: && GET_CODE (SET_DEST (PATTERN (insn))) == REG
251: && REGNO (SET_DEST (PATTERN (insn))) == STACK_POINTER_REGNUM)
252: {
253: delete_insn (insn);
254: if (insn == last_insn)
255: last_insn = prev;
256: }
257: else
258: /* If we find an insn that isn't a stack adjust, stop deleting. */
259: break;
260: /* Back up to insn before the deleted one and try to delete more. */
261: insn = prev;
262: }
263: }
264: #endif
265: #endif
266:
267: if (noop_moves)
268: for (insn = f; insn; )
269: {
270: register rtx next = NEXT_INSN (insn);
271:
272: if (GET_CODE (insn) == INSN)
273: {
274: register rtx body = PATTERN (insn);
275:
276: /* Delete insns that existed just to advise flow-analysis. */
277:
278: if (GET_CODE (body) == USE
279: || GET_CODE (body) == CLOBBER)
280: delete_insn (insn);
281:
282: /* Detect and delete no-op move instructions
283: resulting from not allocating a parameter in a register. */
284:
285: else if (GET_CODE (body) == SET
286: && (SET_DEST (body) == SET_SRC (body)
287: || (GET_CODE (SET_DEST (body)) == MEM
288: && GET_CODE (SET_SRC (body)) == MEM
289: && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
290: && ! SET_DEST (body)->volatil
291: && ! SET_SRC (body)->volatil)
292: delete_insn (insn);
293:
294: /* Detect and ignore no-op move instructions
295: resulting from smart or fortuitous register allocation. */
296:
297: else if (GET_CODE (body) == SET)
298: {
299: int sreg = true_regnum (SET_SRC (body));
300: int dreg = true_regnum (SET_DEST (body));
301:
302: if (sreg == dreg && sreg >= 0)
303: delete_insn (insn);
304: else if (sreg >= 0 && dreg >= 0)
305: {
306: rtx tem = find_equiv_reg (0, insn, 0,
307: sreg, 0, dreg);
308: if (tem != 0
309: && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
310: delete_insn (insn);
311: }
312: }
313: }
314: insn = next;
315: }
316:
317: /* Now iterate optimizing jumps until nothing changes over one pass. */
318: changed = 1;
319: while (changed)
320: {
321: register rtx next;
322: changed = 0;
323:
324: for (insn = f; insn; insn = next)
325: {
326: next = NEXT_INSN (insn);
327:
328: /* On the first iteration, if this is the last jump pass
329: (just before final), do the special peephole optimizations. */
330:
331: if (noop_moves && first && !flag_no_peephole)
332: if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
333: peephole (insn);
334:
335: /* Tension the labels in dispatch tables. */
336:
337: if (GET_CODE (insn) == JUMP_INSN)
338: {
339: if (GET_CODE (PATTERN (insn)) == ADDR_VEC)
340: changed |= tension_vector_labels (PATTERN (insn), 0);
341: if (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
342: changed |= tension_vector_labels (PATTERN (insn), 1);
343: }
344:
345: if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
346: {
347: register rtx reallabelprev = prev_real_insn (JUMP_LABEL (insn));
348:
349: /* Delete insns that adjust stack pointer before a return,
350: if this is the last jump-optimization before final
351: and we need to have a frame pointer. */
352: #if 0
353: #ifdef EXIT_IGNORE_STACK
354: if (noop_moves && frame_pointer_needed && EXIT_IGNORE_STACK
355: && NEXT_INSN (JUMP_LABEL (insn)) == 0)
356: {
357: rtx prev = prev_real_insn (insn);
358: if (prev != 0
359: && GET_CODE (prev) == INSN
360: && GET_CODE (PATTERN (prev)) == SET
361: && GET_CODE (SET_DEST (PATTERN (prev))) == REG
362: && REGNO (SET_DEST (PATTERN (prev))) == STACK_POINTER_REGNUM)
363: {
364: delete_insn (prev);
365: changed = 1;
366: }
367: }
368: #endif
369: #endif
370:
371: /* Detect jump to following insn. */
372: if (reallabelprev == insn && condjump_p (insn))
373: {
374: reallabelprev = PREV_INSN (insn);
375: delete_jump (insn);
376: changed = 1;
377: }
378: /* Detect jumping over an unconditional jump. */
379: else if (reallabelprev != 0
380: && GET_CODE (reallabelprev) == JUMP_INSN
381: && prev_real_insn (reallabelprev) == insn
382: && no_labels_between_p (insn, reallabelprev)
383: && simplejump_p (reallabelprev)
384: /* Ignore this if INSN is a hairy kind of jump,
385: since they may not be invertible.
386: This is conservative; could instead construct
387: the inverted insn and try recognizing it. */
388: && condjump_p (insn))
389: {
390: /* Delete the original unconditional jump (and barrier). */
391: /* But don't lEST (PATTERN (insn))) == STACK_POINTER_REGNUM)
392: {
393: delete_insn (insn);
394: if (insn == last_insn)
395: last_insn = prev;
396: }
397: else
398: /* If we find an insn that isn't a stack adjust, stop deleting. */
399: break;
400: /* Back up to insn before the deleted one and try to delete more. */
401: insn = prev;
402: }
403: }
404: #endif
405: #endif
406:
407: if (noop_moves)
408: for (insn = f; insn; )
409: {
410: register rtx next = NEXT_INSN (insn);
411:
412: if (GET_CODE (insn) == INSN)
413: {
414: register rtx body = PATTERN (insn);
415:
416: /* Delete insns that existed just to advise flow-analysis. */
417:
418: if (GET_CODE (body) == USE
419: || GET_CODE (body) == CLOBBER)
420: delete_insn (insn);
421:
422: /* Detect and delete no-op move instructions
423: resulting from not allocating a parameter in a register. */
424:
425: else if (GET_CODE (body) == SET
426: && (SET_DEST (body) == SET_SRC (body)
427: || (GET_CODE (SET_DEST (body)) == MEM
428: && GET_CODE (SET_SRC (body)) == MEM
429: && rtx_equal_p (SET_SRC (body), SET_DEST (body))))
430: && ! SET_DEST (body)->volatil
431: && ! SET_SRC (body)->volatil)
432: delete_insn (insn);
433:
434: /* Detect and ignore no-op move instructions
435: resulting from smart or fortuitous register allocation. */
436:
437: else if (GET_CODE (body) == SET)
438: {
439: int sreg = true_regnum (SET_SRC (body));
440: int dreg = true_regnum (SET_DEST (body));
441:
442: if (sreg == dreg && sreg >= 0)
443: delete_insn (insn);
444: else if (sreg >= 0 && dreg >= 0)
445: {
446: rtx tem = find_equiv_reg (0, insn, 0,
447: sreg, 0, dreg);
448: if (tem != 0
449: && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
450: delete_insn (insn);
451: }
452: }
453: }
454: insn = next;
455: }
456:
457: /* Now iterate optimizing jumps until nothing changes over one pass. */
458: changed = 1;
459: while (changed)
460: {
461: register rtx next;
462: changed = 0;
463:
464: for (insn = f; insn; insn = next)
465: {
466: next = NEXT_INSN (insn);
467:
468: /* On the first iteration, if this is the last jump pass
469: (just before final), do the special peephole optimizations. */
470:
471: if (noop_moves && first && !flag_no_peephole)
472: if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
473: peephole (insn);
474:
475: /* Tension the labels in dispatch tables. */
476:
477: if (GET_CODE (insn) == JUMP_INSN)
478: {
479: if (GET_CODE (PATTERN (insn)) == ADDR_VEC)
480: changed |= tension_vector_labels (PATTERN (insn), 0);
481: if (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
482: changed |= tension_vector_labels (PATTERN (insn), 1);
483: }
484:
485: if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
486: {
487: register rtx reallabelprev = prev_real_insn (JUMP_LABEL (insn));
488:
489: /* Delete insns that adjust stack pointer before a return,
490: if this is the last jump-optimization before final
491: and we need to have a frame pointer. */
492: #if 0
493: #ifdef EXIT_IGNORE_STACK
494: if (noop_moves && frame_pointer_needed && EXIT_IGNORE_STACK
495: && NEXT_INSN (JUMP_LABEL (insn)) == 0)
496: {
497: rtx prev = prev_real_insn (insn);
498: if (prev != 0
499: && GET_CODE (prev) == INSN
500: && GET_CODE (PATTERN (prev)) == SET
501: && GET_CODE (SET_DEST (PATTERN (prev))) == REG
502: && REGNO (SET_DEST (PATTERN (prev))) == STACK_POINTER_REGNUM)
503: {
504: delete_insn (prev);
505: changed = 1;
506: }
507: }
508: #endif
509: #endif
510:
511: /* Detect jump to following insn. */
512: if (reallabelprev == insn && condjump_p (insn))
513: {
514: reallabelprev = PREV_INSN (insn);
515: delete_jump (insn);
516: changed = 1;
517: }
518: /* Detect jumping over an unconditional jump. */
519: else if (reallabelprev != 0
520: && GET_CODE (reallabelprev) == JUMP_INSN
521: && prev_real_insn (reallabelprev) == insn
522: && no_labels_between_p (insn, reallabelprev)
523: && simplejump_p (reallabelprev)
524: /* Ignore this if INSN is a hairy kind of jump,
525: since they may not be invertible.
526: This is conservative; could instead construct
527: the inverted insn and try recognizing it. */
528: && condjump_p (insn))
529: {
530: /* Delete the original unconditional jump (and barrier). */
531: /* But don't l/* If cannot cross jump to code before the label,
532: see if we can cross jump to another jump to
533: the same label. */
534: /* Try each other jump to this label. */
535: if (INSN_UID (JUMP_LABEL (insn)) < max_uid)
536: for (target = jump_chain[INSN_UID (JUMP_LABEL (insn))];
537: target != 0 && newjpos == 0;
538: target = jump_chain[INSN_UID (target)])
539: if (target != insn
540: && JUMP_LABEL (target) == JUMP_LABEL (insn)
541: /* Ignore TARGET if it's deleted. */
542: && ! target->volatil)
543: find_cross_jump (insn, target, 2,
544: &newjpos, &newlpos);
545:
546: if (newjpos != 0)
547: {
548: do_cross_jump (insn, newjpos, newlpos);
549: changed = 1;
550: next = insn;
551: }
552: }
553: }
554: }
555: else if (GET_CODE (insn) == JUMP_INSN
556: && GET_CODE (PATTERN (insn)) == RETURN)
557: {
558: /* Return insns all "jump to the same place"
559: so we can cross-jump between any two of them. */
560: if (cross_jump)
561: {
562: rtx newjpos, newlpos, target;
563:
564: newjpos = 0;
565:
566: /* If cannot cross jump to code before the label,
567: see if we can cross jump to another jump to
568: the same label. */
569: /* Try each other jump to this label. */
570: for (target = jump_chain[0];
571: target != 0 && newjpos == 0;
572: target = jump_chain[INSN_UID (target)])
573: if (target != insn
574: && ! target->volatil
575: && GET_CODE (PATTERN (target)) == RETURN)
576: find_cross_jump (insn, target, 2,
577: &newjpos, &newlpos);
578:
579: if (newjpos != 0)
580: {
581: do_cross_jump (insn, newjpos, newlpos);
582: changed = 1;
583: next = insn;
584: }
585: }
586: }
587:
588: }
589:
590: first = 0;
591: }
592:
593: /* See if there is still a NOTE_INSN_FUNCTION_END in this function.
594: If so, delete it, and record that this function can drop off the end. */
595:
596: insn = last_insn;
597: while (insn && (GET_CODE (insn) == CODE_LABEL
598: /* If machine uses explicit RETURN insns, no epilogue,
599: then this note precedes the drop-through RETURN. */
600: || (GET_CODE (insn) == JUMP_INSN
601: && GET_CODE (PATTERN (insn)) == RETURN)))
602: insn = PREV_INSN (insn);
603: if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
604: {
605: extern int current_function_returns_null;
606: current_function_returns_null = 1;
607: delete_insn (insn);
608: }
609: }
610:
611: /* Compare the instructions before insn E1 with those before E2.
612: Assume E1 is a jump that jumps to label E2
613: (that is not always true but it might as well be).
614: Find the longest possible equivalent sequences
615: and store the first insns of those sequences into *F1 and *F2.
616: Store zero there if no equivalent preceding instructions are found.
617:
618: We give up if we find a label in stream 1.
619: Actually we could transfer that label into stream 2. */
620:
621: static void
622: find_cross_jump (e1, e2, minimum, f1, f2)
623: rtx e1, e2;
624: int minimum;
625: rtx *f1, *f2;
626: {
627: register rtx i1 = e1, i2 = e2;
628: register rtx p1, p2;
629:
630: rtx last1 = 0, last2 = 0;
631: rtx afterlast1 = 0, afterlast2 = 0;
632:
633: *f1 = 0;
634: *f2 = 0;
635:
636: while (1)
637: {
638: i1 = PREV_INSN (i1);
639: while (i1 && GET_CODE (i1) == NOTE)
640: i1 = PREV_INSN (i1);
641:
642: i2 = PREV_INSN (i2);
643: while (i2 && (GET_CODE (i2) == NOTE || GET_CODE (i2) == CODE_LABEL))
644: i2 = PREV_INSN (i2);
645:
646: if (i1 == 0)
647: break;
648:
649: /* If we will get to this code by jumping, those jumps will be
650: tensioned to go directly to the new label (before I2),
651: so this cross-jumping won't cost extra. So reduce the minimum. */
652: if (GET_CODE (i1) == CODE_LABEL)
653: {
654: --minimum;
655: break;
656: }
657:
658: if (i2 == 0 || GET_CODE (i1) != GET_CODE (i2))
659: break;
660:
661: p1 = PATTERN (i1);
662: p2 = PATTERN (i2);
663:
664: if (GET_CODE (p1) != GET_CODE (p2)
665: || !rtx_renumbered_equal_p (p1, p2))
666: {
667: /* Insns fail to match; cross jumping is limited to the following
668: insns. */
669:
670: /* Don't allow the insn after a compare to be shared by cross-jumping
671: unless the compare is also shared.
672: Here, if either of these non-matching insns is a compare,
673: exclude the following insn from possible cross-jumping. */
674: if ((GET_CODE (p1) == SET && SET_DEST (p1) == cc0_rtx)
675: || (GET_CODE (p2) == SET && SET_DEST (p2) == cc0_rtx))
676: last1 = afterlast1, last2 = afterlast2, ++minimum;
677:
678: /* If cross-jumping here will feed a jump-around-jump optimization,
679: this jump won't cost extra, so reduce the minimum. */
680: if (GET_CODE (i1) == JUMP_INSN
681: && JUMP_LABEL (i1)
682: && prev_real_insn (JUMP_LABEL (i1)) == e1)
683: --minimum;
684: break;
685: }
686:
687: if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER)
688: {
689: /* Ok, this insn is potentially includable in a cross-jump here. */
690: afterlast1 = last1, afterlast2 = last2;
691: last1 = i1, last2 = i2, --minimum;
692: }
693: }
694:
695: if (minimum <= 0 && last1 != 0)
696: *f1 = last1, *f2 = last2;
697: }
698:
699: static void
700: do_cross_jump (insn, newjpos, newlpos)
701: rtx insn, newjpos, newlpos;
702: {
703: register rtx label;
704: /* Find an existing label at this point
705: or make a new one if there is none. */
706: label = PREV_INSN (newlpos);
707: if (GET_CODE (label) != CODE_LABEL)
708: {
709: label = gen_label_rtx ();
710: emit_label_after (label, PREV_INSN (newlpos));
711: LABEL_NUSES (label) = 0;
712: }
713: /* Make the same jump insn jump to the new point. */
714: if (GET_CODE (PATTERN (insn)) == RETURN)
715: {
716: extern rtx gen_jump ();
717: PATTERN (insn) = gen_jump (label);
718: INSN_CODE (insn) = -1;
719: JUMP_LABEL (insn) = label;
720: LABEL_NUSES (label)++;
721: }
722: else
723: redirect_jump (insn, label);
724: /* Delete the matching insns before the jump. */
725: newjpos = PREV_INSN (newjpos);
726: while (NEXT_INSN (newjpos) != insn)
727: /* Don't delete line numbers. */
728: if (GET_CODE (NEXT_INSN (newjpos)) != NOTE)
729: delete_insn (NEXT_INSN (newjpos));
730: else
731: newjpos = NEXT_INSN (newjpos);
732: }
733:
734: /* Return 1 if INSN is a jump that jumps to right after TARGET
735: only on the condition that TARGET itself would drop through.
736: Assumes that TARGET is a conditional jump. */
737:
738: static int
739: jump_back_p (insn, target)
740: rtx insn, target;
741: {
742: rtx cinsn, ctarget;
743: enum rtx_code codei, codet;
744:
745: if (simplejump_p (insn) || ! condjump_p (insn)
746: || simplejump_p (target))
747: return 0;
748: if (target != prev_real_insn (JUMP_LABEL (insn)))
749: return 0;
750:
751: cinsn = XEXP (SET_SRC (PATTERN (insn)), 0);
752: ctarget = XEXP (SET_SRC (PATTERN (target)), 0);
753:
754: codei = GET_CODE (cinsn);
755: codet = GET_CODE (ctarget);
756: if (XEXP (SET_SRC (PATTERN (insn)), 1) == pc_rtx)
757: codei = reverse_condition (codei);
758: if (XEXP (SET_SRC (PATTERN (target)), 2) == pc_rtx)
759: codet = reverse_condition (codet);
760: return (codei == codet
761: && rtx_renumbered_equal_p (XEXP (cinsn, 0), XEXP (ctarget, 0))
762: && rtx_renumbered_equal_p (XEXP (cinsn, 1), XEXP (ctarget, 1)));
763: }
764:
765: /* Given an rtx-code for a comparison, return the code
766: for the negated comparison. */
767:
768: static enum rtx_code
769: reverse_condition (code)
770: enum rtx_code code;
771: {
772: switch (code)
773: {
774: case EQ:
775: return NE;
776:
777: case NE:
778: return EQ;
779:
780: case GT:
781: return LE;
782:
783: case GE:
784: return LT;
785:
786: case LT:
787: return GE;
788:
789: case LE:
790: return GT;
791:
792: case GTU:
793: return LEU;
794:
795: case GEU:
796: return LTU;
797:
798: case LTU:
799: return GEU;
800:
801: case LEU:
802: return GTU;
803:
804: default:
805: abort ();
806: return UNKNOWN;
807: }
808: }
809:
810: /* Return 1 if INSN is an unconditional jump and nothing else. */
811:
812: int
813: simplejump_p (insn)
814: rtx insn;
815: {
816: register rtx x = PATTERN (insn);
817: if (GET_CODE (x) != SET)
818: return 0;
819: if (GET_CODE (SET_DEST (x)) != PC)
820: return 0;
821: if (GET_CODE (SET_SRC (x)) != LABEL_REF)
822: return 0;
823: return 1;
824: }
825:
826: /* Return nonzero if INSN is a (possibly) conditional jump
827: and nothing more. */
828:
829: static int
830: condjump_p (insn)
831: rtx insn;
832: {
833: register rtx x = PATTERN (insn);
834: if (GET_CODE (x) != SET)
835: return 0;
836: if (GET_CODE (SET_DEST (x)) != PC)
837: return 0;
838: if (GET_CODE (SET_SRC (x)) == LABEL_REF)
839: return 1;
840: if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
841: return 0;
842: if (XEXP (SET_SRC (x), 2) == pc_rtx
843: && GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF)
844: return 1;
845: if (XEXP (SET_SRC (x), 1) == pc_rtx
846: && GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF)
847: return 1;
848: return 0;
849: }
850:
851: /* Return 1 if in between BEG and END there is no CODE_LABEL insn. */
852:
853: int
854: no_labels_between_p (beg, end)
855: rtx beg, end;
856: {
857: register rtx p;
858: for (p = beg; p != end; p = NEXT_INSN (p))
859: if (GET_CODE (p) == CODE_LABEL)
860: return 0;
861: return 1;
862: }
863:
864: /* Return the last INSN, CALL_INSN or JUMP_INSN before LABEL;
865: or 0, if there is none. */
866:
867: rtx
868: prev_real_insn (label)
869: rtx label;
870: {
871: register rtx insn = PREV_INSN (label);
872: register RTX_CODE code;
873:
874: while (1)
875: {
876: if (insn == 0)
877: return 0;
878: code = GET_CODE (insn);
879: if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
880: break;
881: insn = PREV_INSN (insn);
882: }
883:
884: return insn;
885: }
886:
887: /* Return the next INSN, CALL_INSN or JUMP_INSN after LABEL;
888: or 0, if there is none. */
889:
890: rtx
891: next_real_insn (label)
892: rtx label;
893: {
894: register rtx insn = NEXT_INSN (label);
895: register RTX_CODE code;
896:
897: while (1)
898: {
899: if (insn == 0)
900: return insn;
901: code = GET_CODE (insn);
902: if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
903: break;
904: insn = NEXT_INSN (insn);
905: }
906:
907: return insn;
908: }
909:
910: /* Return the next CODE_LABEL after the insn INSN, or 0 if there is none. */
911:
912: rtx
913: next_label (insn)
914: rtx insn;
915: {
916: do insn = NEXT_INSN (insn);
917: while (insn != 0 && GET_CODE (insn) != CODE_LABEL);
918: return insn;
919: }
920:
921: /* Follow any unconditional jump at LABEL;
922: return the ultimate label reached by any such chain of jumps.
923: If LABEL is not followed by a jump, return LABEL. */
924:
925: static rtx
926: follow_jumps (label)
927: rtx label;
928: {
929: register rtx insn;
930: register rtx next;
931: register rtx value = label;
932: register int depth;
933:
934: for (depth = 0;
935: (depth < 10
936: && (insn = next_real_insn (value)) != 0
937: && GET_CODE (insn) == JUMP_INSN
938: && JUMP_LABEL (insn) != 0
939: && (next = NEXT_INSN (insn))
940: && GET_CODE (next) == BARRIER);
941: depth++)
942: {
943: /* If we have found a cycle, make the insn jump to itself. */
944: if (JUMP_LABEL (insn) == label)
945: break;
946: value = JUMP_LABEL (insn);
947: }
948: return value;
949: }
950:
951: /* Assuming that field IDX of X is a vector of label_refs,
952: replace each of them by the ultimate label reached by it.
953: Return nonzero if a change is made. */
954:
955: static int
956: tension_vector_labels (x, idx)
957: register rtx x;
958: register int idx;
959: {
960: int changed = 0;
961: register int i;
962: for (i = XVECLEN (x, idx) - 1; i >= 0; i--)
963: {
964: register rtx olabel = XEXP (XVECEXP (x, idx, i), 0);
965: register rtx nlabel = follow_jumps (olabel);
966: if (nlabel != olabel)
967: {
968: XEXP (XVECEXP (x, idx, i), 0) = nlabel;
969: ++LABEL_NUSES (nlabel);
970: if (--LABEL_NUSES (olabel) == 0)
971: delete_insn (olabel);
972: changed = 1;
973: }
974: }
975: return changed;
976: }
977:
978: /* Find all CODE_LABELs referred to in X,
979: and increment their use counts.
980: Also store one of them in JUMP_LABEL (INSN) if INSN is nonzero.
981: Also, when there are consecutive labels,
982: canonicalize on the last of them.
983:
984: Note that two labels separated by a loop-beginning note
985: must be kept distinct if we have not yet done loop-optimization,
986: because the gap between them is where loop-optimize
987: will want to move invariant code to. CROSS_JUMP tells us
988: that loop-optimization is done with. */
989:
990: static void
991: mark_jump_label (x, insn, cross_jump)
992: register rtx x;
993: rtx insn;
994: int cross_jump;
995: {
996: register RTX_CODE code = GET_CODE (x);
997: register int i;
998: register char *fmt;
999:
1000: if (code == LABEL_REF)
1001: {
1002: register rtx label = XEXP (x, 0);
1003: register rtx next;
1004: if (GET_CODE (label) != CODE_LABEL)
1005: return;
1006: /* If there are other labels following this one,
1007: replace it with the last of the consecutive labels. */
1008: for (next = NEXT_INSN (label); next; next = NEXT_INSN (next))
1009: {
1010: if (GET_CODE (next) == CODE_LABEL)
1011: label = next;
1012: else if (GET_CODE (next) != NOTE
1013: || NOTE_LINE_NUMBER (next) == NOTE_INSN_LOOP_BEG
1014: || NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END)
1015: break;
1016: }
1017: XEXP (x, 0) = label;
1018: ++LABEL_NUSES (label);
1019: if (insn)
1020: JUMP_LABEL (insn) = label;
1021: return;
1022: }
1023:
1024: /* Do walk the labels in a vector,
1025: but don't set its JUMP_LABEL. */
1026: if (code == ADDR_VEC || code == ADDR_DIFF_VEC)
1027: insn = 0;
1028:
1029: fmt = GET_RTX_FORMAT (code);
1030: for (i = GET_RTX_LENGTH (code); i >= 0; i--)
1031: {
1032: if (fmt[i] == 'e')
1033: mark_jump_label (XEXP (x, i), insn, cross_jump);
1034: else if (fmt[i] == 'E')
1035: {
1036: register int j;
1037: for (j = 0; j < XVECLEN (x, i); j++)
1038: mark_jump_label (XVECEXP (x, i, j), insn, cross_jump);
1039: }
1040: }
1041: }
1042:
1043: /* If all INSN does is set the pc, delete it,
1044: and delete the insn that set the condition codes for it
1045: if that's what the previous thing was. */
1046:
1047: static void
1048: delete_jump (insn)
1049: rtx insn;
1050: {
1051: register rtx x = PATTERN (insn);
1052: register rtx prev;
1053:
1054: if (GET_CODE (x) == SET
1055: && GET_CODE (SET_DEST (x)) == PC)
1056: {
1057: prev = PREV_INSN (insn);
1058: delete_insn (insn);
1059: /* We assume that at this stage
1060: CC's are always set explicitly
1061: and always immediately before the jump that
1062: will use them. So if the previous insn
1063: exists to set the CC's, delete it. */
1064: while (prev && GET_CODE (prev) == NOTE)
1065: prev = PREV_INSN (prev);
1066: if (prev && GET_CODE (prev) == INSN
1067: && GET_CODE (PATTERN (prev)) == SET
1068: && SET_DEST (PATTERN (prev)) == cc0_rtx)
1069: delete_insn (prev);
1070: }
1071: }
1072:
1073: /* Delete insn INSN from the chain of insns and update label ref counts.
1074: May delete some following insns as a consequence; may even delete
1075: a label elsewhere and insns that follow it.
1076:
1077: Returns the first insn after INSN that was not deleted. */
1078:
1079: rtx
1080: delete_insn (insn)
1081: register rtx insn;
1082: {
1083: register rtx next = NEXT_INSN (insn);
1084: register rtx prev = PREV_INSN (insn);
1085:
1086: if (insn->volatil)
1087: {
1088: /* This insn is already deleted => return first following nondeleted. */
1089: while (next && next->volatil)
1090: next = NEXT_INSN (next);
1091: return next;
1092: }
1093:
1094: /* Mark this insn as deleted. */
1095:
1096: insn->volatil = 1;
1097:
1098: /* If instruction is followed by a barrier,
1099: delete the barrier too. */
1100:
1101: if (next != 0 && GET_CODE (next) == BARRIER)
1102: {
1103: next->volatil = 1;
1104: next = NEXT_INSN (next);
1105: }
1106:
1107: /* Patch out INSN (and the barrier if any) */
1108:
1109: if (optimize)
1110: {
1111: if (prev)
1112: NEXT_INSN (prev) = next;
1113:
1114: if (next)
1115: PREV_INSN (next)= prev;
1116: }
1117:
1118: /* If deleting a jump, decrement the count of the label,
1119: and delete the label if it is now unused. */
1120:
1121: if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
1122: if (--LABEL_NUSES (JUMP_LABEL (insn)) == 0)
1123: {
1124: /* This can delete NEXT or PREV,
1125: either directly if NEXT is JUMP_LABEL (INSN),
1126: or indirectly through more levels of jumps. */
1127: delete_insn (JUMP_LABEL (insn));
1128: /* I feel a little doubtful about this loop,
1129: but I see no clean and sure alternative way
1130: to find the first insn after INSN that is not now deleted.
1131: I hope this works. */
1132: while (next && next->volatil)
1133: next = NEXT_INSN (next);
1134: return next;
1135: }
1136:
1137: while (prev && GET_CODE (prev) == NOTE)
1138: prev = PREV_INSN (prev);
1139:
1140: /* If INSN was a label, delete insns following it if now unreachable. */
1141:
1142: if (GET_CODE (insn) == CODE_LABEL && prev
1143: && GET_CODE (prev) == BARRIER)
1144: {
1145: register RTX_CODE code;
1146: while (next != 0
1147: && ((code = GET_CODE (next)) == INSN
1148: || code == JUMP_INSN || code == CALL_INSN
1149: || code == NOTE))
1150: {
1151: if (code == NOTE
1152: && NOTE_LINE_NUMBER (next) != NOTE_INSN_FUNCTION_END)
1153: next = NEXT_INSN (next);
1154: else
1155: /* Note: if this deletes a jump, it can cause more
1156: deletion of unreachable code, after a different label.
1157: As long as the value from this recursive call is correct,
1158: this invocation functions correctly. */
1159: next = delete_insn (next);
1160: }
1161: }
1162:
1163: return next;
1164: }
1165:
1166: /* Advance from INSN till reaching something not deleted
1167: then return that. May return INSN itself. */
1168:
1169: rtx
1170: next_nondeleted_insn (insn)
1171: rtx insn;
1172: {
1173: while (insn->volatil)
1174: insn = NEXT_INSN (insn);
1175: return insn;
1176: }
1177:
1178: /* Invert the condition of the jump JUMP, and make it jump
1179: to label NLABEL instead of where it jumps now. */
1180:
1181: void
1182: invert_jump (jump, nlabel)
1183: rtx jump, nlabel;
1184: {
1185: register rtx olabel = JUMP_LABEL (jump);
1186: invert_exp (PATTERN (jump), olabel, nlabel);
1187: JUMP_LABEL (jump) = nlabel;
1188: ++LABEL_NUSES (nlabel);
1189: INSN_CODE (jump) = -1;
1190:
1191: if (--LABEL_NUSES (olabel) == 0)
1192: delete_insn (olabel);
1193: }
1194:
1195: /* Invert the jump condition of rtx X,
1196: and replace OLABEL with NLABEL throughout. */
1197:
1198: static void
1199: invert_exp (x, olabel, nlabel)
1200: rtx x;
1201: rtx olabel, nlabel;
1202: {
1203: register RTX_CODE code = GET_CODE (x);
1204: register int i;
1205: register char *fmt;
1206:
1207: if (code == IF_THEN_ELSE)
1208: {
1209: /* Inverting the jump condition of an IF_THEN_ELSE
1210: means exchanging the THEN-part with the ELSE-part. */
1211: register rtx tem = XEXP (x, 1);
1212: XEXP (x, 1) = XEXP (x, 2);
1213: XEXP (x, 2) = tem;
1214: }
1215:
1216: if (code == LABEL_REF)
1217: {
1218: if (XEXP (x, 0) == olabel)
1219: XEXP (x, 0) = nlabel;
1220: return;
1221: }
1222:
1223: fmt = GET_RTX_FORMAT (code);
1224: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1225: {
1226: if (fmt[i] == 'e')
1227: invert_exp (XEXP (x, i), olabel, nlabel);
1228: if (fmt[i] == 'E')
1229: {
1230: register int j;
1231: for (j = 0; j < XVECLEN (x, i); j++)
1232: invert_exp (XVECEXP (x, i, j), olabel, nlabel);
1233: }
1234: }
1235: }
1236:
1237: /* Make jump JUMP jump to label NLABEL instead of where it jumps now.
1238: If the old jump target label is unused as a result,
1239: it and the code following it may be deleted. */
1240:
1241: void
1242: redirect_jump (jump, nlabel)
1243: rtx jump, nlabel;
1244: {
1245: register rtx olabel = JUMP_LABEL (jump);
1246:
1247: if (nlabel == olabel)
1248: return;
1249:
1250: redirect_exp (PATTERN (jump), olabel, nlabel);
1251: JUMP_LABEL (jump) = nlabel;
1252: ++LABEL_NUSES (nlabel);
1253: INSN_CODE (jump) = -1;
1254:
1255: if (--LABEL_NUSES (olabel) == 0)
1256: delete_insn (olabel);
1257: }
1258:
1259: /* Throughout the rtx X,
1260: alter (LABEL_REF OLABEL) to (LABEL_REF NLABEL). */
1261:
1262: static void
1263: redirect_exp (x, olabel, nlabel)
1264: rtx x;
1265: rtx olabel, nlabel;
1266: {
1267: register RTX_CODE code = GET_CODE (x);
1268: register int i;
1269: register char *fmt;
1270:
1271: if (code == LABEL_REF)
1272: {
1273: if (XEXP (x, 0) == olabel)
1274: XEXP (x, 0) = nlabel;
1275: return;
1276: }
1277:
1278: fmt = GET_RTX_FORMAT (code);
1279: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1280: {
1281: if (fmt[i] == 'e')
1282: redirect_exp (XEXP (x, i), olabel, nlabel);
1283: if (fmt[i] == 'E')
1284: {
1285: register int j;
1286: for (j = 0; j < XVECLEN (x, i); j++)
1287: redirect_exp (XVECEXP (x, i, j), olabel, nlabel);
1288: }
1289: }
1290: }
1291:
1292: /* Like rtx_equal_p except that it considers two REGs as equal
1293: if they renumber to the same value. */
1294:
1295: int
1296: rtx_renumbered_equal_p (x, y)
1297: rtx x, y;
1298: {
1299: register int i;
1300: register RTX_CODE code = GET_CODE (x);
1301: register char *fmt;
1302:
1303: if (x == y)
1304: return 1;
1305: if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
1306: && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
1307: && GET_CODE (SUBREG_REG (y)) == REG)))
1308: {
1309: register int j;
1310:
1311: if (GET_MODE (x) != GET_MODE (y))
1312: return 0;
1313:
1314: if (code == SUBREG)
1315: {
1316: i = REGNO (SUBREG_REG (x));
1317: if (reg_renumber[i] >= 0)
1318: i = reg_renumber[i];
1319: i += SUBREG_WORD (x);
1320: }
1321: else
1322: {
1323: i = REGNO (x);
1324: if (reg_renumber[i] >= 0)
1325: i = reg_renumber[i];
1326: }
1327: if (GET_CODE (y) == SUBREG)
1328: {
1329: j = REGNO (SUBREG_REG (y));
1330: if (reg_renumber[j] >= 0)
1331: j = reg_renumber[j];
1332: j += SUBREG_WORD (y);
1333: }
1334: else
1335: {
1336: j = REGNO (y);
1337: if (reg_renumber[j] >= 0)
1338: j = reg_renumber[j];
1339: }
1340: return i == j;
1341: }
1342: /* Now we have disposed of all the cases
1343: in which different rtx codes can match. */
1344: if (code != GET_CODE (y))
1345: return 0;
1346: /* Two label-refs are equivalent if they point at labels
1347: in the same position in the instruction stream. */
1348: if (code == LABEL_REF)
1349: return (next_real_insn (XEXP (x, 0))
1350: == next_real_insn (XEXP (y, 0)));
1351: if (code == SYMBOL_REF)
1352: return XSTR (x, 0) == XSTR (y, 0);
1353:
1354: /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
1355:
1356: if (GET_MODE (x) != GET_MODE (y))
1357: return 0;
1358:
1359: /* Compare the elements. If any pair of corresponding elements
1360: fail to match, return 0 for the whole things. */
1361:
1362: fmt = GET_RTX_FORMAT (code);
1363: for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1364: {
1365: register int j;
1366: switch (fmt[i])
1367: {
1368: case 'i':
1369: if (XINT (x, i) != XINT (y, i))
1370: return 0;
1371: break;
1372:
1373: case 's':
1374: if (strcmp (XSTR (x, i), XSTR (y, i)))
1375: return 0;
1376: break;
1377:
1378: case 'e':
1379: if (! rtx_renumbered_equal_p (XEXP (x, i), XEXP (y, i)))
1380: return 0;
1381: break;
1382:
1383: case '0':
1384: break;
1385:
1386: case 'E':
1387: if (XVECLEN (x, i) != XVECLEN (y, i))
1388: return 0;
1389: for (j = XVECLEN (x, i) - 1; j >= 0; j--)
1390: if (!rtx_renumbered_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)))
1391: return 0;
1392: break;
1393:
1394: /* It is believed that rtx's at this level will never
1395: contain anything but integers and other rtx's,
1396: except for within LABEL_REFs and SYMBOL_REFs. */
1397: default:
1398: abort ();
1399: }
1400: }
1401: return 1;
1402: }
1403:
1404: /* If X is a hard register or equivalent to one or a subregister of one,
1405: return the hard register number. Otherwise, return -1.
1406: Any rtx is valid for X. */
1407:
1408: int
1409: true_regnum (x)
1410: rtx x;
1411: {
1412: if (GET_CODE (x) == REG)
1413: {
1414: if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
1415: return reg_renumber[REGNO (x)];
1416: return REGNO (x);
1417: }
1418: if (GET_CODE (x) == SUBREG)
1419: {
1420: int base = true_regnum (SUBREG_REG (x));
1421: if (base >= 0)
1422: return SUBREG_WORD (x) + base;
1423: }
1424: return -1;
1425: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.