/* 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.
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);
}
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. */
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));
}
}
(left->get_high ()), wi::one (TYPE_PRECISION (type))))
{
left->set_high (right->get_high ());
+ delete right;
continue;
}
}
= 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;
}
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))
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
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 {
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
{}
/* 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
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)
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. */
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 ();
chain->m_entries.length ());
all_candidates.safe_push (chain);
}
+ else
+ delete chain;
}
}
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;