diff mbox series

[01/32] Add function_abi.{h,cc}

Message ID mptef0mzmdg.fsf@arm.com
State New
Headers show
Series Support multiple ABIs in the same translation unit | expand

Commit Message

Richard Sandiford Sept. 11, 2019, 7:03 p.m. UTC
This patch adds new structures and functions for handling
multiple ABIs in a translation unit.  The structures are:

- predefined_function_abi: describes a static, predefined ABI
- function_abi: describes either a predefined ABI or a local
  variant of one (e.g. taking -fipa-ra into account)

The patch adds functions for getting the ABI from a given type
or decl; a later patch will also add a function for getting the
ABI of the target of a call insn.

Although ABIs are about much more than call-clobber/saved choices,
I wanted to keep the name general in case we add more ABI-related
information in future.


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

gcc/
	* Makefile.in (OBJS): Add function-abi.o.
	(GTFILES): Add function-abi.h.
	* function-abi.cc: New file.
	* function-abi.h: Likewise.
	* emit-rtl.h (rtl_data::abi): New field.
	* function.c: Include function-abi.h.
	(prepare_function_start): Initialize crtl->abi.
	* read-rtl-function.c: Include regs.h and function-abi.h.
	(read_rtl_function_body): Initialize crtl->abi.
	(read_rtl_function_body_from_file_range): Likewise.
	* reginfo.c: Include function-abi.h.
	(init_reg_sets_1): Initialize default_function_abi.
	(globalize_reg): Call add_full_reg_clobber for each predefined ABI
	when making a register global.
	* target-globals.h (this_target_function_abi_info): Declare.
	(target_globals::function_abi_info): New field.
	(restore_target_globals): Copy it.
	* target-globals.c: Include function-abi.h.
	(default_target_globals): Initialize the function_abi_info field.
	(target_globals): Allocate it.
	(save_target_globals): Free it.

Comments

Jeff Law Sept. 29, 2019, 8:50 p.m. UTC | #1
On 9/11/19 1:03 PM, Richard Sandiford wrote:
> This patch adds new structures and functions for handling
> multiple ABIs in a translation unit.  The structures are:
> 
> - predefined_function_abi: describes a static, predefined ABI
> - function_abi: describes either a predefined ABI or a local
>   variant of one (e.g. taking -fipa-ra into account)
> 
> The patch adds functions for getting the ABI from a given type
> or decl; a later patch will also add a function for getting the
> ABI of the target of a call insn.
> 
> Although ABIs are about much more than call-clobber/saved choices,
> I wanted to keep the name general in case we add more ABI-related
> information in future.
> 
> 
> 2019-09-11  Richard Sandiford  <richard.sandiford@arm.com>
> 
> gcc/
> 	* Makefile.in (OBJS): Add function-abi.o.
> 	(GTFILES): Add function-abi.h.
> 	* function-abi.cc: New file.
> 	* function-abi.h: Likewise.
> 	* emit-rtl.h (rtl_data::abi): New field.
> 	* function.c: Include function-abi.h.
> 	(prepare_function_start): Initialize crtl->abi.
> 	* read-rtl-function.c: Include regs.h and function-abi.h.
> 	(read_rtl_function_body): Initialize crtl->abi.
> 	(read_rtl_function_body_from_file_range): Likewise.
> 	* reginfo.c: Include function-abi.h.
> 	(init_reg_sets_1): Initialize default_function_abi.
> 	(globalize_reg): Call add_full_reg_clobber for each predefined ABI
> 	when making a register global.
> 	* target-globals.h (this_target_function_abi_info): Declare.
> 	(target_globals::function_abi_info): New field.
> 	(restore_target_globals): Copy it.
> 	* target-globals.c: Include function-abi.h.
> 	(default_target_globals): Initialize the function_abi_info field.
> 	(target_globals): Allocate it.
> 	(save_target_globals): Free it.
So no problem with this as-is.  Questions though:

1. Do we need to stream this information for LTO?

2. Do we need to support it for the RTL front-end, even if primarily for
testing purposes?

These may show up in later patches, if so safely assume that I'll get to
them soon enough :-)

jeff
Richard Sandiford Sept. 30, 2019, 9:19 a.m. UTC | #2
Hi Jeff,

