File: | build/gcc/caller-save.cc |
Warning: | line 1205, column 25 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Save and restore call-clobbered registers which are live across a call. | |||
2 | Copyright (C) 1989-2023 Free Software Foundation, Inc. | |||
3 | ||||
4 | This file is part of GCC. | |||
5 | ||||
6 | GCC is free software; you can redistribute it and/or modify it under | |||
7 | the terms of the GNU General Public License as published by the Free | |||
8 | Software Foundation; either version 3, or (at your option) any later | |||
9 | version. | |||
10 | ||||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
14 | for more details. | |||
15 | ||||
16 | You should have received a copy of the GNU General Public License | |||
17 | along with GCC; see the file COPYING3. If not see | |||
18 | <http://www.gnu.org/licenses/>. */ | |||
19 | ||||
20 | #include "config.h" | |||
21 | #include "system.h" | |||
22 | #include "coretypes.h" | |||
23 | #include "backend.h" | |||
24 | #include "rtl.h" | |||
25 | #include "tree.h" | |||
26 | #include "predict.h" | |||
27 | #include "df.h" | |||
28 | #include "memmodel.h" | |||
29 | #include "tm_p.h" | |||
30 | #include "insn-config.h" | |||
31 | #include "regs.h" | |||
32 | #include "emit-rtl.h" | |||
33 | #include "recog.h" | |||
34 | #include "reload.h" | |||
35 | #include "alias.h" | |||
36 | #include "addresses.h" | |||
37 | #include "dumpfile.h" | |||
38 | #include "rtl-iter.h" | |||
39 | #include "target.h" | |||
40 | #include "function-abi.h" | |||
41 | ||||
42 | #define MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)) (MOVE_MAX((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : ((((global_options .x_ix86_isa_flags & (1UL << 8)) != 0) && (global_options .x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features [X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL] && ix86_tune_features [X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL]) ? 16 : (((global_options .x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / UNITS_PER_WORD(((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)) | |||
43 | ||||
44 | #define regno_save_mode(this_target_reload->x_regno_save_mode) \ | |||
45 | (this_target_reload->x_regno_save_mode) | |||
46 | #define cached_reg_save_code(this_target_reload->x_cached_reg_save_code) \ | |||
47 | (this_target_reload->x_cached_reg_save_code) | |||
48 | #define cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code) \ | |||
49 | (this_target_reload->x_cached_reg_restore_code) | |||
50 | ||||
51 | /* For each hard register, a place on the stack where it can be saved, | |||
52 | if needed. */ | |||
53 | ||||
54 | static rtx | |||
55 | regno_save_mem[FIRST_PSEUDO_REGISTER76][MAX_MOVE_MAX64 / MIN_UNITS_PER_WORD4 + 1]; | |||
56 | ||||
57 | /* The number of elements in the subsequent array. */ | |||
58 | static int save_slots_num; | |||
59 | ||||
60 | /* Allocated slots so far. */ | |||
61 | static rtx save_slots[FIRST_PSEUDO_REGISTER76]; | |||
62 | ||||
63 | /* Set of hard regs currently residing in save area (during insn scan). */ | |||
64 | ||||
65 | static HARD_REG_SET hard_regs_saved; | |||
66 | ||||
67 | /* Number of registers currently in hard_regs_saved. */ | |||
68 | ||||
69 | static int n_regs_saved; | |||
70 | ||||
71 | /* Computed by mark_referenced_regs, all regs referenced in a given | |||
72 | insn. */ | |||
73 | static HARD_REG_SET referenced_regs; | |||
74 | ||||
75 | ||||
76 | typedef void refmarker_fn (rtx *loc, machine_mode mode, int hardregno, | |||
77 | void *mark_arg); | |||
78 | ||||
79 | static int reg_save_code (int, machine_mode); | |||
80 | static int reg_restore_code (int, machine_mode); | |||
81 | ||||
82 | struct saved_hard_reg; | |||
83 | static void initiate_saved_hard_regs (void); | |||
84 | static void new_saved_hard_reg (int, int); | |||
85 | static void finish_saved_hard_regs (void); | |||
86 | static int saved_hard_reg_compare_func (const void *, const void *); | |||
87 | ||||
88 | static void mark_set_regs (rtx, const_rtx, void *); | |||
89 | static void mark_referenced_regs (rtx *, refmarker_fn *mark, void *mark_arg); | |||
90 | static refmarker_fn mark_reg_as_referenced; | |||
91 | static refmarker_fn replace_reg_with_saved_mem; | |||
92 | static int insert_save (class insn_chain *, int, HARD_REG_SET *, | |||
93 | machine_mode *); | |||
94 | static int insert_restore (class insn_chain *, int, int, int, | |||
95 | machine_mode *); | |||
96 | static class insn_chain *insert_one_insn (class insn_chain *, int, int, | |||
97 | rtx); | |||
98 | static void add_stored_regs (rtx, const_rtx, void *); | |||
99 | ||||
100 | ||||
101 | ||||
102 | static GTY(()) rtx savepat; | |||
103 | static GTY(()) rtx restpat; | |||
104 | static GTY(()) rtx test_reg; | |||
105 | static GTY(()) rtx test_mem; | |||
106 | static GTY(()) rtx_insn *saveinsn; | |||
107 | static GTY(()) rtx_insn *restinsn; | |||
108 | ||||
109 | /* Return the INSN_CODE used to save register REG in mode MODE. */ | |||
110 | static int | |||
111 | reg_save_code (int reg, machine_mode mode) | |||
112 | { | |||
113 | bool ok; | |||
114 | if (cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode]) | |||
115 | return cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode]; | |||
116 | if (!targetm.hard_regno_mode_ok (reg, mode)) | |||
117 | { | |||
118 | /* Depending on how targetm.hard_regno_mode_ok is defined, range | |||
119 | propagation might deduce here that reg >= FIRST_PSEUDO_REGISTER. | |||
120 | So the assert below silences a warning. */ | |||
121 | gcc_assert (reg < FIRST_PSEUDO_REGISTER)((void)(!(reg < 76) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 121, __FUNCTION__), 0 : 0)); | |||
122 | cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode] = -1; | |||
123 | cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode] = -1; | |||
124 | return -1; | |||
125 | } | |||
126 | ||||
127 | /* Update the register number and modes of the register | |||
128 | and memory operand. */ | |||
129 | set_mode_and_regno (test_reg, mode, reg); | |||
130 | PUT_MODE (test_mem, mode); | |||
131 | ||||
132 | /* Force re-recognition of the modified insns. */ | |||
133 | INSN_CODE (saveinsn)(((saveinsn)->u.fld[5]).rt_int) = -1; | |||
134 | INSN_CODE (restinsn)(((restinsn)->u.fld[5]).rt_int) = -1; | |||
135 | ||||
136 | cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode] = recog_memoized (saveinsn); | |||
137 | cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode] = recog_memoized (restinsn); | |||
138 | ||||
139 | /* Now extract both insns and see if we can meet their | |||
140 | constraints. We don't know here whether the save and restore will | |||
141 | be in size- or speed-tuned code, so just use the set of enabled | |||
142 | alternatives. */ | |||
143 | ok = (cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode] != -1 | |||
144 | && cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode] != -1); | |||
145 | if (ok) | |||
146 | { | |||
147 | extract_insn (saveinsn); | |||
148 | ok = constrain_operands (1, get_enabled_alternatives (saveinsn)); | |||
149 | extract_insn (restinsn); | |||
150 | ok &= constrain_operands (1, get_enabled_alternatives (restinsn)); | |||
151 | } | |||
152 | ||||
153 | if (! ok) | |||
154 | { | |||
155 | cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode] = -1; | |||
156 | cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode] = -1; | |||
157 | } | |||
158 | gcc_assert (cached_reg_save_code[reg][mode])((void)(!((this_target_reload->x_cached_reg_save_code)[reg ][mode]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 158, __FUNCTION__), 0 : 0)); | |||
159 | return cached_reg_save_code(this_target_reload->x_cached_reg_save_code)[reg][mode]; | |||
160 | } | |||
161 | ||||
162 | /* Return the INSN_CODE used to restore register REG in mode MODE. */ | |||
163 | static int | |||
164 | reg_restore_code (int reg, machine_mode mode) | |||
165 | { | |||
166 | if (cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode]) | |||
167 | return cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode]; | |||
168 | /* Populate our cache. */ | |||
169 | reg_save_code (reg, mode); | |||
170 | return cached_reg_restore_code(this_target_reload->x_cached_reg_restore_code)[reg][mode]; | |||
171 | } | |||
172 | ||||
173 | /* Initialize for caller-save. | |||
174 | ||||
175 | Look at all the hard registers that are used by a call and for which | |||
176 | reginfo.cc has not already excluded from being used across a call. | |||
177 | ||||
178 | Ensure that we can find a mode to save the register and that there is a | |||
179 | simple insn to save and restore the register. This latter check avoids | |||
180 | problems that would occur if we tried to save the MQ register of some | |||
181 | machines directly into memory. */ | |||
182 | ||||
183 | void | |||
184 | init_caller_save (void) | |||
185 | { | |||
186 | rtx addr_reg; | |||
187 | int offset; | |||
188 | rtx address; | |||
189 | int i, j; | |||
190 | ||||
191 | if (caller_save_initialized_p(this_target_reload->x_caller_save_initialized_p)) | |||
192 | return; | |||
193 | ||||
194 | caller_save_initialized_p(this_target_reload->x_caller_save_initialized_p) = true; | |||
195 | ||||
196 | /* First find all the registers that we need to deal with and all | |||
197 | the modes that they can have. If we can't find a mode to use, | |||
198 | we can't have the register live over calls. */ | |||
199 | ||||
200 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
201 | for (j = 1; j <= MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); j++) | |||
202 | { | |||
203 | regno_save_mode(this_target_reload->x_regno_save_mode)[i][j] = HARD_REGNO_CALLER_SAVE_MODE (i, j, VOIDmode)(((i) == 17) ? ((void) 0, E_VOIDmode) : (((void) 0, E_VOIDmode )) == ((void) 0, E_VOIDmode) && (j) != 1 ? ((void) 0, E_VOIDmode) : (((void) 0, E_VOIDmode)) == ((void) 0, E_VOIDmode ) ? choose_hard_reg_mode ((i), (j), nullptr) : (((void) 0, E_VOIDmode )) == (scalar_int_mode ((scalar_int_mode::from_int) E_HImode) ) && !((((((unsigned long) ((i)) - (unsigned long) (0 ) <= (unsigned long) (7) - (unsigned long) (0))) || ((unsigned long) ((i)) - (unsigned long) (36) <= (unsigned long) (43 ) - (unsigned long) (36))) && ix86_tune_features[X86_TUNE_PARTIAL_REG_STALL ]) || ((unsigned long) ((i)) - (unsigned long) (68) <= (unsigned long) (75) - (unsigned long) (68))) ? (scalar_int_mode ((scalar_int_mode ::from_int) E_SImode)) : (((void) 0, E_VOIDmode)) == (scalar_int_mode ((scalar_int_mode::from_int) E_QImode)) && !((((global_options .x_ix86_isa_flags & (1UL << 1)) != 0) ? ((((unsigned long) ((i)) - (unsigned long) (0) <= (unsigned long) (7) - (unsigned long) (0))) || ((unsigned long) ((i)) - (unsigned long ) (36) <= (unsigned long) (43) - (unsigned long) (36))) : ( (unsigned long) ((i)) - (unsigned long) (0) <= (unsigned long ) (3) - (unsigned long) (0))) || ((unsigned long) ((i)) - (unsigned long) (68) <= (unsigned long) (75) - (unsigned long) (68) )) ? (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) : (((void) 0, E_VOIDmode))); | |||
204 | if (regno_save_mode(this_target_reload->x_regno_save_mode)[i][j] == VOIDmode((void) 0, E_VOIDmode) && j == 1) | |||
205 | CLEAR_HARD_REG_BIT (savable_regs(this_target_hard_regs->x_savable_regs), i); | |||
206 | } | |||
207 | ||||
208 | /* The following code tries to approximate the conditions under which | |||
209 | we can easily save and restore a register without scratch registers or | |||
210 | other complexities. It will usually work, except under conditions where | |||
211 | the validity of an insn operand is dependent on the address offset. | |||
212 | No such cases are currently known. | |||
213 | ||||
214 | We first find a typical offset from some BASE_REG_CLASS register. | |||
215 | This address is chosen by finding the first register in the class | |||
216 | and by finding the smallest power of two that is a valid offset from | |||
217 | that register in every mode we will use to save registers. */ | |||
218 | ||||
219 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
220 | if (TEST_HARD_REG_BIT | |||
221 | (reg_class_contents(this_target_hard_regs->x_reg_class_contents) | |||
222 | [(int) base_reg_class (regno_save_mode(this_target_reload->x_regno_save_mode)[i][1], ADDR_SPACE_GENERIC0, | |||
223 | PLUS, CONST_INT)], i)) | |||
224 | break; | |||
225 | ||||
226 | gcc_assert (i < FIRST_PSEUDO_REGISTER)((void)(!(i < 76) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 226, __FUNCTION__), 0 : 0)); | |||
227 | ||||
228 | addr_reg = gen_rtx_REG (Pmode(global_options.x_ix86_pmode == PMODE_DI ? (scalar_int_mode ( (scalar_int_mode::from_int) E_DImode)) : (scalar_int_mode ((scalar_int_mode ::from_int) E_SImode))), i); | |||
229 | ||||
230 | for (offset = 1 << (HOST_BITS_PER_INT(8 * 4) / 2); offset; offset >>= 1) | |||
231 | { | |||
232 | address = gen_rtx_PLUS (Pmode, addr_reg, gen_int_mode (offset, Pmode))gen_rtx_fmt_ee_stat ((PLUS), (((global_options.x_ix86_pmode == PMODE_DI ? (scalar_int_mode ((scalar_int_mode::from_int) E_DImode )) : (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) ))), ((addr_reg)), ((gen_int_mode (offset, (global_options.x_ix86_pmode == PMODE_DI ? (scalar_int_mode ((scalar_int_mode::from_int) E_DImode )) : (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) )))) ); | |||
233 | ||||
234 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
235 | if (regno_save_mode(this_target_reload->x_regno_save_mode)[i][1] != VOIDmode((void) 0, E_VOIDmode) | |||
236 | && ! strict_memory_address_p (regno_save_mode[i][1], address)strict_memory_address_addr_space_p (((this_target_reload-> x_regno_save_mode)[i][1]), (address), 0)) | |||
237 | break; | |||
238 | ||||
239 | if (i == FIRST_PSEUDO_REGISTER76) | |||
240 | break; | |||
241 | } | |||
242 | ||||
243 | /* If we didn't find a valid address, we must use register indirect. */ | |||
244 | if (offset == 0) | |||
245 | address = addr_reg; | |||
246 | ||||
247 | /* Next we try to form an insn to save and restore the register. We | |||
248 | see if such an insn is recognized and meets its constraints. | |||
249 | ||||
250 | To avoid lots of unnecessary RTL allocation, we construct all the RTL | |||
251 | once, then modify the memory and register operands in-place. */ | |||
252 | ||||
253 | test_reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER(((76)) + 5) + 1); | |||
254 | test_mem = gen_rtx_MEM (word_mode, address); | |||
255 | savepat = gen_rtx_SET (test_mem, test_reg)gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), ((test_mem )), ((test_reg)) ); | |||
256 | restpat = gen_rtx_SET (test_reg, test_mem)gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), ((test_reg )), ((test_mem)) ); | |||
257 | ||||
258 | saveinsn = gen_rtx_INSN (VOIDmode((void) 0, E_VOIDmode), 0, 0, 0, savepat, 0, -1, 0); | |||
259 | restinsn = gen_rtx_INSN (VOIDmode((void) 0, E_VOIDmode), 0, 0, 0, restpat, 0, -1, 0); | |||
260 | ||||
261 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
262 | for (j = 1; j <= MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); j++) | |||
263 | if (reg_save_code (i,regno_save_mode(this_target_reload->x_regno_save_mode)[i][j]) == -1) | |||
264 | { | |||
265 | regno_save_mode(this_target_reload->x_regno_save_mode)[i][j] = VOIDmode((void) 0, E_VOIDmode); | |||
266 | if (j == 1) | |||
267 | CLEAR_HARD_REG_BIT (savable_regs(this_target_hard_regs->x_savable_regs), i); | |||
268 | } | |||
269 | } | |||
270 | ||||
271 | ||||
272 | ||||
273 | /* Initialize save areas by showing that we haven't allocated any yet. */ | |||
274 | ||||
275 | void | |||
276 | init_save_areas (void) | |||
277 | { | |||
278 | int i, j; | |||
279 | ||||
280 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
281 | for (j = 1; j <= MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); j++) | |||
282 | regno_save_mem[i][j] = 0; | |||
283 | save_slots_num = 0; | |||
284 | ||||
285 | } | |||
286 | ||||
287 | /* The structure represents a hard register which should be saved | |||
288 | through the call. It is used when the integrated register | |||
289 | allocator (IRA) is used and sharing save slots is on. */ | |||
290 | struct saved_hard_reg | |||
291 | { | |||
292 | /* Order number starting with 0. */ | |||
293 | int num; | |||
294 | /* The hard regno. */ | |||
295 | int hard_regno; | |||
296 | /* Execution frequency of all calls through which given hard | |||
297 | register should be saved. */ | |||
298 | int call_freq; | |||
299 | /* Stack slot reserved to save the hard register through calls. */ | |||
300 | rtx slot; | |||
301 | /* True if it is first hard register in the chain of hard registers | |||
302 | sharing the same stack slot. */ | |||
303 | int first_p; | |||
304 | /* Order number of the next hard register structure with the same | |||
305 | slot in the chain. -1 represents end of the chain. */ | |||
306 | int next; | |||
307 | }; | |||
308 | ||||
309 | /* Map: hard register number to the corresponding structure. */ | |||
310 | static struct saved_hard_reg *hard_reg_map[FIRST_PSEUDO_REGISTER76]; | |||
311 | ||||
312 | /* The number of all structures representing hard registers should be | |||
313 | saved, in order words, the number of used elements in the following | |||
314 | array. */ | |||
315 | static int saved_regs_num; | |||
316 | ||||
317 | /* Pointers to all the structures. Index is the order number of the | |||
318 | corresponding structure. */ | |||
319 | static struct saved_hard_reg *all_saved_regs[FIRST_PSEUDO_REGISTER76]; | |||
320 | ||||
321 | /* First called function for work with saved hard registers. */ | |||
322 | static void | |||
323 | initiate_saved_hard_regs (void) | |||
324 | { | |||
325 | int i; | |||
326 | ||||
327 | saved_regs_num = 0; | |||
328 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
329 | hard_reg_map[i] = NULLnullptr; | |||
330 | } | |||
331 | ||||
332 | /* Allocate and return new saved hard register with given REGNO and | |||
333 | CALL_FREQ. */ | |||
334 | static void | |||
335 | new_saved_hard_reg (int regno, int call_freq) | |||
336 | { | |||
337 | struct saved_hard_reg *saved_reg; | |||
338 | ||||
339 | saved_reg | |||
340 | = (struct saved_hard_reg *) xmalloc (sizeof (struct saved_hard_reg)); | |||
341 | hard_reg_map[regno] = all_saved_regs[saved_regs_num] = saved_reg; | |||
342 | saved_reg->num = saved_regs_num++; | |||
343 | saved_reg->hard_regno = regno; | |||
344 | saved_reg->call_freq = call_freq; | |||
345 | saved_reg->first_p = FALSEfalse; | |||
346 | saved_reg->next = -1; | |||
347 | } | |||
348 | ||||
349 | /* Free memory allocated for the saved hard registers. */ | |||
350 | static void | |||
351 | finish_saved_hard_regs (void) | |||
352 | { | |||
353 | int i; | |||
354 | ||||
355 | for (i = 0; i < saved_regs_num; i++) | |||
356 | free (all_saved_regs[i]); | |||
357 | } | |||
358 | ||||
359 | /* The function is used to sort the saved hard register structures | |||
360 | according their frequency. */ | |||
361 | static int | |||
362 | saved_hard_reg_compare_func (const void *v1p, const void *v2p) | |||
363 | { | |||
364 | const struct saved_hard_reg *p1 = *(struct saved_hard_reg * const *) v1p; | |||
365 | const struct saved_hard_reg *p2 = *(struct saved_hard_reg * const *) v2p; | |||
366 | ||||
367 | if (flag_omit_frame_pointerglobal_options.x_flag_omit_frame_pointer) | |||
368 | { | |||
369 | if (p1->call_freq - p2->call_freq != 0) | |||
370 | return p1->call_freq - p2->call_freq; | |||
371 | } | |||
372 | else if (p2->call_freq - p1->call_freq != 0) | |||
373 | return p2->call_freq - p1->call_freq; | |||
374 | ||||
375 | return p1->num - p2->num; | |||
376 | } | |||
377 | ||||
378 | /* Allocate save areas for any hard registers that might need saving. | |||
379 | We take a conservative approach here and look for call-clobbered hard | |||
380 | registers that are assigned to pseudos that cross calls. This may | |||
381 | overestimate slightly (especially if some of these registers are later | |||
382 | used as spill registers), but it should not be significant. | |||
383 | ||||
384 | For IRA we use priority coloring to decrease stack slots needed for | |||
385 | saving hard registers through calls. We build conflicts for them | |||
386 | to do coloring. | |||
387 | ||||
388 | Future work: | |||
389 | ||||
390 | In the fallback case we should iterate backwards across all possible | |||
391 | modes for the save, choosing the largest available one instead of | |||
392 | falling back to the smallest mode immediately. (eg TF -> DF -> SF). | |||
393 | ||||
394 | We do not try to use "move multiple" instructions that exist | |||
395 | on some machines (such as the 68k moveml). It could be a win to try | |||
396 | and use them when possible. The hard part is doing it in a way that is | |||
397 | machine independent since they might be saving non-consecutive | |||
398 | registers. (imagine caller-saving d0,d1,a0,a1 on the 68k) */ | |||
399 | ||||
400 | void | |||
401 | setup_save_areas (void) | |||
402 | { | |||
403 | int i, j, k, freq; | |||
404 | HARD_REG_SET hard_regs_used; | |||
405 | struct saved_hard_reg *saved_reg; | |||
406 | rtx_insn *insn; | |||
407 | class insn_chain *chain, *next; | |||
408 | unsigned int regno; | |||
409 | HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets; | |||
410 | reg_set_iterator rsi; | |||
411 | ||||
412 | CLEAR_HARD_REG_SET (hard_regs_used); | |||
413 | ||||
414 | /* Find every CALL_INSN and record which hard regs are live across the | |||
415 | call into HARD_REG_MAP and HARD_REGS_USED. */ | |||
416 | initiate_saved_hard_regs (); | |||
417 | /* Create hard reg saved regs. */ | |||
418 | for (chain = reload_insn_chain; chain != 0; chain = next) | |||
419 | { | |||
420 | rtx cheap; | |||
421 | ||||
422 | insn = chain->insn; | |||
423 | next = chain->next; | |||
424 | if (!CALL_P (insn)(((enum rtx_code) (insn)->code) == CALL_INSN) | |||
425 | || find_reg_note (insn, REG_NORETURN, NULLnullptr)) | |||
426 | continue; | |||
427 | freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn))((optimize_function_for_size_p ((cfun + 0)) || !(cfun + 0)-> cfg->count_max.initialized_p ()) ? 1000 : ((BLOCK_FOR_INSN (insn))->count.to_frequency ((cfun + 0)) * 1000 / 10000) ? ((BLOCK_FOR_INSN (insn))->count.to_frequency ((cfun + 0)) * 1000 / 10000) : 1); | |||
428 | REG_SET_TO_HARD_REG_SET (hard_regs_to_save,do { CLEAR_HARD_REG_SET (hard_regs_to_save); reg_set_to_hard_reg_set (&hard_regs_to_save, &chain->live_throughout); } while (0) | |||
429 | &chain->live_throughout)do { CLEAR_HARD_REG_SET (hard_regs_to_save); reg_set_to_hard_reg_set (&hard_regs_to_save, &chain->live_throughout); } while (0); | |||
430 | used_regs = insn_callee_abi (insn).full_reg_clobbers (); | |||
431 | ||||
432 | /* Record all registers set in this call insn. These don't | |||
433 | need to be saved. N.B. the call insn might set a subreg | |||
434 | of a multi-hard-reg pseudo; then the pseudo is considered | |||
435 | live during the call, but the subreg that is set | |||
436 | isn't. */ | |||
437 | CLEAR_HARD_REG_SET (this_insn_sets); | |||
438 | note_stores (insn, mark_set_regs, &this_insn_sets); | |||
439 | /* Sibcalls are considered to set the return value. */ | |||
440 | if (SIBLING_CALL_P (insn)(__extension__ ({ __typeof ((insn)) const _rtx = ((insn)); if (((enum rtx_code) (_rtx)->code) != CALL_INSN) rtl_check_failed_flag ("SIBLING_CALL_P", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 440, __FUNCTION__); _rtx; })->jump) && crtl(&x_rtl)->return_rtx) | |||
441 | mark_set_regs (crtl(&x_rtl)->return_rtx, NULL_RTX(rtx) 0, &this_insn_sets); | |||
442 | ||||
443 | used_regs &= ~(fixed_reg_set(this_target_hard_regs->x_fixed_reg_set) | this_insn_sets); | |||
444 | hard_regs_to_save &= used_regs & savable_regs(this_target_hard_regs->x_savable_regs); | |||
445 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
446 | if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) | |||
447 | { | |||
448 | if (hard_reg_map[regno] != NULLnullptr) | |||
449 | hard_reg_map[regno]->call_freq += freq; | |||
450 | else | |||
451 | new_saved_hard_reg (regno, freq); | |||
452 | SET_HARD_REG_BIT (hard_regs_used, regno); | |||
453 | } | |||
454 | cheap = find_reg_note (insn, REG_RETURNED, NULLnullptr); | |||
455 | if (cheap) | |||
456 | cheap = XEXP (cheap, 0)(((cheap)->u.fld[0]).rt_rtx); | |||
457 | /* Look through all live pseudos, mark their hard registers. */ | |||
458 | EXECUTE_IF_SET_IN_REG_SETfor (bmp_iter_set_init (&(rsi), (&chain->live_throughout ), (76), &(regno)); bmp_iter_set (&(rsi), &(regno )); bmp_iter_next (&(rsi), &(regno))) | |||
459 | (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)for (bmp_iter_set_init (&(rsi), (&chain->live_throughout ), (76), &(regno)); bmp_iter_set (&(rsi), &(regno )); bmp_iter_next (&(rsi), &(regno))) | |||
460 | { | |||
461 | int r = reg_renumber[regno]; | |||
462 | int bound; | |||
463 | ||||
464 | if (r < 0 || regno_reg_rtx[regno] == cheap) | |||
465 | continue; | |||
466 | ||||
467 | bound = r + hard_regno_nregs (r, PSEUDO_REGNO_MODE (regno)((machine_mode) (regno_reg_rtx[regno])->mode)); | |||
468 | for (; r < bound; r++) | |||
469 | if (TEST_HARD_REG_BIT (used_regs, r)) | |||
470 | { | |||
471 | if (hard_reg_map[r] != NULLnullptr) | |||
472 | hard_reg_map[r]->call_freq += freq; | |||
473 | else | |||
474 | new_saved_hard_reg (r, freq); | |||
475 | SET_HARD_REG_BIT (hard_regs_to_save, r); | |||
476 | SET_HARD_REG_BIT (hard_regs_used, r); | |||
477 | } | |||
478 | } | |||
479 | } | |||
480 | ||||
481 | /* If requested, figure out which hard regs can share save slots. */ | |||
482 | if (optimizeglobal_options.x_optimize && flag_ira_share_save_slotsglobal_options.x_flag_ira_share_save_slots) | |||
483 | { | |||
484 | rtx slot; | |||
485 | char *saved_reg_conflicts; | |||
486 | int next_k; | |||
487 | struct saved_hard_reg *saved_reg2, *saved_reg3; | |||
488 | int call_saved_regs_num; | |||
489 | struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER76]; | |||
490 | int best_slot_num; | |||
491 | int prev_save_slots_num; | |||
492 | rtx prev_save_slots[FIRST_PSEUDO_REGISTER76]; | |||
493 | ||||
494 | /* Find saved hard register conflicts. */ | |||
495 | saved_reg_conflicts = (char *) xmalloc (saved_regs_num * saved_regs_num); | |||
496 | memset (saved_reg_conflicts, 0, saved_regs_num * saved_regs_num); | |||
497 | for (chain = reload_insn_chain; chain != 0; chain = next) | |||
498 | { | |||
499 | rtx cheap; | |||
500 | call_saved_regs_num = 0; | |||
501 | insn = chain->insn; | |||
502 | next = chain->next; | |||
503 | if (!CALL_P (insn)(((enum rtx_code) (insn)->code) == CALL_INSN) | |||
504 | || find_reg_note (insn, REG_NORETURN, NULLnullptr)) | |||
505 | continue; | |||
506 | ||||
507 | cheap = find_reg_note (insn, REG_RETURNED, NULLnullptr); | |||
508 | if (cheap) | |||
509 | cheap = XEXP (cheap, 0)(((cheap)->u.fld[0]).rt_rtx); | |||
510 | ||||
511 | REG_SET_TO_HARD_REG_SET (hard_regs_to_save,do { CLEAR_HARD_REG_SET (hard_regs_to_save); reg_set_to_hard_reg_set (&hard_regs_to_save, &chain->live_throughout); } while (0) | |||
512 | &chain->live_throughout)do { CLEAR_HARD_REG_SET (hard_regs_to_save); reg_set_to_hard_reg_set (&hard_regs_to_save, &chain->live_throughout); } while (0); | |||
513 | used_regs = insn_callee_abi (insn).full_reg_clobbers (); | |||
514 | ||||
515 | /* Record all registers set in this call insn. These don't | |||
516 | need to be saved. N.B. the call insn might set a subreg | |||
517 | of a multi-hard-reg pseudo; then the pseudo is considered | |||
518 | live during the call, but the subreg that is set | |||
519 | isn't. */ | |||
520 | CLEAR_HARD_REG_SET (this_insn_sets); | |||
521 | note_stores (insn, mark_set_regs, &this_insn_sets); | |||
522 | /* Sibcalls are considered to set the return value, | |||
523 | compare df-scan.cc:df_get_call_refs. */ | |||
524 | if (SIBLING_CALL_P (insn)(__extension__ ({ __typeof ((insn)) const _rtx = ((insn)); if (((enum rtx_code) (_rtx)->code) != CALL_INSN) rtl_check_failed_flag ("SIBLING_CALL_P", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 524, __FUNCTION__); _rtx; })->jump) && crtl(&x_rtl)->return_rtx) | |||
525 | mark_set_regs (crtl(&x_rtl)->return_rtx, NULL_RTX(rtx) 0, &this_insn_sets); | |||
526 | ||||
527 | used_regs &= ~(fixed_reg_set(this_target_hard_regs->x_fixed_reg_set) | this_insn_sets); | |||
528 | hard_regs_to_save &= used_regs & savable_regs(this_target_hard_regs->x_savable_regs); | |||
529 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
530 | if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) | |||
531 | { | |||
532 | gcc_assert (hard_reg_map[regno] != NULL)((void)(!(hard_reg_map[regno] != nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 532, __FUNCTION__), 0 : 0)); | |||
533 | call_saved_regs[call_saved_regs_num++] = hard_reg_map[regno]; | |||
534 | } | |||
535 | /* Look through all live pseudos, mark their hard registers. */ | |||
536 | EXECUTE_IF_SET_IN_REG_SETfor (bmp_iter_set_init (&(rsi), (&chain->live_throughout ), (76), &(regno)); bmp_iter_set (&(rsi), &(regno )); bmp_iter_next (&(rsi), &(regno))) | |||
537 | (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)for (bmp_iter_set_init (&(rsi), (&chain->live_throughout ), (76), &(regno)); bmp_iter_set (&(rsi), &(regno )); bmp_iter_next (&(rsi), &(regno))) | |||
538 | { | |||
539 | int r = reg_renumber[regno]; | |||
540 | int bound; | |||
541 | ||||
542 | if (r < 0 || regno_reg_rtx[regno] == cheap) | |||
543 | continue; | |||
544 | ||||
545 | bound = r + hard_regno_nregs (r, PSEUDO_REGNO_MODE (regno)((machine_mode) (regno_reg_rtx[regno])->mode)); | |||
546 | for (; r < bound; r++) | |||
547 | if (TEST_HARD_REG_BIT (used_regs, r)) | |||
548 | call_saved_regs[call_saved_regs_num++] = hard_reg_map[r]; | |||
549 | } | |||
550 | for (i = 0; i < call_saved_regs_num; i++) | |||
551 | { | |||
552 | saved_reg = call_saved_regs[i]; | |||
553 | for (j = 0; j < call_saved_regs_num; j++) | |||
554 | if (i != j) | |||
555 | { | |||
556 | saved_reg2 = call_saved_regs[j]; | |||
557 | saved_reg_conflicts[saved_reg->num * saved_regs_num | |||
558 | + saved_reg2->num] | |||
559 | = saved_reg_conflicts[saved_reg2->num * saved_regs_num | |||
560 | + saved_reg->num] | |||
561 | = TRUEtrue; | |||
562 | } | |||
563 | } | |||
564 | } | |||
565 | /* Sort saved hard regs. */ | |||
566 | qsort (all_saved_regs, saved_regs_num, sizeof (struct saved_hard_reg *),gcc_qsort (all_saved_regs, saved_regs_num, sizeof (struct saved_hard_reg *), saved_hard_reg_compare_func) | |||
567 | saved_hard_reg_compare_func)gcc_qsort (all_saved_regs, saved_regs_num, sizeof (struct saved_hard_reg *), saved_hard_reg_compare_func); | |||
568 | /* Initiate slots available from the previous reload | |||
569 | iteration. */ | |||
570 | prev_save_slots_num = save_slots_num; | |||
571 | memcpy (prev_save_slots, save_slots, save_slots_num * sizeof (rtx)); | |||
572 | save_slots_num = 0; | |||
573 | /* Allocate stack slots for the saved hard registers. */ | |||
574 | for (i = 0; i < saved_regs_num; i++) | |||
575 | { | |||
576 | saved_reg = all_saved_regs[i]; | |||
577 | regno = saved_reg->hard_regno; | |||
578 | for (j = 0; j < i; j++) | |||
579 | { | |||
580 | saved_reg2 = all_saved_regs[j]; | |||
581 | if (! saved_reg2->first_p) | |||
582 | continue; | |||
583 | slot = saved_reg2->slot; | |||
584 | for (k = j; k >= 0; k = next_k) | |||
585 | { | |||
586 | saved_reg3 = all_saved_regs[k]; | |||
587 | next_k = saved_reg3->next; | |||
588 | if (saved_reg_conflicts[saved_reg->num * saved_regs_num | |||
589 | + saved_reg3->num]) | |||
590 | break; | |||
591 | } | |||
592 | if (k < 0 | |||
593 | && known_le (GET_MODE_SIZE (regno_save_mode[regno][1]),(!maybe_lt (GET_MODE_SIZE ((this_target_reload->x_regno_save_mode ) [saved_reg2->hard_regno][1]), GET_MODE_SIZE ((this_target_reload ->x_regno_save_mode)[regno][1]))) | |||
594 | GET_MODE_SIZE (regno_save_mode(!maybe_lt (GET_MODE_SIZE ((this_target_reload->x_regno_save_mode ) [saved_reg2->hard_regno][1]), GET_MODE_SIZE ((this_target_reload ->x_regno_save_mode)[regno][1]))) | |||
595 | [saved_reg2->hard_regno][1]))(!maybe_lt (GET_MODE_SIZE ((this_target_reload->x_regno_save_mode ) [saved_reg2->hard_regno][1]), GET_MODE_SIZE ((this_target_reload ->x_regno_save_mode)[regno][1])))) | |||
596 | { | |||
597 | saved_reg->slot | |||
598 | = adjust_address_nvadjust_address_1 (slot, (this_target_reload->x_regno_save_mode )[saved_reg->hard_regno][1], 0, 0, 1, 0, 0) | |||
599 | (slot, regno_save_mode[saved_reg->hard_regno][1], 0)adjust_address_1 (slot, (this_target_reload->x_regno_save_mode )[saved_reg->hard_regno][1], 0, 0, 1, 0, 0); | |||
600 | regno_save_mem[regno][1] = saved_reg->slot; | |||
601 | saved_reg->next = saved_reg2->next; | |||
602 | saved_reg2->next = i; | |||
603 | if (dump_file != NULLnullptr) | |||
604 | fprintf (dump_file, "%d uses slot of %d\n", | |||
605 | regno, saved_reg2->hard_regno); | |||
606 | break; | |||
607 | } | |||
608 | } | |||
609 | if (j == i) | |||
610 | { | |||
611 | saved_reg->first_p = TRUEtrue; | |||
612 | for (best_slot_num = -1, j = 0; j < prev_save_slots_num; j++) | |||
613 | { | |||
614 | slot = prev_save_slots[j]; | |||
615 | if (slot == NULL_RTX(rtx) 0) | |||
616 | continue; | |||
617 | if (known_le (GET_MODE_SIZE (regno_save_mode[regno][1]),(!maybe_lt (GET_MODE_SIZE (((machine_mode) (slot)->mode)), GET_MODE_SIZE ((this_target_reload->x_regno_save_mode)[regno ][1]))) | |||
618 | GET_MODE_SIZE (GET_MODE (slot)))(!maybe_lt (GET_MODE_SIZE (((machine_mode) (slot)->mode)), GET_MODE_SIZE ((this_target_reload->x_regno_save_mode)[regno ][1]))) | |||
619 | && best_slot_num < 0) | |||
620 | best_slot_num = j; | |||
621 | if (GET_MODE (slot)((machine_mode) (slot)->mode) == regno_save_mode(this_target_reload->x_regno_save_mode)[regno][1]) | |||
622 | break; | |||
623 | } | |||
624 | if (best_slot_num >= 0) | |||
625 | { | |||
626 | saved_reg->slot = prev_save_slots[best_slot_num]; | |||
627 | saved_reg->slot | |||
628 | = adjust_address_nvadjust_address_1 (saved_reg->slot, (this_target_reload-> x_regno_save_mode)[saved_reg->hard_regno][1], 0, 0, 1, 0, 0 ) | |||
629 | (saved_reg->slot,adjust_address_1 (saved_reg->slot, (this_target_reload-> x_regno_save_mode)[saved_reg->hard_regno][1], 0, 0, 1, 0, 0 ) | |||
630 | regno_save_mode[saved_reg->hard_regno][1], 0)adjust_address_1 (saved_reg->slot, (this_target_reload-> x_regno_save_mode)[saved_reg->hard_regno][1], 0, 0, 1, 0, 0 ); | |||
631 | if (dump_file != NULLnullptr) | |||
632 | fprintf (dump_file, | |||
633 | "%d uses a slot from prev iteration\n", regno); | |||
634 | prev_save_slots[best_slot_num] = NULL_RTX(rtx) 0; | |||
635 | if (best_slot_num + 1 == prev_save_slots_num) | |||
636 | prev_save_slots_num--; | |||
637 | } | |||
638 | else | |||
639 | { | |||
640 | saved_reg->slot | |||
641 | = assign_stack_local_1 | |||
642 | (regno_save_mode(this_target_reload->x_regno_save_mode)[regno][1], | |||
643 | GET_MODE_SIZE (regno_save_mode(this_target_reload->x_regno_save_mode)[regno][1]), 0, | |||
644 | ASLK_REDUCE_ALIGN1); | |||
645 | if (dump_file != NULLnullptr) | |||
646 | fprintf (dump_file, "%d uses a new slot\n", regno); | |||
647 | } | |||
648 | regno_save_mem[regno][1] = saved_reg->slot; | |||
649 | save_slots[save_slots_num++] = saved_reg->slot; | |||
650 | } | |||
651 | } | |||
652 | free (saved_reg_conflicts); | |||
653 | finish_saved_hard_regs (); | |||
654 | } | |||
655 | else | |||
656 | { | |||
657 | /* We are not sharing slots. | |||
658 | ||||
659 | Run through all the call-used hard-registers and allocate | |||
660 | space for each in the caller-save area. Try to allocate space | |||
661 | in a manner which allows multi-register saves/restores to be done. */ | |||
662 | ||||
663 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
664 | for (j = MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); j > 0; j--) | |||
665 | { | |||
666 | int do_save = 1; | |||
667 | ||||
668 | /* If no mode exists for this size, try another. Also break out | |||
669 | if we have already saved this hard register. */ | |||
670 | if (regno_save_mode(this_target_reload->x_regno_save_mode)[i][j] == VOIDmode((void) 0, E_VOIDmode) || regno_save_mem[i][1] != 0) | |||
671 | continue; | |||
672 | ||||
673 | /* See if any register in this group has been saved. */ | |||
674 | for (k = 0; k < j; k++) | |||
675 | if (regno_save_mem[i + k][1]) | |||
676 | { | |||
677 | do_save = 0; | |||
678 | break; | |||
679 | } | |||
680 | if (! do_save) | |||
681 | continue; | |||
682 | ||||
683 | for (k = 0; k < j; k++) | |||
684 | if (! TEST_HARD_REG_BIT (hard_regs_used, i + k)) | |||
685 | { | |||
686 | do_save = 0; | |||
687 | break; | |||
688 | } | |||
689 | if (! do_save) | |||
690 | continue; | |||
691 | ||||
692 | /* We have found an acceptable mode to store in. Since | |||
693 | hard register is always saved in the widest mode | |||
694 | available, the mode may be wider than necessary, it is | |||
695 | OK to reduce the alignment of spill space. We will | |||
696 | verify that it is equal to or greater than required | |||
697 | when we restore and save the hard register in | |||
698 | insert_restore and insert_save. */ | |||
699 | regno_save_mem[i][j] | |||
700 | = assign_stack_local_1 (regno_save_mode(this_target_reload->x_regno_save_mode)[i][j], | |||
701 | GET_MODE_SIZE (regno_save_mode(this_target_reload->x_regno_save_mode)[i][j]), | |||
702 | 0, ASLK_REDUCE_ALIGN1); | |||
703 | ||||
704 | /* Setup single word save area just in case... */ | |||
705 | for (k = 0; k < j; k++) | |||
706 | /* This should not depend on WORDS_BIG_ENDIAN. | |||
707 | The order of words in regs is the same as in memory. */ | |||
708 | regno_save_mem[i + k][1] | |||
709 | = adjust_address_nv (regno_save_mem[i][j],adjust_address_1 (regno_save_mem[i][j], (this_target_reload-> x_regno_save_mode)[i + k][1], k * (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4), 0, 1, 0, 0) | |||
710 | regno_save_mode[i + k][1],adjust_address_1 (regno_save_mem[i][j], (this_target_reload-> x_regno_save_mode)[i + k][1], k * (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4), 0, 1, 0, 0) | |||
711 | k * UNITS_PER_WORD)adjust_address_1 (regno_save_mem[i][j], (this_target_reload-> x_regno_save_mode)[i + k][1], k * (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4), 0, 1, 0, 0); | |||
712 | } | |||
713 | } | |||
714 | ||||
715 | /* Now loop again and set the alias set of any save areas we made to | |||
716 | the alias set used to represent frame objects. */ | |||
717 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) | |||
718 | for (j = MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); j > 0; j--) | |||
719 | if (regno_save_mem[i][j] != 0) | |||
720 | set_mem_alias_set (regno_save_mem[i][j], get_frame_alias_set ()); | |||
721 | } | |||
722 | ||||
723 | ||||
724 | ||||
725 | /* Find the places where hard regs are live across calls and save them. */ | |||
726 | ||||
727 | void | |||
728 | save_call_clobbered_regs (void) | |||
729 | { | |||
730 | class insn_chain *chain, *next, *last = NULLnullptr; | |||
731 | machine_mode save_mode [FIRST_PSEUDO_REGISTER76]; | |||
732 | ||||
733 | /* Computed in mark_set_regs, holds all registers set by the current | |||
734 | instruction. */ | |||
735 | HARD_REG_SET this_insn_sets; | |||
736 | ||||
737 | CLEAR_HARD_REG_SET (hard_regs_saved); | |||
738 | n_regs_saved = 0; | |||
739 | ||||
740 | for (chain = reload_insn_chain; chain != 0; chain = next) | |||
| ||||
741 | { | |||
742 | rtx_insn *insn = chain->insn; | |||
743 | enum rtx_code code = GET_CODE (insn)((enum rtx_code) (insn)->code); | |||
744 | ||||
745 | next = chain->next; | |||
746 | ||||
747 | gcc_assert (!chain->is_caller_save_insn)((void)(!(!chain->is_caller_save_insn) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 747, __FUNCTION__), 0 : 0)); | |||
748 | ||||
749 | if (NONDEBUG_INSN_P (insn)((((enum rtx_code) (insn)->code) == INSN) || (((enum rtx_code ) (insn)->code) == JUMP_INSN) || (((enum rtx_code) (insn)-> code) == CALL_INSN))) | |||
750 | { | |||
751 | /* If some registers have been saved, see if INSN references | |||
752 | any of them. We must restore them before the insn if so. */ | |||
753 | ||||
754 | if (n_regs_saved
| |||
755 | { | |||
756 | int regno; | |||
757 | HARD_REG_SET this_insn_sets; | |||
758 | ||||
759 | if (code == JUMP_INSN) | |||
760 | /* Restore all registers if this is a JUMP_INSN. */ | |||
761 | referenced_regs = hard_regs_saved; | |||
762 | else | |||
763 | { | |||
764 | CLEAR_HARD_REG_SET (referenced_regs); | |||
765 | mark_referenced_regs (&PATTERN (insn), | |||
766 | mark_reg_as_referenced, NULLnullptr); | |||
767 | referenced_regs &= hard_regs_saved; | |||
768 | } | |||
769 | ||||
770 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
771 | if (TEST_HARD_REG_BIT (referenced_regs, regno)) | |||
772 | regno += insert_restore (chain, 1, regno, MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)), | |||
773 | save_mode); | |||
774 | /* If a saved register is set after the call, this means we no | |||
775 | longer should restore it. This can happen when parts of a | |||
776 | multi-word pseudo do not conflict with other pseudos, so | |||
777 | IRA may allocate the same hard register for both. One may | |||
778 | be live across the call, while the other is set | |||
779 | afterwards. */ | |||
780 | CLEAR_HARD_REG_SET (this_insn_sets); | |||
781 | note_stores (insn, mark_set_regs, &this_insn_sets); | |||
782 | hard_regs_saved &= ~this_insn_sets; | |||
783 | } | |||
784 | ||||
785 | if (code
| |||
786 | && ! SIBLING_CALL_P (insn)(__extension__ ({ __typeof ((insn)) const _rtx = ((insn)); if (((enum rtx_code) (_rtx)->code) != CALL_INSN) rtl_check_failed_flag ("SIBLING_CALL_P", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 786, __FUNCTION__); _rtx; })->jump) | |||
787 | && ! find_reg_note (insn, REG_NORETURN, NULLnullptr)) | |||
788 | { | |||
789 | unsigned regno; | |||
790 | HARD_REG_SET hard_regs_to_save; | |||
791 | reg_set_iterator rsi; | |||
792 | rtx cheap; | |||
793 | ||||
794 | cheap = find_reg_note (insn, REG_RETURNED, NULLnullptr); | |||
795 | if (cheap) | |||
796 | cheap = XEXP (cheap, 0)(((cheap)->u.fld[0]).rt_rtx); | |||
797 | ||||
798 | /* Use the register life information in CHAIN to compute which | |||
799 | regs are live during the call. */ | |||
800 | REG_SET_TO_HARD_REG_SET (hard_regs_to_save,do { CLEAR_HARD_REG_SET (hard_regs_to_save); reg_set_to_hard_reg_set (&hard_regs_to_save, &chain->live_throughout); } while (0) | |||
801 | &chain->live_throughout)do { CLEAR_HARD_REG_SET (hard_regs_to_save); reg_set_to_hard_reg_set (&hard_regs_to_save, &chain->live_throughout); } while (0); | |||
802 | /* Save hard registers always in the widest mode available. */ | |||
803 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
804 | if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) | |||
805 | save_mode [regno] = regno_save_mode(this_target_reload->x_regno_save_mode) [regno][1]; | |||
806 | else | |||
807 | save_mode [regno] = VOIDmode((void) 0, E_VOIDmode); | |||
808 | ||||
809 | /* Look through all live pseudos, mark their hard registers | |||
810 | and choose proper mode for saving. */ | |||
811 | EXECUTE_IF_SET_IN_REG_SETfor (bmp_iter_set_init (&(rsi), (&chain->live_throughout ), (76), &(regno)); bmp_iter_set (&(rsi), &(regno )); bmp_iter_next (&(rsi), &(regno))) | |||
812 | (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)for (bmp_iter_set_init (&(rsi), (&chain->live_throughout ), (76), &(regno)); bmp_iter_set (&(rsi), &(regno )); bmp_iter_next (&(rsi), &(regno))) | |||
813 | { | |||
814 | int r = reg_renumber[regno]; | |||
815 | int nregs; | |||
816 | machine_mode mode; | |||
817 | ||||
818 | if (r < 0 || regno_reg_rtx[regno] == cheap) | |||
819 | continue; | |||
820 | nregs = hard_regno_nregs (r, PSEUDO_REGNO_MODE (regno)((machine_mode) (regno_reg_rtx[regno])->mode)); | |||
821 | mode = HARD_REGNO_CALLER_SAVE_MODE(((r) == 17) ? ((void) 0, E_VOIDmode) : (((machine_mode) (regno_reg_rtx [regno])->mode)) == ((void) 0, E_VOIDmode) && (nregs ) != 1 ? ((void) 0, E_VOIDmode) : (((machine_mode) (regno_reg_rtx [regno])->mode)) == ((void) 0, E_VOIDmode) ? choose_hard_reg_mode ((r), (nregs), nullptr) : (((machine_mode) (regno_reg_rtx[regno ])->mode)) == (scalar_int_mode ((scalar_int_mode::from_int ) E_HImode)) && !((((((unsigned long) ((r)) - (unsigned long) (0) <= (unsigned long) (7) - (unsigned long) (0))) || ((unsigned long) ((r)) - (unsigned long) (36) <= (unsigned long) (43) - (unsigned long) (36))) && ix86_tune_features [X86_TUNE_PARTIAL_REG_STALL]) || ((unsigned long) ((r)) - (unsigned long) (68) <= (unsigned long) (75) - (unsigned long) (68) )) ? (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) : (((machine_mode) (regno_reg_rtx[regno])->mode)) == (scalar_int_mode ((scalar_int_mode::from_int) E_QImode)) && !((((global_options .x_ix86_isa_flags & (1UL << 1)) != 0) ? ((((unsigned long) ((r)) - (unsigned long) (0) <= (unsigned long) (7) - (unsigned long) (0))) || ((unsigned long) ((r)) - (unsigned long ) (36) <= (unsigned long) (43) - (unsigned long) (36))) : ( (unsigned long) ((r)) - (unsigned long) (0) <= (unsigned long ) (3) - (unsigned long) (0))) || ((unsigned long) ((r)) - (unsigned long) (68) <= (unsigned long) (75) - (unsigned long) (68) )) ? (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) : (((machine_mode) (regno_reg_rtx[regno])->mode))) | |||
822 | (r, nregs, PSEUDO_REGNO_MODE (regno))(((r) == 17) ? ((void) 0, E_VOIDmode) : (((machine_mode) (regno_reg_rtx [regno])->mode)) == ((void) 0, E_VOIDmode) && (nregs ) != 1 ? ((void) 0, E_VOIDmode) : (((machine_mode) (regno_reg_rtx [regno])->mode)) == ((void) 0, E_VOIDmode) ? choose_hard_reg_mode ((r), (nregs), nullptr) : (((machine_mode) (regno_reg_rtx[regno ])->mode)) == (scalar_int_mode ((scalar_int_mode::from_int ) E_HImode)) && !((((((unsigned long) ((r)) - (unsigned long) (0) <= (unsigned long) (7) - (unsigned long) (0))) || ((unsigned long) ((r)) - (unsigned long) (36) <= (unsigned long) (43) - (unsigned long) (36))) && ix86_tune_features [X86_TUNE_PARTIAL_REG_STALL]) || ((unsigned long) ((r)) - (unsigned long) (68) <= (unsigned long) (75) - (unsigned long) (68) )) ? (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) : (((machine_mode) (regno_reg_rtx[regno])->mode)) == (scalar_int_mode ((scalar_int_mode::from_int) E_QImode)) && !((((global_options .x_ix86_isa_flags & (1UL << 1)) != 0) ? ((((unsigned long) ((r)) - (unsigned long) (0) <= (unsigned long) (7) - (unsigned long) (0))) || ((unsigned long) ((r)) - (unsigned long ) (36) <= (unsigned long) (43) - (unsigned long) (36))) : ( (unsigned long) ((r)) - (unsigned long) (0) <= (unsigned long ) (3) - (unsigned long) (0))) || ((unsigned long) ((r)) - (unsigned long) (68) <= (unsigned long) (75) - (unsigned long) (68) )) ? (scalar_int_mode ((scalar_int_mode::from_int) E_SImode)) : (((machine_mode) (regno_reg_rtx[regno])->mode))); | |||
823 | if (partial_subreg_p (save_mode[r], mode)) | |||
824 | save_mode[r] = mode; | |||
825 | while (nregs-- > 0) | |||
826 | SET_HARD_REG_BIT (hard_regs_to_save, r + nregs); | |||
827 | } | |||
828 | ||||
829 | /* Record all registers set in this call insn. These don't need | |||
830 | to be saved. N.B. the call insn might set a subreg of a | |||
831 | multi-hard-reg pseudo; then the pseudo is considered live | |||
832 | during the call, but the subreg that is set isn't. */ | |||
833 | CLEAR_HARD_REG_SET (this_insn_sets); | |||
834 | note_stores (insn, mark_set_regs, &this_insn_sets); | |||
835 | ||||
836 | /* Compute which hard regs must be saved before this call. */ | |||
837 | function_abi callee_abi = insn_callee_abi (insn); | |||
838 | hard_regs_to_save &= ~(fixed_reg_set(this_target_hard_regs->x_fixed_reg_set) | |||
839 | | this_insn_sets | |||
840 | | hard_regs_saved); | |||
841 | hard_regs_to_save &= savable_regs(this_target_hard_regs->x_savable_regs); | |||
842 | hard_regs_to_save &= callee_abi.full_reg_clobbers (); | |||
843 | ||||
844 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
845 | if (TEST_HARD_REG_BIT (hard_regs_to_save, regno)) | |||
846 | regno += insert_save (chain, regno, | |||
847 | &hard_regs_to_save, save_mode); | |||
848 | ||||
849 | /* Must recompute n_regs_saved. */ | |||
850 | n_regs_saved = 0; | |||
851 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
852 | if (TEST_HARD_REG_BIT (hard_regs_saved, regno)) | |||
853 | n_regs_saved++; | |||
854 | ||||
855 | if (cheap | |||
856 | && HARD_REGISTER_P (cheap)((((rhs_regno(cheap))) < 76)) | |||
857 | && callee_abi.clobbers_reg_p (GET_MODE (cheap)((machine_mode) (cheap)->mode), | |||
858 | REGNO (cheap)(rhs_regno(cheap)))) | |||
859 | { | |||
860 | rtx dest, newpat; | |||
861 | rtx pat = PATTERN (insn); | |||
862 | if (GET_CODE (pat)((enum rtx_code) (pat)->code) == PARALLEL) | |||
863 | pat = XVECEXP (pat, 0, 0)(((((pat)->u.fld[0]).rt_rtvec))->elem[0]); | |||
864 | dest = SET_DEST (pat)(((pat)->u.fld[0]).rt_rtx); | |||
865 | /* For multiple return values dest is PARALLEL. | |||
866 | Currently we handle only single return value case. */ | |||
867 | if (REG_P (dest)(((enum rtx_code) (dest)->code) == REG)) | |||
868 | { | |||
869 | newpat = gen_rtx_SET (cheap, copy_rtx (dest))gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), ((cheap )), ((copy_rtx (dest))) ); | |||
870 | chain = insert_one_insn (chain, 0, -1, newpat); | |||
871 | } | |||
872 | } | |||
873 | } | |||
874 | last = chain; | |||
875 | } | |||
876 | else if (DEBUG_INSN_P (insn)(((enum rtx_code) (insn)->code) == DEBUG_INSN) && n_regs_saved) | |||
877 | mark_referenced_regs (&PATTERN (insn), | |||
878 | replace_reg_with_saved_mem, | |||
879 | save_mode); | |||
880 | ||||
881 | if (chain->next == 0 || chain->next->block != chain->block) | |||
882 | { | |||
883 | int regno; | |||
884 | /* At the end of the basic block, we must restore any registers that | |||
885 | remain saved. If the last insn in the block is a JUMP_INSN, put | |||
886 | the restore before the insn, otherwise, put it after the insn. */ | |||
887 | ||||
888 | if (n_regs_saved | |||
889 | && DEBUG_INSN_P (insn)(((enum rtx_code) (insn)->code) == DEBUG_INSN) | |||
890 | && last | |||
891 | && last->block == chain->block) | |||
892 | { | |||
893 | rtx_insn *ins, *prev; | |||
894 | basic_block bb = BLOCK_FOR_INSN (insn); | |||
895 | ||||
896 | /* When adding hard reg restores after a DEBUG_INSN, move | |||
897 | all notes between last real insn and this DEBUG_INSN after | |||
898 | the DEBUG_INSN, otherwise we could get code | |||
899 | -g/-g0 differences. */ | |||
900 | for (ins = PREV_INSN (insn); ins != last->insn; ins = prev) | |||
901 | { | |||
902 | prev = PREV_INSN (ins); | |||
903 | if (NOTE_P (ins)(((enum rtx_code) (ins)->code) == NOTE)) | |||
904 | { | |||
905 | SET_NEXT_INSN (prev) = NEXT_INSN (ins); | |||
906 | SET_PREV_INSN (NEXT_INSN (ins)) = prev; | |||
907 | SET_PREV_INSN (ins) = insn; | |||
908 | SET_NEXT_INSN (ins) = NEXT_INSN (insn); | |||
909 | SET_NEXT_INSN (insn) = ins; | |||
910 | if (NEXT_INSN (ins)) | |||
911 | SET_PREV_INSN (NEXT_INSN (ins)) = ins; | |||
912 | if (BB_END (bb)(bb)->il.x.rtl->end_ == insn) | |||
913 | BB_END (bb)(bb)->il.x.rtl->end_ = ins; | |||
914 | } | |||
915 | else | |||
916 | gcc_assert (DEBUG_INSN_P (ins))((void)(!((((enum rtx_code) (ins)->code) == DEBUG_INSN)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 916, __FUNCTION__), 0 : 0)); | |||
917 | } | |||
918 | } | |||
919 | last = NULLnullptr; | |||
920 | ||||
921 | if (n_regs_saved
| |||
922 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER76; regno++) | |||
923 | if (TEST_HARD_REG_BIT (hard_regs_saved, regno)) | |||
924 | regno += insert_restore (chain, JUMP_P (insn)(((enum rtx_code) (insn)->code) == JUMP_INSN), | |||
925 | regno, MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)), save_mode); | |||
926 | } | |||
927 | } | |||
928 | } | |||
929 | ||||
930 | /* Here from note_stores, or directly from save_call_clobbered_regs, when | |||
931 | an insn stores a value in a register. | |||
932 | Set the proper bit or bits in this_insn_sets. All pseudos that have | |||
933 | been assigned hard regs have had their register number changed already, | |||
934 | so we can ignore pseudos. */ | |||
935 | static void | |||
936 | mark_set_regs (rtx reg, const_rtx setter ATTRIBUTE_UNUSED__attribute__ ((__unused__)), void *data) | |||
937 | { | |||
938 | int regno, endregno, i; | |||
939 | HARD_REG_SET *this_insn_sets = (HARD_REG_SET *) data; | |||
940 | ||||
941 | if (GET_CODE (reg)((enum rtx_code) (reg)->code) == SUBREG) | |||
942 | { | |||
943 | rtx inner = SUBREG_REG (reg)(((reg)->u.fld[0]).rt_rtx); | |||
944 | if (!REG_P (inner)(((enum rtx_code) (inner)->code) == REG) || REGNO (inner)(rhs_regno(inner)) >= FIRST_PSEUDO_REGISTER76) | |||
945 | return; | |||
946 | regno = subreg_regno (reg); | |||
947 | endregno = regno + subreg_nregs (reg); | |||
948 | } | |||
949 | else if (REG_P (reg)(((enum rtx_code) (reg)->code) == REG) | |||
950 | && REGNO (reg)(rhs_regno(reg)) < FIRST_PSEUDO_REGISTER76) | |||
951 | { | |||
952 | regno = REGNO (reg)(rhs_regno(reg)); | |||
953 | endregno = END_REGNO (reg); | |||
954 | } | |||
955 | else | |||
956 | return; | |||
957 | ||||
958 | for (i = regno; i < endregno; i++) | |||
959 | SET_HARD_REG_BIT (*this_insn_sets, i); | |||
960 | } | |||
961 | ||||
962 | /* Here from note_stores when an insn stores a value in a register. | |||
963 | Set the proper bit or bits in the passed regset. All pseudos that have | |||
964 | been assigned hard regs have had their register number changed already, | |||
965 | so we can ignore pseudos. */ | |||
966 | static void | |||
967 | add_stored_regs (rtx reg, const_rtx setter, void *data) | |||
968 | { | |||
969 | int regno, endregno, i; | |||
970 | machine_mode mode = GET_MODE (reg)((machine_mode) (reg)->mode); | |||
971 | int offset = 0; | |||
972 | ||||
973 | if (GET_CODE (setter)((enum rtx_code) (setter)->code) == CLOBBER) | |||
974 | return; | |||
975 | ||||
976 | if (GET_CODE (reg)((enum rtx_code) (reg)->code) == SUBREG | |||
977 | && REG_P (SUBREG_REG (reg))(((enum rtx_code) ((((reg)->u.fld[0]).rt_rtx))->code) == REG) | |||
978 | && REGNO (SUBREG_REG (reg))(rhs_regno((((reg)->u.fld[0]).rt_rtx))) < FIRST_PSEUDO_REGISTER76) | |||
979 | { | |||
980 | offset = subreg_regno_offset (REGNO (SUBREG_REG (reg))(rhs_regno((((reg)->u.fld[0]).rt_rtx))), | |||
981 | GET_MODE (SUBREG_REG (reg))((machine_mode) ((((reg)->u.fld[0]).rt_rtx))->mode), | |||
982 | SUBREG_BYTE (reg)(((reg)->u.fld[1]).rt_subreg), | |||
983 | GET_MODE (reg)((machine_mode) (reg)->mode)); | |||
984 | regno = REGNO (SUBREG_REG (reg))(rhs_regno((((reg)->u.fld[0]).rt_rtx))) + offset; | |||
985 | endregno = regno + subreg_nregs (reg); | |||
986 | } | |||
987 | else | |||
988 | { | |||
989 | if (!REG_P (reg)(((enum rtx_code) (reg)->code) == REG) || REGNO (reg)(rhs_regno(reg)) >= FIRST_PSEUDO_REGISTER76) | |||
990 | return; | |||
991 | ||||
992 | regno = REGNO (reg)(rhs_regno(reg)) + offset; | |||
993 | endregno = end_hard_regno (mode, regno); | |||
994 | } | |||
995 | ||||
996 | for (i = regno; i < endregno; i++) | |||
997 | SET_REGNO_REG_SET ((regset) data, i)bitmap_set_bit ((regset) data, i); | |||
998 | } | |||
999 | ||||
1000 | /* Walk X and record all referenced registers in REFERENCED_REGS. */ | |||
1001 | static void | |||
1002 | mark_referenced_regs (rtx *loc, refmarker_fn *mark, void *arg) | |||
1003 | { | |||
1004 | enum rtx_code code = GET_CODE (*loc)((enum rtx_code) (*loc)->code); | |||
1005 | const char *fmt; | |||
1006 | int i, j; | |||
1007 | ||||
1008 | if (code == SET) | |||
1009 | mark_referenced_regs (&SET_SRC (*loc)(((*loc)->u.fld[1]).rt_rtx), mark, arg); | |||
1010 | if (code == SET || code == CLOBBER) | |||
1011 | { | |||
1012 | loc = &SET_DEST (*loc)(((*loc)->u.fld[0]).rt_rtx); | |||
1013 | code = GET_CODE (*loc)((enum rtx_code) (*loc)->code); | |||
1014 | if ((code == REG && REGNO (*loc)(rhs_regno(*loc)) < FIRST_PSEUDO_REGISTER76) | |||
1015 | || code == PC | |||
1016 | || (code == SUBREG && REG_P (SUBREG_REG (*loc))(((enum rtx_code) ((((*loc)->u.fld[0]).rt_rtx))->code) == REG) | |||
1017 | && REGNO (SUBREG_REG (*loc))(rhs_regno((((*loc)->u.fld[0]).rt_rtx))) < FIRST_PSEUDO_REGISTER76 | |||
1018 | /* If we're setting only part of a multi-word register, | |||
1019 | we shall mark it as referenced, because the words | |||
1020 | that are not being set should be restored. */ | |||
1021 | && !read_modify_subreg_p (*loc))) | |||
1022 | return; | |||
1023 | } | |||
1024 | if (code == MEM || code == SUBREG) | |||
1025 | { | |||
1026 | loc = &XEXP (*loc, 0)(((*loc)->u.fld[0]).rt_rtx); | |||
1027 | code = GET_CODE (*loc)((enum rtx_code) (*loc)->code); | |||
1028 | } | |||
1029 | ||||
1030 | if (code == REG) | |||
1031 | { | |||
1032 | int regno = REGNO (*loc)(rhs_regno(*loc)); | |||
1033 | int hardregno = (regno < FIRST_PSEUDO_REGISTER76 ? regno | |||
1034 | : reg_renumber[regno]); | |||
1035 | ||||
1036 | if (hardregno >= 0) | |||
1037 | mark (loc, GET_MODE (*loc)((machine_mode) (*loc)->mode), hardregno, arg); | |||
1038 | else if (arg) | |||
1039 | /* ??? Will we ever end up with an equiv expression in a debug | |||
1040 | insn, that would have required restoring a reg, or will | |||
1041 | reload take care of it for us? */ | |||
1042 | return; | |||
1043 | /* If this is a pseudo that did not get a hard register, scan its | |||
1044 | memory location, since it might involve the use of another | |||
1045 | register, which might be saved. */ | |||
1046 | else if (reg_equiv_mem (regno)(*reg_equivs)[(regno)].mem != 0) | |||
1047 | mark_referenced_regs (&XEXP (reg_equiv_mem (regno), 0)((((*reg_equivs)[(regno)].mem)->u.fld[0]).rt_rtx), mark, arg); | |||
1048 | else if (reg_equiv_address (regno)(*reg_equivs)[(regno)].address != 0) | |||
1049 | mark_referenced_regs (®_equiv_address (regno)(*reg_equivs)[(regno)].address, mark, arg); | |||
1050 | return; | |||
1051 | } | |||
1052 | ||||
1053 | fmt = GET_RTX_FORMAT (code)(rtx_format[(int) (code)]); | |||
1054 | for (i = GET_RTX_LENGTH (code)(rtx_length[(int) (code)]) - 1; i >= 0; i--) | |||
1055 | { | |||
1056 | if (fmt[i] == 'e') | |||
1057 | mark_referenced_regs (&XEXP (*loc, i)(((*loc)->u.fld[i]).rt_rtx), mark, arg); | |||
1058 | else if (fmt[i] == 'E') | |||
1059 | for (j = XVECLEN (*loc, i)(((((*loc)->u.fld[i]).rt_rtvec))->num_elem) - 1; j >= 0; j--) | |||
1060 | mark_referenced_regs (&XVECEXP (*loc, i, j)(((((*loc)->u.fld[i]).rt_rtvec))->elem[j]), mark, arg); | |||
1061 | } | |||
1062 | } | |||
1063 | ||||
1064 | /* Parameter function for mark_referenced_regs() that adds registers | |||
1065 | present in the insn and in equivalent mems and addresses to | |||
1066 | referenced_regs. */ | |||
1067 | ||||
1068 | static void | |||
1069 | mark_reg_as_referenced (rtx *loc ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
1070 | machine_mode mode, | |||
1071 | int hardregno, | |||
1072 | void *arg ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
1073 | { | |||
1074 | add_to_hard_reg_set (&referenced_regs, mode, hardregno); | |||
1075 | } | |||
1076 | ||||
1077 | /* Parameter function for mark_referenced_regs() that replaces | |||
1078 | registers referenced in a debug_insn that would have been restored, | |||
1079 | should it be a non-debug_insn, with their save locations. */ | |||
1080 | ||||
1081 | static void | |||
1082 | replace_reg_with_saved_mem (rtx *loc, | |||
1083 | machine_mode mode, | |||
1084 | int regno, | |||
1085 | void *arg) | |||
1086 | { | |||
1087 | unsigned int i, nregs = hard_regno_nregs (regno, mode); | |||
1088 | rtx mem; | |||
1089 | machine_mode *save_mode = (machine_mode *)arg; | |||
1090 | ||||
1091 | for (i = 0; i < nregs; i++) | |||
1092 | if (TEST_HARD_REG_BIT (hard_regs_saved, regno + i)) | |||
1093 | break; | |||
1094 | ||||
1095 | /* If none of the registers in the range would need restoring, we're | |||
1096 | all set. */ | |||
1097 | if (i == nregs) | |||
1098 | return; | |||
1099 | ||||
1100 | while (++i < nregs) | |||
1101 | if (!TEST_HARD_REG_BIT (hard_regs_saved, regno + i)) | |||
1102 | break; | |||
1103 | ||||
1104 | if (i == nregs | |||
1105 | && regno_save_mem[regno][nregs]) | |||
1106 | { | |||
1107 | mem = copy_rtx (regno_save_mem[regno][nregs]); | |||
1108 | ||||
1109 | if (nregs == hard_regno_nregs (regno, save_mode[regno])) | |||
1110 | mem = adjust_address_nv (mem, save_mode[regno], 0)adjust_address_1 (mem, save_mode[regno], 0, 0, 1, 0, 0); | |||
1111 | ||||
1112 | if (GET_MODE (mem)((machine_mode) (mem)->mode) != mode) | |||
1113 | { | |||
1114 | /* This is gen_lowpart_if_possible(), but without validating | |||
1115 | the newly-formed address. */ | |||
1116 | poly_int64 offset = byte_lowpart_offset (mode, GET_MODE (mem)((machine_mode) (mem)->mode)); | |||
1117 | mem = adjust_address_nv (mem, mode, offset)adjust_address_1 (mem, mode, offset, 0, 1, 0, 0); | |||
1118 | } | |||
1119 | } | |||
1120 | else | |||
1121 | { | |||
1122 | mem = gen_rtx_CONCATN (mode, rtvec_alloc (nregs))gen_rtx_fmt_E_stat ((CONCATN), ((mode)), ((rtvec_alloc (nregs ))) ); | |||
1123 | for (i = 0; i < nregs; i++) | |||
1124 | if (TEST_HARD_REG_BIT (hard_regs_saved, regno + i)) | |||
1125 | { | |||
1126 | gcc_assert (regno_save_mem[regno + i][1])((void)(!(regno_save_mem[regno + i][1]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1126, __FUNCTION__), 0 : 0)); | |||
1127 | XVECEXP (mem, 0, i)(((((mem)->u.fld[0]).rt_rtvec))->elem[i]) = copy_rtx (regno_save_mem[regno + i][1]); | |||
1128 | } | |||
1129 | else | |||
1130 | { | |||
1131 | machine_mode smode = save_mode[regno]; | |||
1132 | gcc_assert (smode != VOIDmode)((void)(!(smode != ((void) 0, E_VOIDmode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1132, __FUNCTION__), 0 : 0)); | |||
1133 | if (hard_regno_nregs (regno, smode) > 1) | |||
1134 | smode = mode_for_size (exact_div (GET_MODE_BITSIZE (mode), | |||
1135 | nregs), | |||
1136 | GET_MODE_CLASS (mode)((enum mode_class) mode_class[mode]), 0).require (); | |||
1137 | XVECEXP (mem, 0, i)(((((mem)->u.fld[0]).rt_rtvec))->elem[i]) = gen_rtx_REG (smode, regno + i); | |||
1138 | } | |||
1139 | } | |||
1140 | ||||
1141 | gcc_assert (GET_MODE (mem) == mode)((void)(!(((machine_mode) (mem)->mode) == mode) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1141, __FUNCTION__), 0 : 0)); | |||
1142 | *loc = mem; | |||
1143 | } | |||
1144 | ||||
1145 | ||||
1146 | /* Insert a sequence of insns to restore. Place these insns in front of | |||
1147 | CHAIN if BEFORE_P is nonzero, behind the insn otherwise. MAXRESTORE is | |||
1148 | the maximum number of registers which should be restored during this call. | |||
1149 | It should never be less than 1 since we only work with entire registers. | |||
1150 | ||||
1151 | Note that we have verified in init_caller_save that we can do this | |||
1152 | with a simple SET, so use it. Set INSN_CODE to what we save there | |||
1153 | since the address might not be valid so the insn might not be recognized. | |||
1154 | These insns will be reloaded and have register elimination done by | |||
1155 | find_reload, so we need not worry about that here. | |||
1156 | ||||
1157 | Return the extra number of registers saved. */ | |||
1158 | ||||
1159 | static int | |||
1160 | insert_restore (class insn_chain *chain, int before_p, int regno, | |||
1161 | int maxrestore, machine_mode *save_mode) | |||
1162 | { | |||
1163 | int i, k; | |||
1164 | rtx pat = NULL_RTX(rtx) 0; | |||
1165 | int code; | |||
1166 | unsigned int numregs = 0; | |||
1167 | class insn_chain *new_chain; | |||
1168 | rtx mem; | |||
1169 | ||||
1170 | /* A common failure mode if register status is not correct in the | |||
1171 | RTL is for this routine to be called with a REGNO we didn't | |||
1172 | expect to save. That will cause us to write an insn with a (nil) | |||
1173 | SET_DEST or SET_SRC. Instead of doing so and causing a crash | |||
1174 | later, check for this common case here instead. This will remove | |||
1175 | one step in debugging such problems. */ | |||
1176 | gcc_assert (regno_save_mem[regno][1])((void)(!(regno_save_mem[regno][1]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1176, __FUNCTION__), 0 : 0)); | |||
1177 | ||||
1178 | /* Get the pattern to emit and update our status. | |||
1179 | ||||
1180 | See if we can restore `maxrestore' registers at once. Work | |||
1181 | backwards to the single register case. */ | |||
1182 | for (i = maxrestore; i > 0; i--) | |||
1183 | { | |||
1184 | int j; | |||
1185 | int ok = 1; | |||
1186 | ||||
1187 | if (regno_save_mem[regno][i] == 0) | |||
1188 | continue; | |||
1189 | ||||
1190 | for (j = 0; j < i; j++) | |||
1191 | if (! TEST_HARD_REG_BIT (hard_regs_saved, regno + j)) | |||
1192 | { | |||
1193 | ok = 0; | |||
1194 | break; | |||
1195 | } | |||
1196 | /* Must do this one restore at a time. */ | |||
1197 | if (! ok
| |||
1198 | continue; | |||
1199 | ||||
1200 | numregs = i; | |||
1201 | break; | |||
1202 | } | |||
1203 | ||||
1204 | mem = regno_save_mem [regno][numregs]; | |||
1205 | if (save_mode [regno] != VOIDmode((void) 0, E_VOIDmode) | |||
| ||||
1206 | && save_mode [regno] != GET_MODE (mem)((machine_mode) (mem)->mode) | |||
1207 | && numregs == hard_regno_nregs (regno, save_mode [regno]) | |||
1208 | /* Check that insn to restore REGNO in save_mode[regno] is | |||
1209 | correct. */ | |||
1210 | && reg_save_code (regno, save_mode[regno]) >= 0) | |||
1211 | mem = adjust_address_nv (mem, save_mode[regno], 0)adjust_address_1 (mem, save_mode[regno], 0, 0, 1, 0, 0); | |||
1212 | else | |||
1213 | mem = copy_rtx (mem); | |||
1214 | ||||
1215 | /* Verify that the alignment of spill space is equal to or greater | |||
1216 | than required. */ | |||
1217 | gcc_assert (MIN (MAX_SUPPORTED_STACK_ALIGNMENT,((void)(!((((((unsigned int) 1 << 28) * 8)) < (get_mode_alignment (((machine_mode) (mem)->mode))) ? ((((unsigned int) 1 << 28) * 8)) : (get_mode_alignment (((machine_mode) (mem)->mode )))) <= (get_mem_attrs (mem)->align)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1218, __FUNCTION__), 0 : 0)) | |||
1218 | GET_MODE_ALIGNMENT (GET_MODE (mem))) <= MEM_ALIGN (mem))((void)(!((((((unsigned int) 1 << 28) * 8)) < (get_mode_alignment (((machine_mode) (mem)->mode))) ? ((((unsigned int) 1 << 28) * 8)) : (get_mode_alignment (((machine_mode) (mem)->mode )))) <= (get_mem_attrs (mem)->align)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1218, __FUNCTION__), 0 : 0)); | |||
1219 | ||||
1220 | pat = gen_rtx_SET (gen_rtx_REG (GET_MODE (mem), regno), mem)gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), ((gen_rtx_REG (((machine_mode) (mem)->mode), regno))), ((mem)) ); | |||
1221 | code = reg_restore_code (regno, GET_MODE (mem)((machine_mode) (mem)->mode)); | |||
1222 | new_chain = insert_one_insn (chain, before_p, code, pat); | |||
1223 | ||||
1224 | /* Clear status for all registers we restored. */ | |||
1225 | for (k = 0; k < i; k++) | |||
1226 | { | |||
1227 | CLEAR_HARD_REG_BIT (hard_regs_saved, regno + k); | |||
1228 | SET_REGNO_REG_SET (&new_chain->dead_or_set, regno + k)bitmap_set_bit (&new_chain->dead_or_set, regno + k); | |||
1229 | n_regs_saved--; | |||
1230 | } | |||
1231 | ||||
1232 | /* Tell our callers how many extra registers we saved/restored. */ | |||
1233 | return numregs - 1; | |||
1234 | } | |||
1235 | ||||
1236 | /* Like insert_restore above, but save registers instead. */ | |||
1237 | ||||
1238 | static int | |||
1239 | insert_save (class insn_chain *chain, int regno, | |||
1240 | HARD_REG_SET *to_save, machine_mode *save_mode) | |||
1241 | { | |||
1242 | int i; | |||
1243 | unsigned int k; | |||
1244 | rtx pat = NULL_RTX(rtx) 0; | |||
1245 | int code; | |||
1246 | unsigned int numregs = 0; | |||
1247 | class insn_chain *new_chain; | |||
1248 | rtx mem; | |||
1249 | ||||
1250 | /* A common failure mode if register status is not correct in the | |||
1251 | RTL is for this routine to be called with a REGNO we didn't | |||
1252 | expect to save. That will cause us to write an insn with a (nil) | |||
1253 | SET_DEST or SET_SRC. Instead of doing so and causing a crash | |||
1254 | later, check for this common case here. This will remove one | |||
1255 | step in debugging such problems. */ | |||
1256 | gcc_assert (regno_save_mem[regno][1])((void)(!(regno_save_mem[regno][1]) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1256, __FUNCTION__), 0 : 0)); | |||
1257 | ||||
1258 | /* Get the pattern to emit and update our status. | |||
1259 | ||||
1260 | See if we can save several registers with a single instruction. | |||
1261 | Work backwards to the single register case. */ | |||
1262 | for (i = MOVE_MAX_WORDS(((((global_options.x_ix86_isa_flags & (1UL << 15)) != 0) && (global_options.x_ix86_move_max == PVW_AVX512 || global_options.x_ix86_store_max == PVW_AVX512)) ? 64 : (( ((global_options.x_ix86_isa_flags & (1UL << 8)) != 0 ) && (global_options.x_ix86_move_max >= PVW_AVX256 || global_options.x_ix86_store_max >= PVW_AVX256)) ? 32 : ((((global_options.x_ix86_isa_flags & (1UL << 51)) != 0) && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL ] && ix86_tune_features[X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL ]) ? 16 : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)))) / (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); i > 0; i--) | |||
1263 | { | |||
1264 | int j; | |||
1265 | int ok = 1; | |||
1266 | if (regno_save_mem[regno][i] == 0) | |||
1267 | continue; | |||
1268 | ||||
1269 | for (j = 0; j < i; j++) | |||
1270 | if (! TEST_HARD_REG_BIT (*to_save, regno + j)) | |||
1271 | { | |||
1272 | ok = 0; | |||
1273 | break; | |||
1274 | } | |||
1275 | /* Must do this one save at a time. */ | |||
1276 | if (! ok) | |||
1277 | continue; | |||
1278 | ||||
1279 | numregs = i; | |||
1280 | break; | |||
1281 | } | |||
1282 | ||||
1283 | mem = regno_save_mem [regno][numregs]; | |||
1284 | if (save_mode [regno] != VOIDmode((void) 0, E_VOIDmode) | |||
1285 | && save_mode [regno] != GET_MODE (mem)((machine_mode) (mem)->mode) | |||
1286 | && numregs == hard_regno_nregs (regno, save_mode [regno]) | |||
1287 | /* Check that insn to save REGNO in save_mode[regno] is | |||
1288 | correct. */ | |||
1289 | && reg_save_code (regno, save_mode[regno]) >= 0) | |||
1290 | mem = adjust_address_nv (mem, save_mode[regno], 0)adjust_address_1 (mem, save_mode[regno], 0, 0, 1, 0, 0); | |||
1291 | else | |||
1292 | mem = copy_rtx (mem); | |||
1293 | ||||
1294 | /* Verify that the alignment of spill space is equal to or greater | |||
1295 | than required. */ | |||
1296 | gcc_assert (MIN (MAX_SUPPORTED_STACK_ALIGNMENT,((void)(!((((((unsigned int) 1 << 28) * 8)) < (get_mode_alignment (((machine_mode) (mem)->mode))) ? ((((unsigned int) 1 << 28) * 8)) : (get_mode_alignment (((machine_mode) (mem)->mode )))) <= (get_mem_attrs (mem)->align)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1297, __FUNCTION__), 0 : 0)) | |||
1297 | GET_MODE_ALIGNMENT (GET_MODE (mem))) <= MEM_ALIGN (mem))((void)(!((((((unsigned int) 1 << 28) * 8)) < (get_mode_alignment (((machine_mode) (mem)->mode))) ? ((((unsigned int) 1 << 28) * 8)) : (get_mode_alignment (((machine_mode) (mem)->mode )))) <= (get_mem_attrs (mem)->align)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1297, __FUNCTION__), 0 : 0)); | |||
1298 | ||||
1299 | pat = gen_rtx_SET (mem, gen_rtx_REG (GET_MODE (mem), regno))gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), ((mem)) , ((gen_rtx_REG (((machine_mode) (mem)->mode), regno))) ); | |||
1300 | code = reg_save_code (regno, GET_MODE (mem)((machine_mode) (mem)->mode)); | |||
1301 | new_chain = insert_one_insn (chain, 1, code, pat); | |||
1302 | ||||
1303 | /* Set hard_regs_saved and dead_or_set for all the registers we saved. */ | |||
1304 | for (k = 0; k < numregs; k++) | |||
1305 | { | |||
1306 | SET_HARD_REG_BIT (hard_regs_saved, regno + k); | |||
1307 | SET_REGNO_REG_SET (&new_chain->dead_or_set, regno + k)bitmap_set_bit (&new_chain->dead_or_set, regno + k); | |||
1308 | n_regs_saved++; | |||
1309 | } | |||
1310 | ||||
1311 | /* Tell our callers how many extra registers we saved/restored. */ | |||
1312 | return numregs - 1; | |||
1313 | } | |||
1314 | ||||
1315 | /* A note_uses callback used by insert_one_insn. Add the hard-register | |||
1316 | equivalent of each REG to regset DATA. */ | |||
1317 | ||||
1318 | static void | |||
1319 | add_used_regs (rtx *loc, void *data) | |||
1320 | { | |||
1321 | subrtx_iterator::array_type array; | |||
1322 | FOR_EACH_SUBRTX (iter, array, *loc, NONCONST)for (subrtx_iterator iter (array, *loc, rtx_nonconst_subrtx_bounds ); !iter.at_end (); iter.next ()) | |||
1323 | { | |||
1324 | const_rtx x = *iter; | |||
1325 | if (REG_P (x)(((enum rtx_code) (x)->code) == REG)) | |||
1326 | { | |||
1327 | unsigned int regno = REGNO (x)(rhs_regno(x)); | |||
1328 | if (HARD_REGISTER_NUM_P (regno)((regno) < 76)) | |||
1329 | bitmap_set_range ((regset) data, regno, REG_NREGS (x)((&(x)->u.reg)->nregs)); | |||
1330 | else | |||
1331 | gcc_checking_assert (reg_renumber[regno] < 0)((void)(!(reg_renumber[regno] < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/caller-save.cc" , 1331, __FUNCTION__), 0 : 0)); | |||
1332 | } | |||
1333 | } | |||
1334 | } | |||
1335 | ||||
1336 | /* Emit a new caller-save insn and set the code. */ | |||
1337 | static class insn_chain * | |||
1338 | insert_one_insn (class insn_chain *chain, int before_p, int code, rtx pat) | |||
1339 | { | |||
1340 | rtx_insn *insn = chain->insn; | |||
1341 | class insn_chain *new_chain; | |||
1342 | ||||
1343 | new_chain = new_insn_chain (); | |||
1344 | if (before_p) | |||
1345 | { | |||
1346 | rtx link; | |||
1347 | ||||
1348 | new_chain->prev = chain->prev; | |||
1349 | if (new_chain->prev != 0) | |||
1350 | new_chain->prev->next = new_chain; | |||
1351 | else | |||
1352 | reload_insn_chain = new_chain; | |||
1353 | ||||
1354 | chain->prev = new_chain; | |||
1355 | new_chain->next = chain; | |||
1356 | new_chain->insn = emit_insn_before (pat, insn); | |||
1357 | /* ??? It would be nice if we could exclude the already / still saved | |||
1358 | registers from the live sets. */ | |||
1359 | COPY_REG_SET (&new_chain->live_throughout, &chain->live_throughout)bitmap_copy (&new_chain->live_throughout, &chain-> live_throughout); | |||
1360 | note_uses (&PATTERN (chain->insn), add_used_regs, | |||
1361 | &new_chain->live_throughout); | |||
1362 | /* If CHAIN->INSN is a call, then the registers which contain | |||
1363 | the arguments to the function are live in the new insn. */ | |||
1364 | if (CALL_P (chain->insn)(((enum rtx_code) (chain->insn)->code) == CALL_INSN)) | |||
1365 | for (link = CALL_INSN_FUNCTION_USAGE (chain->insn)(((chain->insn)->u.fld[7]).rt_rtx); | |||
1366 | link != NULL_RTX(rtx) 0; | |||
1367 | link = XEXP (link, 1)(((link)->u.fld[1]).rt_rtx)) | |||
1368 | note_uses (&XEXP (link, 0)(((link)->u.fld[0]).rt_rtx), add_used_regs, | |||
1369 | &new_chain->live_throughout); | |||
1370 | ||||
1371 | CLEAR_REG_SET (&new_chain->dead_or_set)bitmap_clear (&new_chain->dead_or_set); | |||
1372 | if (chain->insn == BB_HEAD (BASIC_BLOCK_FOR_FN (cfun, chain->block))(((*(((cfun + 0))->cfg->x_basic_block_info))[(chain-> block)]))->il.x.head_) | |||
1373 | BB_HEAD (BASIC_BLOCK_FOR_FN (cfun, chain->block))(((*(((cfun + 0))->cfg->x_basic_block_info))[(chain-> block)]))->il.x.head_ = new_chain->insn; | |||
1374 | } | |||
1375 | else | |||
1376 | { | |||
1377 | new_chain->next = chain->next; | |||
1378 | if (new_chain->next != 0) | |||
1379 | new_chain->next->prev = new_chain; | |||
1380 | chain->next = new_chain; | |||
1381 | new_chain->prev = chain; | |||
1382 | new_chain->insn = emit_insn_after (pat, insn); | |||
1383 | /* ??? It would be nice if we could exclude the already / still saved | |||
1384 | registers from the live sets, and observe REG_UNUSED notes. */ | |||
1385 | COPY_REG_SET (&new_chain->live_throughout, &chain->live_throughout)bitmap_copy (&new_chain->live_throughout, &chain-> live_throughout); | |||
1386 | /* Registers that are set in CHAIN->INSN live in the new insn. | |||
1387 | (Unless there is a REG_UNUSED note for them, but we don't | |||
1388 | look for them here.) */ | |||
1389 | note_stores (chain->insn, add_stored_regs, &new_chain->live_throughout); | |||
1390 | CLEAR_REG_SET (&new_chain->dead_or_set)bitmap_clear (&new_chain->dead_or_set); | |||
1391 | if (chain->insn == BB_END (BASIC_BLOCK_FOR_FN (cfun, chain->block))(((*(((cfun + 0))->cfg->x_basic_block_info))[(chain-> block)]))->il.x.rtl->end_) | |||
1392 | BB_END (BASIC_BLOCK_FOR_FN (cfun, chain->block))(((*(((cfun + 0))->cfg->x_basic_block_info))[(chain-> block)]))->il.x.rtl->end_ = new_chain->insn; | |||
1393 | } | |||
1394 | new_chain->block = chain->block; | |||
1395 | new_chain->is_caller_save_insn = 1; | |||
1396 | ||||
1397 | INSN_CODE (new_chain->insn)(((new_chain->insn)->u.fld[5]).rt_int) = code; | |||
1398 | return new_chain; | |||
1399 | } | |||
1400 | #include "gt-caller-save.h" |