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