t-aarch64-linux (MULTILIB_OSDIRNAMES): Handle multi-arch for ilp32.
[gcc.git] / gcc / tree-ssa-phiopt.c
index 37fdf28d31b98c0368776b71a1173ff277ee5870..71e7b67bf52e62a0b74fcfe826113d46e4727717 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimization of PHI nodes by converting them into straightline code.
-   Copyright (C) 2004-2015 Free Software Foundation, Inc.
+   Copyright (C) 2004-2017 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,32 +21,27 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
-#include "cfghooks.h"
+#include "insn-codes.h"
+#include "rtl.h"
 #include "tree.h"
 #include "gimple.h"
-#include "rtl.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
 #include "ssa.h"
-#include "alias.h"
+#include "optabs-tree.h"
+#include "insn-config.h"
+#include "gimple-pretty-print.h"
 #include "fold-const.h"
 #include "stor-layout.h"
-#include "flags.h"
-#include "tm_p.h"
 #include "cfganal.h"
-#include "internal-fn.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
 #include "gimplify-me.h"
 #include "tree-cfg.h"
-#include "insn-config.h"
 #include "tree-dfa.h"
-#include "tree-pass.h"
-#include "langhooks.h"
 #include "domwalk.h"
 #include "cfgloop.h"
 #include "tree-data-ref.h"
-#include "gimple-pretty-print.h"
-#include "insn-codes.h"
-#include "optabs-tree.h"
 #include "tree-scalar-evolution.h"
 #include "tree-inline.h"
 #include "params.h"
@@ -54,7 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 static unsigned int tree_ssa_phiopt_worker (bool, bool);
 static bool conditional_replacement (basic_block, basic_block,
                                     edge, edge, gphi *, tree, tree);
