[ARM/AArch64][2/2] Crypto intrinsics tuning for Cortex-A53 - pipeline description
[gcc.git] / gcc / ifcvt.c
index 2365e74a41a03b068b4b2a36d6e0e537253e17eb..0d1adce952e0153ef66326ecaa72315e736b46a7 100644 (file)
@@ -1,7 +1,5 @@
 /* If-conversion support.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010,
-   2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2000-2014 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -44,7 +42,6 @@
 #include "df.h"
 #include "vec.h"
 #include "pointer-set.h"
-#include "vecprim.h"
 #include "dbgcnt.h"
 
 #ifndef HAVE_conditional_move
@@ -70,6 +67,9 @@
 
 #define NULL_BLOCK     ((basic_block) NULL)
 
+/* True if after combine pass.  */
+static bool ifcvt_after_combine;
+
 /* # of IF-THEN or IF-THEN-ELSE blocks we looked at  */
 static int num_possible_if_blocks;
 
@@ -91,16 +91,16 @@ static rtx last_active_insn (basic_block, int);
 static rtx find_active_insn_before (basic_block, rtx);
 static rtx find_active_insn_after (basic_block, rtx);
 static basic_block block_fallthru (basic_block);
-static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
+static int cond_exec_process_insns (ce_if_block *, rtx, rtx, rtx, int, int);
 static rtx cond_exec_get_condition (rtx);
 static rtx noce_get_condition (rtx, rtx *, bool);
 static int noce_operand_ok (const_rtx);
-static void merge_if_block (ce_if_block_t *);
+static void merge_if_block (ce_if_block *);
 static int find_cond_trap (basic_block, edge, edge);
 static basic_block find_if_header (basic_block, int);
 static int block_jumps_and_fallthru_p (basic_block, basic_block);
 static int noce_find_if_block (basic_block, edge, edge, int);
-static int cond_exec_find_if_block (ce_if_block_t *);
+static int cond_exec_find_if_block (ce_if_block *);
 static int find_if_case_1 (basic_block, edge, edge);
 static int find_if_case_2 (basic_block, edge, edge);
 static int dead_or_predicable (basic_block, basic_block, basic_block,
@@ -118,7 +118,7 @@ count_bb_insns (const_basic_block bb)
 
   while (1)
     {
-      if (CALL_P (insn) || NONJUMP_INSN_P (insn))
+      if (active_insn_p (insn) && !JUMP_P (insn))
        count++;
 
       if (insn == BB_END (bb))
@@ -144,11 +144,24 @@ cheap_bb_rtx_cost_p (const_basic_block bb, int scale, int max_cost)
   rtx insn = BB_HEAD (bb);
   bool speed = optimize_bb_for_speed_p (bb);
 
+  /* Set scale to REG_BR_PROB_BASE to void the identical scaling
+     applied to insn_rtx_cost when optimizing for size.  Only do
+     this after combine because if-conversion might interfere with
+     passes before combine.
+
+     Use optimize_function_for_speed_p instead of the pre-defined
+     variable speed to make sure it is set to same value for all
+     basic blocks in one if-conversion transformation.  */
+  if (!optimize_function_for_speed_p (cfun) && ifcvt_after_combine)
+    scale = REG_BR_PROB_BASE;
   /* Our branch probability/scaling factors are just estimates and don't
      account for cases where we can get speculation for free and other
      secondary benefits.  So we fudge the scale factor to make speculating
-     appear a little more profitable.  */
-  scale += REG_BR_PROB_BASE / 8;
+     appear a little more profitable when optimizing for performance.  */
+  else
+    scale += REG_BR_PROB_BASE / 8;
+
+
   max_cost *= scale;
 
   while (1)
@@ -299,11 +312,11 @@ block_fallthru (basic_block bb)
    insns were processed.  */
 
 static int
-cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
+cond_exec_process_insns (ce_if_block *ce_info ATTRIBUTE_UNUSED,
                         /* if block information */rtx start,
                         /* first insn to look at */rtx end,
                         /* last insn to look at */rtx test,
-                        /* conditional execution test */rtx prob_val,
+                        /* conditional execution test */int prob_val,
                         /* probability of branch taken. */int mod_ok)
 {
   int must_be_last = FALSE;
@@ -323,7 +336,11 @@ cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
       if (NOTE_P (insn) || DEBUG_INSN_P (insn))
        goto insn_done;
 
-      gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn));
+      gcc_assert (NONJUMP_INSN_P (insn) || CALL_P (insn));
+
+      /* dwarf2out can't cope with conditional unwind info.  */
+      if (RTX_FRAME_RELATED_P (insn))
+       return FALSE;
 
       /* Remove USE insns that get in the way.  */
       if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
@@ -374,10 +391,10 @@ cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
 
       validate_change (insn, &PATTERN (insn), pattern, 1);
 
-      if (CALL_P (insn) && prob_val)
+      if (CALL_P (insn) && prob_val >= 0)
        validate_change (insn, &REG_NOTES (insn),
-                        alloc_EXPR_LIST (REG_BR_PROB, prob_val,
-                                         REG_NOTES (insn)), 1);
+                        gen_rtx_INT_LIST ((enum machine_mode) REG_BR_PROB,
+                                          prob_val, REG_NOTES (insn)), 1);
 
     insn_done:
       if (insn == end)
