rtl-ssa: Handle call clobbers in more places
In order to save (a lot of) memory, RTL-SSA avoids creating individual clobber records for every call-clobbered register. It instead maintains a list & splay tree of calls in an EBB, grouped by ABI. This patch takes these call clobbers into account in a couple more routines. I don't think this will have any effect on existing users, since it's only necessary for hard registers. gcc/ * rtl-ssa/access-utils.h (next_call_clobbers): New function. (is_single_dominating_def, remains_available_on_exit): Replace with... * rtl-ssa/functions.h (function_info::is_single_dominating_def) (function_info::remains_available_on_exit): ...these new member functions. (function_info::m_clobbered_by_calls): New member variable. * rtl-ssa/functions.cc (function_info::function_info): Explicitly initialize m_clobbered_by_calls. * rtl-ssa/insns.cc (function_info::record_call_clobbers): Update m_clobbered_by_calls for each call-clobber note. * rtl-ssa/member-fns.inl (function_info::is_single_dominating_def): New function. Check for call clobbers. * rtl-ssa/accesses.cc (function_info::remains_available_on_exit): Likewise.
This commit is contained in:
parent
ba97d0e3b9
commit
cc15a0f49d
6 changed files with 60 additions and 19 deletions
|
@ -127,24 +127,6 @@ set_with_nondebug_insn_uses (access_info *access)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Return true if SET is the only set of SET->resource () and if it
|
||||
// dominates all uses (excluding uses of SET->resource () at points
|
||||
// where SET->resource () is always undefined).
|
||||
inline bool
|
||||
is_single_dominating_def (const set_info *set)
|
||||
{
|
||||
return set->is_first_def () && set->is_last_def ();
|
||||
}
|
||||
|
||||
// SET is known to be available on entry to BB. Return true if it is
|
||||
// also available on exit from BB. (The value might or might not be live.)
|
||||
inline bool
|
||||
remains_available_on_exit (const set_info *set, bb_info *bb)
|
||||
{
|
||||
return (set->is_last_def ()
|
||||
|| *set->next_def ()->insn () > *bb->end_insn ());
|
||||
}
|
||||
|
||||
// ACCESS is known to be associated with an instruction rather than
|
||||
// a phi node. Return which instruction that is.
|
||||
inline insn_info *
|
||||
|
@ -313,6 +295,15 @@ next_call_clobbers_ignoring (insn_call_clobbers_tree &tree, insn_info *insn,
|
|||
return tree->insn ();
|
||||
}
|
||||
|
||||
// Search forwards from immediately after INSN for the first instruction
|
||||
// recorded in TREE. Return null if no such instruction exists.
|
||||
inline insn_info *
|
||||
next_call_clobbers (insn_call_clobbers_tree &tree, insn_info *insn)
|
||||
{
|
||||
auto ignore = [](const insn_info *) { return false; };
|
||||
return next_call_clobbers_ignoring (tree, insn, ignore);
|
||||
}
|
||||
|
||||
// If ACCESS is a set, return the first use of ACCESS by a nondebug insn I
|
||||
// for which IGNORE (I) is false. Return null if ACCESS is not a set or if
|
||||
// no such use exists.
|
||||
|
|
|
@ -1303,6 +1303,31 @@ function_info::insert_temp_clobber (obstack_watermark &watermark,
|
|||
return insert_access (watermark, clobber, old_defs);
|
||||
}
|
||||
|
||||
// See the comment above the declaration.
|
||||
bool
|
||||
function_info::remains_available_on_exit (const set_info *set, bb_info *bb)
|
||||
{
|
||||
if (HARD_REGISTER_NUM_P (set->regno ())
|
||||
&& TEST_HARD_REG_BIT (m_clobbered_by_calls, set->regno ()))
|
||||
{
|
||||
insn_info *search_insn = (set->bb () == bb
|
||||
? set->insn ()
|
||||
: bb->head_insn ());
|
||||
for (ebb_call_clobbers_info *call_group : bb->ebb ()->call_clobbers ())
|
||||
{
|
||||
if (!call_group->clobbers (set->resource ()))
|
||||
continue;
|
||||
|
||||
insn_info *insn = next_call_clobbers (*call_group, search_insn);
|
||||
if (insn && insn->bb () == bb)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (set->is_last_def ()
|
||||
|| *set->next_def ()->insn () > *bb->end_insn ());
|
||||
}
|
||||
|
||||
// A subroutine of make_uses_available. Try to make USE's definition
|
||||
// available at the head of BB. WILL_BE_DEBUG_USE is true if the
|
||||
// definition will be used only in debug instructions.
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
using namespace rtl_ssa;
|
||||
|
||||
function_info::function_info (function *fn)
|
||||
: m_fn (fn)
|
||||
: m_fn (fn), m_clobbered_by_calls ()
|
||||
{
|
||||
// Force the alignment to be obstack_alignment. Everything else is normal.
|
||||
obstack_specify_allocation (&m_obstack, OBSTACK_CHUNK_SIZE,
|
||||
|
|
|
@ -102,6 +102,11 @@ public:
|
|||
// definitions by things like phi nodes.
|
||||
iterator_range<def_iterator> reg_defs (unsigned int regno) const;
|
||||
|
||||
// Return true if SET is the only set of SET->resource () and if it
|
||||
// dominates all uses (excluding uses of SET->resource () at points
|
||||
// where SET->resource () is always undefined).
|
||||
bool is_single_dominating_def (const set_info *set) const;
|
||||
|
||||
// Check if all uses of register REGNO are either unconditionally undefined
|
||||
// or use the same single dominating definition. Return the definition
|
||||
// if so, otherwise return null.
|
||||
|
@ -116,6 +121,11 @@ public:
|
|||
// scope until the change has been aborted or successfully completed.
|
||||
obstack_watermark new_change_attempt () { return &m_temp_obstack; }
|
||||
|
||||
// SET either occurs in BB or is known to be available on entry to BB.
|
||||
// Return true if it is also available on exit from BB. (The value
|
||||
// might or might not be live.)
|
||||
bool remains_available_on_exit (const set_info *set, bb_info *bb);
|
||||
|
||||
// Make a best attempt to check whether the values used by USES are
|
||||
// available on entry to BB, without solving a full dataflow problem.
|
||||
// If all the values are already live on entry to BB or can be made
|
||||
|
@ -357,6 +367,10 @@ private:
|
|||
// on it. As with M_QUEUED_INSN_UPDATES, these updates are queued until
|
||||
// a convenient point.
|
||||
auto_bitmap m_need_to_purge_dead_edges;
|
||||
|
||||
// The set of hard registers that are fully or partially clobbered
|
||||
// by at least one insn_call_clobbers_note.
|
||||
HARD_REG_SET m_clobbered_by_calls;
|
||||
};
|
||||
|
||||
void pp_function (pretty_printer *, const function_info *);
|
||||
|
|
|
@ -568,6 +568,8 @@ function_info::record_call_clobbers (build_info &bi, insn_info *insn,
|
|||
insn->add_note (insn_clobbers);
|
||||
|
||||
ecc->insert_max_node (insn_clobbers);
|
||||
|
||||
m_clobbered_by_calls |= abi.full_and_partial_reg_clobbers ();
|
||||
}
|
||||
else
|
||||
for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
|
||||
|
|
|
@ -916,6 +916,15 @@ function_info::reg_defs (unsigned int regno) const
|
|||
return { m_defs[regno + 1], nullptr };
|
||||
}
|
||||
|
||||
inline bool
|
||||
function_info::is_single_dominating_def (const set_info *set) const
|
||||
{
|
||||
return (set->is_first_def ()
|
||||
&& set->is_last_def ()
|
||||
&& (!HARD_REGISTER_NUM_P (set->regno ())
|
||||
|| !TEST_HARD_REG_BIT (m_clobbered_by_calls, set->regno ())));
|
||||
}
|
||||
|
||||
inline set_info *
|
||||
function_info::single_dominating_def (unsigned int regno) const
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue