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