Thanks as always for the reviews :-)

Jeff Law <law@redhat.com> writes:
> On 9/11/19 1:03 PM, Richard Sandiford wrote:
>> This patch adds new structures and functions for handling
>> multiple ABIs in a translation unit.  The structures are:
>> 
>> - predefined_function_abi: describes a static, predefined ABI
>> - function_abi: describes either a predefined ABI or a local
>>   variant of one (e.g. taking -fipa-ra into account)
>> 
>> The patch adds functions for getting the ABI from a given type
>> or decl; a later patch will also add a function for getting the
>> ABI of the target of a call insn.
>> 
>> Although ABIs are about much more than call-clobber/saved choices,
>> I wanted to keep the name general in case we add more ABI-related
>> information in future.
>> 
>> 
>> 2019-09-11  Richard Sandiford  <richard.sandiford@arm.com>
>> 
>> gcc/
>> 	* Makefile.in (OBJS): Add function-abi.o.
>> 	(GTFILES): Add function-abi.h.
>> 	* function-abi.cc: New file.
>> 	* function-abi.h: Likewise.
>> 	* emit-rtl.h (rtl_data::abi): New field.
>> 	* function.c: Include function-abi.h.
>> 	(prepare_function_start): Initialize crtl->abi.
>> 	* read-rtl-function.c: Include regs.h and function-abi.h.
>> 	(read_rtl_function_body): Initialize crtl->abi.
>> 	(read_rtl_function_body_from_file_range): Likewise.
>> 	* reginfo.c: Include function-abi.h.
>> 	(init_reg_sets_1): Initialize default_function_abi.
>> 	(globalize_reg): Call add_full_reg_clobber for each predefined ABI
>> 	when making a register global.
>> 	* target-globals.h (this_target_function_abi_info): Declare.
>> 	(target_globals::function_abi_info): New field.
>> 	(restore_target_globals): Copy it.
>> 	* target-globals.c: Include function-abi.h.
>> 	(default_target_globals): Initialize the function_abi_info field.
>> 	(target_globals): Allocate it.
>> 	(save_target_globals): Free it.
> So no problem with this as-is.  Questions though:
>
> 1. Do we need to stream this information for LTO?

At the moment this is all derived information rather than something we need
to stream directly.  E.g. the set of available predefined_function_abis
really only depends on command-line flags.  The mapping from functions
to predefined_function_abis currently depends only on the function type,
so streaming the type is enough to recover the ABI too.  function_abi
additionally depends on RTL stuff that doesn't affect LTO.

> 2. Do we need to support it for the RTL front-end, even if primarily for
> testing purposes?

Yeah, I guess it could be useful to be able to pretend that a function
is defined locally with a certain -fipa-ra clobber set, but I think in
most cases it'd be possible to do this using:

  void __attribute__ ((noinline, noclone))
  callee (void)
  {
    asm ("" ::: ...regs...);
  }

(That's the kind of test I've used in the support for the SVE PCS FWIW,
not posted yet.)

