#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "backend.h"
-#include "insn-codes.h"
-#include "rtl.h"
+#include "basic-block.h"
+#include "bitmap.h"
+#include "sbitmap.h"
+#include "options.h"
+#include "dominance.h"
+#include "function.h"
+#include "cfg.h"
#include "tree.h"
#include "gimple.h"
-#include "cfghooks.h"
#include "tree-pass.h"
#include "ssa.h"
-#include "optabs-tree.h"
#include "gimple-pretty-print.h"
-#include "flags.h"
#include "fold-const.h"
-#include "stor-layout.h"
-#include "calls.h"
#include "cfganal.h"
-#include "gimple-fold.h"
-#include "tree-eh.h"
#include "gimple-iterator.h"
-#include "gimple-walk.h"
#include "tree-cfg.h"
#include "tree-ssa-loop-manip.h"
#include "tree-ssa-loop-niter.h"
-#include "tree-ssa-loop.h"
#include "tree-into-ssa.h"
-#include "tree-ssa.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
#include "tree-ssa-propagate.h"
-#include "tree-chrec.h"
-#include "tree-ssa-threadupdate.h"
-#include "tree-ssa-scopedtables.h"
#include "tree-ssa-threadedge.h"
-#include "omp-general.h"
-#include "target.h"
-#include "case-cfn-macros.h"
-#include "alloc-pool.h"
#include "domwalk.h"
-#include "tree-cfgcleanup.h"
-#include "stringpool.h"
-#include "attribs.h"
#include "vr-values.h"
-#include "builtins.h"
-#include "range-op.h"
-#include "value-range-equiv.h"
#include "gimple-array-bounds.h"
#include "gimple-range.h"
#include "gimple-range-path.h"
-#include "tree-ssa-dom.h"
/* Set of SSA names found live during the RPO traversal of the function
for still active basic-blocks. */
return false;
}
-
-/* Return the LHS of any ASSERT_EXPR where OP appears as the first
- argument to the ASSERT_EXPR and in which the ASSERT_EXPR dominates
- BB. If no such ASSERT_EXPR is found, return OP. */
-
-static tree
-lhs_of_dominating_assert (tree op, basic_block bb, gimple *stmt)
-{
- imm_use_iterator imm_iter;
- gimple *use_stmt;
- use_operand_p use_p;
-
- if (TREE_CODE (op) == SSA_NAME)
- {
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op)
- {
- use_stmt = USE_STMT (use_p);
- if (use_stmt != stmt
- && gimple_assign_single_p (use_stmt)
- && TREE_CODE (gimple_assign_rhs1 (use_stmt)) == ASSERT_EXPR
- && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == op
- && dominated_by_p (CDI_DOMINATORS, bb, gimple_bb (use_stmt)))
- return gimple_assign_lhs (use_stmt);
- }
- }
- return op;
-}
-
/* Searches the case label vector VEC for the index *IDX of the CASE_LABEL
that includes the value VAL. The search is restricted to the range
[START_IDX, n - 1] where n is the size of VEC.
return simplifier.simplify (si);
}
-class vrp_jt_state : public jt_state
-{
-public:
- vrp_jt_state (const_and_copies *copies, avail_exprs_stack *avails)
- : m_copies (copies), m_avails (avails)
- {
- }
- void push (edge e) override
- {
- m_copies->push_marker ();
- m_avails->push_marker ();
- jt_state::push (e);
- }
- void pop () override
- {
- m_copies->pop_to_marker ();
- m_avails->pop_to_marker ();
- jt_state::pop ();
- }
- void register_equiv (tree dest, tree src, bool) override
- {
- m_copies->record_const_or_copy (dest, src);
- }
- void register_equivs_edge (edge e) override
- {
- record_temporary_equivalences (e, m_copies, m_avails);
- }
- void record_ranges_from_stmt (gimple *, bool) override
- {
- }
-private:
- const_and_copies *m_copies;
- avail_exprs_stack *m_avails;
-};
-
-class vrp_jt_simplifier : public jt_simplifier
-{
-public:
- vrp_jt_simplifier (vr_values *v, avail_exprs_stack *avails)
- : m_vr_values (v), m_avail_exprs_stack (avails) { }
-
-private:
- tree simplify (gimple *, gimple *, basic_block, jt_state *) override;
- vr_values *m_vr_values;
- avail_exprs_stack *m_avail_exprs_stack;
-};
-
-tree
-vrp_jt_simplifier::simplify (gimple *stmt, gimple *within_stmt,
- basic_block bb, jt_state *)
-{
- /* First see if the conditional is in the hash table. */
- tree cached_lhs = m_avail_exprs_stack->lookup_avail_expr (stmt, false, true);
- if (cached_lhs && is_gimple_min_invariant (cached_lhs))
- return cached_lhs;
-
- /* Next see if we can solve it with VRP's internal structures. */
- if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
- {
- tree op0 = gimple_cond_lhs (cond_stmt);
- op0 = lhs_of_dominating_assert (op0, bb, stmt);
-
- tree op1 = gimple_cond_rhs (cond_stmt);
- op1 = lhs_of_dominating_assert (op1, bb, stmt);
-
- simplify_using_ranges simplifier (m_vr_values);
- return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
- op0, op1, within_stmt);
- }
- if (gswitch *switch_stmt = dyn_cast <gswitch *> (stmt))
- {
- tree op = gimple_switch_index (switch_stmt);
- if (TREE_CODE (op) != SSA_NAME)
- return NULL_TREE;
-
- op = lhs_of_dominating_assert (op, bb, stmt);
-
- const value_range_equiv *vr = m_vr_values->get_value_range (op);
- return find_case_label_range (switch_stmt, vr);
- }
-
- /* Finally, try vr_values. */
- if (gassign *assign_stmt = dyn_cast <gassign *> (stmt))
- {
- tree lhs = gimple_assign_lhs (assign_stmt);
- if (TREE_CODE (lhs) == SSA_NAME
- && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
- || POINTER_TYPE_P (TREE_TYPE (lhs)))
- && stmt_interesting_for_vrp (stmt))
- {
- edge dummy_e;
- tree dummy_tree;
- value_range_equiv new_vr;
- m_vr_values->extract_range_from_stmt (stmt, &dummy_e, &dummy_tree,
- &new_vr);
- tree singleton;
- if (new_vr.singleton_p (&singleton))
- return singleton;
- }
- }
- return NULL;
-}
-
-/* Blocks which have more than one predecessor and more than
- one successor present jump threading opportunities, i.e.,
- when the block is reached from a specific predecessor, we
- may be able to determine which of the outgoing edges will
- be traversed. When this optimization applies, we are able
- to avoid conditionals at runtime and we may expose secondary
- optimization opportunities.
-
- This class is effectively a driver for the generic jump
- threading code. It basically just presents the generic code
- with edges that may be suitable for jump threading.
-
- Unlike DOM, we do not iterate VRP if jump threading was successful.
- While iterating may expose new opportunities for VRP, it is expected
- those opportunities would be very limited and the compile time cost
- to expose those opportunities would be significant.
-
- As jump threading opportunities are discovered, they are registered
- for later realization. */
-
-class vrp_jump_threader : public dom_walker
-{
-public:
- vrp_jump_threader (function *, vr_values *);
- ~vrp_jump_threader ();
-
- void thread_jumps ()
- {
- walk (m_fun->cfg->x_entry_block_ptr);
- }
-
- void thread_through_all_blocks ()
- {
- // FIXME: Put this in the destructor?
- m_threader->thread_through_all_blocks (false);
- }
-
-private:
- virtual edge before_dom_children (basic_block);
- virtual void after_dom_children (basic_block);
-
- function *m_fun;
- vr_values *m_vr_values;
- const_and_copies *m_const_and_copies;
- avail_exprs_stack *m_avail_exprs_stack;
- hash_table<expr_elt_hasher> *m_avail_exprs;
- vrp_jt_simplifier *m_simplifier;
- jump_threader *m_threader;
- jt_state *m_state;
-};
-
-vrp_jump_threader::vrp_jump_threader (struct function *fun, vr_values *v)
- : dom_walker (CDI_DOMINATORS, REACHABLE_BLOCKS)
-{
- /* Ugh. When substituting values earlier in this pass we can wipe
- the dominance information. So rebuild the dominator information
- as we need it within the jump threading code. */
- calculate_dominance_info (CDI_DOMINATORS);
-
- /* We do not allow VRP information to be used for jump threading
- across a back edge in the CFG. Otherwise it becomes too
- difficult to avoid eliminating loop exit tests. Of course
- EDGE_DFS_BACK is not accurate at this time so we have to
- recompute it. */
- mark_dfs_back_edges ();
-
- /* Allocate our unwinder stack to unwind any temporary equivalences
- that might be recorded. */
- m_const_and_copies = new const_and_copies ();
-
- m_fun = fun;
- m_vr_values = v;
- m_avail_exprs = new hash_table<expr_elt_hasher> (1024);
- m_avail_exprs_stack = new avail_exprs_stack (m_avail_exprs);
- m_state = new vrp_jt_state (m_const_and_copies, m_avail_exprs_stack);
-
- m_simplifier = new vrp_jt_simplifier (m_vr_values, m_avail_exprs_stack);
- m_threader = new jump_threader (m_simplifier, m_state);
-}
-
-vrp_jump_threader::~vrp_jump_threader ()
-{
- /* We do not actually update the CFG or SSA graphs at this point as
- ASSERT_EXPRs are still in the IL and cfg cleanup code does not
- yet handle ASSERT_EXPRs gracefully. */
- delete m_const_and_copies;
- delete m_avail_exprs;
- delete m_avail_exprs_stack;
- delete m_simplifier;
- delete m_threader;
- delete m_state;
-}
-
-/* Called before processing dominator children of BB. We want to look
- at ASSERT_EXPRs and record information from them in the appropriate
- tables.
-
- We could look at other statements here. It's not seen as likely
- to significantly increase the jump threads we discover. */
-
-edge
-vrp_jump_threader::before_dom_children (basic_block bb)
-{
- gimple_stmt_iterator gsi;
-
- m_avail_exprs_stack->push_marker ();
- m_const_and_copies->push_marker ();
- for (gsi = gsi_start_nondebug_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
- if (gimple_assign_single_p (stmt)
- && TREE_CODE (gimple_assign_rhs1 (stmt)) == ASSERT_EXPR)
- {
- tree rhs1 = gimple_assign_rhs1 (stmt);
- tree cond = TREE_OPERAND (rhs1, 1);
- tree inverted = invert_truthvalue (cond);
- vec<cond_equivalence> p;
- p.create (3);
- record_conditions (&p, cond, inverted);
- for (unsigned int i = 0; i < p.length (); i++)
- m_avail_exprs_stack->record_cond (&p[i]);
-
- tree lhs = gimple_assign_lhs (stmt);
- m_const_and_copies->record_const_or_copy (lhs,
- TREE_OPERAND (rhs1, 0));
- p.release ();
- continue;
- }
- break;
- }
- return NULL;
-}
-
-/* Called after processing dominator children of BB. This is where we
- actually call into the threader. */
-void
-vrp_jump_threader::after_dom_children (basic_block bb)
-{
- m_threader->thread_outgoing_edges (bb);
- m_avail_exprs_stack->pop_to_marker ();
- m_const_and_copies->pop_to_marker ();
-}
-
/* STMT is a conditional at the end of a basic block.
If the conditional is of the form SSA_NAME op constant and the SSA_NAME