-static bool factor_out_conditional_conversion (edge, edge, gphi *, tree, tree);
+static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree,
+                                               gimple *);
 static int value_replacement (basic_block, basic_block,
                              edge, edge, gimple *, tree, tree);
 static bool minmax_replacement (basic_block, basic_block,
@@ -238,7 +234,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads)
          continue;
        }
       else if (do_hoist_loads
-                && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
+              && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
        {
          basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;
 
@@ -315,19 +311,20 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads)
 
          /* Something is wrong if we cannot find the arguments in the PHI
             node.  */
-         gcc_assert (arg0 != NULL && arg1 != NULL);
+         gcc_assert (arg0 != NULL_TREE && arg1 != NULL_TREE);
 
-         if (factor_out_conditional_conversion (e1, e2, phi, arg0, arg1))
+         gphi *newphi = factor_out_conditional_conversion (e1, e2, phi,
+                                                           arg0, arg1,
+                                                           cond_stmt);
+         if (newphi != NULL)
            {
+             phi = newphi;
              /* factor_out_conditional_conversion may create a new PHI in
                 BB2 and eliminate an existing PHI in BB2.  Recompute values
                 that may be affected by that change.  */
-             phis = phi_nodes (bb2);
-             phi = single_non_singleton_phi_for_edges (phis, e1, e2);
-             gcc_assert (phi);
              arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
              arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
-             gcc_assert (arg0 != NULL && arg1 != NULL);
+             gcc_assert (arg0 != NULL_TREE && arg1 != NULL_TREE);
            }
 
          /* Do the replacement of conditional if it can be done.  */
@@ -377,8 +374,7 @@ replace_phi_edge_with_variable (basic_block cond_block,
     {
       EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU;
       EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
-      EDGE_SUCC (cond_block, 0)->probability = REG_BR_PROB_BASE;
-      EDGE_SUCC (cond_block, 0)->count += EDGE_SUCC (cond_block, 1)->count;
+      EDGE_SUCC (cond_block, 0)->probability = profile_probability::always ();
 
       block_to_remove = EDGE_SUCC (cond_block, 1)->dest;
     }
@@ -387,8 +383,7 @@ replace_phi_edge_with_variable (basic_block cond_block,
       EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU;
       EDGE_SUCC (cond_block, 1)->flags
        &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
-      EDGE_SUCC (cond_block, 1)->probability = REG_BR_PROB_BASE;
-      EDGE_SUCC (cond_block, 1)->count += EDGE_SUCC (cond_block, 0)->count;
+      EDGE_SUCC (cond_block, 1)->probability = profile_probability::always ();
 
       block_to_remove = EDGE_SUCC (cond_block, 0)->dest;
     }
@@ -407,11 +402,12 @@ replace_phi_edge_with_variable (basic_block cond_block,
 
 /* PR66726: Factor conversion out of COND_EXPR.  If the arguments of the PHI
    stmt are CONVERT_STMT, factor out the conversion and perform the conversion
-   to the result of PHI stmt.  */
+   to the result of PHI stmt.  COND_STMT is the controlling predicate.
+   Return the newly-created PHI, if any.  */
 
-static bool
+static gphi *
 factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
-                                  tree arg0, tree arg1)
+                                  tree arg0, tree arg1, gimple *cond_stmt)
 {
   gimple *arg0_def_stmt = NULL, *arg1_def_stmt = NULL, *new_stmt;
   tree new_arg0 = NULL_TREE, new_arg1 = NULL_TREE;
@@ -426,7 +422,7 @@ factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
      statement have the same unary operation, we can handle more
      than two arguments too.  */
   if (gimple_phi_num_args (phi) != 2)
-    return false;
+    return NULL;
 
   /* First canonicalize to simplify tests.  */
   if (TREE_CODE (arg0) != SSA_NAME)
@@ -438,20 +434,23 @@ factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
   if (TREE_CODE (arg0) != SSA_NAME
       || (TREE_CODE (arg1) != SSA_NAME
          && TREE_CODE (arg1) != INTEGER_CST))
-    return false;
+    return NULL;
 
   /* Check if arg0 is an SSA_NAME and the stmt which defines arg0 is
      a conversion.  */
   arg0_def_stmt = SSA_NAME_DEF_STMT (arg0);
-  if (!is_gimple_assign (arg0_def_stmt)
-      || !gimple_assign_cast_p (arg0_def_stmt))
-    return false;
+  if (!gimple_assign_cast_p (arg0_def_stmt))
+    return NULL;
 
   /* Use the RHS as new_arg0.  */
   convert_code = gimple_assign_rhs_code (arg0_def_stmt);
   new_arg0 = gimple_assign_rhs1 (arg0_def_stmt);
   if (convert_code == VIEW_CONVERT_EXPR)
-    new_arg0 = TREE_OPERAND (new_arg0, 0);
+    {
+      new_arg0 = TREE_OPERAND (new_arg0, 0);
+      if (!is_gimple_reg_type (TREE_TYPE (new_arg0)))
+       return NULL;
+    }
 
   if (TREE_CODE (arg1) == SSA_NAME)
     {
@@ -460,7 +459,7 @@ factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
       arg1_def_stmt = SSA_NAME_DEF_STMT (arg1);
       if (!is_gimple_assign (arg1_def_stmt)
          || gimple_assign_rhs_code (arg1_def_stmt) != convert_code)
-       return false;
+       return NULL;
 
       /* Use the RHS as new_arg1.  */
       new_arg1 = gimple_assign_rhs1 (arg1_def_stmt);
@@ -474,23 +473,47 @@ factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
          && int_fits_type_p (arg1, TREE_TYPE (new_arg0)))
        {
          if (gimple_assign_cast_p (arg0_def_stmt))
-           new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
+           {
+             /* For the INTEGER_CST case, we are just moving the
+                conversion from one place to another, which can often
+                hurt as the conversion moves further away from the
+                statement that computes the value.  So, perform this
+                only if new_arg0 is an operand of COND_STMT, or
+                if arg0_def_stmt is the only non-debug stmt in
+                its basic block, because then it is possible this
+                could enable further optimizations (minmax replacement
+                etc.).  See PR71016.  */
+             if (new_arg0 != gimple_cond_lhs (cond_stmt)
+                 && new_arg0 != gimple_cond_rhs (cond_stmt)
+                 && gimple_bb (arg0_def_stmt) == e0->src)
+               {
+                 gsi = gsi_for_stmt (arg0_def_stmt);
+                 gsi_prev_nondebug (&gsi);
+                 if (!gsi_end_p (gsi))
+                   return NULL;
+                 gsi = gsi_for_stmt (arg0_def_stmt);
+                 gsi_next_nondebug (&gsi);
+                 if (!gsi_end_p (gsi))
+                   return NULL;
+               }
+             new_arg1 = fold_convert (TREE_TYPE (new_arg0), arg1);
+           }
          else
-           return false;
+           return NULL;
        }
       else
-       return false;
+       return NULL;
     }
 
   /*  If arg0/arg1 have > 1 use, then this transformation actually increases
       the number of expressions evaluated at runtime.  */
   if (!has_single_use (arg0)
       || (arg1_def_stmt && !has_single_use (arg1)))
-    return false;
+    return NULL;
 
   /* If types of new_arg0 and new_arg1 are different bailout.  */
   if (!types_compatible_p (TREE_TYPE (new_arg0), TREE_TYPE (new_arg1)))
-    return false;
+    return NULL;
 
   /* Create a new PHI stmt.  */
   result = PHI_RESULT (phi);
@@ -500,21 +523,24 @@ factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "PHI ");
-      print_generic_expr (dump_file, gimple_phi_result (phi), 0);
+      print_generic_expr (dump_file, gimple_phi_result (phi));
       fprintf (dump_file,
               " changed to factor conversion out from COND_EXPR.\n");
       fprintf (dump_file, "New stmt with CAST that defines ");
