diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2019-09-30 16:19:38 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2019-09-30 16:19:38 +0000 |
commit | bd785b44932274f7067105de417938597289962c (patch) | |
tree | 503a651572b5e0035d9cb5422d10f45b3e051b5c /gcc/function-abi.h | |
parent | 0c88d078eba7f51d2e5fc76a630f7eb369c09c87 (diff) | |
download | gcc-bd785b44932274f7067105de417938597289962c.zip gcc-bd785b44932274f7067105de417938597289962c.tar.gz gcc-bd785b44932274f7067105de417938597289962c.tar.bz2 |
Add function_abi.{h,cc}
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-30 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.
From-SVN: r276307
Diffstat (limited to 'gcc/function-abi.h')
-rw-r--r-- | gcc/function-abi.h | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/gcc/function-abi.h b/gcc/function-abi.h new file mode 100644 index 0000000..05e502e --- /dev/null +++ b/gcc/function-abi.h @@ -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 |