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