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