recog_memoized works on an rtx_insn *
[official-gcc.git] / gcc / config / sh / sh_treg_combine.cc
blob5ad7013a4298f7daac0fdb763fbed14bd71453e5
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-2014 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)
10 any later version.
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 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "machmode.h"
25 #include "basic-block.h"
26 #include "df.h"
27 #include "rtl.h"
28 #include "insn-config.h"
29 #include "insn-codes.h"
30 #include "emit-rtl.h"
31 #include "recog.h"
32 #include "tree-pass.h"
33 #include "target.h"
34 #include "expr.h"
36 #include <algorithm>
37 #include <list>
38 #include <vector>
41 This pass tries to optimize for example this:
42 mov.l @(4,r4),r1
43 tst r1,r1
44 movt r1
45 tst r1,r1
46 bt/s .L5
48 into something simpler:
49 mov.l @(4,r4),r1
50 tst r1,r1
51 bf/s .L5
53 Such sequences can be identified by looking for conditional branches and
54 checking whether the ccreg is set before the conditional branch
55 by testing another register for != 0, which was set by a ccreg store.
56 This can be optimized by eliminating the redundant comparison and
57 inverting the branch condition. There can be multiple comparisons in
58 different basic blocks that all end up in the redunant test insn before the
59 conditional branch. Some example RTL ...
61 Example 1)
62 ----------
64 [bb 3]
65 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 0)))
66 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
67 -> bb 5
69 [bb 4]
70 (set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
71 (set (reg:SI 167) (reg:SI 147 t))
72 -> bb 5
74 [bb 5]
75 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
76 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
77 (label_ref:SI 50) (pc)))
79 In [bb 4] elimination of the comparison would require inversion of the branch
80 condition and compensation of other BBs.
81 Instead an inverting reg-move can be used:
83 [bb 3]
84 (set (reg:SI 167) (reg:SI 173))
85 -> bb 5
87 [BB 4]
88 (set (reg:SI 167) (not:SI (reg:SI 177)))
89 -> bb 5
91 [bb 5]
92 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
93 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0)))
94 (label_ref:SI 50) (pc)))
97 Example 2)
98 ----------
100 [bb 3]
101 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
102 (set (reg:SI 167) (reg:SI 147 t))
103 -> bb 5
105 [bb 4]
106 (set (reg:SI 147 t) (gt:SI (reg:SI 177) (reg:SI 179)))
107 (set (reg:SI 167) (reg:SI 147 t))
108 -> bb 5
110 [bb 5]
111 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
112 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
113 (label_ref:SI 51) (pc)))
115 The common comparison is factored out and the branch condition is inverted:
117 [bb 3]
118 (set (reg:SI 167) (reg:SI 173))
119 (set (reg:SI 200) (reg:SI 175))
120 -> bb 5
122 [bb 4]
123 (set (reg:SI 167) (reg:SI 177))
124 (set (reg:SI 200) (reg:SI 179))
125 -> bb 5
127 [bb 5]
128 (set (reg:SI 147 t) (gt:SI (reg:SI 167) (reg:SI 200)))
129 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
130 (label_ref:SI 51) (pc)))
133 Example 3)
134 ----------
136 [bb 3]
137 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
138 (set (reg:SI 167) (reg:SI 147 t))
139 -> bb 5
141 [bb 4]
142 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
143 (set (reg:SI 167) (reg:SI 147 t))
144 -> bb 5
146 [bb 5]
147 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
148 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
149 (label_ref:SI 51) (pc)))
151 The T bit lifetime is extended and the branch condition is inverted:
153 [bb 3]
154 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
155 -> bb 5
157 [bb 4]
158 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
159 -> bb 5
161 [bb 5]
162 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
163 (label_ref:SI 51) (pc)))
166 Example 4)
167 ----------
169 [bb 3]
170 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
171 (set (reg:SI 167) (reg:SI 147 t))
172 -> bb 5
174 [bb 4]
175 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
176 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
177 -> bb 5
179 [bb 5]
180 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
181 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
182 (label_ref:SI 50) (pc)))
184 In this case the comparisons are the same and could be combined, but the
185 branch condition is different for [bb 3] and [bb 5]. Since the comparison
186 is not a zero comparison, we can't negate one of the operands. The best thing
187 we can do here is to eliminate the comparison before the cbranch and invert
188 the ccreg in one of the BBs. On SH2A this will utilize the 'nott' instruction.
190 [bb 3]
191 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
192 -> bb 5
194 [bb 4]
195 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
196 (set (reg:SI 147 t) (xor:SI (reg:SI 147 t) (const_int 1)))
197 -> bb 5
199 [bb 5]
200 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0)) // inverted
201 (label_ref:SI 50) (pc)))
204 In order to handle cases such as above the RTL pass does the following:
206 - Find the ccreg sets (comparisons) and ccreg stores
207 (inverting and non-inverting) in all related BBs.
209 - If the comparison types in the BBs are all the same, try to combine the
210 comparisons in the BBs and replace the zero comparison before the cbranch
211 with the common comparison.
213 - If the cstores are the same, move the comparison before the cbranch
214 and replace the comparisons in the BBs with reg-reg copies to get the
215 operands in place (create new pseudo regs).
217 - If the cstores differ, try to apply the special case
218 (eq (reg) (const_int 0)) -> inverted = (not (reg)).
219 for the subordinate cstore types and eliminate the dominating ones.
221 - If the comparison types in the BBs are not the same, or the first approach
222 doesn't work out for some reason, try to eliminate the comparison before the
223 cbranch by extending the lifetime of the ccreg by leaving the individual
224 comparisons but eliminating the cstores.
225 If the cstores are all the same this is straight forward.
226 If they're not, try to reverse the ccreg for the subordinate cstore type
227 and eliminate the dominating one.
230 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
231 // Helper functions
233 #define log_msg(...)\
234 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); } while (0)
236 #define log_insn(i)\
237 do { if (dump_file != NULL) print_rtl_single (dump_file, \
238 (const_rtx)i); } while (0)
240 #define log_rtx(r)\
241 do { if (dump_file != NULL) print_rtl (dump_file, (const_rtx)r); } while (0)
243 #define log_return(retval, ...)\
244 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
245 return retval; } while (0)
247 #define log_return_void(...)\
248 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
249 return; } while (0)
251 struct set_of_reg
253 // The insn where the search stopped or NULL.
254 rtx_insn *insn;
256 // The set rtx of the specified reg if found, NULL_RTX otherwise.
257 // Notice that the set rtx can also be in a parallel.
258 const_rtx set_rtx;
260 // The set source operand rtx if found, NULL_RTX otherwise.
262 set_src (void) const
264 return set_rtx == NULL_RTX ? NULL_RTX : XEXP (set_rtx, 1);
267 // The set destination operand rtx if found, NULL_RTX otherwise.
269 set_dst (void) const
271 return set_rtx == NULL_RTX ? NULL_RTX : XEXP (set_rtx, 0);
274 bool
275 empty (void) const
277 return insn == NULL_RTX || set_rtx == NULL_RTX;
281 // Given a reg rtx and a start insn find the insn (in the same basic block)
282 // that sets the reg.
283 static set_of_reg
284 find_set_of_reg_bb (rtx reg, rtx_insn *insn)
286 set_of_reg result = { insn, NULL_RTX };
288 if (!REG_P (reg) || insn == NULL)
289 return result;
291 for (result.insn = insn; result.insn != NULL;
292 result.insn = prev_nonnote_insn_bb (result.insn))
294 if (BARRIER_P (result.insn))
295 return result;
296 if (!NONJUMP_INSN_P (result.insn))
297 continue;
298 if (reg_set_p (reg, result.insn))
300 result.set_rtx = set_of (reg, result.insn);
301 if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
302 result.set_rtx = NULL_RTX;
303 return result;
307 return result;
310 static bool
311 reg_dead_after_insn (const_rtx reg, const_rtx insn)
313 return find_regno_note (insn, REG_DEAD, REGNO (reg)) != NULL_RTX;
316 static bool
317 reg_unused_after_insn (const_rtx reg, const_rtx insn)
319 return find_regno_note (insn, REG_UNUSED, REGNO (reg)) != NULL_RTX;
322 // Check whether the two specified basic blocks are adjacent, i.e. there's no
323 // other basic block in between them.
324 static bool
325 is_adjacent_bb (basic_block a, basic_block b)
327 basic_block bb0[] = { a, b };
328 basic_block bb1[] = { b, a };
330 for (int i = 0; i < 2; ++i)
331 for (edge_iterator ei = ei_start (bb0[i]->succs);
332 !ei_end_p (ei); ei_next (&ei))
333 if (ei_edge (ei)->dest == bb1[i])
334 return true;
336 return false;
339 // Internal function of trace_reg_uses.
340 static void
341 trace_reg_uses_1 (rtx reg, rtx_insn *start_insn, basic_block bb, int& count,
342 std::vector<basic_block>& visited_bb, rtx abort_at_insn)
344 if (bb == NULL)
345 return;
347 if (std::find (visited_bb.begin (), visited_bb.end (), bb)
348 != visited_bb.end ())
349 log_return_void ("[bb %d] already visited\n", bb->index);
351 visited_bb.push_back (bb);
353 if (BB_END (bb) == NULL_RTX)
354 log_return_void ("[bb %d] BB_END is null\n", bb->index);
356 if (start_insn == NULL_RTX)
357 log_return_void ("[bb %d] start_insn is null\n", bb->index);
359 rtx end_insn = NEXT_INSN (BB_END (bb));
360 if (end_insn == NULL_RTX)
361 log_return_void ("[bb %d] end_insn is null\n", bb->index);
363 for (rtx_insn *i = NEXT_INSN (start_insn); i != end_insn; i = NEXT_INSN (i))
365 if (INSN_P (i))
367 if (NONDEBUG_INSN_P (i)
368 && (reg_overlap_mentioned_p (reg, PATTERN (i))
369 || (CALL_P (i) && find_reg_fusage (i, USE, reg))))
371 log_msg ("found use in [bb %d] at insn:\n", bb->index);
372 log_insn (i);
373 log_msg ("\n");
374 count += 1;
377 // Stop following this BB if the reg is set or dies along the way.
378 if (reg_set_p (reg, i) || reg_dead_after_insn (reg, i))
379 return;
382 if (abort_at_insn != NULL_RTX && abort_at_insn == i)
383 return;
386 for (edge_iterator ei = ei_start (bb->succs); !ei_end_p (ei); ei_next (&ei))
388 basic_block succ_bb = ei_edge (ei)->dest;
389 trace_reg_uses_1 (reg, BB_HEAD (succ_bb), succ_bb, count, visited_bb,
390 abort_at_insn);
394 // Trace uses of the specified reg in all basic blocks that are reachable from
395 // the specified insn. If 'abort_at_insn' is not null, abort the trace at
396 // that insn. If the insn 'abort_at_insn' uses the specified reg, it is also
397 // counted.
398 static int
399 trace_reg_uses (rtx reg, rtx_insn *start_insn, rtx abort_at_insn)
401 log_msg ("\ntrace_reg_uses\nreg = ");
402 log_rtx (reg);
403 log_msg ("\nstart_insn = ");
404 log_insn (start_insn);
406 int count = 0;
407 std::vector<basic_block> visited_bb;
408 visited_bb.reserve (32);
410 trace_reg_uses_1 (reg, start_insn, BLOCK_FOR_INSN (start_insn),
411 count, visited_bb, abort_at_insn);
412 return count;
415 // FIXME: Remove dependency on SH predicate function somehow.
416 extern int t_reg_operand (rtx, machine_mode);
417 extern int negt_reg_operand (rtx, machine_mode);
419 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
420 // RTL pass class
422 class sh_treg_combine : public rtl_opt_pass
424 public:
425 sh_treg_combine (gcc::context* ctx, bool split_insns, const char* name);
426 virtual ~sh_treg_combine (void);
427 virtual bool gate (function *);
428 virtual unsigned int execute (function *);
430 private:
431 // Type of ccreg store that is supported.
432 enum cstore_type_t
434 cstore_normal = 0,
435 cstore_inverted = 1,
436 cstore_unknown = -1
439 // Type of branch condition that is supported.
440 enum branch_condition_type_t
442 branch_if_true = 1,
443 branch_if_false = 0,
444 unknown_branch_condition = -1
447 // For each basic block there can be a trace entry which consists of an
448 // insn that sets the ccreg (usually a comparison) and a ccreg store.
449 struct bb_entry
451 basic_block bb;
452 set_of_reg setcc;
453 set_of_reg cstore;
454 cstore_type_t cstore_type;
455 std::vector<set_of_reg> cstore_reg_reg_copies;
457 bb_entry (basic_block b)
458 : bb (b), setcc (), cstore (), cstore_type (cstore_unknown) { }
460 rtx comparison_rtx (void) const { return setcc.set_src (); }
463 // A ccreg trace for a conditional branch.
464 struct cbranch_trace
466 rtx_insn *cbranch_insn;
467 branch_condition_type_t cbranch_type;
469 // The comparison against zero right before the conditional branch.
470 set_of_reg setcc;
472 // All BBs that are related to the cbranch. The last BB in the list is
473 // the BB of the cbranch itself and might be empty.
474 std::list<bb_entry> bb_entries;
476 cbranch_trace (rtx_insn *insn)
477 : cbranch_insn (insn),
478 cbranch_type (unknown_branch_condition),
479 setcc ()
483 basic_block bb (void) const { return BLOCK_FOR_INSN (cbranch_insn); }
486 branch_condition_rtx (void) const
488 rtx x = pc_set (cbranch_insn);
489 return x == NULL_RTX ? NULL_RTX : XEXP (XEXP (x, 1), 0);
492 bool
493 can_invert_condition (void) const
495 // The branch condition can be inverted safely only if the condition
496 // reg is dead after the cbranch.
497 return reg_dead_after_insn (XEXP (branch_condition_rtx (), 0),
498 cbranch_insn);
502 static const pass_data default_pass_data;
504 // Tells whether modified or newly added insns are to be split at the end
505 // of the pass.
506 const bool m_split_insns;
508 // rtx of the ccreg that is obtained from the target.
509 rtx m_ccreg;
511 // Newly added or modified insns.
512 std::vector<rtx> m_touched_insns;
514 // Given an rtx determine whether it's a comparison with a constant zero.
515 static bool is_cmp_eq_zero (const_rtx i);
517 // Update the stored mode of the ccreg from the given branch condition rtx.
518 void update_ccreg_mode (const_rtx cond);
520 // Given an rtx, figure out the branch condition, assuming that it is
521 // in canonical form:
522 // (ne (reg) (const_int 0))
523 // (eq (reg) (const_int 0))
524 branch_condition_type_t branch_condition_type (const_rtx cond) const;
526 // Return true if the specified rtx is either a normal ccreg or
527 // a negated form of the ccreg.
528 bool is_normal_ccreg (const_rtx x) const;
529 bool is_inverted_ccreg (const_rtx x) const;
531 // Given a reg rtx and a start insn rtx, try to find the insn in the same
532 // basic block that sets the specified reg.
533 // Return how the search ended and the insn where it stopped or NULL_RTX.
534 enum record_return_t
536 set_found,
537 set_not_found,
538 other_set_found
540 record_return_t record_set_of_reg (rtx reg, rtx_insn *start_insn,
541 bb_entry& e);
543 // Tells whether the cbranch insn of the specified bb_entry can be removed
544 // safely without triggering any side effects.
545 bool can_remove_cstore (const bb_entry& e,
546 const cbranch_trace& trace) const;
548 // Tells whether the setcc insn of the specified bb_entry can be removed
549 // safely without triggering any side effects.
550 bool can_remove_comparison (const bb_entry& e,
551 const cbranch_trace& trace) const;
553 // Tells whether the two specified comparison rtx can be combined into a
554 // single comparison.
555 bool can_combine_comparisons (const_rtx x, const_rtx y) const;
557 // Tells whether the ccreg usage can be extended from the bb_entry on until
558 // the final cbranch of the trace.
559 bool can_extend_ccreg_usage (const bb_entry& e,
560 const cbranch_trace& trace) const;
562 // Create an insn rtx that is a negating reg move (not operation).
563 rtx make_not_reg_insn (rtx dst_reg, rtx src_reg) const;
565 // Create an insn rtx that inverts the ccreg.
566 rtx_insn *make_inv_ccreg_insn (void) const;
568 // Adds the specified insn to the set of modified or newly added insns that
569 // might need splitting at the end of the pass.
570 rtx touched_insn (rtx i);
572 // Try to invert the branch condition of the specified trace.
573 bool try_invert_branch_condition (cbranch_trace& trace);
575 // Try to optimize a cbranch trace by combining comparisons in BBs and
576 // eliminate the cstores.
577 bool try_combine_comparisons (cbranch_trace& trace,
578 int cstore_count, int inv_cstore_count,
579 cstore_type_t dominating_cstore);
581 // Try to optimize a cbranch trace by eliminating the cstores in BBs only.
582 bool try_eliminate_cstores (cbranch_trace& trace,
583 int cstore_count, int inv_cstore_count,
584 cstore_type_t dominating_cstore);
586 // Given a branch insn, try to optimize its branch condition.
587 // If any insns are modified or added they are added to 'm_touched_insns'.
588 void try_optimize_cbranch (rtx_insn *i);
592 const pass_data sh_treg_combine::default_pass_data =
594 RTL_PASS, // type
595 "", // name (overwritten by the constructor)
596 OPTGROUP_NONE, // optinfo_flags
597 TV_OPTIMIZE, // tv_id
598 0, // properties_required
599 0, // properties_provided
600 0, // properties_destroyed
601 0, // todo_flags_start
602 TODO_df_finish | TODO_df_verify // todo_flags_finish
605 sh_treg_combine::sh_treg_combine (gcc::context* ctx, bool split_insns,
606 const char* name)
607 : rtl_opt_pass (default_pass_data, ctx),
608 m_split_insns (split_insns),
609 m_ccreg (NULL_RTX)
611 // Overwrite default name in pass_data base class.
612 this->name = name;
615 sh_treg_combine::~sh_treg_combine (void)
619 void sh_treg_combine::update_ccreg_mode (const_rtx cond)
621 if (REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) != REGNO (m_ccreg))
622 return;
624 machine_mode m = GET_MODE (XEXP (cond, 0));
625 if (m == GET_MODE (m_ccreg))
626 return;
628 PUT_MODE (m_ccreg, m);
629 log_msg ("updated ccreg mode: ");
630 log_rtx (m_ccreg);
631 log_msg ("\n");
634 bool
635 sh_treg_combine::is_cmp_eq_zero (const_rtx i)
637 return i != NULL_RTX && GET_CODE (i) == EQ
638 && REG_P (XEXP (i, 0)) && XEXP (i, 1) == const0_rtx;
641 sh_treg_combine::branch_condition_type_t
642 sh_treg_combine::branch_condition_type (const_rtx cond) const
644 if (cond == NULL_RTX)
645 return unknown_branch_condition;
647 if (GET_CODE (cond) == NE
648 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
649 && XEXP (cond, 1) == const0_rtx)
650 return branch_if_true;
652 else if (GET_CODE (cond) == EQ
653 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
654 && XEXP (cond, 1) == const0_rtx)
655 return branch_if_false;
657 else
658 return unknown_branch_condition;
661 bool
662 sh_treg_combine::is_normal_ccreg (const_rtx x) const
664 return t_reg_operand (const_cast<rtx> (x), VOIDmode);
667 bool
668 sh_treg_combine::is_inverted_ccreg (const_rtx x) const
670 return negt_reg_operand (const_cast<rtx> (x), VOIDmode);
673 sh_treg_combine::record_return_t
674 sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn,
675 bb_entry& new_entry)
677 log_msg ("\n[bb %d]\n", new_entry.bb->index);
679 if (start_insn == NULL_RTX)
680 log_return (set_not_found, "set of reg not found. empty BB?\n");
682 new_entry.cstore_type = cstore_unknown;
684 for (rtx_insn *i = start_insn; i != NULL; )
686 new_entry.cstore = find_set_of_reg_bb (reg, i);
688 if (new_entry.cstore.set_src () == NULL_RTX)
689 log_return (set_not_found, "set of reg not found (cstore)\n");
691 log_insn (new_entry.cstore.insn);
692 log_msg ("\n");
694 if (is_normal_ccreg (new_entry.cstore.set_src ()))
696 log_msg ("normal condition store\n");
697 new_entry.cstore_type = cstore_normal;
699 else if (is_inverted_ccreg (new_entry.cstore.set_src ()))
701 log_msg ("inverted condition store\n");
702 new_entry.cstore_type = cstore_inverted;
704 else if (REG_P (new_entry.cstore.set_src ()))
706 // If it's a reg-reg copy follow the copied reg.
707 new_entry.cstore_reg_reg_copies.push_back (new_entry.cstore);
708 reg = new_entry.cstore.set_src ();
709 i = new_entry.cstore.insn;
711 log_msg ("reg-reg copy. tracing ");
712 log_rtx (reg);
713 log_msg ("\n");
714 continue;
716 else
717 log_return (other_set_found, "not a condition store\n");
719 gcc_assert (new_entry.cstore_type != cstore_unknown);
721 // Now see how the ccreg was set.
722 // For now it must be in the same BB.
723 log_msg ("tracing ccreg\n");
724 new_entry.setcc =
725 find_set_of_reg_bb (m_ccreg,
726 prev_nonnote_insn_bb (new_entry.cstore.insn));
728 // If cstore was found but setcc was not found continue anyway, as
729 // for some of the optimization types the setcc is irrelevant.
730 if (new_entry.setcc.set_src () == NULL_RTX)
731 log_return (set_found, "set of ccreg not found\n");
733 else if (GET_CODE (new_entry.setcc.set_rtx) == SET)
735 // Also allow insns that set the ccreg, but are not true comparison
736 // insns, as long as they are sets and not e.g. clobbers.
737 log_insn (new_entry.setcc.insn);
738 log_msg ("\n");
739 return set_found;
741 else
742 // If cstore was found but setcc was not found continue anyway, as
743 // for some of the optimization types the setcc is irrelevant.
744 log_return (set_found, "unknown set of ccreg\n");
747 log_return (set_not_found, "set of reg not found\n");
750 bool
751 sh_treg_combine::can_remove_cstore (const bb_entry& e,
752 const cbranch_trace& trace) const
754 if (volatile_insn_p (PATTERN (e.cstore.insn)))
756 log_msg ("can't remove insn\n");
757 log_insn (e.cstore.insn);
758 log_return (false, "\nbecause it's volatile\n");
761 // On SH there are parallel patterns which store the ccreg multiple times.
762 // In this case it's not safe.
763 rtx cstore_pat = PATTERN (e.cstore.insn);
764 if (GET_CODE (cstore_pat) == PARALLEL)
765 for (int i = 0; i < XVECLEN (cstore_pat, 0); ++i)
767 rtx x = XVECEXP (cstore_pat, 0, i);
769 // It's the cstore set that we're referring to, ignore that one.
770 if (x != e.cstore.set_rtx
771 && GET_CODE (x) == SET && reg_referenced_p (m_ccreg, x))
773 log_msg ("can't remove insn\n");
774 log_insn (e.cstore.insn);
775 log_return (false, "\nbecause it's a multiple ccreg store\n");
779 // If the cstore sets the ccreg (e.g. negc) and the ccreg is used afterwards
780 // it's not safe.
781 if (modified_in_p (m_ccreg, e.cstore.insn)
782 && !(reg_dead_after_insn (m_ccreg, e.cstore.insn)
783 || reg_unused_after_insn (m_ccreg, e.cstore.insn)))
785 log_msg ("can't remove insn\n");
786 log_insn (e.cstore.insn);
787 log_return (false, "\nbecause it sets the ccreg\n");
790 // If the cstore destination reg is copied around check the reg-reg
791 // copies. At every reg-reg copy the copied reg must be dead and there
792 // must not be a usage of the copied regs between the reg-reg copies.
793 // Otherwise we assume that the result of the cstore is used in some
794 // other way.
795 rtx_insn *prev_insn = e.cstore.insn;
796 for (std::vector<set_of_reg>::const_reverse_iterator i =
797 e.cstore_reg_reg_copies.rbegin ();
798 i != e.cstore_reg_reg_copies.rend (); ++i)
800 if (!reg_dead_after_insn (i->set_src (), i->insn))
802 log_msg ("can't remove insn\n");
803 log_insn (i->insn);
804 log_return (false, "\nbecause source of reg-reg copy doesn't die\n");
807 if (reg_used_between_p (i->set_src (), prev_insn, i->insn))
809 log_msg ("can't remove insn\n");
810 log_insn (i->insn);
811 log_return (false, "\nbecause reg %d is otherwise used\n",
812 REGNO (i->set_src ()));
815 prev_insn = i->insn;
818 // The cstore_dst reg must die after the test before the cbranch, otherwise
819 // it's not safe to remove the cstore.
820 // If the cstore destination reg is copied around check the effective
821 // destination reg of the cstore. The reg-reg copies are recorded in
822 // reverse order, i.e. the most recent reg-reg copy in the insn list
823 // comes first.
824 rtx cstore_dst = e.cstore_reg_reg_copies.empty ()
825 ? e.cstore.set_dst ()
826 : e.cstore_reg_reg_copies.front ().set_dst ();
828 if (!reg_dead_after_insn (cstore_dst, trace.setcc.insn))
830 log_msg ("can't remove insn\n");
831 log_insn (e.cstore.insn);
832 log_return (false, "\nbecause its effective target reg %d doesn't die "
833 "after trace.setcc.insn\n", REGNO (cstore_dst));
836 // Also check that the cstore_dst reg is not used in other reachable code
837 // paths before it dies.
838 // Count the uses of the effective cstore_dst reg (i.e. the last known reg
839 // that holds the cstore value after reg-reg copies) in all BBs that can be
840 // reached from bb_entry's BB including the BB of the cstore insn.
841 // If we get more than 1 uses we assume that it's used somewhere else and is
842 // not safe to be removed.
843 int cstore_dst_use_count = trace_reg_uses (cstore_dst, e.cstore.insn,
844 trace.setcc.insn);
845 if (cstore_dst_use_count > 1)
847 log_msg ("can't remove insn\n");
848 log_insn (e.cstore.insn);
849 log_return (false, "\nbecause its effective target reg %d is used "
850 "in %d other places\n", REGNO (cstore_dst),
851 cstore_dst_use_count - 1);
854 return true;
857 bool
858 sh_treg_combine::can_remove_comparison (const bb_entry& e,
859 const cbranch_trace&/* trace*/) const
861 // If the ccreg is used otherwise between the comparison and the cstore,
862 // it's not safe.
863 if (reg_used_between_p (m_ccreg, e.setcc.insn, e.cstore.insn))
865 log_msg ("can't remove insn\n");
866 log_insn (e.setcc.insn);
867 log_return (false, "\nbecause the ccreg is used otherwise\n");
870 if (!reg_dead_after_insn (m_ccreg, e.cstore.insn)
871 && !reg_unused_after_insn (m_ccreg, e.cstore.insn))
873 log_msg ("can't remove insn\n");
874 log_insn (e.cstore.insn);
875 log_return (false, "\nbecause ccreg is not dead or unused afterwards\n");
878 // On SH there are also multiple set patterns that can be used for
879 // comparisons, such as "shll". It's not safe to remove those.
880 if (multiple_sets (e.setcc.insn))
882 log_msg ("can't remove insn\n");
883 log_insn (e.cstore.insn);
884 log_return (false, "\nbecause it's a multiple set\n");
887 return true;
891 sh_treg_combine::make_not_reg_insn (rtx dst_reg, rtx src_reg) const
893 // This will to go through expanders and may output multiple insns
894 // for multi-word regs.
895 start_sequence ();
896 expand_simple_unop (GET_MODE (dst_reg), NOT, src_reg, dst_reg, 0);
897 rtx i = get_insns ();
898 end_sequence ();
899 return i;
902 rtx_insn *
903 sh_treg_combine::make_inv_ccreg_insn (void) const
905 start_sequence ();
906 rtx_insn *i = emit_insn (gen_rtx_SET (VOIDmode, m_ccreg,
907 gen_rtx_fmt_ee (XOR, GET_MODE (m_ccreg),
908 m_ccreg, const1_rtx)));
909 end_sequence ();
910 return i;
914 sh_treg_combine::touched_insn (rtx i)
916 m_touched_insns.push_back (i);
917 return i;
920 bool
921 sh_treg_combine::can_combine_comparisons (const_rtx x, const_rtx y) const
923 if (GET_CODE (x) != GET_CODE (y))
924 return false;
926 rtx x_op0 = XEXP (x, 0);
927 rtx x_op1 = XEXP (x, 1);
929 rtx y_op0 = XEXP (y, 0);
930 rtx y_op1 = XEXP (y, 1);
932 if (!REG_P (x_op0) || !REG_P (y_op0))
933 return false;
935 if (GET_MODE (x_op0) != GET_MODE (y_op0))
936 return false;
938 // rtx_equal_p also compares the reg numbers which we do not care about
939 // here, as long as both are regs and the modes are the same.
940 if (REG_P (x_op1))
941 return REG_P (y_op1) && GET_MODE (x_op1) == GET_MODE (y_op1);
943 return rtx_equal_p (x_op1, y_op1);
946 bool
947 sh_treg_combine::can_extend_ccreg_usage (const bb_entry& e,
948 const cbranch_trace& trace) const
950 // Check if the ccreg is not modified by other insins in the BB path until
951 // the final cbranch of the trace.
952 // Start checking after the cstore that follows the setcc, assuming that
953 // the cstore will be removed.
955 // The assumption here is that the specified bb_entry's BB is a direct
956 // predecessor of the trace.cbranch_insn's BB.
957 if (e.bb != trace.bb () && !is_adjacent_bb (e.bb, trace.bb ()))
958 log_return (false,
959 "can't extend ccreg usage -- [bb %d] and [bb %d] are not adjacent\n",
960 e.bb->index, trace.bb ()->index);
962 if (e.cstore.empty ())
963 log_return (false, "can't extend ccreg usage -- no cstore\n");
965 // The entry's cstore is in the same BB as the final cbranch.
966 if (e.bb == trace.bb ())
968 if (reg_set_between_p (m_ccreg, e.cstore.insn, trace.setcc.insn))
969 log_return (false,
970 "can't extend ccreg usage -- it's modified between e.cstore.insn "
971 "and trace.setcc.insn");
972 else
973 return true;
976 // The entry's cstore and the final cbranch are in different BBs.
977 if (reg_set_between_p (m_ccreg, e.cstore.insn, NEXT_INSN (BB_END (e.bb))))
978 log_return (false,
979 "can't extend ccreg usage -- it's modified in [bb %d]", e.bb->index);
981 if (reg_set_between_p (m_ccreg, PREV_INSN (BB_HEAD (trace.bb ())),
982 trace.setcc.insn))
983 log_return (false,
984 "can't extend ccreg usage -- it's modified in [bb %d]",
985 trace.bb ()->index);
987 return true;
990 bool
991 sh_treg_combine::try_invert_branch_condition (cbranch_trace& trace)
993 log_msg ("inverting branch condition\n");
995 if (!invert_jump_1 (trace.cbranch_insn, JUMP_LABEL (trace.cbranch_insn)))
996 log_return (false, "invert_jump_1 failed\n");
998 if (verify_changes (num_validated_changes ()))
999 confirm_change_group ();
1000 else
1001 log_return (false, "verify_changed failed\n");
1003 touched_insn (trace.cbranch_insn);
1004 return true;
1007 bool
1008 sh_treg_combine::try_combine_comparisons (cbranch_trace& trace,
1009 int cstore_count,
1010 int inv_cstore_count,
1011 cstore_type_t dominating_cstore)
1013 log_msg ("\ntry_combine_comparisons\n");
1015 // This function will always try to create new pseudos.
1016 if (!can_create_pseudo_p ())
1017 log_return (false, "can't create pseudos\n");
1019 // Check that all ccset insns are comparisons and all comparison types in
1020 // all BBs are the same and could be combined into one single comparison.
1021 rtx comp = NULL_RTX;
1022 rtx comp_insn = NULL_RTX;
1024 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1025 i != trace.bb_entries.end (); ++i)
1027 int i_empty_count = i->setcc.empty () + i->cstore.empty ();
1029 // A completly empty entry is OK (could be the BB of the cbranch).
1030 if (i_empty_count == 2)
1031 continue;
1033 // Otherwise we need both, the setcc and the cstore.
1034 if (i_empty_count != 0)
1035 log_return (false, "bb entry is not a setcc cstore pair\n");
1037 rtx other_comp = i->comparison_rtx ();
1039 if (!COMPARISON_P (other_comp))
1041 log_msg ("setcc is not a comparison:\n");
1042 log_rtx (other_comp);
1043 log_return (false, "\n");
1046 if (comp_insn == NULL_RTX)
1048 comp = other_comp;
1049 comp_insn = i->setcc.insn;
1051 else if (!can_combine_comparisons (comp, other_comp))
1052 return false;
1054 // The goal here is to eliminate all cstores and comparisons in the BBs.
1055 // Thus check if every cstore can actually be removed safely.
1056 if (!can_remove_cstore (*i, trace) || !can_remove_comparison (*i, trace))
1057 return false;
1060 // FIXME: The first operand of the comparison must be a simple reg.
1061 // This effectively prohibits combining div0s comparisons such as
1062 // (lt:SI (xor:SI (reg:SI) (reg:SI)))
1063 if (!REG_P (XEXP (comp, 0)))
1065 log_msg ("comparison operand 0\n");
1066 log_rtx (XEXP (comp, 0));
1067 log_return (false, "\nis not a reg\n");
1070 rtx comp_op0 = gen_reg_rtx (GET_MODE (XEXP (comp, 0)));
1071 rtx comp_op1 = REG_P (XEXP (comp, 1))
1072 ? gen_reg_rtx (GET_MODE (XEXP (comp, 1)))
1073 : XEXP (comp, 1);
1075 // If there are both, inverting and non-inverting cstores, they can only
1076 // be eliminated if the comparison can be inverted. We assume that the
1077 // comparison insns that we find are already minimal and canonicalized.
1078 // There is one special case though, where an integer comparison
1079 // (eq (reg) (const_int 0))
1080 // can be inverted with a sequence
1081 // (eq (not (reg)) (const_int 0))
1082 if (inv_cstore_count != 0 && cstore_count != 0)
1084 if (make_not_reg_insn (comp_op0, comp_op0) == NULL_RTX)
1085 log_return (false, "make_not_reg_insn failed.\n");
1087 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1088 i != trace.bb_entries.end (); ++i)
1090 if (i->setcc.empty () || i->cstore.empty ())
1091 continue;
1093 if (i->cstore_type != dominating_cstore
1094 && !is_cmp_eq_zero (i->comparison_rtx ()))
1096 log_msg ("can't invert comparison in insn\n");
1097 log_insn (i->setcc.insn);
1098 log_return (false,
1099 "\nbecause it's not a (eq (reg) (const_int 0))\n");
1104 if (dominating_cstore == cstore_normal
1105 && !try_invert_branch_condition (trace))
1106 return false;
1108 // Replace the test insn before the cbranch with the common comparison.
1109 // Instead of creating a new insn from scratch we copy the common comparison
1110 // pattern. This simplifies handling parallel comparison patterns, such as
1111 // FP comparisons on SH, which have an extra use on FPSCR.
1112 log_msg ("installing common comparison in [bb %d]\n", trace.bb ()->index);
1114 rtx common_comp_pat = copy_rtx (PATTERN (comp_insn));
1115 rtx common_comp = const_cast<rtx> (set_of (m_ccreg, common_comp_pat));
1117 gcc_assert (common_comp != NULL_RTX);
1119 XEXP (XEXP (common_comp, 1), 0) = comp_op0;
1120 XEXP (XEXP (common_comp, 1), 1) = comp_op1;
1122 log_rtx (common_comp_pat);
1123 log_msg ("\n");
1125 rtx common_comp_insn = touched_insn (emit_insn_after (common_comp_pat,
1126 trace.setcc.insn));
1128 if (REG_P (comp_op0))
1129 add_reg_note (common_comp_insn, REG_DEAD, copy_rtx (comp_op0));
1130 if (REG_P (comp_op1))
1131 add_reg_note (common_comp_insn, REG_DEAD, copy_rtx (comp_op1));
1133 delete_insn (trace.setcc.insn);
1135 // Replace comparison and cstore insns with reg-reg moves in all BBs.
1136 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1137 i != trace.bb_entries.end (); ++i)
1139 if (i->setcc.empty () || i->cstore.empty ())
1140 continue;
1142 rtx i_comp_op0 = XEXP (i->comparison_rtx (), 0);
1143 rtx i_comp_op1 = XEXP (i->comparison_rtx (), 1);
1145 if (i->cstore_type == dominating_cstore)
1147 log_msg ("replacing comparison and cstore with reg move "
1148 "in [bb %d]\n", i->bb->index);
1150 rtx new_i = touched_insn (
1151 emit_insn_after (gen_move_insn (comp_op0, i_comp_op0),
1152 i->setcc.insn));
1154 if (REG_P (i_comp_op0)
1155 && reg_dead_after_insn (i_comp_op0, i->setcc.insn))
1156 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op0));
1158 // If the second operand is a reg, have to emit a move insn.
1159 // Otherwise assume it's a const_int and just reference it.
1160 if (REG_P (comp_op1))
1162 new_i = touched_insn (
1163 emit_insn_after (gen_move_insn (comp_op1, i_comp_op1),
1164 i->setcc.insn));
1166 if (reg_dead_after_insn (i_comp_op1, i->setcc.insn))
1167 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op1));
1170 else
1172 log_msg ("replacing comparison and cstore with inverting reg move "
1173 "in [bb %d]\n", i->bb->index);
1175 rtx new_i = make_not_reg_insn (comp_op0, i_comp_op0);
1176 if (REG_P (i_comp_op0)
1177 && reg_dead_after_insn (i_comp_op0, i->setcc.insn))
1178 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op0));
1180 touched_insn (emit_insn_after (new_i, i->setcc.insn));
1183 delete_insn (i->cstore.insn);
1184 delete_insn (i->setcc.insn);
1187 return true;
1190 bool
1191 sh_treg_combine::try_eliminate_cstores (cbranch_trace& trace,
1192 int cstore_count, int inv_cstore_count,
1193 cstore_type_t dominating_cstore)
1195 log_msg ("\ntry_eliminate_cstores\n");
1197 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1198 i != trace.bb_entries.end (); ++i)
1200 // A completly empty entry is OK (could be the BB of the cbranch).
1201 if (i->setcc.empty () && i->cstore.empty ())
1202 continue;
1204 // We're going to eliminate cstores, but for that they have to be
1205 // there. We don't care about the setcc in this case.
1206 if (i->cstore.empty ())
1207 log_return (false, "bb entry cstore empty -- aborting\n");
1209 // The goal here is to eliminate all cstores in the BBs and extend the
1210 // ccreg usage.
1211 if (!can_extend_ccreg_usage (*i, trace))
1212 return false;
1214 // If the cstore can't be removed we can keep it around as long as
1215 // it doesn't modify the ccreg.
1216 if (!can_remove_cstore (*i, trace)
1217 && modified_in_p (m_ccreg, i->cstore.insn))
1218 log_return (false, "cstore sets ccreg -- aborting\n");
1221 // If there are both, inverting and non-inverting cstores, we'll have to
1222 // invert the ccreg as a replacement for one of them.
1223 if (cstore_count != 0 && inv_cstore_count != 0)
1225 rtx_insn *i = make_inv_ccreg_insn ();
1226 if (recog_memoized (i) < 0)
1228 log_msg ("failed to match ccreg inversion insn:\n");
1229 log_rtx (PATTERN (i));
1230 log_return (false, "\naborting\n");
1234 if (dominating_cstore == cstore_normal
1235 && !try_invert_branch_condition (trace))
1236 return false;
1238 // Eliminate cstores in all BBs.
1239 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1240 i != trace.bb_entries.end (); ++i)
1242 if (i->cstore.empty ())
1243 continue;
1245 if (i->cstore_type == dominating_cstore)
1246 log_msg ("removing cstore in [bb %d]\n", i->bb->index);
1247 else
1249 log_msg ("replacing cstore with ccreg inversion in [bb %d]\n",
1250 i->bb->index);
1252 touched_insn (
1253 emit_insn_after (make_inv_ccreg_insn (), i->cstore.insn));
1256 if (can_remove_cstore (*i, trace))
1257 delete_insn (i->cstore.insn);
1260 log_msg ("removing test insn before cbranch\n");
1261 delete_insn (trace.setcc.insn);
1262 return true;
1265 void
1266 sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
1268 cbranch_trace trace (insn);
1270 log_msg ("\n\n--------------------------------------\n");
1271 log_msg ("found cbranch insn in [bb %d]:\n", trace.bb ()->index);
1272 log_insn (insn);
1274 trace.cbranch_type = branch_condition_type (trace.branch_condition_rtx ());
1276 if (trace.cbranch_type == branch_if_true)
1277 log_msg ("condition: branch if true\n");
1278 else if (trace.cbranch_type == branch_if_false)
1279 log_msg ("condition: branch if false\n");
1280 else
1282 log_msg ("unknown branch condition\n");
1283 log_rtx (trace.branch_condition_rtx ());
1284 log_return_void ("\n");
1287 update_ccreg_mode (trace.branch_condition_rtx ());
1289 // Scan the insns backwards for an insn that sets the ccreg by testing a
1290 // reg against zero like
1291 // (set (reg ccreg) (eq (reg) (const_int 0)))
1292 // The testing insn could also be outside of the current basic block, but
1293 // for now we limit the search to the current basic block.
1294 trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_insn_bb (insn));
1296 if (!is_cmp_eq_zero (trace.setcc.set_src ()))
1297 log_return_void ("could not find set of ccreg in current BB\n");
1299 rtx trace_reg = XEXP (trace.setcc.set_src (), 0);
1301 log_msg ("set of ccreg:\n");
1302 log_insn (trace.setcc.insn);
1304 // See if we can remove the trace.setcc insn safely.
1305 if (reg_used_between_p (m_ccreg, trace.setcc.insn, trace.cbranch_insn))
1306 log_return_void ("ccreg used between testing insn and branch insn\n");
1308 if (volatile_insn_p (PATTERN (trace.setcc.insn)))
1310 log_msg ("can't remove insn\n");
1311 log_insn (trace.setcc.insn);
1312 log_return_void ("\nbecause it's volatile\n");
1315 // Now that we have an insn which tests some reg and sets the condition
1316 // reg before the conditional branch, try to figure out how that tested
1317 // reg was formed, i.e. find all the insns that set the tested reg in
1318 // some way.
1319 // The tested reg might be set in multiple basic blocks so we need to
1320 // check all basic blocks which can reach this current basic block.
1321 // If the set of reg is an inverting or non-inverting store of the condition
1322 // register, check how the ccreg value was obtained.
1323 log_msg ("\ntracing ");
1324 log_rtx (trace_reg);
1325 log_msg ("\n");
1328 // First check the basic block where the conditional branch is in.
1329 // If we find it here there's no point in checking other BBs.
1330 trace.bb_entries.push_front (bb_entry (trace.bb ()));
1332 record_return_t res =
1333 record_set_of_reg (trace_reg, prev_nonnote_insn_bb (trace.setcc.insn),
1334 trace.bb_entries.front ());
1336 if (res == other_set_found)
1337 log_return_void ("other set found - aborting trace\n");
1338 else if (res == set_not_found)
1340 // It seems the initial search in the BB of the conditional branch
1341 // didn't find anything. Now look in all predecessor BBs.
1342 for (edge_iterator ei = ei_start (trace.bb ()->preds);
1343 !ei_end_p (ei); ei_next (&ei))
1345 edge e = ei_edge (ei);
1346 trace.bb_entries.push_front (bb_entry (e->src));
1348 res = record_set_of_reg (trace_reg, BB_END (e->src),
1349 trace.bb_entries.front ());
1350 if (res != set_found)
1351 log_return_void ("set not found - aborting trace\n");
1355 if (dump_file != NULL)
1357 log_msg ("\ncbranch trace summary:\n");
1358 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1359 i != trace.bb_entries.end (); ++i)
1361 log_msg ("\n[bb %d]\n", i->bb->index);
1362 if (!i->setcc.empty ())
1364 log_rtx (i->setcc.set_rtx);
1365 log_msg ("\n");
1367 if (!i->cstore.empty ())
1369 log_rtx (i->cstore.set_rtx);
1370 log_msg ("\n");
1373 for (std::vector<set_of_reg>::const_reverse_iterator j =
1374 i->cstore_reg_reg_copies.rbegin ();
1375 j != i->cstore_reg_reg_copies.rend (); ++j)
1377 log_rtx (j->set_rtx);
1378 log_msg ("\n");
1382 log_rtx (trace.setcc.set_rtx);
1383 log_msg ("\n");
1384 log_rtx (PATTERN (trace.cbranch_insn));
1385 log_msg ("\n");
1388 // Check that we don't have any empty BBs.
1389 // Only the BB with the cbranch may be empty.
1390 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1391 i != trace.bb_entries.end (); ++i)
1392 if (i->setcc.empty () && i->cstore.empty () && i->bb != trace.bb ())
1393 log_return_void ("\n[bb %d] is empty - aborting.\n", i->bb->index);
1395 // Determine the dominating cstore type
1396 // FIXME: Try to take the probabilities of the BBs into account somehow.
1397 int cstore_count = 0;
1398 int inv_cstore_count = 0;
1400 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1401 i != trace.bb_entries.end (); ++i)
1403 if (i->cstore_type == cstore_normal)
1404 cstore_count += 1;
1405 else if (i->cstore_type == cstore_inverted)
1406 inv_cstore_count += 1;
1409 log_msg ("cstore count = %d inverted cstore count = %d\n",
1410 cstore_count, inv_cstore_count);
1412 // This puts a priority on inverting cstores.
1413 cstore_type_t dominating_cstore = inv_cstore_count >= cstore_count
1414 ? cstore_inverted
1415 : cstore_normal;
1417 if (dominating_cstore == cstore_inverted)
1418 log_msg ("will try to eliminate inverted cstore\n");
1419 else if (dominating_cstore == cstore_normal)
1421 log_msg ("will try to eliminate normal cstore\n");
1422 if (!trace.can_invert_condition ())
1423 log_return_void ("branch condition can't be inverted - aborting\n");
1425 else
1426 gcc_unreachable ();
1428 if (try_combine_comparisons (trace, cstore_count, inv_cstore_count,
1429 dominating_cstore))
1430 return;
1432 try_eliminate_cstores (trace, cstore_count, inv_cstore_count,
1433 dominating_cstore);
1436 bool
1437 sh_treg_combine::gate (function *)
1439 return optimize > 0;
1442 unsigned int
1443 sh_treg_combine::execute (function *fun)
1445 unsigned int ccr0 = INVALID_REGNUM;
1446 unsigned int ccr1 = INVALID_REGNUM;
1448 if (targetm.fixed_condition_code_regs (&ccr0, &ccr1)
1449 && ccr0 != INVALID_REGNUM)
1451 // Initially create a reg rtx with VOIDmode.
1452 // When the first conditional branch is discovered, the mode is changed
1453 // to the mode that is actually used by the target.
1454 m_ccreg = gen_rtx_REG (VOIDmode, ccr0);
1457 if (m_ccreg == NULL_RTX)
1458 log_return (0, "no ccreg.\n\n");
1460 if (STORE_FLAG_VALUE != 1)
1461 log_return (0, "unsupported STORE_FLAG_VALUE %d", STORE_FLAG_VALUE);
1463 log_msg ("ccreg: ");
1464 log_rtx (m_ccreg);
1465 log_msg (" STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE);
1467 // Look for basic blocks that end with a conditional branch and try to
1468 // optimize them.
1469 basic_block bb;
1470 FOR_EACH_BB_FN (bb, fun)
1472 rtx_insn *i = BB_END (bb);
1473 if (any_condjump_p (i) && onlyjump_p (i))
1474 try_optimize_cbranch (i);
1477 log_msg ("\n\n");
1479 // If new insns are created and this pass is executed after all insns
1480 // have been split already, we must split the insns we've changed or added
1481 // ourselves here.
1482 // FIXME: Multi-word operations (which emit multiple insns) are not handled
1483 // properly here, since only one insn will end up in 'm_touched_insns'.
1484 // On SH this is not a problem though.
1485 if (m_split_insns)
1486 for (std::vector<rtx>::const_iterator i = m_touched_insns.begin ();
1487 i != m_touched_insns.end (); ++i)
1489 log_msg ("trying to split insn:\n");
1490 log_insn (*i);
1491 log_msg ("\n");
1492 try_split (PATTERN (*i), *i, 0);
1495 m_touched_insns.clear ();
1496 log_return (0, "\n\n");
1499 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1500 // This allows instantiating the pass somewhere else without having to pull
1501 // in a header file.
1502 opt_pass*
1503 make_pass_sh_treg_combine (gcc::context* ctx, bool split_insns,
1504 const char* name)
1506 return new sh_treg_combine (ctx, split_insns, name);