]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/var-tracking.c
alias.c: Use REG_P...
[thirdparty/gcc.git] / gcc / var-tracking.c
CommitLineData
014a1138 1/* Variable tracking routines for the GNU compiler.
32e8bb8e 2 Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009
66647d44 3 Free Software Foundation, Inc.
014a1138
JZ
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9dcd6f09 9 the Free Software Foundation; either version 3, or (at your option)
014a1138
JZ
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
9dcd6f09
NC
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
014a1138
JZ
20
21/* This file contains the variable tracking pass. It computes where
22 variables are located (which registers or where in memory) at each position
23 in instruction stream and emits notes describing the locations.
24 Debug information (DWARF2 location lists) is finally generated from
25 these notes.
26 With this debug information, it is possible to show variables
27 even when debugging optimized code.
28
29 How does the variable tracking pass work?
30
31 First, it scans RTL code for uses, stores and clobbers (register/memory
32 references in instructions), for call insns and for stack adjustments
33 separately for each basic block and saves them to an array of micro
34 operations.
35 The micro operations of one instruction are ordered so that
36 pre-modifying stack adjustment < use < use with no var < call insn <
37 < set < clobber < post-modifying stack adjustment
38
39 Then, a forward dataflow analysis is performed to find out how locations
40 of variables change through code and to propagate the variable locations
41 along control flow graph.
42 The IN set for basic block BB is computed as a union of OUT sets of BB's
43 predecessors, the OUT set for BB is copied from the IN set for BB and
44 is changed according to micro operations in BB.
45
46 The IN and OUT sets for basic blocks consist of a current stack adjustment
47 (used for adjusting offset of variables addressed using stack pointer),
48 the table of structures describing the locations of parts of a variable
49 and for each physical register a linked list for each physical register.
50 The linked list is a list of variable parts stored in the register,
51 i.e. it is a list of triplets (reg, decl, offset) where decl is
52 REG_EXPR (reg) and offset is REG_OFFSET (reg). The linked list is used for
53 effective deleting appropriate variable parts when we set or clobber the
54 register.
55
56 There may be more than one variable part in a register. The linked lists
57 should be pretty short so it is a good data structure here.
58 For example in the following code, register allocator may assign same
59 register to variables A and B, and both of them are stored in the same
60 register in CODE:
61
62 if (cond)
63 set A;
64 else
65 set B;
66 CODE;
67 if (cond)
68 use A;
69 else
70 use B;
71
72 Finally, the NOTE_INSN_VAR_LOCATION notes describing the variable locations
73 are emitted to appropriate positions in RTL code. Each such a note describes
74 the location of one variable at the point in instruction stream where the
75 note is. There is no need to emit a note for each variable before each
76 instruction, we only emit these notes where the location of variable changes
77 (this means that we also emit notes for changes between the OUT set of the
78 previous block and the IN set of the current block).
79
80 The notes consist of two parts:
81 1. the declaration (from REG_EXPR or MEM_EXPR)
82 2. the location of a variable - it is either a simple register/memory
83 reference (for simple variables, for example int),
84 or a parallel of register/memory references (for a large variables
85 which consist of several parts, for example long long).
86
87*/
88
89#include "config.h"
90#include "system.h"
91#include "coretypes.h"
92#include "tm.h"
93#include "rtl.h"
94#include "tree.h"
95#include "hard-reg-set.h"
96#include "basic-block.h"
97#include "flags.h"
98#include "output.h"
99#include "insn-config.h"
100#include "reload.h"
101#include "sbitmap.h"
102#include "alloc-pool.h"
103#include "fibheap.h"
104#include "hashtab.h"
c938250d
JJ
105#include "regs.h"
106#include "expr.h"
ef330312
PB
107#include "timevar.h"
108#include "tree-pass.h"
014a1138
JZ
109
110/* Type of micro operation. */
111enum micro_operation_type
112{
113 MO_USE, /* Use location (REG or MEM). */
114 MO_USE_NO_VAR,/* Use location which is not associated with a variable
115 or the variable is not trackable. */
116 MO_SET, /* Set location. */
ca787200 117 MO_COPY, /* Copy the same portion of a variable from one
96ff6c8c 118 location to another. */
014a1138
JZ
119 MO_CLOBBER, /* Clobber location. */
120 MO_CALL, /* Call insn. */
9ac97460 121 MO_ADJUST /* Adjust stack pointer. */
014a1138
JZ
122};
123
124/* Where shall the note be emitted? BEFORE or AFTER the instruction. */
125enum emit_note_where
126{
127 EMIT_NOTE_BEFORE_INSN,
128 EMIT_NOTE_AFTER_INSN
129};
130
131/* Structure holding information about micro operation. */
132typedef struct micro_operation_def
133{
134 /* Type of micro operation. */
135 enum micro_operation_type type;
136
137 union {
94a7682d
RS
138 /* Location. For MO_SET and MO_COPY, this is the SET that performs
139 the assignment, if known, otherwise it is the target of the
140 assignment. */
014a1138
JZ
141 rtx loc;
142
143 /* Stack adjustment. */
144 HOST_WIDE_INT adjust;
145 } u;
146
dedc1e6d
AO
147 /* The instruction which the micro operation is in, for MO_USE,
148 MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
149 instruction or note in the original flow (before any var-tracking
150 notes are inserted, to simplify emission of notes), for MO_SET
151 and MO_CLOBBER. */
014a1138
JZ
152 rtx insn;
153} micro_operation;
154
155/* Structure for passing some other parameters to function
156 emit_note_insn_var_location. */
157typedef struct emit_note_data_def
158{
159 /* The instruction which the note will be emitted before/after. */
160 rtx insn;
161
162 /* Where the note will be emitted (before/after insn)? */
163 enum emit_note_where where;
164} emit_note_data;
165
166/* Description of location of a part of a variable. The content of a physical
167 register is described by a chain of these structures.
168 The chains are pretty short (usually 1 or 2 elements) and thus
169 chain is the best data structure. */
170typedef struct attrs_def
171{
172 /* Pointer to next member of the list. */
173 struct attrs_def *next;
174
175 /* The rtx of register. */
176 rtx loc;
177
178 /* The declaration corresponding to LOC. */
179 tree decl;
180
181 /* Offset from start of DECL. */
182 HOST_WIDE_INT offset;
183} *attrs;
184
d24686d7
JJ
185/* Structure holding a refcounted hash table. If refcount > 1,
186 it must be first unshared before modified. */
187typedef struct shared_hash_def
188{
189 /* Reference count. */
190 int refcount;
191
192 /* Actual hash table. */
193 htab_t htab;
194} *shared_hash;
195
014a1138
JZ
196/* Structure holding the IN or OUT set for a basic block. */
197typedef struct dataflow_set_def
198{
199 /* Adjustment of stack offset. */
200 HOST_WIDE_INT stack_adjust;
201
202 /* Attributes for registers (lists of attrs). */
203 attrs regs[FIRST_PSEUDO_REGISTER];
204
205 /* Variable locations. */
d24686d7 206 shared_hash vars;
014a1138
JZ
207} dataflow_set;
208
209/* The structure (one for each basic block) containing the information
210 needed for variable tracking. */
211typedef struct variable_tracking_info_def
212{
213 /* Number of micro operations stored in the MOS array. */
214 int n_mos;
215
216 /* The array of micro operations. */
217 micro_operation *mos;
218
219 /* The IN and OUT set for dataflow analysis. */
220 dataflow_set in;
221 dataflow_set out;
222
223 /* Has the block been visited in DFS? */
224 bool visited;
225} *variable_tracking_info;
226
227/* Structure for chaining the locations. */
228typedef struct location_chain_def
229{
230 /* Next element in the chain. */
231 struct location_chain_def *next;
232
233 /* The location (REG or MEM). */
234 rtx loc;
62760ffd
CT
235
236 /* The "value" stored in this location. */
237 rtx set_src;
238
239 /* Initialized? */
240 enum var_init_status init;
014a1138
JZ
241} *location_chain;
242
243/* Structure describing one part of variable. */
244typedef struct variable_part_def
245{
246 /* Chain of locations of the part. */
247 location_chain loc_chain;
248
249 /* Location which was last emitted to location list. */
250 rtx cur_loc;
251
252 /* The offset in the variable. */
253 HOST_WIDE_INT offset;
254} variable_part;
255
256/* Maximum number of location parts. */
257#define MAX_VAR_PARTS 16
258
259/* Structure describing where the variable is located. */
260typedef struct variable_def
261{
262 /* The declaration of the variable. */
263 tree decl;
264
81f2eadb
JZ
265 /* Reference count. */
266 int refcount;
267
014a1138
JZ
268 /* Number of variable parts. */
269 int n_var_parts;
270
271 /* The variable parts. */
272 variable_part var_part[MAX_VAR_PARTS];
273} *variable;
741ac903 274typedef const struct variable_def *const_variable;
014a1138
JZ
275
276/* Hash function for DECL for VARIABLE_HTAB. */
ac3bfd86 277#define VARIABLE_HASH_VAL(decl) (DECL_UID (decl))
014a1138
JZ
278
279/* Pointer to the BB's information specific to variable tracking pass. */
280#define VTI(BB) ((variable_tracking_info) (BB)->aux)
281
8c6c36a3
EB
282/* Macro to access MEM_OFFSET as an HOST_WIDE_INT. Evaluates MEM twice. */
283#define INT_MEM_OFFSET(mem) (MEM_OFFSET (mem) ? INTVAL (MEM_OFFSET (mem)) : 0)
284
014a1138
JZ
285/* Alloc pool for struct attrs_def. */
286static alloc_pool attrs_pool;
287
288/* Alloc pool for struct variable_def. */
289static alloc_pool var_pool;
290
291/* Alloc pool for struct location_chain_def. */
292static alloc_pool loc_chain_pool;
293
d24686d7
JJ
294/* Alloc pool for struct shared_hash_def. */
295static alloc_pool shared_hash_pool;
296
014a1138
JZ
297/* Changed variables, notes will be emitted for them. */
298static htab_t changed_variables;
299
300/* Shall notes be emitted? */
301static bool emit_notes;
302
d24686d7
JJ
303/* Empty shared hashtable. */
304static shared_hash empty_shared_hash;
305
014a1138
JZ
306/* Local function prototypes. */
307static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
308 HOST_WIDE_INT *);
309static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
310 HOST_WIDE_INT *);
311static void bb_stack_adjust_offset (basic_block);
014a1138
JZ
312static bool vt_stack_adjustments (void);
313static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
314static hashval_t variable_htab_hash (const void *);
315static int variable_htab_eq (const void *, const void *);
316static void variable_htab_free (void *);
317
318static void init_attrs_list_set (attrs *);
319static void attrs_list_clear (attrs *);
320static attrs attrs_list_member (attrs, tree, HOST_WIDE_INT);
321static void attrs_list_insert (attrs *, tree, HOST_WIDE_INT, rtx);
322static void attrs_list_copy (attrs *, attrs);
323static void attrs_list_union (attrs *, attrs);
324
62760ffd
CT
325static variable unshare_variable (dataflow_set *set, variable var,
326 enum var_init_status);
014a1138
JZ
327static int vars_copy_1 (void **, void *);
328static void vars_copy (htab_t, htab_t);
ca787200 329static tree var_debug_decl (tree);
62760ffd
CT
330static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
331static void var_reg_delete_and_set (dataflow_set *, rtx, bool,
332 enum var_init_status, rtx);
ca787200 333static void var_reg_delete (dataflow_set *, rtx, bool);
014a1138 334static void var_regno_delete (dataflow_set *, int);
62760ffd
CT
335static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx);
336static void var_mem_delete_and_set (dataflow_set *, rtx, bool,
337 enum var_init_status, rtx);
ca787200 338static void var_mem_delete (dataflow_set *, rtx, bool);
014a1138 339
d24686d7 340static void dataflow_set_init (dataflow_set *);
014a1138
JZ
341static void dataflow_set_clear (dataflow_set *);
342static void dataflow_set_copy (dataflow_set *, dataflow_set *);
343static int variable_union_info_cmp_pos (const void *, const void *);
344static int variable_union (void **, void *);
d24686d7 345static int variable_canonicalize (void **, void *);
014a1138
JZ
346static void dataflow_set_union (dataflow_set *, dataflow_set *);
347static bool variable_part_different_p (variable_part *, variable_part *);
83532fb7 348static bool variable_different_p (variable, variable, bool);
014a1138
JZ
349static int dataflow_set_different_1 (void **, void *);
350static int dataflow_set_different_2 (void **, void *);
351static bool dataflow_set_different (dataflow_set *, dataflow_set *);
352static void dataflow_set_destroy (dataflow_set *);
353
354static bool contains_symbol_ref (rtx);
355static bool track_expr_p (tree);
ca787200 356static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
014a1138
JZ
357static int count_uses (rtx *, void *);
358static void count_uses_1 (rtx *, void *);
7bc980e1 359static void count_stores (rtx, const_rtx, void *);
014a1138
JZ
360static int add_uses (rtx *, void *);
361static void add_uses_1 (rtx *, void *);
7bc980e1 362static void add_stores (rtx, const_rtx, void *);
014a1138
JZ
363static bool compute_bb_dataflow (basic_block);
364static void vt_find_locations (void);
365
366static void dump_attrs_list (attrs);
367static int dump_variable (void **, void *);
368static void dump_vars (htab_t);
369static void dump_dataflow_set (dataflow_set *);
370static void dump_dataflow_sets (void);
371
d24686d7 372static void variable_was_changed (variable, dataflow_set *);
62760ffd
CT
373static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
374 enum var_init_status, rtx);
375static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
376 rtx);
014a1138
JZ
377static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
378static int emit_note_insn_var_location (void **, void *);
379static void emit_notes_for_changes (rtx, enum emit_note_where);
380static int emit_notes_for_differences_1 (void **, void *);
381static int emit_notes_for_differences_2 (void **, void *);
382static void emit_notes_for_differences (rtx, dataflow_set *, dataflow_set *);
383static void emit_notes_in_bb (basic_block);
384static void vt_emit_notes (void);
385
386static bool vt_get_decl_and_offset (rtx, tree *, HOST_WIDE_INT *);
387static void vt_add_function_parameters (void);
388static void vt_initialize (void);
389static void vt_finalize (void);
390
391/* Given a SET, calculate the amount of stack adjustment it contains
392 PRE- and POST-modifying stack pointer.
393 This function is similar to stack_adjust_offset. */
394
395static void
396stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INT *pre,
397 HOST_WIDE_INT *post)
398{
399 rtx src = SET_SRC (pattern);
400 rtx dest = SET_DEST (pattern);
401 enum rtx_code code;
402
403 if (dest == stack_pointer_rtx)
404 {
405 /* (set (reg sp) (plus (reg sp) (const_int))) */
406 code = GET_CODE (src);
407 if (! (code == PLUS || code == MINUS)
408 || XEXP (src, 0) != stack_pointer_rtx
481683e1 409 || !CONST_INT_P (XEXP (src, 1)))
014a1138
JZ
410 return;
411
412 if (code == MINUS)
413 *post += INTVAL (XEXP (src, 1));
414 else
415 *post -= INTVAL (XEXP (src, 1));
416 }
3c0cb5de 417 else if (MEM_P (dest))
014a1138
JZ
418 {
419 /* (set (mem (pre_dec (reg sp))) (foo)) */
420 src = XEXP (dest, 0);
421 code = GET_CODE (src);
422
423 switch (code)
424 {
425 case PRE_MODIFY:
426 case POST_MODIFY:
427 if (XEXP (src, 0) == stack_pointer_rtx)
428 {
429 rtx val = XEXP (XEXP (src, 1), 1);
430 /* We handle only adjustments by constant amount. */
fbc848cc 431 gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS &&
481683e1 432 CONST_INT_P (val));
fbc848cc 433
014a1138
JZ
434 if (code == PRE_MODIFY)
435 *pre -= INTVAL (val);
436 else
437 *post -= INTVAL (val);
438 break;
439 }
440 return;
441
442 case PRE_DEC:
443 if (XEXP (src, 0) == stack_pointer_rtx)
444 {
445 *pre += GET_MODE_SIZE (GET_MODE (dest));
446 break;
447 }
448 return;
449
450 case POST_DEC:
451 if (XEXP (src, 0) == stack_pointer_rtx)
452 {
453 *post += GET_MODE_SIZE (GET_MODE (dest));
454 break;
455 }
456 return;
457
458 case PRE_INC:
459 if (XEXP (src, 0) == stack_pointer_rtx)
460 {
461 *pre -= GET_MODE_SIZE (GET_MODE (dest));
462 break;
463 }
464 return;
465
466 case POST_INC:
467 if (XEXP (src, 0) == stack_pointer_rtx)
468 {
469 *post -= GET_MODE_SIZE (GET_MODE (dest));
470 break;
471 }
472 return;
473
474 default:
475 return;
476 }
477 }
478}
479
480/* Given an INSN, calculate the amount of stack adjustment it contains
481 PRE- and POST-modifying stack pointer. */
482
483static void
484insn_stack_adjust_offset_pre_post (rtx insn, HOST_WIDE_INT *pre,
485 HOST_WIDE_INT *post)
486{
7d407433
BW
487 rtx pattern;
488
014a1138
JZ
489 *pre = 0;
490 *post = 0;
491
7d407433
BW
492 pattern = PATTERN (insn);
493 if (RTX_FRAME_RELATED_P (insn))
494 {
495 rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
496 if (expr)
497 pattern = XEXP (expr, 0);
498 }
499
500 if (GET_CODE (pattern) == SET)
501 stack_adjust_offset_pre_post (pattern, pre, post);
502 else if (GET_CODE (pattern) == PARALLEL
503 || GET_CODE (pattern) == SEQUENCE)
014a1138
JZ
504 {
505 int i;
506
507 /* There may be stack adjustments inside compound insns. Search
508 for them. */
7d407433
BW
509 for ( i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
510 if (GET_CODE (XVECEXP (pattern, 0, i)) == SET)
511 stack_adjust_offset_pre_post (XVECEXP (pattern, 0, i), pre, post);
014a1138
JZ
512 }
513}
514
fb0840fc 515/* Compute stack adjustment in basic block BB. */
014a1138
JZ
516
517static void
518bb_stack_adjust_offset (basic_block bb)
519{
520 HOST_WIDE_INT offset;
521 int i;
522
523 offset = VTI (bb)->in.stack_adjust;
524 for (i = 0; i < VTI (bb)->n_mos; i++)
525 {
526 if (VTI (bb)->mos[i].type == MO_ADJUST)
527 offset += VTI (bb)->mos[i].u.adjust;
528 else if (VTI (bb)->mos[i].type != MO_CALL)
529 {
3c0cb5de 530 if (MEM_P (VTI (bb)->mos[i].u.loc))
014a1138
JZ
531 {
532 VTI (bb)->mos[i].u.loc
533 = adjust_stack_reference (VTI (bb)->mos[i].u.loc, -offset);
534 }
535 }
536 }
537 VTI (bb)->out.stack_adjust = offset;
538}
539
014a1138
JZ
540/* Compute stack adjustments for all blocks by traversing DFS tree.
541 Return true when the adjustments on all incoming edges are consistent.
f91a0beb 542 Heavily borrowed from pre_and_rev_post_order_compute. */
014a1138
JZ
543
544static bool
545vt_stack_adjustments (void)
546{
628f6a4e 547 edge_iterator *stack;
014a1138
JZ
548 int sp;
549
fb0840fc 550 /* Initialize entry block. */
014a1138 551 VTI (ENTRY_BLOCK_PTR)->visited = true;
30e6f306 552 VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
014a1138
JZ
553
554 /* Allocate stack for back-tracking up CFG. */
5ed6ace5 555 stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
014a1138
JZ
556 sp = 0;
557
558 /* Push the first edge on to the stack. */
628f6a4e 559 stack[sp++] = ei_start (ENTRY_BLOCK_PTR->succs);
014a1138
JZ
560
561 while (sp)
562 {
628f6a4e 563 edge_iterator ei;
014a1138
JZ
564 basic_block src;
565 basic_block dest;
566
567 /* Look at the edge on the top of the stack. */
628f6a4e
BE
568 ei = stack[sp - 1];
569 src = ei_edge (ei)->src;
570 dest = ei_edge (ei)->dest;
014a1138
JZ
571
572 /* Check if the edge destination has been visited yet. */
573 if (!VTI (dest)->visited)
574 {
575 VTI (dest)->visited = true;
576 VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
577 bb_stack_adjust_offset (dest);
578
628f6a4e 579 if (EDGE_COUNT (dest->succs) > 0)
014a1138
JZ
580 /* Since the DEST node has been visited for the first
581 time, check its successors. */
628f6a4e 582 stack[sp++] = ei_start (dest->succs);
014a1138
JZ
583 }
584 else
585 {
586 /* Check whether the adjustments on the edges are the same. */
587 if (VTI (dest)->in.stack_adjust != VTI (src)->out.stack_adjust)
588 {
589 free (stack);
590 return false;
591 }
592
628f6a4e 593 if (! ei_one_before_end_p (ei))
014a1138 594 /* Go to the next edge. */
628f6a4e 595 ei_next (&stack[sp - 1]);
014a1138
JZ
596 else
597 /* Return to previous level if there are no more edges. */
598 sp--;
599 }
600 }
601
602 free (stack);
603 return true;
604}
605
30e6f306
RH
606/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
607 to the argument pointer. Return the new rtx. */
014a1138
JZ
608
609static rtx
610adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
611{
30e6f306 612 rtx addr, cfa, tmp;
014a1138 613
f6672e8e
RH
614#ifdef FRAME_POINTER_CFA_OFFSET
615 adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
616 cfa = plus_constant (frame_pointer_rtx, adjustment);
617#else
30e6f306
RH
618 adjustment -= ARG_POINTER_CFA_OFFSET (current_function_decl);
619 cfa = plus_constant (arg_pointer_rtx, adjustment);
f6672e8e 620#endif
feb61729 621
30e6f306
RH
622 addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
623 tmp = simplify_rtx (addr);
014a1138 624 if (tmp)
30e6f306 625 addr = tmp;
014a1138 626
30e6f306 627 return replace_equiv_address_nv (mem, addr);
014a1138
JZ
628}
629
630/* The hash function for variable_htab, computes the hash value
631 from the declaration of variable X. */
632
633static hashval_t
634variable_htab_hash (const void *x)
635{
741ac903 636 const_variable const v = (const_variable) x;
014a1138
JZ
637
638 return (VARIABLE_HASH_VAL (v->decl));
639}
640
641/* Compare the declaration of variable X with declaration Y. */
642
643static int
644variable_htab_eq (const void *x, const void *y)
645{
741ac903
KG
646 const_variable const v = (const_variable) x;
647 const_tree const decl = (const_tree) y;
014a1138
JZ
648
649 return (VARIABLE_HASH_VAL (v->decl) == VARIABLE_HASH_VAL (decl));
650}
651
652/* Free the element of VARIABLE_HTAB (its type is struct variable_def). */
653
654static void
655variable_htab_free (void *elem)
656{
657 int i;
658 variable var = (variable) elem;
659 location_chain node, next;
660
fbc848cc 661 gcc_assert (var->refcount > 0);
81f2eadb
JZ
662
663 var->refcount--;
664 if (var->refcount > 0)
665 return;
666
014a1138
JZ
667 for (i = 0; i < var->n_var_parts; i++)
668 {
669 for (node = var->var_part[i].loc_chain; node; node = next)
670 {
671 next = node->next;
672 pool_free (loc_chain_pool, node);
673 }
674 var->var_part[i].loc_chain = NULL;
675 }
676 pool_free (var_pool, var);
677}
678
679/* Initialize the set (array) SET of attrs to empty lists. */
680
681static void
682init_attrs_list_set (attrs *set)
683{
684 int i;
685
686 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
687 set[i] = NULL;
688}
689
690/* Make the list *LISTP empty. */
691
692static void
693attrs_list_clear (attrs *listp)
694{
695 attrs list, next;
696
697 for (list = *listp; list; list = next)
698 {
699 next = list->next;
700 pool_free (attrs_pool, list);
701 }
702 *listp = NULL;
703}
704
705/* Return true if the pair of DECL and OFFSET is the member of the LIST. */
706
707static attrs
708attrs_list_member (attrs list, tree decl, HOST_WIDE_INT offset)
709{
710 for (; list; list = list->next)
711 if (list->decl == decl && list->offset == offset)
712 return list;
713 return NULL;
714}
715
716/* Insert the triplet DECL, OFFSET, LOC to the list *LISTP. */
717
718static void
719attrs_list_insert (attrs *listp, tree decl, HOST_WIDE_INT offset, rtx loc)
720{
721 attrs list;
722
3d9a9f94 723 list = (attrs) pool_alloc (attrs_pool);
014a1138
JZ
724 list->loc = loc;
725 list->decl = decl;
726 list->offset = offset;
727 list->next = *listp;
728 *listp = list;
729}
730
731/* Copy all nodes from SRC and create a list *DSTP of the copies. */
732
733static void
734attrs_list_copy (attrs *dstp, attrs src)
735{
736 attrs n;
737
738 attrs_list_clear (dstp);
739 for (; src; src = src->next)
740 {
3d9a9f94 741 n = (attrs) pool_alloc (attrs_pool);
014a1138
JZ
742 n->loc = src->loc;
743 n->decl = src->decl;
744 n->offset = src->offset;
745 n->next = *dstp;
746 *dstp = n;
747 }
748}
749
750/* Add all nodes from SRC which are not in *DSTP to *DSTP. */
751
752static void
753attrs_list_union (attrs *dstp, attrs src)
754{
755 for (; src; src = src->next)
756 {
757 if (!attrs_list_member (*dstp, src->decl, src->offset))
758 attrs_list_insert (dstp, src->decl, src->offset, src->loc);
759 }
760}
761
d24686d7
JJ
762/* Shared hashtable support. */
763
764/* Return true if VARS is shared. */
765
766static inline bool
767shared_hash_shared (shared_hash vars)
768{
769 return vars->refcount > 1;
770}
771
772/* Return the hash table for VARS. */
773
774static inline htab_t
775shared_hash_htab (shared_hash vars)
776{
777 return vars->htab;
778}
779
780/* Copy variables into a new hash table. */
781
782static shared_hash
783shared_hash_unshare (shared_hash vars)
784{
785 shared_hash new_vars = (shared_hash) pool_alloc (shared_hash_pool);
786 gcc_assert (vars->refcount > 1);
787 new_vars->refcount = 1;
788 new_vars->htab
789 = htab_create (htab_elements (vars->htab) + 3, variable_htab_hash,
790 variable_htab_eq, variable_htab_free);
791 vars_copy (new_vars->htab, vars->htab);
792 vars->refcount--;
793 return new_vars;
794}
795
796/* Increment reference counter on VARS and return it. */
797
798static inline shared_hash
799shared_hash_copy (shared_hash vars)
800{
801 vars->refcount++;
802 return vars;
803}
804
805/* Decrement reference counter and destroy hash table if not shared
806 anymore. */
014a1138
JZ
807
808static void
d24686d7 809shared_hash_destroy (shared_hash vars)
014a1138 810{
d24686d7
JJ
811 gcc_assert (vars->refcount > 0);
812 if (--vars->refcount == 0)
813 {
814 htab_delete (vars->htab);
815 pool_free (shared_hash_pool, vars);
816 }
817}
818
819/* Unshare *PVARS if shared and return slot for DECL. If INS is
820 INSERT, insert it if not already present. */
821
822static inline void **
823shared_hash_find_slot_unshare (shared_hash *pvars, tree decl,
824 enum insert_option ins)
825{
826 if (shared_hash_shared (*pvars))
827 *pvars = shared_hash_unshare (*pvars);
828 return htab_find_slot_with_hash (shared_hash_htab (*pvars), decl,
829 VARIABLE_HASH_VAL (decl), ins);
830}
831
832/* Return slot for DECL, if it is already present in the hash table.
833 If it is not present, insert it only VARS is not shared, otherwise
834 return NULL. */
835
836static inline void **
837shared_hash_find_slot (shared_hash vars, tree decl)
838{
839 return htab_find_slot_with_hash (shared_hash_htab (vars), decl,
840 VARIABLE_HASH_VAL (decl),
841 shared_hash_shared (vars)
842 ? NO_INSERT : INSERT);
843}
844
845/* Return slot for DECL only if it is already present in the hash table. */
846
847static inline void **
848shared_hash_find_slot_noinsert (shared_hash vars, tree decl)
849{
850 return htab_find_slot_with_hash (shared_hash_htab (vars), decl,
851 VARIABLE_HASH_VAL (decl), NO_INSERT);
852}
853
854/* Return variable for DECL or NULL if not already present in the hash
855 table. */
856
857static inline variable
858shared_hash_find (shared_hash vars, tree decl)
859{
860 return (variable)
861 htab_find_with_hash (shared_hash_htab (vars), decl,
862 VARIABLE_HASH_VAL (decl));
014a1138
JZ
863}
864
81f2eadb 865/* Return a copy of a variable VAR and insert it to dataflow set SET. */
014a1138 866
81f2eadb 867static variable
62760ffd
CT
868unshare_variable (dataflow_set *set, variable var,
869 enum var_init_status initialized)
014a1138 870{
81f2eadb
JZ
871 void **slot;
872 variable new_var;
014a1138
JZ
873 int i;
874
3d9a9f94 875 new_var = (variable) pool_alloc (var_pool);
81f2eadb
JZ
876 new_var->decl = var->decl;
877 new_var->refcount = 1;
878 var->refcount--;
879 new_var->n_var_parts = var->n_var_parts;
014a1138
JZ
880
881 for (i = 0; i < var->n_var_parts; i++)
882 {
11599d14
JZ
883 location_chain node;
884 location_chain *nextp;
014a1138 885
81f2eadb
JZ
886 new_var->var_part[i].offset = var->var_part[i].offset;
887 nextp = &new_var->var_part[i].loc_chain;
888 for (node = var->var_part[i].loc_chain; node; node = node->next)
014a1138
JZ
889 {
890 location_chain new_lc;
891
3d9a9f94 892 new_lc = (location_chain) pool_alloc (loc_chain_pool);
014a1138 893 new_lc->next = NULL;
62760ffd
CT
894 if (node->init > initialized)
895 new_lc->init = node->init;
896 else
897 new_lc->init = initialized;
898 if (node->set_src && !(MEM_P (node->set_src)))
899 new_lc->set_src = node->set_src;
900 else
901 new_lc->set_src = NULL;
014a1138
JZ
902 new_lc->loc = node->loc;
903
11599d14
JZ
904 *nextp = new_lc;
905 nextp = &new_lc->next;
014a1138
JZ
906 }
907
908 /* We are at the basic block boundary when copying variable description
909 so set the CUR_LOC to be the first element of the chain. */
81f2eadb
JZ
910 if (new_var->var_part[i].loc_chain)
911 new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
014a1138 912 else
81f2eadb 913 new_var->var_part[i].cur_loc = NULL;
014a1138
JZ
914 }
915
d24686d7 916 slot = shared_hash_find_slot_unshare (&set->vars, new_var->decl, INSERT);
81f2eadb
JZ
917 *slot = new_var;
918 return new_var;
919}
920
921/* Add a variable from *SLOT to hash table DATA and increase its reference
922 count. */
923
924static int
925vars_copy_1 (void **slot, void *data)
926{
927 htab_t dst = (htab_t) data;
928 variable src, *dstp;
929
930 src = *(variable *) slot;
931 src->refcount++;
932
933 dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
934 VARIABLE_HASH_VAL (src->decl),
935 INSERT);
936 *dstp = src;
937
014a1138
JZ
938 /* Continue traversing the hash table. */
939 return 1;
940}
941
942/* Copy all variables from hash table SRC to hash table DST. */
943
944static void
945vars_copy (htab_t dst, htab_t src)
946{
d24686d7 947 htab_traverse_noresize (src, vars_copy_1, dst);
014a1138
JZ
948}
949
ca787200
AO
950/* Map a decl to its main debug decl. */
951
952static inline tree
953var_debug_decl (tree decl)
954{
955 if (decl && DECL_P (decl)
956 && DECL_DEBUG_EXPR_IS_FROM (decl) && DECL_DEBUG_EXPR (decl)
957 && DECL_P (DECL_DEBUG_EXPR (decl)))
958 decl = DECL_DEBUG_EXPR (decl);
959
960 return decl;
961}
962
dedc1e6d
AO
963/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
964
965static void
62760ffd
CT
966var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
967 rtx set_src)
dedc1e6d
AO
968{
969 tree decl = REG_EXPR (loc);
970 HOST_WIDE_INT offset = REG_OFFSET (loc);
ca787200
AO
971 attrs node;
972
973 decl = var_debug_decl (decl);
dedc1e6d 974
ca787200
AO
975 for (node = set->regs[REGNO (loc)]; node; node = node->next)
976 if (node->decl == decl && node->offset == offset)
977 break;
978 if (!node)
dedc1e6d 979 attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
62760ffd
CT
980 set_variable_part (set, loc, decl, offset, initialized, set_src);
981}
982
32e8bb8e 983static enum var_init_status
62760ffd
CT
984get_init_value (dataflow_set *set, rtx loc, tree decl)
985{
62760ffd
CT
986 variable var;
987 int i;
32e8bb8e 988 enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN;
62760ffd
CT
989
990 if (! flag_var_tracking_uninit)
991 return VAR_INIT_STATUS_INITIALIZED;
992
d24686d7
JJ
993 var = shared_hash_find (set->vars, decl);
994 if (var)
62760ffd 995 {
62760ffd
CT
996 for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
997 {
998 location_chain nextp;
999 for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next)
1000 if (rtx_equal_p (nextp->loc, loc))
1001 {
1002 ret_val = nextp->init;
1003 break;
1004 }
1005 }
1006 }
1007
1008 return ret_val;
dedc1e6d
AO
1009}
1010
ca787200
AO
1011/* Delete current content of register LOC in dataflow set SET and set
1012 the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If
1013 MODIFY is true, any other live copies of the same variable part are
1014 also deleted from the dataflow set, otherwise the variable part is
1015 assumed to be copied from another location holding the same
1016 part. */
014a1138
JZ
1017
1018static void
62760ffd
CT
1019var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify,
1020 enum var_init_status initialized, rtx set_src)
014a1138 1021{
014a1138
JZ
1022 tree decl = REG_EXPR (loc);
1023 HOST_WIDE_INT offset = REG_OFFSET (loc);
11599d14
JZ
1024 attrs node, next;
1025 attrs *nextp;
014a1138 1026
ca787200
AO
1027 decl = var_debug_decl (decl);
1028
62760ffd
CT
1029 if (initialized == VAR_INIT_STATUS_UNKNOWN)
1030 initialized = get_init_value (set, loc, decl);
1031
11599d14
JZ
1032 nextp = &set->regs[REGNO (loc)];
1033 for (node = *nextp; node; node = next)
014a1138
JZ
1034 {
1035 next = node->next;
1036 if (node->decl != decl || node->offset != offset)
1037 {
1038 delete_variable_part (set, node->loc, node->decl, node->offset);
014a1138 1039 pool_free (attrs_pool, node);
11599d14 1040 *nextp = next;
014a1138
JZ
1041 }
1042 else
1043 {
1044 node->loc = loc;
11599d14 1045 nextp = &node->next;
014a1138
JZ
1046 }
1047 }
ca787200 1048 if (modify)
62760ffd
CT
1049 clobber_variable_part (set, loc, decl, offset, set_src);
1050 var_reg_set (set, loc, initialized, set_src);
014a1138
JZ
1051}
1052
ca787200
AO
1053/* Delete current content of register LOC in dataflow set SET. If
1054 CLOBBER is true, also delete any other live copies of the same
1055 variable part. */
014a1138
JZ
1056
1057static void
ca787200 1058var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
014a1138
JZ
1059{
1060 attrs *reg = &set->regs[REGNO (loc)];
1061 attrs node, next;
1062
ca787200
AO
1063 if (clobber)
1064 {
1065 tree decl = REG_EXPR (loc);
1066 HOST_WIDE_INT offset = REG_OFFSET (loc);
1067
1068 decl = var_debug_decl (decl);
1069
62760ffd 1070 clobber_variable_part (set, NULL, decl, offset, NULL);
ca787200
AO
1071 }
1072
014a1138
JZ
1073 for (node = *reg; node; node = next)
1074 {
1075 next = node->next;
1076 delete_variable_part (set, node->loc, node->decl, node->offset);
1077 pool_free (attrs_pool, node);
1078 }
1079 *reg = NULL;
1080}
1081
1082/* Delete content of register with number REGNO in dataflow set SET. */
1083
1084static void
1085var_regno_delete (dataflow_set *set, int regno)
1086{
1087 attrs *reg = &set->regs[regno];
1088 attrs node, next;
1089
1090 for (node = *reg; node; node = next)
1091 {
1092 next = node->next;
1093 delete_variable_part (set, node->loc, node->decl, node->offset);
1094 pool_free (attrs_pool, node);
1095 }
1096 *reg = NULL;
1097}
1098
dedc1e6d
AO
1099/* Set the location part of variable MEM_EXPR (LOC) in dataflow set
1100 SET to LOC.
014a1138
JZ
1101 Adjust the address first if it is stack pointer based. */
1102
1103static void
62760ffd
CT
1104var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
1105 rtx set_src)
014a1138
JZ
1106{
1107 tree decl = MEM_EXPR (loc);
8c6c36a3 1108 HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
014a1138 1109
ca787200
AO
1110 decl = var_debug_decl (decl);
1111
62760ffd 1112 set_variable_part (set, loc, decl, offset, initialized, set_src);
014a1138
JZ
1113}
1114
ca787200
AO
1115/* Delete and set the location part of variable MEM_EXPR (LOC) in
1116 dataflow set SET to LOC. If MODIFY is true, any other live copies
1117 of the same variable part are also deleted from the dataflow set,
1118 otherwise the variable part is assumed to be copied from another
1119 location holding the same part.
dedc1e6d
AO
1120 Adjust the address first if it is stack pointer based. */
1121
1122static void
62760ffd
CT
1123var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify,
1124 enum var_init_status initialized, rtx set_src)
dedc1e6d 1125{
ca787200 1126 tree decl = MEM_EXPR (loc);
8c6c36a3 1127 HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
ca787200
AO
1128
1129 decl = var_debug_decl (decl);
1130
62760ffd
CT
1131 if (initialized == VAR_INIT_STATUS_UNKNOWN)
1132 initialized = get_init_value (set, loc, decl);
1133
ca787200 1134 if (modify)
62760ffd
CT
1135 clobber_variable_part (set, NULL, decl, offset, set_src);
1136 var_mem_set (set, loc, initialized, set_src);
dedc1e6d
AO
1137}
1138
ca787200
AO
1139/* Delete the location part LOC from dataflow set SET. If CLOBBER is
1140 true, also delete any other live copies of the same variable part.
014a1138
JZ
1141 Adjust the address first if it is stack pointer based. */
1142
1143static void
ca787200 1144var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
014a1138
JZ
1145{
1146 tree decl = MEM_EXPR (loc);
8c6c36a3 1147 HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
014a1138 1148
ca787200
AO
1149 decl = var_debug_decl (decl);
1150 if (clobber)
62760ffd 1151 clobber_variable_part (set, NULL, decl, offset, NULL);
014a1138
JZ
1152 delete_variable_part (set, loc, decl, offset);
1153}
1154
1155/* Initialize dataflow set SET to be empty.
1156 VARS_SIZE is the initial size of hash table VARS. */
1157
1158static void
d24686d7 1159dataflow_set_init (dataflow_set *set)
014a1138
JZ
1160{
1161 init_attrs_list_set (set->regs);
d24686d7 1162 set->vars = shared_hash_copy (empty_shared_hash);
014a1138
JZ
1163 set->stack_adjust = 0;
1164}
1165
1166/* Delete the contents of dataflow set SET. */
1167
1168static void
1169dataflow_set_clear (dataflow_set *set)
1170{
1171 int i;
1172
1173 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1174 attrs_list_clear (&set->regs[i]);
1175
d24686d7
JJ
1176 shared_hash_destroy (set->vars);
1177 set->vars = shared_hash_copy (empty_shared_hash);
014a1138
JZ
1178}
1179
1180/* Copy the contents of dataflow set SRC to DST. */
1181
1182static void
1183dataflow_set_copy (dataflow_set *dst, dataflow_set *src)
1184{
1185 int i;
1186
1187 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1188 attrs_list_copy (&dst->regs[i], src->regs[i]);
1189
d24686d7
JJ
1190 shared_hash_destroy (dst->vars);
1191 dst->vars = shared_hash_copy (src->vars);
014a1138
JZ
1192 dst->stack_adjust = src->stack_adjust;
1193}
1194
1195/* Information for merging lists of locations for a given offset of variable.
1196 */
1197struct variable_union_info
1198{
1199 /* Node of the location chain. */
1200 location_chain lc;
1201
1202 /* The sum of positions in the input chains. */
1203 int pos;
1204
1205 /* The position in the chains of SRC and DST dataflow sets. */
1206 int pos_src;
1207 int pos_dst;
1208};
1209
1210/* Compare function for qsort, order the structures by POS element. */
1211
1212static int
1213variable_union_info_cmp_pos (const void *n1, const void *n2)
1214{
3d9a9f94
KG
1215 const struct variable_union_info *const i1 =
1216 (const struct variable_union_info *) n1;
1217 const struct variable_union_info *const i2 =
1218 ( const struct variable_union_info *) n2;
014a1138
JZ
1219
1220 if (i1->pos != i2->pos)
1221 return i1->pos - i2->pos;
1222
1223 return (i1->pos_dst - i2->pos_dst);
1224}
1225
1226/* Compute union of location parts of variable *SLOT and the same variable
1227 from hash table DATA. Compute "sorted" union of the location chains
1228 for common offsets, i.e. the locations of a variable part are sorted by
1229 a priority where the priority is the sum of the positions in the 2 chains
1230 (if a location is only in one list the position in the second list is
1231 defined to be larger than the length of the chains).
1232 When we are updating the location parts the newest location is in the
1233 beginning of the chain, so when we do the described "sorted" union
1234 we keep the newest locations in the beginning. */
1235
1236static int
1237variable_union (void **slot, void *data)
1238{
d24686d7
JJ
1239 variable src, dst;
1240 void **dstp;
014a1138
JZ
1241 dataflow_set *set = (dataflow_set *) data;
1242 int i, j, k;
1243
1244 src = *(variable *) slot;
d24686d7
JJ
1245 dstp = shared_hash_find_slot (set->vars, src->decl);
1246 if (!dstp || !*dstp)
014a1138 1247 {
81f2eadb
JZ
1248 src->refcount++;
1249
1250 /* If CUR_LOC of some variable part is not the first element of
1251 the location chain we are going to change it so we have to make
1252 a copy of the variable. */
1253 for (k = 0; k < src->n_var_parts; k++)
1254 {
fbc848cc
NS
1255 gcc_assert (!src->var_part[k].loc_chain
1256 == !src->var_part[k].cur_loc);
81f2eadb
JZ
1257 if (src->var_part[k].loc_chain)
1258 {
fbc848cc 1259 gcc_assert (src->var_part[k].cur_loc);
81f2eadb
JZ
1260 if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
1261 break;
1262 }
81f2eadb
JZ
1263 }
1264 if (k < src->n_var_parts)
62760ffd
CT
1265 {
1266 enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
1267
1268 if (! flag_var_tracking_uninit)
1269 status = VAR_INIT_STATUS_INITIALIZED;
1270
d24686d7
JJ
1271 if (dstp)
1272 *dstp = (void *) src;
62760ffd
CT
1273 unshare_variable (set, src, status);
1274 }
81f2eadb 1275 else
d24686d7
JJ
1276 {
1277 if (!dstp)
1278 dstp = shared_hash_find_slot_unshare (&set->vars, src->decl,
1279 INSERT);
1280 *dstp = (void *) src;
1281 }
81f2eadb
JZ
1282
1283 /* Continue traversing the hash table. */
1284 return 1;
014a1138
JZ
1285 }
1286 else
d24686d7 1287 dst = (variable) *dstp;
014a1138 1288
fbc848cc 1289 gcc_assert (src->n_var_parts);
014a1138
JZ
1290
1291 /* Count the number of location parts, result is K. */
1292 for (i = 0, j = 0, k = 0;
1293 i < src->n_var_parts && j < dst->n_var_parts; k++)
1294 {
1295 if (src->var_part[i].offset == dst->var_part[j].offset)
1296 {
1297 i++;
1298 j++;
1299 }
1300 else if (src->var_part[i].offset < dst->var_part[j].offset)
1301 i++;
1302 else
1303 j++;
1304 }
81f2eadb
JZ
1305 k += src->n_var_parts - i;
1306 k += dst->n_var_parts - j;
fbc848cc 1307
014a1138
JZ
1308 /* We track only variables whose size is <= MAX_VAR_PARTS bytes
1309 thus there are at most MAX_VAR_PARTS different offsets. */
fbc848cc 1310 gcc_assert (k <= MAX_VAR_PARTS);
014a1138 1311
d24686d7
JJ
1312 if ((dst->refcount > 1 || shared_hash_shared (set->vars))
1313 && dst->n_var_parts != k)
62760ffd
CT
1314 {
1315 enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
1316
1317 if (! flag_var_tracking_uninit)
1318 status = VAR_INIT_STATUS_INITIALIZED;
1319 dst = unshare_variable (set, dst, status);
1320 }
81f2eadb 1321
014a1138
JZ
1322 i = src->n_var_parts - 1;
1323 j = dst->n_var_parts - 1;
1324 dst->n_var_parts = k;
1325
1326 for (k--; k >= 0; k--)
1327 {
81f2eadb 1328 location_chain node, node2;
014a1138
JZ
1329
1330 if (i >= 0 && j >= 0
1331 && src->var_part[i].offset == dst->var_part[j].offset)
1332 {
1333 /* Compute the "sorted" union of the chains, i.e. the locations which
1334 are in both chains go first, they are sorted by the sum of
1335 positions in the chains. */
1336 int dst_l, src_l;
1337 int ii, jj, n;
1338 struct variable_union_info *vui;
81f2eadb
JZ
1339
1340 /* If DST is shared compare the location chains.
1341 If they are different we will modify the chain in DST with
1342 high probability so make a copy of DST. */
d24686d7 1343 if (dst->refcount > 1 || shared_hash_shared (set->vars))
81f2eadb
JZ
1344 {
1345 for (node = src->var_part[i].loc_chain,
1346 node2 = dst->var_part[j].loc_chain; node && node2;
1347 node = node->next, node2 = node2->next)
1348 {
f8cfc6aa
JQ
1349 if (!((REG_P (node2->loc)
1350 && REG_P (node->loc)
81f2eadb
JZ
1351 && REGNO (node2->loc) == REGNO (node->loc))
1352 || rtx_equal_p (node2->loc, node->loc)))
e56f9152
MM
1353 {
1354 if (node2->init < node->init)
1355 node2->init = node->init;
1356 break;
1357 }
81f2eadb
JZ
1358 }
1359 if (node || node2)
62760ffd 1360 dst = unshare_variable (set, dst, VAR_INIT_STATUS_UNKNOWN);
81f2eadb
JZ
1361 }
1362
014a1138
JZ
1363 src_l = 0;
1364 for (node = src->var_part[i].loc_chain; node; node = node->next)
1365 src_l++;
1366 dst_l = 0;
1367 for (node = dst->var_part[j].loc_chain; node; node = node->next)
1368 dst_l++;
5ed6ace5 1369 vui = XCNEWVEC (struct variable_union_info, src_l + dst_l);
014a1138
JZ
1370
1371 /* Fill in the locations from DST. */
1372 for (node = dst->var_part[j].loc_chain, jj = 0; node;
1373 node = node->next, jj++)
1374 {
1375 vui[jj].lc = node;
1376 vui[jj].pos_dst = jj;
1377
1378 /* Value larger than a sum of 2 valid positions. */
1379 vui[jj].pos_src = src_l + dst_l;
1380 }
1381
1382 /* Fill in the locations from SRC. */
1383 n = dst_l;
1384 for (node = src->var_part[i].loc_chain, ii = 0; node;
1385 node = node->next, ii++)
1386 {
1387 /* Find location from NODE. */
1388 for (jj = 0; jj < dst_l; jj++)
1389 {
f8cfc6aa
JQ
1390 if ((REG_P (vui[jj].lc->loc)
1391 && REG_P (node->loc)
014a1138
JZ
1392 && REGNO (vui[jj].lc->loc) == REGNO (node->loc))
1393 || rtx_equal_p (vui[jj].lc->loc, node->loc))
1394 {
1395 vui[jj].pos_src = ii;
1396 break;
1397 }
1398 }
1399 if (jj >= dst_l) /* The location has not been found. */
1400 {
1401 location_chain new_node;
1402
1403 /* Copy the location from SRC. */
3d9a9f94 1404 new_node = (location_chain) pool_alloc (loc_chain_pool);
014a1138 1405 new_node->loc = node->loc;
62760ffd
CT
1406 new_node->init = node->init;
1407 if (!node->set_src || MEM_P (node->set_src))
1408 new_node->set_src = NULL;
1409 else
1410 new_node->set_src = node->set_src;
014a1138
JZ
1411 vui[n].lc = new_node;
1412 vui[n].pos_src = ii;
1413 vui[n].pos_dst = src_l + dst_l;
1414 n++;
1415 }
1416 }
1417
1418 for (ii = 0; ii < src_l + dst_l; ii++)
1419 vui[ii].pos = vui[ii].pos_src + vui[ii].pos_dst;
1420
1421 qsort (vui, n, sizeof (struct variable_union_info),
1422 variable_union_info_cmp_pos);
1423
1424 /* Reconnect the nodes in sorted order. */
1425 for (ii = 1; ii < n; ii++)
1426 vui[ii - 1].lc->next = vui[ii].lc;
1427 vui[n - 1].lc->next = NULL;
1428
1429 dst->var_part[k].loc_chain = vui[0].lc;
1430 dst->var_part[k].offset = dst->var_part[j].offset;
1431
1432 free (vui);
1433 i--;
1434 j--;
1435 }
1436 else if ((i >= 0 && j >= 0
1437 && src->var_part[i].offset < dst->var_part[j].offset)
1438 || i < 0)
1439 {
1440 dst->var_part[k] = dst->var_part[j];
1441 j--;
1442 }
1443 else if ((i >= 0 && j >= 0
1444 && src->var_part[i].offset > dst->var_part[j].offset)
1445 || j < 0)
1446 {
11599d14 1447 location_chain *nextp;
014a1138
JZ
1448
1449 /* Copy the chain from SRC. */
11599d14 1450 nextp = &dst->var_part[k].loc_chain;
014a1138
JZ
1451 for (node = src->var_part[i].loc_chain; node; node = node->next)
1452 {
1453 location_chain new_lc;
1454
3d9a9f94 1455 new_lc = (location_chain) pool_alloc (loc_chain_pool);
014a1138 1456 new_lc->next = NULL;
62760ffd
CT
1457 new_lc->init = node->init;
1458 if (!node->set_src || MEM_P (node->set_src))
1459 new_lc->set_src = NULL;
1460 else
1461 new_lc->set_src = node->set_src;
014a1138
JZ
1462 new_lc->loc = node->loc;
1463
11599d14
JZ
1464 *nextp = new_lc;
1465 nextp = &new_lc->next;
014a1138
JZ
1466 }
1467
1468 dst->var_part[k].offset = src->var_part[i].offset;
1469 i--;
1470 }
1471
1472 /* We are at the basic block boundary when computing union
1473 so set the CUR_LOC to be the first element of the chain. */
1474 if (dst->var_part[k].loc_chain)
1475 dst->var_part[k].cur_loc = dst->var_part[k].loc_chain->loc;
1476 else
1477 dst->var_part[k].cur_loc = NULL;
1478 }
1479
62760ffd
CT
1480 for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++)
1481 {
1482 location_chain node, node2;
1483 for (node = src->var_part[i].loc_chain; node; node = node->next)
1484 for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next)
1485 if (rtx_equal_p (node->loc, node2->loc))
1486 {
1487 if (node->init > node2->init)
1488 node2->init = node->init;
1489 }
1490 }
1491
014a1138
JZ
1492 /* Continue traversing the hash table. */
1493 return 1;
1494}
1495
d24686d7
JJ
1496/* Like variable_union, but only used when doing dataflow_set_union
1497 into an empty hashtab. To allow sharing, dst is initially shared
1498 with src (so all variables are "copied" from src to dst hashtab),
1499 so only unshare_variable for variables that need canonicalization
1500 are needed. */
1501
1502static int
1503variable_canonicalize (void **slot, void *data)
1504{
1505 variable src;
1506 dataflow_set *set = (dataflow_set *) data;
1507 int k;
1508
1509 src = *(variable *) slot;
1510
1511 /* If CUR_LOC of some variable part is not the first element of
1512 the location chain we are going to change it so we have to make
1513 a copy of the variable. */
1514 for (k = 0; k < src->n_var_parts; k++)
1515 {
1516 gcc_assert (!src->var_part[k].loc_chain == !src->var_part[k].cur_loc);
1517 if (src->var_part[k].loc_chain)
1518 {
1519 gcc_assert (src->var_part[k].cur_loc);
1520 if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
1521 break;
1522 }
1523 }
1524 if (k < src->n_var_parts)
1525 {
1526 enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
1527
1528 if (! flag_var_tracking_uninit)
1529 status = VAR_INIT_STATUS_INITIALIZED;
1530
1531 unshare_variable (set, src, status);
1532 }
1533 return 1;
1534}
1535
014a1138
JZ
1536/* Compute union of dataflow sets SRC and DST and store it to DST. */
1537
1538static void
1539dataflow_set_union (dataflow_set *dst, dataflow_set *src)
1540{
1541 int i;
1542
1543 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1544 attrs_list_union (&dst->regs[i], src->regs[i]);
1545
d24686d7
JJ
1546 if (dst->vars == empty_shared_hash)
1547 {
1548 shared_hash_destroy (dst->vars);
1549 dst->vars = shared_hash_copy (src->vars);
1550 htab_traverse (shared_hash_htab (src->vars), variable_canonicalize, dst);
1551 }
1552 else
1553 htab_traverse (shared_hash_htab (src->vars), variable_union, dst);
014a1138
JZ
1554}
1555
1556/* Flag whether two dataflow sets being compared contain different data. */
1557static bool
1558dataflow_set_different_value;
1559
1560static bool
1561variable_part_different_p (variable_part *vp1, variable_part *vp2)
1562{
1563 location_chain lc1, lc2;
1564
1565 for (lc1 = vp1->loc_chain; lc1; lc1 = lc1->next)
1566 {
1567 for (lc2 = vp2->loc_chain; lc2; lc2 = lc2->next)
1568 {
f8cfc6aa 1569 if (REG_P (lc1->loc) && REG_P (lc2->loc))
014a1138
JZ
1570 {
1571 if (REGNO (lc1->loc) == REGNO (lc2->loc))
1572 break;
1573 }
1574 if (rtx_equal_p (lc1->loc, lc2->loc))
1575 break;
1576 }
1577 if (!lc2)
1578 return true;
1579 }
1580 return false;
1581}
1582
83532fb7
JZ
1583/* Return true if variables VAR1 and VAR2 are different.
1584 If COMPARE_CURRENT_LOCATION is true compare also the cur_loc of each
1585 variable part. */
014a1138
JZ
1586
1587static bool
83532fb7
JZ
1588variable_different_p (variable var1, variable var2,
1589 bool compare_current_location)
014a1138
JZ
1590{
1591 int i;
1592
81f2eadb
JZ
1593 if (var1 == var2)
1594 return false;
1595
014a1138
JZ
1596 if (var1->n_var_parts != var2->n_var_parts)
1597 return true;
1598
1599 for (i = 0; i < var1->n_var_parts; i++)
1600 {
1601 if (var1->var_part[i].offset != var2->var_part[i].offset)
1602 return true;
83532fb7
JZ
1603 if (compare_current_location)
1604 {
f8cfc6aa
JQ
1605 if (!((REG_P (var1->var_part[i].cur_loc)
1606 && REG_P (var2->var_part[i].cur_loc)
83532fb7
JZ
1607 && (REGNO (var1->var_part[i].cur_loc)
1608 == REGNO (var2->var_part[i].cur_loc)))
1609 || rtx_equal_p (var1->var_part[i].cur_loc,
1610 var2->var_part[i].cur_loc)))
1611 return true;
1612 }
014a1138
JZ
1613 if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i]))
1614 return true;
1615 if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i]))
1616 return true;
1617 }
1618 return false;
1619}
1620
1621/* Compare variable *SLOT with the same variable in hash table DATA
1622 and set DATAFLOW_SET_DIFFERENT_VALUE if they are different. */
1623
1624static int
1625dataflow_set_different_1 (void **slot, void *data)
1626{
1627 htab_t htab = (htab_t) data;
1628 variable var1, var2;
1629
1630 var1 = *(variable *) slot;
3d9a9f94 1631 var2 = (variable) htab_find_with_hash (htab, var1->decl,
400e39e3 1632 VARIABLE_HASH_VAL (var1->decl));
014a1138
JZ
1633 if (!var2)
1634 {
1635 dataflow_set_different_value = true;
1636
71cc389b 1637 /* Stop traversing the hash table. */
014a1138
JZ
1638 return 0;
1639 }
1640
83532fb7 1641 if (variable_different_p (var1, var2, false))
014a1138
JZ
1642 {
1643 dataflow_set_different_value = true;
1644
71cc389b 1645 /* Stop traversing the hash table. */
014a1138
JZ
1646 return 0;
1647 }
1648
1649 /* Continue traversing the hash table. */
1650 return 1;
1651}
1652
1653/* Compare variable *SLOT with the same variable in hash table DATA
1654 and set DATAFLOW_SET_DIFFERENT_VALUE if they are different. */
1655
1656static int
1657dataflow_set_different_2 (void **slot, void *data)
1658{
1659 htab_t htab = (htab_t) data;
1660 variable var1, var2;
1661
1662 var1 = *(variable *) slot;
3d9a9f94 1663 var2 = (variable) htab_find_with_hash (htab, var1->decl,
400e39e3 1664 VARIABLE_HASH_VAL (var1->decl));
014a1138
JZ
1665 if (!var2)
1666 {
1667 dataflow_set_different_value = true;
1668
71cc389b 1669 /* Stop traversing the hash table. */
014a1138
JZ
1670 return 0;
1671 }
1672
014a1138
JZ
1673 /* If both variables are defined they have been already checked for
1674 equivalence. */
fbc848cc 1675 gcc_assert (!variable_different_p (var1, var2, false));
014a1138
JZ
1676
1677 /* Continue traversing the hash table. */
1678 return 1;
1679}
1680
1681/* Return true if dataflow sets OLD_SET and NEW_SET differ. */
1682
1683static bool
1684dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
1685{
d24686d7
JJ
1686 if (old_set->vars == new_set->vars)
1687 return false;
1688
1689 if (htab_elements (shared_hash_htab (old_set->vars))
1690 != htab_elements (shared_hash_htab (new_set->vars)))
1691 return true;
1692
014a1138
JZ
1693 dataflow_set_different_value = false;
1694
d24686d7
JJ
1695 htab_traverse (shared_hash_htab (old_set->vars), dataflow_set_different_1,
1696 shared_hash_htab (new_set->vars));
014a1138
JZ
1697 if (!dataflow_set_different_value)
1698 {
1699 /* We have compared the variables which are in both hash tables
1700 so now only check whether there are some variables in NEW_SET->VARS
1701 which are not in OLD_SET->VARS. */
d24686d7
JJ
1702 htab_traverse (shared_hash_htab (new_set->vars), dataflow_set_different_2,
1703 shared_hash_htab (old_set->vars));
014a1138
JZ
1704 }
1705 return dataflow_set_different_value;
1706}
1707
1708/* Free the contents of dataflow set SET. */
1709
1710static void
1711dataflow_set_destroy (dataflow_set *set)
1712{
1713 int i;
1714
1715 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1716 attrs_list_clear (&set->regs[i]);
1717
d24686d7 1718 shared_hash_destroy (set->vars);
014a1138
JZ
1719 set->vars = NULL;
1720}
1721
1722/* Return true if RTL X contains a SYMBOL_REF. */
1723
1724static bool
1725contains_symbol_ref (rtx x)
1726{
1727 const char *fmt;
1728 RTX_CODE code;
1729 int i;
1730
1731 if (!x)
1732 return false;
1733
1734 code = GET_CODE (x);
1735 if (code == SYMBOL_REF)
1736 return true;
1737
1738 fmt = GET_RTX_FORMAT (code);
1739 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
1740 {
1741 if (fmt[i] == 'e')
1742 {
1743 if (contains_symbol_ref (XEXP (x, i)))
1744 return true;
1745 }
1746 else if (fmt[i] == 'E')
1747 {
1748 int j;
1749 for (j = 0; j < XVECLEN (x, i); j++)
1750 if (contains_symbol_ref (XVECEXP (x, i, j)))
1751 return true;
1752 }
1753 }
1754
1755 return false;
1756}
1757
1758/* Shall EXPR be tracked? */
1759
1760static bool
1761track_expr_p (tree expr)
1762{
1763 rtx decl_rtl;
ac3bfd86 1764 tree realdecl;
014a1138
JZ
1765
1766 /* If EXPR is not a parameter or a variable do not track it. */
1767 if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL)
1768 return 0;
1769
1770 /* It also must have a name... */
1771 if (!DECL_NAME (expr))
1772 return 0;
1773
1774 /* ... and a RTL assigned to it. */
1775 decl_rtl = DECL_RTL_IF_SET (expr);
1776 if (!decl_rtl)
1777 return 0;
ac3bfd86
DB
1778
1779 /* If this expression is really a debug alias of some other declaration, we
1780 don't need to track this expression if the ultimate declaration is
1781 ignored. */
1782 realdecl = expr;
f991abd1 1783 if (DECL_DEBUG_EXPR_IS_FROM (realdecl) && DECL_DEBUG_EXPR (realdecl))
dad2a933
RH
1784 {
1785 realdecl = DECL_DEBUG_EXPR (realdecl);
1786 /* ??? We don't yet know how to emit DW_OP_piece for variable
1787 that has been SRA'ed. */
1788 if (!DECL_P (realdecl))
1789 return 0;
1790 }
ac3bfd86
DB
1791
1792 /* Do not track EXPR if REALDECL it should be ignored for debugging
1793 purposes. */
1794 if (DECL_IGNORED_P (realdecl))
af931390
JZ
1795 return 0;
1796
014a1138
JZ
1797 /* Do not track global variables until we are able to emit correct location
1798 list for them. */
ac3bfd86 1799 if (TREE_STATIC (realdecl))
014a1138
JZ
1800 return 0;
1801
1802 /* When the EXPR is a DECL for alias of some variable (see example)
1803 the TREE_STATIC flag is not used. Disable tracking all DECLs whose
1804 DECL_RTL contains SYMBOL_REF.
1805
1806 Example:
1807 extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv")));
1808 char **_dl_argv;
1809 */
3c0cb5de 1810 if (MEM_P (decl_rtl)
014a1138
JZ
1811 && contains_symbol_ref (XEXP (decl_rtl, 0)))
1812 return 0;
1813
1814 /* If RTX is a memory it should not be very large (because it would be
1815 an array or struct). */
3c0cb5de 1816 if (MEM_P (decl_rtl))
014a1138
JZ
1817 {
1818 /* Do not track structures and arrays. */
80a3af5b
RH
1819 if (GET_MODE (decl_rtl) == BLKmode
1820 || AGGREGATE_TYPE_P (TREE_TYPE (realdecl)))
014a1138
JZ
1821 return 0;
1822 if (MEM_SIZE (decl_rtl)
1823 && INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS)
1824 return 0;
1825 }
1826
1827 return 1;
1828}
1829
ca787200
AO
1830/* Determine whether a given LOC refers to the same variable part as
1831 EXPR+OFFSET. */
1832
1833static bool
1834same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
1835{
1836 tree expr2;
1837 HOST_WIDE_INT offset2;
1838
1839 if (! DECL_P (expr))
1840 return false;
1841
1842 if (REG_P (loc))
1843 {
1844 expr2 = REG_EXPR (loc);
1845 offset2 = REG_OFFSET (loc);
1846 }
1847 else if (MEM_P (loc))
1848 {
1849 expr2 = MEM_EXPR (loc);
8c6c36a3 1850 offset2 = INT_MEM_OFFSET (loc);
ca787200
AO
1851 }
1852 else
1853 return false;
1854
1855 if (! expr2 || ! DECL_P (expr2))
1856 return false;
1857
1858 expr = var_debug_decl (expr);
1859 expr2 = var_debug_decl (expr2);
1860
1861 return (expr == expr2 && offset == offset2);
1862}
1863
38ae7651
RS
1864/* LOC is a REG or MEM that we would like to track if possible.
1865 If EXPR is null, we don't know what expression LOC refers to,
1866 otherwise it refers to EXPR + OFFSET. STORE_REG_P is true if
1867 LOC is an lvalue register.
94a7682d 1868
38ae7651
RS
1869 Return true if EXPR is nonnull and if LOC, or some lowpart of it,
1870 is something we can track. When returning true, store the mode of
1871 the lowpart we can track in *MODE_OUT (if nonnull) and its offset
1872 from EXPR in *OFFSET_OUT (if nonnull). */
94a7682d 1873
38ae7651
RS
1874static bool
1875track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
1876 enum machine_mode *mode_out, HOST_WIDE_INT *offset_out)
94a7682d
RS
1877{
1878 enum machine_mode mode;
1879
38ae7651
RS
1880 if (expr == NULL || !track_expr_p (expr))
1881 return false;
1882
1883 /* If REG was a paradoxical subreg, its REG_ATTRS will describe the
1884 whole subreg, but only the old inner part is really relevant. */
1885 mode = GET_MODE (loc);
1886 if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc)))
94a7682d
RS
1887 {
1888 enum machine_mode pseudo_mode;
1889
38ae7651 1890 pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc));
94a7682d 1891 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode))
38ae7651
RS
1892 {
1893 offset += byte_lowpart_offset (pseudo_mode, mode);
1894 mode = pseudo_mode;
1895 }
1896 }
1897
1898 /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself.
1899 Do the same if we are storing to a register and EXPR occupies
1900 the whole of register LOC; in that case, the whole of EXPR is
1901 being changed. We exclude complex modes from the second case
1902 because the real and imaginary parts are represented as separate
1903 pseudo registers, even if the whole complex value fits into one
1904 hard register. */
1905 if ((GET_MODE_SIZE (mode) > GET_MODE_SIZE (DECL_MODE (expr))
1906 || (store_reg_p
1907 && !COMPLEX_MODE_P (DECL_MODE (expr))
1908 && hard_regno_nregs[REGNO (loc)][DECL_MODE (expr)] == 1))
1909 && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0)
1910 {
1911 mode = DECL_MODE (expr);
1912 offset = 0;
94a7682d 1913 }
38ae7651
RS
1914
1915 if (offset < 0 || offset >= MAX_VAR_PARTS)
1916 return false;
1917
1918 if (mode_out)
1919 *mode_out = mode;
1920 if (offset_out)
1921 *offset_out = offset;
1922 return true;
94a7682d
RS
1923}
1924
1925/* Return the MODE lowpart of LOC, or null if LOC is not something we
1926 want to track. When returning nonnull, make sure that the attributes
1927 on the returned value are updated. */
1928
1929static rtx
1930var_lowpart (enum machine_mode mode, rtx loc)
1931{
38ae7651 1932 unsigned int offset, reg_offset, regno;
94a7682d
RS
1933
1934 if (!REG_P (loc) && !MEM_P (loc))
1935 return NULL;
1936
1937 if (GET_MODE (loc) == mode)
1938 return loc;
1939
38ae7651 1940 offset = byte_lowpart_offset (mode, GET_MODE (loc));
94a7682d
RS
1941
1942 if (MEM_P (loc))
1943 return adjust_address_nv (loc, mode, offset);
1944
38ae7651 1945 reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc));
94a7682d 1946 regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc),
38ae7651 1947 reg_offset, mode);
94a7682d
RS
1948 return gen_rtx_REG_offset (loc, mode, regno, offset);
1949}
ca787200 1950
014a1138
JZ
1951/* Count uses (register and memory references) LOC which will be tracked.
1952 INSN is instruction which the LOC is part of. */
1953
1954static int
1955count_uses (rtx *loc, void *insn)
1956{
1957 basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
1958
f8cfc6aa 1959 if (REG_P (*loc))
014a1138 1960 {
fbc848cc
NS
1961 gcc_assert (REGNO (*loc) < FIRST_PSEUDO_REGISTER);
1962 VTI (bb)->n_mos++;
014a1138 1963 }
3c0cb5de 1964 else if (MEM_P (*loc)
38ae7651
RS
1965 && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc),
1966 false, NULL, NULL))
014a1138 1967 {
fbc848cc 1968 VTI (bb)->n_mos++;
014a1138
JZ
1969 }
1970
1971 return 0;
1972}
1973
1974/* Helper function for finding all uses of REG/MEM in X in insn INSN. */
1975
1976static void
1977count_uses_1 (rtx *x, void *insn)
1978{
1979 for_each_rtx (x, count_uses, insn);
1980}
1981
1982/* Count stores (register and memory references) LOC which will be tracked.
1983 INSN is instruction which the LOC is part of. */
1984
1985static void
7bc980e1 1986count_stores (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *insn)
014a1138
JZ
1987{
1988 count_uses (&loc, insn);
1989}
1990
1991/* Add uses (register and memory references) LOC which will be tracked
1992 to VTI (bb)->mos. INSN is instruction which the LOC is part of. */
1993
1994static int
1995add_uses (rtx *loc, void *insn)
1996{
38ae7651
RS
1997 enum machine_mode mode;
1998
f8cfc6aa 1999 if (REG_P (*loc))
014a1138
JZ
2000 {
2001 basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
2002 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
2003
38ae7651
RS
2004 if (track_loc_p (*loc, REG_EXPR (*loc), REG_OFFSET (*loc),
2005 false, &mode, NULL))
94a7682d
RS
2006 {
2007 mo->type = MO_USE;
38ae7651 2008 mo->u.loc = var_lowpart (mode, *loc);
94a7682d
RS
2009 }
2010 else
2011 {
2012 mo->type = MO_USE_NO_VAR;
2013 mo->u.loc = *loc;
2014 }
014a1138
JZ
2015 mo->insn = (rtx) insn;
2016 }
3c0cb5de 2017 else if (MEM_P (*loc)
38ae7651
RS
2018 && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc),
2019 false, &mode, NULL))
014a1138
JZ
2020 {
2021 basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
2022 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
2023
2024 mo->type = MO_USE;
38ae7651 2025 mo->u.loc = var_lowpart (mode, *loc);
014a1138
JZ
2026 mo->insn = (rtx) insn;
2027 }
2028
2029 return 0;
2030}
2031
2032/* Helper function for finding all uses of REG/MEM in X in insn INSN. */
2033
2034static void
2035add_uses_1 (rtx *x, void *insn)
2036{
2037 for_each_rtx (x, add_uses, insn);
2038}
2039
2040/* Add stores (register and memory references) LOC which will be tracked
2041 to VTI (bb)->mos. EXPR is the RTL expression containing the store.
2042 INSN is instruction which the LOC is part of. */
2043
2044static void
7bc980e1 2045add_stores (rtx loc, const_rtx expr, void *insn)
014a1138 2046{
38ae7651
RS
2047 enum machine_mode mode;
2048
f8cfc6aa 2049 if (REG_P (loc))
014a1138
JZ
2050 {
2051 basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
2052 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
2053
ca787200 2054 if (GET_CODE (expr) == CLOBBER
38ae7651
RS
2055 || !track_loc_p (loc, REG_EXPR (loc), REG_OFFSET (loc),
2056 true, &mode, NULL))
94a7682d
RS
2057 {
2058 mo->type = MO_CLOBBER;
2059 mo->u.loc = loc;
2060 }
ca787200 2061 else
94a7682d 2062 {
94a7682d
RS
2063 rtx src = NULL;
2064
2065 if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
2066 src = var_lowpart (mode, SET_SRC (expr));
2067 loc = var_lowpart (mode, loc);
2068
2069 if (src == NULL)
2070 {
2071 mo->type = MO_SET;
2072 mo->u.loc = loc;
2073 }
2074 else
2075 {
2076 if (SET_SRC (expr) != src)
2077 expr = gen_rtx_SET (VOIDmode, loc, src);
2078 if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
2079 mo->type = MO_COPY;
2080 else
2081 mo->type = MO_SET;
2082 mo->u.loc = CONST_CAST_RTX (expr);
2083 }
2084 }
62760ffd 2085 mo->insn = (rtx) insn;
014a1138 2086 }
3c0cb5de 2087 else if (MEM_P (loc)
38ae7651
RS
2088 && track_loc_p (loc, MEM_EXPR (loc), INT_MEM_OFFSET (loc),
2089 false, &mode, NULL))
014a1138
JZ
2090 {
2091 basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
2092 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
2093
ca787200 2094 if (GET_CODE (expr) == CLOBBER)
94a7682d
RS
2095 {
2096 mo->type = MO_CLOBBER;
38ae7651 2097 mo->u.loc = var_lowpart (mode, loc);
94a7682d
RS
2098 }
2099 else
2100 {
2101 rtx src = NULL;
2102
2103 if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
38ae7651
RS
2104 src = var_lowpart (mode, SET_SRC (expr));
2105 loc = var_lowpart (mode, loc);
94a7682d
RS
2106
2107 if (src == NULL)
2108 {
2109 mo->type = MO_SET;
2110 mo->u.loc = loc;
2111 }
2112 else
2113 {
38ae7651
RS
2114 if (SET_SRC (expr) != src)
2115 expr = gen_rtx_SET (VOIDmode, loc, src);
94a7682d 2116 if (same_variable_part_p (SET_SRC (expr),
ca787200 2117 MEM_EXPR (loc),
8c6c36a3 2118 INT_MEM_OFFSET (loc)))
94a7682d
RS
2119 mo->type = MO_COPY;
2120 else
2121 mo->type = MO_SET;
2122 mo->u.loc = CONST_CAST_RTX (expr);
2123 }
2124 }
62760ffd 2125 mo->insn = (rtx) insn;
014a1138
JZ
2126 }
2127}
2128
62760ffd 2129static enum var_init_status
94a7682d 2130find_src_status (dataflow_set *in, rtx src)
62760ffd 2131{
62760ffd
CT
2132 tree decl = NULL_TREE;
2133 enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
2134
2135 if (! flag_var_tracking_uninit)
2136 status = VAR_INIT_STATUS_INITIALIZED;
2137
0ef0421e 2138 if (src && REG_P (src))
62760ffd 2139 decl = var_debug_decl (REG_EXPR (src));
0ef0421e 2140 else if (src && MEM_P (src))
62760ffd
CT
2141 decl = var_debug_decl (MEM_EXPR (src));
2142
2143 if (src && decl)
2144 status = get_init_value (in, src, decl);
2145
2146 return status;
2147}
2148
94a7682d
RS
2149/* SRC is the source of an assignment. Use SET to try to find what
2150 was ultimately assigned to SRC. Return that value if known,
2151 otherwise return SRC itself. */
62760ffd
CT
2152
2153static rtx
94a7682d 2154find_src_set_src (dataflow_set *set, rtx src)
62760ffd
CT
2155{
2156 tree decl = NULL_TREE; /* The variable being copied around. */
62760ffd 2157 rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */
62760ffd
CT
2158 variable var;
2159 location_chain nextp;
2160 int i;
2161 bool found;
2162
0ef0421e 2163 if (src && REG_P (src))
62760ffd 2164 decl = var_debug_decl (REG_EXPR (src));
0ef0421e 2165 else if (src && MEM_P (src))
62760ffd
CT
2166 decl = var_debug_decl (MEM_EXPR (src));
2167
2168 if (src && decl)
2169 {
d24686d7
JJ
2170 var = shared_hash_find (set->vars, decl);
2171 if (var)
62760ffd 2172 {
62760ffd
CT
2173 found = false;
2174 for (i = 0; i < var->n_var_parts && !found; i++)
2175 for (nextp = var->var_part[i].loc_chain; nextp && !found;
2176 nextp = nextp->next)
2177 if (rtx_equal_p (nextp->loc, src))
2178 {
2179 set_src = nextp->set_src;
2180 found = true;
2181 }
2182
2183 }
2184 }
2185
2186 return set_src;
2187}
2188
014a1138
JZ
2189/* Compute the changes of variable locations in the basic block BB. */
2190
2191static bool
2192compute_bb_dataflow (basic_block bb)
2193{
2194 int i, n, r;
2195 bool changed;
2196 dataflow_set old_out;
2197 dataflow_set *in = &VTI (bb)->in;
2198 dataflow_set *out = &VTI (bb)->out;
2199
d24686d7 2200 dataflow_set_init (&old_out);
014a1138
JZ
2201 dataflow_set_copy (&old_out, out);
2202 dataflow_set_copy (out, in);
2203
2204 n = VTI (bb)->n_mos;
2205 for (i = 0; i < n; i++)
2206 {
2207 switch (VTI (bb)->mos[i].type)
2208 {
2209 case MO_CALL:
2210 for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
2211 if (TEST_HARD_REG_BIT (call_used_reg_set, r))
2212 var_regno_delete (out, r);
2213 break;
2214
2215 case MO_USE:
dedc1e6d
AO
2216 {
2217 rtx loc = VTI (bb)->mos[i].u.loc;
62760ffd
CT
2218 enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
2219
2220 if (! flag_var_tracking_uninit)
2221 status = VAR_INIT_STATUS_INITIALIZED;
dedc1e6d 2222
481683e1 2223 if (REG_P (loc))
62760ffd 2224 var_reg_set (out, loc, status, NULL);
481683e1 2225 else if (MEM_P (loc))
62760ffd 2226 var_mem_set (out, loc, status, NULL);
dedc1e6d
AO
2227 }
2228 break;
2229
014a1138
JZ
2230 case MO_SET:
2231 {
2232 rtx loc = VTI (bb)->mos[i].u.loc;
94a7682d 2233 rtx set_src = NULL;
62760ffd 2234
94a7682d 2235 if (GET_CODE (loc) == SET)
62760ffd 2236 {
94a7682d
RS
2237 set_src = SET_SRC (loc);
2238 loc = SET_DEST (loc);
62760ffd 2239 }
014a1138 2240
f8cfc6aa 2241 if (REG_P (loc))
62760ffd
CT
2242 var_reg_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
2243 set_src);
ca787200 2244 else if (MEM_P (loc))
62760ffd
CT
2245 var_mem_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
2246 set_src);
ca787200
AO
2247 }
2248 break;
2249
2250 case MO_COPY:
2251 {
2252 rtx loc = VTI (bb)->mos[i].u.loc;
62760ffd 2253 enum var_init_status src_status;
94a7682d
RS
2254 rtx set_src = NULL;
2255
2256 if (GET_CODE (loc) == SET)
2257 {
2258 set_src = SET_SRC (loc);
2259 loc = SET_DEST (loc);
2260 }
62760ffd
CT
2261
2262 if (! flag_var_tracking_uninit)
2263 src_status = VAR_INIT_STATUS_INITIALIZED;
2264 else
94a7682d 2265 src_status = find_src_status (in, set_src);
62760ffd
CT
2266
2267 if (src_status == VAR_INIT_STATUS_UNKNOWN)
94a7682d 2268 src_status = find_src_status (out, set_src);
62760ffd 2269
94a7682d 2270 set_src = find_src_set_src (in, set_src);
ca787200
AO
2271
2272 if (REG_P (loc))
62760ffd 2273 var_reg_delete_and_set (out, loc, false, src_status, set_src);
3c0cb5de 2274 else if (MEM_P (loc))
62760ffd 2275 var_mem_delete_and_set (out, loc, false, src_status, set_src);
014a1138
JZ
2276 }
2277 break;
2278
2279 case MO_USE_NO_VAR:
ca787200
AO
2280 {
2281 rtx loc = VTI (bb)->mos[i].u.loc;
2282
2283 if (REG_P (loc))
2284 var_reg_delete (out, loc, false);
2285 else if (MEM_P (loc))
2286 var_mem_delete (out, loc, false);
2287 }
2288 break;
2289
014a1138
JZ
2290 case MO_CLOBBER:
2291 {
2292 rtx loc = VTI (bb)->mos[i].u.loc;
2293
f8cfc6aa 2294 if (REG_P (loc))
ca787200 2295 var_reg_delete (out, loc, true);
3c0cb5de 2296 else if (MEM_P (loc))
ca787200 2297 var_mem_delete (out, loc, true);
014a1138
JZ
2298 }
2299 break;
2300
2301 case MO_ADJUST:
30e6f306 2302 out->stack_adjust += VTI (bb)->mos[i].u.adjust;
014a1138
JZ
2303 break;
2304 }
2305 }
2306
2307 changed = dataflow_set_different (&old_out, out);
2308 dataflow_set_destroy (&old_out);
2309 return changed;
2310}
2311
2312/* Find the locations of variables in the whole function. */
2313
2314static void
2315vt_find_locations (void)
2316{
2317 fibheap_t worklist, pending, fibheap_swap;
2318 sbitmap visited, in_worklist, in_pending, sbitmap_swap;
2319 basic_block bb;
2320 edge e;
2321 int *bb_order;
2322 int *rc_order;
2323 int i;
2324
2325 /* Compute reverse completion order of depth first search of the CFG
2326 so that the data-flow runs faster. */
5ed6ace5
MD
2327 rc_order = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS);
2328 bb_order = XNEWVEC (int, last_basic_block);
f91a0beb 2329 pre_and_rev_post_order_compute (NULL, rc_order, false);
24bd1a0b 2330 for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
014a1138
JZ
2331 bb_order[rc_order[i]] = i;
2332 free (rc_order);
2333
2334 worklist = fibheap_new ();
2335 pending = fibheap_new ();
2336 visited = sbitmap_alloc (last_basic_block);
2337 in_worklist = sbitmap_alloc (last_basic_block);
2338 in_pending = sbitmap_alloc (last_basic_block);
2339 sbitmap_zero (in_worklist);
014a1138
JZ
2340
2341 FOR_EACH_BB (bb)
0e6ed899
JZ
2342 fibheap_insert (pending, bb_order[bb->index], bb);
2343 sbitmap_ones (in_pending);
014a1138
JZ
2344
2345 while (!fibheap_empty (pending))
2346 {
2347 fibheap_swap = pending;
2348 pending = worklist;
2349 worklist = fibheap_swap;
2350 sbitmap_swap = in_pending;
2351 in_pending = in_worklist;
2352 in_worklist = sbitmap_swap;
2353
2354 sbitmap_zero (visited);
2355
2356 while (!fibheap_empty (worklist))
2357 {
3d9a9f94 2358 bb = (basic_block) fibheap_extract_min (worklist);
014a1138
JZ
2359 RESET_BIT (in_worklist, bb->index);
2360 if (!TEST_BIT (visited, bb->index))
2361 {
2362 bool changed;
628f6a4e 2363 edge_iterator ei;
014a1138
JZ
2364
2365 SET_BIT (visited, bb->index);
2366
2367 /* Calculate the IN set as union of predecessor OUT sets. */
2368 dataflow_set_clear (&VTI (bb)->in);
628f6a4e 2369 FOR_EACH_EDGE (e, ei, bb->preds)
014a1138
JZ
2370 {
2371 dataflow_set_union (&VTI (bb)->in, &VTI (e->src)->out);
2372 }
2373
2374 changed = compute_bb_dataflow (bb);
2375 if (changed)
2376 {
628f6a4e 2377 FOR_EACH_EDGE (e, ei, bb->succs)
014a1138
JZ
2378 {
2379 if (e->dest == EXIT_BLOCK_PTR)
2380 continue;
2381
2382 if (e->dest == bb)
2383 continue;
2384
2385 if (TEST_BIT (visited, e->dest->index))
2386 {
2387 if (!TEST_BIT (in_pending, e->dest->index))
2388 {
2389 /* Send E->DEST to next round. */
2390 SET_BIT (in_pending, e->dest->index);
2391 fibheap_insert (pending,
2392 bb_order[e->dest->index],
2393 e->dest);
2394 }
2395 }
2396 else if (!TEST_BIT (in_worklist, e->dest->index))
2397 {
2398 /* Add E->DEST to current round. */
2399 SET_BIT (in_worklist, e->dest->index);
2400 fibheap_insert (worklist, bb_order[e->dest->index],
2401 e->dest);
2402 }
2403 }
2404 }
2405 }
2406 }
2407 }
2408
2409 free (bb_order);
2410 fibheap_delete (worklist);
2411 fibheap_delete (pending);
2412 sbitmap_free (visited);
2413 sbitmap_free (in_worklist);
2414 sbitmap_free (in_pending);
2415}
2416
2417/* Print the content of the LIST to dump file. */
2418
2419static void
2420dump_attrs_list (attrs list)
2421{
2422 for (; list; list = list->next)
2423 {
c263766c 2424 print_mem_expr (dump_file, list->decl);
30e6f306 2425 fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
014a1138 2426 }
c263766c 2427 fprintf (dump_file, "\n");
014a1138
JZ
2428}
2429
2430/* Print the information about variable *SLOT to dump file. */
2431
2432static int
2433dump_variable (void **slot, void *data ATTRIBUTE_UNUSED)
2434{
2435 variable var = *(variable *) slot;
2436 int i;
2437 location_chain node;
2438
e56f9152 2439 fprintf (dump_file, " name: %s",
014a1138 2440 IDENTIFIER_POINTER (DECL_NAME (var->decl)));
e56f9152
MM
2441 if (dump_flags & TDF_UID)
2442 fprintf (dump_file, " D.%u\n", DECL_UID (var->decl));
2443 else
2444 fprintf (dump_file, "\n");
2445
014a1138
JZ
2446 for (i = 0; i < var->n_var_parts; i++)
2447 {
c263766c 2448 fprintf (dump_file, " offset %ld\n",
014a1138
JZ
2449 (long) var->var_part[i].offset);
2450 for (node = var->var_part[i].loc_chain; node; node = node->next)
2451 {
c263766c 2452 fprintf (dump_file, " ");
62760ffd
CT
2453 if (node->init == VAR_INIT_STATUS_UNINITIALIZED)
2454 fprintf (dump_file, "[uninit]");
c263766c 2455 print_rtl_single (dump_file, node->loc);
014a1138
JZ
2456 }
2457 }
2458
2459 /* Continue traversing the hash table. */
2460 return 1;
2461}
2462
2463/* Print the information about variables from hash table VARS to dump file. */
2464
2465static void
2466dump_vars (htab_t vars)
2467{
2468 if (htab_elements (vars) > 0)
2469 {
c263766c 2470 fprintf (dump_file, "Variables:\n");
014a1138
JZ
2471 htab_traverse (vars, dump_variable, NULL);
2472 }
2473}
2474
2475/* Print the dataflow set SET to dump file. */
2476
2477static void
2478dump_dataflow_set (dataflow_set *set)
2479{
2480 int i;
2481
30e6f306
RH
2482 fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
2483 set->stack_adjust);
d3067303 2484 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
014a1138
JZ
2485 {
2486 if (set->regs[i])
2487 {
c263766c 2488 fprintf (dump_file, "Reg %d:", i);
014a1138
JZ
2489 dump_attrs_list (set->regs[i]);
2490 }
2491 }
d24686d7 2492 dump_vars (shared_hash_htab (set->vars));
c263766c 2493 fprintf (dump_file, "\n");
014a1138
JZ
2494}
2495
2496/* Print the IN and OUT sets for each basic block to dump file. */
2497
2498static void
2499dump_dataflow_sets (void)
2500{
2501 basic_block bb;
2502
2503 FOR_EACH_BB (bb)
2504 {
c263766c
RH
2505 fprintf (dump_file, "\nBasic block %d:\n", bb->index);
2506 fprintf (dump_file, "IN:\n");
014a1138 2507 dump_dataflow_set (&VTI (bb)->in);
c263766c 2508 fprintf (dump_file, "OUT:\n");
014a1138
JZ
2509 dump_dataflow_set (&VTI (bb)->out);
2510 }
2511}
2512
2513/* Add variable VAR to the hash table of changed variables and
d24686d7 2514 if it has no locations delete it from SET's hash table. */
014a1138
JZ
2515
2516static void
d24686d7 2517variable_was_changed (variable var, dataflow_set *set)
014a1138
JZ
2518{
2519 hashval_t hash = VARIABLE_HASH_VAL (var->decl);
2520
2521 if (emit_notes)
2522 {
2523 variable *slot;
2524
2525 slot = (variable *) htab_find_slot_with_hash (changed_variables,
2526 var->decl, hash, INSERT);
2527
d24686d7 2528 if (set && var->n_var_parts == 0)
014a1138
JZ
2529 {
2530 variable empty_var;
014a1138 2531
3d9a9f94 2532 empty_var = (variable) pool_alloc (var_pool);
014a1138 2533 empty_var->decl = var->decl;
81f2eadb 2534 empty_var->refcount = 1;
014a1138
JZ
2535 empty_var->n_var_parts = 0;
2536 *slot = empty_var;
d24686d7 2537 goto drop_var;
014a1138
JZ
2538 }
2539 else
2540 {
d24686d7 2541 var->refcount++;
014a1138
JZ
2542 *slot = var;
2543 }
2544 }
2545 else
2546 {
d24686d7 2547 gcc_assert (set);
014a1138
JZ
2548 if (var->n_var_parts == 0)
2549 {
d24686d7
JJ
2550 void **slot;
2551
2552 drop_var:
2553 slot = shared_hash_find_slot_noinsert (set->vars, var->decl);
014a1138 2554 if (slot)
d24686d7
JJ
2555 {
2556 if (shared_hash_shared (set->vars))
2557 slot = shared_hash_find_slot_unshare (&set->vars, var->decl,
2558 NO_INSERT);
2559 htab_clear_slot (shared_hash_htab (set->vars), slot);
2560 }
014a1138
JZ
2561 }
2562 }
2563}
2564
ca787200
AO
2565/* Look for the index in VAR->var_part corresponding to OFFSET.
2566 Return -1 if not found. If INSERTION_POINT is non-NULL, the
2567 referenced int will be set to the index that the part has or should
2568 have, if it should be inserted. */
2569
2570static inline int
2571find_variable_location_part (variable var, HOST_WIDE_INT offset,
2572 int *insertion_point)
2573{
2574 int pos, low, high;
2575
2576 /* Find the location part. */
2577 low = 0;
2578 high = var->n_var_parts;
2579 while (low != high)
2580 {
2581 pos = (low + high) / 2;
2582 if (var->var_part[pos].offset < offset)
2583 low = pos + 1;
2584 else
2585 high = pos;
2586 }
2587 pos = low;
2588
2589 if (insertion_point)
2590 *insertion_point = pos;
2591
2592 if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
2593 return pos;
2594
2595 return -1;
2596}
2597
014a1138
JZ
2598/* Set the part of variable's location in the dataflow set SET. The variable
2599 part is specified by variable's declaration DECL and offset OFFSET and the
2600 part's location by LOC. */
2601
2602static void
62760ffd
CT
2603set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
2604 enum var_init_status initialized, rtx set_src)
014a1138 2605{
ca787200 2606 int pos;
11599d14
JZ
2607 location_chain node, next;
2608 location_chain *nextp;
014a1138 2609 variable var;
d24686d7
JJ
2610 void **slot = shared_hash_find_slot (set->vars, decl);
2611
2612 if (!slot || !*slot)
014a1138 2613 {
d24686d7
JJ
2614 if (!slot)
2615 slot = shared_hash_find_slot_unshare (&set->vars, decl, INSERT);
014a1138 2616 /* Create new variable information. */
3d9a9f94 2617 var = (variable) pool_alloc (var_pool);
014a1138 2618 var->decl = decl;
81f2eadb 2619 var->refcount = 1;
014a1138
JZ
2620 var->n_var_parts = 1;
2621 var->var_part[0].offset = offset;
2622 var->var_part[0].loc_chain = NULL;
2623 var->var_part[0].cur_loc = NULL;
2624 *slot = var;
2625 pos = 0;
2626 }
2627 else
2628 {
ca787200
AO
2629 int inspos = 0;
2630
014a1138
JZ
2631 var = (variable) *slot;
2632
ca787200 2633 pos = find_variable_location_part (var, offset, &inspos);
014a1138 2634
ca787200 2635 if (pos >= 0)
014a1138 2636 {
81f2eadb
JZ
2637 node = var->var_part[pos].loc_chain;
2638
2639 if (node
f8cfc6aa 2640 && ((REG_P (node->loc) && REG_P (loc)
81f2eadb
JZ
2641 && REGNO (node->loc) == REGNO (loc))
2642 || rtx_equal_p (node->loc, loc)))
2643 {
2644 /* LOC is in the beginning of the chain so we have nothing
2645 to do. */
62760ffd
CT
2646 if (node->init < initialized)
2647 node->init = initialized;
2648 if (set_src != NULL)
2649 node->set_src = set_src;
2650
81f2eadb
JZ
2651 return;
2652 }
2653 else
2654 {
2655 /* We have to make a copy of a shared variable. */
d24686d7 2656 if (var->refcount > 1 || shared_hash_shared (set->vars))
62760ffd 2657 var = unshare_variable (set, var, initialized);
81f2eadb
JZ
2658 }
2659 }
2660 else
2661 {
2662 /* We have not found the location part, new one will be created. */
2663
2664 /* We have to make a copy of the shared variable. */
d24686d7 2665 if (var->refcount > 1 || shared_hash_shared (set->vars))
62760ffd 2666 var = unshare_variable (set, var, initialized);
014a1138 2667
014a1138
JZ
2668 /* We track only variables whose size is <= MAX_VAR_PARTS bytes
2669 thus there are at most MAX_VAR_PARTS different offsets. */
fbc848cc 2670 gcc_assert (var->n_var_parts < MAX_VAR_PARTS);
014a1138 2671
ca787200
AO
2672 /* We have to move the elements of array starting at index
2673 inspos to the next position. */
2674 for (pos = var->n_var_parts; pos > inspos; pos--)
2675 var->var_part[pos] = var->var_part[pos - 1];
014a1138
JZ
2676
2677 var->n_var_parts++;
2678 var->var_part[pos].offset = offset;
2679 var->var_part[pos].loc_chain = NULL;
2680 var->var_part[pos].cur_loc = NULL;
2681 }
2682 }
2683
81f2eadb 2684 /* Delete the location from the list. */
11599d14 2685 nextp = &var->var_part[pos].loc_chain;
014a1138
JZ
2686 for (node = var->var_part[pos].loc_chain; node; node = next)
2687 {
2688 next = node->next;
f8cfc6aa 2689 if ((REG_P (node->loc) && REG_P (loc)
014a1138
JZ
2690 && REGNO (node->loc) == REGNO (loc))
2691 || rtx_equal_p (node->loc, loc))
2692 {
62760ffd
CT
2693 /* Save these values, to assign to the new node, before
2694 deleting this one. */
2695 if (node->init > initialized)
2696 initialized = node->init;
2697 if (node->set_src != NULL && set_src == NULL)
2698 set_src = node->set_src;
014a1138 2699 pool_free (loc_chain_pool, node);
11599d14 2700 *nextp = next;
014a1138
JZ
2701 break;
2702 }
2703 else
11599d14 2704 nextp = &node->next;
014a1138
JZ
2705 }
2706
2707 /* Add the location to the beginning. */
3d9a9f94 2708 node = (location_chain) pool_alloc (loc_chain_pool);
014a1138 2709 node->loc = loc;
62760ffd
CT
2710 node->init = initialized;
2711 node->set_src = set_src;
014a1138
JZ
2712 node->next = var->var_part[pos].loc_chain;
2713 var->var_part[pos].loc_chain = node;
2714
2715 /* If no location was emitted do so. */
2716 if (var->var_part[pos].cur_loc == NULL)
2717 {
2718 var->var_part[pos].cur_loc = loc;
d24686d7 2719 variable_was_changed (var, set);
014a1138
JZ
2720 }
2721}
2722
ca787200
AO
2723/* Remove all recorded register locations for the given variable part
2724 from dataflow set SET, except for those that are identical to loc.
2725 The variable part is specified by variable's declaration DECL and
2726 offset OFFSET. */
2727
2728static void
2729clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
62760ffd 2730 HOST_WIDE_INT offset, rtx set_src)
ca787200 2731{
d24686d7 2732 variable var;
ca787200
AO
2733
2734 if (! decl || ! DECL_P (decl))
2735 return;
2736
d24686d7
JJ
2737 var = shared_hash_find (set->vars, decl);
2738 if (var)
ca787200 2739 {
ca787200
AO
2740 int pos = find_variable_location_part (var, offset, NULL);
2741
2742 if (pos >= 0)
2743 {
2744 location_chain node, next;
2745
2746 /* Remove the register locations from the dataflow set. */
2747 next = var->var_part[pos].loc_chain;
2748 for (node = next; node; node = next)
2749 {
2750 next = node->next;
62760ffd
CT
2751 if (node->loc != loc
2752 && (!flag_var_tracking_uninit
2753 || !set_src
2754 || MEM_P (set_src)
2755 || !rtx_equal_p (set_src, node->set_src)))
d3067303
AO
2756 {
2757 if (REG_P (node->loc))
2758 {
2759 attrs anode, anext;
2760 attrs *anextp;
2761
2762 /* Remove the variable part from the register's
2763 list, but preserve any other variable parts
2764 that might be regarded as live in that same
2765 register. */
2766 anextp = &set->regs[REGNO (node->loc)];
2767 for (anode = *anextp; anode; anode = anext)
2768 {
2769 anext = anode->next;
2770 if (anode->decl == decl
2771 && anode->offset == offset)
2772 {
2773 pool_free (attrs_pool, anode);
2774 *anextp = anext;
2775 }
be71b673
MM
2776 else
2777 anextp = &anode->next;
d3067303
AO
2778 }
2779 }
2780
2781 delete_variable_part (set, node->loc, decl, offset);
2782 }
ca787200
AO
2783 }
2784 }
2785 }
2786}
2787
014a1138
JZ
2788/* Delete the part of variable's location from dataflow set SET. The variable
2789 part is specified by variable's declaration DECL and offset OFFSET and the
2790 part's location by LOC. */
2791
2792static void
2793delete_variable_part (dataflow_set *set, rtx loc, tree decl,
2794 HOST_WIDE_INT offset)
2795{
d24686d7
JJ
2796 variable var = shared_hash_find (set->vars, decl);;
2797 if (var)
014a1138 2798 {
ca787200 2799 int pos = find_variable_location_part (var, offset, NULL);
014a1138 2800
ca787200 2801 if (pos >= 0)
014a1138 2802 {
11599d14
JZ
2803 location_chain node, next;
2804 location_chain *nextp;
014a1138
JZ
2805 bool changed;
2806
d24686d7 2807 if (var->refcount > 1 || shared_hash_shared (set->vars))
81f2eadb
JZ
2808 {
2809 /* If the variable contains the location part we have to
2810 make a copy of the variable. */
2811 for (node = var->var_part[pos].loc_chain; node;
2812 node = node->next)
2813 {
f8cfc6aa 2814 if ((REG_P (node->loc) && REG_P (loc)
81f2eadb
JZ
2815 && REGNO (node->loc) == REGNO (loc))
2816 || rtx_equal_p (node->loc, loc))
2817 {
62760ffd
CT
2818 enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
2819 if (! flag_var_tracking_uninit)
2820 status = VAR_INIT_STATUS_INITIALIZED;
2821 var = unshare_variable (set, var, status);
81f2eadb
JZ
2822 break;
2823 }
2824 }
2825 }
2826
014a1138 2827 /* Delete the location part. */
11599d14
JZ
2828 nextp = &var->var_part[pos].loc_chain;
2829 for (node = *nextp; node; node = next)
014a1138
JZ
2830 {
2831 next = node->next;
f8cfc6aa 2832 if ((REG_P (node->loc) && REG_P (loc)
014a1138
JZ
2833 && REGNO (node->loc) == REGNO (loc))
2834 || rtx_equal_p (node->loc, loc))
2835 {
014a1138 2836 pool_free (loc_chain_pool, node);
11599d14 2837 *nextp = next;
014a1138
JZ
2838 break;
2839 }
2840 else
11599d14 2841 nextp = &node->next;
014a1138
JZ
2842 }
2843
2844 /* If we have deleted the location which was last emitted
2845 we have to emit new location so add the variable to set
2846 of changed variables. */
2847 if (var->var_part[pos].cur_loc
f8cfc6aa
JQ
2848 && ((REG_P (loc)
2849 && REG_P (var->var_part[pos].cur_loc)
014a1138
JZ
2850 && REGNO (loc) == REGNO (var->var_part[pos].cur_loc))
2851 || rtx_equal_p (loc, var->var_part[pos].cur_loc)))
2852 {
2853 changed = true;
2854 if (var->var_part[pos].loc_chain)
2855 var->var_part[pos].cur_loc = var->var_part[pos].loc_chain->loc;
2856 }
2857 else
2858 changed = false;
2859
2860 if (var->var_part[pos].loc_chain == NULL)
2861 {
2862 var->n_var_parts--;
2863 while (pos < var->n_var_parts)
2864 {
2865 var->var_part[pos] = var->var_part[pos + 1];
2866 pos++;
2867 }
2868 }
2869 if (changed)
d24686d7 2870 variable_was_changed (var, set);
014a1138
JZ
2871 }
2872 }
2873}
2874
2875/* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP. DATA contains
2876 additional parameters: WHERE specifies whether the note shall be emitted
2877 before of after instruction INSN. */
2878
2879static int
2880emit_note_insn_var_location (void **varp, void *data)
2881{
2882 variable var = *(variable *) varp;
2883 rtx insn = ((emit_note_data *)data)->insn;
2884 enum emit_note_where where = ((emit_note_data *)data)->where;
2885 rtx note;
c938250d 2886 int i, j, n_var_parts;
014a1138 2887 bool complete;
62760ffd 2888 enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
014a1138
JZ
2889 HOST_WIDE_INT last_limit;
2890 tree type_size_unit;
c938250d
JJ
2891 HOST_WIDE_INT offsets[MAX_VAR_PARTS];
2892 rtx loc[MAX_VAR_PARTS];
014a1138 2893
fbc848cc 2894 gcc_assert (var->decl);
014a1138 2895
62760ffd
CT
2896 if (! flag_var_tracking_uninit)
2897 initialized = VAR_INIT_STATUS_INITIALIZED;
2898
014a1138
JZ
2899 complete = true;
2900 last_limit = 0;
c938250d 2901 n_var_parts = 0;
014a1138
JZ
2902 for (i = 0; i < var->n_var_parts; i++)
2903 {
c938250d
JJ
2904 enum machine_mode mode, wider_mode;
2905
014a1138
JZ
2906 if (last_limit < var->var_part[i].offset)
2907 {
2908 complete = false;
2909 break;
2910 }
c938250d
JJ
2911 else if (last_limit > var->var_part[i].offset)
2912 continue;
2913 offsets[n_var_parts] = var->var_part[i].offset;
2914 loc[n_var_parts] = var->var_part[i].loc_chain->loc;
2915 mode = GET_MODE (loc[n_var_parts]);
62760ffd 2916 initialized = var->var_part[i].loc_chain->init;
c938250d
JJ
2917 last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
2918
2919 /* Attempt to merge adjacent registers or memory. */
2920 wider_mode = GET_MODE_WIDER_MODE (mode);
2921 for (j = i + 1; j < var->n_var_parts; j++)
2922 if (last_limit <= var->var_part[j].offset)
2923 break;
2924 if (j < var->n_var_parts
2925 && wider_mode != VOIDmode
2926 && GET_CODE (loc[n_var_parts])
2927 == GET_CODE (var->var_part[j].loc_chain->loc)
2928 && mode == GET_MODE (var->var_part[j].loc_chain->loc)
2929 && last_limit == var->var_part[j].offset)
2930 {
2931 rtx new_loc = NULL;
2932 rtx loc2 = var->var_part[j].loc_chain->loc;
2933
2934 if (REG_P (loc[n_var_parts])
2935 && hard_regno_nregs[REGNO (loc[n_var_parts])][mode] * 2
2936 == hard_regno_nregs[REGNO (loc[n_var_parts])][wider_mode]
09e18274 2937 && end_hard_regno (mode, REGNO (loc[n_var_parts]))
c938250d
JJ
2938 == REGNO (loc2))
2939 {
2940 if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
2941 new_loc = simplify_subreg (wider_mode, loc[n_var_parts],
2942 mode, 0);
2943 else if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
2944 new_loc = simplify_subreg (wider_mode, loc2, mode, 0);
2945 if (new_loc)
2946 {
2947 if (!REG_P (new_loc)
2948 || REGNO (new_loc) != REGNO (loc[n_var_parts]))
2949 new_loc = NULL;
2950 else
2951 REG_ATTRS (new_loc) = REG_ATTRS (loc[n_var_parts]);
2952 }
2953 }
2954 else if (MEM_P (loc[n_var_parts])
2955 && GET_CODE (XEXP (loc2, 0)) == PLUS
481683e1
SZ
2956 && REG_P (XEXP (XEXP (loc2, 0), 0))
2957 && CONST_INT_P (XEXP (XEXP (loc2, 0), 1)))
c938250d 2958 {
481683e1 2959 if ((REG_P (XEXP (loc[n_var_parts], 0))
c938250d
JJ
2960 && rtx_equal_p (XEXP (loc[n_var_parts], 0),
2961 XEXP (XEXP (loc2, 0), 0))
2962 && INTVAL (XEXP (XEXP (loc2, 0), 1))
2963 == GET_MODE_SIZE (mode))
2964 || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
481683e1 2965 && CONST_INT_P (XEXP (XEXP (loc[n_var_parts], 0), 1))
c938250d
JJ
2966 && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
2967 XEXP (XEXP (loc2, 0), 0))
2968 && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1))
2969 + GET_MODE_SIZE (mode)
2970 == INTVAL (XEXP (XEXP (loc2, 0), 1))))
2971 new_loc = adjust_address_nv (loc[n_var_parts],
2972 wider_mode, 0);
2973 }
2974
2975 if (new_loc)
2976 {
2977 loc[n_var_parts] = new_loc;
2978 mode = wider_mode;
2979 last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
2980 i = j;
2981 }
2982 }
2983 ++n_var_parts;
014a1138
JZ
2984 }
2985 type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (var->decl));
2986 if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
2987 complete = false;
2988
2989 if (where == EMIT_NOTE_AFTER_INSN)
b33614ee 2990 note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
014a1138
JZ
2991 else
2992 note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
2993
62760ffd
CT
2994 if (! flag_var_tracking_uninit)
2995 initialized = VAR_INIT_STATUS_INITIALIZED;
2996
014a1138
JZ
2997 if (!complete)
2998 {
2999 NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
62760ffd 3000 NULL_RTX, (int) initialized);
014a1138 3001 }
c938250d 3002 else if (n_var_parts == 1)
014a1138
JZ
3003 {
3004 rtx expr_list
c938250d 3005 = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
014a1138
JZ
3006
3007 NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
62760ffd
CT
3008 expr_list,
3009 (int) initialized);
014a1138 3010 }
c938250d 3011 else if (n_var_parts)
014a1138 3012 {
014a1138
JZ
3013 rtx parallel;
3014
c938250d
JJ
3015 for (i = 0; i < n_var_parts; i++)
3016 loc[i]
3017 = gen_rtx_EXPR_LIST (VOIDmode, loc[i], GEN_INT (offsets[i]));
3018
014a1138 3019 parallel = gen_rtx_PARALLEL (VOIDmode,
c938250d 3020 gen_rtvec_v (n_var_parts, loc));
014a1138 3021 NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
62760ffd
CT
3022 parallel,
3023 (int) initialized);
014a1138
JZ
3024 }
3025
3026 htab_clear_slot (changed_variables, varp);
3027
014a1138
JZ
3028 /* Continue traversing the hash table. */
3029 return 1;
3030}
3031
3032/* Emit NOTE_INSN_VAR_LOCATION note for each variable from a chain
3033 CHANGED_VARIABLES and delete this chain. WHERE specifies whether the notes
3034 shall be emitted before of after instruction INSN. */
3035
3036static void
3037emit_notes_for_changes (rtx insn, enum emit_note_where where)
3038{
3039 emit_note_data data;
3040
3041 data.insn = insn;
3042 data.where = where;
3043 htab_traverse (changed_variables, emit_note_insn_var_location, &data);
3044}
3045
3046/* Add variable *SLOT to the chain CHANGED_VARIABLES if it differs from the
3047 same variable in hash table DATA or is not there at all. */
3048
3049static int
3050emit_notes_for_differences_1 (void **slot, void *data)
3051{
3052 htab_t new_vars = (htab_t) data;
3053 variable old_var, new_var;
3054
3055 old_var = *(variable *) slot;
3d9a9f94 3056 new_var = (variable) htab_find_with_hash (new_vars, old_var->decl,
400e39e3 3057 VARIABLE_HASH_VAL (old_var->decl));
014a1138
JZ
3058
3059 if (!new_var)
3060 {
3061 /* Variable has disappeared. */
3062 variable empty_var;
3063
3d9a9f94 3064 empty_var = (variable) pool_alloc (var_pool);
014a1138 3065 empty_var->decl = old_var->decl;
d24686d7 3066 empty_var->refcount = 0;
014a1138
JZ
3067 empty_var->n_var_parts = 0;
3068 variable_was_changed (empty_var, NULL);
3069 }
83532fb7 3070 else if (variable_different_p (old_var, new_var, true))
014a1138
JZ
3071 {
3072 variable_was_changed (new_var, NULL);
3073 }
3074
3075 /* Continue traversing the hash table. */
3076 return 1;
3077}
3078
3079/* Add variable *SLOT to the chain CHANGED_VARIABLES if it is not in hash
3080 table DATA. */
3081
3082static int
3083emit_notes_for_differences_2 (void **slot, void *data)
3084{
3085 htab_t old_vars = (htab_t) data;
3086 variable old_var, new_var;
3087
3088 new_var = *(variable *) slot;
3d9a9f94 3089 old_var = (variable) htab_find_with_hash (old_vars, new_var->decl,
400e39e3 3090 VARIABLE_HASH_VAL (new_var->decl));
014a1138
JZ
3091 if (!old_var)
3092 {
3093 /* Variable has appeared. */
3094 variable_was_changed (new_var, NULL);
3095 }
3096
3097 /* Continue traversing the hash table. */
3098 return 1;
3099}
3100
3101/* Emit notes before INSN for differences between dataflow sets OLD_SET and
3102 NEW_SET. */
3103
3104static void
3105emit_notes_for_differences (rtx insn, dataflow_set *old_set,
3106 dataflow_set *new_set)
3107{
d24686d7
JJ
3108 htab_traverse (shared_hash_htab (old_set->vars),
3109 emit_notes_for_differences_1,
3110 shared_hash_htab (new_set->vars));
3111 htab_traverse (shared_hash_htab (new_set->vars),
3112 emit_notes_for_differences_2,
3113 shared_hash_htab (old_set->vars));
014a1138
JZ
3114 emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
3115}
3116
3117/* Emit the notes for changes of location parts in the basic block BB. */
3118
3119static void
3120emit_notes_in_bb (basic_block bb)
3121{
3122 int i;
3123 dataflow_set set;
3124
d24686d7 3125 dataflow_set_init (&set);
014a1138
JZ
3126 dataflow_set_copy (&set, &VTI (bb)->in);
3127
3128 for (i = 0; i < VTI (bb)->n_mos; i++)
3129 {
3130 rtx insn = VTI (bb)->mos[i].insn;
3131
3132 switch (VTI (bb)->mos[i].type)
3133 {
3134 case MO_CALL:
3135 {
3136 int r;
3137
3138 for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
3139 if (TEST_HARD_REG_BIT (call_used_reg_set, r))
3140 {
3141 var_regno_delete (&set, r);
3142 }
3143 emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
3144 }
3145 break;
3146
3147 case MO_USE:
dedc1e6d
AO
3148 {
3149 rtx loc = VTI (bb)->mos[i].u.loc;
62760ffd
CT
3150
3151 enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
3152 if (! flag_var_tracking_uninit)
3153 status = VAR_INIT_STATUS_INITIALIZED;
481683e1 3154 if (REG_P (loc))
62760ffd 3155 var_reg_set (&set, loc, status, NULL);
dedc1e6d 3156 else
62760ffd 3157 var_mem_set (&set, loc, status, NULL);
dedc1e6d
AO
3158
3159 emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
3160 }
3161 break;
3162
014a1138
JZ
3163 case MO_SET:
3164 {
3165 rtx loc = VTI (bb)->mos[i].u.loc;
94a7682d 3166 rtx set_src = NULL;
62760ffd 3167
94a7682d 3168 if (GET_CODE (loc) == SET)
62760ffd 3169 {
94a7682d
RS
3170 set_src = SET_SRC (loc);
3171 loc = SET_DEST (loc);
62760ffd 3172 }
014a1138 3173
f8cfc6aa 3174 if (REG_P (loc))
62760ffd
CT
3175 var_reg_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED,
3176 set_src);
014a1138 3177 else
62760ffd
CT
3178 var_mem_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED,
3179 set_src);
ca787200 3180
62760ffd 3181 emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
ca787200
AO
3182 }
3183 break;
3184
3185 case MO_COPY:
3186 {
3187 rtx loc = VTI (bb)->mos[i].u.loc;
62760ffd 3188 enum var_init_status src_status;
94a7682d
RS
3189 rtx set_src = NULL;
3190
3191 if (GET_CODE (loc) == SET)
3192 {
3193 set_src = SET_SRC (loc);
3194 loc = SET_DEST (loc);
3195 }
62760ffd 3196
94a7682d
RS
3197 src_status = find_src_status (&set, set_src);
3198 set_src = find_src_set_src (&set, set_src);
ca787200
AO
3199
3200 if (REG_P (loc))
62760ffd 3201 var_reg_delete_and_set (&set, loc, false, src_status, set_src);
ca787200 3202 else
62760ffd 3203 var_mem_delete_and_set (&set, loc, false, src_status, set_src);
014a1138 3204
62760ffd 3205 emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
014a1138
JZ
3206 }
3207 break;
3208
3209 case MO_USE_NO_VAR:
014a1138
JZ
3210 {
3211 rtx loc = VTI (bb)->mos[i].u.loc;
3212
f8cfc6aa 3213 if (REG_P (loc))
ca787200 3214 var_reg_delete (&set, loc, false);
014a1138 3215 else
ca787200
AO
3216 var_mem_delete (&set, loc, false);
3217
3218 emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
3219 }
3220 break;
014a1138 3221
ca787200
AO
3222 case MO_CLOBBER:
3223 {
3224 rtx loc = VTI (bb)->mos[i].u.loc;
3225
3226 if (REG_P (loc))
3227 var_reg_delete (&set, loc, true);
dedc1e6d 3228 else
ca787200
AO
3229 var_mem_delete (&set, loc, true);
3230
62760ffd 3231 emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
014a1138
JZ
3232 }
3233 break;
3234
3235 case MO_ADJUST:
30e6f306 3236 set.stack_adjust += VTI (bb)->mos[i].u.adjust;
014a1138
JZ
3237 break;
3238 }
3239 }
3240 dataflow_set_destroy (&set);
3241}
3242
3243/* Emit notes for the whole function. */
3244
3245static void
3246vt_emit_notes (void)
3247{
3248 basic_block bb;
3249 dataflow_set *last_out;
3250 dataflow_set empty;
3251
fbc848cc 3252 gcc_assert (!htab_elements (changed_variables));
014a1138
JZ
3253
3254 /* Enable emitting notes by functions (mainly by set_variable_part and
3255 delete_variable_part). */
3256 emit_notes = true;
3257
d24686d7 3258 dataflow_set_init (&empty);
014a1138
JZ
3259 last_out = &empty;
3260
3261 FOR_EACH_BB (bb)
3262 {
3263 /* Emit the notes for changes of variable locations between two
3264 subsequent basic blocks. */
3265 emit_notes_for_differences (BB_HEAD (bb), last_out, &VTI (bb)->in);
3266
3267 /* Emit the notes for the changes in the basic block itself. */
3268 emit_notes_in_bb (bb);
3269
3270 last_out = &VTI (bb)->out;
3271 }
3272 dataflow_set_destroy (&empty);
3273 emit_notes = false;
3274}
3275
3276/* If there is a declaration and offset associated with register/memory RTL
3277 assign declaration to *DECLP and offset to *OFFSETP, and return true. */
3278
3279static bool
3280vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
3281{
f8cfc6aa 3282 if (REG_P (rtl))
014a1138
JZ
3283 {
3284 if (REG_ATTRS (rtl))
3285 {
3286 *declp = REG_EXPR (rtl);
3287 *offsetp = REG_OFFSET (rtl);
3288 return true;
3289 }
3290 }
3c0cb5de 3291 else if (MEM_P (rtl))
014a1138
JZ
3292 {
3293 if (MEM_ATTRS (rtl))
3294 {
3295 *declp = MEM_EXPR (rtl);
8c6c36a3 3296 *offsetp = INT_MEM_OFFSET (rtl);
014a1138
JZ
3297 return true;
3298 }
3299 }
3300 return false;
3301}
3302
3303/* Insert function parameters to IN and OUT sets of ENTRY_BLOCK. */
3304
3305static void
3306vt_add_function_parameters (void)
3307{
3308 tree parm;
014a1138 3309
014a1138
JZ
3310 for (parm = DECL_ARGUMENTS (current_function_decl);
3311 parm; parm = TREE_CHAIN (parm))
3312 {
3313 rtx decl_rtl = DECL_RTL_IF_SET (parm);
3314 rtx incoming = DECL_INCOMING_RTL (parm);
3315 tree decl;
38ae7651 3316 enum machine_mode mode;
014a1138 3317 HOST_WIDE_INT offset;
81f2eadb 3318 dataflow_set *out;
014a1138
JZ
3319
3320 if (TREE_CODE (parm) != PARM_DECL)
3321 continue;
3322
3323 if (!DECL_NAME (parm))
3324 continue;
3325
3326 if (!decl_rtl || !incoming)
3327 continue;
3328
3329 if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
3330 continue;
3331
3332 if (!vt_get_decl_and_offset (incoming, &decl, &offset))
38ae7651
RS
3333 {
3334 if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
3335 continue;
3336 offset += byte_lowpart_offset (GET_MODE (incoming),
3337 GET_MODE (decl_rtl));
3338 }
014a1138
JZ
3339
3340 if (!decl)
3341 continue;
3342
3d7e23f6
RH
3343 if (parm != decl)
3344 {
3345 /* Assume that DECL_RTL was a pseudo that got spilled to
3346 memory. The spill slot sharing code will force the
3347 memory to reference spill_slot_decl (%sfp), so we don't
3348 match above. That's ok, the pseudo must have referenced
3349 the entire parameter, so just reset OFFSET. */
3350 gcc_assert (decl == get_spill_slot_decl (false));
3351 offset = 0;
3352 }
014a1138 3353
38ae7651
RS
3354 if (!track_loc_p (incoming, parm, offset, false, &mode, &offset))
3355 continue;
3356
014a1138
JZ
3357 out = &VTI (ENTRY_BLOCK_PTR)->out;
3358
f8cfc6aa 3359 if (REG_P (incoming))
014a1138 3360 {
38ae7651 3361 incoming = var_lowpart (mode, incoming);
fbc848cc 3362 gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
014a1138
JZ
3363 attrs_list_insert (&out->regs[REGNO (incoming)],
3364 parm, offset, incoming);
62760ffd
CT
3365 set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED,
3366 NULL);
014a1138 3367 }
3c0cb5de 3368 else if (MEM_P (incoming))
38ae7651
RS
3369 {
3370 incoming = var_lowpart (mode, incoming);
3371 set_variable_part (out, incoming, parm, offset,
3372 VAR_INIT_STATUS_INITIALIZED, NULL);
3373 }
014a1138
JZ
3374 }
3375}
3376
3377/* Allocate and initialize the data structures for variable tracking
3378 and parse the RTL to get the micro operations. */
3379
3380static void
3381vt_initialize (void)
3382{
3383 basic_block bb;
3384
3385 alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
3386
3387 FOR_EACH_BB (bb)
3388 {
3389 rtx insn;
7b39f38b 3390 HOST_WIDE_INT pre, post = 0;
014a1138
JZ
3391
3392 /* Count the number of micro operations. */
3393 VTI (bb)->n_mos = 0;
3394 for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
3395 insn = NEXT_INSN (insn))
3396 {
3397 if (INSN_P (insn))
3398 {
3399 if (!frame_pointer_needed)
3400 {
3401 insn_stack_adjust_offset_pre_post (insn, &pre, &post);
3402 if (pre)
3403 VTI (bb)->n_mos++;
3404 if (post)
3405 VTI (bb)->n_mos++;
3406 }
3407 note_uses (&PATTERN (insn), count_uses_1, insn);
3408 note_stores (PATTERN (insn), count_stores, insn);
4b4bf941 3409 if (CALL_P (insn))
014a1138
JZ
3410 VTI (bb)->n_mos++;
3411 }
3412 }
3413
fb0840fc 3414 /* Add the micro-operations to the array. */
5ed6ace5 3415 VTI (bb)->mos = XNEWVEC (micro_operation, VTI (bb)->n_mos);
014a1138
JZ
3416 VTI (bb)->n_mos = 0;
3417 for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
3418 insn = NEXT_INSN (insn))
3419 {
3420 if (INSN_P (insn))
3421 {
3422 int n1, n2;
3423
3424 if (!frame_pointer_needed)
3425 {
3426 insn_stack_adjust_offset_pre_post (insn, &pre, &post);
3427 if (pre)
3428 {
3429 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
3430
3431 mo->type = MO_ADJUST;
3432 mo->u.adjust = pre;
3433 mo->insn = insn;
3434 }
3435 }
3436
3437 n1 = VTI (bb)->n_mos;
3438 note_uses (&PATTERN (insn), add_uses_1, insn);
3439 n2 = VTI (bb)->n_mos - 1;
3440
3441 /* Order the MO_USEs to be before MO_USE_NO_VARs. */
3442 while (n1 < n2)
3443 {
3444 while (n1 < n2 && VTI (bb)->mos[n1].type == MO_USE)
3445 n1++;
3446 while (n1 < n2 && VTI (bb)->mos[n2].type == MO_USE_NO_VAR)
3447 n2--;
3448 if (n1 < n2)
3449 {
3450 micro_operation sw;
3451
3452 sw = VTI (bb)->mos[n1];
3453 VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
3454 VTI (bb)->mos[n2] = sw;
3455 }
3456 }
3457
4b4bf941 3458 if (CALL_P (insn))
014a1138
JZ
3459 {
3460 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
3461
3462 mo->type = MO_CALL;
3463 mo->insn = insn;
3464 }
3465
3466 n1 = VTI (bb)->n_mos;
dedc1e6d
AO
3467 /* This will record NEXT_INSN (insn), such that we can
3468 insert notes before it without worrying about any
3469 notes that MO_USEs might emit after the insn. */
014a1138
JZ
3470 note_stores (PATTERN (insn), add_stores, insn);
3471 n2 = VTI (bb)->n_mos - 1;
3472
dedc1e6d 3473 /* Order the MO_CLOBBERs to be before MO_SETs. */
014a1138
JZ
3474 while (n1 < n2)
3475 {
dedc1e6d 3476 while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
014a1138 3477 n1++;
ca787200
AO
3478 while (n1 < n2 && (VTI (bb)->mos[n2].type == MO_SET
3479 || VTI (bb)->mos[n2].type == MO_COPY))
014a1138
JZ
3480 n2--;
3481 if (n1 < n2)
3482 {
3483 micro_operation sw;
3484
3485 sw = VTI (bb)->mos[n1];
3486 VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
3487 VTI (bb)->mos[n2] = sw;
3488 }
3489 }
3490
3491 if (!frame_pointer_needed && post)
3492 {
3493 micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
3494
3495 mo->type = MO_ADJUST;
3496 mo->u.adjust = post;
3497 mo->insn = insn;
3498 }
3499 }
3500 }
3501 }
3502
014a1138
JZ
3503 attrs_pool = create_alloc_pool ("attrs_def pool",
3504 sizeof (struct attrs_def), 1024);
3505 var_pool = create_alloc_pool ("variable_def pool",
3506 sizeof (struct variable_def), 64);
3507 loc_chain_pool = create_alloc_pool ("location_chain_def pool",
3508 sizeof (struct location_chain_def),
3509 1024);
d24686d7
JJ
3510 shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
3511 sizeof (struct shared_hash_def), 256);
3512 empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
3513 empty_shared_hash->refcount = 1;
3514 empty_shared_hash->htab
3515 = htab_create (1, variable_htab_hash, variable_htab_eq,
3516 variable_htab_free);
014a1138 3517 changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
d24686d7
JJ
3518 variable_htab_free);
3519
3520 /* Init the IN and OUT sets. */
3521 FOR_ALL_BB (bb)
3522 {
3523 VTI (bb)->visited = false;
3524 dataflow_set_init (&VTI (bb)->in);
3525 dataflow_set_init (&VTI (bb)->out);
3526 }
3527
014a1138 3528 vt_add_function_parameters ();
014a1138
JZ
3529}
3530
3531/* Free the data structures needed for variable tracking. */
3532
3533static void
3534vt_finalize (void)
3535{
3536 basic_block bb;
3537
3538 FOR_EACH_BB (bb)
3539 {
3540 free (VTI (bb)->mos);
3541 }
3542
3543 FOR_ALL_BB (bb)
3544 {
3545 dataflow_set_destroy (&VTI (bb)->in);
3546 dataflow_set_destroy (&VTI (bb)->out);
3547 }
3548 free_aux_for_blocks ();
d24686d7
JJ
3549 htab_delete (empty_shared_hash->htab);
3550 htab_delete (changed_variables);
014a1138
JZ
3551 free_alloc_pool (attrs_pool);
3552 free_alloc_pool (var_pool);
3553 free_alloc_pool (loc_chain_pool);
d24686d7 3554 free_alloc_pool (shared_hash_pool);
014a1138
JZ
3555}
3556
3557/* The entry point to variable tracking pass. */
3558
c2924966 3559unsigned int
014a1138
JZ
3560variable_tracking_main (void)
3561{
3562 if (n_basic_blocks > 500 && n_edges / n_basic_blocks >= 20)
c2924966 3563 return 0;
014a1138
JZ
3564
3565 mark_dfs_back_edges ();
3566 vt_initialize ();
3567 if (!frame_pointer_needed)
3568 {
3569 if (!vt_stack_adjustments ())
3570 {
3571 vt_finalize ();
c2924966 3572 return 0;
014a1138
JZ
3573 }
3574 }
3575
3576 vt_find_locations ();
3577 vt_emit_notes ();
3578
5b4fdb20 3579 if (dump_file && (dump_flags & TDF_DETAILS))
014a1138
JZ
3580 {
3581 dump_dataflow_sets ();
5b4fdb20 3582 dump_flow_info (dump_file, dump_flags);
014a1138
JZ
3583 }
3584
3585 vt_finalize ();
c2924966 3586 return 0;
014a1138 3587}
ef330312
PB
3588\f
3589static bool
3590gate_handle_var_tracking (void)
3591{
3592 return (flag_var_tracking);
3593}
3594
3595
3596
8ddbbcae 3597struct rtl_opt_pass pass_variable_tracking =
ef330312 3598{
8ddbbcae
JH
3599 {
3600 RTL_PASS,
ef330312
PB
3601 "vartrack", /* name */
3602 gate_handle_var_tracking, /* gate */
3603 variable_tracking_main, /* execute */
3604 NULL, /* sub */
3605 NULL, /* next */
3606 0, /* static_pass_number */
3607 TV_VAR_TRACKING, /* tv_id */
3608 0, /* properties_required */
3609 0, /* properties_provided */
3610 0, /* properties_destroyed */
3611 0, /* todo_flags_start */
8ddbbcae
JH
3612 TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
3613 }
ef330312 3614};