-      print_generic_expr (dump_file, result, 0);
+      print_generic_expr (dump_file, result);
       fprintf (dump_file, ".\n");
     }
 
   /* Remove the old cast(s) that has single use.  */
   gsi_for_def = gsi_for_stmt (arg0_def_stmt);
   gsi_remove (&gsi_for_def, true);
+  release_defs (arg0_def_stmt);
+
   if (arg1_def_stmt)
     {
       gsi_for_def = gsi_for_stmt (arg1_def_stmt);
       gsi_remove (&gsi_for_def, true);
+      release_defs (arg1_def_stmt);
     }
 
   add_phi_arg (newphi, new_arg0, e0, locus);
@@ -523,14 +549,14 @@ factor_out_conditional_conversion (edge e0, edge e1, gphi *phi,
   /* Create the conversion stmt and insert it.  */
   if (convert_code == VIEW_CONVERT_EXPR)
     temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp);
-  new_stmt = gimple_build_assign (result,  convert_code, temp);
+  new_stmt = gimple_build_assign (result, convert_code, temp);
   gsi = gsi_after_labels (gimple_bb (phi));
   gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
 
-  /* Remove he original PHI stmt.  */
+  /* Remove the original PHI stmt.  */
   gsi = gsi_for_stmt (phi);
   gsi_remove (&gsi, true);
-  return true;
+  return newphi;
 }
 
 /*  The function conditional_replacement does the main work of doing the
@@ -663,12 +689,12 @@ jump_function_from_stmt (tree *arg, gimple *stmt)
     {
       /* For arg = &p->i transform it to p, if possible.  */
       tree rhs1 = gimple_assign_rhs1 (stmt);
-      HOST_WIDE_INT offset;
+      poly_int64 offset;
       tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs1, 0),
                                                &offset);
       if (tem
          && TREE_CODE (tem) == MEM_REF
-         && (mem_ref_offset (tem) + offset) == 0)
+         && known_eq (mem_ref_offset (tem) + offset, 0))
        {
          *arg = TREE_OPERAND (tem, 0);
          return true;
@@ -810,7 +836,7 @@ neutral_element_p (tree_code code, tree arg, bool right)
 /* Returns true if ARG is an absorbing element for operation CODE.  */
 
 static bool
-absorbing_element_p (tree_code code, tree arg)
+absorbing_element_p (tree_code code, tree arg, bool right, tree rval)
 {
   switch (code)
     {
@@ -821,6 +847,25 @@ absorbing_element_p (tree_code code, tree arg)
     case BIT_AND_EXPR:
       return integer_zerop (arg);
 
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      return !right && integer_zerop (arg);
+
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+      return (!right
+             && integer_zerop (arg)
+             && tree_single_nonzero_warnv_p (rval, NULL));
+
     default:
       return false;
     }
@@ -936,10 +981,10 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
              fprintf (dump_file, "PHI ");
-             print_generic_expr (dump_file, gimple_phi_result (phi), 0);
+             print_generic_expr (dump_file, gimple_phi_result (phi));
              fprintf (dump_file, " reduced for COND_EXPR in block %d to ",
                       cond_bb->index);
-             print_generic_expr (dump_file, arg, 0);
+             print_generic_expr (dump_file, arg);
              fprintf (dump_file, ".\n");
             }
           return 1;
@@ -947,11 +992,13 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
 
     }
 
