gcc/gcc/tree-ssa-threadedge.h
Richard Biener 2cf89ae832 tree-optimization/116166 - forward jump-threading going wild
Currently the forward threader isn't limited as to the search space
it explores and with it now using path-ranger for simplifying
conditions it runs into it became pretty slow for degenerate cases
like compiling insn-emit.cc for RISC-V esp. when compiling for
a host with LOGICAL_OP_NON_SHORT_CIRCUIT disabled.

The following makes the forward threader honor the search space
limit I introduced for the backward threader.  This reduces
compile-time from minutes to seconds for the testcase in PR116166.

Note this wasn't necessary before we had ranger but with ranger
the work we do is quadatic in the length of the threading path
we build up (the same is true for the backwards threader).

	PR tree-optimization/116166
	* tree-ssa-threadedge.h (jump_threader::thread_around_empty_blocks):
	Add limit parameter.
	(jump_threader::thread_through_normal_block): Likewise.
	* tree-ssa-threadedge.cc (jump_threader::thread_around_empty_blocks):
	Honor and decrement limit parameter.
	(jump_threader::thread_through_normal_block): Likewise.
	(jump_threader::thread_across_edge): Initialize limit from
	param_max_jump_thread_paths and pass it down to workers.
2024-08-07 09:14:21 +02:00

135 lines
4.2 KiB
C++

/* Header file for SSA jump threading.
Copyright (C) 2013-2024 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_SSA_THREADEDGE_H
#define GCC_TREE_SSA_THREADEDGE_H
// Class used to maintain path state in the jump threader and pass it
// to the jump threader simplifier.
class jt_state
{
public:
virtual ~jt_state () { }
virtual void push (edge);
virtual void pop ();
virtual void register_equiv (tree dest, tree src, bool update_range);
virtual void register_equivs_edge (edge e);
virtual void register_equivs_stmt (gimple *, basic_block,
class jt_simplifier *);
virtual void record_ranges_from_stmt (gimple *stmt, bool temporary);
void get_path (vec<basic_block> &);
void append_path (basic_block);
void dump (FILE *);
void debug ();
private:
auto_vec<basic_block> m_blocks;
static const basic_block BB_MARKER;
};
// Statement simplifier callback for the jump threader.
class jt_simplifier
{
public:
virtual ~jt_simplifier () { }
virtual tree simplify (gimple *, gimple *, basic_block, jt_state *) = 0;
};
class hybrid_jt_state : public jt_state
{
private:
void register_equivs_stmt (gimple *, basic_block, jt_simplifier *) override
{
// Ranger has no need to simplify anything.
}
};
class hybrid_jt_simplifier : public jt_simplifier
{
public:
hybrid_jt_simplifier (class gimple_ranger *r, class path_range_query *q);
tree simplify (gimple *stmt, gimple *, basic_block, jt_state *) override;
private:
void compute_exit_dependencies (bitmap dependencies,
const vec<basic_block> &path,
gimple *stmt);
gimple_ranger *m_ranger;
path_range_query *m_query;
};
// This is the high level threader. The entry point is
// thread_outgoing_edges(), which calculates and registers paths to be
// threaded. When all candidates have been registered,
// thread_through_all_blocks() is called to actually change the CFG.
class jump_threader
{
public:
jump_threader (jt_simplifier *, class jt_state *);
~jump_threader ();
void thread_outgoing_edges (basic_block);
void remove_jump_threads_including (edge_def *);
bool thread_through_all_blocks (bool may_peel_loop_headers);
private:
tree simplify_control_stmt_condition (edge, gimple *);
tree simplify_control_stmt_condition_1 (edge,
gimple *,
tree op0,
tree_code cond_code,
tree op1,
unsigned limit);
bool thread_around_empty_blocks (vec<class jump_thread_edge *> *path,
edge, bitmap visited, unsigned &limit);
int thread_through_normal_block (vec<jump_thread_edge *> *path,
edge, bitmap visited, unsigned &limit);
void thread_across_edge (edge);
bool record_temporary_equivalences_from_phis (edge);
gimple *record_temporary_equivalences_from_stmts_at_dest (edge);
// Dummy condition to avoid creating lots of throw away statements.
gcond *dummy_cond;
class fwd_jt_path_registry *m_registry;
jt_simplifier *m_simplifier;
jt_state *m_state;
};
extern void propagate_threaded_block_debug_into (basic_block, basic_block);
extern bool single_succ_to_potentially_threadable_block (basic_block);
// ?? All this ssa_name_values stuff is the store of values for
// avail_exprs_stack and const_and_copies, so it really belongs in the
// jump_threader class. However, it's probably not worth touching
// this, since all this windable state is slated to go with the
// ranger.
extern vec<tree> ssa_name_values;
#define SSA_NAME_VALUE(x) \
(SSA_NAME_VERSION (x) < ssa_name_values.length () \
? ssa_name_values[SSA_NAME_VERSION (x)] \
: NULL_TREE)
extern void set_ssa_name_value (tree, tree);
#endif /* GCC_TREE_SSA_THREADEDGE_H */