diff mbox series

[6/6] rtl-ssa: Handle call clobbers in more places

Message ID 20231024105006.3337671-7-richard.sandiford@arm.com
State New
Headers show
Series rtl-ssa: Various fixes needed for the late-combine pass | expand

Commit Message

Richard Sandiford Oct. 24, 2023, 10:50 a.m. UTC
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.
---
 gcc/rtl-ssa/access-utils.h | 27 +++++++++------------------
 gcc/rtl-ssa/accesses.cc    | 25 +++++++++++++++++++++++++
 gcc/rtl-ssa/functions.cc   |  2 +-
 gcc/rtl-ssa/functions.h    | 14 ++++++++++++++
 gcc/rtl-ssa/insns.cc       |  2 ++
 gcc/rtl-ssa/member-fns.inl |  9 +++++++++
 6 files changed, 60 insertions(+), 19 deletions(-)

Comments

Jeff Law Oct. 24, 2023, 5:37 p.m. UTC | #1
On 10/24/23 04:50, Richard Sandiford wrote:
> 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.
OK
jeff
> ---
diff mbox series

Patch

diff --git a/gcc/rtl-ssa/access-utils.h b/gcc/rtl-ssa/access-utils.h
index 84d386b7d8b..0d7a57f843c 100644
--- a/gcc/rtl-ssa/access-utils.h
+++ b/gcc/rtl-ssa/access-utils.h
@@ -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.
diff --git a/gcc/rtl-ssa/accesses.cc b/gcc/rtl-ssa/accesses.cc
index 774ab9d99ee..c35c7efb73d 100644
--- a/gcc/rtl-ssa/accesses.cc
+++ b/gcc/rtl-ssa/accesses.cc
@@ -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.
diff --git a/gcc/rtl-ssa/functions.cc b/gcc/rtl-ssa/functions.cc
index c35d25dbf8f..8a8108baae8 100644
--- a/gcc/rtl-ssa/functions.cc
+++ b/gcc/rtl-ssa/functions.cc
@@ -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,
diff --git a/gcc/rtl-ssa/functions.h b/gcc/rtl-ssa/functions.h
index cd90b6aa9df..ab253e750cb 100644
--- a/gcc/rtl-ssa/functions.h
+++ b/gcc/rtl-ssa/functions.h
@@ -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 *);
diff --git a/gcc/rtl-ssa/insns.cc b/gcc/rtl-ssa/insns.cc
index f970375d906..5fde3f2bb4b 100644
--- a/gcc/rtl-ssa/insns.cc
+++ b/gcc/rtl-ssa/insns.cc
@@ -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)
diff --git a/gcc/rtl-ssa/member-fns.inl b/gcc/rtl-ssa/member-fns.inl
index 3fdca14e0ef..ce2db045b78 100644
--- a/gcc/rtl-ssa/member-fns.inl
+++ b/gcc/rtl-ssa/member-fns.inl
@@ -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
 {