Import pre-release gcc-5.0 to new vendor branch
[dragonfly.git] / contrib / gcc-5.0 / gcc / compare-elim.c
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 \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
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 }