]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/gimple-ssa-evrp.c
rs6000: New iterator CCEITHER
[thirdparty/gcc.git] / gcc / gimple-ssa-evrp.c
index 13ba31d7cd7f08dae8384ad729fbac6cce726a24..5b993886912c62379b28acdc06346ecf501349d7 100644 (file)
@@ -1,5 +1,5 @@
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005-2017 Free Software Foundation, Inc.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -40,13 +40,19 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "tree-cfgcleanup.h"
 #include "vr-values.h"
+#include "gimple-ssa-evrp-analyze.h"
 
 class evrp_folder : public substitute_and_fold_engine
 {
  public:
   tree get_value (tree) FINAL OVERRIDE;
-
+  evrp_folder (class vr_values *vr_values_) : vr_values (vr_values_) { }
+  bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
+    { return vr_values->simplify_stmt_using_ranges (gsi); }
   class vr_values *vr_values;
+
+ private:
+  DISABLE_COPY_AND_ASSIGN (evrp_folder);
 };
 
 tree
@@ -63,7 +69,9 @@ class evrp_dom_walker : public dom_walker
 {
 public:
   evrp_dom_walker ()
-    : dom_walker (CDI_DOMINATORS), stack (10)
+    : dom_walker (CDI_DOMINATORS),
+      evrp_range_analyzer (true),
+      evrp_folder (evrp_range_analyzer.get_vr_values ())
     {
       need_eh_cleanup = BITMAP_ALLOC (NULL);
     }
@@ -73,145 +81,25 @@ public:
     }
   virtual edge before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
-  void push_value_range (tree var, value_range *vr);
-  value_range *pop_value_range (tree var);
-  value_range *try_find_new_range (tree, tree op, tree_code code, tree limit);
+  void cleanup (void);
 
-  /* Cond_stack holds the old VR.  */
-  auto_vec<std::pair <tree, value_range*> > stack;
+ private:
+  DISABLE_COPY_AND_ASSIGN (evrp_dom_walker);
   bitmap need_eh_cleanup;
   auto_vec<gimple *> stmts_to_fixup;
   auto_vec<gimple *> stmts_to_remove;
 
-  class vr_values vr_values;
-
-  /* Temporary delegators.  */
-  value_range *get_value_range (const_tree op)
-    { return vr_values.get_value_range (op); }
-  bool update_value_range (const_tree op, value_range *vr)
-    { return vr_values.update_value_range (op, vr); }
-  void extract_range_from_phi_node (gphi *phi, value_range *vr)
-    { vr_values.extract_range_from_phi_node (phi, vr); }
-  void extract_range_for_var_from_comparison_expr (tree var,
-                                                  enum tree_code cond_code,
-                                                  tree op, tree limit,
-                                                  value_range *vr_p)
-    { vr_values.extract_range_for_var_from_comparison_expr (var, cond_code,
-                                                           op, limit, vr_p); }
-  void adjust_range_with_scev (value_range *vr, struct loop *loop,
-                              gimple *stmt, tree var)
-    { vr_values.adjust_range_with_scev (vr, loop, stmt, var); }
-  tree op_with_constant_singleton_value_range (tree op)
-    { return vr_values.op_with_constant_singleton_value_range (op); }
-  void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
-                               tree *output_p, value_range *vr)
-    { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); }
-  void set_defs_to_varying (gimple *stmt)
-    { return vr_values.set_defs_to_varying (stmt); }
-  void set_vr_value (tree name, value_range *vr)
-    { vr_values.set_vr_value (name, vr); }
-  void simplify_cond_using_ranges_2 (gcond *stmt)
-    { vr_values.simplify_cond_using_ranges_2 (stmt); }
-  void vrp_visit_cond_stmt (gcond *cond, edge *e)
-    { vr_values.vrp_visit_cond_stmt (cond, e); }
+  class evrp_range_analyzer evrp_range_analyzer;
+  class evrp_folder evrp_folder;
 };
 
-/*  Find new range for NAME such that (OP CODE LIMIT) is true.  */
-
-value_range *
-evrp_dom_walker::try_find_new_range (tree name,
-                                    tree op, tree_code code, tree limit)
-{
-  value_range vr = VR_INITIALIZER;
-  value_range *old_vr = get_value_range (name);
-
-  /* Discover VR when condition is true.  */
-  extract_range_for_var_from_comparison_expr (name, code, op,
-                                             limit, &vr);
-  /* If we found any usable VR, set the VR to ssa_name and create a
-     PUSH old value in the stack with the old VR.  */
-  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
-    {
-      if (old_vr->type == vr.type
-         && vrp_operand_equal_p (old_vr->min, vr.min)
-         && vrp_operand_equal_p (old_vr->max, vr.max))
-       return NULL;
-      value_range *new_vr = vr_values.vrp_value_range_pool.allocate ();
-      *new_vr = vr;
-      return new_vr;
-    }
-  return NULL;
-}
-
-/* See if there is any new scope is entered with new VR and set that VR to
-   ssa_name before visiting the statements in the scope.  */
-
 edge
 evrp_dom_walker::before_dom_children (basic_block bb)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "Visiting BB%d\n", bb->index);
 
-  stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL));
-
-  edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false);
-  if (pred_e)
-    {
-      gimple *stmt = last_stmt (pred_e->src);
-      tree op0 = NULL_TREE;
-
-      if (stmt
-         && gimple_code (stmt) == GIMPLE_COND
-         && (op0 = gimple_cond_lhs (stmt))
-         && TREE_CODE (op0) == SSA_NAME
-         && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
-             || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "Visiting controlling predicate ");
-             print_gimple_stmt (dump_file, stmt, 0);
-           }
-         /* Entering a new scope.  Try to see if we can find a VR
-            here.  */
-         tree op1 = gimple_cond_rhs (stmt);
-         if (TREE_OVERFLOW_P (op1))
-           op1 = drop_tree_overflow (op1);
-         tree_code code = gimple_cond_code (stmt);
-
-         auto_vec<assert_info, 8> asserts;
-         register_edge_assert_for (op0, pred_e, code, op0, op1, asserts);
-         if (TREE_CODE (op1) == SSA_NAME)
-           register_edge_assert_for (op1, pred_e, code, op0, op1, asserts);
-
-         auto_vec<std::pair<tree, value_range *>, 8> vrs;
-         for (unsigned i = 0; i < asserts.length (); ++i)
-           {
-             value_range *vr = try_find_new_range (asserts[i].name,
-                                                   asserts[i].expr,
-                                                   asserts[i].comp_code,
-                                                   asserts[i].val);
-             if (vr)
-               vrs.safe_push (std::make_pair (asserts[i].name, vr));
-           }
-         /* Push updated ranges only after finding all of them to avoid
-            ordering issues that can lead to worse ranges.  */
-         for (unsigned i = 0; i < vrs.length (); ++i)
-           push_value_range (vrs[i].first, vrs[i].second);
-       }
-    }
-
-  /* Visit PHI stmts and discover any new VRs possible.  */
-  bool has_unvisited_preds = false;
-  edge_iterator ei;
-  edge e;
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    if (e->flags & EDGE_EXECUTABLE
-       && !(e->src->flags & BB_VISITED))
-      {
-       has_unvisited_preds = true;
-       break;
-      }
+  evrp_range_analyzer.enter (bb);
 
   for (gphi_iterator gpi = gsi_start_phis (bb);
        !gsi_end_p (gpi); gsi_next (&gpi))
@@ -220,58 +108,15 @@ evrp_dom_walker::before_dom_children (basic_block bb)
       tree lhs = PHI_RESULT (phi);
       if (virtual_operand_p (lhs))
        continue;
-      value_range vr_result = VR_INITIALIZER;
-      bool interesting = stmt_interesting_for_vrp (phi);
-      if (interesting && dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Visiting PHI node ");
-         print_gimple_stmt (dump_file, phi, 0);
-       }
-      if (!has_unvisited_preds
-         && interesting)
-       extract_range_from_phi_node (phi, &vr_result);
-      else
-       {
-         set_value_range_to_varying (&vr_result);
-         /* When we have an unvisited executable predecessor we can't
-            use PHI arg ranges which may be still UNDEFINED but have
-            to use VARYING for them.  But we can still resort to
-            SCEV for loop header PHIs.  */
-         struct loop *l;
-         if (interesting
-             && (l = loop_containing_stmt (phi))
-             && l->header == gimple_bb (phi))
-           adjust_range_with_scev (&vr_result, l, phi, lhs);
-       }
-      update_value_range (lhs, &vr_result);
 
