1 /* Post-reload compare elimination.
2 Copyright (C) 2010-2018 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* There is a set of targets whose general-purpose move or addition
21 instructions clobber the flags. These targets cannot split their
22 CBRANCH/CSTORE etc patterns before reload is complete, lest reload
23 itself insert these instructions in between the flags setter and user.
24 Because these targets cannot split the compare from the use, they
25 cannot make use of the comparison elimination offered by the combine pass.
27 This is a small pass intended to provide comparison elimination similar to
28 what is available via NOTICE_UPDATE_CC for cc0 targets. This should help
29 encourage cc0 targets to convert to an explicit post-reload representation
34 (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
36 (1) All comparison patterns are represented as
38 [(set (reg:CC) (compare:CC (reg) (reg_or_immediate)))]
40 (2) All insn patterns that modify the flags are represented as
42 [(set (reg) (operation)
45 (3) If an insn of form (2) can usefully set the flags, there is
46 another pattern of the form
48 [(set (reg:CCM) (compare:CCM (operation) (immediate)))
49 (set (reg) (operation)]
51 The mode CCM will be chosen as if by SELECT_CC_MODE.
53 Note that unlike NOTICE_UPDATE_CC, we do not handle memory operands.
54 This could be handled as a future enhancement.
59 #include "coretypes.h"
66 #include "insn-config.h"
70 #include "tree-pass.h"
74 /* These structures describe a comparison and how it is used. */
76 /* The choice of maximum 3 uses comes from wanting to eliminate the two
77 duplicate compares from a three-way branch on the sign of a value.
78 This is also sufficient to eliminate the duplicate compare against the
79 high-part of a double-word comparison. */
84 /* The instruction in which the result of the compare is used. */
86 /* The location of the flags register within the use. */
88 /* The comparison code applied against the flags register. */
94 /* The comparison instruction. */
97 /* The insn prior to the comparison insn that clobbers the flags. */
98 rtx_insn
*prev_clobber
;
100 /* The insn prior to the comparison insn that sets in_a REG. */
101 rtx_insn
*in_a_setter
;
103 /* The two values being compared. These will be either REGs or
107 /* The REG_EH_REGION of the comparison. */
110 /* Information about how this comparison is used. */
111 struct comparison_use uses
[MAX_CMP_USE
];
113 /* The original CC_MODE for this comparison. */
114 machine_mode orig_mode
;
116 /* The number of uses identified for this comparison. */
117 unsigned short n_uses
;
119 /* True if not all uses of this comparison have been identified.
120 This can happen either for overflowing the array above, or if
121 the flags register is used in some unusual context. */
124 /* True if its inputs are still valid at the end of the block. */
128 static vec
<comparison
*> all_compares
;
130 /* Look for a "conforming" comparison, as defined above. If valid, return
131 the rtx for the COMPARE itself. */
134 conforming_compare (rtx_insn
*insn
)
138 set
= single_set (insn
);
143 if (GET_CODE (src
) != COMPARE
)
146 dest
= SET_DEST (set
);
147 if (!REG_P (dest
) || REGNO (dest
) != targetm
.flags_regnum
)
150 if (!REG_P (XEXP (src
, 0)))
153 if (CONSTANT_P (XEXP (src
, 1)) || REG_P (XEXP (src
, 1)))
156 if (GET_CODE (XEXP (src
, 1)) == UNSPEC
)
158 for (int i
= 0; i
< XVECLEN (XEXP (src
, 1), 0); i
++)
159 if (!REG_P (XVECEXP (XEXP (src
, 1), 0, i
)))
167 /* Look for a pattern of the "correct" form for an insn with a flags clobber
168 for which we may be able to eliminate a compare later. We're not looking
169 to validate any inputs at this time, merely see that the basic shape is
170 correct. The term "arithmetic" may be somewhat misleading... */
173 arithmetic_flags_clobber_p (rtx_insn
*insn
)
177 if (!NONJUMP_INSN_P (insn
))
179 pat
= PATTERN (insn
);
180 if (asm_noperands (pat
) >= 0)
183 if (GET_CODE (pat
) == PARALLEL
&& XVECLEN (pat
, 0) == 2)
185 x
= XVECEXP (pat
, 0, 0);
186 if (GET_CODE (x
) != SET
)
192 x
= XVECEXP (pat
, 0, 1);
193 if (GET_CODE (x
) == CLOBBER
)
196 if (REG_P (x
) && REGNO (x
) == targetm
.flags_regnum
)
204 /* Look for uses of FLAGS in INSN. If we find one we can analyze, record
205 it in CMP; otherwise indicate that we've missed a use. */
208 find_flags_uses_in_insn (struct comparison
*cmp
, rtx_insn
*insn
)
212 /* If we've already lost track of uses, don't bother collecting more. */
213 if (cmp
->missing_uses
)
216 /* Find a USE of the flags register. */
217 FOR_EACH_INSN_USE (use
, insn
)
218 if (DF_REF_REGNO (use
) == targetm
.flags_regnum
)
222 /* If this is an unusual use, quit. */
223 if (DF_REF_TYPE (use
) != DF_REF_REG_USE
)
226 /* If we've run out of slots to record uses, quit. */
227 if (cmp
->n_uses
== MAX_CMP_USE
)
230 /* Unfortunately the location of the flags register, while present
231 in the reference structure, doesn't help. We need to find the
232 comparison code that is outer to the actual flags use. */
233 loc
= DF_REF_LOC (use
);
235 if (GET_CODE (x
) == PARALLEL
)
236 x
= XVECEXP (x
, 0, 0);
238 if (GET_CODE (x
) == IF_THEN_ELSE
)
241 && loc
== &XEXP (x
, 0)
242 && XEXP (x
, 1) == const0_rtx
)
244 /* We've found a use of the flags that we understand. */
245 struct comparison_use
*cuse
= &cmp
->uses
[cmp
->n_uses
++];
248 cuse
->code
= GET_CODE (x
);
256 /* We failed to recognize this use of the flags register. */
257 cmp
->missing_uses
= true;
260 class find_comparison_dom_walker
: public dom_walker
263 find_comparison_dom_walker (cdi_direction direction
)
264 : dom_walker (direction
) {}
266 virtual edge
before_dom_children (basic_block
);
269 /* Return true if conforming COMPARE with EH_NOTE is redundant with comparison
270 CMP and can thus be eliminated. */
273 can_eliminate_compare (rtx compare
, rtx eh_note
, struct comparison
*cmp
)
275 /* Take care that it's in the same EH region. */
276 if (cfun
->can_throw_non_call_exceptions
277 && !rtx_equal_p (eh_note
, cmp
->eh_note
))
280 /* Make sure the compare is redundant with the previous. */
281 if (!rtx_equal_p (XEXP (compare
, 0), cmp
->in_a
)
282 || !rtx_equal_p (XEXP (compare
, 1), cmp
->in_b
))
285 /* New mode must be compatible with the previous compare mode. */
286 machine_mode new_mode
287 = targetm
.cc_modes_compatible (GET_MODE (compare
), cmp
->orig_mode
);
289 if (new_mode
== VOIDmode
)
292 if (cmp
->orig_mode
!= new_mode
)
294 /* Generate new comparison for substitution. */
295 rtx flags
= gen_rtx_REG (new_mode
, targetm
.flags_regnum
);
296 rtx x
= gen_rtx_COMPARE (new_mode
, cmp
->in_a
, cmp
->in_b
);
297 x
= gen_rtx_SET (flags
, x
);
299 if (!validate_change (cmp
->insn
, &PATTERN (cmp
->insn
), x
, false))
302 cmp
->orig_mode
= new_mode
;
308 /* Identify comparison instructions within BB. If the flags from the last
309 compare in the BB is live at the end of the block, install the compare
310 in BB->AUX. Called via dom_walker.walk (). */
313 find_comparison_dom_walker::before_dom_children (basic_block bb
)
315 rtx_insn
*insn
, *next
;
316 bool need_purge
= false;
317 rtx_insn
*last_setter
[FIRST_PSEUDO_REGISTER
];
319 /* The last comparison that was made. Will be reset to NULL
320 once the flags are clobbered. */
321 struct comparison
*last_cmp
= NULL
;
323 /* True iff the last comparison has not been clobbered, nor
324 have its inputs. Used to eliminate duplicate compares. */
325 bool last_cmp_valid
= false;
327 /* The last insn that clobbered the flags, if that insn is of
328 a form that may be valid for eliminating a following compare.
329 To be reset to NULL once the flags are set otherwise. */
330 rtx_insn
*last_clobber
= NULL
;
332 /* Propagate the last live comparison throughout the extended basic block. */
333 if (single_pred_p (bb
))
335 last_cmp
= (struct comparison
*) single_pred (bb
)->aux
;
337 last_cmp_valid
= last_cmp
->inputs_valid
;
340 memset (last_setter
, 0, sizeof (last_setter
));
341 for (insn
= BB_HEAD (bb
); insn
; insn
= next
)
345 next
= (insn
== BB_END (bb
) ? NULL
: NEXT_INSN (insn
));
346 if (!NONDEBUG_INSN_P (insn
))
349 src
= conforming_compare (insn
);
354 if (cfun
->can_throw_non_call_exceptions
)
355 eh_note
= find_reg_note (insn
, REG_EH_REGION
, NULL
);
357 if (last_cmp_valid
&& can_eliminate_compare (src
, eh_note
, last_cmp
))
365 last_cmp
= XCNEW (struct comparison
);
366 last_cmp
->insn
= insn
;
367 last_cmp
->prev_clobber
= last_clobber
;
368 last_cmp
->in_a
= XEXP (src
, 0);
369 last_cmp
->in_b
= XEXP (src
, 1);
370 last_cmp
->eh_note
= eh_note
;
371 last_cmp
->orig_mode
= GET_MODE (src
);
372 if (last_cmp
->in_b
== const0_rtx
373 && last_setter
[REGNO (last_cmp
->in_a
)])
375 rtx set
= single_set (last_setter
[REGNO (last_cmp
->in_a
)]);
376 if (set
&& rtx_equal_p (SET_DEST (set
), last_cmp
->in_a
))
377 last_cmp
->in_a_setter
= last_setter
[REGNO (last_cmp
->in_a
)];
379 all_compares
.safe_push (last_cmp
);
381 /* It's unusual, but be prepared for comparison patterns that
382 also clobber an input, or perhaps a scratch. */
384 last_cmp_valid
= true;
389 /* Notice if this instruction uses the flags register. */
391 find_flags_uses_in_insn (last_cmp
, insn
);
393 /* Notice if this instruction kills the flags register. */
395 FOR_EACH_INSN_DEF (def
, insn
)
396 if (DF_REF_REGNO (def
) == targetm
.flags_regnum
)
398 /* See if this insn could be the "clobber" that eliminates
399 a future comparison. */
400 last_clobber
= (arithmetic_flags_clobber_p (insn
)
403 /* In either case, the previous compare is no longer valid. */
405 last_cmp_valid
= false;
410 /* Notice if any of the inputs to the comparison have changed
411 and remember last insn that sets each register. */
413 FOR_EACH_INSN_DEF (def
, insn
)
416 && (DF_REF_REGNO (def
) == REGNO (last_cmp
->in_a
)
417 || (REG_P (last_cmp
->in_b
)
418 && DF_REF_REGNO (def
) == REGNO (last_cmp
->in_b
))))
419 last_cmp_valid
= false;
420 last_setter
[DF_REF_REGNO (def
)] = insn
;
424 /* Remember the live comparison for subsequent members of
425 the extended basic block. */
429 last_cmp
->inputs_valid
= last_cmp_valid
;
431 /* Look to see if the flags register is live outgoing here, and
432 incoming to any successor not part of the extended basic block. */
433 if (bitmap_bit_p (df_get_live_out (bb
), targetm
.flags_regnum
))
438 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
440 basic_block dest
= e
->dest
;
441 if (bitmap_bit_p (df_get_live_in (bb
), targetm
.flags_regnum
)
442 && !single_pred_p (dest
))
444 last_cmp
->missing_uses
= true;
451 /* If we deleted a compare with a REG_EH_REGION note, we may need to
454 purge_dead_edges (bb
);
459 /* Find all comparisons in the function. */
462 find_comparisons (void)
464 calculate_dominance_info (CDI_DOMINATORS
);
466 find_comparison_dom_walker (CDI_DOMINATORS
)
467 .walk (cfun
->cfg
->x_entry_block_ptr
);
469 clear_aux_for_blocks ();
470 free_dominance_info (CDI_DOMINATORS
);
473 /* Select an alternate CC_MODE for a comparison insn comparing A and B.
474 Note that inputs are almost certainly different than the IN_A and IN_B
475 stored in CMP -- we're called while attempting to eliminate the compare
476 after all. Return the new FLAGS rtx if successful, else return NULL.
477 Note that this function may start a change group. */
480 maybe_select_cc_mode (struct comparison
*cmp
, rtx a ATTRIBUTE_UNUSED
,
481 rtx b ATTRIBUTE_UNUSED
)
483 machine_mode sel_mode
;
484 const int n
= cmp
->n_uses
;
487 #ifndef SELECT_CC_MODE
488 /* Minimize code differences when this target macro is undefined. */
490 #define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
493 /* If we don't have access to all of the uses, we can't validate. */
494 if (cmp
->missing_uses
|| n
== 0)
497 /* Find a new mode that works for all of the uses. Special case the
498 common case of exactly one use. */
501 sel_mode
= SELECT_CC_MODE (cmp
->uses
[0].code
, a
, b
);
502 if (sel_mode
!= cmp
->orig_mode
)
504 flags
= gen_rtx_REG (sel_mode
, targetm
.flags_regnum
);
505 validate_change (cmp
->uses
[0].insn
, cmp
->uses
[0].loc
, flags
, true);
512 sel_mode
= SELECT_CC_MODE (cmp
->uses
[0].code
, a
, b
);
513 for (i
= 1; i
< n
; ++i
)
515 machine_mode new_mode
= SELECT_CC_MODE (cmp
->uses
[i
].code
, a
, b
);
516 if (new_mode
!= sel_mode
)
518 sel_mode
= targetm
.cc_modes_compatible (sel_mode
, new_mode
);
519 if (sel_mode
== VOIDmode
)
524 if (sel_mode
!= cmp
->orig_mode
)
526 flags
= gen_rtx_REG (sel_mode
, targetm
.flags_regnum
);
527 for (i
= 0; i
< n
; ++i
)
528 validate_change (cmp
->uses
[i
].insn
, cmp
->uses
[i
].loc
, flags
, true);
535 /* Return a register RTX holding the same value at START as REG at END, or
536 NULL_RTX if there is none. */
539 equivalent_reg_at_start (rtx reg
, rtx_insn
*end
, rtx_insn
*start
)
541 machine_mode orig_mode
= GET_MODE (reg
);
542 rtx_insn
*bb_head
= BB_HEAD (BLOCK_FOR_INSN (end
));
544 for (rtx_insn
*insn
= PREV_INSN (end
);
546 insn
= PREV_INSN (insn
))
548 const int abnormal_flags
549 = (DF_REF_CONDITIONAL
| DF_REF_PARTIAL
| DF_REF_MAY_CLOBBER
550 | DF_REF_MUST_CLOBBER
| DF_REF_SIGN_EXTRACT
551 | DF_REF_ZERO_EXTRACT
| DF_REF_STRICT_LOW_PART
552 | DF_REF_PRE_POST_MODIFY
);
555 /* Note that the BB_HEAD is always either a note or a label, but in
556 any case it means that REG is defined outside the block. */
559 if (NOTE_P (insn
) || DEBUG_INSN_P (insn
))
562 /* Find a possible def of REG in INSN. */
563 FOR_EACH_INSN_DEF (def
, insn
)
564 if (DF_REF_REGNO (def
) == REGNO (reg
))
567 /* No definitions of REG; continue searching. */
571 /* Bail if this is not a totally normal set of REG. */
572 if (DF_REF_IS_ARTIFICIAL (def
))
574 if (DF_REF_FLAGS (def
) & abnormal_flags
)
577 /* We've found an insn between the compare and the clobber that sets
578 REG. Given that pass_cprop_hardreg has not yet run, we still find
579 situations in which we can usefully look through a copy insn. */
580 rtx x
= single_set (insn
);
588 if (GET_MODE (reg
) != orig_mode
)
594 /* Return true if it is okay to merge the comparison CMP_INSN with
595 the instruction ARITH_INSN. Both instructions are assumed to be in the
596 same basic block with ARITH_INSN appearing before CMP_INSN. This checks
597 that there are no uses or defs of the condition flags or control flow
598 changes between the two instructions. */
601 can_merge_compare_into_arith (rtx_insn
*cmp_insn
, rtx_insn
*arith_insn
)
603 for (rtx_insn
*insn
= PREV_INSN (cmp_insn
);
604 insn
&& insn
!= arith_insn
;
605 insn
= PREV_INSN (insn
))
607 if (!NONDEBUG_INSN_P (insn
))
609 /* Bail if there are jumps or calls in between. */
610 if (!NONJUMP_INSN_P (insn
))
613 /* Bail on old-style asm statements because they lack
614 data flow information. */
615 if (GET_CODE (PATTERN (insn
)) == ASM_INPUT
)
619 /* Find a USE of the flags register. */
620 FOR_EACH_INSN_USE (ref
, insn
)
621 if (DF_REF_REGNO (ref
) == targetm
.flags_regnum
)
624 /* Find a DEF of the flags register. */
625 FOR_EACH_INSN_DEF (ref
, insn
)
626 if (DF_REF_REGNO (ref
) == targetm
.flags_regnum
)
632 /* Given two SET expressions, SET_A and SET_B determine whether they form
633 a recognizable pattern when emitted in parallel. Return that parallel
634 if so. Otherwise return NULL. */
637 try_validate_parallel (rtx set_a
, rtx set_b
)
639 rtx par
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (2, set_a
, set_b
));
640 rtx_insn
*insn
= make_insn_raw (par
);
642 if (insn_invalid_p (insn
, false))
644 crtl
->emit
.x_cur_insn_uid
--;
648 SET_PREV_INSN (insn
) = NULL_RTX
;
649 SET_NEXT_INSN (insn
) = NULL_RTX
;
650 INSN_LOCATION (insn
) = 0;
654 /* For a comparison instruction described by CMP check if it compares a
655 register with zero i.e. it is of the form CC := CMP R1, 0.
656 If it is, find the instruction defining R1 (say I1) and try to create a
657 PARALLEL consisting of I1 and the comparison, representing a flag-setting
658 arithmetic instruction. Example:
660 <instructions that don't read the condition register>
662 I2 can be merged with I1 into:
663 I1: { CC := CMP (R2 + R3) 0 ; R1 := R2 + R3 }
664 This catches cases where R1 is used between I1 and I2 and therefore
665 combine and other RTL optimisations will not try to propagate it into
666 I2. Return true if we succeeded in merging CMP. */
669 try_merge_compare (struct comparison
*cmp
)
671 rtx_insn
*cmp_insn
= cmp
->insn
;
673 if (cmp
->in_b
!= const0_rtx
|| cmp
->in_a_setter
== NULL
)
675 rtx in_a
= cmp
->in_a
;
678 FOR_EACH_INSN_USE (use
, cmp_insn
)
679 if (DF_REF_REGNO (use
) == REGNO (in_a
))
684 rtx_insn
*def_insn
= cmp
->in_a_setter
;
685 rtx set
= single_set (def_insn
);
689 if (!can_merge_compare_into_arith (cmp_insn
, def_insn
))
692 rtx src
= SET_SRC (set
);
694 /* If the source uses addressing modes with side effects, we can't
695 do the merge because we'd end up with a PARALLEL that has two
696 instances of that side effect in it. */
697 if (side_effects_p (src
))
700 rtx flags
= maybe_select_cc_mode (cmp
, src
, CONST0_RTX (GET_MODE (src
)));
703 /* We may already have a change group going through maybe_select_cc_mode.
704 Discard it properly. */
710 = gen_rtx_SET (flags
, gen_rtx_COMPARE (GET_MODE (flags
),
712 CONST0_RTX (GET_MODE (src
))));
713 rtx arith_set
= copy_rtx (PATTERN (def_insn
));
714 rtx par
= try_validate_parallel (flag_set
, arith_set
);
717 /* We may already have a change group going through maybe_select_cc_mode.
718 Discard it properly. */
722 if (!apply_change_group ())
724 emit_insn_after (par
, def_insn
);
725 delete_insn (def_insn
);
726 delete_insn (cmp
->insn
);
730 /* Attempt to replace a comparison with a prior arithmetic insn that can
731 compute the same flags value as the comparison itself. Return true if
732 successful, having made all rtl modifications necessary. */
735 try_eliminate_compare (struct comparison
*cmp
)
737 rtx flags
, in_a
, in_b
, cmp_src
;
739 if (try_merge_compare (cmp
))
742 /* We must have found an interesting "clobber" preceding the compare. */
743 if (cmp
->prev_clobber
== NULL
)
746 /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
747 Given that this target requires this pass, we can assume that most
748 insns do clobber the flags, and so the distance between the compare
749 and the clobber is likely to be small. */
750 /* ??? This is one point at which one could argue that DF_REF_CHAIN would
751 be useful, but it is thought to be too heavy-weight a solution here. */
752 in_a
= equivalent_reg_at_start (cmp
->in_a
, cmp
->insn
, cmp
->prev_clobber
);
756 /* Likewise for IN_B if need be. */
757 if (CONSTANT_P (cmp
->in_b
))
759 else if (REG_P (cmp
->in_b
))
761 in_b
= equivalent_reg_at_start (cmp
->in_b
, cmp
->insn
, cmp
->prev_clobber
);
765 else if (GET_CODE (cmp
->in_b
) == UNSPEC
)
767 const int len
= XVECLEN (cmp
->in_b
, 0);
768 rtvec v
= rtvec_alloc (len
);
769 for (int i
= 0; i
< len
; i
++)
771 rtx r
= equivalent_reg_at_start (XVECEXP (cmp
->in_b
, 0, i
),
772 cmp
->insn
, cmp
->prev_clobber
);
775 RTVEC_ELT (v
, i
) = r
;
777 in_b
= gen_rtx_UNSPEC (GET_MODE (cmp
->in_b
), v
, XINT (cmp
->in_b
, 1));
782 /* We've reached PREV_CLOBBER without finding a modification of IN_A.
783 Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
784 recall that we've already validated the shape of PREV_CLOBBER. */
785 rtx_insn
*insn
= cmp
->prev_clobber
;
787 rtx x
= XVECEXP (PATTERN (insn
), 0, 0);
788 if (rtx_equal_p (SET_DEST (x
), in_a
))
789 cmp_src
= SET_SRC (x
);
791 /* Also check operations with implicit extensions, e.g.:
793 (zero_extend:DI (plus:SI (reg:SI) (reg:SI))))
795 (compare:CCZ (plus:SI (reg:SI) (reg:SI))
797 else if (REG_P (SET_DEST (x
))
799 && REGNO (SET_DEST (x
)) == REGNO (in_a
)
800 && (GET_CODE (SET_SRC (x
)) == ZERO_EXTEND
801 || GET_CODE (SET_SRC (x
)) == SIGN_EXTEND
)
802 && GET_MODE (XEXP (SET_SRC (x
), 0)) == GET_MODE (in_a
))
803 cmp_src
= XEXP (SET_SRC (x
), 0);
805 /* Also check fully redundant comparisons, e.g.:
807 (minus:SI (reg:SI) (reg:SI))))
809 (compare:CC (reg:SI) (reg:SI)))] */
810 else if (REG_P (in_b
)
811 && GET_CODE (SET_SRC (x
)) == MINUS
812 && rtx_equal_p (XEXP (SET_SRC (x
), 0), in_a
)
813 && rtx_equal_p (XEXP (SET_SRC (x
), 1), in_b
))
819 /* If the source uses addressing modes with side effects, we can't
820 do the merge because we'd end up with a PARALLEL that has two
821 instances of that side effect in it. */
822 if (side_effects_p (cmp_src
))
825 /* Determine if we ought to use a different CC_MODE here. */
826 flags
= maybe_select_cc_mode (cmp
, cmp_src
, in_b
);
828 flags
= gen_rtx_REG (cmp
->orig_mode
, targetm
.flags_regnum
);
830 /* Generate a new comparison for installation in the setter. */
831 rtx y
= copy_rtx (cmp_src
);
832 y
= gen_rtx_COMPARE (GET_MODE (flags
), y
, in_b
);
833 y
= gen_rtx_SET (flags
, y
);
835 /* Canonicalize instruction to:
836 [(set (reg:CCM) (compare:CCM (operation) (immediate)))
837 (set (reg) (operation)] */
839 rtvec v
= rtvec_alloc (2);
840 RTVEC_ELT (v
, 0) = y
;
841 RTVEC_ELT (v
, 1) = x
;
843 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, v
);
845 /* Succeed if the new instruction is valid. Note that we may have started
846 a change group within maybe_select_cc_mode, therefore we must continue. */
847 validate_change (insn
, &PATTERN (insn
), pat
, true);
849 if (!apply_change_group ())
852 /* Success. Delete the compare insn... */
853 delete_insn (cmp
->insn
);
855 /* ... and any notes that are now invalid due to multiple sets. */
856 x
= find_regno_note (insn
, REG_UNUSED
, targetm
.flags_regnum
);
858 remove_note (insn
, x
);
859 x
= find_reg_note (insn
, REG_EQUAL
, NULL
);
861 remove_note (insn
, x
);
862 x
= find_reg_note (insn
, REG_EQUIV
, NULL
);
864 remove_note (insn
, x
);
869 /* Main entry point to the pass. */
872 execute_compare_elim_after_reload (void)
876 gcc_checking_assert (!all_compares
.exists ());
878 /* Locate all comparisons and their uses, and eliminate duplicates. */
880 if (all_compares
.exists ())
882 struct comparison
*cmp
;
885 /* Eliminate comparisons that are redundant with flags computation. */
886 FOR_EACH_VEC_ELT (all_compares
, i
, cmp
)
888 try_eliminate_compare (cmp
);
892 all_compares
.release ();
900 const pass_data pass_data_compare_elim_after_reload
=
903 "cmpelim", /* name */
904 OPTGROUP_NONE
, /* optinfo_flags */
906 0, /* properties_required */
907 0, /* properties_provided */
908 0, /* properties_destroyed */
909 0, /* todo_flags_start */
910 ( TODO_df_finish
| TODO_df_verify
), /* todo_flags_finish */
913 class pass_compare_elim_after_reload
: public rtl_opt_pass
916 pass_compare_elim_after_reload (gcc::context
*ctxt
)
917 : rtl_opt_pass (pass_data_compare_elim_after_reload
, ctxt
)
920 /* opt_pass methods: */
921 virtual bool gate (function
*)
923 /* Setting this target hook value is how a backend indicates the need. */
924 if (targetm
.flags_regnum
== INVALID_REGNUM
)
926 return flag_compare_elim_after_reload
;
929 virtual unsigned int execute (function
*)
931 return execute_compare_elim_after_reload ();
934 }; // class pass_compare_elim_after_reload
939 make_pass_compare_elim_after_reload (gcc::context
*ctxt
)
941 return new pass_compare_elim_after_reload (ctxt
);