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