1 /* Post-reload compare elimination.
2 Copyright (C) 2010-2021 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. */
127 /* Whether IN_A is wrapped in a NOT before being compared. */
131 static vec
<comparison
*> all_compares
;
133 /* Return whether X is a NOT unary expression. */
138 return GET_CODE (x
) == NOT
;
141 /* Strip a NOT unary expression around X, if any. */
152 /* Look for a "conforming" comparison, as defined above. If valid, return
153 the rtx for the COMPARE itself. */
156 conforming_compare (rtx_insn
*insn
)
160 set
= single_set (insn
);
165 if (GET_CODE (src
) != COMPARE
)
168 dest
= SET_DEST (set
);
169 if (!REG_P (dest
) || REGNO (dest
) != targetm
.flags_regnum
)
172 if (!REG_P (strip_not (XEXP (src
, 0))))
175 if (CONSTANT_P (XEXP (src
, 1)) || REG_P (XEXP (src
, 1)))
178 if (GET_CODE (XEXP (src
, 1)) == UNSPEC
)
180 for (int i
= 0; i
< XVECLEN (XEXP (src
, 1), 0); i
++)
181 if (!REG_P (XVECEXP (XEXP (src
, 1), 0, i
)))
189 /* Look for a pattern of the "correct" form for an insn with a flags clobber
190 for which we may be able to eliminate a compare later. We're not looking
191 to validate any inputs at this time, merely see that the basic shape is
192 correct. The term "arithmetic" may be somewhat misleading... */
195 arithmetic_flags_clobber_p (rtx_insn
*insn
)
199 if (!NONJUMP_INSN_P (insn
))
201 pat
= PATTERN (insn
);
202 if (asm_noperands (pat
) >= 0)
205 if (GET_CODE (pat
) == PARALLEL
&& XVECLEN (pat
, 0) == 2)
207 x
= XVECEXP (pat
, 0, 0);
208 if (GET_CODE (x
) != SET
)
214 x
= XVECEXP (pat
, 0, 1);
215 if (GET_CODE (x
) == CLOBBER
)
218 if (REG_P (x
) && REGNO (x
) == targetm
.flags_regnum
)
226 /* Look for uses of FLAGS in INSN. If we find one we can analyze, record
227 it in CMP; otherwise indicate that we've missed a use. */
230 find_flags_uses_in_insn (struct comparison
*cmp
, rtx_insn
*insn
)
234 /* If we've already lost track of uses, don't bother collecting more. */
235 if (cmp
->missing_uses
)
238 /* Find a USE of the flags register. */
239 FOR_EACH_INSN_USE (use
, insn
)
240 if (DF_REF_REGNO (use
) == targetm
.flags_regnum
)
244 /* If this is an unusual use, quit. */
245 if (DF_REF_TYPE (use
) != DF_REF_REG_USE
)
248 /* If we've run out of slots to record uses, quit. */
249 if (cmp
->n_uses
== MAX_CMP_USE
)
252 /* Unfortunately the location of the flags register, while present
253 in the reference structure, doesn't help. We need to find the
254 comparison code that is outer to the actual flags use. */
255 loc
= DF_REF_LOC (use
);
257 if (GET_CODE (x
) == PARALLEL
)
258 x
= XVECEXP (x
, 0, 0);
260 if (GET_CODE (x
) == IF_THEN_ELSE
)
263 && loc
== &XEXP (x
, 0)
264 && XEXP (x
, 1) == const0_rtx
)
266 /* We've found a use of the flags that we understand. */
267 struct comparison_use
*cuse
= &cmp
->uses
[cmp
->n_uses
++];
270 cuse
->code
= GET_CODE (x
);
278 /* We failed to recognize this use of the flags register. */
279 cmp
->missing_uses
= true;
282 class find_comparison_dom_walker
: public dom_walker
285 find_comparison_dom_walker (cdi_direction direction
)
286 : dom_walker (direction
) {}
288 virtual edge
before_dom_children (basic_block
);
291 /* Return true if conforming COMPARE with EH_NOTE is redundant with comparison
292 CMP and can thus be eliminated. */
295 can_eliminate_compare (rtx compare
, rtx eh_note
, struct comparison
*cmp
)
297 /* Take care that it's in the same EH region. */
298 if (cfun
->can_throw_non_call_exceptions
299 && !rtx_equal_p (eh_note
, cmp
->eh_note
))
302 /* Make sure the compare is redundant with the previous. */
303 if (!rtx_equal_p (strip_not (XEXP (compare
, 0)), cmp
->in_a
)
304 || !rtx_equal_p (XEXP (compare
, 1), cmp
->in_b
))
307 if (is_not (XEXP (compare
, 0)) != cmp
->not_in_a
)
310 /* New mode must be compatible with the previous compare mode. */
311 machine_mode new_mode
312 = targetm
.cc_modes_compatible (GET_MODE (compare
), cmp
->orig_mode
);
314 if (new_mode
== VOIDmode
)
317 if (cmp
->orig_mode
!= new_mode
)
319 /* Generate new comparison for substitution. */
320 rtx flags
= gen_rtx_REG (new_mode
, targetm
.flags_regnum
);
321 rtx x
= gen_rtx_COMPARE (new_mode
, cmp
->in_a
, cmp
->in_b
);
322 x
= gen_rtx_SET (flags
, x
);
324 if (!validate_change (cmp
->insn
, &PATTERN (cmp
->insn
), x
, false))
327 cmp
->orig_mode
= new_mode
;
333 /* Identify comparison instructions within BB. If the flags from the last
334 compare in the BB is live at the end of the block, install the compare
335 in BB->AUX. Called via dom_walker.walk (). */
338 find_comparison_dom_walker::before_dom_children (basic_block bb
)
340 rtx_insn
*insn
, *next
;
341 bool need_purge
= false;
342 rtx_insn
*last_setter
[FIRST_PSEUDO_REGISTER
];
344 /* The last comparison that was made. Will be reset to NULL
345 once the flags are clobbered. */
346 struct comparison
*last_cmp
= NULL
;
348 /* True iff the last comparison has not been clobbered, nor
349 have its inputs. Used to eliminate duplicate compares. */
350 bool last_cmp_valid
= false;
352 /* The last insn that clobbered the flags, if that insn is of
353 a form that may be valid for eliminating a following compare.
354 To be reset to NULL once the flags are set otherwise. */
355 rtx_insn
*last_clobber
= NULL
;
357 /* Propagate the last live comparison throughout the extended basic block. */
358 if (single_pred_p (bb
))
360 last_cmp
= (struct comparison
*) single_pred (bb
)->aux
;
362 last_cmp_valid
= last_cmp
->inputs_valid
;
365 memset (last_setter
, 0, sizeof (last_setter
));
366 for (insn
= BB_HEAD (bb
); insn
; insn
= next
)
370 next
= (insn
== BB_END (bb
) ? NULL
: NEXT_INSN (insn
));
371 if (!NONDEBUG_INSN_P (insn
))
374 src
= conforming_compare (insn
);
379 if (cfun
->can_throw_non_call_exceptions
)
380 eh_note
= find_reg_note (insn
, REG_EH_REGION
, NULL
);
382 if (last_cmp_valid
&& can_eliminate_compare (src
, eh_note
, last_cmp
))
390 last_cmp
= XCNEW (struct comparison
);
391 last_cmp
->insn
= insn
;
392 last_cmp
->prev_clobber
= last_clobber
;
393 last_cmp
->in_a
= strip_not (XEXP (src
, 0));
394 last_cmp
->in_b
= XEXP (src
, 1);
395 last_cmp
->not_in_a
= is_not (XEXP (src
, 0));
396 last_cmp
->eh_note
= eh_note
;
397 last_cmp
->orig_mode
= GET_MODE (src
);
398 if (last_cmp
->in_b
== const0_rtx
399 && last_setter
[REGNO (last_cmp
->in_a
)])
401 rtx set
= single_set (last_setter
[REGNO (last_cmp
->in_a
)]);
402 if (set
&& rtx_equal_p (SET_DEST (set
), last_cmp
->in_a
))
403 last_cmp
->in_a_setter
= last_setter
[REGNO (last_cmp
->in_a
)];
405 all_compares
.safe_push (last_cmp
);
407 /* It's unusual, but be prepared for comparison patterns that
408 also clobber an input, or perhaps a scratch. */
410 last_cmp_valid
= true;
415 /* Notice if this instruction uses the flags register. */
417 find_flags_uses_in_insn (last_cmp
, insn
);
419 /* Notice if this instruction kills the flags register. */
421 FOR_EACH_INSN_DEF (def
, insn
)
422 if (DF_REF_REGNO (def
) == targetm
.flags_regnum
)
424 /* See if this insn could be the "clobber" that eliminates
425 a future comparison. */
426 last_clobber
= (arithmetic_flags_clobber_p (insn
)
429 /* In either case, the previous compare is no longer valid. */
431 last_cmp_valid
= false;
436 /* Notice if any of the inputs to the comparison have changed
437 and remember last insn that sets each register. */
439 FOR_EACH_INSN_DEF (def
, insn
)
442 && (DF_REF_REGNO (def
) == REGNO (last_cmp
->in_a
)
443 || (REG_P (last_cmp
->in_b
)
444 && DF_REF_REGNO (def
) == REGNO (last_cmp
->in_b
))))
445 last_cmp_valid
= false;
446 last_setter
[DF_REF_REGNO (def
)] = insn
;
450 /* Remember the live comparison for subsequent members of
451 the extended basic block. */
455 last_cmp
->inputs_valid
= last_cmp_valid
;
457 /* Look to see if the flags register is live outgoing here, and
458 incoming to any successor not part of the extended basic block. */
459 if (bitmap_bit_p (df_get_live_out (bb
), targetm
.flags_regnum
))
464 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
466 basic_block dest
= e
->dest
;
467 if (bitmap_bit_p (df_get_live_in (bb
), targetm
.flags_regnum
)
468 && !single_pred_p (dest
))
470 last_cmp
->missing_uses
= true;
477 /* If we deleted a compare with a REG_EH_REGION note, we may need to
480 purge_dead_edges (bb
);
485 /* Find all comparisons in the function. */
488 find_comparisons (void)
490 calculate_dominance_info (CDI_DOMINATORS
);
492 find_comparison_dom_walker (CDI_DOMINATORS
)
493 .walk (cfun
->cfg
->x_entry_block_ptr
);
495 clear_aux_for_blocks ();
496 free_dominance_info (CDI_DOMINATORS
);
499 /* Select an alternate CC_MODE for a comparison insn comparing A and B.
500 Note that inputs are almost certainly different than the IN_A and IN_B
501 stored in CMP -- we're called while attempting to eliminate the compare
502 after all. Return the new FLAGS rtx if successful, else return NULL.
503 Note that this function may start a change group. */
506 maybe_select_cc_mode (struct comparison
*cmp
, rtx a ATTRIBUTE_UNUSED
,
507 rtx b ATTRIBUTE_UNUSED
)
509 machine_mode sel_mode
;
510 const int n
= cmp
->n_uses
;
513 #ifndef SELECT_CC_MODE
514 /* Minimize code differences when this target macro is undefined. */
516 #define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
519 /* If we don't have access to all of the uses, we can't validate. */
520 if (cmp
->missing_uses
|| n
== 0)
523 /* Find a new mode that works for all of the uses. Special case the
524 common case of exactly one use. */
527 sel_mode
= SELECT_CC_MODE (cmp
->uses
[0].code
, a
, b
);
528 if (sel_mode
!= cmp
->orig_mode
)
530 flags
= gen_rtx_REG (sel_mode
, targetm
.flags_regnum
);
531 validate_change (cmp
->uses
[0].insn
, cmp
->uses
[0].loc
, flags
, true);
538 sel_mode
= SELECT_CC_MODE (cmp
->uses
[0].code
, a
, b
);
539 for (i
= 1; i
< n
; ++i
)
541 machine_mode new_mode
= SELECT_CC_MODE (cmp
->uses
[i
].code
, a
, b
);
542 if (new_mode
!= sel_mode
)
544 sel_mode
= targetm
.cc_modes_compatible (sel_mode
, new_mode
);
545 if (sel_mode
== VOIDmode
)
550 if (sel_mode
!= cmp
->orig_mode
)
552 flags
= gen_rtx_REG (sel_mode
, targetm
.flags_regnum
);
553 for (i
= 0; i
< n
; ++i
)
554 validate_change (cmp
->uses
[i
].insn
, cmp
->uses
[i
].loc
, flags
, true);
561 /* Return a register RTX holding the same value at START as REG at END, or
562 NULL_RTX if there is none. */
565 equivalent_reg_at_start (rtx reg
, rtx_insn
*end
, rtx_insn
*start
)
567 machine_mode orig_mode
= GET_MODE (reg
);
568 rtx_insn
*bb_head
= BB_HEAD (BLOCK_FOR_INSN (end
));
570 for (rtx_insn
*insn
= PREV_INSN (end
);
572 insn
= PREV_INSN (insn
))
574 const int abnormal_flags
575 = (DF_REF_CONDITIONAL
| DF_REF_PARTIAL
| DF_REF_MAY_CLOBBER
576 | DF_REF_MUST_CLOBBER
| DF_REF_SIGN_EXTRACT
577 | DF_REF_ZERO_EXTRACT
| DF_REF_STRICT_LOW_PART
578 | DF_REF_PRE_POST_MODIFY
);
581 /* Note that the BB_HEAD is always either a note or a label, but in
582 any case it means that REG is defined outside the block. */
585 if (NOTE_P (insn
) || DEBUG_INSN_P (insn
))
588 /* Find a possible def of REG in INSN. */
589 FOR_EACH_INSN_DEF (def
, insn
)
590 if (DF_REF_REGNO (def
) == REGNO (reg
))
593 /* No definitions of REG; continue searching. */
597 /* Bail if this is not a totally normal set of REG. */
598 if (DF_REF_IS_ARTIFICIAL (def
))
600 if (DF_REF_FLAGS (def
) & abnormal_flags
)
603 /* We've found an insn between the compare and the clobber that sets
604 REG. Given that pass_cprop_hardreg has not yet run, we still find
605 situations in which we can usefully look through a copy insn. */
606 rtx x
= single_set (insn
);
614 if (GET_MODE (reg
) != orig_mode
)
620 /* Return true if it is okay to merge the comparison CMP_INSN with
621 the instruction ARITH_INSN. Both instructions are assumed to be in the
622 same basic block with ARITH_INSN appearing before CMP_INSN. This checks
623 that there are no uses or defs of the condition flags or control flow
624 changes between the two instructions. */
627 can_merge_compare_into_arith (rtx_insn
*cmp_insn
, rtx_insn
*arith_insn
)
629 for (rtx_insn
*insn
= PREV_INSN (cmp_insn
);
630 insn
&& insn
!= arith_insn
;
631 insn
= PREV_INSN (insn
))
633 if (!NONDEBUG_INSN_P (insn
))
635 /* Bail if there are jumps or calls in between. */
636 if (!NONJUMP_INSN_P (insn
))
639 /* Bail on old-style asm statements because they lack
640 data flow information. */
641 if (GET_CODE (PATTERN (insn
)) == ASM_INPUT
)
645 /* Find a USE of the flags register. */
646 FOR_EACH_INSN_USE (ref
, insn
)
647 if (DF_REF_REGNO (ref
) == targetm
.flags_regnum
)
650 /* Find a DEF of the flags register. */
651 FOR_EACH_INSN_DEF (ref
, insn
)
652 if (DF_REF_REGNO (ref
) == targetm
.flags_regnum
)
658 /* Given two SET expressions, SET_A and SET_B determine whether they form
659 a recognizable pattern when emitted in parallel. Return that parallel
660 if so. Otherwise return NULL. */
663 try_validate_parallel (rtx set_a
, rtx set_b
)
665 rtx par
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (2, set_a
, set_b
));
666 rtx_insn
*insn
= make_insn_raw (par
);
668 if (insn_invalid_p (insn
, false))
670 crtl
->emit
.x_cur_insn_uid
--;
674 SET_PREV_INSN (insn
) = NULL_RTX
;
675 SET_NEXT_INSN (insn
) = NULL_RTX
;
676 INSN_LOCATION (insn
) = 0;
680 /* For a comparison instruction described by CMP check if it compares a
681 register with zero i.e. it is of the form CC := CMP R1, 0.
682 If it is, find the instruction defining R1 (say I1) and try to create a
683 PARALLEL consisting of I1 and the comparison, representing a flag-setting
684 arithmetic instruction. Example:
686 <instructions that don't read the condition register>
688 I2 can be merged with I1 into:
689 I1: { CC := CMP (R2 + R3) 0 ; R1 := R2 + R3 }
690 This catches cases where R1 is used between I1 and I2 and therefore
691 combine and other RTL optimisations will not try to propagate it into
692 I2. Return true if we succeeded in merging CMP. */
695 try_merge_compare (struct comparison
*cmp
)
697 rtx_insn
*cmp_insn
= cmp
->insn
;
699 if (cmp
->in_b
!= const0_rtx
|| cmp
->in_a_setter
== NULL
)
701 rtx in_a
= cmp
->in_a
;
704 FOR_EACH_INSN_USE (use
, cmp_insn
)
705 if (DF_REF_REGNO (use
) == REGNO (in_a
))
710 rtx_insn
*def_insn
= cmp
->in_a_setter
;
711 rtx set
= single_set (def_insn
);
715 if (!can_merge_compare_into_arith (cmp_insn
, def_insn
))
718 rtx src
= SET_SRC (set
);
720 /* If the source uses addressing modes with side effects, we can't
721 do the merge because we'd end up with a PARALLEL that has two
722 instances of that side effect in it. */
723 if (side_effects_p (src
))
726 rtx flags
= maybe_select_cc_mode (cmp
, src
, CONST0_RTX (GET_MODE (src
)));
729 /* We may already have a change group going through maybe_select_cc_mode.
730 Discard it properly. */
736 = gen_rtx_SET (flags
, gen_rtx_COMPARE (GET_MODE (flags
),
738 CONST0_RTX (GET_MODE (src
))));
739 rtx arith_set
= copy_rtx (PATTERN (def_insn
));
740 rtx par
= try_validate_parallel (flag_set
, arith_set
);
743 /* We may already have a change group going through maybe_select_cc_mode.
744 Discard it properly. */
748 if (!apply_change_group ())
750 emit_insn_after (par
, def_insn
);
751 delete_insn (def_insn
);
752 delete_insn (cmp
->insn
);
756 /* Attempt to replace a comparison with a prior arithmetic insn that can
757 compute the same flags value as the comparison itself. Return true if
758 successful, having made all rtl modifications necessary. */
761 try_eliminate_compare (struct comparison
*cmp
)
763 rtx flags
, in_a
, in_b
, cmp_a
, cmp_b
;
765 if (try_merge_compare (cmp
))
768 /* We must have found an interesting "clobber" preceding the compare. */
769 if (cmp
->prev_clobber
== NULL
)
772 /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
773 Given that this target requires this pass, we can assume that most
774 insns do clobber the flags, and so the distance between the compare
775 and the clobber is likely to be small. */
776 /* ??? This is one point at which one could argue that DF_REF_CHAIN would
777 be useful, but it is thought to be too heavy-weight a solution here. */
778 in_a
= equivalent_reg_at_start (cmp
->in_a
, cmp
->insn
, cmp
->prev_clobber
);
782 /* Likewise for IN_B if need be. */
783 if (CONSTANT_P (cmp
->in_b
))
785 else if (REG_P (cmp
->in_b
))
787 in_b
= equivalent_reg_at_start (cmp
->in_b
, cmp
->insn
, cmp
->prev_clobber
);
791 else if (GET_CODE (cmp
->in_b
) == UNSPEC
)
793 const int len
= XVECLEN (cmp
->in_b
, 0);
794 rtvec v
= rtvec_alloc (len
);
795 for (int i
= 0; i
< len
; i
++)
797 rtx r
= equivalent_reg_at_start (XVECEXP (cmp
->in_b
, 0, i
),
798 cmp
->insn
, cmp
->prev_clobber
);
801 RTVEC_ELT (v
, i
) = r
;
803 in_b
= gen_rtx_UNSPEC (GET_MODE (cmp
->in_b
), v
, XINT (cmp
->in_b
, 1));
808 /* We've reached PREV_CLOBBER without finding a modification of IN_A.
809 Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
810 recall that we've already validated the shape of PREV_CLOBBER. */
811 rtx_insn
*insn
= cmp
->prev_clobber
;
813 rtx x
= XVECEXP (PATTERN (insn
), 0, 0);
814 if (rtx_equal_p (SET_DEST (x
), in_a
))
817 /* Also check operations with implicit extensions, e.g.:
819 (zero_extend:DI (plus:SI (reg:SI) (reg:SI))))
821 (compare:CCZ (plus:SI (reg:SI) (reg:SI))
823 else if (REG_P (SET_DEST (x
))
825 && REGNO (SET_DEST (x
)) == REGNO (in_a
)
826 && (GET_CODE (SET_SRC (x
)) == ZERO_EXTEND
827 || GET_CODE (SET_SRC (x
)) == SIGN_EXTEND
)
828 && GET_MODE (XEXP (SET_SRC (x
), 0)) == GET_MODE (in_a
))
829 cmp_a
= XEXP (SET_SRC (x
), 0);
831 /* Also check fully redundant comparisons, e.g.:
833 (minus:SI (reg:SI) (reg:SI))))
835 (compare:CC (reg:SI) (reg:SI)))] */
836 else if (REG_P (in_b
)
837 && GET_CODE (SET_SRC (x
)) == MINUS
838 && rtx_equal_p (XEXP (SET_SRC (x
), 0), in_a
)
839 && rtx_equal_p (XEXP (SET_SRC (x
), 1), in_b
))
845 /* If the source uses addressing modes with side effects, we can't
846 do the merge because we'd end up with a PARALLEL that has two
847 instances of that side effect in it. */
848 if (side_effects_p (cmp_a
))
853 else if (rtx_equal_p (SET_DEST (x
), in_b
))
857 if (side_effects_p (cmp_b
))
860 /* Determine if we ought to use a different CC_MODE here. */
861 flags
= maybe_select_cc_mode (cmp
, cmp_a
, cmp_b
);
863 flags
= gen_rtx_REG (cmp
->orig_mode
, targetm
.flags_regnum
);
865 /* Generate a new comparison for installation in the setter. */
866 rtx y
= cmp
->not_in_a
867 ? gen_rtx_NOT (GET_MODE (cmp_a
), copy_rtx (cmp_a
))
869 y
= gen_rtx_COMPARE (GET_MODE (flags
), y
, copy_rtx (cmp_b
));
870 y
= gen_rtx_SET (flags
, y
);
872 /* Canonicalize instruction to:
873 [(set (reg:CCM) (compare:CCM (operation) (immediate)))
874 (set (reg) (operation)] */
876 rtvec v
= rtvec_alloc (2);
877 RTVEC_ELT (v
, 0) = y
;
878 RTVEC_ELT (v
, 1) = x
;
880 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, v
);
882 /* Succeed if the new instruction is valid. Note that we may have started
883 a change group within maybe_select_cc_mode, therefore we must continue. */
884 validate_change (insn
, &PATTERN (insn
), pat
, true);
886 if (!apply_change_group ())
889 /* Success. Delete the compare insn... */
890 delete_insn (cmp
->insn
);
892 /* ... and any notes that are now invalid due to multiple sets. */
893 x
= find_regno_note (insn
, REG_UNUSED
, targetm
.flags_regnum
);
895 remove_note (insn
, x
);
896 x
= find_reg_note (insn
, REG_EQUAL
, NULL
);
898 remove_note (insn
, x
);
899 x
= find_reg_note (insn
, REG_EQUIV
, NULL
);
901 remove_note (insn
, x
);
906 /* Main entry point to the pass. */
909 execute_compare_elim_after_reload (void)
913 gcc_checking_assert (!all_compares
.exists ());
915 /* Locate all comparisons and their uses, and eliminate duplicates. */
917 if (all_compares
.exists ())
919 struct comparison
*cmp
;
922 /* Eliminate comparisons that are redundant with flags computation. */
923 FOR_EACH_VEC_ELT (all_compares
, i
, cmp
)
925 try_eliminate_compare (cmp
);
929 all_compares
.release ();
937 const pass_data pass_data_compare_elim_after_reload
=
940 "cmpelim", /* name */
941 OPTGROUP_NONE
, /* optinfo_flags */
943 0, /* properties_required */
944 0, /* properties_provided */
945 0, /* properties_destroyed */
946 0, /* todo_flags_start */
947 ( TODO_df_finish
| TODO_df_verify
), /* todo_flags_finish */
950 class pass_compare_elim_after_reload
: public rtl_opt_pass
953 pass_compare_elim_after_reload (gcc::context
*ctxt
)
954 : rtl_opt_pass (pass_data_compare_elim_after_reload
, ctxt
)
957 /* opt_pass methods: */
958 virtual bool gate (function
*)
960 /* Setting this target hook value is how a backend indicates the need. */
961 if (targetm
.flags_regnum
== INVALID_REGNUM
)
963 return flag_compare_elim_after_reload
;
966 virtual unsigned int execute (function
*)
968 return execute_compare_elim_after_reload ();
971 }; // class pass_compare_elim_after_reload
976 make_pass_compare_elim_after_reload (gcc::context
*ctxt
)
978 return new pass_compare_elim_after_reload (ctxt
);