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