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