+      value_range *vr = evrp_range_analyzer.get_value_range (lhs);
       /* Mark PHIs whose lhs we fully propagate for removal.  */
-      tree val = op_with_constant_singleton_value_range (lhs);
-      if (val && may_propagate_copy (lhs, val))
+      tree val;
+      if (vr->singleton_p (&val) && may_propagate_copy (lhs, val))
        {
          stmts_to_remove.safe_push (phi);
          continue;
        }
-
-      /* Set the SSA with the value range.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-       {
-         if ((vr_result.type == VR_RANGE
-              || vr_result.type == VR_ANTI_RANGE)
-             && (TREE_CODE (vr_result.min) == INTEGER_CST)
-             && (TREE_CODE (vr_result.max) == INTEGER_CST))
-           set_range_info (lhs, vr_result.type,
-                           wi::to_wide (vr_result.min),
-                           wi::to_wide (vr_result.max));
-       }
-      else if (POINTER_TYPE_P (TREE_TYPE (lhs))
-              && ((vr_result.type == VR_RANGE
-                   && range_includes_zero_p (vr_result.min,
-                                             vr_result.max) == 0)
-                  || (vr_result.type == VR_ANTI_RANGE
-                      && range_includes_zero_p (vr_result.min,
-                                                vr_result.max) == 1)))
-       set_ptr_nonnull (lhs);
     }
 
   edge taken_edge = NULL;
@@ -292,9 +137,11 @@ evrp_dom_walker::before_dom_children (basic_block bb)
          print_gimple_stmt (dump_file, stmt, 0);
        }
 
+      evrp_range_analyzer.record_ranges_from_stmt (stmt, false);
+
       if (gcond *cond = dyn_cast <gcond *> (stmt))
        {
-         vrp_visit_cond_stmt (cond, &taken_edge);
+         evrp_range_analyzer.vrp_visit_cond_stmt (cond, &taken_edge);
          if (taken_edge)
            {
              if (taken_edge->flags & EDGE_TRUE_VALUE)
@@ -308,105 +155,28 @@ evrp_dom_walker::before_dom_children (basic_block bb)
        }
       else if (stmt_interesting_for_vrp (stmt))
        {
-         edge taken_edge;
-         value_range vr = VR_INITIALIZER;
-         extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
-         if (output
-             && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
+         output = get_output_for_vrp (stmt);
+         if (output)
            {
-             update_value_range (output, &vr);
-             vr = *get_value_range (output);
+             tree val;
+             value_range *vr = evrp_range_analyzer.get_value_range (output);
 
              /* Mark stmts whose output we fully propagate for removal.  */
