]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/compare-elim.c
2014-10-27 Andrew MacLeod <amacleod@redhat.com>
[thirdparty/gcc.git] / gcc / compare-elim.c
CommitLineData
a50372fe 1/* Post-reload compare elimination.
3aea1f79 2 Copyright (C) 2010-2014 Free Software Foundation, Inc.
a50372fe 3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20/* There is a set of targets whose general-purpose move or addition
21 instructions clobber the flags. These targets cannot split their
22 CBRANCH/CSTORE etc patterns before reload is complete, lest reload
23 itself insert these instructions in between the flags setter and user.
24 Because these targets cannot split the compare from the use, they
25 cannot make use of the comparison elimination offered by the combine pass.
26
27 This is a small pass intended to provide comparison elimination similar to
28 what is available via NOTICE_UPDATE_CC for cc0 targets. This should help
29 encourage cc0 targets to convert to an explicit post-reload representation
30 of the flags.
31
32 This pass assumes:
33
34 (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
35
36 (1) All comparison patterns are represented as
37
38 [(set (reg:CC) (compare:CC (reg) (immediate)))]
39
40 (2) All insn patterns that modify the flags are represented as
41
42 [(set (reg) (operation)
43 (clobber (reg:CC))]
44
45 (3) If an insn of form (2) can usefully set the flags, there is
46 another pattern of the form
47
48 [(set (reg) (operation)
49 (set (reg:CCM) (compare:CCM (operation) (immediate)))]
50
51 The mode CCM will be chosen as if by SELECT_CC_MODE.
52
53 Note that unlike NOTICE_UPDATE_CC, we do not handle memory operands.
54 This could be handled as a future enhancement.
55*/
56
57#include "config.h"
58#include "system.h"
59#include "coretypes.h"
60#include "tm.h"
61#include "rtl.h"
62#include "tm_p.h"
63#include "insn-config.h"
64#include "recog.h"
65#include "flags.h"
94ea8568 66#include "predict.h"
67#include "vec.h"
68#include "hashtab.h"
69#include "hash-set.h"
70#include "machmode.h"
71#include "hard-reg-set.h"
72#include "input.h"
73#include "function.h"
74#include "dominance.h"
75#include "cfg.h"
76#include "cfgrtl.h"
a50372fe 77#include "basic-block.h"
78#include "tree-pass.h"
79#include "target.h"
80#include "df.h"
81#include "domwalk.h"
82
83\f
84/* These structures describe a comparison and how it is used. */
85
86/* The choice of maximum 3 uses comes from wanting to eliminate the two
87 duplicate compares from a three-way branch on the sign of a value.
88 This is also sufficient to eliminate the duplicate compare against the
89 high-part of a double-word comparison. */
90#define MAX_CMP_USE 3
91
92struct comparison_use
93{
94 /* The instruction in which the result of the compare is used. */
16a15f57 95 rtx_insn *insn;
a50372fe 96 /* The location of the flags register within the use. */
97 rtx *loc;
98 /* The comparison code applied against the flags register. */
99 enum rtx_code code;
100};
101
102struct comparison
103{
104 /* The comparison instruction. */
16a15f57 105 rtx_insn *insn;
a50372fe 106
107 /* The insn prior to the comparison insn that clobbers the flags. */
16a15f57 108 rtx_insn *prev_clobber;
a50372fe 109
110 /* The two values being compared. These will be either REGs or
111 constants. */
112 rtx in_a, in_b;
113
55ed9dcf 114 /* The REG_EH_REGION of the comparison. */
115 rtx eh_note;
116
a50372fe 117 /* Information about how this comparison is used. */
118 struct comparison_use uses[MAX_CMP_USE];
119
120 /* The original CC_MODE for this comparison. */
121 enum machine_mode orig_mode;
122
123 /* The number of uses identified for this comparison. */
124 unsigned short n_uses;
125
126 /* True if not all uses of this comparison have been identified.
127 This can happen either for overflowing the array above, or if
128 the flags register is used in some unusual context. */
129 bool missing_uses;
130
131 /* True if its inputs are still valid at the end of the block. */
132 bool inputs_valid;
133};
134
135typedef struct comparison *comparison_struct_p;
a50372fe 136
f1f41a6c 137static vec<comparison_struct_p> all_compares;
a50372fe 138
139/* Look for a "conforming" comparison, as defined above. If valid, return
140 the rtx for the COMPARE itself. */
141
142static rtx
16a15f57 143conforming_compare (rtx_insn *insn)
a50372fe 144{
145 rtx set, src, dest;
146
147 set = single_set (insn);
148 if (set == NULL)
149 return NULL;
150
151 src = SET_SRC (set);
152 if (GET_CODE (src) != COMPARE)
153 return NULL;
154
155 dest = SET_DEST (set);
156 if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
157 return NULL;
158
159 if (REG_P (XEXP (src, 0))
160 && REG_P (XEXP (src, 0))
161 && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
162 return src;
163
164 return NULL;
165}
166
167/* Look for a pattern of the "correct" form for an insn with a flags clobber
168 for which we may be able to eliminate a compare later. We're not looking
169 to validate any inputs at this time, merely see that the basic shape is
170 correct. The term "arithmetic" may be somewhat misleading... */
171
172static bool
16a15f57 173arithmetic_flags_clobber_p (rtx_insn *insn)
a50372fe 174{
175 rtx pat, x;
176
177 if (!NONJUMP_INSN_P (insn))
178 return false;
179 pat = PATTERN (insn);
180 if (extract_asm_operands (pat))
181 return false;
182
183 if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
184 {
185 x = XVECEXP (pat, 0, 0);
186 if (GET_CODE (x) != SET)
187 return false;
188 x = SET_DEST (x);
189 if (!REG_P (x))
190 return false;
191
192 x = XVECEXP (pat, 0, 1);
193 if (GET_CODE (x) == CLOBBER)
194 {
195 x = XEXP (x, 0);
196 if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
197 return true;
198 }
199 }
200
201 return false;
202}
203
204/* Look for uses of FLAGS in INSN. If we find one we can analyze, record
205 it in CMP; otherwise indicate that we've missed a use. */
206
207static void
16a15f57 208find_flags_uses_in_insn (struct comparison *cmp, rtx_insn *insn)
a50372fe 209{
be10bb5a 210 df_ref use;
a50372fe 211
212 /* If we've already lost track of uses, don't bother collecting more. */
213 if (cmp->missing_uses)
214 return;
215
216 /* Find a USE of the flags register. */
be10bb5a 217 FOR_EACH_INSN_USE (use, insn)
a50372fe 218 if (DF_REF_REGNO (use) == targetm.flags_regnum)
219 {
220 rtx x, *loc;
221
222 /* If this is an unusual use, quit. */
223 if (DF_REF_TYPE (use) != DF_REF_REG_USE)
224 goto fail;
225
226 /* If we've run out of slots to record uses, quit. */
227 if (cmp->n_uses == MAX_CMP_USE)
228 goto fail;
229
230 /* Unfortunately the location of the flags register, while present
231 in the reference structure, doesn't help. We need to find the
232 comparison code that is outer to the actual flags use. */
233 loc = DF_REF_LOC (use);
234 x = PATTERN (insn);
235 if (GET_CODE (x) == PARALLEL)
236 x = XVECEXP (x, 0, 0);
237 x = SET_SRC (x);
238 if (GET_CODE (x) == IF_THEN_ELSE)
239 x = XEXP (x, 0);
240 if (COMPARISON_P (x)
241 && loc == &XEXP (x, 0)
242 && XEXP (x, 1) == const0_rtx)
243 {
244 /* We've found a use of the flags that we understand. */
245 struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
246 cuse->insn = insn;
247 cuse->loc = loc;
248 cuse->code = GET_CODE (x);
249 }
250 else
251 goto fail;
252 }
253 return;
254
255 fail:
256 /* We failed to recognize this use of the flags register. */
257 cmp->missing_uses = true;
258}
259
54c91640 260class find_comparison_dom_walker : public dom_walker
261{
262public:
263 find_comparison_dom_walker (cdi_direction direction)
9af5ce0c 264 : dom_walker (direction) {}
54c91640 265
266 virtual void before_dom_children (basic_block);
267};
268
a50372fe 269/* Identify comparison instructions within BB. If the flags from the last
270 compare in the BB is live at the end of the block, install the compare
54c91640 271 in BB->AUX. Called via dom_walker.walk (). */
a50372fe 272
54c91640 273void
274find_comparison_dom_walker::before_dom_children (basic_block bb)
a50372fe 275{
276 struct comparison *last_cmp;
16a15f57 277 rtx_insn *insn, *next, *last_clobber;
a50372fe 278 bool last_cmp_valid;
55ed9dcf 279 bool need_purge = false;
a50372fe 280 bitmap killed;
281
282 killed = BITMAP_ALLOC (NULL);
283
284 /* The last comparison that was made. Will be reset to NULL
285 once the flags are clobbered. */
286 last_cmp = NULL;
287
288 /* True iff the last comparison has not been clobbered, nor
289 have its inputs. Used to eliminate duplicate compares. */
290 last_cmp_valid = false;
291
292 /* The last insn that clobbered the flags, if that insn is of
293 a form that may be valid for eliminating a following compare.
294 To be reset to NULL once the flags are set otherwise. */
295 last_clobber = NULL;
296
297 /* Propagate the last live comparison throughout the extended basic block. */
298 if (single_pred_p (bb))
299 {
300 last_cmp = (struct comparison *) single_pred (bb)->aux;
301 if (last_cmp)
302 last_cmp_valid = last_cmp->inputs_valid;
303 }
304
305 for (insn = BB_HEAD (bb); insn; insn = next)
306 {
307 rtx src;
308
16a15f57 309 next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn));
a50372fe 310 if (!NONDEBUG_INSN_P (insn))
311 continue;
312
313 /* Compute the set of registers modified by this instruction. */
314 bitmap_clear (killed);
315 df_simulate_find_defs (insn, killed);
316
317 src = conforming_compare (insn);
318 if (src)
319 {
67755ff0 320 enum machine_mode src_mode = GET_MODE (src);
55ed9dcf 321 rtx eh_note = NULL;
67755ff0 322
55ed9dcf 323 if (flag_non_call_exceptions)
324 eh_note = find_reg_note (insn, REG_EH_REGION, NULL);
ea6ad4ae 325
55ed9dcf 326 if (!last_cmp_valid)
327 goto dont_delete;
ea6ad4ae 328
55ed9dcf 329 /* Take care that it's in the same EH region. */
330 if (flag_non_call_exceptions
331 && !rtx_equal_p (eh_note, last_cmp->eh_note))
332 goto dont_delete;
ea6ad4ae 333
55ed9dcf 334 /* Make sure the compare is redundant with the previous. */
335 if (!rtx_equal_p (last_cmp->in_a, XEXP (src, 0))
336 || !rtx_equal_p (last_cmp->in_b, XEXP (src, 1)))
337 goto dont_delete;
ea6ad4ae 338
55ed9dcf 339 /* New mode must be compatible with the previous compare mode. */
340 {
341 enum machine_mode new_mode
342 = targetm.cc_modes_compatible (last_cmp->orig_mode, src_mode);
343 if (new_mode == VOIDmode)
344 goto dont_delete;
ea6ad4ae 345
55ed9dcf 346 if (new_mode != last_cmp->orig_mode)
347 {
348 rtx x, flags = gen_rtx_REG (src_mode, targetm.flags_regnum);
ea6ad4ae 349
55ed9dcf 350 /* Generate new comparison for substitution. */
351 x = gen_rtx_COMPARE (new_mode, XEXP (src, 0), XEXP (src, 1));
352 x = gen_rtx_SET (VOIDmode, flags, x);
a50372fe 353
55ed9dcf 354 if (!validate_change (last_cmp->insn,
355 &PATTERN (last_cmp->insn), x, false))
356 goto dont_delete;
357
358 last_cmp->orig_mode = new_mode;
359 }
360 }
361
362 /* All tests and substitutions succeeded! */
363 if (eh_note)
364 need_purge = true;
365 delete_insn (insn);
366 continue;
367
368 dont_delete:
ea6ad4ae 369 last_cmp = XCNEW (struct comparison);
a50372fe 370 last_cmp->insn = insn;
371 last_cmp->prev_clobber = last_clobber;
372 last_cmp->in_a = XEXP (src, 0);
373 last_cmp->in_b = XEXP (src, 1);
55ed9dcf 374 last_cmp->eh_note = eh_note;
67755ff0 375 last_cmp->orig_mode = src_mode;
f1f41a6c 376 all_compares.safe_push (last_cmp);
a50372fe 377
378 /* It's unusual, but be prepared for comparison patterns that
379 also clobber an input, or perhaps a scratch. */
380 last_clobber = NULL;
381 last_cmp_valid = true;
382 }
383
384 /* Notice if this instruction kills the flags register. */
385 else if (bitmap_bit_p (killed, targetm.flags_regnum))
386 {
387 /* See if this insn could be the "clobber" that eliminates
388 a future comparison. */
389 last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
390
391 /* In either case, the previous compare is no longer valid. */
392 last_cmp = NULL;
393 last_cmp_valid = false;
394 continue;
395 }
396
397 /* Notice if this instruction uses the flags register. */
398 else if (last_cmp)
399 find_flags_uses_in_insn (last_cmp, insn);
400
401 /* Notice if any of the inputs to the comparison have changed. */
402 if (last_cmp_valid
403 && (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
404 || (REG_P (last_cmp->in_b)
405 && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))))
406 last_cmp_valid = false;
407 }
408
409 BITMAP_FREE (killed);
410
411 /* Remember the live comparison for subsequent members of
412 the extended basic block. */
413 if (last_cmp)
414 {
415 bb->aux = last_cmp;
416 last_cmp->inputs_valid = last_cmp_valid;
417
418 /* Look to see if the flags register is live outgoing here, and
419 incoming to any successor not part of the extended basic block. */
7799dcb4 420 if (bitmap_bit_p (df_get_live_out (bb), targetm.flags_regnum))
a50372fe 421 {
422 edge e;
423 edge_iterator ei;
424
425 FOR_EACH_EDGE (e, ei, bb->succs)
426 {
427 basic_block dest = e->dest;
7799dcb4 428 if (bitmap_bit_p (df_get_live_in (bb),
a50372fe 429 targetm.flags_regnum)
430 && !single_pred_p (dest))
431 {
432 last_cmp->missing_uses = true;
433 break;
434 }
435 }
436 }
437 }
55ed9dcf 438
439 /* If we deleted a compare with a REG_EH_REGION note, we may need to
440 remove EH edges. */
441 if (need_purge)
442 purge_dead_edges (bb);
a50372fe 443}
444
445/* Find all comparisons in the function. */
446
447static void
448find_comparisons (void)
449{
a50372fe 450 calculate_dominance_info (CDI_DOMINATORS);
451
54c91640 452 find_comparison_dom_walker (CDI_DOMINATORS)
453 .walk (cfun->cfg->x_entry_block_ptr);
a50372fe 454
455 clear_aux_for_blocks ();
456 free_dominance_info (CDI_DOMINATORS);
457}
458
459/* Select an alternate CC_MODE for a comparison insn comparing A and B.
460 Note that inputs are almost certainly different than the IN_A and IN_B
461 stored in CMP -- we're called while attempting to eliminate the compare
462 after all. Return the new FLAGS rtx if successful, else return NULL.
463 Note that this function may start a change group. */
464
465static rtx
97c6ec6a 466maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
467 rtx b ATTRIBUTE_UNUSED)
a50372fe 468{
469 enum machine_mode sel_mode;
470 const int n = cmp->n_uses;
471 rtx flags = NULL;
472
473#ifndef SELECT_CC_MODE
474 /* Minimize code differences when this target macro is undefined. */
475 return NULL;
476#define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
477#endif
478
479 /* If we don't have access to all of the uses, we can't validate. */
480 if (cmp->missing_uses || n == 0)
481 return NULL;
482
483 /* Find a new mode that works for all of the uses. Special case the
484 common case of exactly one use. */
485 if (n == 1)
486 {
487 sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
488 if (sel_mode != cmp->orig_mode)
489 {
490 flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
491 validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
492 }
493 }
494 else
495 {
496 int i;
497
498 sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
499 for (i = 1; i < n; ++i)
500 {
501 enum machine_mode new_mode;
502 new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
503 if (new_mode != sel_mode)
504 {
505 sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
506 if (sel_mode == VOIDmode)
507 return NULL;
508 }
509 }
510
511 if (sel_mode != cmp->orig_mode)
512 {
513 flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
514 for (i = 0; i < n; ++i)
515 validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
516 }
517 }
518
519 return flags;
520}
521
522/* Attempt to replace a comparison with a prior arithmetic insn that can
523 compute the same flags value as the comparison itself. Return true if
524 successful, having made all rtl modifications necessary. */
525
526static bool
527try_eliminate_compare (struct comparison *cmp)
528{
16a15f57 529 rtx_insn *insn, *bb_head;
530 rtx x, flags, in_a, cmp_src;
a50372fe 531
9d75589a 532 /* We must have found an interesting "clobber" preceding the compare. */
a50372fe 533 if (cmp->prev_clobber == NULL)
534 return false;
535
536 /* ??? For the moment we don't handle comparisons for which IN_B
537 is a register. We accepted these during initial comparison
538 recognition in order to eliminate duplicate compares.
539 An improvement here would be to handle x = a - b; if (a cmp b). */
540 if (!CONSTANT_P (cmp->in_b))
541 return false;
542
543 /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
544 Given that this target requires this pass, we can assume that most
545 insns do clobber the flags, and so the distance between the compare
546 and the clobber is likely to be small. */
547 /* ??? This is one point at which one could argue that DF_REF_CHAIN would
548 be useful, but it is thought to be too heavy-weight a solution here. */
549
550 in_a = cmp->in_a;
551 insn = cmp->insn;
552 bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
553 for (insn = PREV_INSN (insn);
554 insn != cmp->prev_clobber;
555 insn = PREV_INSN (insn))
556 {
557 const int abnormal_flags
558 = (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
559 | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
560 | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
561 | DF_REF_PRE_POST_MODIFY);
be10bb5a 562 df_ref def;
a50372fe 563
564 /* Note that the BB_HEAD is always either a note or a label, but in
565 any case it means that IN_A is defined outside the block. */
566 if (insn == bb_head)
567 return false;
568 if (NOTE_P (insn) || DEBUG_INSN_P (insn))
569 continue;
570
571 /* Find a possible def of IN_A in INSN. */
be10bb5a 572 FOR_EACH_INSN_DEF (def, insn)
a50372fe 573 if (DF_REF_REGNO (def) == REGNO (in_a))
574 break;
575
576 /* No definitions of IN_A; continue searching. */
577 if (def == NULL)
578 continue;
579
580 /* Bail if this is not a totally normal set of IN_A. */
581 if (DF_REF_IS_ARTIFICIAL (def))
582 return false;
583 if (DF_REF_FLAGS (def) & abnormal_flags)
584 return false;
585
586 /* We've found an insn between the compare and the clobber that sets
587 IN_A. Given that pass_cprop_hardreg has not yet run, we still find
588 situations in which we can usefully look through a copy insn. */
589 x = single_set (insn);
590 if (x == NULL)
591 return false;
592 in_a = SET_SRC (x);
593 if (!REG_P (in_a))
594 return false;
595 }
596
597 /* We've reached PREV_CLOBBER without finding a modification of IN_A.
598 Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
599 recall that we've already validated the shape of PREV_CLOBBER. */
600 x = XVECEXP (PATTERN (insn), 0, 0);
56cc4397 601 if (rtx_equal_p (SET_DEST (x), in_a))
602 cmp_src = SET_SRC (x);
603
604 /* Also check operations with implicit extensions, e.g.:
605 [(set (reg:DI)
606 (zero_extend:DI (plus:SI (reg:SI)(reg:SI))))
607 (set (reg:CCZ flags)
608 (compare:CCZ
609 (plus:SI (reg:SI)(reg:SI))
610 (const_int 0)))] */
611 else if (REG_P (SET_DEST (x))
612 && REG_P (in_a)
613 && REGNO (SET_DEST (x)) == REGNO (in_a)
614 && (GET_CODE (SET_SRC (x)) == ZERO_EXTEND
615 || GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
616 && GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
617 cmp_src = XEXP (SET_SRC (x), 0);
618 else
a50372fe 619 return false;
56cc4397 620
a50372fe 621 /* Determine if we ought to use a different CC_MODE here. */
622 flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
623 if (flags == NULL)
624 flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
625
626 /* Generate a new comparison for installation in the setter. */
627 x = copy_rtx (cmp_src);
628 x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
629 x = gen_rtx_SET (VOIDmode, flags, x);
630
631 /* Succeed if the new instruction is valid. Note that we may have started
632 a change group within maybe_select_cc_mode, therefore we must continue. */
633 validate_change (insn, &XVECEXP (PATTERN (insn), 0, 1), x, true);
634 if (!apply_change_group ())
635 return false;
636
637 /* Success. Delete the compare insn... */
638 delete_insn (cmp->insn);
639
640 /* ... and any notes that are now invalid due to multiple sets. */
641 x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
642 if (x)
643 remove_note (insn, x);
644 x = find_reg_note (insn, REG_EQUAL, NULL);
645 if (x)
646 remove_note (insn, x);
647 x = find_reg_note (insn, REG_EQUIV, NULL);
648 if (x)
649 remove_note (insn, x);
650
651 return true;
652}
653
654/* Main entry point to the pass. */
655
656static unsigned int
657execute_compare_elim_after_reload (void)
658{
a50372fe 659 df_analyze ();
660
f1f41a6c 661 gcc_checking_assert (!all_compares.exists ());
a50372fe 662
663 /* Locate all comparisons and their uses, and eliminate duplicates. */
664 find_comparisons ();
f1f41a6c 665 if (all_compares.exists ())
a50372fe 666 {
667 struct comparison *cmp;
668 size_t i;
669
670 /* Eliminate comparisons that are redundant with flags computation. */
f1f41a6c 671 FOR_EACH_VEC_ELT (all_compares, i, cmp)
a50372fe 672 {
673 try_eliminate_compare (cmp);
674 XDELETE (cmp);
675 }
676
f1f41a6c 677 all_compares.release ();
a50372fe 678 }
679
680 return 0;
681}
682
cbe8bda8 683namespace {
684
685const pass_data pass_data_compare_elim_after_reload =
a50372fe 686{
cbe8bda8 687 RTL_PASS, /* type */
688 "cmpelim", /* name */
689 OPTGROUP_NONE, /* optinfo_flags */
cbe8bda8 690 TV_NONE, /* tv_id */
691 0, /* properties_required */
692 0, /* properties_provided */
693 0, /* properties_destroyed */
694 0, /* todo_flags_start */
8b88439e 695 ( TODO_df_finish | TODO_df_verify ), /* todo_flags_finish */
a50372fe 696};
cbe8bda8 697
698class pass_compare_elim_after_reload : public rtl_opt_pass
699{
700public:
9af5ce0c 701 pass_compare_elim_after_reload (gcc::context *ctxt)
702 : rtl_opt_pass (pass_data_compare_elim_after_reload, ctxt)
cbe8bda8 703 {}
704
705 /* opt_pass methods: */
31315c24 706 virtual bool gate (function *)
707 {
708 /* Setting this target hook value is how a backend indicates the need. */
709 if (targetm.flags_regnum == INVALID_REGNUM)
710 return false;
711 return flag_compare_elim_after_reload;
712 }
713
65b0537f 714 virtual unsigned int execute (function *)
715 {
716 return execute_compare_elim_after_reload ();
717 }
cbe8bda8 718
719}; // class pass_compare_elim_after_reload
720
721} // anon namespace
722
723rtl_opt_pass *
724make_pass_compare_elim_after_reload (gcc::context *ctxt)
725{
726 return new pass_compare_elim_after_reload (ctxt);
727}