-  /* Now optimize (x != 0) ? x + y : y to just y.
-     The following condition is too restrictive, there can easily be another
-     stmt in middle_bb, for instance a CONVERT_EXPR for the second argument.  */
-  gimple *assign = last_and_only_stmt (middle_bb);
-  if (!assign || gimple_code (assign) != GIMPLE_ASSIGN
+  /* Now optimize (x != 0) ? x + y : y to just x + y.  */
+  gsi = gsi_last_nondebug_bb (middle_bb);
+  if (gsi_end_p (gsi))
+    return 0;
+
+  gimple *assign = gsi_stmt (gsi);
+  if (!is_gimple_assign (assign)
       || gimple_assign_rhs_class (assign) != GIMPLE_BINARY_RHS
       || (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))
          && !POINTER_TYPE_P (TREE_TYPE (arg0))))
@@ -961,6 +1008,71 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
   if (!gimple_seq_empty_p (phi_nodes (middle_bb)))
     return 0;
 
+  /* Allow up to 2 cheap preparation statements that prepare argument
+     for assign, e.g.:
+      if (y_4 != 0)
+       goto <bb 3>;
+      else
+       goto <bb 4>;
+     <bb 3>:
+      _1 = (int) y_4;
+      iftmp.0_6 = x_5(D) r<< _1;
+     <bb 4>:
+      # iftmp.0_2 = PHI <iftmp.0_6(3), x_5(D)(2)>
+     or:
+      if (y_3(D) == 0)
+       goto <bb 4>;
+      else
+       goto <bb 3>;
+     <bb 3>:
+      y_4 = y_3(D) & 31;
+      _1 = (int) y_4;
+      _6 = x_5(D) r<< _1;
+     <bb 4>:
+      # _2 = PHI <x_5(D)(2), _6(3)>  */
+  gimple *prep_stmt[2] = { NULL, NULL };
+  int prep_cnt;
+  for (prep_cnt = 0; ; prep_cnt++)
+    {
+      gsi_prev_nondebug (&gsi);
+      if (gsi_end_p (gsi))
+       break;
+
+      gimple *g = gsi_stmt (gsi);
+      if (gimple_code (g) == GIMPLE_LABEL)
+       break;
+
+      if (prep_cnt == 2 || !is_gimple_assign (g))
+       return 0;
+
+      tree lhs = gimple_assign_lhs (g);
+      tree rhs1 = gimple_assign_rhs1 (g);
+      use_operand_p use_p;
+      gimple *use_stmt;
+      if (TREE_CODE (lhs) != SSA_NAME
+         || TREE_CODE (rhs1) != SSA_NAME
+         || !INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+         || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
+         || !single_imm_use (lhs, &use_p, &use_stmt)
+         || use_stmt != (prep_cnt ? prep_stmt[prep_cnt - 1] : assign))
+       return 0;
+      switch (gimple_assign_rhs_code (g))
+       {
+       CASE_CONVERT:
+         break;
+       case PLUS_EXPR:
+       case BIT_AND_EXPR:
+       case BIT_IOR_EXPR:
+       case BIT_XOR_EXPR:
+         if (TREE_CODE (gimple_assign_rhs2 (g)) != INTEGER_CST)
+           return 0;
+         break;
+       default:
+         return 0;
+       }
+      prep_stmt[prep_cnt] = g;
+    }
+
   /* Only transform if it removes the condition.  */
   if (!single_non_singleton_phi_for_edges (phi_nodes (gimple_bb (phi)), e0, e1))
     return 0;
