aboutsummaryrefslogtreecommitdiff
path: root/gcc/function-abi.cc
blob: 2c23b4936bf79670a53d29ba267ee69952fa778b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/* 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 (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));
}