aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/gimple-predicate-analysis.cc572
1 files changed, 286 insertions, 286 deletions
diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc
index 8995c11..079e060 100644
--- a/gcc/gimple-predicate-analysis.cc
+++ b/gcc/gimple-predicate-analysis.cc
@@ -1694,292 +1694,6 @@ predicate::simplify (gimple *use_or_def, bool is_use)
(_2 RELOP1 _1) AND (_5 RELOP2 _4) AND (_8 RELOP3 _7) AND (_0 != 0)
*/
-/* Store a PRED in *THIS. */
-
-void
-predicate::push_pred (const pred_info &pred)
-{
- pred_chain chain = vNULL;
- chain.safe_push (pred);
- m_preds.safe_push (chain);
-}
-
-/* Dump predicates in *THIS for STMT prepended by MSG. */
-
-void
-predicate::dump (gimple *stmt, const char *msg) const
-{
- fprintf (dump_file, "%s", msg);
- if (stmt)
- {
- fputc ('\t', dump_file);
- print_gimple_stmt (dump_file, stmt, 0);
- fprintf (dump_file, " is conditional on:\n");
- }
-
- unsigned np = m_preds.length ();
- if (np == 0)
- {
- fprintf (dump_file, "\t(empty)\n");
- return;
- }
-
- {
- tree expr = build_pred_expr (m_preds);
- char *str = print_generic_expr_to_str (expr);
- fprintf (dump_file, "\t%s (expanded)\n", str);
- free (str);
- }
-
- if (np > 1)
- fprintf (dump_file, "\tOR (");
- else
- fputc ('\t', dump_file);
- for (unsigned i = 0; i < np; i++)
- {
- dump_pred_chain (m_preds[i]);
- if (i < np - 1)
- fprintf (dump_file, ", ");
- else if (i > 0)
- fputc (')', dump_file);
- }
- fputc ('\n', dump_file);
-}
-
-/* Initialize USE_PREDS with the predicates of the control dependence chains
- between the basic block DEF_BB that defines a variable of interst and
- USE_BB that uses the variable, respectively. */
-
-bool
-uninit_analysis::init_use_preds (predicate &use_preds, basic_block def_bb,
- basic_block use_bb)
-{
- gcc_assert (use_preds.is_empty ());
-
- /* Set CD_ROOT to the basic block closest to USE_BB that is the control
- equivalent of (is guarded by the same predicate as) DEF_BB that also
- dominates USE_BB. */
- basic_block cd_root = def_bb;
- while (dominated_by_p (CDI_DOMINATORS, use_bb, cd_root))
- {
- /* Find CD_ROOT's closest postdominator that's its control
- equivalent. */
- if (basic_block bb = find_control_equiv_block (cd_root))
- if (dominated_by_p (CDI_DOMINATORS, use_bb, bb))
- {
- cd_root = bb;
- continue;
- }
-
- break;
- }
-
- /* Set DEP_CHAINS to the set of edges between CD_ROOT and USE_BB.
- Each DEP_CHAINS element is a series of edges whose conditions
- are logical conjunctions. Together, the DEP_CHAINS vector is
- used below to initialize an OR expression of the conjunctions. */
- unsigned num_calls = 0;
- unsigned num_chains = 0;
- auto_vec<edge> dep_chains[MAX_NUM_CHAINS];
- auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain;
-
- if (!compute_control_dep_chain (cd_root, use_bb, dep_chains, &num_chains,
- cur_chain, &num_calls))
- {
- gcc_assert (num_chains == 0);
- simple_control_dep_chain (dep_chains[0], cd_root, use_bb);
- num_chains++;
- }
-
- if (DEBUG_PREDICATE_ANALYZER && dump_file)
- {
- fprintf (dump_file, "predicate::predicate (def_bb = %u, use_bb = %u, func_t) "
- "initialized from %u dep_chains:\n\t",
- def_bb->index, use_bb->index, num_chains);
- dump_dep_chains (dep_chains, num_chains);
- }
-
- /* From the set of edges computed above initialize *THIS as the OR
- condition under which the definition in DEF_BB is used in USE_BB.
- Each OR subexpression is represented by one element of DEP_CHAINS,
- where each element consists of a series of AND subexpressions. */
- use_preds.init_from_control_deps (dep_chains, num_chains);
- return !use_preds.is_empty ();
-}
-
-/* Release resources in *THIS. */
-
-predicate::~predicate ()
-{
- unsigned n = m_preds.length ();
- for (unsigned i = 0; i != n; ++i)
- m_preds[i].release ();
- m_preds.release ();
-}
-
-/* Copy-assign RHS to *THIS. */
-
-predicate&
-predicate::operator= (const predicate &rhs)
-{
- if (this == &rhs)
- return *this;
-
- unsigned n = m_preds.length ();
- for (unsigned i = 0; i != n; ++i)
- m_preds[i].release ();
- m_preds.release ();
-
- n = rhs.m_preds.length ();
- for (unsigned i = 0; i != n; ++i)
- {
- const pred_chain &chain = rhs.m_preds[i];
- m_preds.safe_push (chain.copy ());
- }
-
- return *this;
-}
-
-/* For each use edge of PHI, compute all control dependence chains
- and convert those to the composite predicates in M_PREDS.
- Return true if a nonempty predicate has been obtained. */
-
-bool
-uninit_analysis::init_from_phi_def (gphi *phi)
-{
- gcc_assert (m_phi_def_preds.is_empty ());
-
- basic_block phi_bb = gimple_bb (phi);
- /* Find the closest dominating bb to be the control dependence root. */
- basic_block cd_root = get_immediate_dominator (CDI_DOMINATORS, phi_bb);
- if (!cd_root)
- return false;
-
- /* Set DEF_EDGES to the edges to the PHI from the bb's that provide
- definitions of each of the PHI operands for which M_EVAL is false. */
- auto_vec<edge> def_edges;
- hash_set<gimple *> visited_phis;
- collect_phi_def_edges (phi, cd_root, &def_edges, &visited_phis);
-
- unsigned nedges = def_edges.length ();
- if (nedges == 0)
- return false;
-
- unsigned num_chains = 0;
- auto_vec<edge> dep_chains[MAX_NUM_CHAINS];
- auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain;
- for (unsigned i = 0; i < nedges; i++)
- {
- edge e = def_edges[i];
- unsigned num_calls = 0;
- unsigned prev_nc = num_chains;
- compute_control_dep_chain (cd_root, e->src, dep_chains,
- &num_chains, cur_chain, &num_calls);
-
- /* Update the newly added chains with the phi operand edge. */
- if (EDGE_COUNT (e->src->succs) > 1)
- {
- if (prev_nc == num_chains && num_chains < MAX_NUM_CHAINS)
- dep_chains[num_chains++] = vNULL;
- for (unsigned j = prev_nc; j < num_chains; j++)
- dep_chains[j].safe_push (e);
- }
- }
-
- /* Convert control dependence chains to the predicate in *THIS under
- which the PHI operands are defined to values for which M_EVAL is
- false. */
- m_phi_def_preds.init_from_control_deps (dep_chains, num_chains);
- return !m_phi_def_preds.is_empty ();
-}
-
-/* Compute the predicates that guard the use USE_STMT and check if
- the incoming paths that have an empty (or possibly empty) definition
- can be pruned. Return true if it can be determined that the use of
- PHI's def in USE_STMT is guarded by a predicate set that does not
- overlap with the predicate sets of all runtime paths that do not
- have a definition.
-
- Return false if the use is not guarded or if it cannot be determined.
- USE_BB is the bb of the use (for phi operand use, the bb is not the bb
- of the phi stmt, but the source bb of the operand edge).
-
- OPNDS is a bitmap with a bit set for each PHI operand of interest.
-
- THIS->M_PREDS contains the (memoized) defining predicate chains of
- a PHI. If THIS->M_PREDS is empty, the PHI's defining predicate
- chains are computed and stored into THIS->M_PREDS as needed.
-
- VISITED_PHIS is a pointer set of phis being visited. */
-
-bool
-uninit_analysis::is_use_guarded (gimple *use_stmt, basic_block use_bb,
- gphi *phi, unsigned opnds,
- hash_set<gphi *> *visited)
-{
- if (visited->add (phi))
- return false;
-
- /* The basic block where the PHI is defined. */
- basic_block def_bb = gimple_bb (phi);
-
- if (dominated_by_p (CDI_POST_DOMINATORS, def_bb, use_bb))
- /* The use is not guarded. */
- return false;
-
- /* Try to build the predicate expression under which the PHI flows
- into its use. This will be empty if the PHI is defined and used
- in the same bb. */
- predicate use_preds;
- if (!init_use_preds (use_preds, def_bb, use_bb))
- return false;
-
- /* Try to prune the dead incoming phi edges. */
- if (!overlap (phi, opnds, visited, use_preds))
- {
- if (DEBUG_PREDICATE_ANALYZER && dump_file)
- fputs ("found predicate overlap\n", dump_file);
-
- return true;
- }
-
- /* We might be able to prove that if the control dependencies for OPNDS
- are true, the control dependencies for USE_STMT can never be true. */
- if (use_cannot_happen (phi, opnds, use_preds))
- return true;
-
- if (m_phi_def_preds.is_empty ())
- {
- /* Lazily initialize *THIS from PHI. */
- if (!init_from_phi_def (phi))
- return false;
-
- m_phi_def_preds.simplify (phi);
- m_phi_def_preds.normalize (phi);
- }
-
- use_preds.simplify (use_stmt, /*is_use=*/true);
- use_preds.normalize (use_stmt, /*is_use=*/true);
-
- /* Return true if the predicate guarding the valid definition (i.e.,
- *THIS) is a superset of the predicate guarding the use (i.e.,
- USE_PREDS). */
- if (m_phi_def_preds.superset_of (use_preds))
- return true;
-
- return false;
-}
-
-/* Public interface to the above. */
-
-bool
-uninit_analysis::is_use_guarded (gimple *stmt, basic_block use_bb, gphi *phi,
- unsigned opnds)
-{
- hash_set<gphi *> visited;
- return is_use_guarded (stmt, use_bb, phi, opnds, &visited);
-}
-
/* Normalize predicate PRED:
1) if PRED can no longer be normalized, append it to *THIS.
2) otherwise if PRED is of the form x != 0, follow x's definition
@@ -2353,3 +2067,289 @@ predicate::init_from_control_deps (const vec<edge> *dep_chains,
/* Clear M_PREDS to indicate failure. */
m_preds.release ();
}
+/* Store a PRED in *THIS. */
+
+void
+predicate::push_pred (const pred_info &pred)
+{
+ pred_chain chain = vNULL;
+ chain.safe_push (pred);
+ m_preds.safe_push (chain);
+}
+
+/* Dump predicates in *THIS for STMT prepended by MSG. */
+
+void
+predicate::dump (gimple *stmt, const char *msg) const
+{
+ fprintf (dump_file, "%s", msg);
+ if (stmt)
+ {
+ fputc ('\t', dump_file);
+ print_gimple_stmt (dump_file, stmt, 0);
+ fprintf (dump_file, " is conditional on:\n");
+ }
+
+ unsigned np = m_preds.length ();
+ if (np == 0)
+ {
+ fprintf (dump_file, "\t(empty)\n");
+ return;
+ }
+
+ {
+ tree expr = build_pred_expr (m_preds);
+ char *str = print_generic_expr_to_str (expr);
+ fprintf (dump_file, "\t%s (expanded)\n", str);
+ free (str);
+ }
+
+ if (np > 1)
+ fprintf (dump_file, "\tOR (");
+ else
+ fputc ('\t', dump_file);
+ for (unsigned i = 0; i < np; i++)
+ {
+ dump_pred_chain (m_preds[i]);
+ if (i < np - 1)
+ fprintf (dump_file, ", ");
+ else if (i > 0)
+ fputc (')', dump_file);
+ }
+ fputc ('\n', dump_file);
+}
+
+/* Initialize USE_PREDS with the predicates of the control dependence chains
+ between the basic block DEF_BB that defines a variable of interst and
+ USE_BB that uses the variable, respectively. */
+
+bool
+uninit_analysis::init_use_preds (predicate &use_preds, basic_block def_bb,
+ basic_block use_bb)
+{
+ gcc_assert (use_preds.is_empty ());
+
+ /* Set CD_ROOT to the basic block closest to USE_BB that is the control
+ equivalent of (is guarded by the same predicate as) DEF_BB that also
+ dominates USE_BB. */
+ basic_block cd_root = def_bb;
+ while (dominated_by_p (CDI_DOMINATORS, use_bb, cd_root))
+ {
+ /* Find CD_ROOT's closest postdominator that's its control
+ equivalent. */
+ if (basic_block bb = find_control_equiv_block (cd_root))
+ if (dominated_by_p (CDI_DOMINATORS, use_bb, bb))
+ {
+ cd_root = bb;
+ continue;
+ }
+
+ break;
+ }
+
+ /* Set DEP_CHAINS to the set of edges between CD_ROOT and USE_BB.
+ Each DEP_CHAINS element is a series of edges whose conditions
+ are logical conjunctions. Together, the DEP_CHAINS vector is
+ used below to initialize an OR expression of the conjunctions. */
+ unsigned num_calls = 0;
+ unsigned num_chains = 0;
+ auto_vec<edge> dep_chains[MAX_NUM_CHAINS];
+ auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain;
+
+ if (!compute_control_dep_chain (cd_root, use_bb, dep_chains, &num_chains,
+ cur_chain, &num_calls))
+ {
+ gcc_assert (num_chains == 0);
+ simple_control_dep_chain (dep_chains[0], cd_root, use_bb);
+ num_chains++;
+ }
+
+ if (DEBUG_PREDICATE_ANALYZER && dump_file)
+ {
+ fprintf (dump_file, "predicate::predicate (def_bb = %u, use_bb = %u, func_t) "
+ "initialized from %u dep_chains:\n\t",
+ def_bb->index, use_bb->index, num_chains);
+ dump_dep_chains (dep_chains, num_chains);
+ }
+
+ /* From the set of edges computed above initialize *THIS as the OR
+ condition under which the definition in DEF_BB is used in USE_BB.
+ Each OR subexpression is represented by one element of DEP_CHAINS,
+ where each element consists of a series of AND subexpressions. */
+ use_preds.init_from_control_deps (dep_chains, num_chains);
+ return !use_preds.is_empty ();
+}
+
+/* Release resources in *THIS. */
+
+predicate::~predicate ()
+{
+ unsigned n = m_preds.length ();
+ for (unsigned i = 0; i != n; ++i)
+ m_preds[i].release ();
+ m_preds.release ();
+}
+
+/* Copy-assign RHS to *THIS. */
+
+predicate&
+predicate::operator= (const predicate &rhs)
+{
+ if (this == &rhs)
+ return *this;
+
+ unsigned n = m_preds.length ();
+ for (unsigned i = 0; i != n; ++i)
+ m_preds[i].release ();
+ m_preds.release ();
+
+ n = rhs.m_preds.length ();
+ for (unsigned i = 0; i != n; ++i)
+ {
+ const pred_chain &chain = rhs.m_preds[i];
+ m_preds.safe_push (chain.copy ());
+ }
+
+ return *this;
+}
+
+/* For each use edge of PHI, compute all control dependence chains
+ and convert those to the composite predicates in M_PREDS.
+ Return true if a nonempty predicate has been obtained. */
+
+bool
+uninit_analysis::init_from_phi_def (gphi *phi)
+{
+ gcc_assert (m_phi_def_preds.is_empty ());
+
+ basic_block phi_bb = gimple_bb (phi);
+ /* Find the closest dominating bb to be the control dependence root. */
+ basic_block cd_root = get_immediate_dominator (CDI_DOMINATORS, phi_bb);
+ if (!cd_root)
+ return false;
+
+ /* Set DEF_EDGES to the edges to the PHI from the bb's that provide
+ definitions of each of the PHI operands for which M_EVAL is false. */
+ auto_vec<edge> def_edges;
+ hash_set<gimple *> visited_phis;
+ collect_phi_def_edges (phi, cd_root, &def_edges, &visited_phis);
+
+ unsigned nedges = def_edges.length ();
+ if (nedges == 0)
+ return false;
+
+ unsigned num_chains = 0;
+ auto_vec<edge> dep_chains[MAX_NUM_CHAINS];
+ auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain;
+ for (unsigned i = 0; i < nedges; i++)
+ {
+ edge e = def_edges[i];
+ unsigned num_calls = 0;
+ unsigned prev_nc = num_chains;
+ compute_control_dep_chain (cd_root, e->src, dep_chains,
+ &num_chains, cur_chain, &num_calls);
+
+ /* Update the newly added chains with the phi operand edge. */
+ if (EDGE_COUNT (e->src->succs) > 1)
+ {
+ if (prev_nc == num_chains && num_chains < MAX_NUM_CHAINS)
+ dep_chains[num_chains++] = vNULL;
+ for (unsigned j = prev_nc; j < num_chains; j++)
+ dep_chains[j].safe_push (e);
+ }
+ }
+
+ /* Convert control dependence chains to the predicate in *THIS under
+ which the PHI operands are defined to values for which M_EVAL is
+ false. */
+ m_phi_def_preds.init_from_control_deps (dep_chains, num_chains);
+ return !m_phi_def_preds.is_empty ();
+}
+
+/* Compute the predicates that guard the use USE_STMT and check if
+ the incoming paths that have an empty (or possibly empty) definition
+ can be pruned. Return true if it can be determined that the use of
+ PHI's def in USE_STMT is guarded by a predicate set that does not
+ overlap with the predicate sets of all runtime paths that do not
+ have a definition.
+
+ Return false if the use is not guarded or if it cannot be determined.
+ USE_BB is the bb of the use (for phi operand use, the bb is not the bb
+ of the phi stmt, but the source bb of the operand edge).
+
+ OPNDS is a bitmap with a bit set for each PHI operand of interest.
+
+ THIS->M_PREDS contains the (memoized) defining predicate chains of
+ a PHI. If THIS->M_PREDS is empty, the PHI's defining predicate
+ chains are computed and stored into THIS->M_PREDS as needed.
+
+ VISITED_PHIS is a pointer set of phis being visited. */
+
+bool
+uninit_analysis::is_use_guarded (gimple *use_stmt, basic_block use_bb,
+ gphi *phi, unsigned opnds,
+ hash_set<gphi *> *visited)
+{
+ if (visited->add (phi))
+ return false;
+
+ /* The basic block where the PHI is defined. */
+ basic_block def_bb = gimple_bb (phi);
+
+ if (dominated_by_p (CDI_POST_DOMINATORS, def_bb, use_bb))
+ /* The use is not guarded. */
+ return false;
+
+ /* Try to build the predicate expression under which the PHI flows
+ into its use. This will be empty if the PHI is defined and used
+ in the same bb. */
+ predicate use_preds;
+ if (!init_use_preds (use_preds, def_bb, use_bb))
+ return false;
+
+ /* Try to prune the dead incoming phi edges. */
+ if (!overlap (phi, opnds, visited, use_preds))
+ {
+ if (DEBUG_PREDICATE_ANALYZER && dump_file)
+ fputs ("found predicate overlap\n", dump_file);
+
+ return true;
+ }
+
+ /* We might be able to prove that if the control dependencies for OPNDS
+ are true, the control dependencies for USE_STMT can never be true. */
+ if (use_cannot_happen (phi, opnds, use_preds))
+ return true;
+
+ if (m_phi_def_preds.is_empty ())
+ {
+ /* Lazily initialize *THIS from PHI. */
+ if (!init_from_phi_def (phi))
+ return false;
+
+ m_phi_def_preds.simplify (phi);
+ m_phi_def_preds.normalize (phi);
+ }
+
+ use_preds.simplify (use_stmt, /*is_use=*/true);
+ use_preds.normalize (use_stmt, /*is_use=*/true);
+
+ /* Return true if the predicate guarding the valid definition (i.e.,
+ *THIS) is a superset of the predicate guarding the use (i.e.,
+ USE_PREDS). */
+ if (m_phi_def_preds.superset_of (use_preds))
+ return true;
+
+ return false;
+}
+
+/* Public interface to the above. */
+
+bool
+uninit_analysis::is_use_guarded (gimple *stmt, basic_block use_bb, gphi *phi,
+ unsigned opnds)
+{
+ hash_set<gphi *> visited;
+ return is_use_guarded (stmt, use_bb, phi, opnds, &visited);
+}
+