-             tree val;
-             if ((val = op_with_constant_singleton_value_range (output))
+             if (vr->singleton_p (&val)
                  && may_propagate_copy (output, val)
-                 && !stmt_could_throw_p (stmt)
+                 && !stmt_could_throw_p (cfun, stmt)
                  && !gimple_has_side_effects (stmt))
                {
                  stmts_to_remove.safe_push (stmt);
                  continue;
                }
-
-             /* Set the SSA with the value range.  */
-             if (INTEGRAL_TYPE_P (TREE_TYPE (output)))
-               {
-                 if ((vr.type == VR_RANGE
-                      || vr.type == VR_ANTI_RANGE)
-                     && (TREE_CODE (vr.min) == INTEGER_CST)
-                     && (TREE_CODE (vr.max) == INTEGER_CST))
-                   set_range_info (output, vr.type,
-                                   wi::to_wide (vr.min),
-                                   wi::to_wide (vr.max));
-               }
-             else if (POINTER_TYPE_P (TREE_TYPE (output))
-                      && ((vr.type == VR_RANGE
-                           && range_includes_zero_p (vr.min,
-                                                     vr.max) == 0)
-                          || (vr.type == VR_ANTI_RANGE
-                              && range_includes_zero_p (vr.min,
-                                                        vr.max) == 1)))
-               set_ptr_nonnull (output);
-           }
-         else
-           set_defs_to_varying (stmt);
-       }
-      else
-       set_defs_to_varying (stmt);
-
-      /* See if we can derive a range for any of STMT's operands.  */
-      tree op;
-      ssa_op_iter i;
-      FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE)
-       {
-         tree value;
-         enum tree_code comp_code;
-
-         /* If OP is used in such a way that we can infer a value
-            range for it, and we don't find a previous assertion for
-            it, create a new assertion location node for OP.  */
-         if (infer_value_range (stmt, op, &comp_code, &value))
-           {
-             /* If we are able to infer a nonzero value range for OP,
-                then walk backwards through the use-def chain to see if OP
-                was set via a typecast.
-                If so, then we can also infer a nonzero value range
-                for the operand of the NOP_EXPR.  */
-             if (comp_code == NE_EXPR && integer_zerop (value))
-               {
-                 tree t = op;
-                 gimple *def_stmt = SSA_NAME_DEF_STMT (t);
-                 while (is_gimple_assign (def_stmt)
-                        && CONVERT_EXPR_CODE_P
-                             (gimple_assign_rhs_code (def_stmt))
-                        && TREE_CODE
-                             (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
-                        && POINTER_TYPE_P
-                             (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
-                   {
-                     t = gimple_assign_rhs1 (def_stmt);
-                     def_stmt = SSA_NAME_DEF_STMT (t);
-
-                     /* Add VR when (T COMP_CODE value) condition is
-                        true.  */
-                     value_range *op_range
-                       = try_find_new_range (t, t, comp_code, value);
-                     if (op_range)
-                       push_value_range (t, op_range);
-                   }
-               }
-             /* Add VR when (OP COMP_CODE value) condition is true.  */
-             value_range *op_range = try_find_new_range (op, op,
-                                                         comp_code, value);
-             if (op_range)
-               push_value_range (op, op_range);
            }
        }
 
       /* Try folding stmts with the VR discovered.  */
-      class evrp_folder evrp_folder;
-      evrp_folder.vr_values = &vr_values;
       bool did_replace = evrp_folder.replace_uses_in (stmt);
+      gimple_stmt_iterator prev_gsi = gsi;
+      gsi_prev (&prev_gsi);
       if (fold_stmt (&gsi, follow_single_use_edges)
          || did_replace)
        {
@@ -414,9 +184,30 @@ evrp_dom_walker::before_dom_children (basic_block bb)
          update_stmt (stmt);
          did_replace = true;
        }
+      if (evrp_folder.simplify_stmt_using_ranges (&gsi))
+       {
+         stmt = gsi_stmt (gsi);
+         update_stmt (stmt);
+         did_replace = true;
+       }
 
       if (did_replace)
        {
+         /* If we wound up generating new stmts during folding
+            drop all their defs to VARYING.  We can't easily
+            process them because we've already instantiated
+            ranges on uses on STMT that only hold after it.  */
+         if (gsi_end_p (prev_gsi))
+           prev_gsi = gsi_start_bb (bb);
+         else
+           gsi_next (&prev_gsi);
+         while (gsi_stmt (prev_gsi) != gsi_stmt (gsi))
+           {
+             evrp_range_analyzer.get_vr_values ()
+               ->set_defs_to_varying (gsi_stmt (prev_gsi));
+             gsi_next (&prev_gsi);
+           }
+
          /* If we cleaned up EH information from the statement,
             remove EH edges.  */
          if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
@@ -439,6 +230,8 @@ evrp_dom_walker::before_dom_children (basic_block bb)
     }
 
   /* Visit BB successor PHI nodes and replace PHI args.  */
+  edge e;
+  edge_iterator ei;
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
       for (gphi_iterator gpi = gsi_start_phis (e->dest);
@@ -450,103 +243,38 @@ evrp_dom_walker::before_dom_children (basic_block bb)
          if (TREE_CODE (arg) != SSA_NAME
              || virtual_operand_p (arg))
            continue;
-         tree val = op_with_constant_singleton_value_range (arg);
-         if (val && may_propagate_copy (arg, val))
+         value_range *vr = evrp_range_analyzer.get_value_range (arg);
+         tree val;
+         if (vr->singleton_p (&val) && may_propagate_copy (arg, val))
            propagate_value (use_p, val);
        }
     }
  
-  bb->flags |= BB_VISITED;
-
   return taken_edge;
 }
 
-/* Restore/pop VRs valid only for BB when we leave BB.  */
-
 void
-evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
+evrp_dom_walker::after_dom_children (basic_block bb)
 {
-  gcc_checking_assert (!stack.is_empty ());
-  while (stack.last ().first != NULL_TREE)
-    pop_value_range (stack.last ().first);
-  stack.pop ();
+  evrp_range_analyzer.leave (bb);
 }
 
-/* Push the Value Range of VAR to the stack and update it with new VR.  */
+/* Perform any cleanups after the main phase of EVRP has completed.  */
 
 void
-evrp_dom_walker::push_value_range (tree var, value_range *vr)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "pushing new range for ");
-      print_generic_expr (dump_file, var);
-      fprintf (dump_file, ": ");
-      dump_value_range (dump_file, vr);
-      fprintf (dump_file, "\n");
-    }
-  stack.safe_push (std::make_pair (var, get_value_range (var)));
-  set_vr_value (var, vr);
-}
-
-/* Pop the Value Range from the vrp_stack and update VAR with it.  */
-
-value_range *
-evrp_dom_walker::pop_value_range (tree var)
-{
-  value_range *vr = stack.last ().second;
-  gcc_checking_assert (var == stack.last ().first);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "popping range for ");
-      print_generic_expr (dump_file, var);
-      fprintf (dump_file, ", restoring ");
-      dump_value_range (dump_file, vr);
-      fprintf (dump_file, "\n");
-    }
-  set_vr_value (var, vr);
-  stack.pop ();
-  return vr;
-}
-
-
-/* Main entry point for the early vrp pass which is a simplified non-iterative
-   version of vrp where basic blocks are visited in dominance order.  Value
-   ranges discovered in early vrp will also be used by ipa-vrp.  */
-
-static unsigned int
-execute_early_vrp ()
+evrp_dom_walker::cleanup (void)
 {
-  edge e;
-  edge_iterator ei;
-  basic_block bb;
-
-  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
-  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
-  scev_initialize ();
-  calculate_dominance_info (CDI_DOMINATORS);
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      bb->flags &= ~BB_VISITED;
-      FOR_EACH_EDGE (e, ei, bb->preds)
-       e->flags |= EDGE_EXECUTABLE;
-    }
-
-  /* Walk stmts in dominance order and propagate VRP.  */
-  evrp_dom_walker walker;
-  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
   if (dump_file)
     {
       fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
-      walker.vr_values.dump_all_value_ranges (dump_file);
+      evrp_range_analyzer.dump_all_value_ranges (dump_file);
       fprintf (dump_file, "\n");
     }
 
   /* Remove stmts in reverse order to make debug stmt creation possible.  */
