/* Information about fuunction binary interfaces. Copyright (C) 2019-2020 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 . */ #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 (m_id, 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 (m_id, 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 (m_id, 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 (m_id, 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 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: * Bit ID of ABIS is set if the region contains a call with function_abi identifier ID. * MASK contains all the registers that are fully or partially clobbered by calls in the region. This is not quite as accurate as testing each individual call, but it's a close and conservatively-correct approximation. It's much better for some targets than just using MASK. */ HARD_REG_SET call_clobbers_in_region (unsigned int abis, const_hard_reg_set mask, machine_mode mode) { HARD_REG_SET result; CLEAR_HARD_REG_SET (result); for (unsigned int id = 0; abis; abis >>= 1, ++id) if (abis & 1) result |= function_abis[id].mode_clobbers (mode); return result & mask; } /* 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)); if (targetm.calls.fntype_abi) return targetm.calls.fntype_abi (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); const predefined_function_abi &base_abi = fntype_abi (TREE_TYPE (fndecl)); if (flag_ipa_ra && decl_binds_to_current_def_p (fndecl)) if (cgraph_rtl_info *info = cgraph_node::rtl_info (fndecl)) return function_abi (base_abi, info->function_used_regs); return base_abi; } /* Return the ABI of the function called by INSN. */ function_abi insn_callee_abi (const rtx_insn *insn) { gcc_assert (insn && CALL_P (insn)); if (flag_ipa_ra) if (tree fndecl = get_call_fndecl (insn)) return fndecl_abi (fndecl); if (targetm.calls.insn_callee_abi) return targetm.calls.insn_callee_abi (insn); return default_function_abi; } /* Return the ABI of the function called by CALL_EXPR EXP. Return the default ABI for erroneous calls. */ function_abi expr_callee_abi (const_tree exp) { gcc_assert (TREE_CODE (exp) == CALL_EXPR); if (tree fndecl = get_callee_fndecl (exp)) return fndecl_abi (fndecl); tree callee = CALL_EXPR_FN (exp); if (callee == error_mark_node) return default_function_abi; tree type = TREE_TYPE (callee); if (type == error_mark_node) return default_function_abi; gcc_assert (POINTER_TYPE_P (type)); return fntype_abi (TREE_TYPE (type)); }