@@ -969,9 +1081,9 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
   if (optimize_bb_for_speed_p (cond_bb)
       /* The special case is useless if it has a low probability.  */
       && profile_status_for_fn (cfun) != PROFILE_ABSENT
-      && EDGE_PRED (middle_bb, 0)->probability < PROB_EVEN
+      && EDGE_PRED (middle_bb, 0)->probability < profile_probability::even ()
       /* If assign is cheap, there is no point avoiding it.  */
-      && estimate_num_insns (assign, &eni_time_weights)
+      && estimate_num_insns (bb_seq (middle_bb), &eni_time_weights)
         >= 3 * estimate_num_insns (cond, &eni_time_weights))
     return 0;
 
@@ -982,6 +1094,32 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
   tree cond_lhs = gimple_cond_lhs (cond);
   tree cond_rhs = gimple_cond_rhs (cond);
 
+  /* Propagate the cond_rhs constant through preparation stmts,
+     make sure UB isn't invoked while doing that.  */
+  for (int i = prep_cnt - 1; i >= 0; --i)
+    {
+      gimple *g = prep_stmt[i];
+      tree grhs1 = gimple_assign_rhs1 (g);
+      if (!operand_equal_for_phi_arg_p (cond_lhs, grhs1))
+       return 0;
+      cond_lhs = gimple_assign_lhs (g);
+      cond_rhs = fold_convert (TREE_TYPE (grhs1), cond_rhs);
+      if (TREE_CODE (cond_rhs) != INTEGER_CST
+         || TREE_OVERFLOW (cond_rhs))
+       return 0;
+      if (gimple_assign_rhs_class (g) == GIMPLE_BINARY_RHS)
+       {
+         cond_rhs = int_const_binop (gimple_assign_rhs_code (g), cond_rhs,
+                                     gimple_assign_rhs2 (g));
+         if (TREE_OVERFLOW (cond_rhs))
+           return 0;
+       }
+      cond_rhs = fold_convert (TREE_TYPE (cond_lhs), cond_rhs);
+      if (TREE_CODE (cond_rhs) != INTEGER_CST
+         || TREE_OVERFLOW (cond_rhs))
+       return 0;
+    }
+
   if (((code == NE_EXPR && e1 == false_edge)
        || (code == EQ_EXPR && e1 == true_edge))
       && arg0 == lhs
@@ -992,28 +1130,29 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
              && operand_equal_for_phi_arg_p (rhs1, cond_lhs)
              && neutral_element_p (code_def, cond_rhs, false))
          || (operand_equal_for_phi_arg_p (arg1, cond_rhs)
-             && (operand_equal_for_phi_arg_p (rhs2, cond_lhs)
-                 || operand_equal_for_phi_arg_p (rhs1, cond_lhs))
-             && absorbing_element_p (code_def, cond_rhs))))
+             && ((operand_equal_for_phi_arg_p (rhs2, cond_lhs)
+                  && absorbing_element_p (code_def, cond_rhs, true, rhs2))
+                 || (operand_equal_for_phi_arg_p (rhs1, cond_lhs)
+                     && absorbing_element_p (code_def,
+                                             cond_rhs, false, rhs2))))))
     {
       gsi = gsi_for_stmt (cond);
+      /* Moving ASSIGN might change VR of lhs, e.g. when moving u_6
+        def-stmt in:
+          if (n_5 != 0)
+            goto <bb 3>;
+          else
+            goto <bb 4>;
+
+          <bb 3>:
+          # RANGE [0, 4294967294]
+          u_6 = n_5 + 4294967295;
+
+          <bb 4>:
+          # u_3 = PHI <u_6(3), 4294967295(2)>  */
+      reset_flow_sensitive_info (lhs);
       if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
        {
-         /* Moving ASSIGN might change VR of lhs, e.g. when moving u_6
-            def-stmt in:
-            if (n_5 != 0)
-              goto <bb 3>;
-            else
-              goto <bb 4>;
-
-            <bb 3>:
-            # RANGE [0, 4294967294]
-            u_6 = n_5 + 4294967295;
-
-            <bb 4>:
-            # u_3 = PHI <u_6(3), 4294967295(2)>  */
-         SSA_NAME_RANGE_INFO (lhs) = NULL;
-         SSA_NAME_ANTI_RANGE_P (lhs) = 0;
          /* If available, we can use VR of phi result at least.  */
          tree phires = gimple_phi_result (phi);
          struct range_info_def *phires_range_info
@@ -1022,7 +1161,15 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
            duplicate_ssa_name_range_info (lhs, SSA_NAME_RANGE_TYPE (phires),
                                           phires_range_info);
        }
-      gimple_stmt_iterator gsi_from = gsi_for_stmt (assign);
+      gimple_stmt_iterator gsi_from;
+      for (int i = prep_cnt - 1; i >= 0; --i)
+       {
+         tree plhs = gimple_assign_lhs (prep_stmt[i]);
+         reset_flow_sensitive_info (plhs);
+         gsi_from = gsi_for_stmt (prep_stmt[i]);
+         gsi_move_before (&gsi_from, &gsi);
+       }
+      gsi_from = gsi_for_stmt (assign);
       gsi_move_before (&gsi_from, &gsi);
       replace_phi_edge_with_variable (cond_bb, e1, phi, lhs);
       return 2;
@@ -1047,13 +1194,13 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
   gassign *new_stmt;
   edge true_edge, false_edge;
   enum tree_code cmp, minmax, ass_code;
-  tree smaller, larger, arg_true, arg_false;
+  tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false;
   gimple_stmt_iterator gsi, gsi_from;
 
   type = TREE_TYPE (PHI_RESULT (phi));
 
   /* The optimization may be unsafe due to NaNs.  */
-  if (HONOR_NANS (type))
+  if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type))
     return false;
 
   cond = as_a <gcond *> (last_stmt (cond_bb));
