xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/compare-elim.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* Post-reload compare elimination.
2    Copyright (C) 2010-2015 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10 
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along 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) (reg_or_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"
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"
77 #include "basic-block.h"
78 #include "tree-pass.h"
79 #include "target.h"
80 #include "df.h"
81 #include "domwalk.h"
82 
83 
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 
92 struct comparison_use
93 {
94   /* The instruction in which the result of the compare is used.  */
95   rtx_insn *insn;
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 
102 struct comparison
103 {
104   /* The comparison instruction.  */
105   rtx_insn *insn;
106 
107   /* The insn prior to the comparison insn that clobbers the flags.  */
108   rtx_insn *prev_clobber;
109 
110   /* The two values being compared.  These will be either REGs or
111      constants.  */
112   rtx in_a, in_b;
113 
114   /* The REG_EH_REGION of the comparison.  */
115   rtx eh_note;
116 
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   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 
135 typedef struct comparison *comparison_struct_p;
136 
137 static vec<comparison_struct_p> all_compares;
138 
139 /* Look for a "conforming" comparison, as defined above.  If valid, return
140    the rtx for the COMPARE itself.  */
141 
142 static rtx
143 conforming_compare (rtx_insn *insn)
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, 1)) || CONSTANT_P (XEXP (src, 1))))
161     return src;
162 
163   return NULL;
164 }
165 
166 /* Look for a pattern of the "correct" form for an insn with a flags clobber
167    for which we may be able to eliminate a compare later.  We're not looking
168    to validate any inputs at this time, merely see that the basic shape is
169    correct.  The term "arithmetic" may be somewhat misleading...  */
170 
171 static bool
172 arithmetic_flags_clobber_p (rtx_insn *insn)
173 {
174   rtx pat, x;
175 
176   if (!NONJUMP_INSN_P (insn))
177     return false;
178   pat = PATTERN (insn);
179   if (extract_asm_operands (pat))
180     return false;
181 
182   if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
183     {
184       x = XVECEXP (pat, 0, 0);
185       if (GET_CODE (x) != SET)
186 	return false;
187       x = SET_DEST (x);
188       if (!REG_P (x))
189 	return false;
190 
191       x = XVECEXP (pat, 0, 1);
192       if (GET_CODE (x) == CLOBBER)
193 	{
194 	  x = XEXP (x, 0);
195 	  if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
196 	    return true;
197 	}
198     }
199 
200   return false;
201 }
202 
203 /* Look for uses of FLAGS in INSN.  If we find one we can analyze, record
204    it in CMP; otherwise indicate that we've missed a use.  */
205 
206 static void
207 find_flags_uses_in_insn (struct comparison *cmp, rtx_insn *insn)
208 {
209   df_ref use;
210 
211   /* If we've already lost track of uses, don't bother collecting more.  */
212   if (cmp->missing_uses)
213     return;
214 
215   /* Find a USE of the flags register.  */
216   FOR_EACH_INSN_USE (use, insn)
217     if (DF_REF_REGNO (use) == targetm.flags_regnum)
218       {
219 	rtx x, *loc;
220 
221 	/* If this is an unusual use, quit.  */
222 	if (DF_REF_TYPE (use) != DF_REF_REG_USE)
223 	  goto fail;
224 
225 	/* If we've run out of slots to record uses, quit.  */
226 	if (cmp->n_uses == MAX_CMP_USE)
227 	  goto fail;
228 
229 	/* Unfortunately the location of the flags register, while present
230 	   in the reference structure, doesn't help.  We need to find the
231 	   comparison code that is outer to the actual flags use.  */
232 	loc = DF_REF_LOC (use);
233 	x = PATTERN (insn);
234 	if (GET_CODE (x) == PARALLEL)
235 	  x = XVECEXP (x, 0, 0);
236 	x = SET_SRC (x);
237 	if (GET_CODE (x) == IF_THEN_ELSE)
238 	  x = XEXP (x, 0);
239 	if (COMPARISON_P (x)
240 	    && loc == &XEXP (x, 0)
241 	    && XEXP (x, 1) == const0_rtx)
242 	  {
243 	    /* We've found a use of the flags that we understand.  */
244 	    struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
245 	    cuse->insn = insn;
246 	    cuse->loc = loc;
247 	    cuse->code = GET_CODE (x);
248 	  }
249 	else
250 	  goto fail;
251       }
252   return;
253 
254  fail:
255   /* We failed to recognize this use of the flags register.  */
256   cmp->missing_uses = true;
257 }
258 
259 class find_comparison_dom_walker : public dom_walker
260 {
261 public:
262   find_comparison_dom_walker (cdi_direction direction)
263     : dom_walker (direction) {}
264 
265   virtual void before_dom_children (basic_block);
266 };
267 
268 /* Return true if conforming COMPARE with EH_NOTE is redundant with comparison
269    CMP and can thus be eliminated.  */
270 
271 static bool
272 can_eliminate_compare (rtx compare, rtx eh_note, struct comparison *cmp)
273 {
274   /* Take care that it's in the same EH region.  */
275   if (cfun->can_throw_non_call_exceptions
276       && !rtx_equal_p (eh_note, cmp->eh_note))
277     return false;
278 
279   /* Make sure the compare is redundant with the previous.  */
280   if (!rtx_equal_p (XEXP (compare, 0), cmp->in_a)
281       || !rtx_equal_p (XEXP (compare, 1), cmp->in_b))
282     return false;
283 
284   /* New mode must be compatible with the previous compare mode.  */
285   enum machine_mode new_mode
286     = targetm.cc_modes_compatible (GET_MODE (compare), cmp->orig_mode);
287 
288   if (new_mode == VOIDmode)
289     return false;
290 
291   if (cmp->orig_mode != new_mode)
292     {
293       /* Generate new comparison for substitution.  */
294       rtx flags = gen_rtx_REG (new_mode, targetm.flags_regnum);
295       rtx x = gen_rtx_COMPARE (new_mode, cmp->in_a, cmp->in_b);
296       x = gen_rtx_SET (VOIDmode, flags, x);
297 
298       if (!validate_change (cmp->insn, &PATTERN (cmp->insn), x, false))
299 	return false;
300 
301       cmp->orig_mode = new_mode;
302     }
303 
304   return true;
305 }
306 
307 /* Identify comparison instructions within BB.  If the flags from the last
308    compare in the BB is live at the end of the block, install the compare
309    in BB->AUX.  Called via dom_walker.walk ().  */
310 
311 void
312 find_comparison_dom_walker::before_dom_children (basic_block bb)
313 {
314   struct comparison *last_cmp;
315   rtx_insn *insn, *next, *last_clobber;
316   bool last_cmp_valid;
317   bool need_purge = false;
318   bitmap killed;
319 
320   killed = BITMAP_ALLOC (NULL);
321 
322   /* The last comparison that was made.  Will be reset to NULL
323      once the flags are clobbered.  */
324   last_cmp = NULL;
325 
326   /* True iff the last comparison has not been clobbered, nor
327      have its inputs.  Used to eliminate duplicate compares.  */
328   last_cmp_valid = false;
329 
330   /* The last insn that clobbered the flags, if that insn is of
331      a form that may be valid for eliminating a following compare.
332      To be reset to NULL once the flags are set otherwise.  */
333   last_clobber = NULL;
334 
335   /* Propagate the last live comparison throughout the extended basic block. */
336   if (single_pred_p (bb))
337     {
338       last_cmp = (struct comparison *) single_pred (bb)->aux;
339       if (last_cmp)
340 	last_cmp_valid = last_cmp->inputs_valid;
341     }
342 
343   for (insn = BB_HEAD (bb); insn; insn = next)
344     {
345       rtx src;
346 
347       next = (insn == BB_END (bb) ? NULL : NEXT_INSN (insn));
348       if (!NONDEBUG_INSN_P (insn))
349 	continue;
350 
351       /* Compute the set of registers modified by this instruction.  */
352       bitmap_clear (killed);
353       df_simulate_find_defs (insn, killed);
354 
355       src = conforming_compare (insn);
356       if (src)
357 	{
358 	  rtx eh_note = NULL;
359 
360 	  if (cfun->can_throw_non_call_exceptions)
361 	    eh_note = find_reg_note (insn, REG_EH_REGION, NULL);
362 
363 	  if (last_cmp_valid && can_eliminate_compare (src, eh_note, last_cmp))
364 	    {
365 	      if (eh_note)
366 		need_purge = true;
367 	      delete_insn (insn);
368 	      continue;
369 	    }
370 
371 	  last_cmp = XCNEW (struct comparison);
372 	  last_cmp->insn = insn;
373 	  last_cmp->prev_clobber = last_clobber;
374 	  last_cmp->in_a = XEXP (src, 0);
375 	  last_cmp->in_b = XEXP (src, 1);
376 	  last_cmp->eh_note = eh_note;
377 	  last_cmp->orig_mode = GET_MODE (src);
378 	  all_compares.safe_push (last_cmp);
379 
380 	  /* It's unusual, but be prepared for comparison patterns that
381 	     also clobber an input, or perhaps a scratch.  */
382 	  last_clobber = NULL;
383 	  last_cmp_valid = true;
384 	}
385 
386       /* Notice if this instruction kills the flags register.  */
387       else if (bitmap_bit_p (killed, targetm.flags_regnum))
388 	{
389 	  /* See if this insn could be the "clobber" that eliminates
390 	     a future comparison.   */
391 	  last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
392 
393 	  /* In either case, the previous compare is no longer valid.  */
394 	  last_cmp = NULL;
395 	  last_cmp_valid = false;
396 	}
397 
398       /* Notice if this instruction uses the flags register.  */
399       else if (last_cmp)
400 	find_flags_uses_in_insn (last_cmp, insn);
401 
402       /* Notice if any of the inputs to the comparison have changed.  */
403       if (last_cmp_valid
404 	  && (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
405 	      || (REG_P (last_cmp->in_b)
406 		  && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))))
407 	last_cmp_valid = false;
408     }
409 
410   BITMAP_FREE (killed);
411 
412   /* Remember the live comparison for subsequent members of
413      the extended basic block.  */
414   if (last_cmp)
415     {
416       bb->aux = last_cmp;
417       last_cmp->inputs_valid = last_cmp_valid;
418 
419       /* Look to see if the flags register is live outgoing here, and
420 	 incoming to any successor not part of the extended basic block.  */
421       if (bitmap_bit_p (df_get_live_out (bb), targetm.flags_regnum))
422 	{
423 	  edge e;
424 	  edge_iterator ei;
425 
426 	  FOR_EACH_EDGE (e, ei, bb->succs)
427 	    {
428 	      basic_block dest = e->dest;
429 	      if (bitmap_bit_p (df_get_live_in (bb), targetm.flags_regnum)
430 		  && !single_pred_p (dest))
431 		{
432 		  last_cmp->missing_uses = true;
433 		  break;
434 		}
435 	    }
436 	}
437     }
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);
443 }
444 
445 /* Find all comparisons in the function.  */
446 
447 static void
448 find_comparisons (void)
449 {
450   calculate_dominance_info (CDI_DOMINATORS);
451 
452   find_comparison_dom_walker (CDI_DOMINATORS)
453     .walk (cfun->cfg->x_entry_block_ptr);
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 
465 static rtx
466 maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
467 		      rtx b ATTRIBUTE_UNUSED)
468 {
469   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 	  machine_mode new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
502 	  if (new_mode != sel_mode)
503 	    {
504 	      sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
505 	      if (sel_mode == VOIDmode)
506 		return NULL;
507 	    }
508 	}
509 
510       if (sel_mode != cmp->orig_mode)
511 	{
512 	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
513 	  for (i = 0; i < n; ++i)
514 	    validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
515 	}
516     }
517 
518   return flags;
519 }
520 
521 /* Attempt to replace a comparison with a prior arithmetic insn that can
522    compute the same flags value as the comparison itself.  Return true if
523    successful, having made all rtl modifications necessary.  */
524 
525 static bool
526 try_eliminate_compare (struct comparison *cmp)
527 {
528   rtx_insn *insn, *bb_head;
529   rtx x, flags, in_a, cmp_src;
530 
531   /* We must have found an interesting "clobber" preceding the compare.  */
532   if (cmp->prev_clobber == NULL)
533     return false;
534 
535   /* ??? For the moment we don't handle comparisons for which IN_B
536      is a register.  We accepted these during initial comparison
537      recognition in order to eliminate duplicate compares.
538      An improvement here would be to handle x = a - b; if (a cmp b).  */
539   if (!CONSTANT_P (cmp->in_b))
540     return false;
541 
542   /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
543      Given that this target requires this pass, we can assume that most
544      insns do clobber the flags, and so the distance between the compare
545      and the clobber is likely to be small.  */
546   /* ??? This is one point at which one could argue that DF_REF_CHAIN would
547      be useful, but it is thought to be too heavy-weight a solution here.  */
548 
549   in_a = cmp->in_a;
550   insn = cmp->insn;
551   bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
552   for (insn = PREV_INSN (insn);
553        insn != cmp->prev_clobber;
554        insn = PREV_INSN (insn))
555     {
556       const int abnormal_flags
557 	= (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
558 	   | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
559 	   | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
560 	   | DF_REF_PRE_POST_MODIFY);
561       df_ref def;
562 
563       /* Note that the BB_HEAD is always either a note or a label, but in
564 	 any case it means that IN_A is defined outside the block.  */
565       if (insn == bb_head)
566 	return false;
567       if (NOTE_P (insn) || DEBUG_INSN_P (insn))
568 	continue;
569 
570       /* Find a possible def of IN_A in INSN.  */
571       FOR_EACH_INSN_DEF (def, insn)
572 	if (DF_REF_REGNO (def) == REGNO (in_a))
573 	  break;
574 
575       /* No definitions of IN_A; continue searching.  */
576       if (def == NULL)
577 	continue;
578 
579       /* Bail if this is not a totally normal set of IN_A.  */
580       if (DF_REF_IS_ARTIFICIAL (def))
581 	return false;
582       if (DF_REF_FLAGS (def) & abnormal_flags)
583 	return false;
584 
585       /* We've found an insn between the compare and the clobber that sets
586 	 IN_A.  Given that pass_cprop_hardreg has not yet run, we still find
587 	 situations in which we can usefully look through a copy insn.  */
588       x = single_set (insn);
589       if (x == NULL)
590 	return false;
591       in_a = SET_SRC (x);
592       if (!REG_P (in_a))
593 	return false;
594     }
595 
596   /* We've reached PREV_CLOBBER without finding a modification of IN_A.
597      Validate that PREV_CLOBBER itself does in fact refer to IN_A.  Do
598      recall that we've already validated the shape of PREV_CLOBBER.  */
599   x = XVECEXP (PATTERN (insn), 0, 0);
600   if (rtx_equal_p (SET_DEST (x), in_a))
601     cmp_src = SET_SRC (x);
602 
603   /* Also check operations with implicit extensions, e.g.:
604      [(set (reg:DI)
605 	   (zero_extend:DI (plus:SI (reg:SI)(reg:SI))))
606       (set (reg:CCZ flags)
607 	   (compare:CCZ
608 	     (plus:SI (reg:SI)(reg:SI))
609 	     (const_int 0)))]				*/
610   else if (REG_P (SET_DEST (x))
611 	   && REG_P (in_a)
612 	   && REGNO (SET_DEST (x)) == REGNO (in_a)
613 	   && (GET_CODE (SET_SRC (x)) == ZERO_EXTEND
614 	       || GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
615 	   && GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
616     cmp_src = XEXP (SET_SRC (x), 0);
617   else
618     return false;
619 
620   /* Determine if we ought to use a different CC_MODE here.  */
621   flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
622   if (flags == NULL)
623     flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
624 
625   /* Generate a new comparison for installation in the setter.  */
626   x = copy_rtx (cmp_src);
627   x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
628   x = gen_rtx_SET (VOIDmode, flags, x);
629 
630   /* Succeed if the new instruction is valid.  Note that we may have started
631      a change group within maybe_select_cc_mode, therefore we must continue. */
632   validate_change (insn, &XVECEXP (PATTERN (insn), 0, 1), x, true);
633   if (!apply_change_group ())
634     return false;
635 
636   /* Success.  Delete the compare insn...  */
637   delete_insn (cmp->insn);
638 
639   /* ... and any notes that are now invalid due to multiple sets.  */
640   x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
641   if (x)
642     remove_note (insn, x);
643   x = find_reg_note (insn, REG_EQUAL, NULL);
644   if (x)
645     remove_note (insn, x);
646   x = find_reg_note (insn, REG_EQUIV, NULL);
647   if (x)
648     remove_note (insn, x);
649 
650   return true;
651 }
652 
653 /* Main entry point to the pass.  */
654 
655 static unsigned int
656 execute_compare_elim_after_reload (void)
657 {
658   df_analyze ();
659 
660   gcc_checking_assert (!all_compares.exists ());
661 
662   /* Locate all comparisons and their uses, and eliminate duplicates.  */
663   find_comparisons ();
664   if (all_compares.exists ())
665     {
666       struct comparison *cmp;
667       size_t i;
668 
669       /* Eliminate comparisons that are redundant with flags computation.  */
670       FOR_EACH_VEC_ELT (all_compares, i, cmp)
671 	{
672 	  try_eliminate_compare (cmp);
673 	  XDELETE (cmp);
674 	}
675 
676       all_compares.release ();
677     }
678 
679   return 0;
680 }
681 
682 namespace {
683 
684 const pass_data pass_data_compare_elim_after_reload =
685 {
686   RTL_PASS, /* type */
687   "cmpelim", /* name */
688   OPTGROUP_NONE, /* optinfo_flags */
689   TV_NONE, /* tv_id */
690   0, /* properties_required */
691   0, /* properties_provided */
692   0, /* properties_destroyed */
693   0, /* todo_flags_start */
694   ( TODO_df_finish | TODO_df_verify ), /* todo_flags_finish */
695 };
696 
697 class pass_compare_elim_after_reload : public rtl_opt_pass
698 {
699 public:
700   pass_compare_elim_after_reload (gcc::context *ctxt)
701     : rtl_opt_pass (pass_data_compare_elim_after_reload, ctxt)
702   {}
703 
704   /* opt_pass methods: */
705   virtual bool gate (function *)
706     {
707       /* Setting this target hook value is how a backend indicates the need.  */
708       if (targetm.flags_regnum == INVALID_REGNUM)
709 	return false;
710       return flag_compare_elim_after_reload;
711     }
712 
713   virtual unsigned int execute (function *)
714     {
715       return execute_compare_elim_after_reload ();
716     }
717 
718 }; // class pass_compare_elim_after_reload
719 
720 } // anon namespace
721 
722 rtl_opt_pass *
723 make_pass_compare_elim_after_reload (gcc::context *ctxt)
724 {
725   return new pass_compare_elim_after_reload (ctxt);
726 }
727