-  while (! walker.stmts_to_remove.is_empty ())
+  while (! stmts_to_remove.is_empty ())
     {
-      gimple *stmt = walker.stmts_to_remove.pop ();
+      gimple *stmt = stmts_to_remove.pop ();
       if (dump_file && dump_flags & TDF_DETAILS)
        {
          fprintf (dump_file, "Removing dead stmt ");
@@ -564,19 +292,43 @@ execute_early_vrp ()
        }
     }
 
-  if (!bitmap_empty_p (walker.need_eh_cleanup))
-    gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
+  if (!bitmap_empty_p (need_eh_cleanup))
+    gimple_purge_all_dead_eh_edges (need_eh_cleanup);
 
   /* Fixup stmts that became noreturn calls.  This may require splitting
      blocks and thus isn't possible during the dominator walk.  Do this
      in reverse order so we don't inadvertedly remove a stmt we want to
      fixup by visiting a dominating now noreturn call first.  */
-  while (!walker.stmts_to_fixup.is_empty ())
+  while (!stmts_to_fixup.is_empty ())
     {
-      gimple *stmt = walker.stmts_to_fixup.pop ();
+      gimple *stmt = stmts_to_fixup.pop ();
       fixup_noreturn_call (stmt);
     }
 
+  evrp_folder.vr_values->cleanup_edges_and_switches ();
+}
+
+/* Main entry point for the early vrp pass which is a simplified non-iterative
+   version of vrp where basic blocks are visited in dominance order.  Value
+   ranges discovered in early vrp will also be used by ipa-vrp.  */
+
+static unsigned int
+execute_early_vrp ()
+{
+  /* Ideally this setup code would move into the ctor for the dominator
+     walk.  However, this setup can change the number of blocks which
+     invalidates the internal arrays that are set up by the dominator
+     walker.  */
+  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
+  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
+  scev_initialize ();
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  /* Walk stmts in dominance order and propagate VRP.  */
+  evrp_dom_walker walker;
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  walker.cleanup ();
+
   scev_finalize ();
   loop_optimizer_finalize ();
   return 0;