@@ -1061,15 +1208,63 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
 
   /* This transformation is only valid for order comparisons.  Record which
      operand is smaller/larger if the result of the comparison is true.  */
+  alt_smaller = NULL_TREE;
+  alt_larger = NULL_TREE;
   if (cmp == LT_EXPR || cmp == LE_EXPR)
     {
       smaller = gimple_cond_lhs (cond);
       larger = gimple_cond_rhs (cond);
+      /* If we have smaller < CST it is equivalent to smaller <= CST-1.
+        Likewise smaller <= CST is equivalent to smaller < CST+1.  */
+      if (TREE_CODE (larger) == INTEGER_CST)
+       {
+         if (cmp == LT_EXPR)
+           {
+             bool overflow;
+             wide_int alt = wi::sub (wi::to_wide (larger), 1,
+                                     TYPE_SIGN (TREE_TYPE (larger)),
+                                     &overflow);
+             if (! overflow)
+               alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
+           }
+         else
+           {
+             bool overflow;
+             wide_int alt = wi::add (wi::to_wide (larger), 1,
+                                     TYPE_SIGN (TREE_TYPE (larger)),
+                                     &overflow);
+             if (! overflow)
+               alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
+           }
+       }
     }
   else if (cmp == GT_EXPR || cmp == GE_EXPR)
     {
       smaller = gimple_cond_rhs (cond);
       larger = gimple_cond_lhs (cond);
+      /* If we have larger > CST it is equivalent to larger >= CST+1.
+        Likewise larger >= CST is equivalent to larger > CST-1.  */
+      if (TREE_CODE (smaller) == INTEGER_CST)
+       {
+         if (cmp == GT_EXPR)
+           {
+             bool overflow;
+             wide_int alt = wi::add (wi::to_wide (smaller), 1,
+                                     TYPE_SIGN (TREE_TYPE (smaller)),
+                                     &overflow);
+             if (! overflow)
+               alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
+           }
+         else
+           {
+             bool overflow;
+             wide_int alt = wi::sub (wi::to_wide (smaller), 1,
+                                     TYPE_SIGN (TREE_TYPE (smaller)),
+                                     &overflow);
+             if (! overflow)
+               alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
+           }
+       }
     }
   else
     return false;
