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