Branch data Line data Source code
1 : : /* Infrastructure for tracking user variable locations and values
2 : : throughout compilation.
3 : : Copyright (C) 2010-2025 Free Software Foundation, Inc.
4 : : Contributed by Alexandre Oliva <aoliva@redhat.com>.
5 : :
6 : : This file is part of GCC.
7 : :
8 : : GCC is free software; you can redistribute it and/or modify it under
9 : : the terms of the GNU General Public License as published by the Free
10 : : Software Foundation; either version 3, or (at your option) any later
11 : : version.
12 : :
13 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 : : for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with GCC; see the file COPYING3. If not see
20 : : <http://www.gnu.org/licenses/>. */
21 : :
22 : : #include "config.h"
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "backend.h"
26 : : #include "rtl.h"
27 : : #include "df.h"
28 : : #include "valtrack.h"
29 : : #include "regs.h"
30 : : #include "memmodel.h"
31 : : #include "emit-rtl.h"
32 : : #include "rtl-iter.h"
33 : :
34 : : /* gen_lowpart_no_emit hook implementation for DEBUG_INSNs. In DEBUG_INSNs,
35 : : all lowpart SUBREGs are valid, despite what the machine requires for
36 : : instructions. */
37 : :
38 : : static rtx
39 : 173 : gen_lowpart_for_debug (machine_mode mode, rtx x)
40 : : {
41 : 173 : rtx result = gen_lowpart_if_possible (mode, x);
42 : 173 : if (result)
43 : : return result;
44 : :
45 : 4 : if (GET_MODE (x) != VOIDmode)
46 : 4 : return gen_rtx_raw_SUBREG (mode, x,
47 : : subreg_lowpart_offset (mode, GET_MODE (x)));
48 : :
49 : : return NULL_RTX;
50 : : }
51 : :
52 : : /* Replace auto-increment addressing modes with explicit operations to access
53 : : the same addresses without modifying the corresponding registers. */
54 : :
55 : : static rtx
56 : 1010097 : cleanup_auto_inc_dec (rtx src, machine_mode mem_mode ATTRIBUTE_UNUSED)
57 : : {
58 : 1010097 : rtx x = src;
59 : :
60 : 1010097 : const RTX_CODE code = GET_CODE (x);
61 : 1010097 : int i;
62 : 1010097 : const char *fmt;
63 : :
64 : 1010097 : switch (code)
65 : : {
66 : : case REG:
67 : : CASE_CONST_ANY:
68 : : case SYMBOL_REF:
69 : : case CODE_LABEL:
70 : : case PC:
71 : : case SCRATCH:
72 : : /* SCRATCH must be shared because they represent distinct values. */
73 : : return x;
74 : 0 : case CLOBBER:
75 : : /* Share clobbers of hard registers, but do not share pseudo reg
76 : : clobbers or clobbers of hard registers that originated as pseudos.
77 : : This is needed to allow safe register renaming. */
78 : 0 : if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
79 : 0 : && ORIGINAL_REGNO (XEXP (x, 0)) == REGNO (XEXP (x, 0)))
80 : : return x;
81 : : break;
82 : :
83 : 1850 : case CONST:
84 : 1850 : if (shared_const_p (x))
85 : : return x;
86 : : break;
87 : :
88 : 107060 : case MEM:
89 : 107060 : mem_mode = GET_MODE (x);
90 : 107060 : break;
91 : :
92 : 0 : case PRE_INC:
93 : 0 : case PRE_DEC:
94 : 0 : {
95 : 0 : gcc_assert (mem_mode != VOIDmode && mem_mode != BLKmode);
96 : 0 : poly_int64 offset = GET_MODE_SIZE (mem_mode);
97 : 0 : if (code == PRE_DEC)
98 : 0 : offset = -offset;
99 : 0 : return gen_rtx_PLUS (GET_MODE (x),
100 : : cleanup_auto_inc_dec (XEXP (x, 0), mem_mode),
101 : : gen_int_mode (offset, GET_MODE (x)));
102 : : }
103 : :
104 : 0 : case POST_INC:
105 : 0 : case POST_DEC:
106 : 0 : case PRE_MODIFY:
107 : 0 : case POST_MODIFY:
108 : 0 : return cleanup_auto_inc_dec (code == PRE_MODIFY
109 : : ? XEXP (x, 1) : XEXP (x, 0),
110 : 0 : mem_mode);
111 : :
112 : : default:
113 : : break;
114 : : }
115 : :
116 : : /* Copy the various flags, fields, and other information. We assume
117 : : that all fields need copying, and then clear the fields that should
118 : : not be copied. That is the sensible default behavior, and forces
119 : : us to explicitly document why we are *not* copying a flag. */
120 : 336389 : x = shallow_copy_rtx (x);
121 : :
122 : : /* We do not copy FRAME_RELATED for INSNs. */
123 : 336389 : if (INSN_P (x))
124 : 0 : RTX_FLAG (x, frame_related) = 0;
125 : :
126 : 336389 : fmt = GET_RTX_FORMAT (code);
127 : 1002586 : for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
128 : 666197 : if (fmt[i] == 'e')
129 : 546928 : XEXP (x, i) = cleanup_auto_inc_dec (XEXP (x, i), mem_mode);
130 : 119269 : else if (fmt[i] == 'E' || fmt[i] == 'V')
131 : : {
132 : 1005 : int j;
133 : 1005 : XVEC (x, i) = rtvec_alloc (XVECLEN (x, i));
134 : 2014 : for (j = 0; j < XVECLEN (x, i); j++)
135 : 1009 : XVECEXP (x, i, j)
136 : 1009 : = cleanup_auto_inc_dec (XVECEXP (src, i, j), mem_mode);
137 : : }
138 : :
139 : : return x;
140 : : }
141 : :
142 : : /* Auxiliary data structure for propagate_for_debug_stmt. */
143 : :
144 : : struct rtx_subst_pair
145 : : {
146 : : rtx to;
147 : : bool adjusted;
148 : : rtx_insn *insn;
149 : : };
150 : :
151 : : /* DATA points to an rtx_subst_pair. Return the value that should be
152 : : substituted. */
153 : :
154 : : static rtx
155 : 3459182 : propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
156 : : {
157 : 3459182 : struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
158 : :
159 : 3459182 : if (!rtx_equal_p (from, old_rtx))
160 : : return NULL_RTX;
161 : 256351 : if (!pair->adjusted)
162 : : {
163 : 210446 : pair->adjusted = true;
164 : 210446 : pair->to = cleanup_auto_inc_dec (pair->to, VOIDmode);
165 : 210446 : pair->to = make_compound_operation (pair->to, SET);
166 : : /* Avoid propagation from growing DEBUG_INSN expressions too much. */
167 : 210446 : int cnt = 0;
168 : 210446 : subrtx_iterator::array_type array;
169 : 651342 : FOR_EACH_SUBRTX (iter, array, pair->to, ALL)
170 : 460004 : if (REG_P (*iter) && ++cnt > 1)
171 : : {
172 : 19108 : rtx dval = make_debug_expr_from_rtl (old_rtx);
173 : 19108 : rtx to = pair->to;
174 : 19108 : if (volatile_insn_p (to))
175 : 0 : to = gen_rtx_UNKNOWN_VAR_LOC ();
176 : : /* Emit a debug bind insn. */
177 : 19108 : rtx bind
178 : 19108 : = gen_rtx_VAR_LOCATION (GET_MODE (old_rtx),
179 : : DEBUG_EXPR_TREE_DECL (dval), to,
180 : : VAR_INIT_STATUS_INITIALIZED);
181 : 19108 : rtx_insn *bind_insn = emit_debug_insn_before (bind, pair->insn);
182 : 19108 : df_insn_rescan (bind_insn);
183 : 19108 : pair->to = dval;
184 : 19108 : break;
185 : : }
186 : 210446 : return pair->to;
187 : 210446 : }
188 : 45905 : return copy_rtx (pair->to);
189 : : }
190 : :
191 : : /* Replace all the occurrences of DEST with SRC in DEBUG_INSNs between INSN
192 : : and LAST, not including INSN, but including LAST. Also stop at the end
193 : : of THIS_BASIC_BLOCK. */
194 : :
195 : : void
196 : 2088495 : propagate_for_debug (rtx_insn *insn, rtx_insn *last, rtx dest, rtx src,
197 : : basic_block this_basic_block)
198 : : {
199 : 2088495 : rtx_insn *next, *end = NEXT_INSN (BB_END (this_basic_block));
200 : 2088495 : rtx loc;
201 : 2088495 : rtx (*saved_rtl_hook_no_emit) (machine_mode, rtx);
202 : :
203 : 2088495 : struct rtx_subst_pair p;
204 : 2088495 : p.to = src;
205 : 2088495 : p.adjusted = false;
206 : 2088495 : p.insn = NEXT_INSN (insn);
207 : :
208 : 2088495 : next = NEXT_INSN (insn);
209 : 2088495 : last = NEXT_INSN (last);
210 : 2088495 : saved_rtl_hook_no_emit = rtl_hooks.gen_lowpart_no_emit;
211 : 2088495 : rtl_hooks.gen_lowpart_no_emit = gen_lowpart_for_debug;
212 : 8723049 : while (next != last && next != end)
213 : : {
214 : 6634554 : insn = next;
215 : 6634554 : next = NEXT_INSN (insn);
216 : 6634554 : if (DEBUG_BIND_INSN_P (insn))
217 : : {
218 : 1904034 : loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
219 : : dest, propagate_for_debug_subst, &p);
220 : 1904034 : if (loc == INSN_VAR_LOCATION_LOC (insn))
221 : 1648129 : continue;
222 : 255905 : if (volatile_insn_p (loc))
223 : 0 : loc = gen_rtx_UNKNOWN_VAR_LOC ();
224 : 255905 : INSN_VAR_LOCATION_LOC (insn) = loc;
225 : 255905 : df_insn_rescan (insn);
226 : : }
227 : : }
228 : 2088495 : rtl_hooks.gen_lowpart_no_emit = saved_rtl_hook_no_emit;
229 : 2088495 : }
230 : :
231 : : /* Initialize DEBUG to an empty list, and clear USED, if given. */
232 : :
233 : : void
234 : 9623772 : dead_debug_global_init (struct dead_debug_global *debug, bitmap used)
235 : : {
236 : 9623772 : debug->used = used;
237 : 9623772 : debug->htab = NULL;
238 : 9623772 : if (used)
239 : 0 : bitmap_clear (used);
240 : 9623772 : }
241 : :
242 : : /* Initialize DEBUG to an empty list, and clear USED, if given. Link
243 : : back to GLOBAL, if given, and bring in used bits from it. */
244 : :
245 : : void
246 : 360618199 : dead_debug_local_init (struct dead_debug_local *debug, bitmap used,
247 : : struct dead_debug_global *global)
248 : : {
249 : 360618199 : if (!used && global && global->used)
250 : 2833531 : used = BITMAP_ALLOC (NULL);
251 : :
252 : 360618199 : debug->head = NULL;
253 : 360618199 : debug->global = global;
254 : 360618199 : debug->used = used;
255 : 360618199 : debug->to_rescan = NULL;
256 : :
257 : 360618199 : if (used)
258 : : {
259 : 2833531 : if (global && global->used)
260 : 2833531 : bitmap_copy (used, global->used);
261 : : else
262 : 0 : bitmap_clear (used);
263 : : }
264 : 360618199 : }
265 : :
266 : : /* Locate the entry for REG in GLOBAL->htab. */
267 : :
268 : : static dead_debug_global_entry *
269 : 1231258 : dead_debug_global_find (struct dead_debug_global *global, rtx reg)
270 : : {
271 : 1231258 : dead_debug_global_entry temp_entry;
272 : 1231258 : temp_entry.reg = reg;
273 : :
274 : 1231258 : dead_debug_global_entry *entry = global->htab->find (&temp_entry);
275 : 1231258 : gcc_checking_assert (entry && entry->reg == temp_entry.reg);
276 : :
277 : 1231258 : return entry;
278 : : }
279 : :
280 : : /* Insert an entry mapping REG to DTEMP in GLOBAL->htab. */
281 : :
282 : : static dead_debug_global_entry *
283 : 116148 : dead_debug_global_insert (struct dead_debug_global *global, rtx reg, rtx dtemp)
284 : : {
285 : 116148 : dead_debug_global_entry temp_entry;
286 : 116148 : temp_entry.reg = reg;
287 : 116148 : temp_entry.dtemp = dtemp;
288 : :
289 : 116148 : if (!global->htab)
290 : 63540 : global->htab = new hash_table<dead_debug_hash_descr> (31);
291 : :
292 : 116148 : dead_debug_global_entry **slot = global->htab->find_slot (&temp_entry,
293 : : INSERT);
294 : 116148 : gcc_checking_assert (!*slot);
295 : 116148 : *slot = XNEW (dead_debug_global_entry);
296 : 116148 : **slot = temp_entry;
297 : 116148 : return *slot;
298 : : }
299 : :
300 : : /* If UREGNO, referenced by USE, is a pseudo marked as used in GLOBAL,
301 : : replace it with a USE of the debug temp recorded for it, and
302 : : return TRUE. Otherwise, just return FALSE.
303 : :
304 : : If PTO_RESCAN is given, instead of rescanning modified INSNs right
305 : : away, add their UIDs to the bitmap, allocating one of *PTO_RESCAN
306 : : is NULL. */
307 : :
308 : : static bool
309 : 1295632 : dead_debug_global_replace_temp (struct dead_debug_global *global,
310 : : df_ref use, unsigned int uregno,
311 : : bitmap *pto_rescan)
312 : : {
313 : 1295632 : if (!global || uregno < FIRST_PSEUDO_REGISTER
314 : 1075864 : || !global->used
315 : 880099 : || !REG_P (*DF_REF_REAL_LOC (use))
316 : 880081 : || REGNO (*DF_REF_REAL_LOC (use)) != uregno
317 : 2175713 : || !bitmap_bit_p (global->used, uregno))
318 : 494778 : return false;
319 : :
320 : 800854 : dead_debug_global_entry *entry
321 : 800854 : = dead_debug_global_find (global, *DF_REF_REAL_LOC (use));
322 : 800854 : gcc_checking_assert (GET_CODE (entry->reg) == REG
323 : : && REGNO (entry->reg) == uregno);
324 : :
325 : 800854 : if (!entry->dtemp)
326 : : return true;
327 : :
328 : 800852 : *DF_REF_REAL_LOC (use) = entry->dtemp;
329 : 800852 : if (!pto_rescan)
330 : 0 : df_insn_rescan (DF_REF_INSN (use));
331 : : else
332 : : {
333 : 800852 : if (!*pto_rescan)
334 : 0 : *pto_rescan = BITMAP_ALLOC (NULL);
335 : 800852 : bitmap_set_bit (*pto_rescan, INSN_UID (DF_REF_INSN (use)));
336 : : }
337 : :
338 : : return true;
339 : : }
340 : :
341 : : /* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of
342 : : each reset insn. DEBUG is not otherwise modified. If HEAD is
343 : : DEBUG->head, DEBUG->head will be set to NULL at the end.
344 : : Otherwise, entries from DEBUG->head that pertain to reset insns
345 : : will be removed, and only then rescanned. */
346 : :
347 : : static void
348 : 360622690 : dead_debug_reset_uses (struct dead_debug_local *debug,
349 : : struct dead_debug_use *head)
350 : : {
351 : 360622690 : bool got_head = (debug->head == head);
352 : 360622690 : bitmap rescan;
353 : 360622690 : struct dead_debug_use **tailp = &debug->head;
354 : 360622690 : struct dead_debug_use *cur;
355 : 360622690 : bitmap_iterator bi;
356 : 360622690 : unsigned int uid;
357 : :
358 : 360622690 : if (got_head)
359 : 360622690 : rescan = NULL;
360 : : else
361 : 1382 : rescan = BITMAP_ALLOC (NULL);
362 : :
363 : 360737395 : while (head)
364 : : {
365 : 114705 : struct dead_debug_use *next = head->next;
366 : 114705 : rtx_insn *insn;
367 : :
368 : 114705 : insn = DF_REF_INSN (head->use);
369 : 114705 : if (!next || DF_REF_INSN (next->use) != insn)
370 : : {
371 : 113233 : INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
372 : 113233 : if (got_head)
373 : 112211 : df_insn_rescan_debug_internal (insn);
374 : : else
375 : 1022 : bitmap_set_bit (rescan, INSN_UID (insn));
376 : 113233 : if (debug->to_rescan)
377 : 2472 : bitmap_clear_bit (debug->to_rescan, INSN_UID (insn));
378 : : }
379 : 114705 : XDELETE (head);
380 : 114705 : head = next;
381 : : }
382 : :
383 : 360622690 : if (got_head)
384 : : {
385 : 360621308 : debug->head = NULL;
386 : 360621308 : return;
387 : : }
388 : :
389 : 1913 : while ((cur = *tailp))
390 : 531 : if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use))))
391 : : {
392 : 15 : *tailp = cur->next;
393 : 15 : XDELETE (cur);
394 : : }
395 : : else
396 : 516 : tailp = &cur->next;
397 : :
398 : 2404 : EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi)
399 : : {
400 : 2044 : struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
401 : 1022 : if (insn_info)
402 : 1022 : df_insn_rescan_debug_internal (insn_info->insn);
403 : : }
404 : :
405 : 1382 : BITMAP_FREE (rescan);
406 : : }
407 : :
408 : : /* Promote pending local uses of pseudos in DEBUG to global
409 : : substitutions. Uses of non-pseudos are left alone for
410 : : resetting. */
411 : :
412 : : static void
413 : 161850297 : dead_debug_promote_uses (struct dead_debug_local *debug)
414 : : {
415 : 161850297 : for (struct dead_debug_use *head = debug->head, **headp = &debug->head;
416 : 161968877 : head; head = *headp)
417 : : {
418 : 118580 : rtx reg = *DF_REF_REAL_LOC (head->use);
419 : 118580 : df_ref ref;
420 : 118580 : dead_debug_global_entry *entry;
421 : :
422 : 121012 : if (GET_CODE (reg) != REG
423 : 118580 : || REGNO (reg) < FIRST_PSEUDO_REGISTER)
424 : : {
425 : 2432 : headp = &head->next;
426 : 2432 : continue;
427 : : }
428 : :
429 : 116148 : if (!debug->global->used)
430 : 63540 : debug->global->used = BITMAP_ALLOC (NULL);
431 : :
432 : 116148 : bool added = bitmap_set_bit (debug->global->used, REGNO (reg));
433 : 116148 : gcc_checking_assert (added);
434 : :
435 : 116148 : entry = dead_debug_global_insert (debug->global, reg,
436 : : make_debug_expr_from_rtl (reg));
437 : :
438 : 116148 : gcc_checking_assert (entry->dtemp);
439 : :
440 : : /* Tentatively remove the USE from the list. */
441 : 116148 : *headp = head->next;
442 : :
443 : 116148 : if (!debug->to_rescan)
444 : 99358 : debug->to_rescan = BITMAP_ALLOC (NULL);
445 : :
446 : 1580301 : for (ref = DF_REG_USE_CHAIN (REGNO (reg)); ref;
447 : 1464153 : ref = DF_REF_NEXT_REG (ref))
448 : 1464153 : if (DEBUG_INSN_P (DF_REF_INSN (ref)))
449 : : {
450 : 800870 : if (!dead_debug_global_replace_temp (debug->global, ref,
451 : : REGNO (reg),
452 : : &debug->to_rescan))
453 : : {
454 : 18 : rtx_insn *insn = DF_REF_INSN (ref);
455 : 18 : INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
456 : 18 : bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
457 : : }
458 : : }
459 : :
460 : 347643 : for (ref = DF_REG_DEF_CHAIN (REGNO (reg)); ref;
461 : 231495 : ref = DF_REF_NEXT_REG (ref))
462 : 231495 : if (!dead_debug_insert_temp (debug, REGNO (reg), DF_REF_INSN (ref),
463 : : DEBUG_TEMP_BEFORE_WITH_VALUE))
464 : : {
465 : 3537 : rtx bind;
466 : 3537 : bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
467 : 3537 : DEBUG_EXPR_TREE_DECL (entry->dtemp),
468 : : gen_rtx_UNKNOWN_VAR_LOC (),
469 : : VAR_INIT_STATUS_INITIALIZED);
470 : 3537 : rtx_insn *insn = emit_debug_insn_before (bind, DF_REF_INSN (ref));
471 : 3537 : bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
472 : : }
473 : :
474 : 116148 : entry->dtemp = NULL;
475 : 116148 : XDELETE (head);
476 : : }
477 : 161850297 : }
478 : :
479 : : /* Reset all debug insns with pending uses. Release the bitmap in it,
480 : : unless it is USED. USED must be the same bitmap passed to
481 : : dead_debug_local_init. */
482 : :
483 : : void
484 : 360618199 : dead_debug_local_finish (struct dead_debug_local *debug, bitmap used)
485 : : {
486 : 360618199 : if (debug->global)
487 : 161850297 : dead_debug_promote_uses (debug);
488 : :
489 : 360618199 : if (debug->used != used)
490 : 3077381 : BITMAP_FREE (debug->used);
491 : :
492 : 360618199 : dead_debug_reset_uses (debug, debug->head);
493 : :
494 : 360618199 : if (debug->to_rescan)
495 : : {
496 : 202337 : bitmap_iterator bi;
497 : 202337 : unsigned int uid;
498 : :
499 : 1544217 : EXECUTE_IF_SET_IN_BITMAP (debug->to_rescan, 0, uid, bi)
500 : : {
501 : 2683760 : struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
502 : 1341880 : if (insn_info)
503 : 1341880 : df_insn_rescan (insn_info->insn);
504 : : }
505 : 202337 : BITMAP_FREE (debug->to_rescan);
506 : : }
507 : 360618199 : }
508 : :
509 : : /* Release GLOBAL->used unless it is the same as USED. Release the
510 : : mapping hash table if it was initialized. */
511 : :
512 : : void
513 : 9623772 : dead_debug_global_finish (struct dead_debug_global *global, bitmap used)
514 : : {
515 : 9623772 : if (global->used != used)
516 : 63540 : BITMAP_FREE (global->used);
517 : :
518 : 9623772 : delete global->htab;
519 : 9623772 : global->htab = NULL;
520 : 9623772 : }
521 : :
522 : : /* Add USE to DEBUG, or substitute it right away if it's a pseudo in
523 : : the global substitution list. USE must be a dead reference to
524 : : UREGNO in a debug insn. Create a bitmap for DEBUG as needed. */
525 : :
526 : : void
527 : 494762 : dead_debug_add (struct dead_debug_local *debug, df_ref use, unsigned int uregno)
528 : : {
529 : 494762 : if (dead_debug_global_replace_temp (debug->global, use, uregno,
530 : : &debug->to_rescan))
531 : : return;
532 : :
533 : 494760 : struct dead_debug_use *newddu = XNEW (struct dead_debug_use);
534 : :
535 : 494760 : newddu->use = use;
536 : 494760 : newddu->next = debug->head;
537 : 494760 : debug->head = newddu;
538 : :
539 : 494760 : if (!debug->used)
540 : 243850 : debug->used = BITMAP_ALLOC (NULL);
541 : :
542 : : /* ??? If we dealt with split multi-registers below, we should set
543 : : all registers for the used mode in case of hardware
544 : : registers. */
545 : 494760 : bitmap_set_bit (debug->used, uregno);
546 : : }
547 : :
548 : : /* Like lowpart_subreg, but if a subreg is not valid for machine, force
549 : : it anyway - for use in debug insns. */
550 : :
551 : : static rtx
552 : 1936 : debug_lowpart_subreg (machine_mode outer_mode, rtx expr,
553 : : machine_mode inner_mode)
554 : : {
555 : 1936 : if (inner_mode == VOIDmode)
556 : 0 : inner_mode = GET_MODE (expr);
557 : 1936 : poly_int64 offset = subreg_lowpart_offset (outer_mode, inner_mode);
558 : 1936 : rtx ret = simplify_gen_subreg (outer_mode, expr, inner_mode, offset);
559 : 1936 : if (ret)
560 : : return ret;
561 : 5 : if (GET_MODE (expr) != VOIDmode)
562 : 3 : return gen_rtx_raw_SUBREG (outer_mode, expr, offset);
563 : : return NULL_RTX;
564 : : }
565 : :
566 : : /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
567 : : before or after INSN (depending on WHERE), that binds a (possibly
568 : : global) debug temp to the widest-mode use of UREGNO, if WHERE is
569 : : *_WITH_REG, or the value stored in UREGNO by INSN otherwise, and
570 : : replace all uses of UREGNO in DEBUG with uses of the debug temp.
571 : : INSN must be where UREGNO dies, if WHERE is *_BEFORE_*, or where it
572 : : is set otherwise. Return the number of debug insns emitted. */
573 : :
574 : : int
575 : 884195365 : dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
576 : : rtx_insn *insn, enum debug_temp_where where)
577 : : {
578 : 884195365 : struct dead_debug_use **tailp = &debug->head;
579 : 884195365 : struct dead_debug_use *cur;
580 : 884195365 : struct dead_debug_use *uses = NULL;
581 : 884195365 : struct dead_debug_use **usesp = &uses;
582 : 884195365 : rtx reg = NULL_RTX;
583 : 884195365 : rtx breg;
584 : 884195365 : rtx dval = NULL_RTX;
585 : 884195365 : rtx bind;
586 : 884195365 : bool global;
587 : :
588 : 884195365 : if (!debug->used)
589 : : return 0;
590 : :
591 : 80253257 : global = (debug->global && debug->global->used
592 : 157436578 : && bitmap_bit_p (debug->global->used, uregno));
593 : :
594 : 79757285 : if (!global && !bitmap_clear_bit (debug->used, uregno))
595 : : return 0;
596 : :
597 : : /* Move all uses of uregno from debug->head to uses, setting mode to
598 : : the widest referenced mode. */
599 : 1062245 : while ((cur = *tailp))
600 : : {
601 : 466559 : if (DF_REF_REGNO (cur->use) == uregno)
602 : : {
603 : : /* If this loc has been changed e.g. to debug_expr already
604 : : as part of a multi-register use, just drop it. */
605 : 264914 : if (!REG_P (*DF_REF_REAL_LOC (cur->use)))
606 : : {
607 : 43768 : *tailp = cur->next;
608 : 43768 : XDELETE (cur);
609 : 43768 : continue;
610 : : }
611 : 221146 : *usesp = cur;
612 : 221146 : usesp = &cur->next;
613 : 221146 : *tailp = cur->next;
614 : 221146 : cur->next = NULL;
615 : : /* "may" rather than "must" because we want (for example)
616 : : N V4SFs to win over plain V4SF even though N might be 1. */
617 : 221146 : rtx candidate = *DF_REF_REAL_LOC (cur->use);
618 : 221146 : if (!reg
619 : 277074 : || maybe_lt (GET_MODE_BITSIZE (GET_MODE (reg)),
620 : 111856 : GET_MODE_BITSIZE (GET_MODE (candidate))))
621 : : reg = candidate;
622 : : }
623 : : else
624 : 201645 : tailp = &(*tailp)->next;
625 : : }
626 : :
627 : : /* We may have dangling bits in debug->used for registers that were part
628 : : of a multi-register use, one component of which has been reset. */
629 : 595686 : if (reg == NULL)
630 : : {
631 : 430468 : gcc_checking_assert (!uses);
632 : 430468 : if (!global)
633 : : return 0;
634 : : }
635 : :
636 : 165218 : if (global)
637 : : {
638 : 430404 : if (!reg)
639 : 430404 : reg = regno_reg_rtx[uregno];
640 : 430404 : dead_debug_global_entry *entry
641 : 430404 : = dead_debug_global_find (debug->global, reg);
642 : 430404 : gcc_checking_assert (entry->reg == reg);
643 : 430404 : dval = entry->dtemp;
644 : 430404 : if (!dval)
645 : : return 0;
646 : : }
647 : :
648 : 396713 : gcc_checking_assert (uses || global);
649 : :
650 : 396713 : breg = reg;
651 : : /* Recover the expression INSN stores in REG. */
652 : 396713 : if (where == DEBUG_TEMP_BEFORE_WITH_VALUE)
653 : : {
654 : 256203 : rtx set = single_set (insn);
655 : 256203 : rtx dest, src;
656 : :
657 : 256203 : if (set)
658 : : {
659 : 253477 : dest = SET_DEST (set);
660 : 253477 : src = SET_SRC (set);
661 : : /* Reset uses if the REG-setting insn is a CALL. Asm in
662 : : DEBUG_INSN is never useful, we can't emit debug info for
663 : : that. And for volatile_insn_p, it is actually harmful -
664 : : DEBUG_INSNs shouldn't have any side-effects. */
665 : 253476 : if (GET_CODE (src) == CALL || GET_CODE (src) == ASM_OPERANDS
666 : 506949 : || volatile_insn_p (src))
667 : : set = NULL_RTX;
668 : : }
669 : :
670 : : /* ??? Should we try to extract it from a PARALLEL? */
671 : 253472 : if (!set)
672 : : breg = NULL;
673 : : /* Cool, it's the same REG, we can use SRC. */
674 : 253472 : else if (dest == reg)
675 : 249944 : breg = cleanup_auto_inc_dec (src, VOIDmode);
676 : 3528 : else if (REG_P (dest))
677 : : {
678 : : /* Hmm... Something's fishy, we should be setting REG here. */
679 : 1692 : if (REGNO (dest) != REGNO (reg))
680 : : breg = NULL;
681 : : /* If we're not overwriting all the hardware registers that
682 : : setting REG in its mode would, we won't know what to bind
683 : : the debug temp to. ??? We could bind the debug_expr to a
684 : : CONCAT or PARALLEL with the split multi-registers, and
685 : : replace them as we found the corresponding sets. */
686 : 940 : else if (REG_NREGS (reg) != REG_NREGS (dest))
687 : : breg = NULL;
688 : : /* Ok, it's the same (hardware) REG, but with a different
689 : : mode, so SUBREG it. */
690 : : else
691 : 775 : breg = debug_lowpart_subreg (GET_MODE (reg),
692 : : cleanup_auto_inc_dec (src, VOIDmode),
693 : 775 : GET_MODE (dest));
694 : : }
695 : 1836 : else if (GET_CODE (dest) == SUBREG)
696 : : {
697 : : /* We should be setting REG here. Lose. */
698 : 1836 : if (REGNO (SUBREG_REG (dest)) != REGNO (reg))
699 : : breg = NULL;
700 : : /* Lose if we're setting something other than the lowpart of
701 : : REG. */
702 : 1836 : else if (!subreg_lowpart_p (dest))
703 : : breg = NULL;
704 : : /* If we're not overwriting all the hardware registers that
705 : : setting REG in its mode would, we won't know what to bind
706 : : the debug temp to. */
707 : 995 : else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
708 : 995 : && (REG_NREGS (reg)
709 : 0 : != hard_regno_nregs (REGNO (reg), GET_MODE (dest))))
710 : : breg = NULL;
711 : : /* Yay, we can use SRC, just adjust its mode. */
712 : : else
713 : 995 : breg = debug_lowpart_subreg (GET_MODE (reg),
714 : : cleanup_auto_inc_dec (src, VOIDmode),
715 : 995 : GET_MODE (dest));
716 : : }
717 : : /* Oh well, we're out of luck. */
718 : : else
719 : : breg = NULL;
720 : :
721 : : /* We couldn't figure out the value stored in REG, so reset all
722 : : of its pending debug uses. */
723 : 251714 : if (!breg)
724 : : {
725 : 4491 : dead_debug_reset_uses (debug, uses);
726 : 4491 : return 0;
727 : : }
728 : : }
729 : :
730 : : /* If there's a single (debug) use of an otherwise unused REG, and
731 : : the debug use is not part of a larger expression, then it
732 : : probably doesn't make sense to introduce a new debug temp. */
733 : 392222 : if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
734 : : {
735 : 32342 : rtx_insn *next = DF_REF_INSN (uses->use);
736 : :
737 : 32342 : if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
738 : : {
739 : 30232 : XDELETE (uses);
740 : 30232 : return 0;
741 : : }
742 : : }
743 : :
744 : 361990 : if (!global)
745 : : /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */
746 : 134032 : dval = make_debug_expr_from_rtl (reg);
747 : :
748 : : /* Emit a debug bind insn before the insn in which reg dies. */
749 : 361990 : bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
750 : : DEBUG_EXPR_TREE_DECL (dval), breg,
751 : : VAR_INIT_STATUS_INITIALIZED);
752 : :
753 : 361990 : if (where == DEBUG_TEMP_AFTER_WITH_REG
754 : 361990 : || where == DEBUG_TEMP_AFTER_WITH_REG_FORCE)
755 : 95810 : bind = emit_debug_insn_after (bind, insn);
756 : : else
757 : 266180 : bind = emit_debug_insn_before (bind, insn);
758 : 361990 : if (debug->to_rescan == NULL)
759 : 102979 : debug->to_rescan = BITMAP_ALLOC (NULL);
760 : 361990 : bitmap_set_bit (debug->to_rescan, INSN_UID (bind));
761 : :
762 : : /* Adjust all uses. */
763 : 913872 : while ((cur = uses))
764 : : {
765 : 189892 : if (GET_MODE (*DF_REF_REAL_LOC (cur->use)) == GET_MODE (reg))
766 : 189726 : *DF_REF_REAL_LOC (cur->use) = dval;
767 : : else
768 : 166 : *DF_REF_REAL_LOC (cur->use)
769 : 166 : = debug_lowpart_subreg (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval,
770 : 166 : GET_MODE (dval));
771 : : /* ??? Should we simplify subreg of subreg? */
772 : 189892 : bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
773 : 189892 : uses = cur->next;
774 : 189892 : XDELETE (cur);
775 : : }
776 : :
777 : : return 1;
778 : : }
|