]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/gimple-if-to-switch.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / gimple-if-to-switch.cc
index 311f6f6ac97cde24f65460539ae4ee8a18bda5a7..8b3a499ac2120bf963c0d058d00c858745ccd910 100644 (file)
@@ -1,5 +1,5 @@
 /* If-elseif-else to switch conversion pass
-   Copyright (C) 2020 Free Software Foundation, Inc.
+   Copyright (C) 2020-2024 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -59,11 +59,13 @@ using namespace tree_switch_conversion;
 
 struct condition_info
 {
-  typedef vec<std::pair<gphi *, tree>> mapping_vec;
+  typedef auto_vec<std::pair<gphi *, tree>> mapping_vec;
 
-  condition_info (gcond *cond): m_cond (cond), m_bb (gimple_bb (cond)),
-    m_forwarder_bb (NULL), m_ranges (), m_true_edge (NULL), m_false_edge (NULL),
-    m_true_edge_phi_mapping (), m_false_edge_phi_mapping ()
+  condition_info (gcond *cond, bool has_side_effect): m_cond (cond),
+    m_bb (gimple_bb (cond)), m_forwarder_bb (NULL), m_ranges (),
+    m_true_edge (NULL), m_false_edge (NULL),
+    m_true_edge_phi_mapping (), m_false_edge_phi_mapping (),
+    m_has_side_effect (has_side_effect)
   {
     m_ranges.create (0);
   }
@@ -75,11 +77,12 @@ struct condition_info
   gcond *m_cond;
   basic_block m_bb;
   basic_block m_forwarder_bb;
-  vec<range_entry> m_ranges;
+  auto_vec<range_entry> m_ranges;
   edge m_true_edge;
   edge m_false_edge;
   mapping_vec m_true_edge_phi_mapping;
   mapping_vec m_false_edge_phi_mapping;
+  bool m_has_side_effect;
 };
 
 /* Recond PHI mapping for an original edge E and save these into vector VEC.  */
@@ -91,11 +94,8 @@ condition_info::record_phi_mapping (edge e, mapping_vec *vec)
        gsi_next (&gsi))
     {
       gphi *phi = gsi.phi ();
-      if (!virtual_operand_p (gimple_phi_result (phi)))
-       {
-         tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
-         vec->safe_push (std::make_pair (phi, arg));
-       }
+      tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
+      vec->safe_push (std::make_pair (phi, arg));
     }
 }
 
@@ -230,6 +230,7 @@ if_chain::is_beneficial ()
                        (left->get_high ()), wi::one (TYPE_PRECISION (type))))
            {
              left->set_high (right->get_high ());
+             delete right;
              continue;
            }
        }
@@ -244,16 +245,20 @@ if_chain::is_beneficial ()
     = jump_table_cluster::find_jump_tables (filtered_clusters);
   bool r = output.length () < filtered_clusters.length ();
   if (r)
-    dump_clusters (&output, "JT can be built");
-  output.release ();
-  if (r)
-    return true;
+    {
+      dump_clusters (&output, "JT can be built");
+      release_clusters (output);
+      return true;
+    }
+  else
+    output.release ();
 
   output = bit_test_cluster::find_bit_tests (filtered_clusters);
   r = output.length () < filtered_clusters.length ();
   if (r)
     dump_clusters (&output, "BT can be built");
-  output.release ();
+
+  release_clusters (output);
   return r;
 }
 
