1/* Post-reload compare elimination.
2   Copyright (C) 2010-2015 Free Software Foundation, Inc.
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) (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
92struct 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
102struct 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
135typedef struct comparison *comparison_struct_p;
136
137static 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
142static rtx
143conforming_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
171static bool
172arithmetic_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
206static void
207find_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
259class find_comparison_dom_walker : public dom_walker
260{
261public:
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
271static bool
272can_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
311void
312find_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
447static void
448find_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
465static rtx
466maybe_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
525static bool
526try_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
655static unsigned int
656execute_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
682namespace {
683
684const 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
697class pass_compare_elim_after_reload : public rtl_opt_pass
698{
699public:
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
722rtl_opt_pass *
723make_pass_compare_elim_after_reload (gcc::context *ctxt)
724{
725  return new pass_compare_elim_after_reload (ctxt);
726}
727