Richard
Jeff Law Sept. 30, 2019, 9:15 p.m. UTC | #3
On 9/30/19 3:19 AM, Richard Sandiford wrote:
> Hi Jeff,
> 
> Thanks as always for the reviews :-)
> 
> Jeff Law <law@redhat.com> writes:
>> On 9/11/19 1:03 PM, Richard Sandiford wrote:
>>> This patch adds new structures and functions for handling
>>> multiple ABIs in a translation unit.  The structures are:
>>>
>>> - predefined_function_abi: describes a static, predefined ABI
>>> - function_abi: describes either a predefined ABI or a local
>>>   variant of one (e.g. taking -fipa-ra into account)
>>>
>>> The patch adds functions for getting the ABI from a given type
>>> or decl; a later patch will also add a function for getting the
>>> ABI of the target of a call insn.
>>>
>>> Although ABIs are about much more than call-clobber/saved choices,
>>> I wanted to keep the name general in case we add more ABI-related
>>> information in future.
>>>
>>>
>>> 2019-09-11  Richard Sandiford  <richard.sandiford@arm.com>
>>>
>>> gcc/
>>> 	* Makefile.in (OBJS): Add function-abi.o.
>>> 	(GTFILES): Add function-abi.h.
>>> 	* function-abi.cc: New file.
>>> 	* function-abi.h: Likewise.
>>> 	* emit-rtl.h (rtl_data::abi): New field.
>>> 	* function.c: Include function-abi.h.
>>> 	(prepare_function_start): Initialize crtl->abi.
>>> 	* read-rtl-function.c: Include regs.h and function-abi.h.
>>> 	(read_rtl_function_body): Initialize crtl->abi.
>>> 	(read_rtl_function_body_from_file_range): Likewise.
>>> 	* reginfo.c: Include function-abi.h.
>>> 	(init_reg_sets_1): Initialize default_function_abi.
>>> 	(globalize_reg): Call add_full_reg_clobber for each predefined ABI
>>> 	when making a register global.
>>> 	* target-globals.h (this_target_function_abi_info): Declare.
>>> 	(target_globals::function_abi_info): New field.
>>> 	(restore_target_globals): Copy it.
>>> 	* target-globals.c: Include function-abi.h.
>>> 	(default_target_globals): Initialize the function_abi_info field.
>>> 	(target_globals): Allocate it.
>>> 	(save_target_globals): Free it.
>> So no problem with this as-is.  Questions though:
>>
>> 1. Do we need to stream this information for LTO?
> 
> At the moment this is all derived information rather than something we need
> to stream directly.  E.g. the set of available predefined_function_abis
> really only depends on command-line flags.  The mapping from functions
> to predefined_function_abis currently depends only on the function type,
> so streaming the type is enough to recover the ABI too.  function_abi
> additionally depends on RTL stuff that doesn't affect LTO.
OK.  THanks for clarifying.


> 
>> 2. Do we need to support it for the RTL front-end, even if primarily for
>> testing purposes?
> 
> Yeah, I guess it could be useful to be able to pretend that a function
> is defined locally with a certain -fipa-ra clobber set, but I think in
> most cases it'd be possible to do this using:
> 
>   void __attribute__ ((noinline, noclone))
>   callee (void)
>   {
>     asm ("" ::: ...regs...);
>   }
> 
> (That's the kind of test I've used in the support for the SVE PCS FWIW,
> not posted yet.)
Your call on whether or not it's worth it.  Given that it's supposed to
be derived info, I won't lose any sleep if it's not available in the RTL
front-end.

jeff
diff mbox series

Patch

Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	2019-09-09 17:51:55.832574829 +0100
+++ gcc/Makefile.in	2019-09-11 19:47:07.486381992 +0100
@@ -1306,6 +1306,7 @@  OBJS = \
 	fold-const.o \
 	fold-const-call.o \
 	function.o \
+	function-abi.o \
 	function-tests.o \
 	fwprop.o \
 	gcc-rich-location.o \
@@ -2522,6 +2523,7 @@  GTFILES = $(CPPLIB_H) $(srcdir)/input.h
   $(srcdir)/libfuncs.h $(SYMTAB_H) \
   $(srcdir)/real.h $(srcdir)/function.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \
   $(srcdir)/fixed-value.h \
+  $(srcdir)/function-abi.h \
   $(srcdir)/output.h $(srcdir)/cfgloop.h $(srcdir)/cfg.h $(srcdir)/profile-count.h \
   $(srcdir)/cselib.h $(srcdir)/basic-block.h  $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \
   $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \
Index: gcc/function-abi.cc
===================================================================
--- /dev/null	2019-07-30 08:53:31.317691683 +0100
+++ gcc/function-abi.cc	2019-09-11 19:47:07.490381964 +0100
@@ -0,0 +1,145 @@ 
+/* Information about fuunction binary interfaces.
+   Copyright (C) 2019 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/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "regs.h"
+#include "function-abi.h"
+#include "varasm.h"
+#include "cgraph.h"
+
+target_function_abi_info default_target_function_abi_info;
+#if SWITCHABLE_TARGET
+target_function_abi_info *this_target_function_abi_info
+  = &default_target_function_abi_info;
+#endif
+
+/* Initialize a predefined function ABI with the given values of
+   ID and FULL_REG_CLOBBERS.  */
+
+void
+predefined_function_abi::initialize (unsigned int id,
+				     const_hard_reg_set full_reg_clobbers)
+{
+  m_id = id;
+  m_initialized = true;
+  m_full_reg_clobbers = full_reg_clobbers;
+
+  /* Set up the value of m_full_and_partial_reg_clobbers.
+
+     If the ABI specifies that part of a hard register R is call-clobbered,
+     we should be able to find a single-register mode M for which
+     targetm.hard_regno_call_part_clobbered (NULL, R, M) is true.
+     In other words, it shouldn't be the case that R can hold all
+     single-register modes across a call, but can't hold part of
+     a multi-register mode.
+
+     If that assumption doesn't hold for a future target, we would need
+     to change the interface of TARGET_HARD_REGNO_CALL_PART_CLOBBERED so
+     that it tells us which registers in a multi-register value are
+     actually clobbered.  */
+  m_full_and_partial_reg_clobbers = full_reg_clobbers;
+  for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i)
+    {
+      machine_mode mode = (machine_mode) i;
+      for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+	if (targetm.hard_regno_mode_ok (regno, mode)
+	    && hard_regno_nregs (regno, mode) == 1
+	    && targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
+	  SET_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno);
+    }
+
+  /* For each mode MODE, work out which registers are unable to hold
+     any part of a MODE value across a call, i.e. those for which no
+     overlapping call-preserved (reg:MODE REGNO) exists.
+
+     We assume that this can be flipped around to say that a call
+     preserves (reg:MODE REGNO) unless the register overlaps this set.
+     The usual reason for this being true is that if (reg:MODE REGNO)
+     contains a part-clobbered register, that register would be
+     part-clobbered regardless of which part of MODE it holds.
+     For example, if (reg:M 2) occupies two registers and if the
+     register 3 portion of it is part-clobbered, (reg:M 3) is usually
+     either invalid or also part-clobbered.  */
+  for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i)
+    {
+      machine_mode mode = (machine_mode) i;
+      m_mode_clobbers[i] = m_full_and_partial_reg_clobbers;
+      for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+	if (targetm.hard_regno_mode_ok (regno, mode)
+	    && !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno)
+	    && !targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
+	  remove_from_hard_reg_set (&m_mode_clobbers[i], mode, regno);
+    }
+
+  /* Check that the assumptions above actually hold, i.e. that testing
+     for single-register modes makes sense, and that overlap tests for
+     mode_clobbers work as expected.  */
+  if (flag_checking)
+    for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i)
+      {
+	machine_mode mode = (machine_mode) i;
+	const_hard_reg_set all_clobbers = m_full_and_partial_reg_clobbers;
+	for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
+	  if (targetm.hard_regno_mode_ok (regno, mode)
+	      && !overlaps_hard_reg_set_p (m_full_reg_clobbers, mode, regno)
+	      && targetm.hard_regno_call_part_clobbered (NULL, regno, mode))
+	    gcc_assert (overlaps_hard_reg_set_p (all_clobbers, mode, regno)
+			&& overlaps_hard_reg_set_p (m_mode_clobbers[i],
+						    mode, regno));
+      }
+}
+
+/* If the ABI has been initialized, add REGNO to the set of registers
+   that can be completely altered by a call.  */
+
+void
+predefined_function_abi::add_full_reg_clobber (unsigned int regno)
+{
+  if (!m_initialized)
+    return;
+
+  SET_HARD_REG_BIT (m_full_reg_clobbers, regno);
+  SET_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno);
+  for (unsigned int i = 0; i < NUM_MACHINE_MODES; ++i)
+    SET_HARD_REG_BIT (m_mode_clobbers[i], regno);
+}
+
+/* Return the predefined ABI used by functions with type TYPE.  */
+
+const predefined_function_abi &
+fntype_abi (const_tree type)
+{
+  gcc_assert (FUNC_OR_METHOD_TYPE_P (type));
+  return default_function_abi;
+}
+
+/* Return the ABI of function decl FNDECL.  */
+
+function_abi
+fndecl_abi (const_tree fndecl)
+{
+  gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
+  return fntype_abi (TREE_TYPE (fndecl));
+}
Index: gcc/function-abi.h
===================================================================
--- /dev/null	2019-07-30 08:53:31.317691683 +0100
+++ gcc/function-abi.h	2019-09-11 19:47:07.490381964 +0100
@@ -0,0 +1,269 @@ 
+/* Information about fuunction binary interfaces.
+   Copyright (C) 2019 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_FUNCTION_ABI_H
+#define GCC_FUNCTION_ABI_H
+
+/* Most targets use the same ABI for all functions in a translation
+   unit, but some targets support interoperability between several ABIs.
+   Each such ABI has a unique 0-based identifier, with 0 always being
+   the default choice of ABI.
+
+   NUM_ABI_IDS is the maximum number of such ABIs that GCC can handle at once.
+   A bitfield with this number of bits can represent any combinaion of the
+   supported ABIs.  */
+const size_t NUM_ABI_IDS = 8;
+
+/* Information about one of the target's predefined ABIs.  */
+class predefined_function_abi
+{
+public:
+  /* A target-specific identifier for this ABI.  The value must be in
+     the range [0, NUM_ABI_IDS - 1].  */
+  unsigned int id () const { return m_id; }
+
+  /* True if this ABI has been initialized.  */
+  bool initialized_p () const { return m_initialized; }
+
+  /* Return true if a function call is allowed to alter every bit of
+     register REGNO, so that the register contains an arbitrary value
+     on return.  If so, the register cannot hold any part of a value
+     that is live across a call.  */
+  bool
+  clobbers_full_reg_p (unsigned int regno) const
+  {
+    return TEST_HARD_REG_BIT (m_full_reg_clobbers, regno);
+  }
+
+  /* Return true if a function call is allowed to alter some or all bits
+     of register REGNO.
+
+     This is true whenever clobbers_full_reg_p (REGNO) is true.  It is
+     also true if, for example, the ABI says that a call must preserve the
+     low 32 or 64 bits of REGNO, but can clobber the upper bits of REGNO.
+     In the latter case, it is possible for REGNO to hold values that
+     are live across a call, provided that the value occupies only the
+     call-preserved part of the register.  */
+  bool
+  clobbers_at_least_part_of_reg_p (unsigned int regno) const
+  {
+    return TEST_HARD_REG_BIT (m_full_and_partial_reg_clobbers, regno);
+  }
+
+  /* Return true if a function call is allowed to clobber at least part
+     of (reg:MODE REGNO).  If so, it is not possible for the register
+     as a whole to be live across a call.  */
+  bool
+  clobbers_reg_p (machine_mode mode, unsigned int regno) const
+  {
+    return overlaps_hard_reg_set_p (m_mode_clobbers[mode], mode, regno);
+  }
+
+  /* Return the set of registers that a function call is allowed to
+     alter completely, so that the registers contain arbitrary values
+     on return.  This doesn't include registers that a call can only
+     partly clobber (as per TARGET_HARD_REGNO_CALL_PART_CLOBBERED).
+
+     These registers cannot hold any part of a value that is live across
+     a call.  */
+  HARD_REG_SET full_reg_clobbers () const { return m_full_reg_clobbers; }
+
+  /* Return the set of registers that a function call is allowed to alter
+     to some degree.  For example, if an ABI says that a call must preserve
+     the low 32 or 64 bits of a register R, but can clobber the upper bits
+     of R, R would be in this set but not in full_reg_clobbers ().
+
+     This set is a superset of full_reg_clobbers ().  It is possible for a
+     register in full_and_partial_reg_clobbers () & ~full_reg_clobbers ()
+     to contain values that are live across a call, provided that the live
+     value only occupies the call-preserved part of the register.  */
+  HARD_REG_SET
+  full_and_partial_reg_clobbers () const
+  {
+    return m_full_and_partial_reg_clobbers;
+  }
+
+  /* Return the set of registers that cannot be used to hold a value of
+     mode MODE across a function call.  That is:
+
+       (reg:REGNO MODE)
+
+     might be clobbered by a call whenever:
+
+       overlaps_hard_reg_set (mode_clobbers (MODE), MODE, REGNO)
+
+     In allocation terms, the registers in the returned set conflict
+     with any value of mode MODE that is live across a call.  */
+  HARD_REG_SET
+  mode_clobbers (machine_mode mode) const
+  {
+    return m_mode_clobbers[mode];
+  }
+
+  void initialize (unsigned int, const_hard_reg_set);
+  void add_full_reg_clobber (unsigned int);
+
+private:
+  unsigned int m_id : NUM_ABI_IDS;
+  unsigned int m_initialized : 1;
+  HARD_REG_SET m_full_reg_clobbers;
+  HARD_REG_SET m_full_and_partial_reg_clobbers;
+  HARD_REG_SET m_mode_clobbers[NUM_MACHINE_MODES];
+};
+
+/* Describes either a predefined ABI or the ABI of a particular function.
+   In the latter case, the ABI might make use of extra function-specific
+   information, such as for -fipa-ra.  */
+class function_abi
+{
+public:
+  /* Initialize the structure for a general function with the given ABI.  */
+  function_abi (const predefined_function_abi &base_abi)
+    : m_base_abi (&base_abi),
+      m_mask (base_abi.full_and_partial_reg_clobbers ()) {}
+
+  /* Initialize the structure for a function that has the given ABI and
+     that is known not to clobber registers outside MASK.  */
+  function_abi (const predefined_function_abi &base_abi,
+		const_hard_reg_set mask)
+    : m_base_abi (&base_abi), m_mask (mask) {}
+
+  /* The predefined ABI from which this ABI is derived.  */
+  const predefined_function_abi &base_abi () const { return *m_base_abi; }
+
+  /* The target-specific identifier of the predefined ABI.  */
+  unsigned int id () const { return m_base_abi->id (); }
+
+  /* See the corresponding predefined_function_abi functions for
+     details about the following functions.  */
+
+  HARD_REG_SET
+  full_reg_clobbers () const
+  {
+    return m_mask & m_base_abi->full_reg_clobbers ();
+  }
+
+  HARD_REG_SET
+  full_and_partial_reg_clobbers () const
+  {
+    return m_mask & m_base_abi->full_and_partial_reg_clobbers ();
+  }
+
+  HARD_REG_SET
+  mode_clobbers (machine_mode mode) const
+  {
+    return m_mask & m_base_abi->mode_clobbers (mode);
+  }
+
+  bool
+  clobbers_full_reg_p (unsigned int regno) const
+  {
+    return (TEST_HARD_REG_BIT (m_mask, regno)
+	    & m_base_abi->clobbers_full_reg_p (regno));
+  }
+
+  bool
+  clobbers_at_least_part_of_reg_p (unsigned int regno) const
+  {
+    return (TEST_HARD_REG_BIT (m_mask, regno)
+	    & m_base_abi->clobbers_at_least_part_of_reg_p (regno));
+  }
+
+  bool
+  clobbers_reg_p (machine_mode mode, unsigned int regno) const
+  {
+    return overlaps_hard_reg_set_p (mode_clobbers (mode), mode, regno);
+  }
+
+  bool
+  operator== (const function_abi &other) const
+  {
+    return m_base_abi == other.m_base_abi && m_mask == other.m_mask;
+  }
+
+  bool
+  operator!= (const function_abi &other) const
+  {
+    return !operator== (other);
+  }
+
+protected:
+  const predefined_function_abi *m_base_abi;
+  HARD_REG_SET m_mask;
+};
+
+struct target_function_abi_info
+{
+  /* An array of all the target ABIs that are available in this
+     translation unit.  Not all entries are used for all targets,
+     but the structures are relatively small, and using a fixed-size
+     array avoids extra indirection.
+
+     There are various ways of getting an ABI descriptor:
+
+     * fndecl_abi (FNDECL) is the ABI of function FNDECL.
+
+     * fntype_abi (FNTYPE) is the ABI of a function with type FNTYPE.
+
+     * crtl->abi is the ABI of the function that we are currently
+       compiling to rtl.
+
+     * eh_edge_abi is the "ABI" used when taking an EH edge from an
+       exception-throwing statement to an exception handler.  Catching
+       exceptions from calls can be treated as an abnormal return from
+       those calls, and this ABI therefore describes the ABI of functions
+       on such an abnormal return.  Statements that throw non-call
+       exceptions can be treated as being implicitly wrapped in a call
+       that has such an abnormal return.
+
+       At present, no target needs to support more than one EH ABI.
+
+     * function_abis[N] is the ABI with identifier N.  This can be useful
+       when referring back to ABIs that have been collected by number in
+       a bitmask, such as after walking function calls in a particular
+       region of code.
+
+     * default_function_abi refers specifically to the target's default
+       choice of ABI, regardless of which (if any) functions actually
+       use it.  This ABI and data derived from it do *not* provide
+       globally conservatively-correct information, so it is only
+       useful in very specific circumstances.  */
+  predefined_function_abi x_function_abis[NUM_ABI_IDS];
+};
+
+extern target_function_abi_info default_target_function_abi_info;
+#if SWITCHABLE_TARGET
+extern target_function_abi_info *this_target_function_abi_info;
+#else
+#define this_target_function_abi_info (&default_target_function_abi_info)
+#endif
+
+/* See the comment above x_function_abis for when these macros should be used.
+   At present, eh_edge_abi is always the default ABI, but that could change
+   in future if a target needs it to.  */
+#define function_abis \
+  (this_target_function_abi_info->x_function_abis)
+#define default_function_abi \
+  (this_target_function_abi_info->x_function_abis[0])
+#define eh_edge_abi default_function_abi
+
+extern const predefined_function_abi &fntype_abi (const_tree);
+extern function_abi fndecl_abi (const_tree);
+
+#endif
Index: gcc/emit-rtl.h
===================================================================
--- gcc/emit-rtl.h	2019-07-10 19:41:26.395898027 +0100
+++ gcc/emit-rtl.h	2019-09-11 19:47:07.490381964 +0100
@@ -22,6 +22,7 @@  #define GCC_EMIT_RTL_H
 
 class temp_slot;
 typedef class temp_slot *temp_slot_p;
