aboutsummaryrefslogtreecommitdiff
path: root/gcc/function-abi.cc
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2019-09-30 16:19:38 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2019-09-30 16:19:38 +0000
commitbd785b44932274f7067105de417938597289962c (patch)
tree503a651572b5e0035d9cb5422d10f45b3e051b5c /gcc/function-abi.cc
parent0c88d078eba7f51d2e5fc76a630f7eb369c09c87 (diff)
downloadgcc-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.cc')
-rw-r--r--gcc/function-abi.cc145
1 files changed, 145 insertions, 0 deletions
diff --git a/gcc/function-abi.cc b/gcc/function-abi.cc
new file mode 100644
index 0000000..e7c8581
--- /dev/null
+++ b/gcc/function-abi.cc
@@ -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));
+}