@@ -1100,8 +1295,12 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
 
   if (empty_block_p (middle_bb))
     {
-      if (operand_equal_for_phi_arg_p (arg_true, smaller)
-         && operand_equal_for_phi_arg_p (arg_false, larger))
+      if ((operand_equal_for_phi_arg_p (arg_true, smaller)
+          || (alt_smaller
+              && operand_equal_for_phi_arg_p (arg_true, alt_smaller)))
+         && (operand_equal_for_phi_arg_p (arg_false, larger)
+             || (alt_larger
+                 && operand_equal_for_phi_arg_p (arg_true, alt_larger))))
        {
          /* Case
 
@@ -1111,8 +1310,12 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
             rslt = larger;  */
          minmax = MIN_EXPR;
        }
-      else if (operand_equal_for_phi_arg_p (arg_false, smaller)
-              && operand_equal_for_phi_arg_p (arg_true, larger))
+      else if ((operand_equal_for_phi_arg_p (arg_false, smaller)
+               || (alt_smaller
+                   && operand_equal_for_phi_arg_p (arg_false, alt_smaller)))
+              && (operand_equal_for_phi_arg_p (arg_true, larger)
+                  || (alt_larger
+                      && operand_equal_for_phi_arg_p (arg_true, alt_larger))))
        minmax = MAX_EXPR;
       else
        return false;
@@ -1150,7 +1353,9 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
          if (!operand_equal_for_phi_arg_p (lhs, arg_true))
            return false;
 
-         if (operand_equal_for_phi_arg_p (arg_false, larger))
+         if (operand_equal_for_phi_arg_p (arg_false, larger)
+             || (alt_larger
+                 && operand_equal_for_phi_arg_p (arg_false, alt_larger)))
            {
              /* Case
 
@@ -1163,9 +1368,13 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                return false;
 
              minmax = MIN_EXPR;
-             if (operand_equal_for_phi_arg_p (op0, smaller))
+             if (operand_equal_for_phi_arg_p (op0, smaller)
+                 || (alt_smaller
+                     && operand_equal_for_phi_arg_p (op0, alt_smaller)))
                bound = op1;
-             else if (operand_equal_for_phi_arg_p (op1, smaller))
+             else if (operand_equal_for_phi_arg_p (op1, smaller)
+                      || (alt_smaller
+                          && operand_equal_for_phi_arg_p (op1, alt_smaller)))
                bound = op0;
              else
                return false;
@@ -1175,7 +1384,9 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                                                  bound, larger)))
                return false;
            }
-         else if (operand_equal_for_phi_arg_p (arg_false, smaller))
+         else if (operand_equal_for_phi_arg_p (arg_false, smaller)
+                  || (alt_smaller
+                      && operand_equal_for_phi_arg_p (arg_false, alt_smaller)))
            {
              /* Case
 
@@ -1188,9 +1399,13 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                return false;
 
              minmax = MAX_EXPR;
-             if (operand_equal_for_phi_arg_p (op0, larger))
+             if (operand_equal_for_phi_arg_p (op0, larger)
+                 || (alt_larger
+                     && operand_equal_for_phi_arg_p (op0, alt_larger)))
                bound = op1;
-             else if (operand_equal_for_phi_arg_p (op1, larger))
+             else if (operand_equal_for_phi_arg_p (op1, larger)
+                      || (alt_larger
+                          && operand_equal_for_phi_arg_p (op1, alt_larger)))
                bound = op0;
              else
                return false;
@@ -1209,7 +1424,9 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
          if (!operand_equal_for_phi_arg_p (lhs, arg_false))
            return false;
 
-         if (operand_equal_for_phi_arg_p (arg_true, larger))
+         if (operand_equal_for_phi_arg_p (arg_true, larger)
+             || (alt_larger
+                 && operand_equal_for_phi_arg_p (arg_true, alt_larger)))
            {
              /* Case
 
@@ -1222,9 +1439,13 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                return false;
 
              minmax = MAX_EXPR;
-             if (operand_equal_for_phi_arg_p (op0, smaller))
+             if (operand_equal_for_phi_arg_p (op0, smaller)
+                 || (alt_smaller
+                     && operand_equal_for_phi_arg_p (op0, alt_smaller)))
                bound = op1;
-             else if (operand_equal_for_phi_arg_p (op1, smaller))
+             else if (operand_equal_for_phi_arg_p (op1, smaller)
+                      || (alt_smaller
+                          && operand_equal_for_phi_arg_p (op1, alt_smaller)))
                bound = op0;
              else
                return false;
@@ -1234,7 +1455,9 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
                                                  bound, larger)))
                return false;
            }
-         else if (operand_equal_for_phi_arg_p (arg_true, smaller))
+         else if (operand_equal_for_phi_arg_p (arg_true, smaller)
+                  || (alt_smaller
+                      && operand_equal_for_phi_arg_p (arg_true, alt_smaller)))
            {
              /* Case
 
@@ -1266,6 +1489,8 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
       /* Move the statement from the middle block.  */
       gsi = gsi_last_bb (cond_bb);
       gsi_from = gsi_last_nondebug_bb (middle_bb);
+      reset_flow_sensitive_info (SINGLE_SSA_TREE_OPERAND (gsi_stmt (gsi_from),
+                                                         SSA_OP_DEF));
       gsi_move_before (&gsi_from, &gsi);
     }
 
@@ -1284,6 +1509,7 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
   gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
 
   replace_phi_edge_with_variable (cond_bb, e1, phi, result);
+
   return true;
 }
 