+class predefined_function_abi;
 
 /* Information mainlined about RTL representation of incoming arguments.  */
 struct GTY(()) incoming_args {
@@ -64,6 +65,14 @@  struct GTY(()) rtl_data {
   struct function_subsections subsections;
   struct rtl_eh eh;
 
+  /* The ABI of the function, i.e. the interface it presents to its callers.
+     This is the ABI that should be queried to see which registers the
+     function needs to save before it uses them.
+
+     Other functions (including those called by this function) might use
+     different ABIs.  */
+  const predefined_function_abi *GTY((skip)) abi;
+
   /* For function.c  */
 
   /* # of bytes of outgoing arguments.  If ACCUMULATE_OUTGOING_ARGS is
Index: gcc/function.c
===================================================================
--- gcc/function.c	2019-09-10 19:56:45.353177919 +0100
+++ gcc/function.c	2019-09-11 19:47:07.490381964 +0100
@@ -79,6 +79,7 @@  Software Foundation; either version 3, o
 #include "attribs.h"
 #include "gimple.h"
 #include "options.h"
+#include "function-abi.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
@@ -4827,6 +4828,12 @@  push_struct_function (tree fndecl)
 prepare_function_start (void)
 {
   gcc_assert (!get_last_insn ());
+
+  if (in_dummy_function)
+    crtl->abi = &default_function_abi;
+  else
+    crtl->abi = &fndecl_abi (cfun->decl).base_abi ();
+
   init_temp_slots ();
   init_emit ();
   init_varasm_status ();
Index: gcc/read-rtl-function.c
===================================================================
--- gcc/read-rtl-function.c	2019-07-10 19:41:21.619936277 +0100
+++ gcc/read-rtl-function.c	2019-09-11 19:47:07.490381964 +0100
@@ -41,6 +41,8 @@  Software Foundation; either version 3, o
 #include "read-rtl-function.h"
 #include "selftest.h"
 #include "selftest-rtl.h"
+#include "regs.h"
+#include "function-abi.h"
 
 /* Forward decls.  */
 class function_reader;
@@ -1611,6 +1613,7 @@  function_reader::get_insn_by_uid (int ui
 read_rtl_function_body (const char *path)
 {
   initialize_rtl ();
+  crtl->abi = &default_function_abi;
   init_emit ();
   init_varasm_status ();
 
@@ -1644,6 +1647,7 @@  read_rtl_function_body_from_file_range (
     }
 
   initialize_rtl ();
+  crtl->abi = &fndecl_abi (cfun->decl).base_abi ();
   init_emit ();
   init_varasm_status ();
 
Index: gcc/reginfo.c
===================================================================
--- gcc/reginfo.c	2019-09-10 19:57:04.713041281 +0100
+++ gcc/reginfo.c	2019-09-11 19:47:07.490381964 +0100
@@ -43,6 +43,7 @@  Software Foundation; either version 3, o
 #include "reload.h"
 #include "output.h"
 #include "tree-pass.h"
+#include "function-abi.h"
 
 /* Maximum register number used in this function, plus one.  */
 
@@ -419,6 +420,8 @@  init_reg_sets_1 (void)
 	       }
 	  }
      }
+
+  default_function_abi.initialize (0, regs_invalidated_by_call);
 }
 
 /* Compute the table of register modes.
@@ -728,7 +731,11 @@  globalize_reg (tree decl, int i)
      appropriate regs_invalidated_by_call bit, even if it's already
      set in fixed_regs.  */
   if (i != STACK_POINTER_REGNUM)
