]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/sh/sh_treg_combine.cc
2014-11-01 Andrew MacLeod <amacleod@redhat,com>
[thirdparty/gcc.git] / gcc / config / sh / sh_treg_combine.cc
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.
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "machmode.h"
25 #include "predict.h"
26 #include "vec.h"
27 #include "hashtab.h"
28 #include "hash-set.h"
29 #include "tm.h"
30 #include "hard-reg-set.h"
31 #include "input.h"
32 #include "function.h"
33 #include "dominance.h"
34 #include "cfg.h"
35 #include "cfgrtl.h"
36 #include "cfganal.h"
37 #include "lcm.h"
38 #include "cfgbuild.h"
39 #include "cfgcleanup.h"
40 #include "basic-block.h"
41 #include "df.h"
42 #include "rtl.h"
43 #include "insn-config.h"
44 #include "insn-codes.h"
45 #include "emit-rtl.h"
46 #include "recog.h"
47 #include "tree-pass.h"
48 #include "target.h"
49 #include "tree-core.h"
50 #include "optabs.h"
51 #include "expr.h"
52
53 #include <algorithm>
54 #include <list>
55 #include <vector>
56
57 /*
58 This pass tries to optimize for example this:
59 mov.l @(4,r4),r1
60 tst r1,r1
61 movt r1
62 tst r1,r1
63 bt/s .L5
64
65 into something simpler:
66 mov.l @(4,r4),r1
67 tst r1,r1
68 bf/s .L5
69
70 Such sequences can be identified by looking for conditional branches and
71 checking whether the ccreg is set before the conditional branch
72 by testing another register for != 0, which was set by a ccreg store.
73 This can be optimized by eliminating the redundant comparison and
74 inverting the branch condition. There can be multiple comparisons in
75 different basic blocks that all end up in the redunant test insn before the
76 conditional branch. Some example RTL ...
77
78 Example 1)
79 ----------
80
81 [bb 3]
82 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 0)))
83 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
84 -> bb 5
85
86 [bb 4]
87 (set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
88 (set (reg:SI 167) (reg:SI 147 t))
89 -> bb 5
90
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)))
95
96 In [bb 4] elimination of the comparison would require inversion of the branch
97 condition and compensation of other BBs.
98 Instead an inverting reg-move can be used:
99
100 [bb 3]
101 (set (reg:SI 167) (reg:SI 173))
102 -> bb 5
103
104 [BB 4]
105 (set (reg:SI 167) (not:SI (reg:SI 177)))
106 -> bb 5
107
108 [bb 5]
109 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
110 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0)))
111 (label_ref:SI 50) (pc)))
112
113
114 Example 2)
115 ----------
116
117 [bb 3]
118 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
119 (set (reg:SI 167) (reg:SI 147 t))
120 -> bb 5
121
122 [bb 4]
123 (set (reg:SI 147 t) (gt:SI (reg:SI 177) (reg:SI 179)))
124 (set (reg:SI 167) (reg:SI 147 t))
125 -> bb 5
126
127 [bb 5]
128 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
129 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
130 (label_ref:SI 51) (pc)))
131
132 The common comparison is factored out and the branch condition is inverted:
133
134 [bb 3]
135 (set (reg:SI 167) (reg:SI 173))
136 (set (reg:SI 200) (reg:SI 175))
137 -> bb 5
138
139 [bb 4]
140 (set (reg:SI 167) (reg:SI 177))
141 (set (reg:SI 200) (reg:SI 179))
142 -> bb 5
143
144 [bb 5]
145 (set (reg:SI 147 t) (gt:SI (reg:SI 167) (reg:SI 200)))
146 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
147 (label_ref:SI 51) (pc)))
148
149
150 Example 3)
151 ----------
152
153 [bb 3]
154 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
155 (set (reg:SI 167) (reg:SI 147 t))
156 -> bb 5
157
158 [bb 4]
159 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
160 (set (reg:SI 167) (reg:SI 147 t))
161 -> bb 5
162
163 [bb 5]
164 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
165 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
166 (label_ref:SI 51) (pc)))
167
168 The T bit lifetime is extended and the branch condition is inverted:
169
170 [bb 3]
171 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
172 -> bb 5
173
174 [bb 4]
175 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
176 -> bb 5
177
178 [bb 5]
179 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
180 (label_ref:SI 51) (pc)))
181
182
183 Example 4)
184 ----------
185
186 [bb 3]
187 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
188 (set (reg:SI 167) (reg:SI 147 t))
189 -> bb 5
190
191 [bb 4]
192 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
193 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
194 -> bb 5
195
196 [bb 5]
197 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
198 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
199 (label_ref:SI 50) (pc)))
200
201 In this case the comparisons are the same and could be combined, but the
202 branch condition is different for [bb 3] and [bb 5]. Since the comparison
203 is not a zero comparison, we can't negate one of the operands. The best thing
204 we can do here is to eliminate the comparison before the cbranch and invert
205 the ccreg in one of the BBs. On SH2A this will utilize the 'nott' instruction.
206
207 [bb 3]
208 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
209 -> bb 5
210
211 [bb 4]
212 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
213 (set (reg:SI 147 t) (xor:SI (reg:SI 147 t) (const_int 1)))
214 -> bb 5
215
216 [bb 5]
217 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0)) // inverted
218 (label_ref:SI 50) (pc)))
219
220
221 In order to handle cases such as above the RTL pass does the following:
222
223 - Find the ccreg sets (comparisons) and ccreg stores
224 (inverting and non-inverting) in all related BBs.
225
226 - If the comparison types in the BBs are all the same, try to combine the
227 comparisons in the BBs and replace the zero comparison before the cbranch
228 with the common comparison.
229
230 - If the cstores are the same, move the comparison before the cbranch
231 and replace the comparisons in the BBs with reg-reg copies to get the
232 operands in place (create new pseudo regs).
233
234 - If the cstores differ, try to apply the special case
235 (eq (reg) (const_int 0)) -> inverted = (not (reg)).
236 for the subordinate cstore types and eliminate the dominating ones.
237
238 - If the comparison types in the BBs are not the same, or the first approach
239 doesn't work out for some reason, try to eliminate the comparison before the
240 cbranch by extending the lifetime of the ccreg by leaving the individual
241 comparisons but eliminating the cstores.
242 If the cstores are all the same this is straight forward.
243 If they're not, try to reverse the ccreg for the subordinate cstore type
244 and eliminate the dominating one.
245 */
246
247 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
248 // Helper functions
249
250 #define log_msg(...)\
251 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); } while (0)
252
253 #define log_insn(i)\
254 do { if (dump_file != NULL) print_rtl_single (dump_file, \
255 (const_rtx)i); } while (0)
256
257 #define log_rtx(r)\
258 do { if (dump_file != NULL) print_rtl (dump_file, (const_rtx)r); } while (0)
259
260 #define log_return(retval, ...)\
261 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
262 return retval; } while (0)
263
264 #define log_return_void(...)\
265 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
266 return; } while (0)
267
268 struct set_of_reg
269 {
270 // The insn where the search stopped or NULL.
271 rtx_insn *insn;
272
273 // The set rtx of the specified reg if found, NULL_RTX otherwise.
274 // Notice that the set rtx can also be in a parallel.
275 const_rtx set_rtx;
276
277 // The set source operand rtx if found, NULL_RTX otherwise.
278 rtx
279 set_src (void) const
280 {
281 return set_rtx == NULL_RTX ? NULL_RTX : XEXP (set_rtx, 1);
282 }
283
284 // The set destination operand rtx if found, NULL_RTX otherwise.
285 rtx
286 set_dst (void) const
287 {
288 return set_rtx == NULL_RTX ? NULL_RTX : XEXP (set_rtx, 0);
289 }
290
291 bool
292 empty (void) const
293 {
294 return insn == NULL_RTX || set_rtx == NULL_RTX;
295 }
296 };
297
298 // Given a reg rtx and a start insn find the insn (in the same basic block)
299 // that sets the reg.
300 static set_of_reg
301 find_set_of_reg_bb (rtx reg, rtx_insn *insn)
302 {
303 set_of_reg result = { insn, NULL_RTX };
304
305 if (!REG_P (reg) || insn == NULL)
306 return result;
307
308 for (result.insn = insn; result.insn != NULL;
309 result.insn = prev_nonnote_insn_bb (result.insn))
310 {
311 if (BARRIER_P (result.insn))
312 return result;
313 if (!NONJUMP_INSN_P (result.insn))
314 continue;
315 if (reg_set_p (reg, result.insn))
316 {
317 result.set_rtx = set_of (reg, result.insn);
318 if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
319 result.set_rtx = NULL_RTX;
320 return result;
321 }
322 }
323
324 return result;
325 }
326
327 static bool
328 reg_dead_after_insn (const_rtx reg, const_rtx insn)
329 {
330 return find_regno_note (insn, REG_DEAD, REGNO (reg)) != NULL_RTX;
331 }
332
333 static bool
334 reg_unused_after_insn (const_rtx reg, const_rtx insn)
335 {
336 return find_regno_note (insn, REG_UNUSED, REGNO (reg)) != NULL_RTX;
337 }
338
339 // Check whether the two specified basic blocks are adjacent, i.e. there's no
340 // other basic block in between them.
341 static bool
342 is_adjacent_bb (basic_block a, basic_block b)
343 {
344 basic_block bb0[] = { a, b };
345 basic_block bb1[] = { b, a };
346
347 for (int i = 0; i < 2; ++i)
348 for (edge_iterator ei = ei_start (bb0[i]->succs);
349 !ei_end_p (ei); ei_next (&ei))
350 if (ei_edge (ei)->dest == bb1[i])
351 return true;
352
353 return false;
354 }
355
356 // Internal function of trace_reg_uses.
357 static void
358 trace_reg_uses_1 (rtx reg, rtx_insn *start_insn, basic_block bb, int& count,
359 std::vector<basic_block>& visited_bb, rtx abort_at_insn)
360 {
361 if (bb == NULL)
362 return;
363
364 if (std::find (visited_bb.begin (), visited_bb.end (), bb)
365 != visited_bb.end ())
366 log_return_void ("[bb %d] already visited\n", bb->index);
367
368 visited_bb.push_back (bb);
369
370 if (BB_END (bb) == NULL_RTX)
371 log_return_void ("[bb %d] BB_END is null\n", bb->index);
372
373 if (start_insn == NULL_RTX)
374 log_return_void ("[bb %d] start_insn is null\n", bb->index);
375
376 rtx end_insn = NEXT_INSN (BB_END (bb));
377 if (end_insn == NULL_RTX)
378 log_return_void ("[bb %d] end_insn is null\n", bb->index);
379
380 for (rtx_insn *i = NEXT_INSN (start_insn); i != end_insn; i = NEXT_INSN (i))
381 {
382 if (INSN_P (i))
383 {
384 if (NONDEBUG_INSN_P (i)
385 && (reg_overlap_mentioned_p (reg, PATTERN (i))
386 || (CALL_P (i) && find_reg_fusage (i, USE, reg))))
387 {
388 log_msg ("found use in [bb %d] at insn:\n", bb->index);
389 log_insn (i);
390 log_msg ("\n");
391 count += 1;
392 }
393
394 // Stop following this BB if the reg is set or dies along the way.
395 if (reg_set_p (reg, i) || reg_dead_after_insn (reg, i))
396 return;
397 }
398
399 if (abort_at_insn != NULL_RTX && abort_at_insn == i)
400 return;
401 }
402
403 for (edge_iterator ei = ei_start (bb->succs); !ei_end_p (ei); ei_next (&ei))
404 {
405 basic_block succ_bb = ei_edge (ei)->dest;
406 trace_reg_uses_1 (reg, BB_HEAD (succ_bb), succ_bb, count, visited_bb,
407 abort_at_insn);
408 }
409 }
410
411 // Trace uses of the specified reg in all basic blocks that are reachable from
412 // the specified insn. If 'abort_at_insn' is not null, abort the trace at
413 // that insn. If the insn 'abort_at_insn' uses the specified reg, it is also
414 // counted.
415 static int
416 trace_reg_uses (rtx reg, rtx_insn *start_insn, rtx abort_at_insn)
417 {
418 log_msg ("\ntrace_reg_uses\nreg = ");
419 log_rtx (reg);
420 log_msg ("\nstart_insn = ");
421 log_insn (start_insn);
422
423 int count = 0;
424 std::vector<basic_block> visited_bb;
425 visited_bb.reserve (32);
426
427 trace_reg_uses_1 (reg, start_insn, BLOCK_FOR_INSN (start_insn),
428 count, visited_bb, abort_at_insn);
429 return count;
430 }
431
432 // FIXME: Remove dependency on SH predicate function somehow.
433 extern int t_reg_operand (rtx, machine_mode);
434 extern int negt_reg_operand (rtx, machine_mode);
435
436 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
437 // RTL pass class
438
439 class sh_treg_combine : public rtl_opt_pass
440 {
441 public:
442 sh_treg_combine (gcc::context* ctx, bool split_insns, const char* name);
443 virtual ~sh_treg_combine (void);
444 virtual bool gate (function *);
445 virtual unsigned int execute (function *);
446
447 private:
448 // Type of ccreg store that is supported.
449 enum cstore_type_t
450 {
451 cstore_normal = 0,
452 cstore_inverted = 1,
453 cstore_unknown = -1
454 };
455
456 // Type of branch condition that is supported.
457 enum branch_condition_type_t
458 {
459 branch_if_true = 1,
460 branch_if_false = 0,
461 unknown_branch_condition = -1
462 };
463
464 // For each basic block there can be a trace entry which consists of an
465 // insn that sets the ccreg (usually a comparison) and a ccreg store.
466 struct bb_entry
467 {
468 basic_block bb;
469 set_of_reg setcc;
470 set_of_reg cstore;
471 cstore_type_t cstore_type;
472 std::vector<set_of_reg> cstore_reg_reg_copies;
473
474 bb_entry (basic_block b)
475 : bb (b), setcc (), cstore (), cstore_type (cstore_unknown) { }
476
477 rtx comparison_rtx (void) const { return setcc.set_src (); }
478 };
479
480 // A ccreg trace for a conditional branch.
481 struct cbranch_trace
482 {
483 rtx_insn *cbranch_insn;
484 branch_condition_type_t cbranch_type;
485
486 // The comparison against zero right before the conditional branch.
487 set_of_reg setcc;
488
489 // All BBs that are related to the cbranch. The last BB in the list is
490 // the BB of the cbranch itself and might be empty.
491 std::list<bb_entry> bb_entries;
492
493 cbranch_trace (rtx_insn *insn)
494 : cbranch_insn (insn),
495 cbranch_type (unknown_branch_condition),
496 setcc ()
497 {
498 }
499
500 basic_block bb (void) const { return BLOCK_FOR_INSN (cbranch_insn); }
501
502 rtx
503 branch_condition_rtx (void) const
504 {
505 rtx x = pc_set (cbranch_insn);
506 return x == NULL_RTX ? NULL_RTX : XEXP (XEXP (x, 1), 0);
507 }
508
509 bool
510 can_invert_condition (void) const
511 {
512 // The branch condition can be inverted safely only if the condition
513 // reg is dead after the cbranch.
514 return reg_dead_after_insn (XEXP (branch_condition_rtx (), 0),
515 cbranch_insn);
516 }
517 };
518
519 static const pass_data default_pass_data;
520
521 // Tells whether modified or newly added insns are to be split at the end
522 // of the pass.
523 const bool m_split_insns;
524
525 // rtx of the ccreg that is obtained from the target.
526 rtx m_ccreg;
527
528 // Newly added or modified insns.
529 std::vector<rtx> m_touched_insns;
530
531 // Given an rtx determine whether it's a comparison with a constant zero.
532 static bool is_cmp_eq_zero (const_rtx i);
533
534 // Update the stored mode of the ccreg from the given branch condition rtx.
535 void update_ccreg_mode (const_rtx cond);
536
537 // Given an rtx, figure out the branch condition, assuming that it is
538 // in canonical form:
539 // (ne (reg) (const_int 0))
540 // (eq (reg) (const_int 0))
541 branch_condition_type_t branch_condition_type (const_rtx cond) const;
542
543 // Return true if the specified rtx is either a normal ccreg or
544 // a negated form of the ccreg.
545 bool is_normal_ccreg (const_rtx x) const;
546 bool is_inverted_ccreg (const_rtx x) const;
547
548 // Given a reg rtx and a start insn rtx, try to find the insn in the same
549 // basic block that sets the specified reg.
550 // Return how the search ended and the insn where it stopped or NULL_RTX.
551 enum record_return_t
552 {
553 set_found,
554 set_not_found,
555 other_set_found
556 };
557 record_return_t record_set_of_reg (rtx reg, rtx_insn *start_insn,
558 bb_entry& e);
559
560 // Tells whether the cbranch insn of the specified bb_entry can be removed
561 // safely without triggering any side effects.
562 bool can_remove_cstore (const bb_entry& e,
563 const cbranch_trace& trace) const;
564
565 // Tells whether the setcc insn of the specified bb_entry can be removed
566 // safely without triggering any side effects.
567 bool can_remove_comparison (const bb_entry& e,
568 const cbranch_trace& trace) const;
569
570 // Tells whether the two specified comparison rtx can be combined into a
571 // single comparison.
572 bool can_combine_comparisons (const_rtx x, const_rtx y) const;
573
574 // Tells whether the ccreg usage can be extended from the bb_entry on until
575 // the final cbranch of the trace.
576 bool can_extend_ccreg_usage (const bb_entry& e,
577 const cbranch_trace& trace) const;
578
579 // Create an insn rtx that is a negating reg move (not operation).
580 rtx make_not_reg_insn (rtx dst_reg, rtx src_reg) const;
581
582 // Create an insn rtx that inverts the ccreg.
583 rtx_insn *make_inv_ccreg_insn (void) const;
584
585 // Adds the specified insn to the set of modified or newly added insns that
586 // might need splitting at the end of the pass.
587 rtx touched_insn (rtx i);
588
589 // Try to invert the branch condition of the specified trace.
590 bool try_invert_branch_condition (cbranch_trace& trace);
591
592 // Try to optimize a cbranch trace by combining comparisons in BBs and
593 // eliminate the cstores.
594 bool try_combine_comparisons (cbranch_trace& trace,
595 int cstore_count, int inv_cstore_count,
596 cstore_type_t dominating_cstore);
597
598 // Try to optimize a cbranch trace by eliminating the cstores in BBs only.
599 bool try_eliminate_cstores (cbranch_trace& trace,
600 int cstore_count, int inv_cstore_count,
601 cstore_type_t dominating_cstore);
602
603 // Given a branch insn, try to optimize its branch condition.
604 // If any insns are modified or added they are added to 'm_touched_insns'.
605 void try_optimize_cbranch (rtx_insn *i);
606 };
607
608
609 const pass_data sh_treg_combine::default_pass_data =
610 {
611 RTL_PASS, // type
612 "", // name (overwritten by the constructor)
613 OPTGROUP_NONE, // optinfo_flags
614 TV_OPTIMIZE, // tv_id
615 0, // properties_required
616 0, // properties_provided
617 0, // properties_destroyed
618 0, // todo_flags_start
619 TODO_df_finish | TODO_df_verify // todo_flags_finish
620 };
621
622 sh_treg_combine::sh_treg_combine (gcc::context* ctx, bool split_insns,
623 const char* name)
624 : rtl_opt_pass (default_pass_data, ctx),
625 m_split_insns (split_insns),
626 m_ccreg (NULL_RTX)
627 {
628 // Overwrite default name in pass_data base class.
629 this->name = name;
630 }
631
632 sh_treg_combine::~sh_treg_combine (void)
633 {
634 }
635
636 void sh_treg_combine::update_ccreg_mode (const_rtx cond)
637 {
638 if (REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) != REGNO (m_ccreg))
639 return;
640
641 machine_mode m = GET_MODE (XEXP (cond, 0));
642 if (m == GET_MODE (m_ccreg))
643 return;
644
645 PUT_MODE (m_ccreg, m);
646 log_msg ("updated ccreg mode: ");
647 log_rtx (m_ccreg);
648 log_msg ("\n");
649 }
650
651 bool
652 sh_treg_combine::is_cmp_eq_zero (const_rtx i)
653 {
654 return i != NULL_RTX && GET_CODE (i) == EQ
655 && REG_P (XEXP (i, 0)) && XEXP (i, 1) == const0_rtx;
656 }
657
658 sh_treg_combine::branch_condition_type_t
659 sh_treg_combine::branch_condition_type (const_rtx cond) const
660 {
661 if (cond == NULL_RTX)
662 return unknown_branch_condition;
663
664 if (GET_CODE (cond) == NE
665 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
666 && XEXP (cond, 1) == const0_rtx)
667 return branch_if_true;
668
669 else if (GET_CODE (cond) == EQ
670 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
671 && XEXP (cond, 1) == const0_rtx)
672 return branch_if_false;
673
674 else
675 return unknown_branch_condition;
676 }
677
678 bool
679 sh_treg_combine::is_normal_ccreg (const_rtx x) const
680 {
681 return t_reg_operand (const_cast<rtx> (x), VOIDmode);
682 }
683
684 bool
685 sh_treg_combine::is_inverted_ccreg (const_rtx x) const
686 {
687 return negt_reg_operand (const_cast<rtx> (x), VOIDmode);
688 }
689
690 sh_treg_combine::record_return_t
691 sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn,
692 bb_entry& new_entry)
693 {
694 log_msg ("\n[bb %d]\n", new_entry.bb->index);
695
696 if (start_insn == NULL_RTX)
697 log_return (set_not_found, "set of reg not found. empty BB?\n");
698
699 new_entry.cstore_type = cstore_unknown;
700
701 for (rtx_insn *i = start_insn; i != NULL; )
702 {
703 new_entry.cstore = find_set_of_reg_bb (reg, i);
704
705 if (new_entry.cstore.set_src () == NULL_RTX)
706 log_return (set_not_found, "set of reg not found (cstore)\n");
707
708 log_insn (new_entry.cstore.insn);
709 log_msg ("\n");
710
711 if (is_normal_ccreg (new_entry.cstore.set_src ()))
712 {
713 log_msg ("normal condition store\n");
714 new_entry.cstore_type = cstore_normal;
715 }
716 else if (is_inverted_ccreg (new_entry.cstore.set_src ()))
717 {
718 log_msg ("inverted condition store\n");
719 new_entry.cstore_type = cstore_inverted;
720 }
721 else if (REG_P (new_entry.cstore.set_src ()))
722 {
723 // If it's a reg-reg copy follow the copied reg.
724 new_entry.cstore_reg_reg_copies.push_back (new_entry.cstore);
725 reg = new_entry.cstore.set_src ();
726 i = new_entry.cstore.insn;
727
728 log_msg ("reg-reg copy. tracing ");
729 log_rtx (reg);
730 log_msg ("\n");
731 continue;
732 }
733 else
734 log_return (other_set_found, "not a condition store\n");
735
736 gcc_assert (new_entry.cstore_type != cstore_unknown);
737
738 // Now see how the ccreg was set.
739 // For now it must be in the same BB.
740 log_msg ("tracing ccreg\n");
741 new_entry.setcc =
742 find_set_of_reg_bb (m_ccreg,
743 prev_nonnote_insn_bb (new_entry.cstore.insn));
744
745 // If cstore was found but setcc was not found continue anyway, as
746 // for some of the optimization types the setcc is irrelevant.
747 if (new_entry.setcc.set_src () == NULL_RTX)
748 log_return (set_found, "set of ccreg not found\n");
749
750 else if (GET_CODE (new_entry.setcc.set_rtx) == SET)
751 {
752 // Also allow insns that set the ccreg, but are not true comparison
753 // insns, as long as they are sets and not e.g. clobbers.
754 log_insn (new_entry.setcc.insn);
755 log_msg ("\n");
756 return set_found;
757 }
758 else
759 // If cstore was found but setcc was not found continue anyway, as
760 // for some of the optimization types the setcc is irrelevant.
761 log_return (set_found, "unknown set of ccreg\n");
762 }
763
764 log_return (set_not_found, "set of reg not found\n");
765 }
766
767 bool
768 sh_treg_combine::can_remove_cstore (const bb_entry& e,
769 const cbranch_trace& trace) const
770 {
771 if (volatile_insn_p (PATTERN (e.cstore.insn)))
772 {
773 log_msg ("can't remove insn\n");
774 log_insn (e.cstore.insn);
775 log_return (false, "\nbecause it's volatile\n");
776 }
777
778 // On SH there are parallel patterns which store the ccreg multiple times.
779 // In this case it's not safe.
780 rtx cstore_pat = PATTERN (e.cstore.insn);
781 if (GET_CODE (cstore_pat) == PARALLEL)
782 for (int i = 0; i < XVECLEN (cstore_pat, 0); ++i)
783 {
784 rtx x = XVECEXP (cstore_pat, 0, i);
785
786 // It's the cstore set that we're referring to, ignore that one.
787 if (x != e.cstore.set_rtx
788 && GET_CODE (x) == SET && reg_referenced_p (m_ccreg, x))
789 {
790 log_msg ("can't remove insn\n");
791 log_insn (e.cstore.insn);
792 log_return (false, "\nbecause it's a multiple ccreg store\n");
793 }
794 }
795
796 // If the cstore sets the ccreg (e.g. negc) and the ccreg is used afterwards
797 // it's not safe.
798 if (modified_in_p (m_ccreg, e.cstore.insn)
799 && !(reg_dead_after_insn (m_ccreg, e.cstore.insn)
800 || reg_unused_after_insn (m_ccreg, e.cstore.insn)))
801 {
802 log_msg ("can't remove insn\n");
803 log_insn (e.cstore.insn);
804 log_return (false, "\nbecause it sets the ccreg\n");
805 }
806
807 // If the cstore destination reg is copied around check the reg-reg
808 // copies. At every reg-reg copy the copied reg must be dead and there
809 // must not be a usage of the copied regs between the reg-reg copies.
810 // Otherwise we assume that the result of the cstore is used in some
811 // other way.
812 rtx_insn *prev_insn = e.cstore.insn;
813 for (std::vector<set_of_reg>::const_reverse_iterator i =
814 e.cstore_reg_reg_copies.rbegin ();
815 i != e.cstore_reg_reg_copies.rend (); ++i)
816 {
817 if (!reg_dead_after_insn (i->set_src (), i->insn))
818 {
819 log_msg ("can't remove insn\n");
820 log_insn (i->insn);
821 log_return (false, "\nbecause source of reg-reg copy doesn't die\n");
822 }
823
824 if (reg_used_between_p (i->set_src (), prev_insn, i->insn))
825 {
826 log_msg ("can't remove insn\n");
827 log_insn (i->insn);
828 log_return (false, "\nbecause reg %d is otherwise used\n",
829 REGNO (i->set_src ()));
830 }
831
832 prev_insn = i->insn;
833 }
834
835 // The cstore_dst reg must die after the test before the cbranch, otherwise
836 // it's not safe to remove the cstore.
837 // If the cstore destination reg is copied around check the effective
838 // destination reg of the cstore. The reg-reg copies are recorded in
839 // reverse order, i.e. the most recent reg-reg copy in the insn list
840 // comes first.
841 rtx cstore_dst = e.cstore_reg_reg_copies.empty ()
842 ? e.cstore.set_dst ()
843 : e.cstore_reg_reg_copies.front ().set_dst ();
844
845 if (!reg_dead_after_insn (cstore_dst, trace.setcc.insn))
846 {
847 log_msg ("can't remove insn\n");
848 log_insn (e.cstore.insn);
849 log_return (false, "\nbecause its effective target reg %d doesn't die "
850 "after trace.setcc.insn\n", REGNO (cstore_dst));
851 }
852
853 // Also check that the cstore_dst reg is not used in other reachable code
854 // paths before it dies.
855 // Count the uses of the effective cstore_dst reg (i.e. the last known reg
856 // that holds the cstore value after reg-reg copies) in all BBs that can be
857 // reached from bb_entry's BB including the BB of the cstore insn.
858 // If we get more than 1 uses we assume that it's used somewhere else and is
859 // not safe to be removed.
860 int cstore_dst_use_count = trace_reg_uses (cstore_dst, e.cstore.insn,
861 trace.setcc.insn);
862 if (cstore_dst_use_count > 1)
863 {
864 log_msg ("can't remove insn\n");
865 log_insn (e.cstore.insn);
866 log_return (false, "\nbecause its effective target reg %d is used "
867 "in %d other places\n", REGNO (cstore_dst),
868 cstore_dst_use_count - 1);
869 }
870
871 return true;
872 }
873
874 bool
875 sh_treg_combine::can_remove_comparison (const bb_entry& e,
876 const cbranch_trace&/* trace*/) const
877 {
878 // If the ccreg is used otherwise between the comparison and the cstore,
879 // it's not safe.
880 if (reg_used_between_p (m_ccreg, e.setcc.insn, e.cstore.insn))
881 {
882 log_msg ("can't remove insn\n");
883 log_insn (e.setcc.insn);
884 log_return (false, "\nbecause the ccreg is used otherwise\n");
885 }
886
887 if (!reg_dead_after_insn (m_ccreg, e.cstore.insn)
888 && !reg_unused_after_insn (m_ccreg, e.cstore.insn))
889 {
890 log_msg ("can't remove insn\n");
891 log_insn (e.cstore.insn);
892 log_return (false, "\nbecause ccreg is not dead or unused afterwards\n");
893 }
894
895 // On SH there are also multiple set patterns that can be used for
896 // comparisons, such as "shll". It's not safe to remove those.
897 if (multiple_sets (e.setcc.insn))
898 {
899 log_msg ("can't remove insn\n");
900 log_insn (e.cstore.insn);
901 log_return (false, "\nbecause it's a multiple set\n");
902 }
903
904 return true;
905 }
906
907 rtx
908 sh_treg_combine::make_not_reg_insn (rtx dst_reg, rtx src_reg) const
909 {
910 // This will to go through expanders and may output multiple insns
911 // for multi-word regs.
912 start_sequence ();
913 expand_simple_unop (GET_MODE (dst_reg), NOT, src_reg, dst_reg, 0);
914 rtx i = get_insns ();
915 end_sequence ();
916 return i;
917 }
918
919 rtx_insn *
920 sh_treg_combine::make_inv_ccreg_insn (void) const
921 {
922 start_sequence ();
923 rtx_insn *i = emit_insn (gen_rtx_SET (VOIDmode, m_ccreg,
924 gen_rtx_fmt_ee (XOR, GET_MODE (m_ccreg),
925 m_ccreg, const1_rtx)));
926 end_sequence ();
927 return i;
928 }
929
930 rtx
931 sh_treg_combine::touched_insn (rtx i)
932 {
933 m_touched_insns.push_back (i);
934 return i;
935 }
936
937 bool
938 sh_treg_combine::can_combine_comparisons (const_rtx x, const_rtx y) const
939 {
940 if (GET_CODE (x) != GET_CODE (y))
941 return false;
942
943 rtx x_op0 = XEXP (x, 0);
944 rtx x_op1 = XEXP (x, 1);
945
946 rtx y_op0 = XEXP (y, 0);
947 rtx y_op1 = XEXP (y, 1);
948
949 if (!REG_P (x_op0) || !REG_P (y_op0))
950 return false;
951
952 if (GET_MODE (x_op0) != GET_MODE (y_op0))
953 return false;
954
955 // rtx_equal_p also compares the reg numbers which we do not care about
956 // here, as long as both are regs and the modes are the same.
957 if (REG_P (x_op1))
958 return REG_P (y_op1) && GET_MODE (x_op1) == GET_MODE (y_op1);
959
960 return rtx_equal_p (x_op1, y_op1);
961 }
962
963 bool
964 sh_treg_combine::can_extend_ccreg_usage (const bb_entry& e,
965 const cbranch_trace& trace) const
966 {
967 // Check if the ccreg is not modified by other insins in the BB path until
968 // the final cbranch of the trace.
969 // Start checking after the cstore that follows the setcc, assuming that
970 // the cstore will be removed.
971
972 // The assumption here is that the specified bb_entry's BB is a direct
973 // predecessor of the trace.cbranch_insn's BB.
974 if (e.bb != trace.bb () && !is_adjacent_bb (e.bb, trace.bb ()))
975 log_return (false,
976 "can't extend ccreg usage -- [bb %d] and [bb %d] are not adjacent\n",
977 e.bb->index, trace.bb ()->index);
978
979 if (e.cstore.empty ())
980 log_return (false, "can't extend ccreg usage -- no cstore\n");
981
982 // The entry's cstore is in the same BB as the final cbranch.
983 if (e.bb == trace.bb ())
984 {
985 if (reg_set_between_p (m_ccreg, e.cstore.insn, trace.setcc.insn))
986 log_return (false,
987 "can't extend ccreg usage -- it's modified between e.cstore.insn "
988 "and trace.setcc.insn");
989 else
990 return true;
991 }
992
993 // The entry's cstore and the final cbranch are in different BBs.
994 if (reg_set_between_p (m_ccreg, e.cstore.insn, NEXT_INSN (BB_END (e.bb))))
995 log_return (false,
996 "can't extend ccreg usage -- it's modified in [bb %d]", e.bb->index);
997
998 if (reg_set_between_p (m_ccreg, PREV_INSN (BB_HEAD (trace.bb ())),
999 trace.setcc.insn))
1000 log_return (false,
1001 "can't extend ccreg usage -- it's modified in [bb %d]",
1002 trace.bb ()->index);
1003
1004 return true;
1005 }
1006
1007 bool
1008 sh_treg_combine::try_invert_branch_condition (cbranch_trace& trace)
1009 {
1010 log_msg ("inverting branch condition\n");
1011
1012 if (!invert_jump_1 (trace.cbranch_insn, JUMP_LABEL (trace.cbranch_insn)))
1013 log_return (false, "invert_jump_1 failed\n");
1014
1015 if (verify_changes (num_validated_changes ()))
1016 confirm_change_group ();
1017 else
1018 log_return (false, "verify_changed failed\n");
1019
1020 touched_insn (trace.cbranch_insn);
1021 return true;
1022 }
1023
1024 bool
1025 sh_treg_combine::try_combine_comparisons (cbranch_trace& trace,
1026 int cstore_count,
1027 int inv_cstore_count,
1028 cstore_type_t dominating_cstore)
1029 {
1030 log_msg ("\ntry_combine_comparisons\n");
1031
1032 // This function will always try to create new pseudos.
1033 if (!can_create_pseudo_p ())
1034 log_return (false, "can't create pseudos\n");
1035
1036 // Check that all ccset insns are comparisons and all comparison types in
1037 // all BBs are the same and could be combined into one single comparison.
1038 rtx comp = NULL_RTX;
1039 rtx comp_insn = NULL_RTX;
1040
1041 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1042 i != trace.bb_entries.end (); ++i)
1043 {
1044 int i_empty_count = i->setcc.empty () + i->cstore.empty ();
1045
1046 // A completly empty entry is OK (could be the BB of the cbranch).
1047 if (i_empty_count == 2)
1048 continue;
1049
1050 // Otherwise we need both, the setcc and the cstore.
1051 if (i_empty_count != 0)
1052 log_return (false, "bb entry is not a setcc cstore pair\n");
1053
1054 rtx other_comp = i->comparison_rtx ();
1055
1056 if (!COMPARISON_P (other_comp))
1057 {
1058 log_msg ("setcc is not a comparison:\n");
1059 log_rtx (other_comp);
1060 log_return (false, "\n");
1061 }
1062
1063 if (comp_insn == NULL_RTX)
1064 {
1065 comp = other_comp;
1066 comp_insn = i->setcc.insn;
1067 }
1068 else if (!can_combine_comparisons (comp, other_comp))
1069 return false;
1070
1071 // The goal here is to eliminate all cstores and comparisons in the BBs.
1072 // Thus check if every cstore can actually be removed safely.
1073 if (!can_remove_cstore (*i, trace) || !can_remove_comparison (*i, trace))
1074 return false;
1075 }
1076
1077 // FIXME: The first operand of the comparison must be a simple reg.
1078 // This effectively prohibits combining div0s comparisons such as
1079 // (lt:SI (xor:SI (reg:SI) (reg:SI)))
1080 if (!REG_P (XEXP (comp, 0)))
1081 {
1082 log_msg ("comparison operand 0\n");
1083 log_rtx (XEXP (comp, 0));
1084 log_return (false, "\nis not a reg\n");
1085 }
1086
1087 rtx comp_op0 = gen_reg_rtx (GET_MODE (XEXP (comp, 0)));
1088 rtx comp_op1 = REG_P (XEXP (comp, 1))
1089 ? gen_reg_rtx (GET_MODE (XEXP (comp, 1)))
1090 : XEXP (comp, 1);
1091
1092 // If there are both, inverting and non-inverting cstores, they can only
1093 // be eliminated if the comparison can be inverted. We assume that the
1094 // comparison insns that we find are already minimal and canonicalized.
1095 // There is one special case though, where an integer comparison
1096 // (eq (reg) (const_int 0))
1097 // can be inverted with a sequence
1098 // (eq (not (reg)) (const_int 0))
1099 if (inv_cstore_count != 0 && cstore_count != 0)
1100 {
1101 if (make_not_reg_insn (comp_op0, comp_op0) == NULL_RTX)
1102 log_return (false, "make_not_reg_insn failed.\n");
1103
1104 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1105 i != trace.bb_entries.end (); ++i)
1106 {
1107 if (i->setcc.empty () || i->cstore.empty ())
1108 continue;
1109
1110 if (i->cstore_type != dominating_cstore
1111 && !is_cmp_eq_zero (i->comparison_rtx ()))
1112 {
1113 log_msg ("can't invert comparison in insn\n");
1114 log_insn (i->setcc.insn);
1115 log_return (false,
1116 "\nbecause it's not a (eq (reg) (const_int 0))\n");
1117 }
1118 }
1119 }
1120
1121 if (dominating_cstore == cstore_normal
1122 && !try_invert_branch_condition (trace))
1123 return false;
1124
1125 // Replace the test insn before the cbranch with the common comparison.
1126 // Instead of creating a new insn from scratch we copy the common comparison
1127 // pattern. This simplifies handling parallel comparison patterns, such as
1128 // FP comparisons on SH, which have an extra use on FPSCR.
1129 log_msg ("installing common comparison in [bb %d]\n", trace.bb ()->index);
1130
1131 rtx common_comp_pat = copy_rtx (PATTERN (comp_insn));
1132 rtx common_comp = const_cast<rtx> (set_of (m_ccreg, common_comp_pat));
1133
1134 gcc_assert (common_comp != NULL_RTX);
1135
1136 XEXP (XEXP (common_comp, 1), 0) = comp_op0;
1137 XEXP (XEXP (common_comp, 1), 1) = comp_op1;
1138
1139 log_rtx (common_comp_pat);
1140 log_msg ("\n");
1141
1142 rtx common_comp_insn = touched_insn (emit_insn_after (common_comp_pat,
1143 trace.setcc.insn));
1144
1145 if (REG_P (comp_op0))
1146 add_reg_note (common_comp_insn, REG_DEAD, copy_rtx (comp_op0));
1147 if (REG_P (comp_op1))
1148 add_reg_note (common_comp_insn, REG_DEAD, copy_rtx (comp_op1));
1149
1150 delete_insn (trace.setcc.insn);
1151
1152 // Replace comparison and cstore insns with reg-reg moves in all BBs.
1153 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1154 i != trace.bb_entries.end (); ++i)
1155 {
1156 if (i->setcc.empty () || i->cstore.empty ())
1157 continue;
1158
1159 rtx i_comp_op0 = XEXP (i->comparison_rtx (), 0);
1160 rtx i_comp_op1 = XEXP (i->comparison_rtx (), 1);
1161
1162 if (i->cstore_type == dominating_cstore)
1163 {
1164 log_msg ("replacing comparison and cstore with reg move "
1165 "in [bb %d]\n", i->bb->index);
1166
1167 rtx new_i = touched_insn (
1168 emit_insn_after (gen_move_insn (comp_op0, i_comp_op0),
1169 i->setcc.insn));
1170
1171 if (REG_P (i_comp_op0)
1172 && reg_dead_after_insn (i_comp_op0, i->setcc.insn))
1173 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op0));
1174
1175 // If the second operand is a reg, have to emit a move insn.
1176 // Otherwise assume it's a const_int and just reference it.
1177 if (REG_P (comp_op1))
1178 {
1179 new_i = touched_insn (
1180 emit_insn_after (gen_move_insn (comp_op1, i_comp_op1),
1181 i->setcc.insn));
1182
1183 if (reg_dead_after_insn (i_comp_op1, i->setcc.insn))
1184 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op1));
1185 }
1186 }
1187 else
1188 {
1189 log_msg ("replacing comparison and cstore with inverting reg move "
1190 "in [bb %d]\n", i->bb->index);
1191
1192 rtx new_i = make_not_reg_insn (comp_op0, i_comp_op0);
1193 if (REG_P (i_comp_op0)
1194 && reg_dead_after_insn (i_comp_op0, i->setcc.insn))
1195 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op0));
1196
1197 touched_insn (emit_insn_after (new_i, i->setcc.insn));
1198 }
1199
1200 delete_insn (i->cstore.insn);
1201 delete_insn (i->setcc.insn);
1202 }
1203
1204 return true;
1205 }
1206
1207 bool
1208 sh_treg_combine::try_eliminate_cstores (cbranch_trace& trace,
1209 int cstore_count, int inv_cstore_count,
1210 cstore_type_t dominating_cstore)
1211 {
1212 log_msg ("\ntry_eliminate_cstores\n");
1213
1214 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1215 i != trace.bb_entries.end (); ++i)
1216 {
1217 // A completly empty entry is OK (could be the BB of the cbranch).
1218 if (i->setcc.empty () && i->cstore.empty ())
1219 continue;
1220
1221 // We're going to eliminate cstores, but for that they have to be
1222 // there. We don't care about the setcc in this case.
1223 if (i->cstore.empty ())
1224 log_return (false, "bb entry cstore empty -- aborting\n");
1225
1226 // The goal here is to eliminate all cstores in the BBs and extend the
1227 // ccreg usage.
1228 if (!can_extend_ccreg_usage (*i, trace))
1229 return false;
1230
1231 // If the cstore can't be removed we can keep it around as long as
1232 // it doesn't modify the ccreg.
1233 if (!can_remove_cstore (*i, trace)
1234 && modified_in_p (m_ccreg, i->cstore.insn))
1235 log_return (false, "cstore sets ccreg -- aborting\n");
1236 }
1237
1238 // If there are both, inverting and non-inverting cstores, we'll have to
1239 // invert the ccreg as a replacement for one of them.
1240 if (cstore_count != 0 && inv_cstore_count != 0)
1241 {
1242 rtx_insn *i = make_inv_ccreg_insn ();
1243 if (recog_memoized (i) < 0)
1244 {
1245 log_msg ("failed to match ccreg inversion insn:\n");
1246 log_rtx (PATTERN (i));
1247 log_return (false, "\naborting\n");
1248 }
1249 }
1250
1251 if (dominating_cstore == cstore_normal
1252 && !try_invert_branch_condition (trace))
1253 return false;
1254
1255 // Eliminate cstores in all BBs.
1256 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1257 i != trace.bb_entries.end (); ++i)
1258 {
1259 if (i->cstore.empty ())
1260 continue;
1261
1262 if (i->cstore_type == dominating_cstore)
1263 log_msg ("removing cstore in [bb %d]\n", i->bb->index);
1264 else
1265 {
1266 log_msg ("replacing cstore with ccreg inversion in [bb %d]\n",
1267 i->bb->index);
1268
1269 touched_insn (
1270 emit_insn_after (make_inv_ccreg_insn (), i->cstore.insn));
1271 }
1272
1273 if (can_remove_cstore (*i, trace))
1274 delete_insn (i->cstore.insn);
1275 }
1276
1277 log_msg ("removing test insn before cbranch\n");
1278 delete_insn (trace.setcc.insn);
1279 return true;
1280 }
1281
1282 void
1283 sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
1284 {
1285 cbranch_trace trace (insn);
1286
1287 log_msg ("\n\n--------------------------------------\n");
1288 log_msg ("found cbranch insn in [bb %d]:\n", trace.bb ()->index);
1289 log_insn (insn);
1290
1291 trace.cbranch_type = branch_condition_type (trace.branch_condition_rtx ());
1292
1293 if (trace.cbranch_type == branch_if_true)
1294 log_msg ("condition: branch if true\n");
1295 else if (trace.cbranch_type == branch_if_false)
1296 log_msg ("condition: branch if false\n");
1297 else
1298 {
1299 log_msg ("unknown branch condition\n");
1300 log_rtx (trace.branch_condition_rtx ());
1301 log_return_void ("\n");
1302 }
1303
1304 update_ccreg_mode (trace.branch_condition_rtx ());
1305
1306 // Scan the insns backwards for an insn that sets the ccreg by testing a
1307 // reg against zero like
1308 // (set (reg ccreg) (eq (reg) (const_int 0)))
1309 // The testing insn could also be outside of the current basic block, but
1310 // for now we limit the search to the current basic block.
1311 trace.setcc = find_set_of_reg_bb (m_ccreg, prev_nonnote_insn_bb (insn));
1312
1313 if (!is_cmp_eq_zero (trace.setcc.set_src ()))
1314 log_return_void ("could not find set of ccreg in current BB\n");
1315
1316 rtx trace_reg = XEXP (trace.setcc.set_src (), 0);
1317
1318 log_msg ("set of ccreg:\n");
1319 log_insn (trace.setcc.insn);
1320
1321 // See if we can remove the trace.setcc insn safely.
1322 if (reg_used_between_p (m_ccreg, trace.setcc.insn, trace.cbranch_insn))
1323 log_return_void ("ccreg used between testing insn and branch insn\n");
1324
1325 if (volatile_insn_p (PATTERN (trace.setcc.insn)))
1326 {
1327 log_msg ("can't remove insn\n");
1328 log_insn (trace.setcc.insn);
1329 log_return_void ("\nbecause it's volatile\n");
1330 }
1331
1332 // Now that we have an insn which tests some reg and sets the condition
1333 // reg before the conditional branch, try to figure out how that tested
1334 // reg was formed, i.e. find all the insns that set the tested reg in
1335 // some way.
1336 // The tested reg might be set in multiple basic blocks so we need to
1337 // check all basic blocks which can reach this current basic block.
1338 // If the set of reg is an inverting or non-inverting store of the condition
1339 // register, check how the ccreg value was obtained.
1340 log_msg ("\ntracing ");
1341 log_rtx (trace_reg);
1342 log_msg ("\n");
1343
1344
1345 // First check the basic block where the conditional branch is in.
1346 // If we find it here there's no point in checking other BBs.
1347 trace.bb_entries.push_front (bb_entry (trace.bb ()));
1348
1349 record_return_t res =
1350 record_set_of_reg (trace_reg, prev_nonnote_insn_bb (trace.setcc.insn),
1351 trace.bb_entries.front ());
1352
1353 if (res == other_set_found)
1354 log_return_void ("other set found - aborting trace\n");
1355 else if (res == set_not_found)
1356 {
1357 // It seems the initial search in the BB of the conditional branch
1358 // didn't find anything. Now look in all predecessor BBs.
1359 for (edge_iterator ei = ei_start (trace.bb ()->preds);
1360 !ei_end_p (ei); ei_next (&ei))
1361 {
1362 edge e = ei_edge (ei);
1363 trace.bb_entries.push_front (bb_entry (e->src));
1364
1365 res = record_set_of_reg (trace_reg, BB_END (e->src),
1366 trace.bb_entries.front ());
1367 if (res != set_found)
1368 log_return_void ("set not found - aborting trace\n");
1369 }
1370 }
1371
1372 if (dump_file != NULL)
1373 {
1374 log_msg ("\ncbranch trace summary:\n");
1375 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1376 i != trace.bb_entries.end (); ++i)
1377 {
1378 log_msg ("\n[bb %d]\n", i->bb->index);
1379 if (!i->setcc.empty ())
1380 {
1381 log_rtx (i->setcc.set_rtx);
1382 log_msg ("\n");
1383 }
1384 if (!i->cstore.empty ())
1385 {
1386 log_rtx (i->cstore.set_rtx);
1387 log_msg ("\n");
1388 }
1389
1390 for (std::vector<set_of_reg>::const_reverse_iterator j =
1391 i->cstore_reg_reg_copies.rbegin ();
1392 j != i->cstore_reg_reg_copies.rend (); ++j)
1393 {
1394 log_rtx (j->set_rtx);
1395 log_msg ("\n");
1396 }
1397 }
1398
1399 log_rtx (trace.setcc.set_rtx);
1400 log_msg ("\n");
1401 log_rtx (PATTERN (trace.cbranch_insn));
1402 log_msg ("\n");
1403 }
1404
1405 // Check that we don't have any empty BBs.
1406 // Only the BB with the cbranch may be empty.
1407 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1408 i != trace.bb_entries.end (); ++i)
1409 if (i->setcc.empty () && i->cstore.empty () && i->bb != trace.bb ())
1410 log_return_void ("\n[bb %d] is empty - aborting.\n", i->bb->index);
1411
1412 // Determine the dominating cstore type
1413 // FIXME: Try to take the probabilities of the BBs into account somehow.
1414 int cstore_count = 0;
1415 int inv_cstore_count = 0;
1416
1417 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
1418 i != trace.bb_entries.end (); ++i)
1419 {
1420 if (i->cstore_type == cstore_normal)
1421 cstore_count += 1;
1422 else if (i->cstore_type == cstore_inverted)
1423 inv_cstore_count += 1;
1424 }
1425
1426 log_msg ("cstore count = %d inverted cstore count = %d\n",
1427 cstore_count, inv_cstore_count);
1428
1429 // This puts a priority on inverting cstores.
1430 cstore_type_t dominating_cstore = inv_cstore_count >= cstore_count
1431 ? cstore_inverted
1432 : cstore_normal;
1433
1434 if (dominating_cstore == cstore_inverted)
1435 log_msg ("will try to eliminate inverted cstore\n");
1436 else if (dominating_cstore == cstore_normal)
1437 {
1438 log_msg ("will try to eliminate normal cstore\n");
1439 if (!trace.can_invert_condition ())
1440 log_return_void ("branch condition can't be inverted - aborting\n");
1441 }
1442 else
1443 gcc_unreachable ();
1444
1445 if (try_combine_comparisons (trace, cstore_count, inv_cstore_count,
1446 dominating_cstore))
1447 return;
1448
1449 try_eliminate_cstores (trace, cstore_count, inv_cstore_count,
1450 dominating_cstore);
1451 }
1452
1453 bool
1454 sh_treg_combine::gate (function *)
1455 {
1456 return optimize > 0;
1457 }
1458
1459 unsigned int
1460 sh_treg_combine::execute (function *fun)
1461 {
1462 unsigned int ccr0 = INVALID_REGNUM;
1463 unsigned int ccr1 = INVALID_REGNUM;
1464
1465 if (targetm.fixed_condition_code_regs (&ccr0, &ccr1)
1466 && ccr0 != INVALID_REGNUM)
1467 {
1468 // Initially create a reg rtx with VOIDmode.
1469 // When the first conditional branch is discovered, the mode is changed
1470 // to the mode that is actually used by the target.
1471 m_ccreg = gen_rtx_REG (VOIDmode, ccr0);
1472 }
1473
1474 if (m_ccreg == NULL_RTX)
1475 log_return (0, "no ccreg.\n\n");
1476
1477 if (STORE_FLAG_VALUE != 1)
1478 log_return (0, "unsupported STORE_FLAG_VALUE %d", STORE_FLAG_VALUE);
1479
1480 log_msg ("ccreg: ");
1481 log_rtx (m_ccreg);
1482 log_msg (" STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE);
1483
1484 // Look for basic blocks that end with a conditional branch and try to
1485 // optimize them.
1486 basic_block bb;
1487 FOR_EACH_BB_FN (bb, fun)
1488 {
1489 rtx_insn *i = BB_END (bb);
1490 if (any_condjump_p (i) && onlyjump_p (i))
1491 try_optimize_cbranch (i);
1492 }
1493
1494 log_msg ("\n\n");
1495
1496 // If new insns are created and this pass is executed after all insns
1497 // have been split already, we must split the insns we've changed or added
1498 // ourselves here.
1499 // FIXME: Multi-word operations (which emit multiple insns) are not handled
1500 // properly here, since only one insn will end up in 'm_touched_insns'.
1501 // On SH this is not a problem though.
1502 if (m_split_insns)
1503 for (std::vector<rtx>::const_iterator i = m_touched_insns.begin ();
1504 i != m_touched_insns.end (); ++i)
1505 {
1506 log_msg ("trying to split insn:\n");
1507 log_insn (*i);
1508 log_msg ("\n");
1509 try_split (PATTERN (*i), *i, 0);
1510 }
1511
1512 m_touched_insns.clear ();
1513 log_return (0, "\n\n");
1514 }
1515
1516 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1517 // This allows instantiating the pass somewhere else without having to pull
1518 // in a header file.
1519 opt_pass*
1520 make_pass_sh_treg_combine (gcc::context* ctx, bool split_insns,
1521 const char* name)
1522 {
1523 return new sh_treg_combine (ctx, split_insns, name);
1524 }