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