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