aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/var-tracking.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/var-tracking.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/var-tracking.c3463
1 files changed, 0 insertions, 3463 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/var-tracking.c b/gcc-4.2.1-5666.3/gcc/var-tracking.c
deleted file mode 100644
index 7fc631e4d..000000000
--- a/gcc-4.2.1-5666.3/gcc/var-tracking.c
+++ /dev/null
@@ -1,3463 +0,0 @@
-/* Variable tracking routines for the GNU compiler.
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
-
- This file is part of GCC.
-
- GCC is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GCC is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
-
-/* This file contains the variable tracking pass. It computes where
- variables are located (which registers or where in memory) at each position
- in instruction stream and emits notes describing the locations.
- Debug information (DWARF2 location lists) is finally generated from
- these notes.
- With this debug information, it is possible to show variables
- even when debugging optimized code.
-
- How does the variable tracking pass work?
-
- First, it scans RTL code for uses, stores and clobbers (register/memory
- references in instructions), for call insns and for stack adjustments
- separately for each basic block and saves them to an array of micro
- operations.
- The micro operations of one instruction are ordered so that
- pre-modifying stack adjustment < use < use with no var < call insn <
- < set < clobber < post-modifying stack adjustment
-
- Then, a forward dataflow analysis is performed to find out how locations
- of variables change through code and to propagate the variable locations
- along control flow graph.
- The IN set for basic block BB is computed as a union of OUT sets of BB's
- predecessors, the OUT set for BB is copied from the IN set for BB and
- is changed according to micro operations in BB.
-
- The IN and OUT sets for basic blocks consist of a current stack adjustment
- (used for adjusting offset of variables addressed using stack pointer),
- the table of structures describing the locations of parts of a variable
- and for each physical register a linked list for each physical register.
- The linked list is a list of variable parts stored in the register,
- i.e. it is a list of triplets (reg, decl, offset) where decl is
- REG_EXPR (reg) and offset is REG_OFFSET (reg). The linked list is used for
- effective deleting appropriate variable parts when we set or clobber the
- register.
-
- There may be more than one variable part in a register. The linked lists
- should be pretty short so it is a good data structure here.
- For example in the following code, register allocator may assign same
- register to variables A and B, and both of them are stored in the same
- register in CODE:
-
- if (cond)
- set A;
- else
- set B;
- CODE;
- if (cond)
- use A;
- else
- use B;
-
- Finally, the NOTE_INSN_VAR_LOCATION notes describing the variable locations
- are emitted to appropriate positions in RTL code. Each such a note describes
- the location of one variable at the point in instruction stream where the
- note is. There is no need to emit a note for each variable before each
- instruction, we only emit these notes where the location of variable changes
- (this means that we also emit notes for changes between the OUT set of the
- previous block and the IN set of the current block).
-
- The notes consist of two parts:
- 1. the declaration (from REG_EXPR or MEM_EXPR)
- 2. the location of a variable - it is either a simple register/memory
- reference (for simple variables, for example int),
- or a parallel of register/memory references (for a large variables
- which consist of several parts, for example long long).
-
-*/
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "rtl.h"
-#include "tree.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
-#include "flags.h"
-#include "output.h"
-#include "insn-config.h"
-#include "reload.h"
-#include "sbitmap.h"
-#include "alloc-pool.h"
-#include "fibheap.h"
-#include "hashtab.h"
-#include "regs.h"
-#include "expr.h"
-#include "timevar.h"
-#include "tree-pass.h"
-/* APPLE LOCAL 6414738 */
-#include "langhooks.h"
-
-/* Type of micro operation. */
-enum micro_operation_type
-{
- MO_USE, /* Use location (REG or MEM). */
- MO_USE_NO_VAR,/* Use location which is not associated with a variable
- or the variable is not trackable. */
- MO_SET, /* Set location. */
- MO_COPY, /* Copy the same portion of a variable from one
- location to another. */
- MO_CLOBBER, /* Clobber location. */
- MO_CALL, /* Call insn. */
- MO_ADJUST /* Adjust stack pointer. */
-};
-
-/* Where shall the note be emitted? BEFORE or AFTER the instruction. */
-enum emit_note_where
-{
- EMIT_NOTE_BEFORE_INSN,
- EMIT_NOTE_AFTER_INSN
-};
-
-/* Structure holding information about micro operation. */
-typedef struct micro_operation_def
-{
- /* Type of micro operation. */
- enum micro_operation_type type;
-
- union {
- /* Location. */
- rtx loc;
-
- /* Stack adjustment. */
- HOST_WIDE_INT adjust;
- } u;
-
- /* The instruction which the micro operation is in, for MO_USE,
- MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
- instruction or note in the original flow (before any var-tracking
- notes are inserted, to simplify emission of notes), for MO_SET
- and MO_CLOBBER. */
- rtx insn;
-} micro_operation;
-
-/* Structure for passing some other parameters to function
- emit_note_insn_var_location. */
-typedef struct emit_note_data_def
-{
- /* The instruction which the note will be emitted before/after. */
- rtx insn;
-
- /* Where the note will be emitted (before/after insn)? */
- enum emit_note_where where;
-} emit_note_data;
-
-/* Description of location of a part of a variable. The content of a physical
- register is described by a chain of these structures.
- The chains are pretty short (usually 1 or 2 elements) and thus
- chain is the best data structure. */
-typedef struct attrs_def
-{
- /* Pointer to next member of the list. */
- struct attrs_def *next;
-
- /* The rtx of register. */
- rtx loc;
-
- /* The declaration corresponding to LOC. */
- tree decl;
-
- /* Offset from start of DECL. */
- HOST_WIDE_INT offset;
-} *attrs;
-
-/* Structure holding the IN or OUT set for a basic block. */
-typedef struct dataflow_set_def
-{
- /* Adjustment of stack offset. */
- HOST_WIDE_INT stack_adjust;
-
- /* Attributes for registers (lists of attrs). */
- attrs regs[FIRST_PSEUDO_REGISTER];
-
- /* Variable locations. */
- htab_t vars;
-} dataflow_set;
-
-/* The structure (one for each basic block) containing the information
- needed for variable tracking. */
-typedef struct variable_tracking_info_def
-{
- /* Number of micro operations stored in the MOS array. */
- int n_mos;
-
- /* The array of micro operations. */
- micro_operation *mos;
-
- /* The IN and OUT set for dataflow analysis. */
- dataflow_set in;
- dataflow_set out;
-
- /* Has the block been visited in DFS? */
- bool visited;
-} *variable_tracking_info;
-
-/* Structure for chaining the locations. */
-typedef struct location_chain_def
-{
- /* Next element in the chain. */
- struct location_chain_def *next;
-
- /* The location (REG or MEM). */
- rtx loc;
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- /* The "value" stored in this location. */
- rtx set_src;
-
- /* Initialized? */
- enum var_init_status init;
- /* APPLE LOCAL end track initialization status 4964532 */
-} *location_chain;
-
-/* Structure describing one part of variable. */
-typedef struct variable_part_def
-{
- /* Chain of locations of the part. */
- location_chain loc_chain;
-
- /* Location which was last emitted to location list. */
- rtx cur_loc;
-
- /* The offset in the variable. */
- HOST_WIDE_INT offset;
-} variable_part;
-
-/* Maximum number of location parts. */
-#define MAX_VAR_PARTS 16
-
-/* Structure describing where the variable is located. */
-typedef struct variable_def
-{
- /* The declaration of the variable. */
- tree decl;
-
- /* Reference count. */
- int refcount;
-
- /* Number of variable parts. */
- int n_var_parts;
-
- /* The variable parts. */
- variable_part var_part[MAX_VAR_PARTS];
-} *variable;
-
-/* Hash function for DECL for VARIABLE_HTAB. */
-#define VARIABLE_HASH_VAL(decl) (DECL_UID (decl))
-
-/* Pointer to the BB's information specific to variable tracking pass. */
-#define VTI(BB) ((variable_tracking_info) (BB)->aux)
-
-/* Alloc pool for struct attrs_def. */
-static alloc_pool attrs_pool;
-
-/* Alloc pool for struct variable_def. */
-static alloc_pool var_pool;
-
-/* Alloc pool for struct location_chain_def. */
-static alloc_pool loc_chain_pool;
-
-/* Changed variables, notes will be emitted for them. */
-static htab_t changed_variables;
-
-/* Shall notes be emitted? */
-static bool emit_notes;
-
-/* Local function prototypes. */
-static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
- HOST_WIDE_INT *);
-static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
- HOST_WIDE_INT *);
-static void bb_stack_adjust_offset (basic_block);
-static bool vt_stack_adjustments (void);
-static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
-static hashval_t variable_htab_hash (const void *);
-static int variable_htab_eq (const void *, const void *);
-static void variable_htab_free (void *);
-
-static void init_attrs_list_set (attrs *);
-static void attrs_list_clear (attrs *);
-static attrs attrs_list_member (attrs, tree, HOST_WIDE_INT);
-static void attrs_list_insert (attrs *, tree, HOST_WIDE_INT, rtx);
-static void attrs_list_copy (attrs *, attrs);
-static void attrs_list_union (attrs *, attrs);
-
-static void vars_clear (htab_t);
-/* APPLE LOCAL begin track initialization status 4964532 */
-static variable unshare_variable (dataflow_set *set, variable var,
- enum var_init_status);
-static int vars_copy_1 (void **, void *);
-static void vars_copy (htab_t, htab_t);
-static tree var_debug_decl (tree);
-static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
-static void var_reg_delete_and_set (dataflow_set *, rtx, bool,
- enum var_init_status, rtx);
-static void var_reg_delete (dataflow_set *, rtx, bool);
-static void var_regno_delete (dataflow_set *, int);
-static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx);
-static void var_mem_delete_and_set (dataflow_set *, rtx, bool,
- enum var_init_status, rtx);
-/* APPLE LOCAL end track initialization status 4964532 */
-static void var_mem_delete (dataflow_set *, rtx, bool);
-
-static void dataflow_set_init (dataflow_set *, int);
-static void dataflow_set_clear (dataflow_set *);
-static void dataflow_set_copy (dataflow_set *, dataflow_set *);
-static int variable_union_info_cmp_pos (const void *, const void *);
-static int variable_union (void **, void *);
-static void dataflow_set_union (dataflow_set *, dataflow_set *);
-static bool variable_part_different_p (variable_part *, variable_part *);
-static bool variable_different_p (variable, variable, bool);
-static int dataflow_set_different_1 (void **, void *);
-static int dataflow_set_different_2 (void **, void *);
-static bool dataflow_set_different (dataflow_set *, dataflow_set *);
-static void dataflow_set_destroy (dataflow_set *);
-
-static bool contains_symbol_ref (rtx);
-static bool track_expr_p (tree);
-static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
-static int count_uses (rtx *, void *);
-static void count_uses_1 (rtx *, void *);
-static void count_stores (rtx, rtx, void *);
-static int add_uses (rtx *, void *);
-static void add_uses_1 (rtx *, void *);
-static void add_stores (rtx, rtx, void *);
-static bool compute_bb_dataflow (basic_block);
-static void vt_find_locations (void);
-
-static void dump_attrs_list (attrs);
-static int dump_variable (void **, void *);
-static void dump_vars (htab_t);
-static void dump_dataflow_set (dataflow_set *);
-static void dump_dataflow_sets (void);
-
-static void variable_was_changed (variable, htab_t);
-/* APPLE LOCAL begin track initialization status 4964532 */
-static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
- enum var_init_status, rtx);
-static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
- rtx);
-/* APPLE LOCAL end track initialization status 4964532 */
-static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
-static int emit_note_insn_var_location (void **, void *);
-static void emit_notes_for_changes (rtx, enum emit_note_where);
-static int emit_notes_for_differences_1 (void **, void *);
-static int emit_notes_for_differences_2 (void **, void *);
-static void emit_notes_for_differences (rtx, dataflow_set *, dataflow_set *);
-static void emit_notes_in_bb (basic_block);
-static void vt_emit_notes (void);
-
-static bool vt_get_decl_and_offset (rtx, tree *, HOST_WIDE_INT *);
-static void vt_add_function_parameters (void);
-static void vt_initialize (void);
-static void vt_finalize (void);
-
-/* Given a SET, calculate the amount of stack adjustment it contains
- PRE- and POST-modifying stack pointer.
- This function is similar to stack_adjust_offset. */
-
-static void
-stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INT *pre,
- HOST_WIDE_INT *post)
-{
- rtx src = SET_SRC (pattern);
- rtx dest = SET_DEST (pattern);
- enum rtx_code code;
-
- if (dest == stack_pointer_rtx)
- {
- /* (set (reg sp) (plus (reg sp) (const_int))) */
- code = GET_CODE (src);
- if (! (code == PLUS || code == MINUS)
- || XEXP (src, 0) != stack_pointer_rtx
- || GET_CODE (XEXP (src, 1)) != CONST_INT)
- return;
-
- if (code == MINUS)
- *post += INTVAL (XEXP (src, 1));
- else
- *post -= INTVAL (XEXP (src, 1));
- }
- else if (MEM_P (dest))
- {
- /* (set (mem (pre_dec (reg sp))) (foo)) */
- src = XEXP (dest, 0);
- code = GET_CODE (src);
-
- switch (code)
- {
- case PRE_MODIFY:
- case POST_MODIFY:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- rtx val = XEXP (XEXP (src, 1), 1);
- /* We handle only adjustments by constant amount. */
- gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS &&
- GET_CODE (val) == CONST_INT);
-
- if (code == PRE_MODIFY)
- *pre -= INTVAL (val);
- else
- *post -= INTVAL (val);
- break;
- }
- return;
-
- case PRE_DEC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *pre += GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- case POST_DEC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *post += GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- case PRE_INC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *pre -= GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- case POST_INC:
- if (XEXP (src, 0) == stack_pointer_rtx)
- {
- *post -= GET_MODE_SIZE (GET_MODE (dest));
- break;
- }
- return;
-
- default:
- return;
- }
- }
-}
-
-/* Given an INSN, calculate the amount of stack adjustment it contains
- PRE- and POST-modifying stack pointer. */
-
-static void
-insn_stack_adjust_offset_pre_post (rtx insn, HOST_WIDE_INT *pre,
- HOST_WIDE_INT *post)
-{
- *pre = 0;
- *post = 0;
-
- if (GET_CODE (PATTERN (insn)) == SET)
- stack_adjust_offset_pre_post (PATTERN (insn), pre, post);
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- int i;
-
- /* There may be stack adjustments inside compound insns. Search
- for them. */
- for ( i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
- stack_adjust_offset_pre_post (XVECEXP (PATTERN (insn), 0, i),
- pre, post);
- }
-}
-
-/* Compute stack adjustment in basic block BB. */
-
-static void
-bb_stack_adjust_offset (basic_block bb)
-{
- HOST_WIDE_INT offset;
- int i;
-
- offset = VTI (bb)->in.stack_adjust;
- for (i = 0; i < VTI (bb)->n_mos; i++)
- {
- if (VTI (bb)->mos[i].type == MO_ADJUST)
- offset += VTI (bb)->mos[i].u.adjust;
- else if (VTI (bb)->mos[i].type != MO_CALL)
- {
- if (MEM_P (VTI (bb)->mos[i].u.loc))
- {
- VTI (bb)->mos[i].u.loc
- = adjust_stack_reference (VTI (bb)->mos[i].u.loc, -offset);
- }
- }
- }
- VTI (bb)->out.stack_adjust = offset;
-}
-
-/* Compute stack adjustments for all blocks by traversing DFS tree.
- Return true when the adjustments on all incoming edges are consistent.
- Heavily borrowed from pre_and_rev_post_order_compute. */
-
-static bool
-vt_stack_adjustments (void)
-{
- edge_iterator *stack;
- int sp;
-
- /* Initialize entry block. */
- VTI (ENTRY_BLOCK_PTR)->visited = true;
- VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
-
- /* Allocate stack for back-tracking up CFG. */
- stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
- sp = 0;
-
- /* Push the first edge on to the stack. */
- stack[sp++] = ei_start (ENTRY_BLOCK_PTR->succs);
-
- while (sp)
- {
- edge_iterator ei;
- basic_block src;
- basic_block dest;
-
- /* Look at the edge on the top of the stack. */
- ei = stack[sp - 1];
- src = ei_edge (ei)->src;
- dest = ei_edge (ei)->dest;
-
- /* Check if the edge destination has been visited yet. */
- if (!VTI (dest)->visited)
- {
- VTI (dest)->visited = true;
- VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
- bb_stack_adjust_offset (dest);
-
- if (EDGE_COUNT (dest->succs) > 0)
- /* Since the DEST node has been visited for the first
- time, check its successors. */
- stack[sp++] = ei_start (dest->succs);
- }
- else
- {
- /* Check whether the adjustments on the edges are the same. */
- if (VTI (dest)->in.stack_adjust != VTI (src)->out.stack_adjust)
- {
- free (stack);
- return false;
- }
-
- if (! ei_one_before_end_p (ei))
- /* Go to the next edge. */
- ei_next (&stack[sp - 1]);
- else
- /* Return to previous level if there are no more edges. */
- sp--;
- }
- }
-
- free (stack);
- return true;
-}
-
-/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
- to the argument pointer. Return the new rtx. */
-
-static rtx
-adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
-{
- rtx addr, cfa, tmp;
-
-#ifdef FRAME_POINTER_CFA_OFFSET
- adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
- cfa = plus_constant (frame_pointer_rtx, adjustment);
-#else
- adjustment -= ARG_POINTER_CFA_OFFSET (current_function_decl);
- cfa = plus_constant (arg_pointer_rtx, adjustment);
-#endif
-
- addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
- tmp = simplify_rtx (addr);
- if (tmp)
- addr = tmp;
-
- return replace_equiv_address_nv (mem, addr);
-}
-
-/* The hash function for variable_htab, computes the hash value
- from the declaration of variable X. */
-
-static hashval_t
-variable_htab_hash (const void *x)
-{
- const variable v = (const variable) x;
-
- return (VARIABLE_HASH_VAL (v->decl));
-}
-
-/* Compare the declaration of variable X with declaration Y. */
-
-static int
-variable_htab_eq (const void *x, const void *y)
-{
- const variable v = (const variable) x;
- const tree decl = (const tree) y;
-
- return (VARIABLE_HASH_VAL (v->decl) == VARIABLE_HASH_VAL (decl));
-}
-
-/* Free the element of VARIABLE_HTAB (its type is struct variable_def). */
-
-static void
-variable_htab_free (void *elem)
-{
- int i;
- variable var = (variable) elem;
- location_chain node, next;
-
- gcc_assert (var->refcount > 0);
-
- var->refcount--;
- if (var->refcount > 0)
- return;
-
- for (i = 0; i < var->n_var_parts; i++)
- {
- for (node = var->var_part[i].loc_chain; node; node = next)
- {
- next = node->next;
- pool_free (loc_chain_pool, node);
- }
- var->var_part[i].loc_chain = NULL;
- }
- pool_free (var_pool, var);
-}
-
-/* Initialize the set (array) SET of attrs to empty lists. */
-
-static void
-init_attrs_list_set (attrs *set)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- set[i] = NULL;
-}
-
-/* Make the list *LISTP empty. */
-
-static void
-attrs_list_clear (attrs *listp)
-{
- attrs list, next;
-
- for (list = *listp; list; list = next)
- {
- next = list->next;
- pool_free (attrs_pool, list);
- }
- *listp = NULL;
-}
-
-/* Return true if the pair of DECL and OFFSET is the member of the LIST. */
-
-static attrs
-attrs_list_member (attrs list, tree decl, HOST_WIDE_INT offset)
-{
- for (; list; list = list->next)
- if (list->decl == decl && list->offset == offset)
- return list;
- return NULL;
-}
-
-/* Insert the triplet DECL, OFFSET, LOC to the list *LISTP. */
-
-static void
-attrs_list_insert (attrs *listp, tree decl, HOST_WIDE_INT offset, rtx loc)
-{
- attrs list;
-
- list = pool_alloc (attrs_pool);
- list->loc = loc;
- list->decl = decl;
- list->offset = offset;
- list->next = *listp;
- *listp = list;
-}
-
-/* Copy all nodes from SRC and create a list *DSTP of the copies. */
-
-static void
-attrs_list_copy (attrs *dstp, attrs src)
-{
- attrs n;
-
- attrs_list_clear (dstp);
- for (; src; src = src->next)
- {
- n = pool_alloc (attrs_pool);
- n->loc = src->loc;
- n->decl = src->decl;
- n->offset = src->offset;
- n->next = *dstp;
- *dstp = n;
- }
-}
-
-/* Add all nodes from SRC which are not in *DSTP to *DSTP. */
-
-static void
-attrs_list_union (attrs *dstp, attrs src)
-{
- for (; src; src = src->next)
- {
- if (!attrs_list_member (*dstp, src->decl, src->offset))
- attrs_list_insert (dstp, src->decl, src->offset, src->loc);
- }
-}
-
-/* Delete all variables from hash table VARS. */
-
-static void
-vars_clear (htab_t vars)
-{
- htab_empty (vars);
-}
-
-/* Return a copy of a variable VAR and insert it to dataflow set SET. */
-
-/* APPLE LOCAL begin track initialization status 4964532 */
-static variable
-unshare_variable (dataflow_set *set, variable var,
- enum var_init_status initialized)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- void **slot;
- variable new_var;
- int i;
-
- new_var = pool_alloc (var_pool);
- new_var->decl = var->decl;
- new_var->refcount = 1;
- var->refcount--;
- new_var->n_var_parts = var->n_var_parts;
-
- for (i = 0; i < var->n_var_parts; i++)
- {
- location_chain node;
- location_chain *nextp;
-
- new_var->var_part[i].offset = var->var_part[i].offset;
- nextp = &new_var->var_part[i].loc_chain;
- for (node = var->var_part[i].loc_chain; node; node = node->next)
- {
- location_chain new_lc;
-
- new_lc = pool_alloc (loc_chain_pool);
- new_lc->next = NULL;
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (node->init > initialized)
- new_lc->init = node->init;
- else
- new_lc->init = initialized;
- if (node->set_src && !(MEM_P (node->set_src)))
- new_lc->set_src = node->set_src;
- else
- new_lc->set_src = NULL;
- /* APPLE LOCAL end track initialization status 4964532 */
- new_lc->loc = node->loc;
-
- *nextp = new_lc;
- nextp = &new_lc->next;
- }
-
- /* We are at the basic block boundary when copying variable description
- so set the CUR_LOC to be the first element of the chain. */
- if (new_var->var_part[i].loc_chain)
- new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
- else
- new_var->var_part[i].cur_loc = NULL;
- }
-
- slot = htab_find_slot_with_hash (set->vars, new_var->decl,
- VARIABLE_HASH_VAL (new_var->decl),
- INSERT);
- *slot = new_var;
- return new_var;
-}
-
-/* Add a variable from *SLOT to hash table DATA and increase its reference
- count. */
-
-static int
-vars_copy_1 (void **slot, void *data)
-{
- htab_t dst = (htab_t) data;
- variable src, *dstp;
-
- src = *(variable *) slot;
- src->refcount++;
-
- dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
- VARIABLE_HASH_VAL (src->decl),
- INSERT);
- *dstp = src;
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Copy all variables from hash table SRC to hash table DST. */
-
-static void
-vars_copy (htab_t dst, htab_t src)
-{
- vars_clear (dst);
- htab_traverse (src, vars_copy_1, dst);
-}
-
-/* Map a decl to its main debug decl. */
-
-static inline tree
-var_debug_decl (tree decl)
-{
- if (decl && DECL_P (decl)
- && DECL_DEBUG_EXPR_IS_FROM (decl) && DECL_DEBUG_EXPR (decl)
- && DECL_P (DECL_DEBUG_EXPR (decl)))
- decl = DECL_DEBUG_EXPR (decl);
-
- return decl;
-}
-
-/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */
-
-/* APPLE LOCAL begin track initialization status 4964532 */
-static void
-var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
- rtx set_src)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- tree decl = REG_EXPR (loc);
- HOST_WIDE_INT offset = REG_OFFSET (loc);
- attrs node;
-
- decl = var_debug_decl (decl);
-
- for (node = set->regs[REGNO (loc)]; node; node = node->next)
- if (node->decl == decl && node->offset == offset)
- break;
- if (!node)
- attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
- /* APPLE LOCAL begin track initialization status 4964532 */
- set_variable_part (set, loc, decl, offset, initialized, set_src);
-}
-
-static int
-get_init_value (dataflow_set *set, rtx loc, tree decl)
-{
- void **slot;
- variable var;
- int i;
- int ret_val = STATUS_UNKNOWN;
-
- if (! TARGET_DWARF_UNINIT_VARS)
- return STATUS_INITIALIZED;
-
- slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
- NO_INSERT);
- if (slot)
- {
- var = * (variable *) slot;
- for (i = 0; i < var->n_var_parts && ret_val == STATUS_UNKNOWN; i++)
- {
- location_chain nextp;
- for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next)
- if (rtx_equal_p (nextp->loc, loc))
- {
- ret_val = nextp->init;
- break;
- }
- }
- }
-
- return ret_val;
-}
-/* APPLE LOCAL end track initialization status 4964532 */
-
-/* Delete current content of register LOC in dataflow set SET and set
- the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If
- MODIFY is true, any other live copies of the same variable part are
- also deleted from the dataflow set, otherwise the variable part is
- assumed to be copied from another location holding the same
- part. */
-
-/* APPLE LOCAL begin track initialization status 4964532 */
-static void
-var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify,
- enum var_init_status initialized, rtx set_src)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- tree decl = REG_EXPR (loc);
- HOST_WIDE_INT offset = REG_OFFSET (loc);
- attrs node, next;
- attrs *nextp;
-
- decl = var_debug_decl (decl);
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (initialized == STATUS_UNKNOWN)
- initialized = get_init_value (set, loc, decl);
- /* APPLE LOCAL end track initialization status 4964532 */
-
- nextp = &set->regs[REGNO (loc)];
- for (node = *nextp; node; node = next)
- {
- next = node->next;
- if (node->decl != decl || node->offset != offset)
- {
- delete_variable_part (set, node->loc, node->decl, node->offset);
- pool_free (attrs_pool, node);
- *nextp = next;
- }
- else
- {
- node->loc = loc;
- nextp = &node->next;
- }
- }
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (modify)
- clobber_variable_part (set, loc, decl, offset, set_src);
- var_reg_set (set, loc, initialized, set_src);
- /* APPLE LOCAL end track initialization status 4964532 */
-}
-
-/* Delete current content of register LOC in dataflow set SET. If
- CLOBBER is true, also delete any other live copies of the same
- variable part. */
-
-static void
-var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
-{
- attrs *reg = &set->regs[REGNO (loc)];
- attrs node, next;
-
- if (clobber)
- {
- tree decl = REG_EXPR (loc);
- HOST_WIDE_INT offset = REG_OFFSET (loc);
-
- decl = var_debug_decl (decl);
-
- /* APPLE LOCAL track initialization status 4964532 */
- clobber_variable_part (set, NULL, decl, offset, NULL);
- }
-
- for (node = *reg; node; node = next)
- {
- next = node->next;
- delete_variable_part (set, node->loc, node->decl, node->offset);
- pool_free (attrs_pool, node);
- }
- *reg = NULL;
-}
-
-/* Delete content of register with number REGNO in dataflow set SET. */
-
-static void
-var_regno_delete (dataflow_set *set, int regno)
-{
- attrs *reg = &set->regs[regno];
- attrs node, next;
-
- for (node = *reg; node; node = next)
- {
- next = node->next;
- delete_variable_part (set, node->loc, node->decl, node->offset);
- pool_free (attrs_pool, node);
- }
- *reg = NULL;
-}
-
-/* Set the location part of variable MEM_EXPR (LOC) in dataflow set
- SET to LOC.
- Adjust the address first if it is stack pointer based. */
-
-/* APPLE LOCAL begin track initialization status 4964532 */
-static void
-var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
- rtx set_src)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- tree decl = MEM_EXPR (loc);
- HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
-
- decl = var_debug_decl (decl);
-
- /* APPLE LOCAL track initialization status 4964532 */
- set_variable_part (set, loc, decl, offset, initialized, set_src);
-}
-
-/* Delete and set the location part of variable MEM_EXPR (LOC) in
- dataflow set SET to LOC. If MODIFY is true, any other live copies
- of the same variable part are also deleted from the dataflow set,
- otherwise the variable part is assumed to be copied from another
- location holding the same part.
- Adjust the address first if it is stack pointer based. */
-
-/* APPLE LOCAL begin track initialization status 4964532 */
-static void
-var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify,
- enum var_init_status initialized, rtx set_src)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- tree decl = MEM_EXPR (loc);
- HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
-
- decl = var_debug_decl (decl);
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (initialized == STATUS_UNKNOWN)
- initialized = get_init_value (set, loc, decl);
-
- if (modify)
- clobber_variable_part (set, NULL, decl, offset, set_src);
- var_mem_set (set, loc, initialized, set_src);
- /* APPLE LOCAL end track initialization status 4964532 */
-}
-
-/* Delete the location part LOC from dataflow set SET. If CLOBBER is
- true, also delete any other live copies of the same variable part.
- Adjust the address first if it is stack pointer based. */
-
-static void
-var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
-{
- tree decl = MEM_EXPR (loc);
- HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
-
- decl = var_debug_decl (decl);
- if (clobber)
- /* APPLE LOCAL track initialization status 4964532 */
- clobber_variable_part (set, NULL, decl, offset, NULL);
- delete_variable_part (set, loc, decl, offset);
-}
-
-/* Initialize dataflow set SET to be empty.
- VARS_SIZE is the initial size of hash table VARS. */
-
-static void
-dataflow_set_init (dataflow_set *set, int vars_size)
-{
- init_attrs_list_set (set->regs);
- set->vars = htab_create (vars_size, variable_htab_hash, variable_htab_eq,
- variable_htab_free);
- set->stack_adjust = 0;
-}
-
-/* Delete the contents of dataflow set SET. */
-
-static void
-dataflow_set_clear (dataflow_set *set)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- attrs_list_clear (&set->regs[i]);
-
- vars_clear (set->vars);
-}
-
-/* Copy the contents of dataflow set SRC to DST. */
-
-static void
-dataflow_set_copy (dataflow_set *dst, dataflow_set *src)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- attrs_list_copy (&dst->regs[i], src->regs[i]);
-
- vars_copy (dst->vars, src->vars);
- dst->stack_adjust = src->stack_adjust;
-}
-
-/* Information for merging lists of locations for a given offset of variable.
- */
-struct variable_union_info
-{
- /* Node of the location chain. */
- location_chain lc;
-
- /* The sum of positions in the input chains. */
- int pos;
-
- /* The position in the chains of SRC and DST dataflow sets. */
- int pos_src;
- int pos_dst;
-};
-
-/* Compare function for qsort, order the structures by POS element. */
-
-static int
-variable_union_info_cmp_pos (const void *n1, const void *n2)
-{
- const struct variable_union_info *i1 = n1;
- const struct variable_union_info *i2 = n2;
-
- if (i1->pos != i2->pos)
- return i1->pos - i2->pos;
-
- return (i1->pos_dst - i2->pos_dst);
-}
-
-/* Compute union of location parts of variable *SLOT and the same variable
- from hash table DATA. Compute "sorted" union of the location chains
- for common offsets, i.e. the locations of a variable part are sorted by
- a priority where the priority is the sum of the positions in the 2 chains
- (if a location is only in one list the position in the second list is
- defined to be larger than the length of the chains).
- When we are updating the location parts the newest location is in the
- beginning of the chain, so when we do the described "sorted" union
- we keep the newest locations in the beginning. */
-
-static int
-variable_union (void **slot, void *data)
-{
- variable src, dst, *dstp;
- dataflow_set *set = (dataflow_set *) data;
- int i, j, k;
-
- src = *(variable *) slot;
- dstp = (variable *) htab_find_slot_with_hash (set->vars, src->decl,
- VARIABLE_HASH_VAL (src->decl),
- INSERT);
- if (!*dstp)
- {
- src->refcount++;
-
- /* If CUR_LOC of some variable part is not the first element of
- the location chain we are going to change it so we have to make
- a copy of the variable. */
- for (k = 0; k < src->n_var_parts; k++)
- {
- gcc_assert (!src->var_part[k].loc_chain
- == !src->var_part[k].cur_loc);
- if (src->var_part[k].loc_chain)
- {
- gcc_assert (src->var_part[k].cur_loc);
- if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
- break;
- }
- }
- if (k < src->n_var_parts)
- /* APPLE LOCAL begin track initialization status 4964532 */
- {
- enum var_init_status status = STATUS_UNKNOWN;
-
- if (! TARGET_DWARF_UNINIT_VARS)
- status = STATUS_INITIALIZED;
-
- unshare_variable (set, src, status);
- }
- /* APPLE LOCAL end track initialization status 4964532 */
- else
- *dstp = src;
-
- /* Continue traversing the hash table. */
- return 1;
- }
- else
- dst = *dstp;
-
- gcc_assert (src->n_var_parts);
-
- /* Count the number of location parts, result is K. */
- for (i = 0, j = 0, k = 0;
- i < src->n_var_parts && j < dst->n_var_parts; k++)
- {
- if (src->var_part[i].offset == dst->var_part[j].offset)
- {
- i++;
- j++;
- }
- else if (src->var_part[i].offset < dst->var_part[j].offset)
- i++;
- else
- j++;
- }
- k += src->n_var_parts - i;
- k += dst->n_var_parts - j;
-
- /* We track only variables whose size is <= MAX_VAR_PARTS bytes
- thus there are at most MAX_VAR_PARTS different offsets. */
- gcc_assert (k <= MAX_VAR_PARTS);
-
- if (dst->refcount > 1 && dst->n_var_parts != k)
- /* APPLE LOCAL begin track initialization status 4964532 */
- {
- enum var_init_status status = STATUS_UNKNOWN;
-
- if (! TARGET_DWARF_UNINIT_VARS)
- status = STATUS_INITIALIZED;
- dst = unshare_variable (set, dst, status);
- }
- /* APPLE LOCAL end track initialization status 4964532 */
-
- i = src->n_var_parts - 1;
- j = dst->n_var_parts - 1;
- dst->n_var_parts = k;
-
- for (k--; k >= 0; k--)
- {
- location_chain node, node2;
-
- if (i >= 0 && j >= 0
- && src->var_part[i].offset == dst->var_part[j].offset)
- {
- /* Compute the "sorted" union of the chains, i.e. the locations which
- are in both chains go first, they are sorted by the sum of
- positions in the chains. */
- int dst_l, src_l;
- int ii, jj, n;
- struct variable_union_info *vui;
-
- /* If DST is shared compare the location chains.
- If they are different we will modify the chain in DST with
- high probability so make a copy of DST. */
- if (dst->refcount > 1)
- {
- for (node = src->var_part[i].loc_chain,
- node2 = dst->var_part[j].loc_chain; node && node2;
- node = node->next, node2 = node2->next)
- {
- if (!((REG_P (node2->loc)
- && REG_P (node->loc)
- && REGNO (node2->loc) == REGNO (node->loc))
- || rtx_equal_p (node2->loc, node->loc)))
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (node2->init < node->init)
- node2->init = node->init;
- /* APPLE LOCAL end track initialization status 4964532 */
- break;
- }
- if (node || node2)
- /* APPLE LOCAL track initialization status 4964532 */
- dst = unshare_variable (set, dst, STATUS_UNKNOWN);
- }
-
- src_l = 0;
- for (node = src->var_part[i].loc_chain; node; node = node->next)
- src_l++;
- dst_l = 0;
- for (node = dst->var_part[j].loc_chain; node; node = node->next)
- dst_l++;
- vui = XCNEWVEC (struct variable_union_info, src_l + dst_l);
-
- /* Fill in the locations from DST. */
- for (node = dst->var_part[j].loc_chain, jj = 0; node;
- node = node->next, jj++)
- {
- vui[jj].lc = node;
- vui[jj].pos_dst = jj;
-
- /* Value larger than a sum of 2 valid positions. */
- vui[jj].pos_src = src_l + dst_l;
- }
-
- /* Fill in the locations from SRC. */
- n = dst_l;
- for (node = src->var_part[i].loc_chain, ii = 0; node;
- node = node->next, ii++)
- {
- /* Find location from NODE. */
- for (jj = 0; jj < dst_l; jj++)
- {
- if ((REG_P (vui[jj].lc->loc)
- && REG_P (node->loc)
- && REGNO (vui[jj].lc->loc) == REGNO (node->loc))
- || rtx_equal_p (vui[jj].lc->loc, node->loc))
- {
- vui[jj].pos_src = ii;
- break;
- }
- }
- if (jj >= dst_l) /* The location has not been found. */
- {
- location_chain new_node;
-
- /* Copy the location from SRC. */
- new_node = pool_alloc (loc_chain_pool);
- new_node->loc = node->loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- new_node->init = node->init;
- if (!node->set_src || MEM_P (node->set_src))
- new_node->set_src = NULL;
- else
- new_node->set_src = node->set_src;
- /* APPLE LOCAL end track initialization status 4964532 */
- vui[n].lc = new_node;
- vui[n].pos_src = ii;
- vui[n].pos_dst = src_l + dst_l;
- n++;
- }
- }
-
- for (ii = 0; ii < src_l + dst_l; ii++)
- vui[ii].pos = vui[ii].pos_src + vui[ii].pos_dst;
-
- qsort (vui, n, sizeof (struct variable_union_info),
- variable_union_info_cmp_pos);
-
- /* Reconnect the nodes in sorted order. */
- for (ii = 1; ii < n; ii++)
- vui[ii - 1].lc->next = vui[ii].lc;
- vui[n - 1].lc->next = NULL;
-
- dst->var_part[k].loc_chain = vui[0].lc;
- dst->var_part[k].offset = dst->var_part[j].offset;
-
- free (vui);
- i--;
- j--;
- }
- else if ((i >= 0 && j >= 0
- && src->var_part[i].offset < dst->var_part[j].offset)
- || i < 0)
- {
- dst->var_part[k] = dst->var_part[j];
- j--;
- }
- else if ((i >= 0 && j >= 0
- && src->var_part[i].offset > dst->var_part[j].offset)
- || j < 0)
- {
- location_chain *nextp;
-
- /* Copy the chain from SRC. */
- nextp = &dst->var_part[k].loc_chain;
- for (node = src->var_part[i].loc_chain; node; node = node->next)
- {
- location_chain new_lc;
-
- new_lc = pool_alloc (loc_chain_pool);
- new_lc->next = NULL;
- /* APPLE LOCAL begin track initialization status 4964532 */
- new_lc->init = node->init;
- if (!node->set_src || MEM_P (node->set_src))
- new_lc->set_src = NULL;
- else
- new_lc->set_src = node->set_src;
- /* APPLE LOCAL end track initialization status 4964532 */
- new_lc->loc = node->loc;
-
- *nextp = new_lc;
- nextp = &new_lc->next;
- }
-
- dst->var_part[k].offset = src->var_part[i].offset;
- i--;
- }
-
- /* We are at the basic block boundary when computing union
- so set the CUR_LOC to be the first element of the chain. */
- if (dst->var_part[k].loc_chain)
- dst->var_part[k].cur_loc = dst->var_part[k].loc_chain->loc;
- else
- dst->var_part[k].cur_loc = NULL;
- }
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++)
- {
- location_chain node, node2;
- for (node = src->var_part[i].loc_chain; node; node = node->next)
- for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next)
- if (rtx_equal_p (node->loc, node2->loc))
- {
- if (node->init > node2->init)
- node2->init = node->init;
- }
- }
- /* APPLE LOCAL end track initialization status 4964532 */
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Compute union of dataflow sets SRC and DST and store it to DST. */
-
-static void
-dataflow_set_union (dataflow_set *dst, dataflow_set *src)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- attrs_list_union (&dst->regs[i], src->regs[i]);
-
- htab_traverse (src->vars, variable_union, dst);
-}
-
-/* Flag whether two dataflow sets being compared contain different data. */
-static bool
-dataflow_set_different_value;
-
-static bool
-variable_part_different_p (variable_part *vp1, variable_part *vp2)
-{
- location_chain lc1, lc2;
-
- for (lc1 = vp1->loc_chain; lc1; lc1 = lc1->next)
- {
- for (lc2 = vp2->loc_chain; lc2; lc2 = lc2->next)
- {
- if (REG_P (lc1->loc) && REG_P (lc2->loc))
- {
- if (REGNO (lc1->loc) == REGNO (lc2->loc))
- break;
- }
- if (rtx_equal_p (lc1->loc, lc2->loc))
- break;
- }
- if (!lc2)
- return true;
- }
- return false;
-}
-
-/* Return true if variables VAR1 and VAR2 are different.
- If COMPARE_CURRENT_LOCATION is true compare also the cur_loc of each
- variable part. */
-
-static bool
-variable_different_p (variable var1, variable var2,
- bool compare_current_location)
-{
- int i;
-
- if (var1 == var2)
- return false;
-
- if (var1->n_var_parts != var2->n_var_parts)
- return true;
-
- for (i = 0; i < var1->n_var_parts; i++)
- {
- if (var1->var_part[i].offset != var2->var_part[i].offset)
- return true;
- if (compare_current_location)
- {
- if (!((REG_P (var1->var_part[i].cur_loc)
- && REG_P (var2->var_part[i].cur_loc)
- && (REGNO (var1->var_part[i].cur_loc)
- == REGNO (var2->var_part[i].cur_loc)))
- || rtx_equal_p (var1->var_part[i].cur_loc,
- var2->var_part[i].cur_loc)))
- return true;
- }
- if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i]))
- return true;
- if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i]))
- return true;
- }
- return false;
-}
-
-/* Compare variable *SLOT with the same variable in hash table DATA
- and set DATAFLOW_SET_DIFFERENT_VALUE if they are different. */
-
-static int
-dataflow_set_different_1 (void **slot, void *data)
-{
- htab_t htab = (htab_t) data;
- variable var1, var2;
-
- var1 = *(variable *) slot;
- var2 = htab_find_with_hash (htab, var1->decl,
- VARIABLE_HASH_VAL (var1->decl));
- if (!var2)
- {
- dataflow_set_different_value = true;
-
- /* Stop traversing the hash table. */
- return 0;
- }
-
- if (variable_different_p (var1, var2, false))
- {
- dataflow_set_different_value = true;
-
- /* Stop traversing the hash table. */
- return 0;
- }
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Compare variable *SLOT with the same variable in hash table DATA
- and set DATAFLOW_SET_DIFFERENT_VALUE if they are different. */
-
-static int
-dataflow_set_different_2 (void **slot, void *data)
-{
- htab_t htab = (htab_t) data;
- variable var1, var2;
-
- var1 = *(variable *) slot;
- var2 = htab_find_with_hash (htab, var1->decl,
- VARIABLE_HASH_VAL (var1->decl));
- if (!var2)
- {
- dataflow_set_different_value = true;
-
- /* Stop traversing the hash table. */
- return 0;
- }
-
- /* If both variables are defined they have been already checked for
- equivalence. */
- gcc_assert (!variable_different_p (var1, var2, false));
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Return true if dataflow sets OLD_SET and NEW_SET differ. */
-
-static bool
-dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
-{
- dataflow_set_different_value = false;
-
- htab_traverse (old_set->vars, dataflow_set_different_1, new_set->vars);
- if (!dataflow_set_different_value)
- {
- /* We have compared the variables which are in both hash tables
- so now only check whether there are some variables in NEW_SET->VARS
- which are not in OLD_SET->VARS. */
- htab_traverse (new_set->vars, dataflow_set_different_2, old_set->vars);
- }
- return dataflow_set_different_value;
-}
-
-/* Free the contents of dataflow set SET. */
-
-static void
-dataflow_set_destroy (dataflow_set *set)
-{
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- attrs_list_clear (&set->regs[i]);
-
- htab_delete (set->vars);
- set->vars = NULL;
-}
-
-/* Return true if RTL X contains a SYMBOL_REF. */
-
-static bool
-contains_symbol_ref (rtx x)
-{
- const char *fmt;
- RTX_CODE code;
- int i;
-
- if (!x)
- return false;
-
- code = GET_CODE (x);
- if (code == SYMBOL_REF)
- return true;
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- {
- if (contains_symbol_ref (XEXP (x, i)))
- return true;
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (contains_symbol_ref (XVECEXP (x, i, j)))
- return true;
- }
- }
-
- return false;
-}
-
-/* Shall EXPR be tracked? */
-
-static bool
-track_expr_p (tree expr)
-{
- rtx decl_rtl;
- tree realdecl;
-
- /* If EXPR is not a parameter or a variable do not track it. */
- if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL)
- return 0;
-
- /* It also must have a name... */
- if (!DECL_NAME (expr))
- return 0;
-
- /* ... and a RTL assigned to it. */
- decl_rtl = DECL_RTL_IF_SET (expr);
- if (!decl_rtl)
- return 0;
-
- /* If this expression is really a debug alias of some other declaration, we
- don't need to track this expression if the ultimate declaration is
- ignored. */
- realdecl = expr;
- if (DECL_DEBUG_EXPR_IS_FROM (realdecl) && DECL_DEBUG_EXPR (realdecl))
- {
- realdecl = DECL_DEBUG_EXPR (realdecl);
- /* ??? We don't yet know how to emit DW_OP_piece for variable
- that has been SRA'ed. */
- if (!DECL_P (realdecl))
- return 0;
- }
-
- /* Do not track EXPR if REALDECL it should be ignored for debugging
- purposes. */
- if (DECL_IGNORED_P (realdecl))
- return 0;
-
- /* Do not track global variables until we are able to emit correct location
- list for them. */
- if (TREE_STATIC (realdecl))
- return 0;
-
- /* When the EXPR is a DECL for alias of some variable (see example)
- the TREE_STATIC flag is not used. Disable tracking all DECLs whose
- DECL_RTL contains SYMBOL_REF.
-
- Example:
- extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv")));
- char **_dl_argv;
- */
- if (MEM_P (decl_rtl)
- && contains_symbol_ref (XEXP (decl_rtl, 0)))
- return 0;
-
- /* If RTX is a memory it should not be very large (because it would be
- an array or struct). */
- if (MEM_P (decl_rtl))
- {
- /* Do not track structures and arrays. */
- if (GET_MODE (decl_rtl) == BLKmode
- || AGGREGATE_TYPE_P (TREE_TYPE (realdecl)))
- return 0;
- if (MEM_SIZE (decl_rtl)
- && INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS)
- return 0;
- }
-
- return 1;
-}
-
-/* Determine whether a given LOC refers to the same variable part as
- EXPR+OFFSET. */
-
-static bool
-same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
-{
- tree expr2;
- HOST_WIDE_INT offset2;
-
- if (! DECL_P (expr))
- return false;
-
- if (REG_P (loc))
- {
- expr2 = REG_EXPR (loc);
- offset2 = REG_OFFSET (loc);
- }
- else if (MEM_P (loc))
- {
- expr2 = MEM_EXPR (loc);
- offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
- }
- else
- return false;
-
- if (! expr2 || ! DECL_P (expr2))
- return false;
-
- expr = var_debug_decl (expr);
- expr2 = var_debug_decl (expr2);
-
- return (expr == expr2 && offset == offset2);
-}
-
-
-/* Count uses (register and memory references) LOC which will be tracked.
- INSN is instruction which the LOC is part of. */
-
-static int
-count_uses (rtx *loc, void *insn)
-{
- basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
-
- if (REG_P (*loc))
- {
- gcc_assert (REGNO (*loc) < FIRST_PSEUDO_REGISTER);
- VTI (bb)->n_mos++;
- }
- else if (MEM_P (*loc)
- && MEM_EXPR (*loc)
- && track_expr_p (MEM_EXPR (*loc)))
- {
- VTI (bb)->n_mos++;
- }
-
- return 0;
-}
-
-/* Helper function for finding all uses of REG/MEM in X in insn INSN. */
-
-static void
-count_uses_1 (rtx *x, void *insn)
-{
- for_each_rtx (x, count_uses, insn);
-}
-
-/* Count stores (register and memory references) LOC which will be tracked.
- INSN is instruction which the LOC is part of. */
-
-static void
-count_stores (rtx loc, rtx expr ATTRIBUTE_UNUSED, void *insn)
-{
- count_uses (&loc, insn);
-}
-
-/* Add uses (register and memory references) LOC which will be tracked
- to VTI (bb)->mos. INSN is instruction which the LOC is part of. */
-
-static int
-add_uses (rtx *loc, void *insn)
-{
- if (REG_P (*loc))
- {
- basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- mo->type = ((REG_EXPR (*loc) && track_expr_p (REG_EXPR (*loc)))
- ? MO_USE : MO_USE_NO_VAR);
- mo->u.loc = *loc;
- mo->insn = (rtx) insn;
- }
- else if (MEM_P (*loc)
- && MEM_EXPR (*loc)
- && track_expr_p (MEM_EXPR (*loc)))
- {
- basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- mo->type = MO_USE;
- mo->u.loc = *loc;
- mo->insn = (rtx) insn;
- }
-
- return 0;
-}
-
-/* Helper function for finding all uses of REG/MEM in X in insn INSN. */
-
-static void
-add_uses_1 (rtx *x, void *insn)
-{
- for_each_rtx (x, add_uses, insn);
-}
-
-/* Add stores (register and memory references) LOC which will be tracked
- to VTI (bb)->mos. EXPR is the RTL expression containing the store.
- INSN is instruction which the LOC is part of. */
-
-static void
-add_stores (rtx loc, rtx expr, void *insn)
-{
- if (REG_P (loc))
- {
- basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- if (GET_CODE (expr) == CLOBBER
- || ! REG_EXPR (loc)
- || ! track_expr_p (REG_EXPR (loc)))
- mo->type = MO_CLOBBER;
- else if (GET_CODE (expr) == SET
- && SET_DEST (expr) == loc
- && same_variable_part_p (SET_SRC (expr),
- REG_EXPR (loc),
- REG_OFFSET (loc)))
- mo->type = MO_COPY;
- else
- mo->type = MO_SET;
- mo->u.loc = loc;
- /* APPLE LOCAL track initialization status 4964532 */
- mo->insn = (rtx) insn;
- }
- else if (MEM_P (loc)
- && MEM_EXPR (loc)
- && track_expr_p (MEM_EXPR (loc)))
- {
- basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- if (GET_CODE (expr) == CLOBBER)
- mo->type = MO_CLOBBER;
- else if (GET_CODE (expr) == SET
- && SET_DEST (expr) == loc
- && same_variable_part_p (SET_SRC (expr),
- MEM_EXPR (loc),
- MEM_OFFSET (loc)
- ? INTVAL (MEM_OFFSET (loc)) : 0))
- mo->type = MO_COPY;
- else
- mo->type = MO_SET;
- mo->u.loc = loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- mo->insn = (rtx) insn;
- }
-}
-
-static enum var_init_status
-find_src_status (dataflow_set *in, rtx loc, rtx insn)
-{
- rtx src = NULL_RTX;
- tree decl = NULL_TREE;
- enum var_init_status status = STATUS_UNINITIALIZED;
-
- if (! TARGET_DWARF_UNINIT_VARS)
- status = STATUS_INITIALIZED;
-
- if (GET_CODE (PATTERN (insn)) == SET)
- src = SET_SRC (PATTERN (insn));
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- int i;
- for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
- && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == loc)
- src = SET_SRC (XVECEXP (PATTERN (insn), 0, i));
- }
- /* APPLE LOCAL begin ARM 5595749 */
- else if (GET_CODE (PATTERN (insn)) == COND_EXEC
- && GET_CODE (COND_EXEC_CODE (PATTERN (insn))) == SET)
- src = SET_SRC (COND_EXEC_CODE (PATTERN (insn)));
- else
- gcc_unreachable ();
- /* APPLE LOCAL end ARM 5595749 */
-
- if (REG_P (src))
- decl = var_debug_decl (REG_EXPR (src));
- else if (MEM_P (src))
- decl = var_debug_decl (MEM_EXPR (src));
-
- if (src && decl)
- status = get_init_value (in, src, decl);
-
- return status;
-}
-
-/* LOC is the destination the variable is being copied to. INSN
- contains the copy instruction. SET is the dataflow set containing
- the variable in LOC. */
-
-static rtx
-find_src_set_src (dataflow_set *set, rtx loc, rtx insn)
-{
- tree decl = NULL_TREE; /* The variable being copied around. */
- rtx src = NULL_RTX; /* The location "decl" is being copied from. */
- rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */
- void **slot;
- variable var;
- location_chain nextp;
- int i;
- bool found;
-
- if (GET_CODE (PATTERN (insn)) == SET)
- src = SET_SRC (PATTERN (insn));
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
- && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == loc)
- src = SET_SRC (XVECEXP (PATTERN (insn), 0, i));
- }
- /* APPLE LOCAL begin ARM 5595749 */
- else if (GET_CODE (PATTERN (insn)) == COND_EXEC
- && GET_CODE (COND_EXEC_CODE (PATTERN (insn))) == SET)
- src = SET_SRC (COND_EXEC_CODE (PATTERN (insn)));
- else
- gcc_unreachable ();
- /* APPLE LOCAL end ARM 5595749 */
-
- if (REG_P (src))
- decl = var_debug_decl (REG_EXPR (src));
- else if (MEM_P (src))
- decl = var_debug_decl (MEM_EXPR (src));
-
- if (src && decl)
- {
- slot = htab_find_slot_with_hash (set->vars, decl,
- VARIABLE_HASH_VAL (decl), NO_INSERT);
-
- if (slot)
- {
- var = *(variable *) slot;
- found = false;
- for (i = 0; i < var->n_var_parts && !found; i++)
- for (nextp = var->var_part[i].loc_chain; nextp && !found;
- nextp = nextp->next)
- if (rtx_equal_p (nextp->loc, src))
- {
- set_src = nextp->set_src;
- found = true;
- }
-
- }
- }
-
- return set_src;
-}
-/* APPLE LOCAL end track initialization status 4964532 */
-
-/* Compute the changes of variable locations in the basic block BB. */
-
-static bool
-compute_bb_dataflow (basic_block bb)
-{
- int i, n, r;
- bool changed;
- dataflow_set old_out;
- dataflow_set *in = &VTI (bb)->in;
- dataflow_set *out = &VTI (bb)->out;
-
- dataflow_set_init (&old_out, htab_elements (VTI (bb)->out.vars) + 3);
- dataflow_set_copy (&old_out, out);
- dataflow_set_copy (out, in);
-
- n = VTI (bb)->n_mos;
- for (i = 0; i < n; i++)
- {
- switch (VTI (bb)->mos[i].type)
- {
- case MO_CALL:
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (TEST_HARD_REG_BIT (call_used_reg_set, r))
- var_regno_delete (out, r);
- break;
-
- case MO_USE:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- enum var_init_status status = STATUS_UNINITIALIZED;
-
- if (! TARGET_DWARF_UNINIT_VARS)
- status = STATUS_INITIALIZED;
-
- if (GET_CODE (loc) == REG)
- var_reg_set (out, loc, status, NULL);
- else if (GET_CODE (loc) == MEM)
- var_mem_set (out, loc, status, NULL);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- break;
-
- case MO_SET:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- rtx set_src = NULL;
- rtx insn = VTI (bb)->mos[i].insn;
-
- if (GET_CODE (PATTERN (insn)) == SET)
- set_src = SET_SRC (PATTERN (insn));
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- int j;
- for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
- && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc)
- set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j));
- }
-
- if (REG_P (loc))
- var_reg_delete_and_set (out, loc, true, STATUS_INITIALIZED,
- set_src);
- else if (MEM_P (loc))
- var_mem_delete_and_set (out, loc, true, STATUS_INITIALIZED,
- set_src);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- break;
-
- case MO_COPY:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- enum var_init_status src_status;
- rtx set_src;
-
- if (! TARGET_DWARF_UNINIT_VARS)
- src_status = STATUS_INITIALIZED;
- else
- src_status = find_src_status (in, loc, VTI (bb)->mos[i].insn);
-
- if (src_status == STATUS_UNKNOWN)
- src_status = find_src_status (out, loc, VTI (bb)->mos[i].insn);
-
- set_src = find_src_set_src (in, loc, VTI (bb)->mos[i].insn);
-
- if (REG_P (loc))
- var_reg_delete_and_set (out, loc, false, src_status, set_src);
- else if (MEM_P (loc))
- var_mem_delete_and_set (out, loc, false, src_status, set_src);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- break;
-
- case MO_USE_NO_VAR:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
-
- if (REG_P (loc))
- var_reg_delete (out, loc, false);
- else if (MEM_P (loc))
- var_mem_delete (out, loc, false);
- }
- break;
-
- case MO_CLOBBER:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
-
- if (REG_P (loc))
- var_reg_delete (out, loc, true);
- else if (MEM_P (loc))
- var_mem_delete (out, loc, true);
- }
- break;
-
- case MO_ADJUST:
- out->stack_adjust += VTI (bb)->mos[i].u.adjust;
- break;
- }
- }
-
- changed = dataflow_set_different (&old_out, out);
- dataflow_set_destroy (&old_out);
- return changed;
-}
-
-/* Find the locations of variables in the whole function. */
-
-static void
-vt_find_locations (void)
-{
- fibheap_t worklist, pending, fibheap_swap;
- sbitmap visited, in_worklist, in_pending, sbitmap_swap;
- basic_block bb;
- edge e;
- int *bb_order;
- int *rc_order;
- int i;
-
- /* Compute reverse completion order of depth first search of the CFG
- so that the data-flow runs faster. */
- rc_order = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS);
- bb_order = XNEWVEC (int, last_basic_block);
- pre_and_rev_post_order_compute (NULL, rc_order, false);
- for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
- bb_order[rc_order[i]] = i;
- free (rc_order);
-
- worklist = fibheap_new ();
- pending = fibheap_new ();
- visited = sbitmap_alloc (last_basic_block);
- in_worklist = sbitmap_alloc (last_basic_block);
- in_pending = sbitmap_alloc (last_basic_block);
- sbitmap_zero (in_worklist);
-
- FOR_EACH_BB (bb)
- fibheap_insert (pending, bb_order[bb->index], bb);
- sbitmap_ones (in_pending);
-
- while (!fibheap_empty (pending))
- {
- fibheap_swap = pending;
- pending = worklist;
- worklist = fibheap_swap;
- sbitmap_swap = in_pending;
- in_pending = in_worklist;
- in_worklist = sbitmap_swap;
-
- sbitmap_zero (visited);
-
- while (!fibheap_empty (worklist))
- {
- bb = fibheap_extract_min (worklist);
- RESET_BIT (in_worklist, bb->index);
- if (!TEST_BIT (visited, bb->index))
- {
- bool changed;
- edge_iterator ei;
-
- SET_BIT (visited, bb->index);
-
- /* Calculate the IN set as union of predecessor OUT sets. */
- dataflow_set_clear (&VTI (bb)->in);
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- dataflow_set_union (&VTI (bb)->in, &VTI (e->src)->out);
- }
-
- changed = compute_bb_dataflow (bb);
- if (changed)
- {
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- if (e->dest == EXIT_BLOCK_PTR)
- continue;
-
- if (e->dest == bb)
- continue;
-
- if (TEST_BIT (visited, e->dest->index))
- {
- if (!TEST_BIT (in_pending, e->dest->index))
- {
- /* Send E->DEST to next round. */
- SET_BIT (in_pending, e->dest->index);
- fibheap_insert (pending,
- bb_order[e->dest->index],
- e->dest);
- }
- }
- else if (!TEST_BIT (in_worklist, e->dest->index))
- {
- /* Add E->DEST to current round. */
- SET_BIT (in_worklist, e->dest->index);
- fibheap_insert (worklist, bb_order[e->dest->index],
- e->dest);
- }
- }
- }
- }
- }
- }
-
- free (bb_order);
- fibheap_delete (worklist);
- fibheap_delete (pending);
- sbitmap_free (visited);
- sbitmap_free (in_worklist);
- sbitmap_free (in_pending);
-}
-
-/* Print the content of the LIST to dump file. */
-
-static void
-dump_attrs_list (attrs list)
-{
- for (; list; list = list->next)
- {
- print_mem_expr (dump_file, list->decl);
- fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
- }
- fprintf (dump_file, "\n");
-}
-
-/* Print the information about variable *SLOT to dump file. */
-
-static int
-dump_variable (void **slot, void *data ATTRIBUTE_UNUSED)
-{
- variable var = *(variable *) slot;
- int i;
- location_chain node;
-
- fprintf (dump_file, " name: %s\n",
- IDENTIFIER_POINTER (DECL_NAME (var->decl)));
- for (i = 0; i < var->n_var_parts; i++)
- {
- fprintf (dump_file, " offset %ld\n",
- (long) var->var_part[i].offset);
- for (node = var->var_part[i].loc_chain; node; node = node->next)
- {
- fprintf (dump_file, " ");
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (node->init == STATUS_UNINITIALIZED)
- fprintf (dump_file, "[uninit]");
- /* APPLE LOCAL end track initialization status 4964532 */
- print_rtl_single (dump_file, node->loc);
- }
- }
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Print the information about variables from hash table VARS to dump file. */
-
-static void
-dump_vars (htab_t vars)
-{
- if (htab_elements (vars) > 0)
- {
- fprintf (dump_file, "Variables:\n");
- htab_traverse (vars, dump_variable, NULL);
- }
-}
-
-/* Print the dataflow set SET to dump file. */
-
-static void
-dump_dataflow_set (dataflow_set *set)
-{
- int i;
-
- fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
- set->stack_adjust);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- if (set->regs[i])
- {
- fprintf (dump_file, "Reg %d:", i);
- dump_attrs_list (set->regs[i]);
- }
- }
- dump_vars (set->vars);
- fprintf (dump_file, "\n");
-}
-
-/* Print the IN and OUT sets for each basic block to dump file. */
-
-static void
-dump_dataflow_sets (void)
-{
- basic_block bb;
-
- FOR_EACH_BB (bb)
- {
- fprintf (dump_file, "\nBasic block %d:\n", bb->index);
- fprintf (dump_file, "IN:\n");
- dump_dataflow_set (&VTI (bb)->in);
- fprintf (dump_file, "OUT:\n");
- dump_dataflow_set (&VTI (bb)->out);
- }
-}
-
-/* APPLE LOCAL begin 6414738 */
-/* Compare variable *SLOT with the same variable in hash table DATA;
- if not identical, print difference on file _F. */
-static const char *_set_name;
-static FILE *_f;
-static int
-dump_dataflow_set_difference_1 (void **slot, void *data)
-{
- htab_t htab = (htab_t) data;
- variable var1, var2;
-
- var1 = *(variable *) slot;
- var2 = htab_find_with_hash (htab, var1->decl,
- VARIABLE_HASH_VAL (var1->decl));
- if (!var2)
- fprintf (_f, "%s only in %s set\n", lang_hooks.decl_printable_name (var1->decl, 0), _set_name);
- else if (variable_different_p (var1, var2, false))
- fprintf (_f, "%s present but not identical in sets\n", lang_hooks.decl_printable_name (var1->decl, 0));
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Print dataflow set difference to stderr. Plagiarized from
- dataflow_set_different. Never called; intended for use from
- GDB. */
-void debug_dataflow_set_difference (dataflow_set *, dataflow_set *);
-void
-debug_dataflow_set_difference (dataflow_set *left_set, dataflow_set *right_set)
-{
- _f = stderr;
- _set_name = "left";
- htab_traverse (left_set->vars, dump_dataflow_set_difference_1, right_set->vars);
- _set_name = "right";
- htab_traverse (right_set->vars, dump_dataflow_set_difference_1, left_set->vars);
-}
-
-void debug_dataflow_set (dataflow_set *);
-void
-debug_dataflow_set (dataflow_set *set)
-{
- FILE *saved_dump_file = dump_file;
- dump_file = stderr;
- dump_dataflow_set (set);
- dump_file = saved_dump_file;
-}
-void debug_var_tracking (void);
-void
-debug_var_tracking (void)
-{
- FILE *saved_dump_file = dump_file;
- dump_file = stderr;
- dump_dataflow_sets ();
- dump_flow_info (stderr, dump_flags);
- dump_file = saved_dump_file;
-}
-/* APPLE LOCAL end 6414738 */
-
-/* Add variable VAR to the hash table of changed variables and
- if it has no locations delete it from hash table HTAB. */
-
-static void
-variable_was_changed (variable var, htab_t htab)
-{
- hashval_t hash = VARIABLE_HASH_VAL (var->decl);
-
- if (emit_notes)
- {
- variable *slot;
-
- slot = (variable *) htab_find_slot_with_hash (changed_variables,
- var->decl, hash, INSERT);
-
- if (htab && var->n_var_parts == 0)
- {
- variable empty_var;
- void **old;
-
- empty_var = pool_alloc (var_pool);
- empty_var->decl = var->decl;
- empty_var->refcount = 1;
- empty_var->n_var_parts = 0;
- *slot = empty_var;
-
- old = htab_find_slot_with_hash (htab, var->decl, hash,
- NO_INSERT);
- if (old)
- htab_clear_slot (htab, old);
- }
- else
- {
- *slot = var;
- }
- }
- else
- {
- gcc_assert (htab);
- if (var->n_var_parts == 0)
- {
- void **slot = htab_find_slot_with_hash (htab, var->decl, hash,
- NO_INSERT);
- if (slot)
- htab_clear_slot (htab, slot);
- }
- }
-}
-
-/* Look for the index in VAR->var_part corresponding to OFFSET.
- Return -1 if not found. If INSERTION_POINT is non-NULL, the
- referenced int will be set to the index that the part has or should
- have, if it should be inserted. */
-
-static inline int
-find_variable_location_part (variable var, HOST_WIDE_INT offset,
- int *insertion_point)
-{
- int pos, low, high;
-
- /* Find the location part. */
- low = 0;
- high = var->n_var_parts;
- while (low != high)
- {
- pos = (low + high) / 2;
- if (var->var_part[pos].offset < offset)
- low = pos + 1;
- else
- high = pos;
- }
- pos = low;
-
- if (insertion_point)
- *insertion_point = pos;
-
- if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
- return pos;
-
- return -1;
-}
-
-/* Set the part of variable's location in the dataflow set SET. The variable
- part is specified by variable's declaration DECL and offset OFFSET and the
- part's location by LOC. */
-
-/* APPLE LOCAL begin track initialization status 4964532 */
-static void
-set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
- enum var_init_status initialized, rtx set_src)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- int pos;
- location_chain node, next;
- location_chain *nextp;
- variable var;
- void **slot;
-
- slot = htab_find_slot_with_hash (set->vars, decl,
- VARIABLE_HASH_VAL (decl), INSERT);
- if (!*slot)
- {
- /* Create new variable information. */
- var = pool_alloc (var_pool);
- var->decl = decl;
- var->refcount = 1;
- var->n_var_parts = 1;
- var->var_part[0].offset = offset;
- var->var_part[0].loc_chain = NULL;
- var->var_part[0].cur_loc = NULL;
- *slot = var;
- pos = 0;
- }
- else
- {
- int inspos = 0;
-
- var = (variable) *slot;
-
- pos = find_variable_location_part (var, offset, &inspos);
-
- if (pos >= 0)
- {
- node = var->var_part[pos].loc_chain;
-
- if (node
- && ((REG_P (node->loc) && REG_P (loc)
- && REGNO (node->loc) == REGNO (loc))
- || rtx_equal_p (node->loc, loc)))
- {
- /* LOC is in the beginning of the chain so we have nothing
- to do. */
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (node->init < initialized)
- node->init = initialized;
- if (set_src != NULL)
- node->set_src = set_src;
-
- *slot = var;
- /* APPLE LOCAL end track initialization status 4964532 */
- return;
- }
- else
- {
- /* We have to make a copy of a shared variable. */
- if (var->refcount > 1)
- /* APPLE LOCAL track initialization status 4964532 */
- var = unshare_variable (set, var, initialized);
- }
- }
- else
- {
- /* We have not found the location part, new one will be created. */
-
- /* We have to make a copy of the shared variable. */
- if (var->refcount > 1)
- /* APPLE LOCAL track initialization status 4964532 */
- var = unshare_variable (set, var, initialized);
-
- /* We track only variables whose size is <= MAX_VAR_PARTS bytes
- thus there are at most MAX_VAR_PARTS different offsets. */
- gcc_assert (var->n_var_parts < MAX_VAR_PARTS);
-
- /* We have to move the elements of array starting at index
- inspos to the next position. */
- for (pos = var->n_var_parts; pos > inspos; pos--)
- var->var_part[pos] = var->var_part[pos - 1];
-
- var->n_var_parts++;
- var->var_part[pos].offset = offset;
- var->var_part[pos].loc_chain = NULL;
- var->var_part[pos].cur_loc = NULL;
- }
- }
-
- /* Delete the location from the list. */
- nextp = &var->var_part[pos].loc_chain;
- for (node = var->var_part[pos].loc_chain; node; node = next)
- {
- next = node->next;
- if ((REG_P (node->loc) && REG_P (loc)
- && REGNO (node->loc) == REGNO (loc))
- || rtx_equal_p (node->loc, loc))
- {
- /* APPLE LOCAL begin track initialization status 4964532 */
- /* Save these values, to assign to the new node, before
- deleting this one. */
- if (node->init > initialized)
- initialized = node->init;
- if (node->set_src != NULL && set_src == NULL)
- set_src = node->set_src;
- /* APPLE LOCAL end track initialization status 4964532 */
- pool_free (loc_chain_pool, node);
- *nextp = next;
- break;
- }
- else
- nextp = &node->next;
- }
-
- /* Add the location to the beginning. */
- node = pool_alloc (loc_chain_pool);
- node->loc = loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- node->init = initialized;
- node->set_src = set_src;
- /* APPLE LOCAL end track initialization status 4964532 */
- node->next = var->var_part[pos].loc_chain;
- var->var_part[pos].loc_chain = node;
-
- /* If no location was emitted do so. */
- if (var->var_part[pos].cur_loc == NULL)
- {
- var->var_part[pos].cur_loc = loc;
- variable_was_changed (var, set->vars);
- }
-}
-
-/* Remove all recorded register locations for the given variable part
- from dataflow set SET, except for those that are identical to loc.
- The variable part is specified by variable's declaration DECL and
- offset OFFSET. */
-
-static void
-/* APPLE LOCAL begin track initialization status 4964532 */
-clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
- HOST_WIDE_INT offset, rtx set_src)
-/* APPLE LOCAL end track initialization status 4964532 */
-{
- void **slot;
-
- if (! decl || ! DECL_P (decl))
- return;
-
- slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
- NO_INSERT);
- if (slot)
- {
- variable var = (variable) *slot;
- int pos = find_variable_location_part (var, offset, NULL);
-
- if (pos >= 0)
- {
- location_chain node, next;
-
- /* Remove the register locations from the dataflow set. */
- next = var->var_part[pos].loc_chain;
- for (node = next; node; node = next)
- {
- next = node->next;
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (node->loc != loc
- && (!(TARGET_DWARF_UNINIT_VARS)
- || !set_src
- || MEM_P (set_src)
- || !rtx_equal_p (set_src, node->set_src)))
- /* APPLE LOCAL end track initialization status 4964532 */
- {
- if (REG_P (node->loc))
- {
- attrs anode, anext;
- attrs *anextp;
-
- /* Remove the variable part from the register's
- list, but preserve any other variable parts
- that might be regarded as live in that same
- register. */
- anextp = &set->regs[REGNO (node->loc)];
- for (anode = *anextp; anode; anode = anext)
- {
- anext = anode->next;
- if (anode->decl == decl
- && anode->offset == offset)
- {
- pool_free (attrs_pool, anode);
- *anextp = anext;
- }
- /* APPLE LOCAL begin 6414738 */
- else
- anextp = &anode->next;
- /* APPLE LOCAL end 6414738 */
- }
- }
-
- delete_variable_part (set, node->loc, decl, offset);
- }
- }
- }
- }
-}
-
-/* Delete the part of variable's location from dataflow set SET. The variable
- part is specified by variable's declaration DECL and offset OFFSET and the
- part's location by LOC. */
-
-static void
-delete_variable_part (dataflow_set *set, rtx loc, tree decl,
- HOST_WIDE_INT offset)
-{
- void **slot;
-
- slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
- NO_INSERT);
- if (slot)
- {
- variable var = (variable) *slot;
- int pos = find_variable_location_part (var, offset, NULL);
-
- if (pos >= 0)
- {
- location_chain node, next;
- location_chain *nextp;
- bool changed;
-
- if (var->refcount > 1)
- {
- /* If the variable contains the location part we have to
- make a copy of the variable. */
- for (node = var->var_part[pos].loc_chain; node;
- node = node->next)
- {
- if ((REG_P (node->loc) && REG_P (loc)
- && REGNO (node->loc) == REGNO (loc))
- || rtx_equal_p (node->loc, loc))
- {
- /* APPLE LOCAL begin track initialization status 4964532 */
- enum var_init_status status = STATUS_UNKNOWN;
- if (! TARGET_DWARF_UNINIT_VARS)
- status = STATUS_INITIALIZED;
- var = unshare_variable (set, var, status);
- break;
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- }
- }
-
- /* Delete the location part. */
- nextp = &var->var_part[pos].loc_chain;
- for (node = *nextp; node; node = next)
- {
- next = node->next;
- if ((REG_P (node->loc) && REG_P (loc)
- && REGNO (node->loc) == REGNO (loc))
- || rtx_equal_p (node->loc, loc))
- {
- pool_free (loc_chain_pool, node);
- *nextp = next;
- break;
- }
- else
- nextp = &node->next;
- }
-
- /* If we have deleted the location which was last emitted
- we have to emit new location so add the variable to set
- of changed variables. */
- if (var->var_part[pos].cur_loc
- && ((REG_P (loc)
- && REG_P (var->var_part[pos].cur_loc)
- && REGNO (loc) == REGNO (var->var_part[pos].cur_loc))
- || rtx_equal_p (loc, var->var_part[pos].cur_loc)))
- {
- changed = true;
- if (var->var_part[pos].loc_chain)
- var->var_part[pos].cur_loc = var->var_part[pos].loc_chain->loc;
- }
- else
- changed = false;
-
- if (var->var_part[pos].loc_chain == NULL)
- {
- var->n_var_parts--;
- while (pos < var->n_var_parts)
- {
- var->var_part[pos] = var->var_part[pos + 1];
- pos++;
- }
- }
- if (changed)
- variable_was_changed (var, set->vars);
- }
- }
-}
-
-/* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP. DATA contains
- additional parameters: WHERE specifies whether the note shall be emitted
- before of after instruction INSN. */
-
-static int
-emit_note_insn_var_location (void **varp, void *data)
-{
- variable var = *(variable *) varp;
- rtx insn = ((emit_note_data *)data)->insn;
- enum emit_note_where where = ((emit_note_data *)data)->where;
- rtx note;
- int i, j, n_var_parts;
- bool complete;
- /* APPLE LOCAL track initialization status 4964532 */
- enum var_init_status initialized = STATUS_UNINITIALIZED;
- HOST_WIDE_INT last_limit;
- tree type_size_unit;
- HOST_WIDE_INT offsets[MAX_VAR_PARTS];
- rtx loc[MAX_VAR_PARTS];
-
- gcc_assert (var->decl);
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (! TARGET_DWARF_UNINIT_VARS)
- initialized = STATUS_INITIALIZED;
- /* APPLE LOCAL end track initialization stauts. */
-
- complete = true;
- last_limit = 0;
- n_var_parts = 0;
- for (i = 0; i < var->n_var_parts; i++)
- {
- enum machine_mode mode, wider_mode;
-
- if (last_limit < var->var_part[i].offset)
- {
- complete = false;
- break;
- }
- else if (last_limit > var->var_part[i].offset)
- continue;
- offsets[n_var_parts] = var->var_part[i].offset;
- loc[n_var_parts] = var->var_part[i].loc_chain->loc;
- mode = GET_MODE (loc[n_var_parts]);
- /* APPLE LOCAL track initialization status 4964532 */
- initialized = var->var_part[i].loc_chain->init;
- last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
-
- /* Attempt to merge adjacent registers or memory. */
- wider_mode = GET_MODE_WIDER_MODE (mode);
- for (j = i + 1; j < var->n_var_parts; j++)
- if (last_limit <= var->var_part[j].offset)
- break;
- if (j < var->n_var_parts
- && wider_mode != VOIDmode
- && GET_CODE (loc[n_var_parts])
- == GET_CODE (var->var_part[j].loc_chain->loc)
- && mode == GET_MODE (var->var_part[j].loc_chain->loc)
- && last_limit == var->var_part[j].offset)
- {
- rtx new_loc = NULL;
- rtx loc2 = var->var_part[j].loc_chain->loc;
-
- if (REG_P (loc[n_var_parts])
- && hard_regno_nregs[REGNO (loc[n_var_parts])][mode] * 2
- == hard_regno_nregs[REGNO (loc[n_var_parts])][wider_mode]
- && REGNO (loc[n_var_parts])
- + hard_regno_nregs[REGNO (loc[n_var_parts])][mode]
- == REGNO (loc2))
- {
- if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
- new_loc = simplify_subreg (wider_mode, loc[n_var_parts],
- mode, 0);
- else if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
- new_loc = simplify_subreg (wider_mode, loc2, mode, 0);
- if (new_loc)
- {
- if (!REG_P (new_loc)
- || REGNO (new_loc) != REGNO (loc[n_var_parts]))
- new_loc = NULL;
- else
- REG_ATTRS (new_loc) = REG_ATTRS (loc[n_var_parts]);
- }
- }
- else if (MEM_P (loc[n_var_parts])
- && GET_CODE (XEXP (loc2, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (loc2, 0), 0)) == REG
- && GET_CODE (XEXP (XEXP (loc2, 0), 1)) == CONST_INT)
- {
- if ((GET_CODE (XEXP (loc[n_var_parts], 0)) == REG
- && rtx_equal_p (XEXP (loc[n_var_parts], 0),
- XEXP (XEXP (loc2, 0), 0))
- && INTVAL (XEXP (XEXP (loc2, 0), 1))
- == GET_MODE_SIZE (mode))
- || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
- && GET_CODE (XEXP (XEXP (loc[n_var_parts], 0), 1))
- == CONST_INT
- && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
- XEXP (XEXP (loc2, 0), 0))
- && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1))
- + GET_MODE_SIZE (mode)
- == INTVAL (XEXP (XEXP (loc2, 0), 1))))
- new_loc = adjust_address_nv (loc[n_var_parts],
- wider_mode, 0);
- }
-
- if (new_loc)
- {
- loc[n_var_parts] = new_loc;
- mode = wider_mode;
- last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
- i = j;
- }
- }
- ++n_var_parts;
- }
- type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (var->decl));
- if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
- complete = false;
-
- if (where == EMIT_NOTE_AFTER_INSN)
- note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
- else
- note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- if (!(TARGET_DWARF_UNINIT_VARS))
- initialized = STATUS_INITIALIZED;
- /* APPLE LOCAL end track initialization status 4964532 */
-
- if (!complete)
- {
- /* APPLE LOCAL begin track initialization status 4964532 */
- NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
- NULL_RTX, 0);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- else if (n_var_parts == 1)
- {
- rtx expr_list
- = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
- expr_list,
- (int) initialized);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- else if (n_var_parts)
- {
- rtx parallel;
-
- for (i = 0; i < n_var_parts; i++)
- loc[i]
- = gen_rtx_EXPR_LIST (VOIDmode, loc[i], GEN_INT (offsets[i]));
-
- parallel = gen_rtx_PARALLEL (VOIDmode,
- gen_rtvec_v (n_var_parts, loc));
- /* APPLE LOCAL begin track initialization status 4964532 */
- NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
- parallel,
- (int) initialized);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- NOTE_VAR_LOCATION_STATUS (note) = (int) initialized;
- /* APPLE LOCAL end track initialization status 4964532 */
-
- htab_clear_slot (changed_variables, varp);
-
- /* When there are no location parts the variable has been already
- removed from hash table and a new empty variable was created.
- Free the empty variable. */
- if (var->n_var_parts == 0)
- {
- pool_free (var_pool, var);
- }
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Emit NOTE_INSN_VAR_LOCATION note for each variable from a chain
- CHANGED_VARIABLES and delete this chain. WHERE specifies whether the notes
- shall be emitted before of after instruction INSN. */
-
-static void
-emit_notes_for_changes (rtx insn, enum emit_note_where where)
-{
- emit_note_data data;
-
- data.insn = insn;
- data.where = where;
- htab_traverse (changed_variables, emit_note_insn_var_location, &data);
-}
-
-/* Add variable *SLOT to the chain CHANGED_VARIABLES if it differs from the
- same variable in hash table DATA or is not there at all. */
-
-static int
-emit_notes_for_differences_1 (void **slot, void *data)
-{
- htab_t new_vars = (htab_t) data;
- variable old_var, new_var;
-
- old_var = *(variable *) slot;
- new_var = htab_find_with_hash (new_vars, old_var->decl,
- VARIABLE_HASH_VAL (old_var->decl));
-
- if (!new_var)
- {
- /* Variable has disappeared. */
- variable empty_var;
-
- empty_var = pool_alloc (var_pool);
- empty_var->decl = old_var->decl;
- empty_var->refcount = 1;
- empty_var->n_var_parts = 0;
- variable_was_changed (empty_var, NULL);
- }
- else if (variable_different_p (old_var, new_var, true))
- {
- variable_was_changed (new_var, NULL);
- }
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Add variable *SLOT to the chain CHANGED_VARIABLES if it is not in hash
- table DATA. */
-
-static int
-emit_notes_for_differences_2 (void **slot, void *data)
-{
- htab_t old_vars = (htab_t) data;
- variable old_var, new_var;
-
- new_var = *(variable *) slot;
- old_var = htab_find_with_hash (old_vars, new_var->decl,
- VARIABLE_HASH_VAL (new_var->decl));
- if (!old_var)
- {
- /* Variable has appeared. */
- variable_was_changed (new_var, NULL);
- }
-
- /* Continue traversing the hash table. */
- return 1;
-}
-
-/* Emit notes before INSN for differences between dataflow sets OLD_SET and
- NEW_SET. */
-
-static void
-emit_notes_for_differences (rtx insn, dataflow_set *old_set,
- dataflow_set *new_set)
-{
- htab_traverse (old_set->vars, emit_notes_for_differences_1, new_set->vars);
- htab_traverse (new_set->vars, emit_notes_for_differences_2, old_set->vars);
- emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
-}
-
-/* Emit the notes for changes of location parts in the basic block BB. */
-
-static void
-emit_notes_in_bb (basic_block bb)
-{
- int i;
- dataflow_set set;
-
- dataflow_set_init (&set, htab_elements (VTI (bb)->in.vars) + 3);
- dataflow_set_copy (&set, &VTI (bb)->in);
-
- for (i = 0; i < VTI (bb)->n_mos; i++)
- {
- rtx insn = VTI (bb)->mos[i].insn;
-
- switch (VTI (bb)->mos[i].type)
- {
- case MO_CALL:
- {
- int r;
-
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (TEST_HARD_REG_BIT (call_used_reg_set, r))
- {
- var_regno_delete (&set, r);
- }
- emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
- }
- break;
-
- case MO_USE:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
-
- /* APPLE LOCAL begin track initialization status 4964532 */
- enum var_init_status status = STATUS_UNINITIALIZED;
- if (! TARGET_DWARF_UNINIT_VARS)
- status = STATUS_INITIALIZED;
- if (GET_CODE (loc) == REG)
- var_reg_set (&set, loc, status, NULL);
- else
- var_mem_set (&set, loc, status, NULL);
- /* APPLE LOCAL end track initialization status 4964532 */
-
- emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
- }
- break;
-
- case MO_SET:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- rtx set_src = NULL;
-
- if (GET_CODE (PATTERN (insn)) == SET)
- set_src = SET_SRC (PATTERN (insn));
- else if (GET_CODE (PATTERN (insn)) == PARALLEL
- || GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- int j;
- for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
- && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc)
- set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j));
- }
-
- if (REG_P (loc))
- var_reg_delete_and_set (&set, loc, true, STATUS_INITIALIZED,
- set_src);
- else
- var_mem_delete_and_set (&set, loc, true, STATUS_INITIALIZED,
- set_src);
-
- emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- break;
-
- case MO_COPY:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
- /* APPLE LOCAL begin track initialization status 4964532 */
- enum var_init_status src_status;
- rtx set_src;
-
- src_status = find_src_status (&set, loc, VTI (bb)->mos[i].insn);
- set_src = find_src_set_src (&set, loc, VTI (bb)->mos[i].insn);
-
- if (REG_P (loc))
- var_reg_delete_and_set (&set, loc, false, src_status, set_src);
- else
- var_mem_delete_and_set (&set, loc, false, src_status, set_src);
-
- emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
- break;
-
- case MO_USE_NO_VAR:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
-
- if (REG_P (loc))
- var_reg_delete (&set, loc, false);
- else
- var_mem_delete (&set, loc, false);
-
- emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
- }
- break;
-
- case MO_CLOBBER:
- {
- rtx loc = VTI (bb)->mos[i].u.loc;
-
- if (REG_P (loc))
- var_reg_delete (&set, loc, true);
- else
- var_mem_delete (&set, loc, true);
-
- /* APPLE LOCAL track initialization status 4964532 */
- emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
- }
- break;
-
- case MO_ADJUST:
- set.stack_adjust += VTI (bb)->mos[i].u.adjust;
- break;
- }
- }
- dataflow_set_destroy (&set);
-}
-
-/* Emit notes for the whole function. */
-
-static void
-vt_emit_notes (void)
-{
- basic_block bb;
- dataflow_set *last_out;
- dataflow_set empty;
-
- gcc_assert (!htab_elements (changed_variables));
-
- /* Enable emitting notes by functions (mainly by set_variable_part and
- delete_variable_part). */
- emit_notes = true;
-
- dataflow_set_init (&empty, 7);
- last_out = &empty;
-
- FOR_EACH_BB (bb)
- {
- /* Emit the notes for changes of variable locations between two
- subsequent basic blocks. */
- emit_notes_for_differences (BB_HEAD (bb), last_out, &VTI (bb)->in);
-
- /* Emit the notes for the changes in the basic block itself. */
- emit_notes_in_bb (bb);
-
- last_out = &VTI (bb)->out;
- }
- dataflow_set_destroy (&empty);
- emit_notes = false;
-}
-
-/* If there is a declaration and offset associated with register/memory RTL
- assign declaration to *DECLP and offset to *OFFSETP, and return true. */
-
-static bool
-vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
-{
- if (REG_P (rtl))
- {
- if (REG_ATTRS (rtl))
- {
- *declp = REG_EXPR (rtl);
- *offsetp = REG_OFFSET (rtl);
- return true;
- }
- }
- else if (MEM_P (rtl))
- {
- if (MEM_ATTRS (rtl))
- {
- *declp = MEM_EXPR (rtl);
- *offsetp = MEM_OFFSET (rtl) ? INTVAL (MEM_OFFSET (rtl)) : 0;
- return true;
- }
- }
- return false;
-}
-
-/* Insert function parameters to IN and OUT sets of ENTRY_BLOCK. */
-
-static void
-vt_add_function_parameters (void)
-{
- tree parm;
-
- for (parm = DECL_ARGUMENTS (current_function_decl);
- parm; parm = TREE_CHAIN (parm))
- {
- rtx decl_rtl = DECL_RTL_IF_SET (parm);
- rtx incoming = DECL_INCOMING_RTL (parm);
- tree decl;
- HOST_WIDE_INT offset;
- dataflow_set *out;
-
- if (TREE_CODE (parm) != PARM_DECL)
- continue;
-
- if (!DECL_NAME (parm))
- continue;
-
- if (!decl_rtl || !incoming)
- continue;
-
- if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
- continue;
-
- if (!vt_get_decl_and_offset (incoming, &decl, &offset))
- if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
- continue;
-
- if (!decl)
- continue;
-
- gcc_assert (parm == decl);
-
- out = &VTI (ENTRY_BLOCK_PTR)->out;
-
- if (REG_P (incoming))
- {
- gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
- attrs_list_insert (&out->regs[REGNO (incoming)],
- parm, offset, incoming);
- /* APPLE LOCAL begin track initialization status 4964532 */
- set_variable_part (out, incoming, parm, offset, STATUS_INITIALIZED,
- NULL);
- }
- else if (MEM_P (incoming))
- set_variable_part (out, incoming, parm, offset, STATUS_INITIALIZED,
- NULL);
- /* APPLE LOCAL end track initialization status 4964532 */
- }
-}
-
-/* Allocate and initialize the data structures for variable tracking
- and parse the RTL to get the micro operations. */
-
-static void
-vt_initialize (void)
-{
- basic_block bb;
-
- alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
-
- FOR_EACH_BB (bb)
- {
- rtx insn;
- HOST_WIDE_INT pre, post = 0;
-
- /* Count the number of micro operations. */
- VTI (bb)->n_mos = 0;
- for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- {
- if (!frame_pointer_needed)
- {
- insn_stack_adjust_offset_pre_post (insn, &pre, &post);
- if (pre)
- VTI (bb)->n_mos++;
- if (post)
- VTI (bb)->n_mos++;
- }
- note_uses (&PATTERN (insn), count_uses_1, insn);
- note_stores (PATTERN (insn), count_stores, insn);
- if (CALL_P (insn))
- VTI (bb)->n_mos++;
- }
- }
-
- /* Add the micro-operations to the array. */
- VTI (bb)->mos = XNEWVEC (micro_operation, VTI (bb)->n_mos);
- VTI (bb)->n_mos = 0;
- for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- {
- int n1, n2;
-
- if (!frame_pointer_needed)
- {
- insn_stack_adjust_offset_pre_post (insn, &pre, &post);
- if (pre)
- {
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- mo->type = MO_ADJUST;
- mo->u.adjust = pre;
- mo->insn = insn;
- }
- }
-
- n1 = VTI (bb)->n_mos;
- note_uses (&PATTERN (insn), add_uses_1, insn);
- n2 = VTI (bb)->n_mos - 1;
-
- /* Order the MO_USEs to be before MO_USE_NO_VARs. */
- while (n1 < n2)
- {
- while (n1 < n2 && VTI (bb)->mos[n1].type == MO_USE)
- n1++;
- while (n1 < n2 && VTI (bb)->mos[n2].type == MO_USE_NO_VAR)
- n2--;
- if (n1 < n2)
- {
- micro_operation sw;
-
- sw = VTI (bb)->mos[n1];
- VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
- VTI (bb)->mos[n2] = sw;
- }
- }
-
- if (CALL_P (insn))
- {
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- mo->type = MO_CALL;
- mo->insn = insn;
- }
-
- n1 = VTI (bb)->n_mos;
- /* This will record NEXT_INSN (insn), such that we can
- insert notes before it without worrying about any
- notes that MO_USEs might emit after the insn. */
- note_stores (PATTERN (insn), add_stores, insn);
- n2 = VTI (bb)->n_mos - 1;
-
- /* Order the MO_CLOBBERs to be before MO_SETs. */
- while (n1 < n2)
- {
- while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
- n1++;
- while (n1 < n2 && (VTI (bb)->mos[n2].type == MO_SET
- || VTI (bb)->mos[n2].type == MO_COPY))
- n2--;
- if (n1 < n2)
- {
- micro_operation sw;
-
- sw = VTI (bb)->mos[n1];
- VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
- VTI (bb)->mos[n2] = sw;
- }
- }
-
- if (!frame_pointer_needed && post)
- {
- micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
- mo->type = MO_ADJUST;
- mo->u.adjust = post;
- mo->insn = insn;
- }
- }
- }
- }
-
- /* Init the IN and OUT sets. */
- FOR_ALL_BB (bb)
- {
- VTI (bb)->visited = false;
- dataflow_set_init (&VTI (bb)->in, 7);
- dataflow_set_init (&VTI (bb)->out, 7);
- }
-
- attrs_pool = create_alloc_pool ("attrs_def pool",
- sizeof (struct attrs_def), 1024);
- var_pool = create_alloc_pool ("variable_def pool",
- sizeof (struct variable_def), 64);
- loc_chain_pool = create_alloc_pool ("location_chain_def pool",
- sizeof (struct location_chain_def),
- 1024);
- changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
- NULL);
- vt_add_function_parameters ();
-}
-
-/* Free the data structures needed for variable tracking. */
-
-static void
-vt_finalize (void)
-{
- basic_block bb;
-
- FOR_EACH_BB (bb)
- {
- free (VTI (bb)->mos);
- }
-
- FOR_ALL_BB (bb)
- {
- dataflow_set_destroy (&VTI (bb)->in);
- dataflow_set_destroy (&VTI (bb)->out);
- }
- free_aux_for_blocks ();
- free_alloc_pool (attrs_pool);
- free_alloc_pool (var_pool);
- free_alloc_pool (loc_chain_pool);
- htab_delete (changed_variables);
-}
-
-/* The entry point to variable tracking pass. */
-
-unsigned int
-variable_tracking_main (void)
-{
- if (n_basic_blocks > 500 && n_edges / n_basic_blocks >= 20)
- return 0;
-
- mark_dfs_back_edges ();
- vt_initialize ();
- if (!frame_pointer_needed)
- {
- if (!vt_stack_adjustments ())
- {
- vt_finalize ();
- return 0;
- }
- }
-
- vt_find_locations ();
- vt_emit_notes ();
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- dump_dataflow_sets ();
- dump_flow_info (dump_file, dump_flags);
- }
-
- vt_finalize ();
- return 0;
-}
-
-static bool
-gate_handle_var_tracking (void)
-{
- return (flag_var_tracking);
-}
-
-
-
-struct tree_opt_pass pass_variable_tracking =
-{
- "vartrack", /* name */
- gate_handle_var_tracking, /* gate */
- variable_tracking_main, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_VAR_TRACKING, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 'V' /* letter */
-};
-