Make ira call df_set_regs_ever_live for extra call-clobbered regs
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 30 Sep 2019 16:39:38 +0000 (16:39 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 30 Sep 2019 16:39:38 +0000 (16:39 +0000)
If we support multiple ABIs in the same translation unit, it can
sometimes be the case that a callee clobbers more registers than
its caller is allowed to.  We need to call df_set_regs_ever_live
on these extra registers so that the prologue and epilogue code
can handle them appropriately.

This patch does that in IRA.  I wanted to avoid another full
instruction walk just for this, so I combined it with the existing
set_paradoxical_subreg walk.  This happens before the first
calculation of elimination offsets.

2019-09-30  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* function-abi.h (function_abi_aggregator): New class.
* function-abi.cc (function_abi_aggregator::caller_save_regs): New
function.
* ira.c (update_equiv_regs_prescan): New function.  Call
set_paradoxical_subreg here rather than...
(update_equiv_regs): ...here.
(ira): Call update_equiv_regs_prescan.

From-SVN: r276339

gcc/ChangeLog
gcc/function-abi.cc
gcc/function-abi.h
gcc/ira.c

index 00a1731..28e411c 100644 (file)
@@ -1,5 +1,15 @@
 2019-09-30  Richard Sandiford  <richard.sandiford@arm.com>
 
+       * function-abi.h (function_abi_aggregator): New class.
+       * function-abi.cc (function_abi_aggregator::caller_save_regs): New
+       function.
+       * ira.c (update_equiv_regs_prescan): New function.  Call
+       set_paradoxical_subreg here rather than...
+       (update_equiv_regs): ...here.
+       (ira): Call update_equiv_regs_prescan.
+
+2019-09-30  Richard Sandiford  <richard.sandiford@arm.com>
+
        * hard-reg-set.h (regs_invalidated_by_call): Only define if
        IN_TARGET_CODE.
        (call_used_or_fixed_regs): Likewise.
index 4bace9e..eee789a 100644 (file)
@@ -126,6 +126,42 @@ predefined_function_abi::add_full_reg_clobber (unsigned int regno)
     SET_HARD_REG_BIT (m_mode_clobbers[i], regno);
 }
 
+/* Return the set of registers that the caller of the recorded functions must
+   save in order to honor the requirements of CALLER_ABI.  */
+
+HARD_REG_SET
+function_abi_aggregator::
+caller_save_regs (const function_abi &caller_abi) const
+{
+  HARD_REG_SET result;
+  CLEAR_HARD_REG_SET (result);
+  for (unsigned int abi_id = 0; abi_id < NUM_ABI_IDS; ++abi_id)
+    {
+      const predefined_function_abi &callee_abi = function_abis[abi_id];
+
+      /* Skip cases that clearly aren't problematic.  */
+      if (abi_id == caller_abi.id ()
+         || hard_reg_set_empty_p (m_abi_clobbers[abi_id]))
+       continue;
+
+      /* Collect the set of registers that can be "more clobbered" by
+        CALLEE_ABI than by CALLER_ABI.  */
+      HARD_REG_SET extra_clobbers;
+      CLEAR_HARD_REG_SET (extra_clobbers);
+      for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i)
+       {
+         machine_mode mode = (machine_mode) i;
+         extra_clobbers |= (callee_abi.mode_clobbers (mode)
+                            & ~caller_abi.mode_clobbers (mode));
+       }
+
+      /* Restrict it to the set of registers that we actually saw
+        clobbers for (e.g. taking -fipa-ra into account).  */
+      result |= (extra_clobbers & m_abi_clobbers[abi_id]);
+    }
+  return result;
+}
+
 /* Return the set of registers that cannot be used to hold a value of
    mode MODE across the calls in a region described by ABIS and MASK, where:
 
index 8dd139e..9bb4d17 100644 (file)
@@ -208,6 +208,27 @@ protected:
   HARD_REG_SET m_mask;
 };
 
+/* This class collects information about the ABIs of functions that are
+   called in a particular region of code.  It is mostly intended to be
+   used as a local variable during an IR walk.  */
+class function_abi_aggregator
+{
+public:
+  function_abi_aggregator () : m_abi_clobbers () {}
+
+  /* Record that the code region calls a function with the given ABI.  */
+  void
+  note_callee_abi (const function_abi &abi)
+  {
+    m_abi_clobbers[abi.id ()] |= abi.full_and_partial_reg_clobbers ();
+  }
+
+  HARD_REG_SET caller_save_regs (const function_abi &) const;
+
+private:
+  HARD_REG_SET m_abi_clobbers[NUM_ABI_IDS];
+};
+
 struct target_function_abi_info
 {
   /* An array of all the target ABIs that are available in this
index 925ea26..3b4f9a8 100644 (file)
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3362,6 +3362,37 @@ def_dominates_uses (int regno)
   return true;
 }
 
+/* Scan the instructions before update_equiv_regs.  Record which registers
+   are referenced as paradoxical subregs.  Also check for cases in which
+   the current function needs to save a register that one of its call
+   instructions clobbers.
+
+   These things are logically unrelated, but it's more efficient to do
+   them together.  */
+
+static void
+update_equiv_regs_prescan (void)
+{
+  basic_block bb;
+  rtx_insn *insn;
+  function_abi_aggregator callee_abis;
+
+  FOR_EACH_BB_FN (bb, cfun)
+    FOR_BB_INSNS (bb, insn)
+      if (NONDEBUG_INSN_P (insn))
+       {
+         set_paradoxical_subreg (insn);
+         if (CALL_P (insn))
+           callee_abis.note_callee_abi (insn_callee_abi (insn));
+       }
+
+  HARD_REG_SET extra_caller_saves = callee_abis.caller_save_regs (*crtl->abi);
+  if (!hard_reg_set_empty_p (extra_caller_saves))
+    for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+      if (TEST_HARD_REG_BIT (extra_caller_saves, regno))
+       df_set_regs_ever_live (regno, true);
+}
+
 /* Find registers that are equivalent to a single value throughout the
    compilation (either because they can be referenced in memory or are
    set once from a single constant).  Lower their priority for a
@@ -3378,15 +3409,6 @@ update_equiv_regs (void)
   rtx_insn *insn;
   basic_block bb;
 
-  /* Scan insns and set pdx_subregs if the reg is used in a
-     paradoxical subreg.  Don't set such reg equivalent to a mem,
-     because lra will not substitute such equiv memory in order to
-     prevent access beyond allocated memory for paradoxical memory subreg.  */
-  FOR_EACH_BB_FN (bb, cfun)
-    FOR_BB_INSNS (bb, insn)
-      if (NONDEBUG_INSN_P (insn))
-       set_paradoxical_subreg (insn);
-
   /* Scan the insns and find which registers have equivalences.  Do this
      in a separate scan of the insns because (due to -fcse-follow-jumps)
      a register can be set below its use.  */
@@ -5276,6 +5298,7 @@ ira (FILE *f)
   init_alias_analysis ();
   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
   reg_equiv = XCNEWVEC (struct equivalence, max_reg_num ());
+  update_equiv_regs_prescan ();
   update_equiv_regs ();
 
   /* Don't move insns if live range shrinkage or register