1 /* An SH specific RTL pass that tries to combine comparisons and redundant
2 condition code register stores across multiple basic blocks.
3 Copyright (C) 2013-2024 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #define IN_TARGET_CODE 1
24 #define INCLUDE_ALGORITHM
26 #define INCLUDE_VECTOR
28 #include "coretypes.h"
38 #include "tree-pass.h"
43 This pass tries to optimize for example this:
50 into something simpler:
55 Such sequences can be identified by looking for conditional branches and
56 checking whether the ccreg is set before the conditional branch
57 by testing another register for != 0, which was set by a ccreg store.
58 This can be optimized by eliminating the redundant comparison and
59 inverting the branch condition. There can be multiple comparisons in
60 different basic blocks that all end up in the redunant test insn before the
61 conditional branch. Some example RTL ...
67 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 0)))
68 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
72 (set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
73 (set (reg:SI 167) (reg:SI 147 t))
77 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
78 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
79 (label_ref:SI 50) (pc)))
81 In [bb 4] elimination of the comparison would require inversion of the branch
82 condition and compensation of other BBs.
83 Instead the comparison in [bb 3] can be replaced with the comparison in [bb 5]
84 by using a reg-reg move. In [bb 4] a logical not is used to compensate the
88 (set (reg:SI 167) (reg:SI 173))
92 (set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
93 (set (reg:SI 167) (reg:SI 147 t))
97 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
98 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0)))
99 (label_ref:SI 50) (pc)))
106 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
107 (set (reg:SI 167) (reg:SI 147 t))
111 (set (reg:SI 147 t) (gt:SI (reg:SI 177) (reg:SI 179)))
112 (set (reg:SI 167) (reg:SI 147 t))
116 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
117 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
118 (label_ref:SI 51) (pc)))
120 The common comparison is factored out and the branch condition is inverted:
123 (set (reg:SI 167) (reg:SI 173))
124 (set (reg:SI 200) (reg:SI 175))
128 (set (reg:SI 167) (reg:SI 177))
129 (set (reg:SI 200) (reg:SI 179))
133 (set (reg:SI 147 t) (gt:SI (reg:SI 167) (reg:SI 200)))
134 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
135 (label_ref:SI 51) (pc)))
142 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
143 (set (reg:SI 167) (reg:SI 147 t))
147 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
148 (set (reg:SI 167) (reg:SI 147 t))
152 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
153 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
154 (label_ref:SI 51) (pc)))
156 The T bit lifetime is extended and the branch condition is inverted:
159 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
163 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
167 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
168 (label_ref:SI 51) (pc)))
175 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
176 (set (reg:SI 167) (reg:SI 147 t))
180 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
181 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
185 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
186 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
187 (label_ref:SI 50) (pc)))
189 In this case the comparisons are the same and could be combined, but the
190 branch condition is different for [bb 3] and [bb 5]. Since the comparison
191 is not a zero comparison, we can't negate one of the operands. The best thing
192 we can do here is to eliminate the comparison before the cbranch and invert
193 the ccreg in one of the BBs. On SH2A this will utilize the 'nott' instruction.
196 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
200 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
201 (set (reg:SI 147 t) (xor:SI (reg:SI 147 t) (const_int 1)))
205 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0)) // inverted
206 (label_ref:SI 50) (pc)))
209 In order to handle cases such as above the RTL pass does the following:
211 - Find the ccreg sets (comparisons) and ccreg stores
212 (inverting and non-inverting) in all related BBs.
214 - If the comparison types in the BBs are all the same, try to combine the
215 comparisons in the BBs and replace the zero comparison before the cbranch
216 with the common comparison.
218 - If the cstores are the same, move the comparison before the cbranch
219 and replace the comparisons in the BBs with reg-reg copies to get the
220 operands in place (create new pseudo regs).
222 - If the cstores differ and the comparison is a test against zero,
223 use reg-reg copies for the dominating cstores and logical not cstores
224 for the subordinate cstores.
226 - If the comparison types in the BBs are not the same, or the first approach
227 doesn't work out for some reason, try to eliminate the comparison before the
228 cbranch by extending the lifetime of the ccreg by leaving the individual
229 comparisons but eliminating the cstores.
230 If the cstores are all the same this is straight forward.
231 If they're not, try to reverse the ccreg for the subordinate cstore type
232 and eliminate the dominating one.
235 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
238 #define log_msg(...)\
239 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); } while (0)
242 do { if (dump_file != NULL) print_rtl_single (dump_file, \
243 (const_rtx)i); } while (0)
246 do { if (dump_file != NULL) print_rtl (dump_file, (const_rtx)r); } while (0)
248 #define log_return(retval, ...)\
249 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
250 return retval; } while (0)
252 #define log_return_void(...)\
253 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
258 // The insn where the search stopped or NULL.
261 // The set rtx of the specified reg if found, NULL_RTX otherwise.
262 // Notice that the set rtx can also be in a parallel.
265 // The set source operand rtx if found, NULL_RTX otherwise.
269 return set_rtx
== NULL_RTX
? NULL_RTX
: XEXP (set_rtx
, 1);
272 // The set destination operand rtx if found, NULL_RTX otherwise.
276 return set_rtx
== NULL_RTX
? NULL_RTX
: XEXP (set_rtx
, 0);
282 return insn
== NULL_RTX
|| set_rtx
== NULL_RTX
;
286 // Given a reg rtx and a start insn find the insn (in the same basic block)
287 // that sets the reg.
289 find_set_of_reg_bb (rtx reg
, rtx_insn
*insn
)
291 set_of_reg result
= { insn
, NULL_RTX
};
293 if (!REG_P (reg
) || insn
== NULL
)
296 for (result
.insn
= insn
; result
.insn
!= NULL
;
297 result
.insn
= prev_nonnote_nondebug_insn_bb (result
.insn
))
299 if (BARRIER_P (result
.insn
))
301 if (!NONJUMP_INSN_P (result
.insn
))
303 if (reg_set_p (reg
, result
.insn
))
305 result
.set_rtx
= set_of (reg
, result
.insn
);
306 if (result
.set_rtx
== NULL_RTX
|| GET_CODE (result
.set_rtx
) != SET
)
307 result
.set_rtx
= NULL_RTX
;
316 reg_dead_after_insn (const_rtx reg
, const_rtx insn
)
318 return find_regno_note (insn
, REG_DEAD
, REGNO (reg
)) != NULL_RTX
;
322 reg_unused_after_insn (const_rtx reg
, const_rtx insn
)
324 return find_regno_note (insn
, REG_UNUSED
, REGNO (reg
)) != NULL_RTX
;
327 // Check whether the two specified basic blocks are adjacent, i.e. there's no
328 // other basic block in between them.
330 is_adjacent_bb (basic_block a
, basic_block b
)
332 basic_block bb0
[] = { a
, b
};
333 basic_block bb1
[] = { b
, a
};
335 for (int i
= 0; i
< 2; ++i
)
336 for (edge_iterator ei
= ei_start (bb0
[i
]->succs
);
337 !ei_end_p (ei
); ei_next (&ei
))
338 if (ei_edge (ei
)->dest
== bb1
[i
])
344 // Internal function of trace_reg_uses.
346 trace_reg_uses_1 (rtx reg
, rtx_insn
*start_insn
, basic_block bb
, int& count
,
347 std::vector
<basic_block
>& visited_bb
, rtx abort_at_insn
)
352 if (std::find (visited_bb
.begin (), visited_bb
.end (), bb
)
353 != visited_bb
.end ())
354 log_return_void ("[bb %d] already visited\n", bb
->index
);
356 visited_bb
.push_back (bb
);
358 if (BB_END (bb
) == NULL_RTX
)
359 log_return_void ("[bb %d] BB_END is null\n", bb
->index
);
361 if (start_insn
== NULL_RTX
)
362 log_return_void ("[bb %d] start_insn is null\n", bb
->index
);
364 rtx end_insn
= NEXT_INSN (BB_END (bb
));
365 if (end_insn
== NULL_RTX
)
366 log_return_void ("[bb %d] end_insn is null\n", bb
->index
);
368 for (rtx_insn
*i
= NEXT_INSN (start_insn
); i
!= end_insn
; i
= NEXT_INSN (i
))
372 if (NONDEBUG_INSN_P (i
)
373 && (reg_overlap_mentioned_p (reg
, PATTERN (i
))
374 || (CALL_P (i
) && find_reg_fusage (i
, USE
, reg
))))
376 log_msg ("found use in [bb %d] at insn:\n", bb
->index
);
382 // Stop following this BB if the reg is set or dies along the way.
383 if (reg_set_p (reg
, i
) || reg_dead_after_insn (reg
, i
))
387 if (abort_at_insn
!= NULL_RTX
&& abort_at_insn
== i
)
391 for (edge_iterator ei
= ei_start (bb
->succs
); !ei_end_p (ei
); ei_next (&ei
))
393 basic_block succ_bb
= ei_edge (ei
)->dest
;
394 trace_reg_uses_1 (reg
, BB_HEAD (succ_bb
), succ_bb
, count
, visited_bb
,
399 // Trace uses of the specified reg in all basic blocks that are reachable from
400 // the specified insn. If 'abort_at_insn' is not null, abort the trace at
401 // that insn. If the insn 'abort_at_insn' uses the specified reg, it is also
404 trace_reg_uses (rtx reg
, rtx_insn
*start_insn
, rtx abort_at_insn
)
406 log_msg ("\ntrace_reg_uses\nreg = ");
408 log_msg ("\nstart_insn = ");
409 log_insn (start_insn
);
412 std::vector
<basic_block
> visited_bb
;
413 visited_bb
.reserve (32);
415 trace_reg_uses_1 (reg
, start_insn
, BLOCK_FOR_INSN (start_insn
),
416 count
, visited_bb
, abort_at_insn
);
421 is_conditional_insn (rtx_insn
* i
)
423 if (! (INSN_P (i
) && NONDEBUG_INSN_P (i
)))
427 return GET_CODE (p
) == SET
&& GET_CODE (XEXP (p
, 1)) == IF_THEN_ELSE
;
430 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
433 class sh_treg_combine
: public rtl_opt_pass
436 sh_treg_combine (gcc::context
* ctx
, bool split_insns
, const char* name
);
437 virtual ~sh_treg_combine (void);
438 virtual bool gate (function
*);
439 virtual unsigned int execute (function
*);
442 // Type of ccreg store that is supported.
450 // Type of branch condition that is supported.
451 enum branch_condition_type_t
455 unknown_branch_condition
= -1
458 // For each basic block there can be a trace entry which consists of an
459 // insn that sets the ccreg (usually a comparison) and a ccreg store.
465 cstore_type_t cstore_type
;
466 std::vector
<set_of_reg
> cstore_reg_reg_copies
;
468 bb_entry (basic_block b
)
469 : bb (b
), setcc (), cstore (), cstore_type (cstore_unknown
) { }
471 rtx
comparison_rtx (void) const { return setcc
.set_src (); }
474 // A ccreg trace for a conditional branch.
477 rtx_insn
*cbranch_insn
;
478 rtx
* condition_rtx_in_insn
;
479 branch_condition_type_t cbranch_type
;
481 // The comparison against zero right before the conditional branch.
484 // All BBs that are related to the cbranch. The last BB in the list is
485 // the BB of the cbranch itself and might be empty.
486 std::list
<bb_entry
> bb_entries
;
488 cbranch_trace (rtx_insn
*insn
)
489 : cbranch_insn (insn
),
490 condition_rtx_in_insn (NULL
),
491 cbranch_type (unknown_branch_condition
),
494 if (is_conditional_insn (cbranch_insn
))
495 condition_rtx_in_insn
= &XEXP (XEXP (PATTERN (cbranch_insn
), 1), 0);
496 else if (rtx x
= pc_set (cbranch_insn
))
497 condition_rtx_in_insn
= &XEXP (XEXP (x
, 1), 0);
500 basic_block
bb (void) const { return BLOCK_FOR_INSN (cbranch_insn
); }
503 branch_condition_rtx (void) const
505 return condition_rtx_in_insn
!= NULL
? *condition_rtx_in_insn
: NULL
;
508 branch_condition_rtx_ref (void) const
510 // Before anything gets to invoke this function, there are other checks
511 // in place to make sure that we have a known branch condition and thus
512 // the ref to the rtx in the insn.
513 gcc_assert (condition_rtx_in_insn
!= NULL
);
514 return *condition_rtx_in_insn
;
518 can_invert_condition (void) const
520 // The branch condition can be inverted safely only if the condition
521 // reg is dead after the cbranch.
522 return reg_dead_after_insn (XEXP (branch_condition_rtx (), 0),
527 static const pass_data default_pass_data
;
529 // Tells whether modified or newly added insns are to be split at the end
531 const bool m_split_insns
;
533 // rtx of the ccreg that is obtained from the target.
536 // Newly added or modified insns.
537 std::vector
<rtx
> m_touched_insns
;
539 // Given an rtx determine whether it's a comparison with a constant zero.
540 static bool is_cmp_eq_zero (const_rtx i
);
542 // Update the stored mode of the ccreg from the given branch condition rtx.
543 void update_ccreg_mode (const_rtx cond
);
545 // Given an rtx, figure out the branch condition, assuming that it is
546 // in canonical form:
547 // (ne (reg) (const_int 0))
548 // (eq (reg) (const_int 0))
549 branch_condition_type_t
branch_condition_type (const_rtx cond
) const;
551 // Return true if the specified rtx is either a normal ccreg or
552 // a negated form of the ccreg.
553 bool is_normal_ccreg (const_rtx x
) const;
554 bool is_inverted_ccreg (const_rtx x
) const;
556 // Given a reg rtx and a start insn rtx, try to find the insn in the same
557 // basic block that sets the specified reg.
558 // Return how the search ended and the insn where it stopped or NULL_RTX.
565 record_return_t
record_set_of_reg (rtx reg
, rtx_insn
*start_insn
,
568 // Tells whether the cbranch insn of the specified bb_entry can be removed
569 // safely without triggering any side effects.
570 bool can_remove_cstore (const bb_entry
& e
,
571 const cbranch_trace
& trace
) const;
573 // Tells whether the setcc insn of the specified bb_entry can be removed
574 // safely without triggering any side effects.
575 bool can_remove_comparison (const bb_entry
& e
,
576 const cbranch_trace
& trace
) const;
578 // Tells whether the two specified comparison rtx can be combined into a
579 // single comparison.
580 bool can_combine_comparisons (const_rtx x
, const_rtx y
) const;
582 // Tells whether the ccreg usage can be extended from the bb_entry on until
583 // the final cbranch of the trace.
584 bool can_extend_ccreg_usage (const bb_entry
& e
,
585 const cbranch_trace
& trace
) const;
587 // Create an insn rtx that performs a logical not (test != 0) on the src_reg
588 // and stores the result in dst_reg.
589 rtx
make_not_reg_insn (rtx dst_reg
, rtx src_reg
) const;
591 // Create an insn rtx that inverts the ccreg.
592 rtx_insn
*make_inv_ccreg_insn (void) const;
594 // Adds the specified insn to the set of modified or newly added insns that
595 // might need splitting at the end of the pass.
596 rtx
touched_insn (rtx i
);
598 // Try to invert the branch condition of the specified trace.
599 bool try_invert_branch_condition (cbranch_trace
& trace
);
601 // Try to optimize a cbranch trace by combining comparisons in BBs and
602 // eliminate the cstores.
603 bool try_combine_comparisons (cbranch_trace
& trace
,
604 int cstore_count
, int inv_cstore_count
,
605 cstore_type_t dominating_cstore
);
607 // Try to optimize a cbranch trace by eliminating the cstores in BBs only.
608 bool try_eliminate_cstores (cbranch_trace
& trace
,
609 int cstore_count
, int inv_cstore_count
,
610 cstore_type_t dominating_cstore
);
612 // Given a branch insn, try to optimize its branch condition.
613 // If any insns are modified or added they are added to 'm_touched_insns'.
614 void try_optimize_cbranch (rtx_insn
*i
);
618 const pass_data
sh_treg_combine::default_pass_data
=
621 "", // name (overwritten by the constructor)
622 OPTGROUP_NONE
, // optinfo_flags
623 TV_OPTIMIZE
, // tv_id
624 0, // properties_required
625 0, // properties_provided
626 0, // properties_destroyed
627 0, // todo_flags_start
628 TODO_df_finish
| TODO_df_verify
// todo_flags_finish
631 sh_treg_combine::sh_treg_combine (gcc::context
* ctx
, bool split_insns
,
633 : rtl_opt_pass (default_pass_data
, ctx
),
634 m_split_insns (split_insns
),
637 // Overwrite default name in pass_data base class.
641 sh_treg_combine::~sh_treg_combine (void)
645 void sh_treg_combine::update_ccreg_mode (const_rtx cond
)
647 if (REG_P (XEXP (cond
, 0)) && REGNO (XEXP (cond
, 0)) != REGNO (m_ccreg
))
650 machine_mode m
= GET_MODE (XEXP (cond
, 0));
651 if (m
== GET_MODE (m_ccreg
))
654 PUT_MODE (m_ccreg
, m
);
655 log_msg ("updated ccreg mode: ");
661 sh_treg_combine::is_cmp_eq_zero (const_rtx i
)
663 return i
!= NULL_RTX
&& GET_CODE (i
) == EQ
664 && REG_P (XEXP (i
, 0)) && XEXP (i
, 1) == const0_rtx
;
667 sh_treg_combine::branch_condition_type_t
668 sh_treg_combine::branch_condition_type (const_rtx cond
) const
670 if (cond
== NULL_RTX
)
671 return unknown_branch_condition
;
673 if (GET_CODE (cond
) == NE
674 && REG_P (XEXP (cond
, 0)) && REGNO (XEXP (cond
, 0)) == REGNO (m_ccreg
)
675 && XEXP (cond
, 1) == const0_rtx
)
676 return branch_if_true
;
678 else if (GET_CODE (cond
) == EQ
679 && REG_P (XEXP (cond
, 0)) && REGNO (XEXP (cond
, 0)) == REGNO (m_ccreg
)
680 && XEXP (cond
, 1) == const0_rtx
)
681 return branch_if_false
;
684 return unknown_branch_condition
;
688 sh_treg_combine::is_normal_ccreg (const_rtx x
) const
690 return t_reg_operand (const_cast<rtx
> (x
), VOIDmode
);
694 sh_treg_combine::is_inverted_ccreg (const_rtx x
) const
696 return negt_reg_operand (const_cast<rtx
> (x
), VOIDmode
);
699 sh_treg_combine::record_return_t
700 sh_treg_combine::record_set_of_reg (rtx reg
, rtx_insn
*start_insn
,
703 log_msg ("\n[bb %d]\n", new_entry
.bb
->index
);
705 if (start_insn
== NULL_RTX
)
706 log_return (set_not_found
, "set of reg not found. empty BB?\n");
708 new_entry
.cstore_type
= cstore_unknown
;
710 for (rtx_insn
*i
= start_insn
; i
!= NULL
; )
712 new_entry
.cstore
= find_set_of_reg_bb (reg
, i
);
714 if (new_entry
.cstore
.set_src () == NULL_RTX
)
715 log_return (set_not_found
, "set of reg not found (cstore)\n");
717 log_insn (new_entry
.cstore
.insn
);
720 if (is_normal_ccreg (new_entry
.cstore
.set_src ()))
722 log_msg ("normal condition store\n");
723 new_entry
.cstore_type
= cstore_normal
;
725 else if (is_inverted_ccreg (new_entry
.cstore
.set_src ()))
727 log_msg ("inverted condition store\n");
728 new_entry
.cstore_type
= cstore_inverted
;
730 else if (REG_P (new_entry
.cstore
.set_src ()))
732 // If it's a reg-reg copy follow the copied reg, but ignore
733 // nop copies of the reg onto itself.
734 if (REGNO (new_entry
.cstore
.set_src ()) == REGNO (reg
))
736 i
= prev_nonnote_nondebug_insn_bb (i
);
740 new_entry
.cstore_reg_reg_copies
.push_back (new_entry
.cstore
);
741 reg
= new_entry
.cstore
.set_src ();
742 i
= new_entry
.cstore
.insn
;
744 log_msg ("reg-reg copy. tracing ");
750 log_return (other_set_found
, "not a condition store\n");
752 gcc_assert (new_entry
.cstore_type
!= cstore_unknown
);
754 // Now see how the ccreg was set.
755 // For now it must be in the same BB.
756 log_msg ("tracing ccreg\n");
757 new_entry
.setcc
= find_set_of_reg_bb
758 (m_ccreg
, prev_nonnote_nondebug_insn_bb (new_entry
.cstore
.insn
));
760 // If cstore was found but setcc was not found continue anyway, as
761 // for some of the optimization types the setcc is irrelevant.
762 if (new_entry
.setcc
.set_src () == NULL_RTX
)
763 log_return (set_found
, "set of ccreg not found\n");
765 else if (GET_CODE (new_entry
.setcc
.set_rtx
) == SET
)
767 // Also allow insns that set the ccreg, but are not true comparison
768 // insns, as long as they are sets and not e.g. clobbers.
769 log_insn (new_entry
.setcc
.insn
);
774 // If cstore was found but setcc was not found continue anyway, as
775 // for some of the optimization types the setcc is irrelevant.
776 log_return (set_found
, "unknown set of ccreg\n");
779 log_return (set_not_found
, "set of reg not found\n");
783 sh_treg_combine::can_remove_cstore (const bb_entry
& e
,
784 const cbranch_trace
& trace
) const
786 if (volatile_insn_p (PATTERN (e
.cstore
.insn
)))
788 log_msg ("can't remove insn\n");
789 log_insn (e
.cstore
.insn
);
790 log_return (false, "\nbecause it's volatile\n");
793 // On SH there are parallel patterns which store the ccreg multiple times.
794 // In this case it's not safe.
795 rtx cstore_pat
= PATTERN (e
.cstore
.insn
);
796 if (GET_CODE (cstore_pat
) == PARALLEL
)
797 for (int i
= 0; i
< XVECLEN (cstore_pat
, 0); ++i
)
799 rtx x
= XVECEXP (cstore_pat
, 0, i
);
801 // It's the cstore set that we're referring to, ignore that one.
802 if (x
!= e
.cstore
.set_rtx
803 && GET_CODE (x
) == SET
&& reg_referenced_p (m_ccreg
, x
))
805 log_msg ("can't remove insn\n");
806 log_insn (e
.cstore
.insn
);
807 log_return (false, "\nbecause it's a multiple ccreg store\n");
811 // If the cstore sets the ccreg (e.g. negc) and the ccreg is used afterwards
813 if (modified_in_p (m_ccreg
, e
.cstore
.insn
)
814 && !(reg_dead_after_insn (m_ccreg
, e
.cstore
.insn
)
815 || reg_unused_after_insn (m_ccreg
, e
.cstore
.insn
)))
817 log_msg ("can't remove insn\n");
818 log_insn (e
.cstore
.insn
);
819 log_return (false, "\nbecause it sets the ccreg\n");
822 // If the cstore destination reg is copied around check the reg-reg
823 // copies. At every reg-reg copy the copied reg must be dead and there
824 // must not be a usage of the copied regs between the reg-reg copies.
825 // Otherwise we assume that the result of the cstore is used in some
827 rtx_insn
*prev_insn
= e
.cstore
.insn
;
828 for (std::vector
<set_of_reg
>::const_reverse_iterator i
=
829 e
.cstore_reg_reg_copies
.rbegin ();
830 i
!= e
.cstore_reg_reg_copies
.rend (); ++i
)
832 if (!reg_dead_after_insn (i
->set_src (), i
->insn
))
834 log_msg ("can't remove insn\n");
836 log_return (false, "\nbecause source of reg-reg copy doesn't die\n");
839 if (reg_used_between_p (i
->set_src (), prev_insn
, i
->insn
))
841 log_msg ("can't remove insn\n");
843 log_return (false, "\nbecause reg %d is otherwise used\n",
844 REGNO (i
->set_src ()));
850 // The cstore_dst reg must die after the test before the cbranch, otherwise
851 // it's not safe to remove the cstore.
852 // If the cstore destination reg is copied around check the effective
853 // destination reg of the cstore. The reg-reg copies are recorded in
854 // reverse order, i.e. the most recent reg-reg copy in the insn list
856 rtx cstore_dst
= e
.cstore_reg_reg_copies
.empty ()
857 ? e
.cstore
.set_dst ()
858 : e
.cstore_reg_reg_copies
.front ().set_dst ();
860 if (!reg_dead_after_insn (cstore_dst
, trace
.setcc
.insn
))
862 log_msg ("can't remove insn\n");
863 log_insn (e
.cstore
.insn
);
864 log_return (false, "\nbecause its effective target reg %d doesn't die "
865 "after trace.setcc.insn\n", REGNO (cstore_dst
));
868 // Also check that the cstore_dst reg is not used in other reachable code
869 // paths before it dies.
870 // Count the uses of the effective cstore_dst reg (i.e. the last known reg
871 // that holds the cstore value after reg-reg copies) in all BBs that can be
872 // reached from bb_entry's BB including the BB of the cstore insn.
873 // If we get more than 1 uses we assume that it's used somewhere else and is
874 // not safe to be removed.
875 int cstore_dst_use_count
= trace_reg_uses (cstore_dst
, e
.cstore
.insn
,
877 if (cstore_dst_use_count
> 1)
879 log_msg ("can't remove insn\n");
880 log_insn (e
.cstore
.insn
);
881 log_return (false, "\nbecause its effective target reg %d is used "
882 "in %d other places\n", REGNO (cstore_dst
),
883 cstore_dst_use_count
- 1);
890 sh_treg_combine::can_remove_comparison (const bb_entry
& e
,
891 const cbranch_trace
&/* trace*/) const
893 // If the ccreg is used otherwise between the comparison and the cstore,
895 if (reg_used_between_p (m_ccreg
, e
.setcc
.insn
, e
.cstore
.insn
))
897 log_msg ("can't remove insn\n");
898 log_insn (e
.setcc
.insn
);
899 log_return (false, "\nbecause the ccreg is used otherwise\n");
902 if (!reg_dead_after_insn (m_ccreg
, e
.cstore
.insn
)
903 && !reg_unused_after_insn (m_ccreg
, e
.cstore
.insn
))
905 log_msg ("can't remove insn\n");
906 log_insn (e
.cstore
.insn
);
907 log_return (false, "\nbecause ccreg is not dead or unused afterwards\n");
910 // On SH there are also multiple set patterns that can be used for
911 // comparisons, such as "shll". It's not safe to remove those.
912 if (multiple_sets (e
.setcc
.insn
))
914 log_msg ("can't remove insn\n");
915 log_insn (e
.cstore
.insn
);
916 log_return (false, "\nbecause it's a multiple set\n");
923 sh_treg_combine::make_not_reg_insn (rtx dst_reg
, rtx src_reg
) const
925 // On SH we can do only SImode and DImode comparisons.
926 if (! (GET_MODE (src_reg
) == SImode
|| GET_MODE (src_reg
) == DImode
))
929 // On SH we can store the ccreg into an SImode or DImode reg only.
930 if (! (GET_MODE (dst_reg
) == SImode
|| GET_MODE (dst_reg
) == DImode
))
935 emit_insn (gen_rtx_SET (m_ccreg
, gen_rtx_fmt_ee (EQ
, SImode
,
936 src_reg
, const0_rtx
)));
938 if (GET_MODE (dst_reg
) == SImode
)
939 emit_move_insn (dst_reg
, m_ccreg
);
940 else if (GET_MODE (dst_reg
) == DImode
)
942 emit_move_insn (gen_lowpart (SImode
, dst_reg
), m_ccreg
);
943 emit_move_insn (gen_highpart (SImode
, dst_reg
), const0_rtx
);
948 rtx i
= get_insns ();
955 sh_treg_combine::make_inv_ccreg_insn (void) const
958 rtx_insn
*i
= emit_insn (gen_rtx_SET (m_ccreg
,
959 gen_rtx_fmt_ee (XOR
, GET_MODE (m_ccreg
),
960 m_ccreg
, const1_rtx
)));
966 sh_treg_combine::touched_insn (rtx i
)
968 m_touched_insns
.push_back (i
);
973 sh_treg_combine::can_combine_comparisons (const_rtx x
, const_rtx y
) const
975 if (GET_CODE (x
) != GET_CODE (y
))
978 rtx x_op0
= XEXP (x
, 0);
979 rtx x_op1
= XEXP (x
, 1);
981 rtx y_op0
= XEXP (y
, 0);
982 rtx y_op1
= XEXP (y
, 1);
984 if (!REG_P (x_op0
) || !REG_P (y_op0
))
987 if (GET_MODE (x_op0
) != GET_MODE (y_op0
))
990 // rtx_equal_p also compares the reg numbers which we do not care about
991 // here, as long as both are regs and the modes are the same.
993 return REG_P (y_op1
) && GET_MODE (x_op1
) == GET_MODE (y_op1
);
995 return rtx_equal_p (x_op1
, y_op1
);
999 sh_treg_combine::can_extend_ccreg_usage (const bb_entry
& e
,
1000 const cbranch_trace
& trace
) const
1002 // Check if the ccreg is not modified by other insins in the BB path until
1003 // the final cbranch of the trace.
1004 // Start checking after the cstore that follows the setcc, assuming that
1005 // the cstore will be removed.
1007 // The assumption here is that the specified bb_entry's BB is a direct
1008 // predecessor of the trace.cbranch_insn's BB.
1009 if (e
.bb
!= trace
.bb () && !is_adjacent_bb (e
.bb
, trace
.bb ()))
1011 "can't extend ccreg usage -- [bb %d] and [bb %d] are not adjacent\n",
1012 e
.bb
->index
, trace
.bb ()->index
);
1014 if (e
.cstore
.empty ())
1015 log_return (false, "can't extend ccreg usage -- no cstore\n");
1017 // The entry's cstore is in the same BB as the final cbranch.
1018 if (e
.bb
== trace
.bb ())
1020 if (reg_set_between_p (m_ccreg
, e
.cstore
.insn
, trace
.setcc
.insn
))
1022 "can't extend ccreg usage -- it's modified between e.cstore.insn "
1023 "and trace.setcc.insn");
1028 // The entry's cstore and the final cbranch are in different BBs.
1029 if (reg_set_between_p (m_ccreg
, e
.cstore
.insn
, NEXT_INSN (BB_END (e
.bb
))))
1031 "can't extend ccreg usage -- it's modified in [bb %d]", e
.bb
->index
);
1033 if (reg_set_between_p (m_ccreg
, PREV_INSN (BB_HEAD (trace
.bb ())),
1036 "can't extend ccreg usage -- it's modified in [bb %d]",
1037 trace
.bb ()->index
);
1043 sh_treg_combine::try_invert_branch_condition (cbranch_trace
& trace
)
1045 log_msg ("inverting branch condition\n");
1047 rtx
& comp
= trace
.branch_condition_rtx_ref ();
1049 rtx_code rev_cmp_code
= reversed_comparison_code (comp
, trace
.cbranch_insn
);
1051 if (rev_cmp_code
== UNKNOWN
)
1052 log_return (false, "reversed_comparison_code = UNKNOWN\n");
1054 validate_change (trace
.cbranch_insn
, &comp
,
1055 gen_rtx_fmt_ee (rev_cmp_code
,
1056 GET_MODE (comp
), XEXP (comp
, 0),
1060 if (verify_changes (num_validated_changes ()))
1061 confirm_change_group ();
1063 log_return (false, "verify_changed failed\n");
1065 touched_insn (trace
.cbranch_insn
);
1070 sh_treg_combine::try_combine_comparisons (cbranch_trace
& trace
,
1072 int inv_cstore_count
,
1073 cstore_type_t dominating_cstore
)
1075 log_msg ("\ntry_combine_comparisons\n");
1077 // This function will always try to create new pseudos.
1078 if (!can_create_pseudo_p ())
1079 log_return (false, "can't create pseudos\n");
1081 // Check that all ccset insns are comparisons and all comparison types in
1082 // all BBs are the same and could be combined into one single comparison.
1083 rtx comp
= NULL_RTX
;
1084 rtx comp_insn
= NULL_RTX
;
1086 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1087 i
!= trace
.bb_entries
.end (); ++i
)
1089 int i_empty_count
= i
->setcc
.empty () + i
->cstore
.empty ();
1091 // A completly empty entry is OK (could be the BB of the cbranch).
1092 if (i_empty_count
== 2)
1095 // Otherwise we need both, the setcc and the cstore.
1096 if (i_empty_count
!= 0)
1097 log_return (false, "bb entry is not a setcc cstore pair\n");
1099 rtx other_comp
= i
->comparison_rtx ();
1101 if (!COMPARISON_P (other_comp
))
1103 log_msg ("setcc is not a comparison:\n");
1104 log_rtx (other_comp
);
1105 log_return (false, "\n");
1108 if (comp_insn
== NULL_RTX
)
1111 comp_insn
= i
->setcc
.insn
;
1113 else if (!can_combine_comparisons (comp
, other_comp
))
1116 // The goal here is to eliminate all cstores and comparisons in the BBs.
1117 // Thus check if every cstore can actually be removed safely.
1118 if (!can_remove_cstore (*i
, trace
) || !can_remove_comparison (*i
, trace
))
1122 // FIXME: The first operand of the comparison must be a simple reg.
1123 // This effectively prohibits combining div0s comparisons such as
1124 // (lt:SI (xor:SI (reg:SI) (reg:SI)))
1125 if (!REG_P (XEXP (comp
, 0)))
1127 log_msg ("comparison operand 0\n");
1128 log_rtx (XEXP (comp
, 0));
1129 log_return (false, "\nis not a reg\n");
1132 rtx comp_op0
= gen_reg_rtx (GET_MODE (XEXP (comp
, 0)));
1133 rtx comp_op1
= REG_P (XEXP (comp
, 1))
1134 ? gen_reg_rtx (GET_MODE (XEXP (comp
, 1)))
1137 // If there are both, inverting and non-inverting cstores, they can only
1138 // be eliminated if the comparison can be inverted. We assume that the
1139 // comparison insns that we find are already minimal and canonicalized.
1140 // There is one special case though, where an integer comparison
1141 // (eq (reg) (const_int 0))
1142 // can be inverted with a sequence
1143 // (set (t) (eq (reg) (const_int 0))
1145 // (eq (reg) (const_int 0))
1147 // FIXME: On SH2A it might be better to use the nott insn in this case,
1148 // i.e. do the try_eliminate_cstores approach instead.
1149 if (inv_cstore_count
!= 0 && cstore_count
!= 0)
1151 if (make_not_reg_insn (comp_op0
, comp_op0
) == NULL_RTX
)
1152 log_return (false, "make_not_reg_insn failed.\n");
1154 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1155 i
!= trace
.bb_entries
.end (); ++i
)
1157 if (i
->setcc
.empty () || i
->cstore
.empty ())
1160 if (i
->cstore_type
!= dominating_cstore
1161 && !is_cmp_eq_zero (i
->comparison_rtx ()))
1163 log_msg ("can't invert comparison in insn\n");
1164 log_insn (i
->setcc
.insn
);
1166 "\nbecause it's not a (eq (reg) (const_int 0))\n");
1171 if (dominating_cstore
== cstore_normal
1172 && !try_invert_branch_condition (trace
))
1175 // Replace the test insn before the cbranch with the common comparison.
1176 // Instead of creating a new insn from scratch we copy the common comparison
1177 // pattern. This simplifies handling parallel comparison patterns, such as
1178 // FP comparisons on SH, which have an extra use on FPSCR.
1179 log_msg ("installing common comparison in [bb %d]\n", trace
.bb ()->index
);
1181 rtx common_comp_pat
= copy_rtx (PATTERN (comp_insn
));
1182 rtx common_comp
= const_cast<rtx
> (set_of (m_ccreg
, common_comp_pat
));
1184 gcc_assert (common_comp
!= NULL_RTX
);
1186 XEXP (XEXP (common_comp
, 1), 0) = comp_op0
;
1187 XEXP (XEXP (common_comp
, 1), 1) = comp_op1
;
1189 log_rtx (common_comp_pat
);
1192 rtx common_comp_insn
= touched_insn (emit_insn_after (common_comp_pat
,
1195 if (REG_P (comp_op0
))
1196 add_reg_note (common_comp_insn
, REG_DEAD
, copy_rtx (comp_op0
));
1197 if (REG_P (comp_op1
))
1198 add_reg_note (common_comp_insn
, REG_DEAD
, copy_rtx (comp_op1
));
1200 delete_insn (trace
.setcc
.insn
);
1202 // Replace comparison and cstore insns with reg-reg moves in all BBs.
1203 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1204 i
!= trace
.bb_entries
.end (); ++i
)
1206 if (i
->setcc
.empty () || i
->cstore
.empty ())
1209 rtx i_comp_op0
= XEXP (i
->comparison_rtx (), 0);
1210 rtx i_comp_op1
= XEXP (i
->comparison_rtx (), 1);
1212 if (i
->cstore_type
== dominating_cstore
)
1214 log_msg ("replacing comparison and cstore with reg move "
1215 "in [bb %d]\n", i
->bb
->index
);
1217 rtx new_i
= touched_insn (
1218 emit_insn_after (gen_move_insn (comp_op0
, i_comp_op0
),
1221 if (REG_P (i_comp_op0
)
1222 && reg_dead_after_insn (i_comp_op0
, i
->setcc
.insn
))
1223 add_reg_note (new_i
, REG_DEAD
, copy_rtx (i_comp_op0
));
1225 // If the second operand is a reg, have to emit a move insn.
1226 // Otherwise assume it's a const_int and just reference it.
1227 if (REG_P (comp_op1
))
1229 new_i
= touched_insn (
1230 emit_insn_after (gen_move_insn (comp_op1
, i_comp_op1
),
1233 if (reg_dead_after_insn (i_comp_op1
, i
->setcc
.insn
))
1234 add_reg_note (new_i
, REG_DEAD
, copy_rtx (i_comp_op1
));
1239 log_msg ("replacing comparison and cstore with inverting reg move "
1240 "in [bb %d]\n", i
->bb
->index
);
1242 rtx new_i
= make_not_reg_insn (comp_op0
, i_comp_op0
);
1243 if (REG_P (i_comp_op0
)
1244 && reg_dead_after_insn (i_comp_op0
, i
->setcc
.insn
))
1245 add_reg_note (new_i
, REG_DEAD
, copy_rtx (i_comp_op0
));
1247 touched_insn (emit_insn_after (new_i
, i
->setcc
.insn
));
1250 delete_insn (i
->cstore
.insn
);
1251 delete_insn (i
->setcc
.insn
);
1258 sh_treg_combine::try_eliminate_cstores (cbranch_trace
& trace
,
1259 int cstore_count
, int inv_cstore_count
,
1260 cstore_type_t dominating_cstore
)
1262 log_msg ("\ntry_eliminate_cstores\n");
1264 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1265 i
!= trace
.bb_entries
.end (); ++i
)
1267 // A completly empty entry is OK (could be the BB of the cbranch).
1268 if (i
->setcc
.empty () && i
->cstore
.empty ())
1271 // We're going to eliminate cstores, but for that they have to be
1272 // there. We don't care about the setcc in this case.
1273 if (i
->cstore
.empty ())
1274 log_return (false, "bb entry cstore empty -- aborting\n");
1276 // The goal here is to eliminate all cstores in the BBs and extend the
1278 if (!can_extend_ccreg_usage (*i
, trace
))
1281 // If the cstore can't be removed we can keep it around as long as
1282 // it doesn't modify the ccreg.
1283 if (!can_remove_cstore (*i
, trace
)
1284 && modified_in_p (m_ccreg
, i
->cstore
.insn
))
1285 log_return (false, "cstore sets ccreg -- aborting\n");
1288 // If there are both, inverting and non-inverting cstores, we'll have to
1289 // invert the ccreg as a replacement for one of them.
1290 if (cstore_count
!= 0 && inv_cstore_count
!= 0)
1292 rtx_insn
*i
= make_inv_ccreg_insn ();
1293 if (recog_memoized (i
) < 0)
1295 log_msg ("failed to match ccreg inversion insn:\n");
1296 log_rtx (PATTERN (i
));
1297 log_return (false, "\naborting\n");
1301 if (dominating_cstore
== cstore_normal
1302 && !try_invert_branch_condition (trace
))
1305 // Eliminate cstores in all BBs.
1306 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1307 i
!= trace
.bb_entries
.end (); ++i
)
1309 if (i
->cstore
.empty ())
1312 if (i
->cstore_type
== dominating_cstore
)
1313 log_msg ("removing cstore in [bb %d]\n", i
->bb
->index
);
1316 log_msg ("replacing cstore with ccreg inversion in [bb %d]\n",
1320 emit_insn_after (make_inv_ccreg_insn (), i
->cstore
.insn
));
1323 if (can_remove_cstore (*i
, trace
))
1324 delete_insn (i
->cstore
.insn
);
1327 log_msg ("removing test insn before cbranch\n");
1328 delete_insn (trace
.setcc
.insn
);
1333 sh_treg_combine::try_optimize_cbranch (rtx_insn
*insn
)
1335 cbranch_trace
trace (insn
);
1337 log_msg ("\n\n--------------------------------------\n");
1338 log_msg ("found cbranch insn in [bb %d]:\n", trace
.bb ()->index
);
1341 trace
.cbranch_type
= branch_condition_type (trace
.branch_condition_rtx ());
1343 if (trace
.cbranch_type
== branch_if_true
)
1344 log_msg ("condition: branch if true\n");
1345 else if (trace
.cbranch_type
== branch_if_false
)
1346 log_msg ("condition: branch if false\n");
1349 log_msg ("unknown branch condition\n");
1350 log_rtx (trace
.branch_condition_rtx ());
1351 log_return_void ("\n");
1354 update_ccreg_mode (trace
.branch_condition_rtx ());
1356 // Scan the insns backwards for an insn that sets the ccreg by testing a
1357 // reg against zero like
1358 // (set (reg ccreg) (eq (reg) (const_int 0)))
1359 // The testing insn could also be outside of the current basic block, but
1360 // for now we limit the search to the current basic block.
1361 trace
.setcc
= find_set_of_reg_bb
1362 (m_ccreg
, prev_nonnote_nondebug_insn_bb (insn
));
1364 if (trace
.setcc
.set_src () == NULL_RTX
)
1365 log_return_void ("could not find set of ccreg in current BB\n");
1367 if (!is_cmp_eq_zero (trace
.setcc
.set_src ())
1368 && !is_inverted_ccreg (trace
.setcc
.set_src ()))
1370 log_msg ("unsupported set of ccreg in current BB: ");
1371 log_rtx (trace
.setcc
.set_src ());
1372 log_return_void ("\n");
1375 rtx trace_reg
= XEXP (trace
.setcc
.set_src (), 0);
1377 log_msg ("set of ccreg:\n");
1378 log_insn (trace
.setcc
.insn
);
1380 // See if we can remove the trace.setcc insn safely.
1381 if (reg_used_between_p (m_ccreg
, trace
.setcc
.insn
, trace
.cbranch_insn
))
1382 log_return_void ("ccreg used between testing insn and branch insn\n");
1384 if (volatile_insn_p (PATTERN (trace
.setcc
.insn
)))
1386 log_msg ("can't remove insn\n");
1387 log_insn (trace
.setcc
.insn
);
1388 log_return_void ("\nbecause it's volatile\n");
1391 // If the ccreg is inverted before cbranch try inverting the branch
1393 if (is_inverted_ccreg (trace
.setcc
.set_src ()))
1395 if (!trace
.can_invert_condition ())
1396 log_return_void ("branch condition can't be inverted - aborting\n");
1398 if (try_invert_branch_condition (trace
))
1399 delete_insn (trace
.setcc
.insn
);
1404 // Now that we have an insn which tests some reg and sets the condition
1405 // reg before the conditional branch, try to figure out how that tested
1406 // reg was formed, i.e. find all the insns that set the tested reg in
1408 // The tested reg might be set in multiple basic blocks so we need to
1409 // check all basic blocks which can reach this current basic block.
1410 // If the set of reg is an inverting or non-inverting store of the condition
1411 // register, check how the ccreg value was obtained.
1412 log_msg ("\ntracing ");
1413 log_rtx (trace_reg
);
1417 // First check the basic block where the conditional branch is in.
1418 // If we find it here there's no point in checking other BBs.
1419 trace
.bb_entries
.push_front (bb_entry (trace
.bb ()));
1421 record_return_t res
= record_set_of_reg
1422 (trace_reg
, prev_nonnote_nondebug_insn_bb (trace
.setcc
.insn
),
1423 trace
.bb_entries
.front ());
1425 if (res
== other_set_found
)
1426 log_return_void ("other set found - aborting trace\n");
1427 else if (res
== set_not_found
)
1429 // It seems the initial search in the BB of the conditional branch
1430 // didn't find anything. Now look in all predecessor BBs.
1431 for (edge_iterator ei
= ei_start (trace
.bb ()->preds
);
1432 !ei_end_p (ei
); ei_next (&ei
))
1434 edge e
= ei_edge (ei
);
1435 trace
.bb_entries
.push_front (bb_entry (e
->src
));
1437 res
= record_set_of_reg (trace_reg
, BB_END (e
->src
),
1438 trace
.bb_entries
.front ());
1439 if (res
!= set_found
)
1440 log_return_void ("set not found - aborting trace\n");
1444 if (dump_file
!= NULL
)
1446 log_msg ("\ncbranch trace summary:\n");
1447 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1448 i
!= trace
.bb_entries
.end (); ++i
)
1450 log_msg ("\n[bb %d]\n", i
->bb
->index
);
1451 if (!i
->setcc
.empty ())
1453 log_rtx (i
->setcc
.set_rtx
);
1456 if (!i
->cstore
.empty ())
1458 log_rtx (i
->cstore
.set_rtx
);
1462 for (std::vector
<set_of_reg
>::const_reverse_iterator j
=
1463 i
->cstore_reg_reg_copies
.rbegin ();
1464 j
!= i
->cstore_reg_reg_copies
.rend (); ++j
)
1466 log_rtx (j
->set_rtx
);
1471 log_rtx (trace
.setcc
.set_rtx
);
1473 log_rtx (PATTERN (trace
.cbranch_insn
));
1477 // Check that we don't have any empty BBs.
1478 // Only the BB with the cbranch may be empty.
1479 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1480 i
!= trace
.bb_entries
.end (); ++i
)
1481 if (i
->setcc
.empty () && i
->cstore
.empty () && i
->bb
!= trace
.bb ())
1482 log_return_void ("\n[bb %d] is empty - aborting.\n", i
->bb
->index
);
1484 // Determine the dominating cstore type
1485 // FIXME: Try to take the probabilities of the BBs into account somehow.
1486 int cstore_count
= 0;
1487 int inv_cstore_count
= 0;
1489 for (std::list
<bb_entry
>::const_iterator i
= trace
.bb_entries
.begin ();
1490 i
!= trace
.bb_entries
.end (); ++i
)
1492 if (i
->cstore_type
== cstore_normal
)
1494 else if (i
->cstore_type
== cstore_inverted
)
1495 inv_cstore_count
+= 1;
1498 log_msg ("cstore count = %d inverted cstore count = %d\n",
1499 cstore_count
, inv_cstore_count
);
1501 // This puts a priority on inverting cstores.
1502 cstore_type_t dominating_cstore
= inv_cstore_count
>= cstore_count
1506 if (dominating_cstore
== cstore_inverted
)
1507 log_msg ("will try to eliminate inverted cstore\n");
1508 else if (dominating_cstore
== cstore_normal
)
1510 log_msg ("will try to eliminate normal cstore\n");
1511 if (!trace
.can_invert_condition ())
1512 log_return_void ("branch condition can't be inverted - aborting\n");
1517 if (try_combine_comparisons (trace
, cstore_count
, inv_cstore_count
,
1521 try_eliminate_cstores (trace
, cstore_count
, inv_cstore_count
,
1526 sh_treg_combine::gate (function
*)
1528 return optimize
> 0;
1532 sh_treg_combine::execute (function
*fun
)
1534 unsigned int ccr0
= INVALID_REGNUM
;
1535 unsigned int ccr1
= INVALID_REGNUM
;
1537 if (targetm
.fixed_condition_code_regs (&ccr0
, &ccr1
)
1538 && ccr0
!= INVALID_REGNUM
)
1540 // Initially create a reg rtx with VOIDmode.
1541 // When the first conditional branch is discovered, the mode is changed
1542 // to the mode that is actually used by the target.
1543 m_ccreg
= gen_rtx_REG (VOIDmode
, ccr0
);
1546 if (m_ccreg
== NULL_RTX
)
1547 log_return (0, "no ccreg.\n\n");
1549 if (STORE_FLAG_VALUE
!= 1)
1550 log_return (0, "unsupported STORE_FLAG_VALUE %d", STORE_FLAG_VALUE
);
1552 log_msg ("ccreg: ");
1554 log_msg (" STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE
);
1556 // Look for basic blocks that end with a conditional branch or for
1557 // conditional insns and try to optimize them.
1559 FOR_EACH_BB_FN (bb
, fun
)
1561 rtx_insn
* i
= BB_END (bb
);
1562 if (i
== NULL
|| i
== PREV_INSN (BB_HEAD (bb
)))
1565 // A conditional branch is always the last insn of a basic block.
1566 if (any_condjump_p (i
) && onlyjump_p (i
))
1568 try_optimize_cbranch (i
);
1572 // Check all insns in block for conditional insns.
1573 for (; i
!= NULL
&& i
!= PREV_INSN (BB_HEAD (bb
)); i
= PREV_INSN (i
))
1574 if (is_conditional_insn (i
))
1575 try_optimize_cbranch (i
);
1580 // If new insns are created and this pass is executed after all insns
1581 // have been split already, we must split the insns we've changed or added
1583 // FIXME: Multi-word operations (which emit multiple insns) are not handled
1584 // properly here, since only one insn will end up in 'm_touched_insns'.
1585 // On SH this is not a problem though.
1587 for (std::vector
<rtx
>::const_iterator i
= m_touched_insns
.begin ();
1588 i
!= m_touched_insns
.end (); ++i
)
1590 log_msg ("trying to split insn:\n");
1593 try_split (PATTERN (*i
), safe_as_a
<rtx_insn
*> (*i
), 0);
1596 m_touched_insns
.clear ();
1597 log_return (0, "\n\n");
1600 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1601 // This allows instantiating the pass somewhere else without having to pull
1602 // in a header file.
1604 make_pass_sh_treg_combine (gcc::context
* ctx
, bool split_insns
,
1607 return new sh_treg_combine (ctx
, split_insns
, name
);