@@ -1378,6 +1604,14 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
   else
     negate = false;
 
+  /* If the code negates only iff positive then make sure to not
+     introduce undefined behavior when negating or computing the absolute.
+     ???  We could use range info if present to check for arg1 == INT_MIN.  */
+  if (negate
+      && (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+         && ! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))))
+    return false;
+
   result = duplicate_ssa_name (result, NULL);
 
   if (negate)
@@ -1476,7 +1710,7 @@ public:
   nontrapping_dom_walker (cdi_direction direction, hash_set<tree> *ps)
     : dom_walker (direction), m_nontrapping (ps), m_seen_ssa_names (128) {}
 
-  virtual void before_dom_children (basic_block);
+  virtual edge before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
 
 private:
@@ -1495,7 +1729,7 @@ private:
 };
 
 /* Called by walk_dominator_tree, when entering the block BB.  */
-void
+edge
 nontrapping_dom_walker::before_dom_children (basic_block bb)
 {
   edge e;
@@ -1518,7 +1752,9 @@ nontrapping_dom_walker::before_dom_children (basic_block bb)
     {
       gimple *stmt = gsi_stmt (gsi);
 
-      if (is_gimple_call (stmt) && !nonfreeing_call_p (stmt))
+      if ((gimple_code (stmt) == GIMPLE_ASM && gimple_vdef (stmt))
+         || (is_gimple_call (stmt)
+             && (!nonfreeing_call_p (stmt) || !nonbarrier_call_p (stmt))))
        nt_call_phase++;
       else if (gimple_assign_single_p (stmt) && !gimple_has_volatile_ops (stmt))
        {
@@ -1526,6 +1762,7 @@ nontrapping_dom_walker::before_dom_children (basic_block bb)
          add_or_mark_expr (bb, gimple_assign_rhs1 (stmt), false);
        }
     }
+  return NULL;
 }
 
 /* Called by walk_dominator_tree, when basic block BB is exited.  */
@@ -1674,9 +1911,24 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
   gsi_remove (&gsi, true);
   release_defs (assign);
 
+  /* Make both store and load use alias-set zero as we have to
+     deal with the case of the store being a conditional change
+     of the dynamic type.  */
+  lhs = unshare_expr (lhs);
+  tree *basep = &lhs;
+  while (handled_component_p (*basep))
+    basep = &TREE_OPERAND (*basep, 0);
+  if (TREE_CODE (*basep) == MEM_REF
+      || TREE_CODE (*basep) == TARGET_MEM_REF)
+    TREE_OPERAND (*basep, 1)
+      = fold_convert (ptr_type_node, TREE_OPERAND (*basep, 1));
+  else
+    *basep = build2 (MEM_REF, TREE_TYPE (*basep),
+                    build_fold_addr_expr (*basep),
+                    build_zero_cst (ptr_type_node));
+
   /* 2) Insert a load from the memory of the store to the temporary
         on the edge which did not contain the store.  */
-  lhs = unshare_expr (lhs);
   name = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "cstore");
   new_stmt = gimple_build_assign (name, lhs);
   gimple_set_location (new_stmt, locus);