@@ -377,7 +382,7 @@ convert_if_conditions_to_switch (if_chain *chain)
 
 static void
 find_conditions (basic_block bb,
-                hash_map<basic_block, condition_info> *conditions_in_bbs)
+                hash_map<basic_block, condition_info *> *conditions_in_bbs)
 {
   gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
   if (gsi_end_p (gsi))
@@ -387,14 +392,11 @@ find_conditions (basic_block bb,
   if (cond == NULL)
     return;
 
-  if (!no_side_effect_bb (bb))
-    return;
-
   tree lhs = gimple_cond_lhs (cond);
   tree rhs = gimple_cond_rhs (cond);
   tree_code code = gimple_cond_code (cond);
 
-  condition_info info (cond);
+  condition_info *info = new condition_info (cond, !no_side_effect_bb (bb));
 
   gassign *def;
   if (code == NE_EXPR
@@ -405,49 +407,52 @@ find_conditions (basic_block bb,
       enum tree_code rhs_code = gimple_assign_rhs_code (def);
       if (rhs_code == BIT_IOR_EXPR)
        {
-         info.m_ranges.safe_grow (2, true);
-         init_range_entry (&info.m_ranges[0], gimple_assign_rhs1 (def), NULL);
-         init_range_entry (&info.m_ranges[1], gimple_assign_rhs2 (def), NULL);
+         info->m_ranges.safe_grow (2, true);
+         init_range_entry (&info->m_ranges[0], gimple_assign_rhs1 (def), NULL);
+         init_range_entry (&info->m_ranges[1], gimple_assign_rhs2 (def), NULL);
        }
     }
   else
     {
-      info.m_ranges.safe_grow (1, true);
-      init_range_entry (&info.m_ranges[0], NULL_TREE, cond);
+      info->m_ranges.safe_grow (1, true);
+      init_range_entry (&info->m_ranges[0], NULL_TREE, cond);
     }
 
   /* All identified ranges must have equal expression and IN_P flag.  */
-  if (!info.m_ranges.is_empty ())
+  if (!info->m_ranges.is_empty ())
     {
       edge true_edge, false_edge;
-      tree expr = info.m_ranges[0].exp;
-      bool in_p = info.m_ranges[0].in_p;
+      tree expr = info->m_ranges[0].exp;
+      bool in_p = info->m_ranges[0].in_p;
 
       extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
-      info.m_true_edge = in_p ? true_edge : false_edge;
-      info.m_false_edge = in_p ? false_edge : true_edge;
-
-      for (unsigned i = 0; i < info.m_ranges.length (); ++i)
-       if (info.m_ranges[i].exp == NULL_TREE
-           || !INTEGRAL_TYPE_P (TREE_TYPE (info.m_ranges[i].exp))
-           || info.m_ranges[i].low == NULL_TREE
-           || info.m_ranges[i].high == NULL_TREE
-           || (TYPE_PRECISION (TREE_TYPE (info.m_ranges[i].low))
-               != TYPE_PRECISION (TREE_TYPE (info.m_ranges[i].high))))
-         return;
-
-      for (unsigned i = 1; i < info.m_ranges.length (); ++i)
-       if (info.m_ranges[i].exp != expr
-           || info.m_ranges[i].in_p != in_p)
-         return;
-
-      info.record_phi_mapping (info.m_true_edge,
-                              &info.m_true_edge_phi_mapping);
-      info.record_phi_mapping (info.m_false_edge,
-                              &info.m_false_edge_phi_mapping);
+      info->m_true_edge = in_p ? true_edge : false_edge;
+      info->m_false_edge = in_p ? false_edge : true_edge;
+
+      for (unsigned i = 0; i < info->m_ranges.length (); ++i)
+       if (info->m_ranges[i].exp == NULL_TREE
+           || !INTEGRAL_TYPE_P (TREE_TYPE (info->m_ranges[i].exp))
+           || info->m_ranges[i].low == NULL_TREE
+           || info->m_ranges[i].high == NULL_TREE
+           || (TYPE_PRECISION (TREE_TYPE (info->m_ranges[i].low))
+               != TYPE_PRECISION (TREE_TYPE (info->m_ranges[i].high))))
+         goto exit;
+
+      for (unsigned i = 1; i < info->m_ranges.length (); ++i)
+       if (info->m_ranges[i].exp != expr
+           || info->m_ranges[i].in_p != in_p)
+         goto exit;
+
+      info->record_phi_mapping (info->m_true_edge,
+                               &info->m_true_edge_phi_mapping);
+      info->record_phi_mapping (info->m_false_edge,
+                               &info->m_false_edge_phi_mapping);
       conditions_in_bbs->put (bb, info);
+      return;
     }
 
+exit:
+  delete info;
 }
 
 namespace {
@@ -462,7 +467,7 @@ const pass_data pass_data_if_to_switch =
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  TODO_cleanup_cfg | TODO_update_ssa /* todo_flags_finish */
+  TODO_update_ssa /* todo_flags_finish */
 };
 
 class pass_if_to_switch : public gimple_opt_pass
@@ -473,13 +478,13 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual bool gate (function *)
+  bool gate (function *) final override
   {
     return (jump_table_cluster::is_enabled ()
            || bit_test_cluster::is_enabled ());
   }
 
-  virtual unsigned int execute (function *);
+  unsigned int execute (function *) final override;
 
 }; // class pass_if_to_switch
 
@@ -487,7 +492,7 @@ unsigned int
 pass_if_to_switch::execute (function *fun)
 {
   auto_vec<if_chain *> all_candidates;
-  hash_map<basic_block, condition_info> conditions_in_bbs;
+  hash_map<basic_block, condition_info *> conditions_in_bbs;
 
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
@@ -507,9 +512,10 @@ pass_if_to_switch::execute (function *fun)
        continue;
 
       bitmap_set_bit (seen_bbs, bb->index);
-      condition_info *info = conditions_in_bbs.get (bb);
-      if (info)
+      condition_info **slot = conditions_in_bbs.get (bb);
+      if (slot)
        {
+         condition_info *info = *slot;
          if_chain *chain = new if_chain ();
          chain->m_entries.safe_push (info);
          /* Try to find a chain starting in this BB.  */
@@ -518,19 +524,23 @@ pass_if_to_switch::execute (function *fun)
              if (!single_pred_p (gimple_bb (info->m_cond)))
                break;
              edge e = single_pred_edge (gimple_bb (info->m_cond));
-             condition_info *info2 = conditions_in_bbs.get (e->src);
-             if (!info2 || info->m_ranges[0].exp != info2->m_ranges[0].exp)
+             condition_info **info2 = conditions_in_bbs.get (e->src);
+             if (!info2 || info->m_ranges[0].exp != (*info2)->m_ranges[0].exp)
                break;
 
              /* It is important that the blocks are linked through FALSE_EDGE.
                 For an expression of index != VALUE, true and false edges
                 are flipped.  */
-             if (info2->m_false_edge != e)
+             if ((*info2)->m_false_edge != e)
                break;
 
-             chain->m_entries.safe_push (info2);
+             /* Only the first BB in a chain can have a side effect.  */
+             if (info->m_has_side_effect)
+               break;
+
+             chain->m_entries.safe_push (*info2);
              bitmap_set_bit (seen_bbs, e->src->index);
-             info = info2;
+             info = *info2;
            }
 
          chain->m_entries.reverse ();
@@ -546,6 +556,8 @@ pass_if_to_switch::execute (function *fun)
                                 chain->m_entries.length ());
              all_candidates.safe_push (chain);
            }
+         else
+           delete chain;
        }
     }
 
@@ -557,10 +569,14 @@ pass_if_to_switch::execute (function *fun)
 
   free (rpo);
 
+  for (hash_map<basic_block, condition_info *>::iterator it
+       = conditions_in_bbs.begin (); it != conditions_in_bbs.end (); ++it)
+    delete (*it).second;
+
   if (!all_candidates.is_empty ())
     {
       free_dominance_info (CDI_DOMINATORS);
-      mark_virtual_operands_for_renaming (fun);
+      return TODO_cleanup_cfg;
     }
 
   return 0;