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