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