-    SET_HARD_REG_BIT (regs_invalidated_by_call, i);
+    {
+      SET_HARD_REG_BIT (regs_invalidated_by_call, i);
+      for (unsigned int i = 0; i < NUM_ABI_IDS; ++i)
+	function_abis[i].add_full_reg_clobber (i);
+    }
 
   /* If already fixed, nothing else to do.  */
   if (fixed_regs[i])
Index: gcc/target-globals.h
===================================================================
--- gcc/target-globals.h	2019-07-10 19:41:21.635936149 +0100
+++ gcc/target-globals.h	2019-09-11 19:47:07.490381964 +0100
@@ -26,6 +26,7 @@  #define TARGET_GLOBALS_H 1
 extern struct target_rtl *this_target_rtl;
 extern struct target_recog *this_target_recog;
 extern struct target_hard_regs *this_target_hard_regs;
+extern struct target_function_abi_info *this_target_function_abi_info;
 extern struct target_reload *this_target_reload;
 extern struct target_expmed *this_target_expmed;
 extern struct target_optabs *this_target_optabs;
@@ -48,6 +49,7 @@  class GTY(()) target_globals {
   struct target_rtl *rtl;
   struct target_recog *GTY((skip)) recog;
   struct target_hard_regs *GTY((skip)) hard_regs;
+  struct target_function_abi_info *GTY((skip)) function_abi_info;
   struct target_reload *GTY((skip)) reload;
   struct target_expmed *GTY((skip)) expmed;
   struct target_optabs *GTY((skip)) optabs;
@@ -75,6 +77,7 @@  restore_target_globals (class target_glo
   this_target_rtl = g->rtl;
   this_target_recog = g->recog;
   this_target_hard_regs = g->hard_regs;
+  this_target_function_abi_info = g->function_abi_info;
   this_target_reload = g->reload;
   this_target_expmed = g->expmed;
   this_target_optabs = g->optabs;
Index: gcc/target-globals.c
===================================================================
--- gcc/target-globals.c	2019-07-10 19:41:21.635936149 +0100
+++ gcc/target-globals.c	2019-09-11 19:47:07.490381964 +0100
@@ -40,6 +40,7 @@  Software Foundation; either version 3, o
 #include "gcse.h"
 #include "bb-reorder.h"
 #include "lower-subreg.h"
+#include "function-abi.h"
 
 #if SWITCHABLE_TARGET
 class target_globals default_target_globals = {
@@ -48,6 +49,7 @@  class target_globals default_target_glob
   &default_target_rtl,
   &default_target_recog,
   &default_target_hard_regs,
+  &default_target_function_abi_info,
   &default_target_reload,
   &default_target_expmed,
   &default_target_optabs,
@@ -70,6 +72,7 @@  save_target_globals (void)
   g->rtl = ggc_cleared_alloc<target_rtl> ();
   g->recog = XCNEW (struct target_recog);
   g->hard_regs = XCNEW (struct target_hard_regs);
+  g->function_abi_info = XCNEW (struct target_function_abi_info);
   g->reload = XCNEW (struct target_reload);
   g->expmed = XCNEW (struct target_expmed);
   g->optabs = XCNEW (struct target_optabs);
@@ -127,6 +130,7 @@  target_globals::~target_globals ()
       XDELETE (regs);
       XDELETE (recog);
       XDELETE (hard_regs);
+      XDELETE (function_abi_info);
       XDELETE (reload);
       XDELETE (expmed);
       XDELETE (optabs);