@@ -421,7 +438,7 @@ cond_exec_get_condition (rtx jump)
    converting the block.  */
 
 static int
-cond_exec_process_if_block (ce_if_block_t * ce_info,
+cond_exec_process_if_block (ce_if_block * ce_info,
                            /* if block information */int do_multiple_p)
 {
   basic_block test_bb = ce_info->test_bb;      /* last test block */
@@ -436,14 +453,15 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
   int then_mod_ok;             /* whether conditional mods are ok in THEN */
   rtx true_expr;               /* test for else block insns */
   rtx false_expr;              /* test for then block insns */
-  rtx true_prob_val;           /* probability of else block */
-  rtx false_prob_val;          /* probability of then block */
+  int true_prob_val;           /* probability of else block */
+  int false_prob_val;          /* probability of then block */
   rtx then_last_head = NULL_RTX;       /* Last match at the head of THEN */
   rtx else_last_head = NULL_RTX;       /* Last match at the head of ELSE */
   rtx then_first_tail = NULL_RTX;      /* First match at the tail of THEN */
   rtx else_first_tail = NULL_RTX;      /* First match at the tail of ELSE */
   int then_n_insns, else_n_insns, n_insns;
   enum rtx_code false_code;
+  rtx note;
 
   /* If test is comprised of && or || elements, and we've failed at handling
      all of them together, just use the last test if it is the special case of
@@ -508,7 +526,10 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
          n_insns -= 2 * n_matching;
        }
 
-      if (then_start && else_start)
+      if (then_start
+         && else_start
+         && then_n_insns > n_matching
+         && else_n_insns > n_matching)
        {
          int longest_match = MIN (then_n_insns - n_matching,
                                   else_n_insns - n_matching);
@@ -575,14 +596,17 @@ cond_exec_process_if_block (ce_if_block_t * ce_info,
     goto fail;
 #endif
 
-  true_prob_val = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
-  if (true_prob_val)
+  note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
+  if (note)
     {
-      true_prob_val = XEXP (true_prob_val, 0);
-      false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
+      true_prob_val = XINT (note, 0);
+      false_prob_val = REG_BR_PROB_BASE - true_prob_val;
     }
   else
-    false_prob_val = NULL_RTX;
+    {
+      true_prob_val = -1;
+      false_prob_val = -1;
+    }
 
   /* If we have && or || tests, do them here.  These tests are in the adjacent
      blocks after the first block containing the test.  */
@@ -967,6 +991,8 @@ end_ifcvt_sequence (struct noce_if_info *if_info)
 
   set_used_flags (if_info->x);
   set_used_flags (if_info->cond);
+  set_used_flags (if_info->a);
+  set_used_flags (if_info->b);
   unshare_all_rtl_in_chain (seq);
   end_sequence ();
 
@@ -1093,12 +1119,13 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       ifalse = INTVAL (if_info->a);
       itrue = INTVAL (if_info->b);
 
+      diff = (unsigned HOST_WIDE_INT) itrue - ifalse;
       /* Make sure we can represent the difference between the two values.  */
-      if ((itrue - ifalse > 0)
+      if ((diff > 0)
          != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
        return FALSE;
 
-      diff = trunc_int_for_mode (itrue - ifalse, mode);
+      diff = trunc_int_for_mode (diff, mode);
 
       can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
                     != UNKNOWN);
@@ -1129,7 +1156,7 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       if (reversep)
        {
          tmp = itrue; itrue = ifalse; ifalse = tmp;
-         diff = trunc_int_for_mode (-diff, mode);
+         diff = trunc_int_for_mode (-(unsigned HOST_WIDE_INT) diff, mode);
        }
 
       start_sequence ();
@@ -1147,8 +1174,8 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
          target = expand_simple_binop (mode,
                                        (diff == STORE_FLAG_VALUE
                                         ? PLUS : MINUS),
-                                       GEN_INT (ifalse), target, if_info->x, 0,
-                                       OPTAB_WIDEN);
+                                       gen_int_mode (ifalse, mode), target,
+                                       if_info->x, 0, OPTAB_WIDEN);
        }
 
       /* if (test) x = 8; else x = 0;
@@ -1165,8 +1192,8 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       else if (itrue == -1)
        {
          target = expand_simple_binop (mode, IOR,
-                                       target, GEN_INT (ifalse), if_info->x, 0,
-                                       OPTAB_WIDEN);
+                                       target, gen_int_mode (ifalse, mode),
+                                       if_info->x, 0, OPTAB_WIDEN);
        }
 
       /* if (test) x = a; else x = b;
@@ -1174,11 +1201,11 @@ noce_try_store_flag_constants (struct noce_if_info *if_info)
       else
        {
          target = expand_simple_binop (mode, AND,
-                                       target, GEN_INT (diff), if_info->x, 0,
-                                       OPTAB_WIDEN);
+                                       target, gen_int_mode (diff, mode),
+                                       if_info->x, 0, OPTAB_WIDEN);
          if (target)
            target = expand_simple_binop (mode, PLUS,
-                                         target, GEN_INT (ifalse),
+                                         target, gen_int_mode (ifalse, mode),
                                          if_info->x, 0, OPTAB_WIDEN);
        }
 
@@ -2494,6 +2521,12 @@ noce_process_if_block (struct noce_if_info *if_info)
          || ! noce_operand_ok (SET_SRC (set_b))
          || reg_overlap_mentioned_p (x, SET_SRC (set_b))
          || modified_between_p (SET_SRC (set_b), insn_b, jump)
+         /* Avoid extending the lifetime of hard registers on small
+            register class machines.  */
+         || (REG_P (SET_SRC (set_b))
+             && HARD_REGISTER_P (SET_SRC (set_b))
+             && targetm.small_register_classes_for_mode_p
+                  (GET_MODE (SET_SRC (set_b))))
          /* Likewise with X.  In particular this can happen when
             noce_get_condition looks farther back in the instruction
             stream than one might expect.  */
@@ -2695,7 +2728,7 @@ noce_process_if_block (struct noce_if_info *if_info)
 static int
 check_cond_move_block (basic_block bb,
                       struct pointer_map_t *vals,
-                      VEC (rtx, heap) **regs,
+                      vec<rtx> *regs,
                       rtx cond)
 {
   rtx insn;
@@ -2760,7 +2793,7 @@ check_cond_move_block (basic_block bb,
       slot = pointer_map_insert (vals, (void *) dest);
       *slot = (void *) src;
 
-      VEC_safe_push (rtx, heap, *regs, dest);
+      regs->safe_push (dest);
     }
 
   return TRUE;
@@ -2851,8 +2884,8 @@ cond_move_process_if_block (struct noce_if_info *if_info)
   int c;
   struct pointer_map_t *then_vals;
   struct pointer_map_t *else_vals;
-  VEC (rtx, heap) *then_regs = NULL;
-  VEC (rtx, heap) *else_regs = NULL;
+  vec<rtx> then_regs = vNULL;
+  vec<rtx> else_regs = vNULL;
   unsigned int i;
   int success_p = FALSE;
 
@@ -2874,7 +2907,7 @@ cond_move_process_if_block (struct noce_if_info *if_info)
      source register does not change after the assignment.  Also count
      the number of registers set in only one of the blocks.  */
   c = 0;
-  FOR_EACH_VEC_ELT (rtx, then_regs, i, reg)
+  FOR_EACH_VEC_ELT (then_regs, i, reg)
     {
       void **then_slot = pointer_map_contains (then_vals, reg);
       void **else_slot = pointer_map_contains (else_vals, reg);
@@ -2893,7 +2926,7 @@ cond_move_process_if_block (struct noce_if_info *if_info)
     }
 
   /* Finish off c for MAX_CONDITIONAL_EXECUTE.  */
-  FOR_EACH_VEC_ELT (rtx, else_regs, i, reg)
+  FOR_EACH_VEC_ELT (else_regs, i, reg)
     {
       gcc_checking_assert (pointer_map_contains (else_vals, reg));
       if (!pointer_map_contains (then_vals, reg))
@@ -2957,8 +2990,8 @@ cond_move_process_if_block (struct noce_if_info *if_info)
 done:
   pointer_map_destroy (then_vals);
   pointer_map_destroy (else_vals);
-  VEC_free (rtx, heap, then_regs);
-  VEC_free (rtx, heap, else_regs);
+  then_regs.release ();
+  else_regs.release ();
   return success_p;
 }
 
@@ -3127,6 +3160,20 @@ merge_if_block (struct ce_if_block * ce_info)
 
   if (then_bb)
     {
+      /* If THEN_BB has no successors, then there's a BARRIER after it.
+        If COMBO_BB has more than one successor (THEN_BB), then that BARRIER
+        is no longer needed, and in fact it is incorrect to leave it in
+        the insn stream.  */
+      if (EDGE_COUNT (then_bb->succs) == 0
+         && EDGE_COUNT (combo_bb->succs) > 1)
+       {
+         rtx end = NEXT_INSN (BB_END (then_bb));
+         while (end && NOTE_P (end) && !NOTE_INSN_BASIC_BLOCK_P (end))
+           end = NEXT_INSN (end);
+
+         if (end && BARRIER_P (end))
+           delete_insn (end);
+       }
       merge_blocks (combo_bb, then_bb);
       num_true_changes++;
     }
@@ -3136,6 +3183,20 @@ merge_if_block (struct ce_if_block * ce_info)
      get their addresses taken.  */
   if (else_bb)
     {
+      /* If ELSE_BB has no successors, then there's a BARRIER after it.
+        If COMBO_BB has more than one successor (ELSE_BB), then that BARRIER
+        is no longer needed, and in fact it is incorrect to leave it in
+        the insn stream.  */
+      if (EDGE_COUNT (else_bb->succs) == 0
+         && EDGE_COUNT (combo_bb->succs) > 1)
+       {
+         rtx end = NEXT_INSN (BB_END (else_bb));
+         while (end && NOTE_P (end) && !NOTE_INSN_BASIC_BLOCK_P (end))
+           end = NEXT_INSN (end);
+
+         if (end && BARRIER_P (end))
+           delete_insn (end);
+       }
       merge_blocks (combo_bb, else_bb);
       num_true_changes++;
     }
@@ -3160,7 +3221,8 @@ merge_if_block (struct ce_if_block * ce_info)
       /* There should still be something at the end of the THEN or ELSE
          blocks taking us to our final destination.  */
        gcc_assert (JUMP_P (last)
-                   || (EDGE_SUCC (combo_bb, 0)->dest == EXIT_BLOCK_PTR
+                   || (EDGE_SUCC (combo_bb, 0)->dest
+                       == EXIT_BLOCK_PTR_FOR_FN (cfun)
                        && CALL_P (last)
                        && SIBLING_CALL_P (last))
                    || ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH)
@@ -3174,7 +3236,7 @@ merge_if_block (struct ce_if_block * ce_info)
      may be zero incoming edges if the THEN block didn't actually join
      back up (as with a call to a non-return function).  */
   else if (EDGE_COUNT (join_bb->preds) < 2
-          && join_bb != EXIT_BLOCK_PTR)
+          && join_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
     {
       /* We can merge the JOIN cleanly and update the dataflow try
         again on this pass.*/
@@ -3191,7 +3253,7 @@ merge_if_block (struct ce_if_block * ce_info)
                  && single_succ (combo_bb) == join_bb);
 
       /* Remove the jump and cruft from the end of the COMBO block.  */
-      if (join_bb != EXIT_BLOCK_PTR)
+      if (join_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
        tidy_fallthru_edge (single_succ_edge (combo_bb));
     }
 
@@ -3206,7 +3268,7 @@ merge_if_block (struct ce_if_block * ce_info)
 static basic_block
 find_if_header (basic_block test_bb, int pass)
 {
-  ce_if_block_t ce_info;
+  ce_if_block ce_info;
   edge then_edge;
   edge else_edge;
 
@@ -3470,7 +3532,7 @@ cond_exec_find_if_block (struct ce_if_block * ce_info)
      code processing.  ??? we should fix this in the future.  */
   if (EDGE_COUNT (then_bb->succs) == 0)
     {
-      if (single_pred_p (else_bb))
+      if (single_pred_p (else_bb) && else_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
        {
          rtx last_insn = BB_END (then_bb);
 
@@ -3561,7 +3623,8 @@ cond_exec_find_if_block (struct ce_if_block * ce_info)
   next = then_bb;
   if (else_bb && (next = next->next_bb) != else_bb)
     return FALSE;
-  if ((next = next->next_bb) != join_bb && join_bb != EXIT_BLOCK_PTR)
+  if ((next = next->next_bb) != join_bb
+      && join_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
     {
       if (else_bb)
        join_bb = NULL;
@@ -3669,7 +3732,7 @@ find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
   /* Wire together the blocks again.  */
   if (current_ir_type () == IR_RTL_CFGLAYOUT)
     single_succ_edge (test_bb)->flags |= EDGE_FALLTHRU;
-  else
+  else if (trap_bb == then_bb)
     {
       rtx lab, newjump;
 
@@ -3700,7 +3763,7 @@ block_has_only_trap (basic_block bb)
   rtx trap;
 
   /* We're not the exit block.  */
-  if (bb == EXIT_BLOCK_PTR)
+  if (bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
     return NULL_RTX;
 
   /* The block must have no successors.  */
@@ -3856,7 +3919,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
                                    predictable_edge_p (then_edge)))))
     return FALSE;
 
-  if (else_bb == EXIT_BLOCK_PTR)
+  if (else_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
     {
       rtx jump = BB_END (else_edge->src);
       gcc_assert (JUMP_P (jump));
@@ -3877,12 +3940,12 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
 
   if (then_bb->next_bb == else_bb
       && then_bb->prev_bb == test_bb
-      && else_bb != EXIT_BLOCK_PTR)
+      && else_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
     {
       redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb);
       new_bb = 0;
     }
-  else if (else_bb == EXIT_BLOCK_PTR)
+  else if (else_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
     new_bb = force_nonfallthru_and_redirect (FALLTHRU_EDGE (test_bb),
                                             else_bb, else_target);
   else
@@ -3900,10 +3963,9 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
   if (new_bb)
     {
       df_bb_replace (then_bb_index, new_bb);
-      /* Since the fallthru edge was redirected from test_bb to new_bb,
-         we need to ensure that new_bb is in the same partition as
-         test bb (you can not fall through across section boundaries).  */
-      BB_COPY_PARTITION (new_bb, test_bb);
+      /* This should have been done above via force_nonfallthru_and_redirect
+         (possibly called from redirect_edge_and_branch_force).  */
+      gcc_checking_assert (BB_PARTITION (new_bb) == BB_PARTITION (test_bb));
     }
 
   num_true_changes++;
@@ -4082,6 +4144,21 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
        end = PREV_INSN (end);
     }
 
+  /* Don't move frame-related insn across the conditional branch.  This
+     can lead to one of the paths of the branch having wrong unwind info.  */
+  if (epilogue_completed)
+    {
+      rtx insn = head;
+      while (1)
+       {
+         if (INSN_P (insn) && RTX_FRAME_RELATED_P (insn))
+           return FALSE;
+         if (insn == end)
+           break;
+         insn = NEXT_INSN (insn);
+       }
+    }
+
   /* Disable handling dead code by conditional execution if the machine needs
      to do anything funny with the tests, etc.  */
 #ifndef IFCVT_MODIFY_TESTS
@@ -4093,15 +4170,14 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
         All that's left is making sure the insns involved can actually
         be predicated.  */
 
-      rtx cond, prob_val;
+      rtx cond;
 
       cond = cond_exec_get_condition (jump);
       if (! cond)
        return FALSE;
 
-      prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
-      if (prob_val)
-       prob_val = XEXP (prob_val, 0);
+      rtx note = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
+      int prob_val = (note ? XINT (note, 0) : -1);
 
       if (reversep)
        {
@@ -4110,8 +4186,8 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
            return FALSE;
          cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
                                 XEXP (cond, 1));
-         if (prob_val)
-           prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
+         if (prob_val >= 0)
+           prob_val = REG_BR_PROB_BASE - prob_val;
        }
 
       if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0)
@@ -4173,9 +4249,9 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
         saved in caller-saved regs.  A caller-saved reg requires the
         prologue, killing a shrink-wrap opportunity.  */
       if ((flag_shrink_wrap && HAVE_simple_return && !epilogue_completed)
-         && ENTRY_BLOCK_PTR->next_bb == test_bb
+         && ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb == test_bb
          && single_succ_p (new_dest)
-         && single_succ (new_dest) == EXIT_BLOCK_PTR
+         && single_succ (new_dest) == EXIT_BLOCK_PTR_FOR_FN (cfun)
          && bitmap_intersect_p (df_get_live_in (new_dest), merge_set))
        {
          regset return_regs;
@@ -4190,8 +4266,10 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
                && targetm.calls.function_value_regno_p (i))
              bitmap_set_bit (return_regs, INCOMING_REGNO (i));
 
-         bitmap_and_into (return_regs, df_get_live_out (ENTRY_BLOCK_PTR));
-         bitmap_and_into (return_regs, df_get_live_in (EXIT_BLOCK_PTR));
+         bitmap_and_into (return_regs,
+                          df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+         bitmap_and_into (return_regs,
+                          df_get_live_in (EXIT_BLOCK_PTR_FOR_FN (cfun)));
          if (!bitmap_empty_p (return_regs))
            {
              FOR_BB_INSNS_REVERSE (new_dest, insn)
@@ -4236,7 +4314,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
     {
       if (JUMP_P (BB_END (dest_edge->src)))
        new_dest_label = JUMP_LABEL (BB_END (dest_edge->src));
-      else if (new_dest == EXIT_BLOCK_PTR)
+      else if (new_dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
        new_dest_label = ret_rtx;
       else
        new_dest_label = block_label (new_dest);
@@ -4333,10 +4411,11 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
   return FALSE;
 }
 \f
-/* Main entry point for all if-conversion.  */
+/* Main entry point for all if-conversion.  AFTER_COMBINE is true if
+   we are after combine pass.  */
 
 static void
-if_convert (void)
+if_convert (bool after_combine)
 {
   basic_block bb;
   int pass;
@@ -4347,6 +4426,8 @@ if_convert (void)
       df_live_set_all_dirty ();
     }
 
+  /* Record whether we are after combine pass.  */
+  ifcvt_after_combine = after_combine;
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
   num_true_changes = 0;
@@ -4378,7 +4459,7 @@ if_convert (void)
        fprintf (dump_file, "\n\n========== Pass %d ==========\n", pass);
 #endif
 
-      FOR_EACH_BB (bb)
+      FOR_EACH_BB_FN (bb, cfun)
        {
           basic_block new_bb;
           while (!df_get_bb_dirty (bb)
@@ -4450,34 +4531,51 @@ rest_of_handle_if_conversion (void)
          dump_flow_info (dump_file, dump_flags);
        }
       cleanup_cfg (CLEANUP_EXPENSIVE);
-      if_convert ();
+      if_convert (false);
     }
 
   cleanup_cfg (0);
   return 0;
 }
 
-struct rtl_opt_pass pass_rtl_ifcvt =
+namespace {
+
+const pass_data pass_data_rtl_ifcvt =
 {
- {
-  RTL_PASS,
-  "ce1",                                /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_if_conversion,            /* gate */
-  rest_of_handle_if_conversion,         /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_IFCVT,                             /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  0                                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "ce1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_IFCVT, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_df_finish | TODO_verify_rtl_sharing | 0 ), /* todo_flags_finish */
 };
 
+class pass_rtl_ifcvt : public rtl_opt_pass
+{
+public:
+  pass_rtl_ifcvt (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_rtl_ifcvt, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_if_conversion (); }
+  unsigned int execute () { return rest_of_handle_if_conversion (); }
+
+}; // class pass_rtl_ifcvt
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_ifcvt (gcc::context *ctxt)
+{
+  return new pass_rtl_ifcvt (ctxt);
+}
+
 static bool
 gate_handle_if_after_combine (void)
 {
@@ -4491,31 +4589,48 @@ gate_handle_if_after_combine (void)
 static unsigned int
 rest_of_handle_if_after_combine (void)
 {
-  if_convert ();
+  if_convert (true);
   return 0;
 }
 
-struct rtl_opt_pass pass_if_after_combine =
+namespace {
+
+const pass_data pass_data_if_after_combine =
 {
- {
-  RTL_PASS,
-  "ce2",                                /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_if_after_combine,         /* gate */
-  rest_of_handle_if_after_combine,      /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_IFCVT,                             /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "ce2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_IFCVT, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_df_finish | TODO_verify_rtl_sharing ), /* todo_flags_finish */
 };
 
+class pass_if_after_combine : public rtl_opt_pass
+{
+public:
+  pass_if_after_combine (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_if_after_combine, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_if_after_combine (); }
+  unsigned int execute () { return rest_of_handle_if_after_combine (); }
+
+}; // class pass_if_after_combine
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_if_after_combine (gcc::context *ctxt)
+{
+  return new pass_if_after_combine (ctxt);
+}
+
 
 static bool
 gate_handle_if_after_reload (void)
@@ -4527,28 +4642,45 @@ gate_handle_if_after_reload (void)
 static unsigned int
 rest_of_handle_if_after_reload (void)
 {
-  if_convert ();
+  if_convert (true);
   return 0;
 }
 
 
-struct rtl_opt_pass pass_if_after_reload =
+namespace {
+
+const pass_data pass_data_if_after_reload =
 {
- {
-  RTL_PASS,
-  "ce3",                                /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_if_after_reload,          /* gate */
-  rest_of_handle_if_after_reload,       /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_IFCVT2,                            /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "ce3", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_IFCVT2, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_df_finish | TODO_verify_rtl_sharing ), /* todo_flags_finish */
 };
+
+class pass_if_after_reload : public rtl_opt_pass
+{
+public:
+  pass_if_after_reload (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_if_after_reload, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_if_after_reload (); }
+  unsigned int execute () { return rest_of_handle_if_after_reload (); }
+
+}; // class pass_if_after_reload
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_if_after_reload (gcc::context *ctxt)
+{
+  return new pass_if_after_reload (ctxt);
+}