138fd1498Szrj /* Variable tracking routines for the GNU compiler.
238fd1498Szrj    Copyright (C) 2002-2018 Free Software Foundation, Inc.
338fd1498Szrj 
438fd1498Szrj    This file is part of GCC.
538fd1498Szrj 
638fd1498Szrj    GCC is free software; you can redistribute it and/or modify it
738fd1498Szrj    under the terms of the GNU General Public License as published by
838fd1498Szrj    the Free Software Foundation; either version 3, or (at your option)
938fd1498Szrj    any later version.
1038fd1498Szrj 
1138fd1498Szrj    GCC is distributed in the hope that it will be useful, but WITHOUT
1238fd1498Szrj    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1338fd1498Szrj    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1438fd1498Szrj    License for more details.
1538fd1498Szrj 
1638fd1498Szrj    You should have received a copy of the GNU General Public License
1738fd1498Szrj    along with GCC; see the file COPYING3.  If not see
1838fd1498Szrj    <http://www.gnu.org/licenses/>.  */
1938fd1498Szrj 
2038fd1498Szrj /* This file contains the variable tracking pass.  It computes where
2138fd1498Szrj    variables are located (which registers or where in memory) at each position
2238fd1498Szrj    in instruction stream and emits notes describing the locations.
2338fd1498Szrj    Debug information (DWARF2 location lists) is finally generated from
2438fd1498Szrj    these notes.
2538fd1498Szrj    With this debug information, it is possible to show variables
2638fd1498Szrj    even when debugging optimized code.
2738fd1498Szrj 
2838fd1498Szrj    How does the variable tracking pass work?
2938fd1498Szrj 
3038fd1498Szrj    First, it scans RTL code for uses, stores and clobbers (register/memory
3138fd1498Szrj    references in instructions), for call insns and for stack adjustments
3238fd1498Szrj    separately for each basic block and saves them to an array of micro
3338fd1498Szrj    operations.
3438fd1498Szrj    The micro operations of one instruction are ordered so that
3538fd1498Szrj    pre-modifying stack adjustment < use < use with no var < call insn <
3638fd1498Szrj      < clobber < set < post-modifying stack adjustment
3738fd1498Szrj 
3838fd1498Szrj    Then, a forward dataflow analysis is performed to find out how locations
3938fd1498Szrj    of variables change through code and to propagate the variable locations
4038fd1498Szrj    along control flow graph.
4138fd1498Szrj    The IN set for basic block BB is computed as a union of OUT sets of BB's
4238fd1498Szrj    predecessors, the OUT set for BB is copied from the IN set for BB and
4338fd1498Szrj    is changed according to micro operations in BB.
4438fd1498Szrj 
4538fd1498Szrj    The IN and OUT sets for basic blocks consist of a current stack adjustment
4638fd1498Szrj    (used for adjusting offset of variables addressed using stack pointer),
4738fd1498Szrj    the table of structures describing the locations of parts of a variable
4838fd1498Szrj    and for each physical register a linked list for each physical register.
4938fd1498Szrj    The linked list is a list of variable parts stored in the register,
5038fd1498Szrj    i.e. it is a list of triplets (reg, decl, offset) where decl is
5138fd1498Szrj    REG_EXPR (reg) and offset is REG_OFFSET (reg).  The linked list is used for
5238fd1498Szrj    effective deleting appropriate variable parts when we set or clobber the
5338fd1498Szrj    register.
5438fd1498Szrj 
5538fd1498Szrj    There may be more than one variable part in a register.  The linked lists
5638fd1498Szrj    should be pretty short so it is a good data structure here.
5738fd1498Szrj    For example in the following code, register allocator may assign same
5838fd1498Szrj    register to variables A and B, and both of them are stored in the same
5938fd1498Szrj    register in CODE:
6038fd1498Szrj 
6138fd1498Szrj      if (cond)
6238fd1498Szrj        set A;
6338fd1498Szrj      else
6438fd1498Szrj        set B;
6538fd1498Szrj      CODE;
6638fd1498Szrj      if (cond)
6738fd1498Szrj        use A;
6838fd1498Szrj      else
6938fd1498Szrj        use B;
7038fd1498Szrj 
7138fd1498Szrj    Finally, the NOTE_INSN_VAR_LOCATION notes describing the variable locations
7238fd1498Szrj    are emitted to appropriate positions in RTL code.  Each such a note describes
7338fd1498Szrj    the location of one variable at the point in instruction stream where the
7438fd1498Szrj    note is.  There is no need to emit a note for each variable before each
7538fd1498Szrj    instruction, we only emit these notes where the location of variable changes
7638fd1498Szrj    (this means that we also emit notes for changes between the OUT set of the
7738fd1498Szrj    previous block and the IN set of the current block).
7838fd1498Szrj 
7938fd1498Szrj    The notes consist of two parts:
8038fd1498Szrj    1. the declaration (from REG_EXPR or MEM_EXPR)
8138fd1498Szrj    2. the location of a variable - it is either a simple register/memory
8238fd1498Szrj       reference (for simple variables, for example int),
8338fd1498Szrj       or a parallel of register/memory references (for a large variables
8438fd1498Szrj       which consist of several parts, for example long long).
8538fd1498Szrj 
8638fd1498Szrj */
8738fd1498Szrj 
8838fd1498Szrj #include "config.h"
8938fd1498Szrj #include "system.h"
9038fd1498Szrj #include "coretypes.h"
9138fd1498Szrj #include "backend.h"
9238fd1498Szrj #include "target.h"
9338fd1498Szrj #include "rtl.h"
9438fd1498Szrj #include "tree.h"
9538fd1498Szrj #include "cfghooks.h"
9638fd1498Szrj #include "alloc-pool.h"
9738fd1498Szrj #include "tree-pass.h"
9838fd1498Szrj #include "memmodel.h"
9938fd1498Szrj #include "tm_p.h"
10038fd1498Szrj #include "insn-config.h"
10138fd1498Szrj #include "regs.h"
10238fd1498Szrj #include "emit-rtl.h"
10338fd1498Szrj #include "recog.h"
10438fd1498Szrj #include "diagnostic.h"
10538fd1498Szrj #include "varasm.h"
10638fd1498Szrj #include "stor-layout.h"
10738fd1498Szrj #include "cfgrtl.h"
10838fd1498Szrj #include "cfganal.h"
10938fd1498Szrj #include "reload.h"
11038fd1498Szrj #include "calls.h"
11138fd1498Szrj #include "tree-dfa.h"
11238fd1498Szrj #include "tree-ssa.h"
11338fd1498Szrj #include "cselib.h"
11438fd1498Szrj #include "params.h"
11538fd1498Szrj #include "tree-pretty-print.h"
11638fd1498Szrj #include "rtl-iter.h"
11738fd1498Szrj #include "fibonacci_heap.h"
11838fd1498Szrj 
11938fd1498Szrj typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
12038fd1498Szrj typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
12138fd1498Szrj 
12238fd1498Szrj /* var-tracking.c assumes that tree code with the same value as VALUE rtx code
12338fd1498Szrj    has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
12438fd1498Szrj    Currently the value is the same as IDENTIFIER_NODE, which has such
12538fd1498Szrj    a property.  If this compile time assertion ever fails, make sure that
12638fd1498Szrj    the new tree code that equals (int) VALUE has the same property.  */
12738fd1498Szrj extern char check_value_val[(int) VALUE == (int) IDENTIFIER_NODE ? 1 : -1];
12838fd1498Szrj 
12938fd1498Szrj /* Type of micro operation.  */
13038fd1498Szrj enum micro_operation_type
13138fd1498Szrj {
13238fd1498Szrj   MO_USE,	/* Use location (REG or MEM).  */
13338fd1498Szrj   MO_USE_NO_VAR,/* Use location which is not associated with a variable
13438fd1498Szrj 		   or the variable is not trackable.  */
13538fd1498Szrj   MO_VAL_USE,	/* Use location which is associated with a value.  */
13638fd1498Szrj   MO_VAL_LOC,   /* Use location which appears in a debug insn.  */
13738fd1498Szrj   MO_VAL_SET,	/* Set location associated with a value.  */
13838fd1498Szrj   MO_SET,	/* Set location.  */
13938fd1498Szrj   MO_COPY,	/* Copy the same portion of a variable from one
14038fd1498Szrj 		   location to another.  */
14138fd1498Szrj   MO_CLOBBER,	/* Clobber location.  */
14238fd1498Szrj   MO_CALL,	/* Call insn.  */
14338fd1498Szrj   MO_ADJUST	/* Adjust stack pointer.  */
14438fd1498Szrj 
14538fd1498Szrj };
14638fd1498Szrj 
14738fd1498Szrj static const char * const ATTRIBUTE_UNUSED
14838fd1498Szrj micro_operation_type_name[] = {
14938fd1498Szrj   "MO_USE",
15038fd1498Szrj   "MO_USE_NO_VAR",
15138fd1498Szrj   "MO_VAL_USE",
15238fd1498Szrj   "MO_VAL_LOC",
15338fd1498Szrj   "MO_VAL_SET",
15438fd1498Szrj   "MO_SET",
15538fd1498Szrj   "MO_COPY",
15638fd1498Szrj   "MO_CLOBBER",
15738fd1498Szrj   "MO_CALL",
15838fd1498Szrj   "MO_ADJUST"
15938fd1498Szrj };
16038fd1498Szrj 
16138fd1498Szrj /* Where shall the note be emitted?  BEFORE or AFTER the instruction.
16238fd1498Szrj    Notes emitted as AFTER_CALL are to take effect during the call,
16338fd1498Szrj    rather than after the call.  */
16438fd1498Szrj enum emit_note_where
16538fd1498Szrj {
16638fd1498Szrj   EMIT_NOTE_BEFORE_INSN,
16738fd1498Szrj   EMIT_NOTE_AFTER_INSN,
16838fd1498Szrj   EMIT_NOTE_AFTER_CALL_INSN
16938fd1498Szrj };
17038fd1498Szrj 
17138fd1498Szrj /* Structure holding information about micro operation.  */
17238fd1498Szrj struct micro_operation
17338fd1498Szrj {
17438fd1498Szrj   /* Type of micro operation.  */
17538fd1498Szrj   enum micro_operation_type type;
17638fd1498Szrj 
17738fd1498Szrj   /* The instruction which the micro operation is in, for MO_USE,
17838fd1498Szrj      MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
17938fd1498Szrj      instruction or note in the original flow (before any var-tracking
18038fd1498Szrj      notes are inserted, to simplify emission of notes), for MO_SET
18138fd1498Szrj      and MO_CLOBBER.  */
18238fd1498Szrj   rtx_insn *insn;
18338fd1498Szrj 
18438fd1498Szrj   union {
18538fd1498Szrj     /* Location.  For MO_SET and MO_COPY, this is the SET that
18638fd1498Szrj        performs the assignment, if known, otherwise it is the target
18738fd1498Szrj        of the assignment.  For MO_VAL_USE and MO_VAL_SET, it is a
18838fd1498Szrj        CONCAT of the VALUE and the LOC associated with it.  For
18938fd1498Szrj        MO_VAL_LOC, it is a CONCAT of the VALUE and the VAR_LOCATION
19038fd1498Szrj        associated with it.  */
19138fd1498Szrj     rtx loc;
19238fd1498Szrj 
19338fd1498Szrj     /* Stack adjustment.  */
19438fd1498Szrj     HOST_WIDE_INT adjust;
19538fd1498Szrj   } u;
19638fd1498Szrj };
19738fd1498Szrj 
19838fd1498Szrj 
19938fd1498Szrj /* A declaration of a variable, or an RTL value being handled like a
20038fd1498Szrj    declaration.  */
20138fd1498Szrj typedef void *decl_or_value;
20238fd1498Szrj 
20338fd1498Szrj /* Return true if a decl_or_value DV is a DECL or NULL.  */
20438fd1498Szrj static inline bool
dv_is_decl_p(decl_or_value dv)20538fd1498Szrj dv_is_decl_p (decl_or_value dv)
20638fd1498Szrj {
20738fd1498Szrj   return !dv || (int) TREE_CODE ((tree) dv) != (int) VALUE;
20838fd1498Szrj }
20938fd1498Szrj 
21038fd1498Szrj /* Return true if a decl_or_value is a VALUE rtl.  */
21138fd1498Szrj static inline bool
dv_is_value_p(decl_or_value dv)21238fd1498Szrj dv_is_value_p (decl_or_value dv)
21338fd1498Szrj {
21438fd1498Szrj   return dv && !dv_is_decl_p (dv);
21538fd1498Szrj }
21638fd1498Szrj 
21738fd1498Szrj /* Return the decl in the decl_or_value.  */
21838fd1498Szrj static inline tree
dv_as_decl(decl_or_value dv)21938fd1498Szrj dv_as_decl (decl_or_value dv)
22038fd1498Szrj {
22138fd1498Szrj   gcc_checking_assert (dv_is_decl_p (dv));
22238fd1498Szrj   return (tree) dv;
22338fd1498Szrj }
22438fd1498Szrj 
22538fd1498Szrj /* Return the value in the decl_or_value.  */
22638fd1498Szrj static inline rtx
dv_as_value(decl_or_value dv)22738fd1498Szrj dv_as_value (decl_or_value dv)
22838fd1498Szrj {
22938fd1498Szrj   gcc_checking_assert (dv_is_value_p (dv));
23038fd1498Szrj   return (rtx)dv;
23138fd1498Szrj }
23238fd1498Szrj 
23338fd1498Szrj /* Return the opaque pointer in the decl_or_value.  */
23438fd1498Szrj static inline void *
dv_as_opaque(decl_or_value dv)23538fd1498Szrj dv_as_opaque (decl_or_value dv)
23638fd1498Szrj {
23738fd1498Szrj   return dv;
23838fd1498Szrj }
23938fd1498Szrj 
24038fd1498Szrj 
24138fd1498Szrj /* Description of location of a part of a variable.  The content of a physical
24238fd1498Szrj    register is described by a chain of these structures.
24338fd1498Szrj    The chains are pretty short (usually 1 or 2 elements) and thus
24438fd1498Szrj    chain is the best data structure.  */
24538fd1498Szrj struct attrs
24638fd1498Szrj {
24738fd1498Szrj   /* Pointer to next member of the list.  */
24838fd1498Szrj   attrs *next;
24938fd1498Szrj 
25038fd1498Szrj   /* The rtx of register.  */
25138fd1498Szrj   rtx loc;
25238fd1498Szrj 
25338fd1498Szrj   /* The declaration corresponding to LOC.  */
25438fd1498Szrj   decl_or_value dv;
25538fd1498Szrj 
25638fd1498Szrj   /* Offset from start of DECL.  */
25738fd1498Szrj   HOST_WIDE_INT offset;
25838fd1498Szrj };
25938fd1498Szrj 
26038fd1498Szrj /* Structure for chaining the locations.  */
26138fd1498Szrj struct location_chain
26238fd1498Szrj {
26338fd1498Szrj   /* Next element in the chain.  */
26438fd1498Szrj   location_chain *next;
26538fd1498Szrj 
26638fd1498Szrj   /* The location (REG, MEM or VALUE).  */
26738fd1498Szrj   rtx loc;
26838fd1498Szrj 
26938fd1498Szrj   /* The "value" stored in this location.  */
27038fd1498Szrj   rtx set_src;
27138fd1498Szrj 
27238fd1498Szrj   /* Initialized? */
27338fd1498Szrj   enum var_init_status init;
27438fd1498Szrj };
27538fd1498Szrj 
27638fd1498Szrj /* A vector of loc_exp_dep holds the active dependencies of a one-part
27738fd1498Szrj    DV on VALUEs, i.e., the VALUEs expanded so as to form the current
27838fd1498Szrj    location of DV.  Each entry is also part of VALUE' s linked-list of
27938fd1498Szrj    backlinks back to DV.  */
28038fd1498Szrj struct loc_exp_dep
28138fd1498Szrj {
28238fd1498Szrj   /* The dependent DV.  */
28338fd1498Szrj   decl_or_value dv;
28438fd1498Szrj   /* The dependency VALUE or DECL_DEBUG.  */
28538fd1498Szrj   rtx value;
28638fd1498Szrj   /* The next entry in VALUE's backlinks list.  */
28738fd1498Szrj   struct loc_exp_dep *next;
28838fd1498Szrj   /* A pointer to the pointer to this entry (head or prev's next) in
28938fd1498Szrj      the doubly-linked list.  */
29038fd1498Szrj   struct loc_exp_dep **pprev;
29138fd1498Szrj };
29238fd1498Szrj 
29338fd1498Szrj 
29438fd1498Szrj /* This data structure holds information about the depth of a variable
29538fd1498Szrj    expansion.  */
29638fd1498Szrj struct expand_depth
29738fd1498Szrj {
29838fd1498Szrj   /* This measures the complexity of the expanded expression.  It
29938fd1498Szrj      grows by one for each level of expansion that adds more than one
30038fd1498Szrj      operand.  */
30138fd1498Szrj   int complexity;
30238fd1498Szrj   /* This counts the number of ENTRY_VALUE expressions in an
30338fd1498Szrj      expansion.  We want to minimize their use.  */
30438fd1498Szrj   int entryvals;
30538fd1498Szrj };
30638fd1498Szrj 
30738fd1498Szrj /* This data structure is allocated for one-part variables at the time
30838fd1498Szrj    of emitting notes.  */
30938fd1498Szrj struct onepart_aux
31038fd1498Szrj {
31138fd1498Szrj   /* Doubly-linked list of dependent DVs.  These are DVs whose cur_loc
31238fd1498Szrj      computation used the expansion of this variable, and that ought
31338fd1498Szrj      to be notified should this variable change.  If the DV's cur_loc
31438fd1498Szrj      expanded to NULL, all components of the loc list are regarded as
31538fd1498Szrj      active, so that any changes in them give us a chance to get a
31638fd1498Szrj      location.  Otherwise, only components of the loc that expanded to
31738fd1498Szrj      non-NULL are regarded as active dependencies.  */
31838fd1498Szrj   loc_exp_dep *backlinks;
31938fd1498Szrj   /* This holds the LOC that was expanded into cur_loc.  We need only
32038fd1498Szrj      mark a one-part variable as changed if the FROM loc is removed,
32138fd1498Szrj      or if it has no known location and a loc is added, or if it gets
32238fd1498Szrj      a change notification from any of its active dependencies.  */
32338fd1498Szrj   rtx from;
32438fd1498Szrj   /* The depth of the cur_loc expression.  */
32538fd1498Szrj   expand_depth depth;
32638fd1498Szrj   /* Dependencies actively used when expand FROM into cur_loc.  */
32738fd1498Szrj   vec<loc_exp_dep, va_heap, vl_embed> deps;
32838fd1498Szrj };
32938fd1498Szrj 
33038fd1498Szrj /* Structure describing one part of variable.  */
33138fd1498Szrj struct variable_part
33238fd1498Szrj {
33338fd1498Szrj   /* Chain of locations of the part.  */
33438fd1498Szrj   location_chain *loc_chain;
33538fd1498Szrj 
33638fd1498Szrj   /* Location which was last emitted to location list.  */
33738fd1498Szrj   rtx cur_loc;
33838fd1498Szrj 
33938fd1498Szrj   union variable_aux
34038fd1498Szrj   {
34138fd1498Szrj     /* The offset in the variable, if !var->onepart.  */
34238fd1498Szrj     HOST_WIDE_INT offset;
34338fd1498Szrj 
34438fd1498Szrj     /* Pointer to auxiliary data, if var->onepart and emit_notes.  */
34538fd1498Szrj     struct onepart_aux *onepaux;
34638fd1498Szrj   } aux;
34738fd1498Szrj };
34838fd1498Szrj 
34938fd1498Szrj /* Maximum number of location parts.  */
35038fd1498Szrj #define MAX_VAR_PARTS 16
35138fd1498Szrj 
35238fd1498Szrj /* Enumeration type used to discriminate various types of one-part
35338fd1498Szrj    variables.  */
35438fd1498Szrj enum onepart_enum
35538fd1498Szrj {
35638fd1498Szrj   /* Not a one-part variable.  */
35738fd1498Szrj   NOT_ONEPART = 0,
35838fd1498Szrj   /* A one-part DECL that is not a DEBUG_EXPR_DECL.  */
35938fd1498Szrj   ONEPART_VDECL = 1,
36038fd1498Szrj   /* A DEBUG_EXPR_DECL.  */
36138fd1498Szrj   ONEPART_DEXPR = 2,
36238fd1498Szrj   /* A VALUE.  */
36338fd1498Szrj   ONEPART_VALUE = 3
36438fd1498Szrj };
36538fd1498Szrj 
36638fd1498Szrj /* Structure describing where the variable is located.  */
36738fd1498Szrj struct variable
36838fd1498Szrj {
36938fd1498Szrj   /* The declaration of the variable, or an RTL value being handled
37038fd1498Szrj      like a declaration.  */
37138fd1498Szrj   decl_or_value dv;
37238fd1498Szrj 
37338fd1498Szrj   /* Reference count.  */
37438fd1498Szrj   int refcount;
37538fd1498Szrj 
37638fd1498Szrj   /* Number of variable parts.  */
37738fd1498Szrj   char n_var_parts;
37838fd1498Szrj 
37938fd1498Szrj   /* What type of DV this is, according to enum onepart_enum.  */
38038fd1498Szrj   ENUM_BITFIELD (onepart_enum) onepart : CHAR_BIT;
38138fd1498Szrj 
38238fd1498Szrj   /* True if this variable_def struct is currently in the
38338fd1498Szrj      changed_variables hash table.  */
38438fd1498Szrj   bool in_changed_variables;
38538fd1498Szrj 
38638fd1498Szrj   /* The variable parts.  */
38738fd1498Szrj   variable_part var_part[1];
38838fd1498Szrj };
38938fd1498Szrj 
39038fd1498Szrj /* Pointer to the BB's information specific to variable tracking pass.  */
39138fd1498Szrj #define VTI(BB) ((variable_tracking_info *) (BB)->aux)
39238fd1498Szrj 
39338fd1498Szrj /* Return MEM_OFFSET (MEM) as a HOST_WIDE_INT, or 0 if we can't.  */
39438fd1498Szrj 
39538fd1498Szrj static inline HOST_WIDE_INT
int_mem_offset(const_rtx mem)39638fd1498Szrj int_mem_offset (const_rtx mem)
39738fd1498Szrj {
39838fd1498Szrj   HOST_WIDE_INT offset;
39938fd1498Szrj   if (MEM_OFFSET_KNOWN_P (mem) && MEM_OFFSET (mem).is_constant (&offset))
40038fd1498Szrj     return offset;
40138fd1498Szrj   return 0;
40238fd1498Szrj }
40338fd1498Szrj 
40438fd1498Szrj #if CHECKING_P && (GCC_VERSION >= 2007)
40538fd1498Szrj 
40638fd1498Szrj /* Access VAR's Ith part's offset, checking that it's not a one-part
40738fd1498Szrj    variable.  */
40838fd1498Szrj #define VAR_PART_OFFSET(var, i) __extension__			\
40938fd1498Szrj (*({  variable *const __v = (var);				\
41038fd1498Szrj       gcc_checking_assert (!__v->onepart);			\
41138fd1498Szrj       &__v->var_part[(i)].aux.offset; }))
41238fd1498Szrj 
41338fd1498Szrj /* Access VAR's one-part auxiliary data, checking that it is a
41438fd1498Szrj    one-part variable.  */
41538fd1498Szrj #define VAR_LOC_1PAUX(var) __extension__			\
41638fd1498Szrj (*({  variable *const __v = (var);				\
41738fd1498Szrj       gcc_checking_assert (__v->onepart);			\
41838fd1498Szrj       &__v->var_part[0].aux.onepaux; }))
41938fd1498Szrj 
42038fd1498Szrj #else
42138fd1498Szrj #define VAR_PART_OFFSET(var, i) ((var)->var_part[(i)].aux.offset)
42238fd1498Szrj #define VAR_LOC_1PAUX(var) ((var)->var_part[0].aux.onepaux)
42338fd1498Szrj #endif
42438fd1498Szrj 
42538fd1498Szrj /* These are accessor macros for the one-part auxiliary data.  When
42638fd1498Szrj    convenient for users, they're guarded by tests that the data was
42738fd1498Szrj    allocated.  */
42838fd1498Szrj #define VAR_LOC_DEP_LST(var) (VAR_LOC_1PAUX (var)		  \
42938fd1498Szrj 			      ? VAR_LOC_1PAUX (var)->backlinks	  \
43038fd1498Szrj 			      : NULL)
43138fd1498Szrj #define VAR_LOC_DEP_LSTP(var) (VAR_LOC_1PAUX (var)		  \
43238fd1498Szrj 			       ? &VAR_LOC_1PAUX (var)->backlinks  \
43338fd1498Szrj 			       : NULL)
43438fd1498Szrj #define VAR_LOC_FROM(var) (VAR_LOC_1PAUX (var)->from)
43538fd1498Szrj #define VAR_LOC_DEPTH(var) (VAR_LOC_1PAUX (var)->depth)
43638fd1498Szrj #define VAR_LOC_DEP_VEC(var) (VAR_LOC_1PAUX (var)		  \
43738fd1498Szrj 			      ? &VAR_LOC_1PAUX (var)->deps	  \
43838fd1498Szrj 			      : NULL)
43938fd1498Szrj 
44038fd1498Szrj 
44138fd1498Szrj 
44238fd1498Szrj typedef unsigned int dvuid;
44338fd1498Szrj 
44438fd1498Szrj /* Return the uid of DV.  */
44538fd1498Szrj 
44638fd1498Szrj static inline dvuid
dv_uid(decl_or_value dv)44738fd1498Szrj dv_uid (decl_or_value dv)
44838fd1498Szrj {
44938fd1498Szrj   if (dv_is_value_p (dv))
45038fd1498Szrj     return CSELIB_VAL_PTR (dv_as_value (dv))->uid;
45138fd1498Szrj   else
45238fd1498Szrj     return DECL_UID (dv_as_decl (dv));
45338fd1498Szrj }
45438fd1498Szrj 
45538fd1498Szrj /* Compute the hash from the uid.  */
45638fd1498Szrj 
45738fd1498Szrj static inline hashval_t
dv_uid2hash(dvuid uid)45838fd1498Szrj dv_uid2hash (dvuid uid)
45938fd1498Szrj {
46038fd1498Szrj   return uid;
46138fd1498Szrj }
46238fd1498Szrj 
46338fd1498Szrj /* The hash function for a mask table in a shared_htab chain.  */
46438fd1498Szrj 
46538fd1498Szrj static inline hashval_t
dv_htab_hash(decl_or_value dv)46638fd1498Szrj dv_htab_hash (decl_or_value dv)
46738fd1498Szrj {
46838fd1498Szrj   return dv_uid2hash (dv_uid (dv));
46938fd1498Szrj }
47038fd1498Szrj 
47138fd1498Szrj static void variable_htab_free (void *);
47238fd1498Szrj 
47338fd1498Szrj /* Variable hashtable helpers.  */
47438fd1498Szrj 
47538fd1498Szrj struct variable_hasher : pointer_hash <variable>
47638fd1498Szrj {
47738fd1498Szrj   typedef void *compare_type;
47838fd1498Szrj   static inline hashval_t hash (const variable *);
47938fd1498Szrj   static inline bool equal (const variable *, const void *);
48038fd1498Szrj   static inline void remove (variable *);
48138fd1498Szrj };
48238fd1498Szrj 
48338fd1498Szrj /* The hash function for variable_htab, computes the hash value
48438fd1498Szrj    from the declaration of variable X.  */
48538fd1498Szrj 
48638fd1498Szrj inline hashval_t
hash(const variable * v)48738fd1498Szrj variable_hasher::hash (const variable *v)
48838fd1498Szrj {
48938fd1498Szrj   return dv_htab_hash (v->dv);
49038fd1498Szrj }
49138fd1498Szrj 
49238fd1498Szrj /* Compare the declaration of variable X with declaration Y.  */
49338fd1498Szrj 
49438fd1498Szrj inline bool
equal(const variable * v,const void * y)49538fd1498Szrj variable_hasher::equal (const variable *v, const void *y)
49638fd1498Szrj {
49738fd1498Szrj   decl_or_value dv = CONST_CAST2 (decl_or_value, const void *, y);
49838fd1498Szrj 
49938fd1498Szrj   return (dv_as_opaque (v->dv) == dv_as_opaque (dv));
50038fd1498Szrj }
50138fd1498Szrj 
50238fd1498Szrj /* Free the element of VARIABLE_HTAB (its type is struct variable_def).  */
50338fd1498Szrj 
50438fd1498Szrj inline void
remove(variable * var)50538fd1498Szrj variable_hasher::remove (variable *var)
50638fd1498Szrj {
50738fd1498Szrj   variable_htab_free (var);
50838fd1498Szrj }
50938fd1498Szrj 
51038fd1498Szrj typedef hash_table<variable_hasher> variable_table_type;
51138fd1498Szrj typedef variable_table_type::iterator variable_iterator_type;
51238fd1498Szrj 
51338fd1498Szrj /* Structure for passing some other parameters to function
51438fd1498Szrj    emit_note_insn_var_location.  */
51538fd1498Szrj struct emit_note_data
51638fd1498Szrj {
51738fd1498Szrj   /* The instruction which the note will be emitted before/after.  */
51838fd1498Szrj   rtx_insn *insn;
51938fd1498Szrj 
52038fd1498Szrj   /* Where the note will be emitted (before/after insn)?  */
52138fd1498Szrj   enum emit_note_where where;
52238fd1498Szrj 
52338fd1498Szrj   /* The variables and values active at this point.  */
52438fd1498Szrj   variable_table_type *vars;
52538fd1498Szrj };
52638fd1498Szrj 
52738fd1498Szrj /* Structure holding a refcounted hash table.  If refcount > 1,
52838fd1498Szrj    it must be first unshared before modified.  */
52938fd1498Szrj struct shared_hash
53038fd1498Szrj {
53138fd1498Szrj   /* Reference count.  */
53238fd1498Szrj   int refcount;
53338fd1498Szrj 
53438fd1498Szrj   /* Actual hash table.  */
53538fd1498Szrj   variable_table_type *htab;
53638fd1498Szrj };
53738fd1498Szrj 
53838fd1498Szrj /* Structure holding the IN or OUT set for a basic block.  */
53938fd1498Szrj struct dataflow_set
54038fd1498Szrj {
54138fd1498Szrj   /* Adjustment of stack offset.  */
54238fd1498Szrj   HOST_WIDE_INT stack_adjust;
54338fd1498Szrj 
54438fd1498Szrj   /* Attributes for registers (lists of attrs).  */
54538fd1498Szrj   attrs *regs[FIRST_PSEUDO_REGISTER];
54638fd1498Szrj 
54738fd1498Szrj   /* Variable locations.  */
54838fd1498Szrj   shared_hash *vars;
54938fd1498Szrj 
55038fd1498Szrj   /* Vars that is being traversed.  */
55138fd1498Szrj   shared_hash *traversed_vars;
55238fd1498Szrj };
55338fd1498Szrj 
55438fd1498Szrj /* The structure (one for each basic block) containing the information
55538fd1498Szrj    needed for variable tracking.  */
55638fd1498Szrj struct variable_tracking_info
55738fd1498Szrj {
55838fd1498Szrj   /* The vector of micro operations.  */
55938fd1498Szrj   vec<micro_operation> mos;
56038fd1498Szrj 
56138fd1498Szrj   /* The IN and OUT set for dataflow analysis.  */
56238fd1498Szrj   dataflow_set in;
56338fd1498Szrj   dataflow_set out;
56438fd1498Szrj 
56538fd1498Szrj   /* The permanent-in dataflow set for this block.  This is used to
56638fd1498Szrj      hold values for which we had to compute entry values.  ??? This
56738fd1498Szrj      should probably be dynamically allocated, to avoid using more
56838fd1498Szrj      memory in non-debug builds.  */
56938fd1498Szrj   dataflow_set *permp;
57038fd1498Szrj 
57138fd1498Szrj   /* Has the block been visited in DFS?  */
57238fd1498Szrj   bool visited;
57338fd1498Szrj 
57438fd1498Szrj   /* Has the block been flooded in VTA?  */
57538fd1498Szrj   bool flooded;
57638fd1498Szrj 
57738fd1498Szrj };
57838fd1498Szrj 
57938fd1498Szrj /* Alloc pool for struct attrs_def.  */
58038fd1498Szrj object_allocator<attrs> attrs_pool ("attrs pool");
58138fd1498Szrj 
58238fd1498Szrj /* Alloc pool for struct variable_def with MAX_VAR_PARTS entries.  */
58338fd1498Szrj 
58438fd1498Szrj static pool_allocator var_pool
58538fd1498Szrj   ("variable_def pool", sizeof (variable) +
58638fd1498Szrj    (MAX_VAR_PARTS - 1) * sizeof (((variable *)NULL)->var_part[0]));
58738fd1498Szrj 
58838fd1498Szrj /* Alloc pool for struct variable_def with a single var_part entry.  */
58938fd1498Szrj static pool_allocator valvar_pool
59038fd1498Szrj   ("small variable_def pool", sizeof (variable));
59138fd1498Szrj 
59238fd1498Szrj /* Alloc pool for struct location_chain.  */
59338fd1498Szrj static object_allocator<location_chain> location_chain_pool
59438fd1498Szrj   ("location_chain pool");
59538fd1498Szrj 
59638fd1498Szrj /* Alloc pool for struct shared_hash.  */
59738fd1498Szrj static object_allocator<shared_hash> shared_hash_pool ("shared_hash pool");
59838fd1498Szrj 
59938fd1498Szrj /* Alloc pool for struct loc_exp_dep_s for NOT_ONEPART variables.  */
60038fd1498Szrj object_allocator<loc_exp_dep> loc_exp_dep_pool ("loc_exp_dep pool");
60138fd1498Szrj 
60238fd1498Szrj /* Changed variables, notes will be emitted for them.  */
60338fd1498Szrj static variable_table_type *changed_variables;
60438fd1498Szrj 
60538fd1498Szrj /* Shall notes be emitted?  */
60638fd1498Szrj static bool emit_notes;
60738fd1498Szrj 
60838fd1498Szrj /* Values whose dynamic location lists have gone empty, but whose
60938fd1498Szrj    cselib location lists are still usable.  Use this to hold the
61038fd1498Szrj    current location, the backlinks, etc, during emit_notes.  */
61138fd1498Szrj static variable_table_type *dropped_values;
61238fd1498Szrj 
61338fd1498Szrj /* Empty shared hashtable.  */
61438fd1498Szrj static shared_hash *empty_shared_hash;
61538fd1498Szrj 
61638fd1498Szrj /* Scratch register bitmap used by cselib_expand_value_rtx.  */
61738fd1498Szrj static bitmap scratch_regs = NULL;
61838fd1498Szrj 
61938fd1498Szrj #ifdef HAVE_window_save
62038fd1498Szrj struct GTY(()) parm_reg {
62138fd1498Szrj   rtx outgoing;
62238fd1498Szrj   rtx incoming;
62338fd1498Szrj };
62438fd1498Szrj 
62538fd1498Szrj 
62638fd1498Szrj /* Vector of windowed parameter registers, if any.  */
62738fd1498Szrj static vec<parm_reg, va_gc> *windowed_parm_regs = NULL;
62838fd1498Szrj #endif
62938fd1498Szrj 
63038fd1498Szrj /* Variable used to tell whether cselib_process_insn called our hook.  */
63138fd1498Szrj static bool cselib_hook_called;
63238fd1498Szrj 
63338fd1498Szrj /* Local function prototypes.  */
63438fd1498Szrj static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
63538fd1498Szrj 					  HOST_WIDE_INT *);
63638fd1498Szrj static void insn_stack_adjust_offset_pre_post (rtx_insn *, HOST_WIDE_INT *,
63738fd1498Szrj 					       HOST_WIDE_INT *);
63838fd1498Szrj static bool vt_stack_adjustments (void);
63938fd1498Szrj 
64038fd1498Szrj static void init_attrs_list_set (attrs **);
64138fd1498Szrj static void attrs_list_clear (attrs **);
64238fd1498Szrj static attrs *attrs_list_member (attrs *, decl_or_value, HOST_WIDE_INT);
64338fd1498Szrj static void attrs_list_insert (attrs **, decl_or_value, HOST_WIDE_INT, rtx);
64438fd1498Szrj static void attrs_list_copy (attrs **, attrs *);
64538fd1498Szrj static void attrs_list_union (attrs **, attrs *);
64638fd1498Szrj 
64738fd1498Szrj static variable **unshare_variable (dataflow_set *set, variable **slot,
64838fd1498Szrj 					variable *var, enum var_init_status);
64938fd1498Szrj static void vars_copy (variable_table_type *, variable_table_type *);
65038fd1498Szrj static tree var_debug_decl (tree);
65138fd1498Szrj static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
65238fd1498Szrj static void var_reg_delete_and_set (dataflow_set *, rtx, bool,
65338fd1498Szrj 				    enum var_init_status, rtx);
65438fd1498Szrj static void var_reg_delete (dataflow_set *, rtx, bool);
65538fd1498Szrj static void var_regno_delete (dataflow_set *, int);
65638fd1498Szrj static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx);
65738fd1498Szrj static void var_mem_delete_and_set (dataflow_set *, rtx, bool,
65838fd1498Szrj 				    enum var_init_status, rtx);
65938fd1498Szrj static void var_mem_delete (dataflow_set *, rtx, bool);
66038fd1498Szrj 
66138fd1498Szrj static void dataflow_set_init (dataflow_set *);
66238fd1498Szrj static void dataflow_set_clear (dataflow_set *);
66338fd1498Szrj static void dataflow_set_copy (dataflow_set *, dataflow_set *);
66438fd1498Szrj static int variable_union_info_cmp_pos (const void *, const void *);
66538fd1498Szrj static void dataflow_set_union (dataflow_set *, dataflow_set *);
66638fd1498Szrj static location_chain *find_loc_in_1pdv (rtx, variable *,
66738fd1498Szrj 					 variable_table_type *);
66838fd1498Szrj static bool canon_value_cmp (rtx, rtx);
66938fd1498Szrj static int loc_cmp (rtx, rtx);
67038fd1498Szrj static bool variable_part_different_p (variable_part *, variable_part *);
67138fd1498Szrj static bool onepart_variable_different_p (variable *, variable *);
67238fd1498Szrj static bool variable_different_p (variable *, variable *);
67338fd1498Szrj static bool dataflow_set_different (dataflow_set *, dataflow_set *);
67438fd1498Szrj static void dataflow_set_destroy (dataflow_set *);
67538fd1498Szrj 
67638fd1498Szrj static bool track_expr_p (tree, bool);
67738fd1498Szrj static void add_uses_1 (rtx *, void *);
67838fd1498Szrj static void add_stores (rtx, const_rtx, void *);
67938fd1498Szrj static bool compute_bb_dataflow (basic_block);
68038fd1498Szrj static bool vt_find_locations (void);
68138fd1498Szrj 
68238fd1498Szrj static void dump_attrs_list (attrs *);
68338fd1498Szrj static void dump_var (variable *);
68438fd1498Szrj static void dump_vars (variable_table_type *);
68538fd1498Szrj static void dump_dataflow_set (dataflow_set *);
68638fd1498Szrj static void dump_dataflow_sets (void);
68738fd1498Szrj 
68838fd1498Szrj static void set_dv_changed (decl_or_value, bool);
68938fd1498Szrj static void variable_was_changed (variable *, dataflow_set *);
69038fd1498Szrj static variable **set_slot_part (dataflow_set *, rtx, variable **,
69138fd1498Szrj 				 decl_or_value, HOST_WIDE_INT,
69238fd1498Szrj 				 enum var_init_status, rtx);
69338fd1498Szrj static void set_variable_part (dataflow_set *, rtx,
69438fd1498Szrj 			       decl_or_value, HOST_WIDE_INT,
69538fd1498Szrj 			       enum var_init_status, rtx, enum insert_option);
69638fd1498Szrj static variable **clobber_slot_part (dataflow_set *, rtx,
69738fd1498Szrj 				     variable **, HOST_WIDE_INT, rtx);
69838fd1498Szrj static void clobber_variable_part (dataflow_set *, rtx,
69938fd1498Szrj 				   decl_or_value, HOST_WIDE_INT, rtx);
70038fd1498Szrj static variable **delete_slot_part (dataflow_set *, rtx, variable **,
70138fd1498Szrj 				    HOST_WIDE_INT);
70238fd1498Szrj static void delete_variable_part (dataflow_set *, rtx,
70338fd1498Szrj 				  decl_or_value, HOST_WIDE_INT);
70438fd1498Szrj static void emit_notes_in_bb (basic_block, dataflow_set *);
70538fd1498Szrj static void vt_emit_notes (void);
70638fd1498Szrj 
70738fd1498Szrj static void vt_add_function_parameters (void);
70838fd1498Szrj static bool vt_initialize (void);
70938fd1498Szrj static void vt_finalize (void);
71038fd1498Szrj 
71138fd1498Szrj /* Callback for stack_adjust_offset_pre_post, called via for_each_inc_dec.  */
71238fd1498Szrj 
71338fd1498Szrj static int
stack_adjust_offset_pre_post_cb(rtx,rtx op,rtx dest,rtx src,rtx srcoff,void * arg)71438fd1498Szrj stack_adjust_offset_pre_post_cb (rtx, rtx op, rtx dest, rtx src, rtx srcoff,
71538fd1498Szrj 				 void *arg)
71638fd1498Szrj {
71738fd1498Szrj   if (dest != stack_pointer_rtx)
71838fd1498Szrj     return 0;
71938fd1498Szrj 
72038fd1498Szrj   switch (GET_CODE (op))
72138fd1498Szrj     {
72238fd1498Szrj     case PRE_INC:
72338fd1498Szrj     case PRE_DEC:
72438fd1498Szrj       ((HOST_WIDE_INT *)arg)[0] -= INTVAL (srcoff);
72538fd1498Szrj       return 0;
72638fd1498Szrj     case POST_INC:
72738fd1498Szrj     case POST_DEC:
72838fd1498Szrj       ((HOST_WIDE_INT *)arg)[1] -= INTVAL (srcoff);
72938fd1498Szrj       return 0;
73038fd1498Szrj     case PRE_MODIFY:
73138fd1498Szrj     case POST_MODIFY:
73238fd1498Szrj       /* We handle only adjustments by constant amount.  */
73338fd1498Szrj       gcc_assert (GET_CODE (src) == PLUS
73438fd1498Szrj 		  && CONST_INT_P (XEXP (src, 1))
73538fd1498Szrj 		  && XEXP (src, 0) == stack_pointer_rtx);
73638fd1498Szrj       ((HOST_WIDE_INT *)arg)[GET_CODE (op) == POST_MODIFY]
73738fd1498Szrj 	-= INTVAL (XEXP (src, 1));
73838fd1498Szrj       return 0;
73938fd1498Szrj     default:
74038fd1498Szrj       gcc_unreachable ();
74138fd1498Szrj     }
74238fd1498Szrj }
74338fd1498Szrj 
74438fd1498Szrj /* Given a SET, calculate the amount of stack adjustment it contains
74538fd1498Szrj    PRE- and POST-modifying stack pointer.
74638fd1498Szrj    This function is similar to stack_adjust_offset.  */
74738fd1498Szrj 
74838fd1498Szrj static void
stack_adjust_offset_pre_post(rtx pattern,HOST_WIDE_INT * pre,HOST_WIDE_INT * post)74938fd1498Szrj stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INT *pre,
75038fd1498Szrj 			      HOST_WIDE_INT *post)
75138fd1498Szrj {
75238fd1498Szrj   rtx src = SET_SRC (pattern);
75338fd1498Szrj   rtx dest = SET_DEST (pattern);
75438fd1498Szrj   enum rtx_code code;
75538fd1498Szrj 
75638fd1498Szrj   if (dest == stack_pointer_rtx)
75738fd1498Szrj     {
75838fd1498Szrj       /* (set (reg sp) (plus (reg sp) (const_int))) */
75938fd1498Szrj       code = GET_CODE (src);
76038fd1498Szrj       if (! (code == PLUS || code == MINUS)
76138fd1498Szrj 	  || XEXP (src, 0) != stack_pointer_rtx
76238fd1498Szrj 	  || !CONST_INT_P (XEXP (src, 1)))
76338fd1498Szrj 	return;
76438fd1498Szrj 
76538fd1498Szrj       if (code == MINUS)
76638fd1498Szrj 	*post += INTVAL (XEXP (src, 1));
76738fd1498Szrj       else
76838fd1498Szrj 	*post -= INTVAL (XEXP (src, 1));
76938fd1498Szrj       return;
77038fd1498Szrj     }
77138fd1498Szrj   HOST_WIDE_INT res[2] = { 0, 0 };
77238fd1498Szrj   for_each_inc_dec (pattern, stack_adjust_offset_pre_post_cb, res);
77338fd1498Szrj   *pre += res[0];
77438fd1498Szrj   *post += res[1];
77538fd1498Szrj }
77638fd1498Szrj 
77738fd1498Szrj /* Given an INSN, calculate the amount of stack adjustment it contains
77838fd1498Szrj    PRE- and POST-modifying stack pointer.  */
77938fd1498Szrj 
78038fd1498Szrj static void
insn_stack_adjust_offset_pre_post(rtx_insn * insn,HOST_WIDE_INT * pre,HOST_WIDE_INT * post)78138fd1498Szrj insn_stack_adjust_offset_pre_post (rtx_insn *insn, HOST_WIDE_INT *pre,
78238fd1498Szrj 				   HOST_WIDE_INT *post)
78338fd1498Szrj {
78438fd1498Szrj   rtx pattern;
78538fd1498Szrj 
78638fd1498Szrj   *pre = 0;
78738fd1498Szrj   *post = 0;
78838fd1498Szrj 
78938fd1498Szrj   pattern = PATTERN (insn);
79038fd1498Szrj   if (RTX_FRAME_RELATED_P (insn))
79138fd1498Szrj     {
79238fd1498Szrj       rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
79338fd1498Szrj       if (expr)
79438fd1498Szrj 	pattern = XEXP (expr, 0);
79538fd1498Szrj     }
79638fd1498Szrj 
79738fd1498Szrj   if (GET_CODE (pattern) == SET)
79838fd1498Szrj     stack_adjust_offset_pre_post (pattern, pre, post);
79938fd1498Szrj   else if (GET_CODE (pattern) == PARALLEL
80038fd1498Szrj 	   || GET_CODE (pattern) == SEQUENCE)
80138fd1498Szrj     {
80238fd1498Szrj       int i;
80338fd1498Szrj 
80438fd1498Szrj       /* There may be stack adjustments inside compound insns.  Search
80538fd1498Szrj 	 for them.  */
80638fd1498Szrj       for ( i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
80738fd1498Szrj 	if (GET_CODE (XVECEXP (pattern, 0, i)) == SET)
80838fd1498Szrj 	  stack_adjust_offset_pre_post (XVECEXP (pattern, 0, i), pre, post);
80938fd1498Szrj     }
81038fd1498Szrj }
81138fd1498Szrj 
81238fd1498Szrj /* Compute stack adjustments for all blocks by traversing DFS tree.
81338fd1498Szrj    Return true when the adjustments on all incoming edges are consistent.
81438fd1498Szrj    Heavily borrowed from pre_and_rev_post_order_compute.  */
81538fd1498Szrj 
81638fd1498Szrj static bool
vt_stack_adjustments(void)81738fd1498Szrj vt_stack_adjustments (void)
81838fd1498Szrj {
81938fd1498Szrj   edge_iterator *stack;
82038fd1498Szrj   int sp;
82138fd1498Szrj 
82238fd1498Szrj   /* Initialize entry block.  */
82338fd1498Szrj   VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->visited = true;
82438fd1498Szrj   VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->in.stack_adjust
82538fd1498Szrj     = INCOMING_FRAME_SP_OFFSET;
82638fd1498Szrj   VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out.stack_adjust
82738fd1498Szrj     = INCOMING_FRAME_SP_OFFSET;
82838fd1498Szrj 
82938fd1498Szrj   /* Allocate stack for back-tracking up CFG.  */
83038fd1498Szrj   stack = XNEWVEC (edge_iterator, n_basic_blocks_for_fn (cfun) + 1);
83138fd1498Szrj   sp = 0;
83238fd1498Szrj 
83338fd1498Szrj   /* Push the first edge on to the stack.  */
83438fd1498Szrj   stack[sp++] = ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs);
83538fd1498Szrj 
83638fd1498Szrj   while (sp)
83738fd1498Szrj     {
83838fd1498Szrj       edge_iterator ei;
83938fd1498Szrj       basic_block src;
84038fd1498Szrj       basic_block dest;
84138fd1498Szrj 
84238fd1498Szrj       /* Look at the edge on the top of the stack.  */
84338fd1498Szrj       ei = stack[sp - 1];
84438fd1498Szrj       src = ei_edge (ei)->src;
84538fd1498Szrj       dest = ei_edge (ei)->dest;
84638fd1498Szrj 
84738fd1498Szrj       /* Check if the edge destination has been visited yet.  */
84838fd1498Szrj       if (!VTI (dest)->visited)
84938fd1498Szrj 	{
85038fd1498Szrj 	  rtx_insn *insn;
85138fd1498Szrj 	  HOST_WIDE_INT pre, post, offset;
85238fd1498Szrj 	  VTI (dest)->visited = true;
85338fd1498Szrj 	  VTI (dest)->in.stack_adjust = offset = VTI (src)->out.stack_adjust;
85438fd1498Szrj 
85538fd1498Szrj 	  if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
85638fd1498Szrj 	    for (insn = BB_HEAD (dest);
85738fd1498Szrj 		 insn != NEXT_INSN (BB_END (dest));
85838fd1498Szrj 		 insn = NEXT_INSN (insn))
85938fd1498Szrj 	      if (INSN_P (insn))
86038fd1498Szrj 		{
86138fd1498Szrj 		  insn_stack_adjust_offset_pre_post (insn, &pre, &post);
86238fd1498Szrj 		  offset += pre + post;
86338fd1498Szrj 		}
86438fd1498Szrj 
86538fd1498Szrj 	  VTI (dest)->out.stack_adjust = offset;
86638fd1498Szrj 
86738fd1498Szrj 	  if (EDGE_COUNT (dest->succs) > 0)
86838fd1498Szrj 	    /* Since the DEST node has been visited for the first
86938fd1498Szrj 	       time, check its successors.  */
87038fd1498Szrj 	    stack[sp++] = ei_start (dest->succs);
87138fd1498Szrj 	}
87238fd1498Szrj       else
87338fd1498Szrj 	{
87438fd1498Szrj 	  /* We can end up with different stack adjustments for the exit block
87538fd1498Szrj 	     of a shrink-wrapped function if stack_adjust_offset_pre_post
87638fd1498Szrj 	     doesn't understand the rtx pattern used to restore the stack
87738fd1498Szrj 	     pointer in the epilogue.  For example, on s390(x), the stack
87838fd1498Szrj 	     pointer is often restored via a load-multiple instruction
87938fd1498Szrj 	     and so no stack_adjust offset is recorded for it.  This means
88038fd1498Szrj 	     that the stack offset at the end of the epilogue block is the
88138fd1498Szrj 	     same as the offset before the epilogue, whereas other paths
88238fd1498Szrj 	     to the exit block will have the correct stack_adjust.
88338fd1498Szrj 
88438fd1498Szrj 	     It is safe to ignore these differences because (a) we never
88538fd1498Szrj 	     use the stack_adjust for the exit block in this pass and
88638fd1498Szrj 	     (b) dwarf2cfi checks whether the CFA notes in a shrink-wrapped
88738fd1498Szrj 	     function are correct.
88838fd1498Szrj 
88938fd1498Szrj 	     We must check whether the adjustments on other edges are
89038fd1498Szrj 	     the same though.  */
89138fd1498Szrj 	  if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
89238fd1498Szrj 	      && VTI (dest)->in.stack_adjust != VTI (src)->out.stack_adjust)
89338fd1498Szrj 	    {
89438fd1498Szrj 	      free (stack);
89538fd1498Szrj 	      return false;
89638fd1498Szrj 	    }
89738fd1498Szrj 
89838fd1498Szrj 	  if (! ei_one_before_end_p (ei))
89938fd1498Szrj 	    /* Go to the next edge.  */
90038fd1498Szrj 	    ei_next (&stack[sp - 1]);
90138fd1498Szrj 	  else
90238fd1498Szrj 	    /* Return to previous level if there are no more edges.  */
90338fd1498Szrj 	    sp--;
90438fd1498Szrj 	}
90538fd1498Szrj     }
90638fd1498Szrj 
90738fd1498Szrj   free (stack);
90838fd1498Szrj   return true;
90938fd1498Szrj }
91038fd1498Szrj 
91138fd1498Szrj /* arg_pointer_rtx resp. frame_pointer_rtx if stack_pointer_rtx or
91238fd1498Szrj    hard_frame_pointer_rtx is being mapped to it and offset for it.  */
91338fd1498Szrj static rtx cfa_base_rtx;
91438fd1498Szrj static HOST_WIDE_INT cfa_base_offset;
91538fd1498Szrj 
91638fd1498Szrj /* Compute a CFA-based value for an ADJUSTMENT made to stack_pointer_rtx
91738fd1498Szrj    or hard_frame_pointer_rtx.  */
91838fd1498Szrj 
91938fd1498Szrj static inline rtx
compute_cfa_pointer(HOST_WIDE_INT adjustment)92038fd1498Szrj compute_cfa_pointer (HOST_WIDE_INT adjustment)
92138fd1498Szrj {
92238fd1498Szrj   return plus_constant (Pmode, cfa_base_rtx, adjustment + cfa_base_offset);
92338fd1498Szrj }
92438fd1498Szrj 
92538fd1498Szrj /* Adjustment for hard_frame_pointer_rtx to cfa base reg,
92638fd1498Szrj    or -1 if the replacement shouldn't be done.  */
92738fd1498Szrj static HOST_WIDE_INT hard_frame_pointer_adjustment = -1;
92838fd1498Szrj 
92938fd1498Szrj /* Data for adjust_mems callback.  */
93038fd1498Szrj 
93138fd1498Szrj struct adjust_mem_data
93238fd1498Szrj {
93338fd1498Szrj   bool store;
93438fd1498Szrj   machine_mode mem_mode;
93538fd1498Szrj   HOST_WIDE_INT stack_adjust;
93638fd1498Szrj   auto_vec<rtx> side_effects;
93738fd1498Szrj };
93838fd1498Szrj 
93938fd1498Szrj /* Helper for adjust_mems.  Return true if X is suitable for
94038fd1498Szrj    transformation of wider mode arithmetics to narrower mode.  */
94138fd1498Szrj 
94238fd1498Szrj static bool
use_narrower_mode_test(rtx x,const_rtx subreg)94338fd1498Szrj use_narrower_mode_test (rtx x, const_rtx subreg)
94438fd1498Szrj {
94538fd1498Szrj   subrtx_var_iterator::array_type array;
94638fd1498Szrj   FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST)
94738fd1498Szrj     {
94838fd1498Szrj       rtx x = *iter;
94938fd1498Szrj       if (CONSTANT_P (x))
95038fd1498Szrj 	iter.skip_subrtxes ();
95138fd1498Szrj       else
95238fd1498Szrj 	switch (GET_CODE (x))
95338fd1498Szrj 	  {
95438fd1498Szrj 	  case REG:
95538fd1498Szrj 	    if (cselib_lookup (x, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
95638fd1498Szrj 	      return false;
95738fd1498Szrj 	    if (!validate_subreg (GET_MODE (subreg), GET_MODE (x), x,
95838fd1498Szrj 				  subreg_lowpart_offset (GET_MODE (subreg),
95938fd1498Szrj 							 GET_MODE (x))))
96038fd1498Szrj 	      return false;
96138fd1498Szrj 	    break;
96238fd1498Szrj 	  case PLUS:
96338fd1498Szrj 	  case MINUS:
96438fd1498Szrj 	  case MULT:
96538fd1498Szrj 	    break;
96638fd1498Szrj 	  case ASHIFT:
967*58e805e6Szrj 	    if (GET_MODE (XEXP (x, 1)) != VOIDmode)
968*58e805e6Szrj 	      {
969*58e805e6Szrj 		enum machine_mode mode = GET_MODE (subreg);
970*58e805e6Szrj 		rtx op1 = XEXP (x, 1);
971*58e805e6Szrj 		enum machine_mode op1_mode = GET_MODE (op1);
972*58e805e6Szrj 		if (GET_MODE_PRECISION (as_a <scalar_int_mode> (mode))
973*58e805e6Szrj 		    < GET_MODE_PRECISION (as_a <scalar_int_mode> (op1_mode)))
974*58e805e6Szrj 		  {
975*58e805e6Szrj 		    poly_uint64 byte = subreg_lowpart_offset (mode, op1_mode);
976*58e805e6Szrj 		    if (GET_CODE (op1) == SUBREG || GET_CODE (op1) == CONCAT)
977*58e805e6Szrj 		      {
978*58e805e6Szrj 			if (!simplify_subreg (mode, op1, op1_mode, byte))
979*58e805e6Szrj 			  return false;
980*58e805e6Szrj 		      }
981*58e805e6Szrj 		    else if (!validate_subreg (mode, op1_mode, op1, byte))
982*58e805e6Szrj 		      return false;
983*58e805e6Szrj 		  }
984*58e805e6Szrj 	      }
98538fd1498Szrj 	    iter.substitute (XEXP (x, 0));
98638fd1498Szrj 	    break;
98738fd1498Szrj 	  default:
98838fd1498Szrj 	    return false;
98938fd1498Szrj 	  }
99038fd1498Szrj     }
99138fd1498Szrj   return true;
99238fd1498Szrj }
99338fd1498Szrj 
99438fd1498Szrj /* Transform X into narrower mode MODE from wider mode WMODE.  */
99538fd1498Szrj 
99638fd1498Szrj static rtx
use_narrower_mode(rtx x,scalar_int_mode mode,scalar_int_mode wmode)99738fd1498Szrj use_narrower_mode (rtx x, scalar_int_mode mode, scalar_int_mode wmode)
99838fd1498Szrj {
99938fd1498Szrj   rtx op0, op1;
100038fd1498Szrj   if (CONSTANT_P (x))
100138fd1498Szrj     return lowpart_subreg (mode, x, wmode);
100238fd1498Szrj   switch (GET_CODE (x))
100338fd1498Szrj     {
100438fd1498Szrj     case REG:
100538fd1498Szrj       return lowpart_subreg (mode, x, wmode);
100638fd1498Szrj     case PLUS:
100738fd1498Szrj     case MINUS:
100838fd1498Szrj     case MULT:
100938fd1498Szrj       op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
101038fd1498Szrj       op1 = use_narrower_mode (XEXP (x, 1), mode, wmode);
101138fd1498Szrj       return simplify_gen_binary (GET_CODE (x), mode, op0, op1);
101238fd1498Szrj     case ASHIFT:
101338fd1498Szrj       op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
101438fd1498Szrj       op1 = XEXP (x, 1);
101538fd1498Szrj       /* Ensure shift amount is not wider than mode.  */
101638fd1498Szrj       if (GET_MODE (op1) == VOIDmode)
101738fd1498Szrj 	op1 = lowpart_subreg (mode, op1, wmode);
101838fd1498Szrj       else if (GET_MODE_PRECISION (mode)
101938fd1498Szrj 	       < GET_MODE_PRECISION (as_a <scalar_int_mode> (GET_MODE (op1))))
102038fd1498Szrj 	op1 = lowpart_subreg (mode, op1, GET_MODE (op1));
102138fd1498Szrj       return simplify_gen_binary (ASHIFT, mode, op0, op1);
102238fd1498Szrj     default:
102338fd1498Szrj       gcc_unreachable ();
102438fd1498Szrj     }
102538fd1498Szrj }
102638fd1498Szrj 
102738fd1498Szrj /* Helper function for adjusting used MEMs.  */
102838fd1498Szrj 
102938fd1498Szrj static rtx
adjust_mems(rtx loc,const_rtx old_rtx,void * data)103038fd1498Szrj adjust_mems (rtx loc, const_rtx old_rtx, void *data)
103138fd1498Szrj {
103238fd1498Szrj   struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
103338fd1498Szrj   rtx mem, addr = loc, tem;
103438fd1498Szrj   machine_mode mem_mode_save;
103538fd1498Szrj   bool store_save;
103638fd1498Szrj   scalar_int_mode tem_mode, tem_subreg_mode;
103738fd1498Szrj   poly_int64 size;
103838fd1498Szrj   switch (GET_CODE (loc))
103938fd1498Szrj     {
104038fd1498Szrj     case REG:
104138fd1498Szrj       /* Don't do any sp or fp replacements outside of MEM addresses
104238fd1498Szrj          on the LHS.  */
104338fd1498Szrj       if (amd->mem_mode == VOIDmode && amd->store)
104438fd1498Szrj 	return loc;
104538fd1498Szrj       if (loc == stack_pointer_rtx
104638fd1498Szrj 	  && !frame_pointer_needed
104738fd1498Szrj 	  && cfa_base_rtx)
104838fd1498Szrj 	return compute_cfa_pointer (amd->stack_adjust);
104938fd1498Szrj       else if (loc == hard_frame_pointer_rtx
105038fd1498Szrj 	       && frame_pointer_needed
105138fd1498Szrj 	       && hard_frame_pointer_adjustment != -1
105238fd1498Szrj 	       && cfa_base_rtx)
105338fd1498Szrj 	return compute_cfa_pointer (hard_frame_pointer_adjustment);
105438fd1498Szrj       gcc_checking_assert (loc != virtual_incoming_args_rtx);
105538fd1498Szrj       return loc;
105638fd1498Szrj     case MEM:
105738fd1498Szrj       mem = loc;
105838fd1498Szrj       if (!amd->store)
105938fd1498Szrj 	{
106038fd1498Szrj 	  mem = targetm.delegitimize_address (mem);
106138fd1498Szrj 	  if (mem != loc && !MEM_P (mem))
106238fd1498Szrj 	    return simplify_replace_fn_rtx (mem, old_rtx, adjust_mems, data);
106338fd1498Szrj 	}
106438fd1498Szrj 
106538fd1498Szrj       addr = XEXP (mem, 0);
106638fd1498Szrj       mem_mode_save = amd->mem_mode;
106738fd1498Szrj       amd->mem_mode = GET_MODE (mem);
106838fd1498Szrj       store_save = amd->store;
106938fd1498Szrj       amd->store = false;
107038fd1498Szrj       addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
107138fd1498Szrj       amd->store = store_save;
107238fd1498Szrj       amd->mem_mode = mem_mode_save;
107338fd1498Szrj       if (mem == loc)
107438fd1498Szrj 	addr = targetm.delegitimize_address (addr);
107538fd1498Szrj       if (addr != XEXP (mem, 0))
107638fd1498Szrj 	mem = replace_equiv_address_nv (mem, addr);
107738fd1498Szrj       if (!amd->store)
107838fd1498Szrj 	mem = avoid_constant_pool_reference (mem);
107938fd1498Szrj       return mem;
108038fd1498Szrj     case PRE_INC:
108138fd1498Szrj     case PRE_DEC:
108238fd1498Szrj       size = GET_MODE_SIZE (amd->mem_mode);
108338fd1498Szrj       addr = plus_constant (GET_MODE (loc), XEXP (loc, 0),
108438fd1498Szrj 			    GET_CODE (loc) == PRE_INC ? size : -size);
108538fd1498Szrj       /* FALLTHRU */
108638fd1498Szrj     case POST_INC:
108738fd1498Szrj     case POST_DEC:
108838fd1498Szrj       if (addr == loc)
108938fd1498Szrj 	addr = XEXP (loc, 0);
109038fd1498Szrj       gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode);
109138fd1498Szrj       addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
109238fd1498Szrj       size = GET_MODE_SIZE (amd->mem_mode);
109338fd1498Szrj       tem = plus_constant (GET_MODE (loc), XEXP (loc, 0),
109438fd1498Szrj 			   (GET_CODE (loc) == PRE_INC
109538fd1498Szrj 			    || GET_CODE (loc) == POST_INC) ? size : -size);
109638fd1498Szrj       store_save = amd->store;
109738fd1498Szrj       amd->store = false;
109838fd1498Szrj       tem = simplify_replace_fn_rtx (tem, old_rtx, adjust_mems, data);
109938fd1498Szrj       amd->store = store_save;
110038fd1498Szrj       amd->side_effects.safe_push (gen_rtx_SET (XEXP (loc, 0), tem));
110138fd1498Szrj       return addr;
110238fd1498Szrj     case PRE_MODIFY:
110338fd1498Szrj       addr = XEXP (loc, 1);
110438fd1498Szrj       /* FALLTHRU */
110538fd1498Szrj     case POST_MODIFY:
110638fd1498Szrj       if (addr == loc)
110738fd1498Szrj 	addr = XEXP (loc, 0);
110838fd1498Szrj       gcc_assert (amd->mem_mode != VOIDmode);
110938fd1498Szrj       addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
111038fd1498Szrj       store_save = amd->store;
111138fd1498Szrj       amd->store = false;
111238fd1498Szrj       tem = simplify_replace_fn_rtx (XEXP (loc, 1), old_rtx,
111338fd1498Szrj 				     adjust_mems, data);
111438fd1498Szrj       amd->store = store_save;
111538fd1498Szrj       amd->side_effects.safe_push (gen_rtx_SET (XEXP (loc, 0), tem));
111638fd1498Szrj       return addr;
111738fd1498Szrj     case SUBREG:
111838fd1498Szrj       /* First try without delegitimization of whole MEMs and
111938fd1498Szrj 	 avoid_constant_pool_reference, which is more likely to succeed.  */
112038fd1498Szrj       store_save = amd->store;
112138fd1498Szrj       amd->store = true;
112238fd1498Szrj       addr = simplify_replace_fn_rtx (SUBREG_REG (loc), old_rtx, adjust_mems,
112338fd1498Szrj 				      data);
112438fd1498Szrj       amd->store = store_save;
112538fd1498Szrj       mem = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
112638fd1498Szrj       if (mem == SUBREG_REG (loc))
112738fd1498Szrj 	{
112838fd1498Szrj 	  tem = loc;
112938fd1498Szrj 	  goto finish_subreg;
113038fd1498Szrj 	}
113138fd1498Szrj       tem = simplify_gen_subreg (GET_MODE (loc), mem,
113238fd1498Szrj 				 GET_MODE (SUBREG_REG (loc)),
113338fd1498Szrj 				 SUBREG_BYTE (loc));
113438fd1498Szrj       if (tem)
113538fd1498Szrj 	goto finish_subreg;
113638fd1498Szrj       tem = simplify_gen_subreg (GET_MODE (loc), addr,
113738fd1498Szrj 				 GET_MODE (SUBREG_REG (loc)),
113838fd1498Szrj 				 SUBREG_BYTE (loc));
113938fd1498Szrj       if (tem == NULL_RTX)
114038fd1498Szrj 	tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
114138fd1498Szrj     finish_subreg:
114238fd1498Szrj       if (MAY_HAVE_DEBUG_BIND_INSNS
114338fd1498Szrj 	  && GET_CODE (tem) == SUBREG
114438fd1498Szrj 	  && (GET_CODE (SUBREG_REG (tem)) == PLUS
114538fd1498Szrj 	      || GET_CODE (SUBREG_REG (tem)) == MINUS
114638fd1498Szrj 	      || GET_CODE (SUBREG_REG (tem)) == MULT
114738fd1498Szrj 	      || GET_CODE (SUBREG_REG (tem)) == ASHIFT)
114838fd1498Szrj 	  && is_a <scalar_int_mode> (GET_MODE (tem), &tem_mode)
114938fd1498Szrj 	  && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (tem)),
115038fd1498Szrj 				     &tem_subreg_mode)
115138fd1498Szrj 	  && (GET_MODE_PRECISION (tem_mode)
115238fd1498Szrj 	      < GET_MODE_PRECISION (tem_subreg_mode))
115338fd1498Szrj 	  && subreg_lowpart_p (tem)
115438fd1498Szrj 	  && use_narrower_mode_test (SUBREG_REG (tem), tem))
115538fd1498Szrj 	return use_narrower_mode (SUBREG_REG (tem), tem_mode, tem_subreg_mode);
115638fd1498Szrj       return tem;
115738fd1498Szrj     case ASM_OPERANDS:
115838fd1498Szrj       /* Don't do any replacements in second and following
115938fd1498Szrj 	 ASM_OPERANDS of inline-asm with multiple sets.
116038fd1498Szrj 	 ASM_OPERANDS_INPUT_VEC, ASM_OPERANDS_INPUT_CONSTRAINT_VEC
116138fd1498Szrj 	 and ASM_OPERANDS_LABEL_VEC need to be equal between
116238fd1498Szrj 	 all the ASM_OPERANDs in the insn and adjust_insn will
116338fd1498Szrj 	 fix this up.  */
116438fd1498Szrj       if (ASM_OPERANDS_OUTPUT_IDX (loc) != 0)
116538fd1498Szrj 	return loc;
116638fd1498Szrj       break;
116738fd1498Szrj     default:
116838fd1498Szrj       break;
116938fd1498Szrj     }
117038fd1498Szrj   return NULL_RTX;
117138fd1498Szrj }
117238fd1498Szrj 
117338fd1498Szrj /* Helper function for replacement of uses.  */
117438fd1498Szrj 
117538fd1498Szrj static void
adjust_mem_uses(rtx * x,void * data)117638fd1498Szrj adjust_mem_uses (rtx *x, void *data)
117738fd1498Szrj {
117838fd1498Szrj   rtx new_x = simplify_replace_fn_rtx (*x, NULL_RTX, adjust_mems, data);
117938fd1498Szrj   if (new_x != *x)
118038fd1498Szrj     validate_change (NULL_RTX, x, new_x, true);
118138fd1498Szrj }
118238fd1498Szrj 
118338fd1498Szrj /* Helper function for replacement of stores.  */
118438fd1498Szrj 
118538fd1498Szrj static void
adjust_mem_stores(rtx loc,const_rtx expr,void * data)118638fd1498Szrj adjust_mem_stores (rtx loc, const_rtx expr, void *data)
118738fd1498Szrj {
118838fd1498Szrj   if (MEM_P (loc))
118938fd1498Szrj     {
119038fd1498Szrj       rtx new_dest = simplify_replace_fn_rtx (SET_DEST (expr), NULL_RTX,
119138fd1498Szrj 					      adjust_mems, data);
119238fd1498Szrj       if (new_dest != SET_DEST (expr))
119338fd1498Szrj 	{
119438fd1498Szrj 	  rtx xexpr = CONST_CAST_RTX (expr);
119538fd1498Szrj 	  validate_change (NULL_RTX, &SET_DEST (xexpr), new_dest, true);
119638fd1498Szrj 	}
119738fd1498Szrj     }
119838fd1498Szrj }
119938fd1498Szrj 
120038fd1498Szrj /* Simplify INSN.  Remove all {PRE,POST}_{INC,DEC,MODIFY} rtxes,
120138fd1498Szrj    replace them with their value in the insn and add the side-effects
120238fd1498Szrj    as other sets to the insn.  */
120338fd1498Szrj 
120438fd1498Szrj static void
adjust_insn(basic_block bb,rtx_insn * insn)120538fd1498Szrj adjust_insn (basic_block bb, rtx_insn *insn)
120638fd1498Szrj {
120738fd1498Szrj   rtx set;
120838fd1498Szrj 
120938fd1498Szrj #ifdef HAVE_window_save
121038fd1498Szrj   /* If the target machine has an explicit window save instruction, the
121138fd1498Szrj      transformation OUTGOING_REGNO -> INCOMING_REGNO is done there.  */
121238fd1498Szrj   if (RTX_FRAME_RELATED_P (insn)
121338fd1498Szrj       && find_reg_note (insn, REG_CFA_WINDOW_SAVE, NULL_RTX))
121438fd1498Szrj     {
121538fd1498Szrj       unsigned int i, nregs = vec_safe_length (windowed_parm_regs);
121638fd1498Szrj       rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2));
121738fd1498Szrj       parm_reg *p;
121838fd1498Szrj 
121938fd1498Szrj       FOR_EACH_VEC_SAFE_ELT (windowed_parm_regs, i, p)
122038fd1498Szrj 	{
122138fd1498Szrj 	  XVECEXP (rtl, 0, i * 2)
122238fd1498Szrj 	    = gen_rtx_SET (p->incoming, p->outgoing);
122338fd1498Szrj 	  /* Do not clobber the attached DECL, but only the REG.  */
122438fd1498Szrj 	  XVECEXP (rtl, 0, i * 2 + 1)
122538fd1498Szrj 	    = gen_rtx_CLOBBER (GET_MODE (p->outgoing),
122638fd1498Szrj 			       gen_raw_REG (GET_MODE (p->outgoing),
122738fd1498Szrj 					    REGNO (p->outgoing)));
122838fd1498Szrj 	}
122938fd1498Szrj 
123038fd1498Szrj       validate_change (NULL_RTX, &PATTERN (insn), rtl, true);
123138fd1498Szrj       return;
123238fd1498Szrj     }
123338fd1498Szrj #endif
123438fd1498Szrj 
123538fd1498Szrj   adjust_mem_data amd;
123638fd1498Szrj   amd.mem_mode = VOIDmode;
123738fd1498Szrj   amd.stack_adjust = -VTI (bb)->out.stack_adjust;
123838fd1498Szrj 
123938fd1498Szrj   amd.store = true;
124038fd1498Szrj   note_stores (PATTERN (insn), adjust_mem_stores, &amd);
124138fd1498Szrj 
124238fd1498Szrj   amd.store = false;
124338fd1498Szrj   if (GET_CODE (PATTERN (insn)) == PARALLEL
124438fd1498Szrj       && asm_noperands (PATTERN (insn)) > 0
124538fd1498Szrj       && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
124638fd1498Szrj     {
124738fd1498Szrj       rtx body, set0;
124838fd1498Szrj       int i;
124938fd1498Szrj 
125038fd1498Szrj       /* inline-asm with multiple sets is tiny bit more complicated,
125138fd1498Szrj 	 because the 3 vectors in ASM_OPERANDS need to be shared between
125238fd1498Szrj 	 all ASM_OPERANDS in the instruction.  adjust_mems will
125338fd1498Szrj 	 not touch ASM_OPERANDS other than the first one, asm_noperands
125438fd1498Szrj 	 test above needs to be called before that (otherwise it would fail)
125538fd1498Szrj 	 and afterwards this code fixes it up.  */
125638fd1498Szrj       note_uses (&PATTERN (insn), adjust_mem_uses, &amd);
125738fd1498Szrj       body = PATTERN (insn);
125838fd1498Szrj       set0 = XVECEXP (body, 0, 0);
125938fd1498Szrj       gcc_checking_assert (GET_CODE (set0) == SET
126038fd1498Szrj 			   && GET_CODE (SET_SRC (set0)) == ASM_OPERANDS
126138fd1498Szrj 			   && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set0)) == 0);
126238fd1498Szrj       for (i = 1; i < XVECLEN (body, 0); i++)
126338fd1498Szrj 	if (GET_CODE (XVECEXP (body, 0, i)) != SET)
126438fd1498Szrj 	  break;
126538fd1498Szrj 	else
126638fd1498Szrj 	  {
126738fd1498Szrj 	    set = XVECEXP (body, 0, i);
126838fd1498Szrj 	    gcc_checking_assert (GET_CODE (SET_SRC (set)) == ASM_OPERANDS
126938fd1498Szrj 				 && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set))
127038fd1498Szrj 				    == i);
127138fd1498Szrj 	    if (ASM_OPERANDS_INPUT_VEC (SET_SRC (set))
127238fd1498Szrj 		!= ASM_OPERANDS_INPUT_VEC (SET_SRC (set0))
127338fd1498Szrj 		|| ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set))
127438fd1498Szrj 		   != ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0))
127538fd1498Szrj 		|| ASM_OPERANDS_LABEL_VEC (SET_SRC (set))
127638fd1498Szrj 		   != ASM_OPERANDS_LABEL_VEC (SET_SRC (set0)))
127738fd1498Szrj 	      {
127838fd1498Szrj 		rtx newsrc = shallow_copy_rtx (SET_SRC (set));
127938fd1498Szrj 		ASM_OPERANDS_INPUT_VEC (newsrc)
128038fd1498Szrj 		  = ASM_OPERANDS_INPUT_VEC (SET_SRC (set0));
128138fd1498Szrj 		ASM_OPERANDS_INPUT_CONSTRAINT_VEC (newsrc)
128238fd1498Szrj 		  = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0));
128338fd1498Szrj 		ASM_OPERANDS_LABEL_VEC (newsrc)
128438fd1498Szrj 		  = ASM_OPERANDS_LABEL_VEC (SET_SRC (set0));
128538fd1498Szrj 		validate_change (NULL_RTX, &SET_SRC (set), newsrc, true);
128638fd1498Szrj 	      }
128738fd1498Szrj 	  }
128838fd1498Szrj     }
128938fd1498Szrj   else
129038fd1498Szrj     note_uses (&PATTERN (insn), adjust_mem_uses, &amd);
129138fd1498Szrj 
129238fd1498Szrj   /* For read-only MEMs containing some constant, prefer those
129338fd1498Szrj      constants.  */
129438fd1498Szrj   set = single_set (insn);
129538fd1498Szrj   if (set && MEM_P (SET_SRC (set)) && MEM_READONLY_P (SET_SRC (set)))
129638fd1498Szrj     {
129738fd1498Szrj       rtx note = find_reg_equal_equiv_note (insn);
129838fd1498Szrj 
129938fd1498Szrj       if (note && CONSTANT_P (XEXP (note, 0)))
130038fd1498Szrj 	validate_change (NULL_RTX, &SET_SRC (set), XEXP (note, 0), true);
130138fd1498Szrj     }
130238fd1498Szrj 
130338fd1498Szrj   if (!amd.side_effects.is_empty ())
130438fd1498Szrj     {
130538fd1498Szrj       rtx *pat, new_pat;
130638fd1498Szrj       int i, oldn;
130738fd1498Szrj 
130838fd1498Szrj       pat = &PATTERN (insn);
130938fd1498Szrj       if (GET_CODE (*pat) == COND_EXEC)
131038fd1498Szrj 	pat = &COND_EXEC_CODE (*pat);
131138fd1498Szrj       if (GET_CODE (*pat) == PARALLEL)
131238fd1498Szrj 	oldn = XVECLEN (*pat, 0);
131338fd1498Szrj       else
131438fd1498Szrj 	oldn = 1;
131538fd1498Szrj       unsigned int newn = amd.side_effects.length ();
131638fd1498Szrj       new_pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (oldn + newn));
131738fd1498Szrj       if (GET_CODE (*pat) == PARALLEL)
131838fd1498Szrj 	for (i = 0; i < oldn; i++)
131938fd1498Szrj 	  XVECEXP (new_pat, 0, i) = XVECEXP (*pat, 0, i);
132038fd1498Szrj       else
132138fd1498Szrj 	XVECEXP (new_pat, 0, 0) = *pat;
132238fd1498Szrj 
132338fd1498Szrj       rtx effect;
132438fd1498Szrj       unsigned int j;
132538fd1498Szrj       FOR_EACH_VEC_ELT_REVERSE (amd.side_effects, j, effect)
132638fd1498Szrj 	XVECEXP (new_pat, 0, j + oldn) = effect;
132738fd1498Szrj       validate_change (NULL_RTX, pat, new_pat, true);
132838fd1498Szrj     }
132938fd1498Szrj }
133038fd1498Szrj 
133138fd1498Szrj /* Return the DEBUG_EXPR of a DEBUG_EXPR_DECL or the VALUE in DV.  */
133238fd1498Szrj static inline rtx
dv_as_rtx(decl_or_value dv)133338fd1498Szrj dv_as_rtx (decl_or_value dv)
133438fd1498Szrj {
133538fd1498Szrj   tree decl;
133638fd1498Szrj 
133738fd1498Szrj   if (dv_is_value_p (dv))
133838fd1498Szrj     return dv_as_value (dv);
133938fd1498Szrj 
134038fd1498Szrj   decl = dv_as_decl (dv);
134138fd1498Szrj 
134238fd1498Szrj   gcc_checking_assert (TREE_CODE (decl) == DEBUG_EXPR_DECL);
134338fd1498Szrj   return DECL_RTL_KNOWN_SET (decl);
134438fd1498Szrj }
134538fd1498Szrj 
134638fd1498Szrj /* Return nonzero if a decl_or_value must not have more than one
134738fd1498Szrj    variable part.  The returned value discriminates among various
134838fd1498Szrj    kinds of one-part DVs ccording to enum onepart_enum.  */
134938fd1498Szrj static inline onepart_enum
dv_onepart_p(decl_or_value dv)135038fd1498Szrj dv_onepart_p (decl_or_value dv)
135138fd1498Szrj {
135238fd1498Szrj   tree decl;
135338fd1498Szrj 
135438fd1498Szrj   if (!MAY_HAVE_DEBUG_BIND_INSNS)
135538fd1498Szrj     return NOT_ONEPART;
135638fd1498Szrj 
135738fd1498Szrj   if (dv_is_value_p (dv))
135838fd1498Szrj     return ONEPART_VALUE;
135938fd1498Szrj 
136038fd1498Szrj   decl = dv_as_decl (dv);
136138fd1498Szrj 
136238fd1498Szrj   if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
136338fd1498Szrj     return ONEPART_DEXPR;
136438fd1498Szrj 
136538fd1498Szrj   if (target_for_debug_bind (decl) != NULL_TREE)
136638fd1498Szrj     return ONEPART_VDECL;
136738fd1498Szrj 
136838fd1498Szrj   return NOT_ONEPART;
136938fd1498Szrj }
137038fd1498Szrj 
137138fd1498Szrj /* Return the variable pool to be used for a dv of type ONEPART.  */
137238fd1498Szrj static inline pool_allocator &
onepart_pool(onepart_enum onepart)137338fd1498Szrj onepart_pool (onepart_enum onepart)
137438fd1498Szrj {
137538fd1498Szrj   return onepart ? valvar_pool : var_pool;
137638fd1498Szrj }
137738fd1498Szrj 
137838fd1498Szrj /* Allocate a variable_def from the corresponding variable pool.  */
137938fd1498Szrj static inline variable *
onepart_pool_allocate(onepart_enum onepart)138038fd1498Szrj onepart_pool_allocate (onepart_enum onepart)
138138fd1498Szrj {
138238fd1498Szrj   return (variable*) onepart_pool (onepart).allocate ();
138338fd1498Szrj }
138438fd1498Szrj 
138538fd1498Szrj /* Build a decl_or_value out of a decl.  */
138638fd1498Szrj static inline decl_or_value
dv_from_decl(tree decl)138738fd1498Szrj dv_from_decl (tree decl)
138838fd1498Szrj {
138938fd1498Szrj   decl_or_value dv;
139038fd1498Szrj   dv = decl;
139138fd1498Szrj   gcc_checking_assert (dv_is_decl_p (dv));
139238fd1498Szrj   return dv;
139338fd1498Szrj }
139438fd1498Szrj 
139538fd1498Szrj /* Build a decl_or_value out of a value.  */
139638fd1498Szrj static inline decl_or_value
dv_from_value(rtx value)139738fd1498Szrj dv_from_value (rtx value)
139838fd1498Szrj {
139938fd1498Szrj   decl_or_value dv;
140038fd1498Szrj   dv = value;
140138fd1498Szrj   gcc_checking_assert (dv_is_value_p (dv));
140238fd1498Szrj   return dv;
140338fd1498Szrj }
140438fd1498Szrj 
140538fd1498Szrj /* Return a value or the decl of a debug_expr as a decl_or_value.  */
140638fd1498Szrj static inline decl_or_value
dv_from_rtx(rtx x)140738fd1498Szrj dv_from_rtx (rtx x)
140838fd1498Szrj {
140938fd1498Szrj   decl_or_value dv;
141038fd1498Szrj 
141138fd1498Szrj   switch (GET_CODE (x))
141238fd1498Szrj     {
141338fd1498Szrj     case DEBUG_EXPR:
141438fd1498Szrj       dv = dv_from_decl (DEBUG_EXPR_TREE_DECL (x));
141538fd1498Szrj       gcc_checking_assert (DECL_RTL_KNOWN_SET (DEBUG_EXPR_TREE_DECL (x)) == x);
141638fd1498Szrj       break;
141738fd1498Szrj 
141838fd1498Szrj     case VALUE:
141938fd1498Szrj       dv = dv_from_value (x);
142038fd1498Szrj       break;
142138fd1498Szrj 
142238fd1498Szrj     default:
142338fd1498Szrj       gcc_unreachable ();
142438fd1498Szrj     }
142538fd1498Szrj 
142638fd1498Szrj   return dv;
142738fd1498Szrj }
142838fd1498Szrj 
142938fd1498Szrj extern void debug_dv (decl_or_value dv);
143038fd1498Szrj 
143138fd1498Szrj DEBUG_FUNCTION void
debug_dv(decl_or_value dv)143238fd1498Szrj debug_dv (decl_or_value dv)
143338fd1498Szrj {
143438fd1498Szrj   if (dv_is_value_p (dv))
143538fd1498Szrj     debug_rtx (dv_as_value (dv));
143638fd1498Szrj   else
143738fd1498Szrj     debug_generic_stmt (dv_as_decl (dv));
143838fd1498Szrj }
143938fd1498Szrj 
144038fd1498Szrj static void loc_exp_dep_clear (variable *var);
144138fd1498Szrj 
144238fd1498Szrj /* Free the element of VARIABLE_HTAB (its type is struct variable_def).  */
144338fd1498Szrj 
144438fd1498Szrj static void
variable_htab_free(void * elem)144538fd1498Szrj variable_htab_free (void *elem)
144638fd1498Szrj {
144738fd1498Szrj   int i;
144838fd1498Szrj   variable *var = (variable *) elem;
144938fd1498Szrj   location_chain *node, *next;
145038fd1498Szrj 
145138fd1498Szrj   gcc_checking_assert (var->refcount > 0);
145238fd1498Szrj 
145338fd1498Szrj   var->refcount--;
145438fd1498Szrj   if (var->refcount > 0)
145538fd1498Szrj     return;
145638fd1498Szrj 
145738fd1498Szrj   for (i = 0; i < var->n_var_parts; i++)
145838fd1498Szrj     {
145938fd1498Szrj       for (node = var->var_part[i].loc_chain; node; node = next)
146038fd1498Szrj 	{
146138fd1498Szrj 	  next = node->next;
146238fd1498Szrj 	  delete node;
146338fd1498Szrj 	}
146438fd1498Szrj       var->var_part[i].loc_chain = NULL;
146538fd1498Szrj     }
146638fd1498Szrj   if (var->onepart && VAR_LOC_1PAUX (var))
146738fd1498Szrj     {
146838fd1498Szrj       loc_exp_dep_clear (var);
146938fd1498Szrj       if (VAR_LOC_DEP_LST (var))
147038fd1498Szrj 	VAR_LOC_DEP_LST (var)->pprev = NULL;
147138fd1498Szrj       XDELETE (VAR_LOC_1PAUX (var));
147238fd1498Szrj       /* These may be reused across functions, so reset
147338fd1498Szrj 	 e.g. NO_LOC_P.  */
147438fd1498Szrj       if (var->onepart == ONEPART_DEXPR)
147538fd1498Szrj 	set_dv_changed (var->dv, true);
147638fd1498Szrj     }
147738fd1498Szrj   onepart_pool (var->onepart).remove (var);
147838fd1498Szrj }
147938fd1498Szrj 
148038fd1498Szrj /* Initialize the set (array) SET of attrs to empty lists.  */
148138fd1498Szrj 
148238fd1498Szrj static void
init_attrs_list_set(attrs ** set)148338fd1498Szrj init_attrs_list_set (attrs **set)
148438fd1498Szrj {
148538fd1498Szrj   int i;
148638fd1498Szrj 
148738fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
148838fd1498Szrj     set[i] = NULL;
148938fd1498Szrj }
149038fd1498Szrj 
149138fd1498Szrj /* Make the list *LISTP empty.  */
149238fd1498Szrj 
149338fd1498Szrj static void
attrs_list_clear(attrs ** listp)149438fd1498Szrj attrs_list_clear (attrs **listp)
149538fd1498Szrj {
149638fd1498Szrj   attrs *list, *next;
149738fd1498Szrj 
149838fd1498Szrj   for (list = *listp; list; list = next)
149938fd1498Szrj     {
150038fd1498Szrj       next = list->next;
150138fd1498Szrj       delete list;
150238fd1498Szrj     }
150338fd1498Szrj   *listp = NULL;
150438fd1498Szrj }
150538fd1498Szrj 
150638fd1498Szrj /* Return true if the pair of DECL and OFFSET is the member of the LIST.  */
150738fd1498Szrj 
150838fd1498Szrj static attrs *
attrs_list_member(attrs * list,decl_or_value dv,HOST_WIDE_INT offset)150938fd1498Szrj attrs_list_member (attrs *list, decl_or_value dv, HOST_WIDE_INT offset)
151038fd1498Szrj {
151138fd1498Szrj   for (; list; list = list->next)
151238fd1498Szrj     if (dv_as_opaque (list->dv) == dv_as_opaque (dv) && list->offset == offset)
151338fd1498Szrj       return list;
151438fd1498Szrj   return NULL;
151538fd1498Szrj }
151638fd1498Szrj 
151738fd1498Szrj /* Insert the triplet DECL, OFFSET, LOC to the list *LISTP.  */
151838fd1498Szrj 
151938fd1498Szrj static void
attrs_list_insert(attrs ** listp,decl_or_value dv,HOST_WIDE_INT offset,rtx loc)152038fd1498Szrj attrs_list_insert (attrs **listp, decl_or_value dv,
152138fd1498Szrj 		   HOST_WIDE_INT offset, rtx loc)
152238fd1498Szrj {
152338fd1498Szrj   attrs *list = new attrs;
152438fd1498Szrj   list->loc = loc;
152538fd1498Szrj   list->dv = dv;
152638fd1498Szrj   list->offset = offset;
152738fd1498Szrj   list->next = *listp;
152838fd1498Szrj   *listp = list;
152938fd1498Szrj }
153038fd1498Szrj 
153138fd1498Szrj /* Copy all nodes from SRC and create a list *DSTP of the copies.  */
153238fd1498Szrj 
153338fd1498Szrj static void
attrs_list_copy(attrs ** dstp,attrs * src)153438fd1498Szrj attrs_list_copy (attrs **dstp, attrs *src)
153538fd1498Szrj {
153638fd1498Szrj   attrs_list_clear (dstp);
153738fd1498Szrj   for (; src; src = src->next)
153838fd1498Szrj     {
153938fd1498Szrj       attrs *n = new attrs;
154038fd1498Szrj       n->loc = src->loc;
154138fd1498Szrj       n->dv = src->dv;
154238fd1498Szrj       n->offset = src->offset;
154338fd1498Szrj       n->next = *dstp;
154438fd1498Szrj       *dstp = n;
154538fd1498Szrj     }
154638fd1498Szrj }
154738fd1498Szrj 
154838fd1498Szrj /* Add all nodes from SRC which are not in *DSTP to *DSTP.  */
154938fd1498Szrj 
155038fd1498Szrj static void
attrs_list_union(attrs ** dstp,attrs * src)155138fd1498Szrj attrs_list_union (attrs **dstp, attrs *src)
155238fd1498Szrj {
155338fd1498Szrj   for (; src; src = src->next)
155438fd1498Szrj     {
155538fd1498Szrj       if (!attrs_list_member (*dstp, src->dv, src->offset))
155638fd1498Szrj 	attrs_list_insert (dstp, src->dv, src->offset, src->loc);
155738fd1498Szrj     }
155838fd1498Szrj }
155938fd1498Szrj 
156038fd1498Szrj /* Combine nodes that are not onepart nodes from SRC and SRC2 into
156138fd1498Szrj    *DSTP.  */
156238fd1498Szrj 
156338fd1498Szrj static void
attrs_list_mpdv_union(attrs ** dstp,attrs * src,attrs * src2)156438fd1498Szrj attrs_list_mpdv_union (attrs **dstp, attrs *src, attrs *src2)
156538fd1498Szrj {
156638fd1498Szrj   gcc_assert (!*dstp);
156738fd1498Szrj   for (; src; src = src->next)
156838fd1498Szrj     {
156938fd1498Szrj       if (!dv_onepart_p (src->dv))
157038fd1498Szrj 	attrs_list_insert (dstp, src->dv, src->offset, src->loc);
157138fd1498Szrj     }
157238fd1498Szrj   for (src = src2; src; src = src->next)
157338fd1498Szrj     {
157438fd1498Szrj       if (!dv_onepart_p (src->dv)
157538fd1498Szrj 	  && !attrs_list_member (*dstp, src->dv, src->offset))
157638fd1498Szrj 	attrs_list_insert (dstp, src->dv, src->offset, src->loc);
157738fd1498Szrj     }
157838fd1498Szrj }
157938fd1498Szrj 
158038fd1498Szrj /* Shared hashtable support.  */
158138fd1498Szrj 
158238fd1498Szrj /* Return true if VARS is shared.  */
158338fd1498Szrj 
158438fd1498Szrj static inline bool
shared_hash_shared(shared_hash * vars)158538fd1498Szrj shared_hash_shared (shared_hash *vars)
158638fd1498Szrj {
158738fd1498Szrj   return vars->refcount > 1;
158838fd1498Szrj }
158938fd1498Szrj 
159038fd1498Szrj /* Return the hash table for VARS.  */
159138fd1498Szrj 
159238fd1498Szrj static inline variable_table_type *
shared_hash_htab(shared_hash * vars)159338fd1498Szrj shared_hash_htab (shared_hash *vars)
159438fd1498Szrj {
159538fd1498Szrj   return vars->htab;
159638fd1498Szrj }
159738fd1498Szrj 
159838fd1498Szrj /* Return true if VAR is shared, or maybe because VARS is shared.  */
159938fd1498Szrj 
160038fd1498Szrj static inline bool
shared_var_p(variable * var,shared_hash * vars)160138fd1498Szrj shared_var_p (variable *var, shared_hash *vars)
160238fd1498Szrj {
160338fd1498Szrj   /* Don't count an entry in the changed_variables table as a duplicate.  */
160438fd1498Szrj   return ((var->refcount > 1 + (int) var->in_changed_variables)
160538fd1498Szrj 	  || shared_hash_shared (vars));
160638fd1498Szrj }
160738fd1498Szrj 
160838fd1498Szrj /* Copy variables into a new hash table.  */
160938fd1498Szrj 
161038fd1498Szrj static shared_hash *
shared_hash_unshare(shared_hash * vars)161138fd1498Szrj shared_hash_unshare (shared_hash *vars)
161238fd1498Szrj {
161338fd1498Szrj   shared_hash *new_vars = new shared_hash;
161438fd1498Szrj   gcc_assert (vars->refcount > 1);
161538fd1498Szrj   new_vars->refcount = 1;
161638fd1498Szrj   new_vars->htab = new variable_table_type (vars->htab->elements () + 3);
161738fd1498Szrj   vars_copy (new_vars->htab, vars->htab);
161838fd1498Szrj   vars->refcount--;
161938fd1498Szrj   return new_vars;
162038fd1498Szrj }
162138fd1498Szrj 
162238fd1498Szrj /* Increment reference counter on VARS and return it.  */
162338fd1498Szrj 
162438fd1498Szrj static inline shared_hash *
shared_hash_copy(shared_hash * vars)162538fd1498Szrj shared_hash_copy (shared_hash *vars)
162638fd1498Szrj {
162738fd1498Szrj   vars->refcount++;
162838fd1498Szrj   return vars;
162938fd1498Szrj }
163038fd1498Szrj 
163138fd1498Szrj /* Decrement reference counter and destroy hash table if not shared
163238fd1498Szrj    anymore.  */
163338fd1498Szrj 
163438fd1498Szrj static void
shared_hash_destroy(shared_hash * vars)163538fd1498Szrj shared_hash_destroy (shared_hash *vars)
163638fd1498Szrj {
163738fd1498Szrj   gcc_checking_assert (vars->refcount > 0);
163838fd1498Szrj   if (--vars->refcount == 0)
163938fd1498Szrj     {
164038fd1498Szrj       delete vars->htab;
164138fd1498Szrj       delete vars;
164238fd1498Szrj     }
164338fd1498Szrj }
164438fd1498Szrj 
164538fd1498Szrj /* Unshare *PVARS if shared and return slot for DV.  If INS is
164638fd1498Szrj    INSERT, insert it if not already present.  */
164738fd1498Szrj 
164838fd1498Szrj static inline variable **
shared_hash_find_slot_unshare_1(shared_hash ** pvars,decl_or_value dv,hashval_t dvhash,enum insert_option ins)164938fd1498Szrj shared_hash_find_slot_unshare_1 (shared_hash **pvars, decl_or_value dv,
165038fd1498Szrj 				 hashval_t dvhash, enum insert_option ins)
165138fd1498Szrj {
165238fd1498Szrj   if (shared_hash_shared (*pvars))
165338fd1498Szrj     *pvars = shared_hash_unshare (*pvars);
165438fd1498Szrj   return shared_hash_htab (*pvars)->find_slot_with_hash (dv, dvhash, ins);
165538fd1498Szrj }
165638fd1498Szrj 
165738fd1498Szrj static inline variable **
shared_hash_find_slot_unshare(shared_hash ** pvars,decl_or_value dv,enum insert_option ins)165838fd1498Szrj shared_hash_find_slot_unshare (shared_hash **pvars, decl_or_value dv,
165938fd1498Szrj 			       enum insert_option ins)
166038fd1498Szrj {
166138fd1498Szrj   return shared_hash_find_slot_unshare_1 (pvars, dv, dv_htab_hash (dv), ins);
166238fd1498Szrj }
166338fd1498Szrj 
166438fd1498Szrj /* Return slot for DV, if it is already present in the hash table.
166538fd1498Szrj    If it is not present, insert it only VARS is not shared, otherwise
166638fd1498Szrj    return NULL.  */
166738fd1498Szrj 
166838fd1498Szrj static inline variable **
shared_hash_find_slot_1(shared_hash * vars,decl_or_value dv,hashval_t dvhash)166938fd1498Szrj shared_hash_find_slot_1 (shared_hash *vars, decl_or_value dv, hashval_t dvhash)
167038fd1498Szrj {
167138fd1498Szrj   return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash,
167238fd1498Szrj 						       shared_hash_shared (vars)
167338fd1498Szrj 						       ? NO_INSERT : INSERT);
167438fd1498Szrj }
167538fd1498Szrj 
167638fd1498Szrj static inline variable **
shared_hash_find_slot(shared_hash * vars,decl_or_value dv)167738fd1498Szrj shared_hash_find_slot (shared_hash *vars, decl_or_value dv)
167838fd1498Szrj {
167938fd1498Szrj   return shared_hash_find_slot_1 (vars, dv, dv_htab_hash (dv));
168038fd1498Szrj }
168138fd1498Szrj 
168238fd1498Szrj /* Return slot for DV only if it is already present in the hash table.  */
168338fd1498Szrj 
168438fd1498Szrj static inline variable **
shared_hash_find_slot_noinsert_1(shared_hash * vars,decl_or_value dv,hashval_t dvhash)168538fd1498Szrj shared_hash_find_slot_noinsert_1 (shared_hash *vars, decl_or_value dv,
168638fd1498Szrj 				  hashval_t dvhash)
168738fd1498Szrj {
168838fd1498Szrj   return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash, NO_INSERT);
168938fd1498Szrj }
169038fd1498Szrj 
169138fd1498Szrj static inline variable **
shared_hash_find_slot_noinsert(shared_hash * vars,decl_or_value dv)169238fd1498Szrj shared_hash_find_slot_noinsert (shared_hash *vars, decl_or_value dv)
169338fd1498Szrj {
169438fd1498Szrj   return shared_hash_find_slot_noinsert_1 (vars, dv, dv_htab_hash (dv));
169538fd1498Szrj }
169638fd1498Szrj 
169738fd1498Szrj /* Return variable for DV or NULL if not already present in the hash
169838fd1498Szrj    table.  */
169938fd1498Szrj 
170038fd1498Szrj static inline variable *
shared_hash_find_1(shared_hash * vars,decl_or_value dv,hashval_t dvhash)170138fd1498Szrj shared_hash_find_1 (shared_hash *vars, decl_or_value dv, hashval_t dvhash)
170238fd1498Szrj {
170338fd1498Szrj   return shared_hash_htab (vars)->find_with_hash (dv, dvhash);
170438fd1498Szrj }
170538fd1498Szrj 
170638fd1498Szrj static inline variable *
shared_hash_find(shared_hash * vars,decl_or_value dv)170738fd1498Szrj shared_hash_find (shared_hash *vars, decl_or_value dv)
170838fd1498Szrj {
170938fd1498Szrj   return shared_hash_find_1 (vars, dv, dv_htab_hash (dv));
171038fd1498Szrj }
171138fd1498Szrj 
171238fd1498Szrj /* Return true if TVAL is better than CVAL as a canonival value.  We
171338fd1498Szrj    choose lowest-numbered VALUEs, using the RTX address as a
171438fd1498Szrj    tie-breaker.  The idea is to arrange them into a star topology,
171538fd1498Szrj    such that all of them are at most one step away from the canonical
171638fd1498Szrj    value, and the canonical value has backlinks to all of them, in
171738fd1498Szrj    addition to all the actual locations.  We don't enforce this
171838fd1498Szrj    topology throughout the entire dataflow analysis, though.
171938fd1498Szrj  */
172038fd1498Szrj 
172138fd1498Szrj static inline bool
canon_value_cmp(rtx tval,rtx cval)172238fd1498Szrj canon_value_cmp (rtx tval, rtx cval)
172338fd1498Szrj {
172438fd1498Szrj   return !cval
172538fd1498Szrj     || CSELIB_VAL_PTR (tval)->uid < CSELIB_VAL_PTR (cval)->uid;
172638fd1498Szrj }
172738fd1498Szrj 
172838fd1498Szrj static bool dst_can_be_shared;
172938fd1498Szrj 
173038fd1498Szrj /* Return a copy of a variable VAR and insert it to dataflow set SET.  */
173138fd1498Szrj 
173238fd1498Szrj static variable **
unshare_variable(dataflow_set * set,variable ** slot,variable * var,enum var_init_status initialized)173338fd1498Szrj unshare_variable (dataflow_set *set, variable **slot, variable *var,
173438fd1498Szrj 		  enum var_init_status initialized)
173538fd1498Szrj {
173638fd1498Szrj   variable *new_var;
173738fd1498Szrj   int i;
173838fd1498Szrj 
173938fd1498Szrj   new_var = onepart_pool_allocate (var->onepart);
174038fd1498Szrj   new_var->dv = var->dv;
174138fd1498Szrj   new_var->refcount = 1;
174238fd1498Szrj   var->refcount--;
174338fd1498Szrj   new_var->n_var_parts = var->n_var_parts;
174438fd1498Szrj   new_var->onepart = var->onepart;
174538fd1498Szrj   new_var->in_changed_variables = false;
174638fd1498Szrj 
174738fd1498Szrj   if (! flag_var_tracking_uninit)
174838fd1498Szrj     initialized = VAR_INIT_STATUS_INITIALIZED;
174938fd1498Szrj 
175038fd1498Szrj   for (i = 0; i < var->n_var_parts; i++)
175138fd1498Szrj     {
175238fd1498Szrj       location_chain *node;
175338fd1498Szrj       location_chain **nextp;
175438fd1498Szrj 
175538fd1498Szrj       if (i == 0 && var->onepart)
175638fd1498Szrj 	{
175738fd1498Szrj 	  /* One-part auxiliary data is only used while emitting
175838fd1498Szrj 	     notes, so propagate it to the new variable in the active
175938fd1498Szrj 	     dataflow set.  If we're not emitting notes, this will be
176038fd1498Szrj 	     a no-op.  */
176138fd1498Szrj 	  gcc_checking_assert (!VAR_LOC_1PAUX (var) || emit_notes);
176238fd1498Szrj 	  VAR_LOC_1PAUX (new_var) = VAR_LOC_1PAUX (var);
176338fd1498Szrj 	  VAR_LOC_1PAUX (var) = NULL;
176438fd1498Szrj 	}
176538fd1498Szrj       else
176638fd1498Szrj 	VAR_PART_OFFSET (new_var, i) = VAR_PART_OFFSET (var, i);
176738fd1498Szrj       nextp = &new_var->var_part[i].loc_chain;
176838fd1498Szrj       for (node = var->var_part[i].loc_chain; node; node = node->next)
176938fd1498Szrj 	{
177038fd1498Szrj 	  location_chain *new_lc;
177138fd1498Szrj 
177238fd1498Szrj 	  new_lc = new location_chain;
177338fd1498Szrj 	  new_lc->next = NULL;
177438fd1498Szrj 	  if (node->init > initialized)
177538fd1498Szrj 	    new_lc->init = node->init;
177638fd1498Szrj 	  else
177738fd1498Szrj 	    new_lc->init = initialized;
177838fd1498Szrj 	  if (node->set_src && !(MEM_P (node->set_src)))
177938fd1498Szrj 	    new_lc->set_src = node->set_src;
178038fd1498Szrj 	  else
178138fd1498Szrj 	    new_lc->set_src = NULL;
178238fd1498Szrj 	  new_lc->loc = node->loc;
178338fd1498Szrj 
178438fd1498Szrj 	  *nextp = new_lc;
178538fd1498Szrj 	  nextp = &new_lc->next;
178638fd1498Szrj 	}
178738fd1498Szrj 
178838fd1498Szrj       new_var->var_part[i].cur_loc = var->var_part[i].cur_loc;
178938fd1498Szrj     }
179038fd1498Szrj 
179138fd1498Szrj   dst_can_be_shared = false;
179238fd1498Szrj   if (shared_hash_shared (set->vars))
179338fd1498Szrj     slot = shared_hash_find_slot_unshare (&set->vars, var->dv, NO_INSERT);
179438fd1498Szrj   else if (set->traversed_vars && set->vars != set->traversed_vars)
179538fd1498Szrj     slot = shared_hash_find_slot_noinsert (set->vars, var->dv);
179638fd1498Szrj   *slot = new_var;
179738fd1498Szrj   if (var->in_changed_variables)
179838fd1498Szrj     {
179938fd1498Szrj       variable **cslot
180038fd1498Szrj 	= changed_variables->find_slot_with_hash (var->dv,
180138fd1498Szrj 						  dv_htab_hash (var->dv),
180238fd1498Szrj 						  NO_INSERT);
180338fd1498Szrj       gcc_assert (*cslot == (void *) var);
180438fd1498Szrj       var->in_changed_variables = false;
180538fd1498Szrj       variable_htab_free (var);
180638fd1498Szrj       *cslot = new_var;
180738fd1498Szrj       new_var->in_changed_variables = true;
180838fd1498Szrj     }
180938fd1498Szrj   return slot;
181038fd1498Szrj }
181138fd1498Szrj 
181238fd1498Szrj /* Copy all variables from hash table SRC to hash table DST.  */
181338fd1498Szrj 
181438fd1498Szrj static void
vars_copy(variable_table_type * dst,variable_table_type * src)181538fd1498Szrj vars_copy (variable_table_type *dst, variable_table_type *src)
181638fd1498Szrj {
181738fd1498Szrj   variable_iterator_type hi;
181838fd1498Szrj   variable *var;
181938fd1498Szrj 
182038fd1498Szrj   FOR_EACH_HASH_TABLE_ELEMENT (*src, var, variable, hi)
182138fd1498Szrj     {
182238fd1498Szrj       variable **dstp;
182338fd1498Szrj       var->refcount++;
182438fd1498Szrj       dstp = dst->find_slot_with_hash (var->dv, dv_htab_hash (var->dv),
182538fd1498Szrj 				       INSERT);
182638fd1498Szrj       *dstp = var;
182738fd1498Szrj     }
182838fd1498Szrj }
182938fd1498Szrj 
183038fd1498Szrj /* Map a decl to its main debug decl.  */
183138fd1498Szrj 
183238fd1498Szrj static inline tree
var_debug_decl(tree decl)183338fd1498Szrj var_debug_decl (tree decl)
183438fd1498Szrj {
183538fd1498Szrj   if (decl && VAR_P (decl) && DECL_HAS_DEBUG_EXPR_P (decl))
183638fd1498Szrj     {
183738fd1498Szrj       tree debugdecl = DECL_DEBUG_EXPR (decl);
183838fd1498Szrj       if (DECL_P (debugdecl))
183938fd1498Szrj 	decl = debugdecl;
184038fd1498Szrj     }
184138fd1498Szrj 
184238fd1498Szrj   return decl;
184338fd1498Szrj }
184438fd1498Szrj 
184538fd1498Szrj /* Set the register LOC to contain DV, OFFSET.  */
184638fd1498Szrj 
184738fd1498Szrj static void
var_reg_decl_set(dataflow_set * set,rtx loc,enum var_init_status initialized,decl_or_value dv,HOST_WIDE_INT offset,rtx set_src,enum insert_option iopt)184838fd1498Szrj var_reg_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
184938fd1498Szrj 		  decl_or_value dv, HOST_WIDE_INT offset, rtx set_src,
185038fd1498Szrj 		  enum insert_option iopt)
185138fd1498Szrj {
185238fd1498Szrj   attrs *node;
185338fd1498Szrj   bool decl_p = dv_is_decl_p (dv);
185438fd1498Szrj 
185538fd1498Szrj   if (decl_p)
185638fd1498Szrj     dv = dv_from_decl (var_debug_decl (dv_as_decl (dv)));
185738fd1498Szrj 
185838fd1498Szrj   for (node = set->regs[REGNO (loc)]; node; node = node->next)
185938fd1498Szrj     if (dv_as_opaque (node->dv) == dv_as_opaque (dv)
186038fd1498Szrj 	&& node->offset == offset)
186138fd1498Szrj       break;
186238fd1498Szrj   if (!node)
186338fd1498Szrj     attrs_list_insert (&set->regs[REGNO (loc)], dv, offset, loc);
186438fd1498Szrj   set_variable_part (set, loc, dv, offset, initialized, set_src, iopt);
186538fd1498Szrj }
186638fd1498Szrj 
186738fd1498Szrj /* Return true if we should track a location that is OFFSET bytes from
186838fd1498Szrj    a variable.  Store the constant offset in *OFFSET_OUT if so.  */
186938fd1498Szrj 
187038fd1498Szrj static bool
track_offset_p(poly_int64 offset,HOST_WIDE_INT * offset_out)187138fd1498Szrj track_offset_p (poly_int64 offset, HOST_WIDE_INT *offset_out)
187238fd1498Szrj {
187338fd1498Szrj   HOST_WIDE_INT const_offset;
187438fd1498Szrj   if (!offset.is_constant (&const_offset)
187538fd1498Szrj       || !IN_RANGE (const_offset, 0, MAX_VAR_PARTS - 1))
187638fd1498Szrj     return false;
187738fd1498Szrj   *offset_out = const_offset;
187838fd1498Szrj   return true;
187938fd1498Szrj }
188038fd1498Szrj 
188138fd1498Szrj /* Return the offset of a register that track_offset_p says we
188238fd1498Szrj    should track.  */
188338fd1498Szrj 
188438fd1498Szrj static HOST_WIDE_INT
get_tracked_reg_offset(rtx loc)188538fd1498Szrj get_tracked_reg_offset (rtx loc)
188638fd1498Szrj {
188738fd1498Szrj   HOST_WIDE_INT offset;
188838fd1498Szrj   if (!track_offset_p (REG_OFFSET (loc), &offset))
188938fd1498Szrj     gcc_unreachable ();
189038fd1498Szrj   return offset;
189138fd1498Szrj }
189238fd1498Szrj 
189338fd1498Szrj /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
189438fd1498Szrj 
189538fd1498Szrj static void
var_reg_set(dataflow_set * set,rtx loc,enum var_init_status initialized,rtx set_src)189638fd1498Szrj var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
189738fd1498Szrj 	     rtx set_src)
189838fd1498Szrj {
189938fd1498Szrj   tree decl = REG_EXPR (loc);
190038fd1498Szrj   HOST_WIDE_INT offset = get_tracked_reg_offset (loc);
190138fd1498Szrj 
190238fd1498Szrj   var_reg_decl_set (set, loc, initialized,
190338fd1498Szrj 		    dv_from_decl (decl), offset, set_src, INSERT);
190438fd1498Szrj }
190538fd1498Szrj 
190638fd1498Szrj static enum var_init_status
get_init_value(dataflow_set * set,rtx loc,decl_or_value dv)190738fd1498Szrj get_init_value (dataflow_set *set, rtx loc, decl_or_value dv)
190838fd1498Szrj {
190938fd1498Szrj   variable *var;
191038fd1498Szrj   int i;
191138fd1498Szrj   enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN;
191238fd1498Szrj 
191338fd1498Szrj   if (! flag_var_tracking_uninit)
191438fd1498Szrj     return VAR_INIT_STATUS_INITIALIZED;
191538fd1498Szrj 
191638fd1498Szrj   var = shared_hash_find (set->vars, dv);
191738fd1498Szrj   if (var)
191838fd1498Szrj     {
191938fd1498Szrj       for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
192038fd1498Szrj 	{
192138fd1498Szrj 	  location_chain *nextp;
192238fd1498Szrj 	  for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next)
192338fd1498Szrj 	    if (rtx_equal_p (nextp->loc, loc))
192438fd1498Szrj 	      {
192538fd1498Szrj 		ret_val = nextp->init;
192638fd1498Szrj 		break;
192738fd1498Szrj 	      }
192838fd1498Szrj 	}
192938fd1498Szrj     }
193038fd1498Szrj 
193138fd1498Szrj   return ret_val;
193238fd1498Szrj }
193338fd1498Szrj 
193438fd1498Szrj /* Delete current content of register LOC in dataflow set SET and set
193538fd1498Szrj    the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  If
193638fd1498Szrj    MODIFY is true, any other live copies of the same variable part are
193738fd1498Szrj    also deleted from the dataflow set, otherwise the variable part is
193838fd1498Szrj    assumed to be copied from another location holding the same
193938fd1498Szrj    part.  */
194038fd1498Szrj 
194138fd1498Szrj static void
var_reg_delete_and_set(dataflow_set * set,rtx loc,bool modify,enum var_init_status initialized,rtx set_src)194238fd1498Szrj var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify,
194338fd1498Szrj 			enum var_init_status initialized, rtx set_src)
194438fd1498Szrj {
194538fd1498Szrj   tree decl = REG_EXPR (loc);
194638fd1498Szrj   HOST_WIDE_INT offset = get_tracked_reg_offset (loc);
194738fd1498Szrj   attrs *node, *next;
194838fd1498Szrj   attrs **nextp;
194938fd1498Szrj 
195038fd1498Szrj   decl = var_debug_decl (decl);
195138fd1498Szrj 
195238fd1498Szrj   if (initialized == VAR_INIT_STATUS_UNKNOWN)
195338fd1498Szrj     initialized = get_init_value (set, loc, dv_from_decl (decl));
195438fd1498Szrj 
195538fd1498Szrj   nextp = &set->regs[REGNO (loc)];
195638fd1498Szrj   for (node = *nextp; node; node = next)
195738fd1498Szrj     {
195838fd1498Szrj       next = node->next;
195938fd1498Szrj       if (dv_as_opaque (node->dv) != decl || node->offset != offset)
196038fd1498Szrj 	{
196138fd1498Szrj 	  delete_variable_part (set, node->loc, node->dv, node->offset);
196238fd1498Szrj 	  delete node;
196338fd1498Szrj 	  *nextp = next;
196438fd1498Szrj 	}
196538fd1498Szrj       else
196638fd1498Szrj 	{
196738fd1498Szrj 	  node->loc = loc;
196838fd1498Szrj 	  nextp = &node->next;
196938fd1498Szrj 	}
197038fd1498Szrj     }
197138fd1498Szrj   if (modify)
197238fd1498Szrj     clobber_variable_part (set, loc, dv_from_decl (decl), offset, set_src);
197338fd1498Szrj   var_reg_set (set, loc, initialized, set_src);
197438fd1498Szrj }
197538fd1498Szrj 
197638fd1498Szrj /* Delete the association of register LOC in dataflow set SET with any
197738fd1498Szrj    variables that aren't onepart.  If CLOBBER is true, also delete any
197838fd1498Szrj    other live copies of the same variable part, and delete the
197938fd1498Szrj    association with onepart dvs too.  */
198038fd1498Szrj 
198138fd1498Szrj static void
var_reg_delete(dataflow_set * set,rtx loc,bool clobber)198238fd1498Szrj var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
198338fd1498Szrj {
198438fd1498Szrj   attrs **nextp = &set->regs[REGNO (loc)];
198538fd1498Szrj   attrs *node, *next;
198638fd1498Szrj 
198738fd1498Szrj   HOST_WIDE_INT offset;
198838fd1498Szrj   if (clobber && track_offset_p (REG_OFFSET (loc), &offset))
198938fd1498Szrj     {
199038fd1498Szrj       tree decl = REG_EXPR (loc);
199138fd1498Szrj 
199238fd1498Szrj       decl = var_debug_decl (decl);
199338fd1498Szrj 
199438fd1498Szrj       clobber_variable_part (set, NULL, dv_from_decl (decl), offset, NULL);
199538fd1498Szrj     }
199638fd1498Szrj 
199738fd1498Szrj   for (node = *nextp; node; node = next)
199838fd1498Szrj     {
199938fd1498Szrj       next = node->next;
200038fd1498Szrj       if (clobber || !dv_onepart_p (node->dv))
200138fd1498Szrj 	{
200238fd1498Szrj 	  delete_variable_part (set, node->loc, node->dv, node->offset);
200338fd1498Szrj 	  delete node;
200438fd1498Szrj 	  *nextp = next;
200538fd1498Szrj 	}
200638fd1498Szrj       else
200738fd1498Szrj 	nextp = &node->next;
200838fd1498Szrj     }
200938fd1498Szrj }
201038fd1498Szrj 
201138fd1498Szrj /* Delete content of register with number REGNO in dataflow set SET.  */
201238fd1498Szrj 
201338fd1498Szrj static void
var_regno_delete(dataflow_set * set,int regno)201438fd1498Szrj var_regno_delete (dataflow_set *set, int regno)
201538fd1498Szrj {
201638fd1498Szrj   attrs **reg = &set->regs[regno];
201738fd1498Szrj   attrs *node, *next;
201838fd1498Szrj 
201938fd1498Szrj   for (node = *reg; node; node = next)
202038fd1498Szrj     {
202138fd1498Szrj       next = node->next;
202238fd1498Szrj       delete_variable_part (set, node->loc, node->dv, node->offset);
202338fd1498Szrj       delete node;
202438fd1498Szrj     }
202538fd1498Szrj   *reg = NULL;
202638fd1498Szrj }
202738fd1498Szrj 
202838fd1498Szrj /* Return true if I is the negated value of a power of two.  */
202938fd1498Szrj static bool
negative_power_of_two_p(HOST_WIDE_INT i)203038fd1498Szrj negative_power_of_two_p (HOST_WIDE_INT i)
203138fd1498Szrj {
203238fd1498Szrj   unsigned HOST_WIDE_INT x = -(unsigned HOST_WIDE_INT)i;
203338fd1498Szrj   return pow2_or_zerop (x);
203438fd1498Szrj }
203538fd1498Szrj 
203638fd1498Szrj /* Strip constant offsets and alignments off of LOC.  Return the base
203738fd1498Szrj    expression.  */
203838fd1498Szrj 
203938fd1498Szrj static rtx
vt_get_canonicalize_base(rtx loc)204038fd1498Szrj vt_get_canonicalize_base (rtx loc)
204138fd1498Szrj {
204238fd1498Szrj   while ((GET_CODE (loc) == PLUS
204338fd1498Szrj 	  || GET_CODE (loc) == AND)
204438fd1498Szrj 	 && GET_CODE (XEXP (loc, 1)) == CONST_INT
204538fd1498Szrj 	 && (GET_CODE (loc) != AND
204638fd1498Szrj 	     || negative_power_of_two_p (INTVAL (XEXP (loc, 1)))))
204738fd1498Szrj     loc = XEXP (loc, 0);
204838fd1498Szrj 
204938fd1498Szrj   return loc;
205038fd1498Szrj }
205138fd1498Szrj 
205238fd1498Szrj /* This caches canonicalized addresses for VALUEs, computed using
205338fd1498Szrj    information in the global cselib table.  */
205438fd1498Szrj static hash_map<rtx, rtx> *global_get_addr_cache;
205538fd1498Szrj 
205638fd1498Szrj /* This caches canonicalized addresses for VALUEs, computed using
205738fd1498Szrj    information from the global cache and information pertaining to a
205838fd1498Szrj    basic block being analyzed.  */
205938fd1498Szrj static hash_map<rtx, rtx> *local_get_addr_cache;
206038fd1498Szrj 
206138fd1498Szrj static rtx vt_canonicalize_addr (dataflow_set *, rtx);
206238fd1498Szrj 
206338fd1498Szrj /* Return the canonical address for LOC, that must be a VALUE, using a
206438fd1498Szrj    cached global equivalence or computing it and storing it in the
206538fd1498Szrj    global cache.  */
206638fd1498Szrj 
206738fd1498Szrj static rtx
get_addr_from_global_cache(rtx const loc)206838fd1498Szrj get_addr_from_global_cache (rtx const loc)
206938fd1498Szrj {
207038fd1498Szrj   rtx x;
207138fd1498Szrj 
207238fd1498Szrj   gcc_checking_assert (GET_CODE (loc) == VALUE);
207338fd1498Szrj 
207438fd1498Szrj   bool existed;
207538fd1498Szrj   rtx *slot = &global_get_addr_cache->get_or_insert (loc, &existed);
207638fd1498Szrj   if (existed)
207738fd1498Szrj     return *slot;
207838fd1498Szrj 
207938fd1498Szrj   x = canon_rtx (get_addr (loc));
208038fd1498Szrj 
208138fd1498Szrj   /* Tentative, avoiding infinite recursion.  */
208238fd1498Szrj   *slot = x;
208338fd1498Szrj 
208438fd1498Szrj   if (x != loc)
208538fd1498Szrj     {
208638fd1498Szrj       rtx nx = vt_canonicalize_addr (NULL, x);
208738fd1498Szrj       if (nx != x)
208838fd1498Szrj 	{
208938fd1498Szrj 	  /* The table may have moved during recursion, recompute
209038fd1498Szrj 	     SLOT.  */
209138fd1498Szrj 	  *global_get_addr_cache->get (loc) = x = nx;
209238fd1498Szrj 	}
209338fd1498Szrj     }
209438fd1498Szrj 
209538fd1498Szrj   return x;
209638fd1498Szrj }
209738fd1498Szrj 
209838fd1498Szrj /* Return the canonical address for LOC, that must be a VALUE, using a
209938fd1498Szrj    cached local equivalence or computing it and storing it in the
210038fd1498Szrj    local cache.  */
210138fd1498Szrj 
210238fd1498Szrj static rtx
get_addr_from_local_cache(dataflow_set * set,rtx const loc)210338fd1498Szrj get_addr_from_local_cache (dataflow_set *set, rtx const loc)
210438fd1498Szrj {
210538fd1498Szrj   rtx x;
210638fd1498Szrj   decl_or_value dv;
210738fd1498Szrj   variable *var;
210838fd1498Szrj   location_chain *l;
210938fd1498Szrj 
211038fd1498Szrj   gcc_checking_assert (GET_CODE (loc) == VALUE);
211138fd1498Szrj 
211238fd1498Szrj   bool existed;
211338fd1498Szrj   rtx *slot = &local_get_addr_cache->get_or_insert (loc, &existed);
211438fd1498Szrj   if (existed)
211538fd1498Szrj     return *slot;
211638fd1498Szrj 
211738fd1498Szrj   x = get_addr_from_global_cache (loc);
211838fd1498Szrj 
211938fd1498Szrj   /* Tentative, avoiding infinite recursion.  */
212038fd1498Szrj   *slot = x;
212138fd1498Szrj 
212238fd1498Szrj   /* Recurse to cache local expansion of X, or if we need to search
212338fd1498Szrj      for a VALUE in the expansion.  */
212438fd1498Szrj   if (x != loc)
212538fd1498Szrj     {
212638fd1498Szrj       rtx nx = vt_canonicalize_addr (set, x);
212738fd1498Szrj       if (nx != x)
212838fd1498Szrj 	{
212938fd1498Szrj 	  slot = local_get_addr_cache->get (loc);
213038fd1498Szrj 	  *slot = x = nx;
213138fd1498Szrj 	}
213238fd1498Szrj       return x;
213338fd1498Szrj     }
213438fd1498Szrj 
213538fd1498Szrj   dv = dv_from_rtx (x);
213638fd1498Szrj   var = shared_hash_find (set->vars, dv);
213738fd1498Szrj   if (!var)
213838fd1498Szrj     return x;
213938fd1498Szrj 
214038fd1498Szrj   /* Look for an improved equivalent expression.  */
214138fd1498Szrj   for (l = var->var_part[0].loc_chain; l; l = l->next)
214238fd1498Szrj     {
214338fd1498Szrj       rtx base = vt_get_canonicalize_base (l->loc);
214438fd1498Szrj       if (GET_CODE (base) == VALUE
214538fd1498Szrj 	  && canon_value_cmp (base, loc))
214638fd1498Szrj 	{
214738fd1498Szrj 	  rtx nx = vt_canonicalize_addr (set, l->loc);
214838fd1498Szrj 	  if (x != nx)
214938fd1498Szrj 	    {
215038fd1498Szrj 	      slot = local_get_addr_cache->get (loc);
215138fd1498Szrj 	      *slot = x = nx;
215238fd1498Szrj 	    }
215338fd1498Szrj 	  break;
215438fd1498Szrj 	}
215538fd1498Szrj     }
215638fd1498Szrj 
215738fd1498Szrj   return x;
215838fd1498Szrj }
215938fd1498Szrj 
216038fd1498Szrj /* Canonicalize LOC using equivalences from SET in addition to those
216138fd1498Szrj    in the cselib static table.  It expects a VALUE-based expression,
216238fd1498Szrj    and it will only substitute VALUEs with other VALUEs or
216338fd1498Szrj    function-global equivalences, so that, if two addresses have base
216438fd1498Szrj    VALUEs that are locally or globally related in ways that
216538fd1498Szrj    memrefs_conflict_p cares about, they will both canonicalize to
216638fd1498Szrj    expressions that have the same base VALUE.
216738fd1498Szrj 
216838fd1498Szrj    The use of VALUEs as canonical base addresses enables the canonical
216938fd1498Szrj    RTXs to remain unchanged globally, if they resolve to a constant,
217038fd1498Szrj    or throughout a basic block otherwise, so that they can be cached
217138fd1498Szrj    and the cache needs not be invalidated when REGs, MEMs or such
217238fd1498Szrj    change.  */
217338fd1498Szrj 
217438fd1498Szrj static rtx
vt_canonicalize_addr(dataflow_set * set,rtx oloc)217538fd1498Szrj vt_canonicalize_addr (dataflow_set *set, rtx oloc)
217638fd1498Szrj {
217738fd1498Szrj   HOST_WIDE_INT ofst = 0;
217838fd1498Szrj   machine_mode mode = GET_MODE (oloc);
217938fd1498Szrj   rtx loc = oloc;
218038fd1498Szrj   rtx x;
218138fd1498Szrj   bool retry = true;
218238fd1498Szrj 
218338fd1498Szrj   while (retry)
218438fd1498Szrj     {
218538fd1498Szrj       while (GET_CODE (loc) == PLUS
218638fd1498Szrj 	     && GET_CODE (XEXP (loc, 1)) == CONST_INT)
218738fd1498Szrj 	{
218838fd1498Szrj 	  ofst += INTVAL (XEXP (loc, 1));
218938fd1498Szrj 	  loc = XEXP (loc, 0);
219038fd1498Szrj 	}
219138fd1498Szrj 
219238fd1498Szrj       /* Alignment operations can't normally be combined, so just
219338fd1498Szrj 	 canonicalize the base and we're done.  We'll normally have
219438fd1498Szrj 	 only one stack alignment anyway.  */
219538fd1498Szrj       if (GET_CODE (loc) == AND
219638fd1498Szrj 	  && GET_CODE (XEXP (loc, 1)) == CONST_INT
219738fd1498Szrj 	  && negative_power_of_two_p (INTVAL (XEXP (loc, 1))))
219838fd1498Szrj 	{
219938fd1498Szrj 	  x = vt_canonicalize_addr (set, XEXP (loc, 0));
220038fd1498Szrj 	  if (x != XEXP (loc, 0))
220138fd1498Szrj 	    loc = gen_rtx_AND (mode, x, XEXP (loc, 1));
220238fd1498Szrj 	  retry = false;
220338fd1498Szrj 	}
220438fd1498Szrj 
220538fd1498Szrj       if (GET_CODE (loc) == VALUE)
220638fd1498Szrj 	{
220738fd1498Szrj 	  if (set)
220838fd1498Szrj 	    loc = get_addr_from_local_cache (set, loc);
220938fd1498Szrj 	  else
221038fd1498Szrj 	    loc = get_addr_from_global_cache (loc);
221138fd1498Szrj 
221238fd1498Szrj 	  /* Consolidate plus_constants.  */
221338fd1498Szrj 	  while (ofst && GET_CODE (loc) == PLUS
221438fd1498Szrj 		 && GET_CODE (XEXP (loc, 1)) == CONST_INT)
221538fd1498Szrj 	    {
221638fd1498Szrj 	      ofst += INTVAL (XEXP (loc, 1));
221738fd1498Szrj 	      loc = XEXP (loc, 0);
221838fd1498Szrj 	    }
221938fd1498Szrj 
222038fd1498Szrj 	  retry = false;
222138fd1498Szrj 	}
222238fd1498Szrj       else
222338fd1498Szrj 	{
222438fd1498Szrj 	  x = canon_rtx (loc);
222538fd1498Szrj 	  if (retry)
222638fd1498Szrj 	    retry = (x != loc);
222738fd1498Szrj 	  loc = x;
222838fd1498Szrj 	}
222938fd1498Szrj     }
223038fd1498Szrj 
223138fd1498Szrj   /* Add OFST back in.  */
223238fd1498Szrj   if (ofst)
223338fd1498Szrj     {
223438fd1498Szrj       /* Don't build new RTL if we can help it.  */
223538fd1498Szrj       if (GET_CODE (oloc) == PLUS
223638fd1498Szrj 	  && XEXP (oloc, 0) == loc
223738fd1498Szrj 	  && INTVAL (XEXP (oloc, 1)) == ofst)
223838fd1498Szrj 	return oloc;
223938fd1498Szrj 
224038fd1498Szrj       loc = plus_constant (mode, loc, ofst);
224138fd1498Szrj     }
224238fd1498Szrj 
224338fd1498Szrj   return loc;
224438fd1498Szrj }
224538fd1498Szrj 
224638fd1498Szrj /* Return true iff there's a true dependence between MLOC and LOC.
224738fd1498Szrj    MADDR must be a canonicalized version of MLOC's address.  */
224838fd1498Szrj 
224938fd1498Szrj static inline bool
vt_canon_true_dep(dataflow_set * set,rtx mloc,rtx maddr,rtx loc)225038fd1498Szrj vt_canon_true_dep (dataflow_set *set, rtx mloc, rtx maddr, rtx loc)
225138fd1498Szrj {
225238fd1498Szrj   if (GET_CODE (loc) != MEM)
225338fd1498Szrj     return false;
225438fd1498Szrj 
225538fd1498Szrj   rtx addr = vt_canonicalize_addr (set, XEXP (loc, 0));
225638fd1498Szrj   if (!canon_true_dependence (mloc, GET_MODE (mloc), maddr, loc, addr))
225738fd1498Szrj     return false;
225838fd1498Szrj 
225938fd1498Szrj   return true;
226038fd1498Szrj }
226138fd1498Szrj 
226238fd1498Szrj /* Hold parameters for the hashtab traversal function
226338fd1498Szrj    drop_overlapping_mem_locs, see below.  */
226438fd1498Szrj 
226538fd1498Szrj struct overlapping_mems
226638fd1498Szrj {
226738fd1498Szrj   dataflow_set *set;
226838fd1498Szrj   rtx loc, addr;
226938fd1498Szrj };
227038fd1498Szrj 
227138fd1498Szrj /* Remove all MEMs that overlap with COMS->LOC from the location list
227238fd1498Szrj    of a hash table entry for a onepart variable.  COMS->ADDR must be a
227338fd1498Szrj    canonicalized form of COMS->LOC's address, and COMS->LOC must be
227438fd1498Szrj    canonicalized itself.  */
227538fd1498Szrj 
227638fd1498Szrj int
drop_overlapping_mem_locs(variable ** slot,overlapping_mems * coms)227738fd1498Szrj drop_overlapping_mem_locs (variable **slot, overlapping_mems *coms)
227838fd1498Szrj {
227938fd1498Szrj   dataflow_set *set = coms->set;
228038fd1498Szrj   rtx mloc = coms->loc, addr = coms->addr;
228138fd1498Szrj   variable *var = *slot;
228238fd1498Szrj 
228338fd1498Szrj   if (var->onepart != NOT_ONEPART)
228438fd1498Szrj     {
228538fd1498Szrj       location_chain *loc, **locp;
228638fd1498Szrj       bool changed = false;
228738fd1498Szrj       rtx cur_loc;
228838fd1498Szrj 
228938fd1498Szrj       gcc_assert (var->n_var_parts == 1);
229038fd1498Szrj 
229138fd1498Szrj       if (shared_var_p (var, set->vars))
229238fd1498Szrj 	{
229338fd1498Szrj 	  for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
229438fd1498Szrj 	    if (vt_canon_true_dep (set, mloc, addr, loc->loc))
229538fd1498Szrj 	      break;
229638fd1498Szrj 
229738fd1498Szrj 	  if (!loc)
229838fd1498Szrj 	    return 1;
229938fd1498Szrj 
230038fd1498Szrj 	  slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN);
230138fd1498Szrj 	  var = *slot;
230238fd1498Szrj 	  gcc_assert (var->n_var_parts == 1);
230338fd1498Szrj 	}
230438fd1498Szrj 
230538fd1498Szrj       if (VAR_LOC_1PAUX (var))
230638fd1498Szrj 	cur_loc = VAR_LOC_FROM (var);
230738fd1498Szrj       else
230838fd1498Szrj 	cur_loc = var->var_part[0].cur_loc;
230938fd1498Szrj 
231038fd1498Szrj       for (locp = &var->var_part[0].loc_chain, loc = *locp;
231138fd1498Szrj 	   loc; loc = *locp)
231238fd1498Szrj 	{
231338fd1498Szrj 	  if (!vt_canon_true_dep (set, mloc, addr, loc->loc))
231438fd1498Szrj 	    {
231538fd1498Szrj 	      locp = &loc->next;
231638fd1498Szrj 	      continue;
231738fd1498Szrj 	    }
231838fd1498Szrj 
231938fd1498Szrj 	  *locp = loc->next;
232038fd1498Szrj 	  /* If we have deleted the location which was last emitted
232138fd1498Szrj 	     we have to emit new location so add the variable to set
232238fd1498Szrj 	     of changed variables.  */
232338fd1498Szrj 	  if (cur_loc == loc->loc)
232438fd1498Szrj 	    {
232538fd1498Szrj 	      changed = true;
232638fd1498Szrj 	      var->var_part[0].cur_loc = NULL;
232738fd1498Szrj 	      if (VAR_LOC_1PAUX (var))
232838fd1498Szrj 		VAR_LOC_FROM (var) = NULL;
232938fd1498Szrj 	    }
233038fd1498Szrj 	  delete loc;
233138fd1498Szrj 	}
233238fd1498Szrj 
233338fd1498Szrj       if (!var->var_part[0].loc_chain)
233438fd1498Szrj 	{
233538fd1498Szrj 	  var->n_var_parts--;
233638fd1498Szrj 	  changed = true;
233738fd1498Szrj 	}
233838fd1498Szrj       if (changed)
233938fd1498Szrj 	variable_was_changed (var, set);
234038fd1498Szrj     }
234138fd1498Szrj 
234238fd1498Szrj   return 1;
234338fd1498Szrj }
234438fd1498Szrj 
234538fd1498Szrj /* Remove from SET all VALUE bindings to MEMs that overlap with LOC.  */
234638fd1498Szrj 
234738fd1498Szrj static void
clobber_overlapping_mems(dataflow_set * set,rtx loc)234838fd1498Szrj clobber_overlapping_mems (dataflow_set *set, rtx loc)
234938fd1498Szrj {
235038fd1498Szrj   struct overlapping_mems coms;
235138fd1498Szrj 
235238fd1498Szrj   gcc_checking_assert (GET_CODE (loc) == MEM);
235338fd1498Szrj 
235438fd1498Szrj   coms.set = set;
235538fd1498Szrj   coms.loc = canon_rtx (loc);
235638fd1498Szrj   coms.addr = vt_canonicalize_addr (set, XEXP (loc, 0));
235738fd1498Szrj 
235838fd1498Szrj   set->traversed_vars = set->vars;
235938fd1498Szrj   shared_hash_htab (set->vars)
236038fd1498Szrj     ->traverse <overlapping_mems*, drop_overlapping_mem_locs> (&coms);
236138fd1498Szrj   set->traversed_vars = NULL;
236238fd1498Szrj }
236338fd1498Szrj 
236438fd1498Szrj /* Set the location of DV, OFFSET as the MEM LOC.  */
236538fd1498Szrj 
236638fd1498Szrj static void
var_mem_decl_set(dataflow_set * set,rtx loc,enum var_init_status initialized,decl_or_value dv,HOST_WIDE_INT offset,rtx set_src,enum insert_option iopt)236738fd1498Szrj var_mem_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
236838fd1498Szrj 		  decl_or_value dv, HOST_WIDE_INT offset, rtx set_src,
236938fd1498Szrj 		  enum insert_option iopt)
237038fd1498Szrj {
237138fd1498Szrj   if (dv_is_decl_p (dv))
237238fd1498Szrj     dv = dv_from_decl (var_debug_decl (dv_as_decl (dv)));
237338fd1498Szrj 
237438fd1498Szrj   set_variable_part (set, loc, dv, offset, initialized, set_src, iopt);
237538fd1498Szrj }
237638fd1498Szrj 
237738fd1498Szrj /* Set the location part of variable MEM_EXPR (LOC) in dataflow set
237838fd1498Szrj    SET to LOC.
237938fd1498Szrj    Adjust the address first if it is stack pointer based.  */
238038fd1498Szrj 
238138fd1498Szrj static void
var_mem_set(dataflow_set * set,rtx loc,enum var_init_status initialized,rtx set_src)238238fd1498Szrj var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
238338fd1498Szrj 	     rtx set_src)
238438fd1498Szrj {
238538fd1498Szrj   tree decl = MEM_EXPR (loc);
238638fd1498Szrj   HOST_WIDE_INT offset = int_mem_offset (loc);
238738fd1498Szrj 
238838fd1498Szrj   var_mem_decl_set (set, loc, initialized,
238938fd1498Szrj 		    dv_from_decl (decl), offset, set_src, INSERT);
239038fd1498Szrj }
239138fd1498Szrj 
239238fd1498Szrj /* Delete and set the location part of variable MEM_EXPR (LOC) in
239338fd1498Szrj    dataflow set SET to LOC.  If MODIFY is true, any other live copies
239438fd1498Szrj    of the same variable part are also deleted from the dataflow set,
239538fd1498Szrj    otherwise the variable part is assumed to be copied from another
239638fd1498Szrj    location holding the same part.
239738fd1498Szrj    Adjust the address first if it is stack pointer based.  */
239838fd1498Szrj 
239938fd1498Szrj static void
var_mem_delete_and_set(dataflow_set * set,rtx loc,bool modify,enum var_init_status initialized,rtx set_src)240038fd1498Szrj var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify,
240138fd1498Szrj 			enum var_init_status initialized, rtx set_src)
240238fd1498Szrj {
240338fd1498Szrj   tree decl = MEM_EXPR (loc);
240438fd1498Szrj   HOST_WIDE_INT offset = int_mem_offset (loc);
240538fd1498Szrj 
240638fd1498Szrj   clobber_overlapping_mems (set, loc);
240738fd1498Szrj   decl = var_debug_decl (decl);
240838fd1498Szrj 
240938fd1498Szrj   if (initialized == VAR_INIT_STATUS_UNKNOWN)
241038fd1498Szrj     initialized = get_init_value (set, loc, dv_from_decl (decl));
241138fd1498Szrj 
241238fd1498Szrj   if (modify)
241338fd1498Szrj     clobber_variable_part (set, NULL, dv_from_decl (decl), offset, set_src);
241438fd1498Szrj   var_mem_set (set, loc, initialized, set_src);
241538fd1498Szrj }
241638fd1498Szrj 
241738fd1498Szrj /* Delete the location part LOC from dataflow set SET.  If CLOBBER is
241838fd1498Szrj    true, also delete any other live copies of the same variable part.
241938fd1498Szrj    Adjust the address first if it is stack pointer based.  */
242038fd1498Szrj 
242138fd1498Szrj static void
var_mem_delete(dataflow_set * set,rtx loc,bool clobber)242238fd1498Szrj var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
242338fd1498Szrj {
242438fd1498Szrj   tree decl = MEM_EXPR (loc);
242538fd1498Szrj   HOST_WIDE_INT offset = int_mem_offset (loc);
242638fd1498Szrj 
242738fd1498Szrj   clobber_overlapping_mems (set, loc);
242838fd1498Szrj   decl = var_debug_decl (decl);
242938fd1498Szrj   if (clobber)
243038fd1498Szrj     clobber_variable_part (set, NULL, dv_from_decl (decl), offset, NULL);
243138fd1498Szrj   delete_variable_part (set, loc, dv_from_decl (decl), offset);
243238fd1498Szrj }
243338fd1498Szrj 
243438fd1498Szrj /* Return true if LOC should not be expanded for location expressions,
243538fd1498Szrj    or used in them.  */
243638fd1498Szrj 
243738fd1498Szrj static inline bool
unsuitable_loc(rtx loc)243838fd1498Szrj unsuitable_loc (rtx loc)
243938fd1498Szrj {
244038fd1498Szrj   switch (GET_CODE (loc))
244138fd1498Szrj     {
244238fd1498Szrj     case PC:
244338fd1498Szrj     case SCRATCH:
244438fd1498Szrj     case CC0:
244538fd1498Szrj     case ASM_INPUT:
244638fd1498Szrj     case ASM_OPERANDS:
244738fd1498Szrj       return true;
244838fd1498Szrj 
244938fd1498Szrj     default:
245038fd1498Szrj       return false;
245138fd1498Szrj     }
245238fd1498Szrj }
245338fd1498Szrj 
245438fd1498Szrj /* Bind VAL to LOC in SET.  If MODIFIED, detach LOC from any values
245538fd1498Szrj    bound to it.  */
245638fd1498Szrj 
245738fd1498Szrj static inline void
val_bind(dataflow_set * set,rtx val,rtx loc,bool modified)245838fd1498Szrj val_bind (dataflow_set *set, rtx val, rtx loc, bool modified)
245938fd1498Szrj {
246038fd1498Szrj   if (REG_P (loc))
246138fd1498Szrj     {
246238fd1498Szrj       if (modified)
246338fd1498Szrj 	var_regno_delete (set, REGNO (loc));
246438fd1498Szrj       var_reg_decl_set (set, loc, VAR_INIT_STATUS_INITIALIZED,
246538fd1498Szrj 			dv_from_value (val), 0, NULL_RTX, INSERT);
246638fd1498Szrj     }
246738fd1498Szrj   else if (MEM_P (loc))
246838fd1498Szrj     {
246938fd1498Szrj       struct elt_loc_list *l = CSELIB_VAL_PTR (val)->locs;
247038fd1498Szrj 
247138fd1498Szrj       if (modified)
247238fd1498Szrj 	clobber_overlapping_mems (set, loc);
247338fd1498Szrj 
247438fd1498Szrj       if (l && GET_CODE (l->loc) == VALUE)
247538fd1498Szrj 	l = canonical_cselib_val (CSELIB_VAL_PTR (l->loc))->locs;
247638fd1498Szrj 
247738fd1498Szrj       /* If this MEM is a global constant, we don't need it in the
247838fd1498Szrj 	 dynamic tables.  ??? We should test this before emitting the
247938fd1498Szrj 	 micro-op in the first place.  */
248038fd1498Szrj       while (l)
248138fd1498Szrj 	if (GET_CODE (l->loc) == MEM && XEXP (l->loc, 0) == XEXP (loc, 0))
248238fd1498Szrj 	  break;
248338fd1498Szrj 	else
248438fd1498Szrj 	  l = l->next;
248538fd1498Szrj 
248638fd1498Szrj       if (!l)
248738fd1498Szrj 	var_mem_decl_set (set, loc, VAR_INIT_STATUS_INITIALIZED,
248838fd1498Szrj 			  dv_from_value (val), 0, NULL_RTX, INSERT);
248938fd1498Szrj     }
249038fd1498Szrj   else
249138fd1498Szrj     {
249238fd1498Szrj       /* Other kinds of equivalences are necessarily static, at least
249338fd1498Szrj 	 so long as we do not perform substitutions while merging
249438fd1498Szrj 	 expressions.  */
249538fd1498Szrj       gcc_unreachable ();
249638fd1498Szrj       set_variable_part (set, loc, dv_from_value (val), 0,
249738fd1498Szrj 			 VAR_INIT_STATUS_INITIALIZED, NULL_RTX, INSERT);
249838fd1498Szrj     }
249938fd1498Szrj }
250038fd1498Szrj 
250138fd1498Szrj /* Bind a value to a location it was just stored in.  If MODIFIED
250238fd1498Szrj    holds, assume the location was modified, detaching it from any
250338fd1498Szrj    values bound to it.  */
250438fd1498Szrj 
250538fd1498Szrj static void
val_store(dataflow_set * set,rtx val,rtx loc,rtx_insn * insn,bool modified)250638fd1498Szrj val_store (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn,
250738fd1498Szrj 	   bool modified)
250838fd1498Szrj {
250938fd1498Szrj   cselib_val *v = CSELIB_VAL_PTR (val);
251038fd1498Szrj 
251138fd1498Szrj   gcc_assert (cselib_preserved_value_p (v));
251238fd1498Szrj 
251338fd1498Szrj   if (dump_file)
251438fd1498Szrj     {
251538fd1498Szrj       fprintf (dump_file, "%i: ", insn ? INSN_UID (insn) : 0);
251638fd1498Szrj       print_inline_rtx (dump_file, loc, 0);
251738fd1498Szrj       fprintf (dump_file, " evaluates to ");
251838fd1498Szrj       print_inline_rtx (dump_file, val, 0);
251938fd1498Szrj       if (v->locs)
252038fd1498Szrj 	{
252138fd1498Szrj 	  struct elt_loc_list *l;
252238fd1498Szrj 	  for (l = v->locs; l; l = l->next)
252338fd1498Szrj 	    {
252438fd1498Szrj 	      fprintf (dump_file, "\n%i: ", INSN_UID (l->setting_insn));
252538fd1498Szrj 	      print_inline_rtx (dump_file, l->loc, 0);
252638fd1498Szrj 	    }
252738fd1498Szrj 	}
252838fd1498Szrj       fprintf (dump_file, "\n");
252938fd1498Szrj     }
253038fd1498Szrj 
253138fd1498Szrj   gcc_checking_assert (!unsuitable_loc (loc));
253238fd1498Szrj 
253338fd1498Szrj   val_bind (set, val, loc, modified);
253438fd1498Szrj }
253538fd1498Szrj 
253638fd1498Szrj /* Clear (canonical address) slots that reference X.  */
253738fd1498Szrj 
253838fd1498Szrj bool
local_get_addr_clear_given_value(rtx const &,rtx * slot,rtx x)253938fd1498Szrj local_get_addr_clear_given_value (rtx const &, rtx *slot, rtx x)
254038fd1498Szrj {
254138fd1498Szrj   if (vt_get_canonicalize_base (*slot) == x)
254238fd1498Szrj     *slot = NULL;
254338fd1498Szrj   return true;
254438fd1498Szrj }
254538fd1498Szrj 
254638fd1498Szrj /* Reset this node, detaching all its equivalences.  Return the slot
254738fd1498Szrj    in the variable hash table that holds dv, if there is one.  */
254838fd1498Szrj 
254938fd1498Szrj static void
val_reset(dataflow_set * set,decl_or_value dv)255038fd1498Szrj val_reset (dataflow_set *set, decl_or_value dv)
255138fd1498Szrj {
255238fd1498Szrj   variable *var = shared_hash_find (set->vars, dv) ;
255338fd1498Szrj   location_chain *node;
255438fd1498Szrj   rtx cval;
255538fd1498Szrj 
255638fd1498Szrj   if (!var || !var->n_var_parts)
255738fd1498Szrj     return;
255838fd1498Szrj 
255938fd1498Szrj   gcc_assert (var->n_var_parts == 1);
256038fd1498Szrj 
256138fd1498Szrj   if (var->onepart == ONEPART_VALUE)
256238fd1498Szrj     {
256338fd1498Szrj       rtx x = dv_as_value (dv);
256438fd1498Szrj 
256538fd1498Szrj       /* Relationships in the global cache don't change, so reset the
256638fd1498Szrj 	 local cache entry only.  */
256738fd1498Szrj       rtx *slot = local_get_addr_cache->get (x);
256838fd1498Szrj       if (slot)
256938fd1498Szrj 	{
257038fd1498Szrj 	  /* If the value resolved back to itself, odds are that other
257138fd1498Szrj 	     values may have cached it too.  These entries now refer
257238fd1498Szrj 	     to the old X, so detach them too.  Entries that used the
257338fd1498Szrj 	     old X but resolved to something else remain ok as long as
257438fd1498Szrj 	     that something else isn't also reset.  */
257538fd1498Szrj 	  if (*slot == x)
257638fd1498Szrj 	    local_get_addr_cache
257738fd1498Szrj 	      ->traverse<rtx, local_get_addr_clear_given_value> (x);
257838fd1498Szrj 	  *slot = NULL;
257938fd1498Szrj 	}
258038fd1498Szrj     }
258138fd1498Szrj 
258238fd1498Szrj   cval = NULL;
258338fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
258438fd1498Szrj     if (GET_CODE (node->loc) == VALUE
258538fd1498Szrj 	&& canon_value_cmp (node->loc, cval))
258638fd1498Szrj       cval = node->loc;
258738fd1498Szrj 
258838fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
258938fd1498Szrj     if (GET_CODE (node->loc) == VALUE && cval != node->loc)
259038fd1498Szrj       {
259138fd1498Szrj 	/* Redirect the equivalence link to the new canonical
259238fd1498Szrj 	   value, or simply remove it if it would point at
259338fd1498Szrj 	   itself.  */
259438fd1498Szrj 	if (cval)
259538fd1498Szrj 	  set_variable_part (set, cval, dv_from_value (node->loc),
259638fd1498Szrj 			     0, node->init, node->set_src, NO_INSERT);
259738fd1498Szrj 	delete_variable_part (set, dv_as_value (dv),
259838fd1498Szrj 			      dv_from_value (node->loc), 0);
259938fd1498Szrj       }
260038fd1498Szrj 
260138fd1498Szrj   if (cval)
260238fd1498Szrj     {
260338fd1498Szrj       decl_or_value cdv = dv_from_value (cval);
260438fd1498Szrj 
260538fd1498Szrj       /* Keep the remaining values connected, accumulating links
260638fd1498Szrj 	 in the canonical value.  */
260738fd1498Szrj       for (node = var->var_part[0].loc_chain; node; node = node->next)
260838fd1498Szrj 	{
260938fd1498Szrj 	  if (node->loc == cval)
261038fd1498Szrj 	    continue;
261138fd1498Szrj 	  else if (GET_CODE (node->loc) == REG)
261238fd1498Szrj 	    var_reg_decl_set (set, node->loc, node->init, cdv, 0,
261338fd1498Szrj 			      node->set_src, NO_INSERT);
261438fd1498Szrj 	  else if (GET_CODE (node->loc) == MEM)
261538fd1498Szrj 	    var_mem_decl_set (set, node->loc, node->init, cdv, 0,
261638fd1498Szrj 			      node->set_src, NO_INSERT);
261738fd1498Szrj 	  else
261838fd1498Szrj 	    set_variable_part (set, node->loc, cdv, 0,
261938fd1498Szrj 			       node->init, node->set_src, NO_INSERT);
262038fd1498Szrj 	}
262138fd1498Szrj     }
262238fd1498Szrj 
262338fd1498Szrj   /* We remove this last, to make sure that the canonical value is not
262438fd1498Szrj      removed to the point of requiring reinsertion.  */
262538fd1498Szrj   if (cval)
262638fd1498Szrj     delete_variable_part (set, dv_as_value (dv), dv_from_value (cval), 0);
262738fd1498Szrj 
262838fd1498Szrj   clobber_variable_part (set, NULL, dv, 0, NULL);
262938fd1498Szrj }
263038fd1498Szrj 
263138fd1498Szrj /* Find the values in a given location and map the val to another
263238fd1498Szrj    value, if it is unique, or add the location as one holding the
263338fd1498Szrj    value.  */
263438fd1498Szrj 
263538fd1498Szrj static void
val_resolve(dataflow_set * set,rtx val,rtx loc,rtx_insn * insn)263638fd1498Szrj val_resolve (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn)
263738fd1498Szrj {
263838fd1498Szrj   decl_or_value dv = dv_from_value (val);
263938fd1498Szrj 
264038fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
264138fd1498Szrj     {
264238fd1498Szrj       if (insn)
264338fd1498Szrj 	fprintf (dump_file, "%i: ", INSN_UID (insn));
264438fd1498Szrj       else
264538fd1498Szrj 	fprintf (dump_file, "head: ");
264638fd1498Szrj       print_inline_rtx (dump_file, val, 0);
264738fd1498Szrj       fputs (" is at ", dump_file);
264838fd1498Szrj       print_inline_rtx (dump_file, loc, 0);
264938fd1498Szrj       fputc ('\n', dump_file);
265038fd1498Szrj     }
265138fd1498Szrj 
265238fd1498Szrj   val_reset (set, dv);
265338fd1498Szrj 
265438fd1498Szrj   gcc_checking_assert (!unsuitable_loc (loc));
265538fd1498Szrj 
265638fd1498Szrj   if (REG_P (loc))
265738fd1498Szrj     {
265838fd1498Szrj       attrs *node, *found = NULL;
265938fd1498Szrj 
266038fd1498Szrj       for (node = set->regs[REGNO (loc)]; node; node = node->next)
266138fd1498Szrj 	if (dv_is_value_p (node->dv)
266238fd1498Szrj 	    && GET_MODE (dv_as_value (node->dv)) == GET_MODE (loc))
266338fd1498Szrj 	  {
266438fd1498Szrj 	    found = node;
266538fd1498Szrj 
266638fd1498Szrj 	    /* Map incoming equivalences.  ??? Wouldn't it be nice if
266738fd1498Szrj 	     we just started sharing the location lists?  Maybe a
266838fd1498Szrj 	     circular list ending at the value itself or some
266938fd1498Szrj 	     such.  */
267038fd1498Szrj 	    set_variable_part (set, dv_as_value (node->dv),
267138fd1498Szrj 			       dv_from_value (val), node->offset,
267238fd1498Szrj 			       VAR_INIT_STATUS_INITIALIZED, NULL_RTX, INSERT);
267338fd1498Szrj 	    set_variable_part (set, val, node->dv, node->offset,
267438fd1498Szrj 			       VAR_INIT_STATUS_INITIALIZED, NULL_RTX, INSERT);
267538fd1498Szrj 	  }
267638fd1498Szrj 
267738fd1498Szrj       /* If we didn't find any equivalence, we need to remember that
267838fd1498Szrj 	 this value is held in the named register.  */
267938fd1498Szrj       if (found)
268038fd1498Szrj 	return;
268138fd1498Szrj     }
268238fd1498Szrj   /* ??? Attempt to find and merge equivalent MEMs or other
268338fd1498Szrj      expressions too.  */
268438fd1498Szrj 
268538fd1498Szrj   val_bind (set, val, loc, false);
268638fd1498Szrj }
268738fd1498Szrj 
268838fd1498Szrj /* Initialize dataflow set SET to be empty.
268938fd1498Szrj    VARS_SIZE is the initial size of hash table VARS.  */
269038fd1498Szrj 
269138fd1498Szrj static void
dataflow_set_init(dataflow_set * set)269238fd1498Szrj dataflow_set_init (dataflow_set *set)
269338fd1498Szrj {
269438fd1498Szrj   init_attrs_list_set (set->regs);
269538fd1498Szrj   set->vars = shared_hash_copy (empty_shared_hash);
269638fd1498Szrj   set->stack_adjust = 0;
269738fd1498Szrj   set->traversed_vars = NULL;
269838fd1498Szrj }
269938fd1498Szrj 
270038fd1498Szrj /* Delete the contents of dataflow set SET.  */
270138fd1498Szrj 
270238fd1498Szrj static void
dataflow_set_clear(dataflow_set * set)270338fd1498Szrj dataflow_set_clear (dataflow_set *set)
270438fd1498Szrj {
270538fd1498Szrj   int i;
270638fd1498Szrj 
270738fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
270838fd1498Szrj     attrs_list_clear (&set->regs[i]);
270938fd1498Szrj 
271038fd1498Szrj   shared_hash_destroy (set->vars);
271138fd1498Szrj   set->vars = shared_hash_copy (empty_shared_hash);
271238fd1498Szrj }
271338fd1498Szrj 
271438fd1498Szrj /* Copy the contents of dataflow set SRC to DST.  */
271538fd1498Szrj 
271638fd1498Szrj static void
dataflow_set_copy(dataflow_set * dst,dataflow_set * src)271738fd1498Szrj dataflow_set_copy (dataflow_set *dst, dataflow_set *src)
271838fd1498Szrj {
271938fd1498Szrj   int i;
272038fd1498Szrj 
272138fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
272238fd1498Szrj     attrs_list_copy (&dst->regs[i], src->regs[i]);
272338fd1498Szrj 
272438fd1498Szrj   shared_hash_destroy (dst->vars);
272538fd1498Szrj   dst->vars = shared_hash_copy (src->vars);
272638fd1498Szrj   dst->stack_adjust = src->stack_adjust;
272738fd1498Szrj }
272838fd1498Szrj 
272938fd1498Szrj /* Information for merging lists of locations for a given offset of variable.
273038fd1498Szrj  */
273138fd1498Szrj struct variable_union_info
273238fd1498Szrj {
273338fd1498Szrj   /* Node of the location chain.  */
273438fd1498Szrj   location_chain *lc;
273538fd1498Szrj 
273638fd1498Szrj   /* The sum of positions in the input chains.  */
273738fd1498Szrj   int pos;
273838fd1498Szrj 
273938fd1498Szrj   /* The position in the chain of DST dataflow set.  */
274038fd1498Szrj   int pos_dst;
274138fd1498Szrj };
274238fd1498Szrj 
274338fd1498Szrj /* Buffer for location list sorting and its allocated size.  */
274438fd1498Szrj static struct variable_union_info *vui_vec;
274538fd1498Szrj static int vui_allocated;
274638fd1498Szrj 
274738fd1498Szrj /* Compare function for qsort, order the structures by POS element.  */
274838fd1498Szrj 
274938fd1498Szrj static int
variable_union_info_cmp_pos(const void * n1,const void * n2)275038fd1498Szrj variable_union_info_cmp_pos (const void *n1, const void *n2)
275138fd1498Szrj {
275238fd1498Szrj   const struct variable_union_info *const i1 =
275338fd1498Szrj     (const struct variable_union_info *) n1;
275438fd1498Szrj   const struct variable_union_info *const i2 =
275538fd1498Szrj     ( const struct variable_union_info *) n2;
275638fd1498Szrj 
275738fd1498Szrj   if (i1->pos != i2->pos)
275838fd1498Szrj     return i1->pos - i2->pos;
275938fd1498Szrj 
276038fd1498Szrj   return (i1->pos_dst - i2->pos_dst);
276138fd1498Szrj }
276238fd1498Szrj 
276338fd1498Szrj /* Compute union of location parts of variable *SLOT and the same variable
276438fd1498Szrj    from hash table DATA.  Compute "sorted" union of the location chains
276538fd1498Szrj    for common offsets, i.e. the locations of a variable part are sorted by
276638fd1498Szrj    a priority where the priority is the sum of the positions in the 2 chains
276738fd1498Szrj    (if a location is only in one list the position in the second list is
276838fd1498Szrj    defined to be larger than the length of the chains).
276938fd1498Szrj    When we are updating the location parts the newest location is in the
277038fd1498Szrj    beginning of the chain, so when we do the described "sorted" union
277138fd1498Szrj    we keep the newest locations in the beginning.  */
277238fd1498Szrj 
277338fd1498Szrj static int
variable_union(variable * src,dataflow_set * set)277438fd1498Szrj variable_union (variable *src, dataflow_set *set)
277538fd1498Szrj {
277638fd1498Szrj   variable *dst;
277738fd1498Szrj   variable **dstp;
277838fd1498Szrj   int i, j, k;
277938fd1498Szrj 
278038fd1498Szrj   dstp = shared_hash_find_slot (set->vars, src->dv);
278138fd1498Szrj   if (!dstp || !*dstp)
278238fd1498Szrj     {
278338fd1498Szrj       src->refcount++;
278438fd1498Szrj 
278538fd1498Szrj       dst_can_be_shared = false;
278638fd1498Szrj       if (!dstp)
278738fd1498Szrj 	dstp = shared_hash_find_slot_unshare (&set->vars, src->dv, INSERT);
278838fd1498Szrj 
278938fd1498Szrj       *dstp = src;
279038fd1498Szrj 
279138fd1498Szrj       /* Continue traversing the hash table.  */
279238fd1498Szrj       return 1;
279338fd1498Szrj     }
279438fd1498Szrj   else
279538fd1498Szrj     dst = *dstp;
279638fd1498Szrj 
279738fd1498Szrj   gcc_assert (src->n_var_parts);
279838fd1498Szrj   gcc_checking_assert (src->onepart == dst->onepart);
279938fd1498Szrj 
280038fd1498Szrj   /* We can combine one-part variables very efficiently, because their
280138fd1498Szrj      entries are in canonical order.  */
280238fd1498Szrj   if (src->onepart)
280338fd1498Szrj     {
280438fd1498Szrj       location_chain **nodep, *dnode, *snode;
280538fd1498Szrj 
280638fd1498Szrj       gcc_assert (src->n_var_parts == 1
280738fd1498Szrj 		  && dst->n_var_parts == 1);
280838fd1498Szrj 
280938fd1498Szrj       snode = src->var_part[0].loc_chain;
281038fd1498Szrj       gcc_assert (snode);
281138fd1498Szrj 
281238fd1498Szrj     restart_onepart_unshared:
281338fd1498Szrj       nodep = &dst->var_part[0].loc_chain;
281438fd1498Szrj       dnode = *nodep;
281538fd1498Szrj       gcc_assert (dnode);
281638fd1498Szrj 
281738fd1498Szrj       while (snode)
281838fd1498Szrj 	{
281938fd1498Szrj 	  int r = dnode ? loc_cmp (dnode->loc, snode->loc) : 1;
282038fd1498Szrj 
282138fd1498Szrj 	  if (r > 0)
282238fd1498Szrj 	    {
282338fd1498Szrj 	      location_chain *nnode;
282438fd1498Szrj 
282538fd1498Szrj 	      if (shared_var_p (dst, set->vars))
282638fd1498Szrj 		{
282738fd1498Szrj 		  dstp = unshare_variable (set, dstp, dst,
282838fd1498Szrj 					   VAR_INIT_STATUS_INITIALIZED);
282938fd1498Szrj 		  dst = *dstp;
283038fd1498Szrj 		  goto restart_onepart_unshared;
283138fd1498Szrj 		}
283238fd1498Szrj 
283338fd1498Szrj 	      *nodep = nnode = new location_chain;
283438fd1498Szrj 	      nnode->loc = snode->loc;
283538fd1498Szrj 	      nnode->init = snode->init;
283638fd1498Szrj 	      if (!snode->set_src || MEM_P (snode->set_src))
283738fd1498Szrj 		nnode->set_src = NULL;
283838fd1498Szrj 	      else
283938fd1498Szrj 		nnode->set_src = snode->set_src;
284038fd1498Szrj 	      nnode->next = dnode;
284138fd1498Szrj 	      dnode = nnode;
284238fd1498Szrj 	    }
284338fd1498Szrj 	  else if (r == 0)
284438fd1498Szrj 	    gcc_checking_assert (rtx_equal_p (dnode->loc, snode->loc));
284538fd1498Szrj 
284638fd1498Szrj 	  if (r >= 0)
284738fd1498Szrj 	    snode = snode->next;
284838fd1498Szrj 
284938fd1498Szrj 	  nodep = &dnode->next;
285038fd1498Szrj 	  dnode = *nodep;
285138fd1498Szrj 	}
285238fd1498Szrj 
285338fd1498Szrj       return 1;
285438fd1498Szrj     }
285538fd1498Szrj 
285638fd1498Szrj   gcc_checking_assert (!src->onepart);
285738fd1498Szrj 
285838fd1498Szrj   /* Count the number of location parts, result is K.  */
285938fd1498Szrj   for (i = 0, j = 0, k = 0;
286038fd1498Szrj        i < src->n_var_parts && j < dst->n_var_parts; k++)
286138fd1498Szrj     {
286238fd1498Szrj       if (VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j))
286338fd1498Szrj 	{
286438fd1498Szrj 	  i++;
286538fd1498Szrj 	  j++;
286638fd1498Szrj 	}
286738fd1498Szrj       else if (VAR_PART_OFFSET (src, i) < VAR_PART_OFFSET (dst, j))
286838fd1498Szrj 	i++;
286938fd1498Szrj       else
287038fd1498Szrj 	j++;
287138fd1498Szrj     }
287238fd1498Szrj   k += src->n_var_parts - i;
287338fd1498Szrj   k += dst->n_var_parts - j;
287438fd1498Szrj 
287538fd1498Szrj   /* We track only variables whose size is <= MAX_VAR_PARTS bytes
287638fd1498Szrj      thus there are at most MAX_VAR_PARTS different offsets.  */
287738fd1498Szrj   gcc_checking_assert (dst->onepart ? k == 1 : k <= MAX_VAR_PARTS);
287838fd1498Szrj 
287938fd1498Szrj   if (dst->n_var_parts != k && shared_var_p (dst, set->vars))
288038fd1498Szrj     {
288138fd1498Szrj       dstp = unshare_variable (set, dstp, dst, VAR_INIT_STATUS_UNKNOWN);
288238fd1498Szrj       dst = *dstp;
288338fd1498Szrj     }
288438fd1498Szrj 
288538fd1498Szrj   i = src->n_var_parts - 1;
288638fd1498Szrj   j = dst->n_var_parts - 1;
288738fd1498Szrj   dst->n_var_parts = k;
288838fd1498Szrj 
288938fd1498Szrj   for (k--; k >= 0; k--)
289038fd1498Szrj     {
289138fd1498Szrj       location_chain *node, *node2;
289238fd1498Szrj 
289338fd1498Szrj       if (i >= 0 && j >= 0
289438fd1498Szrj 	  && VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j))
289538fd1498Szrj 	{
289638fd1498Szrj 	  /* Compute the "sorted" union of the chains, i.e. the locations which
289738fd1498Szrj 	     are in both chains go first, they are sorted by the sum of
289838fd1498Szrj 	     positions in the chains.  */
289938fd1498Szrj 	  int dst_l, src_l;
290038fd1498Szrj 	  int ii, jj, n;
290138fd1498Szrj 	  struct variable_union_info *vui;
290238fd1498Szrj 
290338fd1498Szrj 	  /* If DST is shared compare the location chains.
290438fd1498Szrj 	     If they are different we will modify the chain in DST with
290538fd1498Szrj 	     high probability so make a copy of DST.  */
290638fd1498Szrj 	  if (shared_var_p (dst, set->vars))
290738fd1498Szrj 	    {
290838fd1498Szrj 	      for (node = src->var_part[i].loc_chain,
290938fd1498Szrj 		   node2 = dst->var_part[j].loc_chain; node && node2;
291038fd1498Szrj 		   node = node->next, node2 = node2->next)
291138fd1498Szrj 		{
291238fd1498Szrj 		  if (!((REG_P (node2->loc)
291338fd1498Szrj 			 && REG_P (node->loc)
291438fd1498Szrj 			 && REGNO (node2->loc) == REGNO (node->loc))
291538fd1498Szrj 			|| rtx_equal_p (node2->loc, node->loc)))
291638fd1498Szrj 		    {
291738fd1498Szrj 		      if (node2->init < node->init)
291838fd1498Szrj 		        node2->init = node->init;
291938fd1498Szrj 		      break;
292038fd1498Szrj 		    }
292138fd1498Szrj 		}
292238fd1498Szrj 	      if (node || node2)
292338fd1498Szrj 		{
292438fd1498Szrj 		  dstp = unshare_variable (set, dstp, dst,
292538fd1498Szrj 					   VAR_INIT_STATUS_UNKNOWN);
292638fd1498Szrj 		  dst = (variable *)*dstp;
292738fd1498Szrj 		}
292838fd1498Szrj 	    }
292938fd1498Szrj 
293038fd1498Szrj 	  src_l = 0;
293138fd1498Szrj 	  for (node = src->var_part[i].loc_chain; node; node = node->next)
293238fd1498Szrj 	    src_l++;
293338fd1498Szrj 	  dst_l = 0;
293438fd1498Szrj 	  for (node = dst->var_part[j].loc_chain; node; node = node->next)
293538fd1498Szrj 	    dst_l++;
293638fd1498Szrj 
293738fd1498Szrj 	  if (dst_l == 1)
293838fd1498Szrj 	    {
293938fd1498Szrj 	      /* The most common case, much simpler, no qsort is needed.  */
294038fd1498Szrj 	      location_chain *dstnode = dst->var_part[j].loc_chain;
294138fd1498Szrj 	      dst->var_part[k].loc_chain = dstnode;
294238fd1498Szrj 	      VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (dst, j);
294338fd1498Szrj 	      node2 = dstnode;
294438fd1498Szrj 	      for (node = src->var_part[i].loc_chain; node; node = node->next)
294538fd1498Szrj 		if (!((REG_P (dstnode->loc)
294638fd1498Szrj 		       && REG_P (node->loc)
294738fd1498Szrj 		       && REGNO (dstnode->loc) == REGNO (node->loc))
294838fd1498Szrj 		      || rtx_equal_p (dstnode->loc, node->loc)))
294938fd1498Szrj 		  {
295038fd1498Szrj 		    location_chain *new_node;
295138fd1498Szrj 
295238fd1498Szrj 		    /* Copy the location from SRC.  */
295338fd1498Szrj 		    new_node = new location_chain;
295438fd1498Szrj 		    new_node->loc = node->loc;
295538fd1498Szrj 		    new_node->init = node->init;
295638fd1498Szrj 		    if (!node->set_src || MEM_P (node->set_src))
295738fd1498Szrj 		      new_node->set_src = NULL;
295838fd1498Szrj 		    else
295938fd1498Szrj 		      new_node->set_src = node->set_src;
296038fd1498Szrj 		    node2->next = new_node;
296138fd1498Szrj 		    node2 = new_node;
296238fd1498Szrj 		  }
296338fd1498Szrj 	      node2->next = NULL;
296438fd1498Szrj 	    }
296538fd1498Szrj 	  else
296638fd1498Szrj 	    {
296738fd1498Szrj 	      if (src_l + dst_l > vui_allocated)
296838fd1498Szrj 		{
296938fd1498Szrj 		  vui_allocated = MAX (vui_allocated * 2, src_l + dst_l);
297038fd1498Szrj 		  vui_vec = XRESIZEVEC (struct variable_union_info, vui_vec,
297138fd1498Szrj 					vui_allocated);
297238fd1498Szrj 		}
297338fd1498Szrj 	      vui = vui_vec;
297438fd1498Szrj 
297538fd1498Szrj 	      /* Fill in the locations from DST.  */
297638fd1498Szrj 	      for (node = dst->var_part[j].loc_chain, jj = 0; node;
297738fd1498Szrj 		   node = node->next, jj++)
297838fd1498Szrj 		{
297938fd1498Szrj 		  vui[jj].lc = node;
298038fd1498Szrj 		  vui[jj].pos_dst = jj;
298138fd1498Szrj 
298238fd1498Szrj 		  /* Pos plus value larger than a sum of 2 valid positions.  */
298338fd1498Szrj 		  vui[jj].pos = jj + src_l + dst_l;
298438fd1498Szrj 		}
298538fd1498Szrj 
298638fd1498Szrj 	      /* Fill in the locations from SRC.  */
298738fd1498Szrj 	      n = dst_l;
298838fd1498Szrj 	      for (node = src->var_part[i].loc_chain, ii = 0; node;
298938fd1498Szrj 		   node = node->next, ii++)
299038fd1498Szrj 		{
299138fd1498Szrj 		  /* Find location from NODE.  */
299238fd1498Szrj 		  for (jj = 0; jj < dst_l; jj++)
299338fd1498Szrj 		    {
299438fd1498Szrj 		      if ((REG_P (vui[jj].lc->loc)
299538fd1498Szrj 			   && REG_P (node->loc)
299638fd1498Szrj 			   && REGNO (vui[jj].lc->loc) == REGNO (node->loc))
299738fd1498Szrj 			  || rtx_equal_p (vui[jj].lc->loc, node->loc))
299838fd1498Szrj 			{
299938fd1498Szrj 			  vui[jj].pos = jj + ii;
300038fd1498Szrj 			  break;
300138fd1498Szrj 			}
300238fd1498Szrj 		    }
300338fd1498Szrj 		  if (jj >= dst_l)	/* The location has not been found.  */
300438fd1498Szrj 		    {
300538fd1498Szrj 		      location_chain *new_node;
300638fd1498Szrj 
300738fd1498Szrj 		      /* Copy the location from SRC.  */
300838fd1498Szrj 		      new_node = new location_chain;
300938fd1498Szrj 		      new_node->loc = node->loc;
301038fd1498Szrj 		      new_node->init = node->init;
301138fd1498Szrj 		      if (!node->set_src || MEM_P (node->set_src))
301238fd1498Szrj 			new_node->set_src = NULL;
301338fd1498Szrj 		      else
301438fd1498Szrj 			new_node->set_src = node->set_src;
301538fd1498Szrj 		      vui[n].lc = new_node;
301638fd1498Szrj 		      vui[n].pos_dst = src_l + dst_l;
301738fd1498Szrj 		      vui[n].pos = ii + src_l + dst_l;
301838fd1498Szrj 		      n++;
301938fd1498Szrj 		    }
302038fd1498Szrj 		}
302138fd1498Szrj 
302238fd1498Szrj 	      if (dst_l == 2)
302338fd1498Szrj 		{
302438fd1498Szrj 		  /* Special case still very common case.  For dst_l == 2
302538fd1498Szrj 		     all entries dst_l ... n-1 are sorted, with for i >= dst_l
302638fd1498Szrj 		     vui[i].pos == i + src_l + dst_l.  */
302738fd1498Szrj 		  if (vui[0].pos > vui[1].pos)
302838fd1498Szrj 		    {
302938fd1498Szrj 		      /* Order should be 1, 0, 2... */
303038fd1498Szrj 		      dst->var_part[k].loc_chain = vui[1].lc;
303138fd1498Szrj 		      vui[1].lc->next = vui[0].lc;
303238fd1498Szrj 		      if (n >= 3)
303338fd1498Szrj 			{
303438fd1498Szrj 			  vui[0].lc->next = vui[2].lc;
303538fd1498Szrj 			  vui[n - 1].lc->next = NULL;
303638fd1498Szrj 			}
303738fd1498Szrj 		      else
303838fd1498Szrj 			vui[0].lc->next = NULL;
303938fd1498Szrj 		      ii = 3;
304038fd1498Szrj 		    }
304138fd1498Szrj 		  else
304238fd1498Szrj 		    {
304338fd1498Szrj 		      dst->var_part[k].loc_chain = vui[0].lc;
304438fd1498Szrj 		      if (n >= 3 && vui[2].pos < vui[1].pos)
304538fd1498Szrj 			{
304638fd1498Szrj 			  /* Order should be 0, 2, 1, 3... */
304738fd1498Szrj 			  vui[0].lc->next = vui[2].lc;
304838fd1498Szrj 			  vui[2].lc->next = vui[1].lc;
304938fd1498Szrj 			  if (n >= 4)
305038fd1498Szrj 			    {
305138fd1498Szrj 			      vui[1].lc->next = vui[3].lc;
305238fd1498Szrj 			      vui[n - 1].lc->next = NULL;
305338fd1498Szrj 			    }
305438fd1498Szrj 			  else
305538fd1498Szrj 			    vui[1].lc->next = NULL;
305638fd1498Szrj 			  ii = 4;
305738fd1498Szrj 			}
305838fd1498Szrj 		      else
305938fd1498Szrj 			{
306038fd1498Szrj 			  /* Order should be 0, 1, 2... */
306138fd1498Szrj 			  ii = 1;
306238fd1498Szrj 			  vui[n - 1].lc->next = NULL;
306338fd1498Szrj 			}
306438fd1498Szrj 		    }
306538fd1498Szrj 		  for (; ii < n; ii++)
306638fd1498Szrj 		    vui[ii - 1].lc->next = vui[ii].lc;
306738fd1498Szrj 		}
306838fd1498Szrj 	      else
306938fd1498Szrj 		{
307038fd1498Szrj 		  qsort (vui, n, sizeof (struct variable_union_info),
307138fd1498Szrj 			 variable_union_info_cmp_pos);
307238fd1498Szrj 
307338fd1498Szrj 		  /* Reconnect the nodes in sorted order.  */
307438fd1498Szrj 		  for (ii = 1; ii < n; ii++)
307538fd1498Szrj 		    vui[ii - 1].lc->next = vui[ii].lc;
307638fd1498Szrj 		  vui[n - 1].lc->next = NULL;
307738fd1498Szrj 		  dst->var_part[k].loc_chain = vui[0].lc;
307838fd1498Szrj 		}
307938fd1498Szrj 
308038fd1498Szrj 	      VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (dst, j);
308138fd1498Szrj 	    }
308238fd1498Szrj 	  i--;
308338fd1498Szrj 	  j--;
308438fd1498Szrj 	}
308538fd1498Szrj       else if ((i >= 0 && j >= 0
308638fd1498Szrj 		&& VAR_PART_OFFSET (src, i) < VAR_PART_OFFSET (dst, j))
308738fd1498Szrj 	       || i < 0)
308838fd1498Szrj 	{
308938fd1498Szrj 	  dst->var_part[k] = dst->var_part[j];
309038fd1498Szrj 	  j--;
309138fd1498Szrj 	}
309238fd1498Szrj       else if ((i >= 0 && j >= 0
309338fd1498Szrj 		&& VAR_PART_OFFSET (src, i) > VAR_PART_OFFSET (dst, j))
309438fd1498Szrj 	       || j < 0)
309538fd1498Szrj 	{
309638fd1498Szrj 	  location_chain **nextp;
309738fd1498Szrj 
309838fd1498Szrj 	  /* Copy the chain from SRC.  */
309938fd1498Szrj 	  nextp = &dst->var_part[k].loc_chain;
310038fd1498Szrj 	  for (node = src->var_part[i].loc_chain; node; node = node->next)
310138fd1498Szrj 	    {
310238fd1498Szrj 	      location_chain *new_lc;
310338fd1498Szrj 
310438fd1498Szrj 	      new_lc = new location_chain;
310538fd1498Szrj 	      new_lc->next = NULL;
310638fd1498Szrj 	      new_lc->init = node->init;
310738fd1498Szrj 	      if (!node->set_src || MEM_P (node->set_src))
310838fd1498Szrj 		new_lc->set_src = NULL;
310938fd1498Szrj 	      else
311038fd1498Szrj 		new_lc->set_src = node->set_src;
311138fd1498Szrj 	      new_lc->loc = node->loc;
311238fd1498Szrj 
311338fd1498Szrj 	      *nextp = new_lc;
311438fd1498Szrj 	      nextp = &new_lc->next;
311538fd1498Szrj 	    }
311638fd1498Szrj 
311738fd1498Szrj 	  VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (src, i);
311838fd1498Szrj 	  i--;
311938fd1498Szrj 	}
312038fd1498Szrj       dst->var_part[k].cur_loc = NULL;
312138fd1498Szrj     }
312238fd1498Szrj 
312338fd1498Szrj   if (flag_var_tracking_uninit)
312438fd1498Szrj     for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++)
312538fd1498Szrj       {
312638fd1498Szrj 	location_chain *node, *node2;
312738fd1498Szrj 	for (node = src->var_part[i].loc_chain; node; node = node->next)
312838fd1498Szrj 	  for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next)
312938fd1498Szrj 	    if (rtx_equal_p (node->loc, node2->loc))
313038fd1498Szrj 	      {
313138fd1498Szrj 		if (node->init > node2->init)
313238fd1498Szrj 		  node2->init = node->init;
313338fd1498Szrj 	      }
313438fd1498Szrj       }
313538fd1498Szrj 
313638fd1498Szrj   /* Continue traversing the hash table.  */
313738fd1498Szrj   return 1;
313838fd1498Szrj }
313938fd1498Szrj 
314038fd1498Szrj /* Compute union of dataflow sets SRC and DST and store it to DST.  */
314138fd1498Szrj 
314238fd1498Szrj static void
dataflow_set_union(dataflow_set * dst,dataflow_set * src)314338fd1498Szrj dataflow_set_union (dataflow_set *dst, dataflow_set *src)
314438fd1498Szrj {
314538fd1498Szrj   int i;
314638fd1498Szrj 
314738fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
314838fd1498Szrj     attrs_list_union (&dst->regs[i], src->regs[i]);
314938fd1498Szrj 
315038fd1498Szrj   if (dst->vars == empty_shared_hash)
315138fd1498Szrj     {
315238fd1498Szrj       shared_hash_destroy (dst->vars);
315338fd1498Szrj       dst->vars = shared_hash_copy (src->vars);
315438fd1498Szrj     }
315538fd1498Szrj   else
315638fd1498Szrj     {
315738fd1498Szrj       variable_iterator_type hi;
315838fd1498Szrj       variable *var;
315938fd1498Szrj 
316038fd1498Szrj       FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (src->vars),
316138fd1498Szrj 				   var, variable, hi)
316238fd1498Szrj 	variable_union (var, dst);
316338fd1498Szrj     }
316438fd1498Szrj }
316538fd1498Szrj 
316638fd1498Szrj /* Whether the value is currently being expanded.  */
316738fd1498Szrj #define VALUE_RECURSED_INTO(x) \
316838fd1498Szrj   (RTL_FLAG_CHECK2 ("VALUE_RECURSED_INTO", (x), VALUE, DEBUG_EXPR)->used)
316938fd1498Szrj 
317038fd1498Szrj /* Whether no expansion was found, saving useless lookups.
317138fd1498Szrj    It must only be set when VALUE_CHANGED is clear.  */
317238fd1498Szrj #define NO_LOC_P(x) \
317338fd1498Szrj   (RTL_FLAG_CHECK2 ("NO_LOC_P", (x), VALUE, DEBUG_EXPR)->return_val)
317438fd1498Szrj 
317538fd1498Szrj /* Whether cur_loc in the value needs to be (re)computed.  */
317638fd1498Szrj #define VALUE_CHANGED(x) \
317738fd1498Szrj   (RTL_FLAG_CHECK1 ("VALUE_CHANGED", (x), VALUE)->frame_related)
317838fd1498Szrj /* Whether cur_loc in the decl needs to be (re)computed.  */
317938fd1498Szrj #define DECL_CHANGED(x) TREE_VISITED (x)
318038fd1498Szrj 
318138fd1498Szrj /* Record (if NEWV) that DV needs to have its cur_loc recomputed.  For
318238fd1498Szrj    user DECLs, this means they're in changed_variables.  Values and
318338fd1498Szrj    debug exprs may be left with this flag set if no user variable
318438fd1498Szrj    requires them to be evaluated.  */
318538fd1498Szrj 
318638fd1498Szrj static inline void
set_dv_changed(decl_or_value dv,bool newv)318738fd1498Szrj set_dv_changed (decl_or_value dv, bool newv)
318838fd1498Szrj {
318938fd1498Szrj   switch (dv_onepart_p (dv))
319038fd1498Szrj     {
319138fd1498Szrj     case ONEPART_VALUE:
319238fd1498Szrj       if (newv)
319338fd1498Szrj 	NO_LOC_P (dv_as_value (dv)) = false;
319438fd1498Szrj       VALUE_CHANGED (dv_as_value (dv)) = newv;
319538fd1498Szrj       break;
319638fd1498Szrj 
319738fd1498Szrj     case ONEPART_DEXPR:
319838fd1498Szrj       if (newv)
319938fd1498Szrj 	NO_LOC_P (DECL_RTL_KNOWN_SET (dv_as_decl (dv))) = false;
320038fd1498Szrj       /* Fall through.  */
320138fd1498Szrj 
320238fd1498Szrj     default:
320338fd1498Szrj       DECL_CHANGED (dv_as_decl (dv)) = newv;
320438fd1498Szrj       break;
320538fd1498Szrj     }
320638fd1498Szrj }
320738fd1498Szrj 
320838fd1498Szrj /* Return true if DV needs to have its cur_loc recomputed.  */
320938fd1498Szrj 
321038fd1498Szrj static inline bool
dv_changed_p(decl_or_value dv)321138fd1498Szrj dv_changed_p (decl_or_value dv)
321238fd1498Szrj {
321338fd1498Szrj   return (dv_is_value_p (dv)
321438fd1498Szrj 	  ? VALUE_CHANGED (dv_as_value (dv))
321538fd1498Szrj 	  : DECL_CHANGED (dv_as_decl (dv)));
321638fd1498Szrj }
321738fd1498Szrj 
321838fd1498Szrj /* Return a location list node whose loc is rtx_equal to LOC, in the
321938fd1498Szrj    location list of a one-part variable or value VAR, or in that of
322038fd1498Szrj    any values recursively mentioned in the location lists.  VARS must
322138fd1498Szrj    be in star-canonical form.  */
322238fd1498Szrj 
322338fd1498Szrj static location_chain *
find_loc_in_1pdv(rtx loc,variable * var,variable_table_type * vars)322438fd1498Szrj find_loc_in_1pdv (rtx loc, variable *var, variable_table_type *vars)
322538fd1498Szrj {
322638fd1498Szrj   location_chain *node;
322738fd1498Szrj   enum rtx_code loc_code;
322838fd1498Szrj 
322938fd1498Szrj   if (!var)
323038fd1498Szrj     return NULL;
323138fd1498Szrj 
323238fd1498Szrj   gcc_checking_assert (var->onepart);
323338fd1498Szrj 
323438fd1498Szrj   if (!var->n_var_parts)
323538fd1498Szrj     return NULL;
323638fd1498Szrj 
323738fd1498Szrj   gcc_checking_assert (loc != dv_as_opaque (var->dv));
323838fd1498Szrj 
323938fd1498Szrj   loc_code = GET_CODE (loc);
324038fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
324138fd1498Szrj     {
324238fd1498Szrj       decl_or_value dv;
324338fd1498Szrj       variable *rvar;
324438fd1498Szrj 
324538fd1498Szrj       if (GET_CODE (node->loc) != loc_code)
324638fd1498Szrj 	{
324738fd1498Szrj 	  if (GET_CODE (node->loc) != VALUE)
324838fd1498Szrj 	    continue;
324938fd1498Szrj 	}
325038fd1498Szrj       else if (loc == node->loc)
325138fd1498Szrj 	return node;
325238fd1498Szrj       else if (loc_code != VALUE)
325338fd1498Szrj 	{
325438fd1498Szrj 	  if (rtx_equal_p (loc, node->loc))
325538fd1498Szrj 	    return node;
325638fd1498Szrj 	  continue;
325738fd1498Szrj 	}
325838fd1498Szrj 
325938fd1498Szrj       /* Since we're in star-canonical form, we don't need to visit
326038fd1498Szrj 	 non-canonical nodes: one-part variables and non-canonical
326138fd1498Szrj 	 values would only point back to the canonical node.  */
326238fd1498Szrj       if (dv_is_value_p (var->dv)
326338fd1498Szrj 	  && !canon_value_cmp (node->loc, dv_as_value (var->dv)))
326438fd1498Szrj 	{
326538fd1498Szrj 	  /* Skip all subsequent VALUEs.  */
326638fd1498Szrj 	  while (node->next && GET_CODE (node->next->loc) == VALUE)
326738fd1498Szrj 	    {
326838fd1498Szrj 	      node = node->next;
326938fd1498Szrj 	      gcc_checking_assert (!canon_value_cmp (node->loc,
327038fd1498Szrj 						     dv_as_value (var->dv)));
327138fd1498Szrj 	      if (loc == node->loc)
327238fd1498Szrj 		return node;
327338fd1498Szrj 	    }
327438fd1498Szrj 	  continue;
327538fd1498Szrj 	}
327638fd1498Szrj 
327738fd1498Szrj       gcc_checking_assert (node == var->var_part[0].loc_chain);
327838fd1498Szrj       gcc_checking_assert (!node->next);
327938fd1498Szrj 
328038fd1498Szrj       dv = dv_from_value (node->loc);
328138fd1498Szrj       rvar = vars->find_with_hash (dv, dv_htab_hash (dv));
328238fd1498Szrj       return find_loc_in_1pdv (loc, rvar, vars);
328338fd1498Szrj     }
328438fd1498Szrj 
328538fd1498Szrj   /* ??? Gotta look in cselib_val locations too.  */
328638fd1498Szrj 
328738fd1498Szrj   return NULL;
328838fd1498Szrj }
328938fd1498Szrj 
329038fd1498Szrj /* Hash table iteration argument passed to variable_merge.  */
329138fd1498Szrj struct dfset_merge
329238fd1498Szrj {
329338fd1498Szrj   /* The set in which the merge is to be inserted.  */
329438fd1498Szrj   dataflow_set *dst;
329538fd1498Szrj   /* The set that we're iterating in.  */
329638fd1498Szrj   dataflow_set *cur;
329738fd1498Szrj   /* The set that may contain the other dv we are to merge with.  */
329838fd1498Szrj   dataflow_set *src;
329938fd1498Szrj   /* Number of onepart dvs in src.  */
330038fd1498Szrj   int src_onepart_cnt;
330138fd1498Szrj };
330238fd1498Szrj 
330338fd1498Szrj /* Insert LOC in *DNODE, if it's not there yet.  The list must be in
330438fd1498Szrj    loc_cmp order, and it is maintained as such.  */
330538fd1498Szrj 
330638fd1498Szrj static void
insert_into_intersection(location_chain ** nodep,rtx loc,enum var_init_status status)330738fd1498Szrj insert_into_intersection (location_chain **nodep, rtx loc,
330838fd1498Szrj 			  enum var_init_status status)
330938fd1498Szrj {
331038fd1498Szrj   location_chain *node;
331138fd1498Szrj   int r;
331238fd1498Szrj 
331338fd1498Szrj   for (node = *nodep; node; nodep = &node->next, node = *nodep)
331438fd1498Szrj     if ((r = loc_cmp (node->loc, loc)) == 0)
331538fd1498Szrj       {
331638fd1498Szrj 	node->init = MIN (node->init, status);
331738fd1498Szrj 	return;
331838fd1498Szrj       }
331938fd1498Szrj     else if (r > 0)
332038fd1498Szrj       break;
332138fd1498Szrj 
332238fd1498Szrj   node = new location_chain;
332338fd1498Szrj 
332438fd1498Szrj   node->loc = loc;
332538fd1498Szrj   node->set_src = NULL;
332638fd1498Szrj   node->init = status;
332738fd1498Szrj   node->next = *nodep;
332838fd1498Szrj   *nodep = node;
332938fd1498Szrj }
333038fd1498Szrj 
333138fd1498Szrj /* Insert in DEST the intersection of the locations present in both
333238fd1498Szrj    S1NODE and S2VAR, directly or indirectly.  S1NODE is from a
333338fd1498Szrj    variable in DSM->cur, whereas S2VAR is from DSM->src.  dvar is in
333438fd1498Szrj    DSM->dst.  */
333538fd1498Szrj 
333638fd1498Szrj static void
intersect_loc_chains(rtx val,location_chain ** dest,struct dfset_merge * dsm,location_chain * s1node,variable * s2var)333738fd1498Szrj intersect_loc_chains (rtx val, location_chain **dest, struct dfset_merge *dsm,
333838fd1498Szrj 		      location_chain *s1node, variable *s2var)
333938fd1498Szrj {
334038fd1498Szrj   dataflow_set *s1set = dsm->cur;
334138fd1498Szrj   dataflow_set *s2set = dsm->src;
334238fd1498Szrj   location_chain *found;
334338fd1498Szrj 
334438fd1498Szrj   if (s2var)
334538fd1498Szrj     {
334638fd1498Szrj       location_chain *s2node;
334738fd1498Szrj 
334838fd1498Szrj       gcc_checking_assert (s2var->onepart);
334938fd1498Szrj 
335038fd1498Szrj       if (s2var->n_var_parts)
335138fd1498Szrj 	{
335238fd1498Szrj 	  s2node = s2var->var_part[0].loc_chain;
335338fd1498Szrj 
335438fd1498Szrj 	  for (; s1node && s2node;
335538fd1498Szrj 	       s1node = s1node->next, s2node = s2node->next)
335638fd1498Szrj 	    if (s1node->loc != s2node->loc)
335738fd1498Szrj 	      break;
335838fd1498Szrj 	    else if (s1node->loc == val)
335938fd1498Szrj 	      continue;
336038fd1498Szrj 	    else
336138fd1498Szrj 	      insert_into_intersection (dest, s1node->loc,
336238fd1498Szrj 					MIN (s1node->init, s2node->init));
336338fd1498Szrj 	}
336438fd1498Szrj     }
336538fd1498Szrj 
336638fd1498Szrj   for (; s1node; s1node = s1node->next)
336738fd1498Szrj     {
336838fd1498Szrj       if (s1node->loc == val)
336938fd1498Szrj 	continue;
337038fd1498Szrj 
337138fd1498Szrj       if ((found = find_loc_in_1pdv (s1node->loc, s2var,
337238fd1498Szrj 				     shared_hash_htab (s2set->vars))))
337338fd1498Szrj 	{
337438fd1498Szrj 	  insert_into_intersection (dest, s1node->loc,
337538fd1498Szrj 				    MIN (s1node->init, found->init));
337638fd1498Szrj 	  continue;
337738fd1498Szrj 	}
337838fd1498Szrj 
337938fd1498Szrj       if (GET_CODE (s1node->loc) == VALUE
338038fd1498Szrj 	  && !VALUE_RECURSED_INTO (s1node->loc))
338138fd1498Szrj 	{
338238fd1498Szrj 	  decl_or_value dv = dv_from_value (s1node->loc);
338338fd1498Szrj 	  variable *svar = shared_hash_find (s1set->vars, dv);
338438fd1498Szrj 	  if (svar)
338538fd1498Szrj 	    {
338638fd1498Szrj 	      if (svar->n_var_parts == 1)
338738fd1498Szrj 		{
338838fd1498Szrj 		  VALUE_RECURSED_INTO (s1node->loc) = true;
338938fd1498Szrj 		  intersect_loc_chains (val, dest, dsm,
339038fd1498Szrj 					svar->var_part[0].loc_chain,
339138fd1498Szrj 					s2var);
339238fd1498Szrj 		  VALUE_RECURSED_INTO (s1node->loc) = false;
339338fd1498Szrj 		}
339438fd1498Szrj 	    }
339538fd1498Szrj 	}
339638fd1498Szrj 
339738fd1498Szrj       /* ??? gotta look in cselib_val locations too.  */
339838fd1498Szrj 
339938fd1498Szrj       /* ??? if the location is equivalent to any location in src,
340038fd1498Szrj 	 searched recursively
340138fd1498Szrj 
340238fd1498Szrj 	   add to dst the values needed to represent the equivalence
340338fd1498Szrj 
340438fd1498Szrj      telling whether locations S is equivalent to another dv's
340538fd1498Szrj      location list:
340638fd1498Szrj 
340738fd1498Szrj        for each location D in the list
340838fd1498Szrj 
340938fd1498Szrj          if S and D satisfy rtx_equal_p, then it is present
341038fd1498Szrj 
341138fd1498Szrj 	 else if D is a value, recurse without cycles
341238fd1498Szrj 
341338fd1498Szrj 	 else if S and D have the same CODE and MODE
341438fd1498Szrj 
341538fd1498Szrj 	   for each operand oS and the corresponding oD
341638fd1498Szrj 
341738fd1498Szrj 	     if oS and oD are not equivalent, then S an D are not equivalent
341838fd1498Szrj 
341938fd1498Szrj 	     else if they are RTX vectors
342038fd1498Szrj 
342138fd1498Szrj 	       if any vector oS element is not equivalent to its respective oD,
342238fd1498Szrj 	       then S and D are not equivalent
342338fd1498Szrj 
342438fd1498Szrj    */
342538fd1498Szrj 
342638fd1498Szrj 
342738fd1498Szrj     }
342838fd1498Szrj }
342938fd1498Szrj 
343038fd1498Szrj /* Return -1 if X should be before Y in a location list for a 1-part
343138fd1498Szrj    variable, 1 if Y should be before X, and 0 if they're equivalent
343238fd1498Szrj    and should not appear in the list.  */
343338fd1498Szrj 
343438fd1498Szrj static int
loc_cmp(rtx x,rtx y)343538fd1498Szrj loc_cmp (rtx x, rtx y)
343638fd1498Szrj {
343738fd1498Szrj   int i, j, r;
343838fd1498Szrj   RTX_CODE code = GET_CODE (x);
343938fd1498Szrj   const char *fmt;
344038fd1498Szrj 
344138fd1498Szrj   if (x == y)
344238fd1498Szrj     return 0;
344338fd1498Szrj 
344438fd1498Szrj   if (REG_P (x))
344538fd1498Szrj     {
344638fd1498Szrj       if (!REG_P (y))
344738fd1498Szrj 	return -1;
344838fd1498Szrj       gcc_assert (GET_MODE (x) == GET_MODE (y));
344938fd1498Szrj       if (REGNO (x) == REGNO (y))
345038fd1498Szrj 	return 0;
345138fd1498Szrj       else if (REGNO (x) < REGNO (y))
345238fd1498Szrj 	return -1;
345338fd1498Szrj       else
345438fd1498Szrj 	return 1;
345538fd1498Szrj     }
345638fd1498Szrj 
345738fd1498Szrj   if (REG_P (y))
345838fd1498Szrj     return 1;
345938fd1498Szrj 
346038fd1498Szrj   if (MEM_P (x))
346138fd1498Szrj     {
346238fd1498Szrj       if (!MEM_P (y))
346338fd1498Szrj 	return -1;
346438fd1498Szrj       gcc_assert (GET_MODE (x) == GET_MODE (y));
346538fd1498Szrj       return loc_cmp (XEXP (x, 0), XEXP (y, 0));
346638fd1498Szrj     }
346738fd1498Szrj 
346838fd1498Szrj   if (MEM_P (y))
346938fd1498Szrj     return 1;
347038fd1498Szrj 
347138fd1498Szrj   if (GET_CODE (x) == VALUE)
347238fd1498Szrj     {
347338fd1498Szrj       if (GET_CODE (y) != VALUE)
347438fd1498Szrj 	return -1;
347538fd1498Szrj       /* Don't assert the modes are the same, that is true only
347638fd1498Szrj 	 when not recursing.  (subreg:QI (value:SI 1:1) 0)
347738fd1498Szrj 	 and (subreg:QI (value:DI 2:2) 0) can be compared,
347838fd1498Szrj 	 even when the modes are different.  */
347938fd1498Szrj       if (canon_value_cmp (x, y))
348038fd1498Szrj 	return -1;
348138fd1498Szrj       else
348238fd1498Szrj 	return 1;
348338fd1498Szrj     }
348438fd1498Szrj 
348538fd1498Szrj   if (GET_CODE (y) == VALUE)
348638fd1498Szrj     return 1;
348738fd1498Szrj 
348838fd1498Szrj   /* Entry value is the least preferable kind of expression.  */
348938fd1498Szrj   if (GET_CODE (x) == ENTRY_VALUE)
349038fd1498Szrj     {
349138fd1498Szrj       if (GET_CODE (y) != ENTRY_VALUE)
349238fd1498Szrj 	return 1;
349338fd1498Szrj       gcc_assert (GET_MODE (x) == GET_MODE (y));
349438fd1498Szrj       return loc_cmp (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y));
349538fd1498Szrj     }
349638fd1498Szrj 
349738fd1498Szrj   if (GET_CODE (y) == ENTRY_VALUE)
349838fd1498Szrj     return -1;
349938fd1498Szrj 
350038fd1498Szrj   if (GET_CODE (x) == GET_CODE (y))
350138fd1498Szrj     /* Compare operands below.  */;
350238fd1498Szrj   else if (GET_CODE (x) < GET_CODE (y))
350338fd1498Szrj     return -1;
350438fd1498Szrj   else
350538fd1498Szrj     return 1;
350638fd1498Szrj 
350738fd1498Szrj   gcc_assert (GET_MODE (x) == GET_MODE (y));
350838fd1498Szrj 
350938fd1498Szrj   if (GET_CODE (x) == DEBUG_EXPR)
351038fd1498Szrj     {
351138fd1498Szrj       if (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
351238fd1498Szrj 	  < DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)))
351338fd1498Szrj 	return -1;
351438fd1498Szrj       gcc_checking_assert (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
351538fd1498Szrj 			   > DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)));
351638fd1498Szrj       return 1;
351738fd1498Szrj     }
351838fd1498Szrj 
351938fd1498Szrj   fmt = GET_RTX_FORMAT (code);
352038fd1498Szrj   for (i = 0; i < GET_RTX_LENGTH (code); i++)
352138fd1498Szrj     switch (fmt[i])
352238fd1498Szrj       {
352338fd1498Szrj       case 'w':
352438fd1498Szrj 	if (XWINT (x, i) == XWINT (y, i))
352538fd1498Szrj 	  break;
352638fd1498Szrj 	else if (XWINT (x, i) < XWINT (y, i))
352738fd1498Szrj 	  return -1;
352838fd1498Szrj 	else
352938fd1498Szrj 	  return 1;
353038fd1498Szrj 
353138fd1498Szrj       case 'n':
353238fd1498Szrj       case 'i':
353338fd1498Szrj 	if (XINT (x, i) == XINT (y, i))
353438fd1498Szrj 	  break;
353538fd1498Szrj 	else if (XINT (x, i) < XINT (y, i))
353638fd1498Szrj 	  return -1;
353738fd1498Szrj 	else
353838fd1498Szrj 	  return 1;
353938fd1498Szrj 
354038fd1498Szrj       case 'p':
354138fd1498Szrj 	r = compare_sizes_for_sort (SUBREG_BYTE (x), SUBREG_BYTE (y));
354238fd1498Szrj 	if (r != 0)
354338fd1498Szrj 	  return r;
354438fd1498Szrj 	break;
354538fd1498Szrj 
354638fd1498Szrj       case 'V':
354738fd1498Szrj       case 'E':
354838fd1498Szrj 	/* Compare the vector length first.  */
354938fd1498Szrj 	if (XVECLEN (x, i) == XVECLEN (y, i))
355038fd1498Szrj 	  /* Compare the vectors elements.  */;
355138fd1498Szrj 	else if (XVECLEN (x, i) < XVECLEN (y, i))
355238fd1498Szrj 	  return -1;
355338fd1498Szrj 	else
355438fd1498Szrj 	  return 1;
355538fd1498Szrj 
355638fd1498Szrj 	for (j = 0; j < XVECLEN (x, i); j++)
355738fd1498Szrj 	  if ((r = loc_cmp (XVECEXP (x, i, j),
355838fd1498Szrj 			    XVECEXP (y, i, j))))
355938fd1498Szrj 	    return r;
356038fd1498Szrj 	break;
356138fd1498Szrj 
356238fd1498Szrj       case 'e':
356338fd1498Szrj 	if ((r = loc_cmp (XEXP (x, i), XEXP (y, i))))
356438fd1498Szrj 	  return r;
356538fd1498Szrj 	break;
356638fd1498Szrj 
356738fd1498Szrj       case 'S':
356838fd1498Szrj       case 's':
356938fd1498Szrj 	if (XSTR (x, i) == XSTR (y, i))
357038fd1498Szrj 	  break;
357138fd1498Szrj 	if (!XSTR (x, i))
357238fd1498Szrj 	  return -1;
357338fd1498Szrj 	if (!XSTR (y, i))
357438fd1498Szrj 	  return 1;
357538fd1498Szrj 	if ((r = strcmp (XSTR (x, i), XSTR (y, i))) == 0)
357638fd1498Szrj 	  break;
357738fd1498Szrj 	else if (r < 0)
357838fd1498Szrj 	  return -1;
357938fd1498Szrj 	else
358038fd1498Szrj 	  return 1;
358138fd1498Szrj 
358238fd1498Szrj       case 'u':
358338fd1498Szrj 	/* These are just backpointers, so they don't matter.  */
358438fd1498Szrj 	break;
358538fd1498Szrj 
358638fd1498Szrj       case '0':
358738fd1498Szrj       case 't':
358838fd1498Szrj 	break;
358938fd1498Szrj 
359038fd1498Szrj 	/* It is believed that rtx's at this level will never
359138fd1498Szrj 	   contain anything but integers and other rtx's,
359238fd1498Szrj 	   except for within LABEL_REFs and SYMBOL_REFs.  */
359338fd1498Szrj       default:
359438fd1498Szrj 	gcc_unreachable ();
359538fd1498Szrj       }
359638fd1498Szrj   if (CONST_WIDE_INT_P (x))
359738fd1498Szrj     {
359838fd1498Szrj       /* Compare the vector length first.  */
359938fd1498Szrj       if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
360038fd1498Szrj 	return 1;
360138fd1498Szrj       else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
360238fd1498Szrj 	return -1;
360338fd1498Szrj 
360438fd1498Szrj       /* Compare the vectors elements.  */;
360538fd1498Szrj       for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
360638fd1498Szrj 	{
360738fd1498Szrj 	  if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
360838fd1498Szrj 	    return -1;
360938fd1498Szrj 	  if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
361038fd1498Szrj 	    return 1;
361138fd1498Szrj 	}
361238fd1498Szrj     }
361338fd1498Szrj 
361438fd1498Szrj   return 0;
361538fd1498Szrj }
361638fd1498Szrj 
361738fd1498Szrj /* Check the order of entries in one-part variables.   */
361838fd1498Szrj 
361938fd1498Szrj int
canonicalize_loc_order_check(variable ** slot,dataflow_set * data ATTRIBUTE_UNUSED)362038fd1498Szrj canonicalize_loc_order_check (variable **slot,
362138fd1498Szrj 			      dataflow_set *data ATTRIBUTE_UNUSED)
362238fd1498Szrj {
362338fd1498Szrj   variable *var = *slot;
362438fd1498Szrj   location_chain *node, *next;
362538fd1498Szrj 
362638fd1498Szrj #ifdef ENABLE_RTL_CHECKING
362738fd1498Szrj   int i;
362838fd1498Szrj   for (i = 0; i < var->n_var_parts; i++)
362938fd1498Szrj     gcc_assert (var->var_part[0].cur_loc == NULL);
363038fd1498Szrj   gcc_assert (!var->in_changed_variables);
363138fd1498Szrj #endif
363238fd1498Szrj 
363338fd1498Szrj   if (!var->onepart)
363438fd1498Szrj     return 1;
363538fd1498Szrj 
363638fd1498Szrj   gcc_assert (var->n_var_parts == 1);
363738fd1498Szrj   node = var->var_part[0].loc_chain;
363838fd1498Szrj   gcc_assert (node);
363938fd1498Szrj 
364038fd1498Szrj   while ((next = node->next))
364138fd1498Szrj     {
364238fd1498Szrj       gcc_assert (loc_cmp (node->loc, next->loc) < 0);
364338fd1498Szrj       node = next;
364438fd1498Szrj     }
364538fd1498Szrj 
364638fd1498Szrj   return 1;
364738fd1498Szrj }
364838fd1498Szrj 
364938fd1498Szrj /* Mark with VALUE_RECURSED_INTO values that have neighbors that are
365038fd1498Szrj    more likely to be chosen as canonical for an equivalence set.
365138fd1498Szrj    Ensure less likely values can reach more likely neighbors, making
365238fd1498Szrj    the connections bidirectional.  */
365338fd1498Szrj 
365438fd1498Szrj int
canonicalize_values_mark(variable ** slot,dataflow_set * set)365538fd1498Szrj canonicalize_values_mark (variable **slot, dataflow_set *set)
365638fd1498Szrj {
365738fd1498Szrj   variable *var = *slot;
365838fd1498Szrj   decl_or_value dv = var->dv;
365938fd1498Szrj   rtx val;
366038fd1498Szrj   location_chain *node;
366138fd1498Szrj 
366238fd1498Szrj   if (!dv_is_value_p (dv))
366338fd1498Szrj     return 1;
366438fd1498Szrj 
366538fd1498Szrj   gcc_checking_assert (var->n_var_parts == 1);
366638fd1498Szrj 
366738fd1498Szrj   val = dv_as_value (dv);
366838fd1498Szrj 
366938fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
367038fd1498Szrj     if (GET_CODE (node->loc) == VALUE)
367138fd1498Szrj       {
367238fd1498Szrj 	if (canon_value_cmp (node->loc, val))
367338fd1498Szrj 	  VALUE_RECURSED_INTO (val) = true;
367438fd1498Szrj 	else
367538fd1498Szrj 	  {
367638fd1498Szrj 	    decl_or_value odv = dv_from_value (node->loc);
367738fd1498Szrj 	    variable **oslot;
367838fd1498Szrj 	    oslot = shared_hash_find_slot_noinsert (set->vars, odv);
367938fd1498Szrj 
368038fd1498Szrj 	    set_slot_part (set, val, oslot, odv, 0,
368138fd1498Szrj 			   node->init, NULL_RTX);
368238fd1498Szrj 
368338fd1498Szrj 	    VALUE_RECURSED_INTO (node->loc) = true;
368438fd1498Szrj 	  }
368538fd1498Szrj       }
368638fd1498Szrj 
368738fd1498Szrj   return 1;
368838fd1498Szrj }
368938fd1498Szrj 
369038fd1498Szrj /* Remove redundant entries from equivalence lists in onepart
369138fd1498Szrj    variables, canonicalizing equivalence sets into star shapes.  */
369238fd1498Szrj 
369338fd1498Szrj int
canonicalize_values_star(variable ** slot,dataflow_set * set)369438fd1498Szrj canonicalize_values_star (variable **slot, dataflow_set *set)
369538fd1498Szrj {
369638fd1498Szrj   variable *var = *slot;
369738fd1498Szrj   decl_or_value dv = var->dv;
369838fd1498Szrj   location_chain *node;
369938fd1498Szrj   decl_or_value cdv;
370038fd1498Szrj   rtx val, cval;
370138fd1498Szrj   variable **cslot;
370238fd1498Szrj   bool has_value;
370338fd1498Szrj   bool has_marks;
370438fd1498Szrj 
370538fd1498Szrj   if (!var->onepart)
370638fd1498Szrj     return 1;
370738fd1498Szrj 
370838fd1498Szrj   gcc_checking_assert (var->n_var_parts == 1);
370938fd1498Szrj 
371038fd1498Szrj   if (dv_is_value_p (dv))
371138fd1498Szrj     {
371238fd1498Szrj       cval = dv_as_value (dv);
371338fd1498Szrj       if (!VALUE_RECURSED_INTO (cval))
371438fd1498Szrj 	return 1;
371538fd1498Szrj       VALUE_RECURSED_INTO (cval) = false;
371638fd1498Szrj     }
371738fd1498Szrj   else
371838fd1498Szrj     cval = NULL_RTX;
371938fd1498Szrj 
372038fd1498Szrj  restart:
372138fd1498Szrj   val = cval;
372238fd1498Szrj   has_value = false;
372338fd1498Szrj   has_marks = false;
372438fd1498Szrj 
372538fd1498Szrj   gcc_assert (var->n_var_parts == 1);
372638fd1498Szrj 
372738fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
372838fd1498Szrj     if (GET_CODE (node->loc) == VALUE)
372938fd1498Szrj       {
373038fd1498Szrj 	has_value = true;
373138fd1498Szrj 	if (VALUE_RECURSED_INTO (node->loc))
373238fd1498Szrj 	  has_marks = true;
373338fd1498Szrj 	if (canon_value_cmp (node->loc, cval))
373438fd1498Szrj 	  cval = node->loc;
373538fd1498Szrj       }
373638fd1498Szrj 
373738fd1498Szrj   if (!has_value)
373838fd1498Szrj     return 1;
373938fd1498Szrj 
374038fd1498Szrj   if (cval == val)
374138fd1498Szrj     {
374238fd1498Szrj       if (!has_marks || dv_is_decl_p (dv))
374338fd1498Szrj 	return 1;
374438fd1498Szrj 
374538fd1498Szrj       /* Keep it marked so that we revisit it, either after visiting a
374638fd1498Szrj 	 child node, or after visiting a new parent that might be
374738fd1498Szrj 	 found out.  */
374838fd1498Szrj       VALUE_RECURSED_INTO (val) = true;
374938fd1498Szrj 
375038fd1498Szrj       for (node = var->var_part[0].loc_chain; node; node = node->next)
375138fd1498Szrj 	if (GET_CODE (node->loc) == VALUE
375238fd1498Szrj 	    && VALUE_RECURSED_INTO (node->loc))
375338fd1498Szrj 	  {
375438fd1498Szrj 	    cval = node->loc;
375538fd1498Szrj 	  restart_with_cval:
375638fd1498Szrj 	    VALUE_RECURSED_INTO (cval) = false;
375738fd1498Szrj 	    dv = dv_from_value (cval);
375838fd1498Szrj 	    slot = shared_hash_find_slot_noinsert (set->vars, dv);
375938fd1498Szrj 	    if (!slot)
376038fd1498Szrj 	      {
376138fd1498Szrj 		gcc_assert (dv_is_decl_p (var->dv));
376238fd1498Szrj 		/* The canonical value was reset and dropped.
376338fd1498Szrj 		   Remove it.  */
376438fd1498Szrj 		clobber_variable_part (set, NULL, var->dv, 0, NULL);
376538fd1498Szrj 		return 1;
376638fd1498Szrj 	      }
376738fd1498Szrj 	    var = *slot;
376838fd1498Szrj 	    gcc_assert (dv_is_value_p (var->dv));
376938fd1498Szrj 	    if (var->n_var_parts == 0)
377038fd1498Szrj 	      return 1;
377138fd1498Szrj 	    gcc_assert (var->n_var_parts == 1);
377238fd1498Szrj 	    goto restart;
377338fd1498Szrj 	  }
377438fd1498Szrj 
377538fd1498Szrj       VALUE_RECURSED_INTO (val) = false;
377638fd1498Szrj 
377738fd1498Szrj       return 1;
377838fd1498Szrj     }
377938fd1498Szrj 
378038fd1498Szrj   /* Push values to the canonical one.  */
378138fd1498Szrj   cdv = dv_from_value (cval);
378238fd1498Szrj   cslot = shared_hash_find_slot_noinsert (set->vars, cdv);
378338fd1498Szrj 
378438fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
378538fd1498Szrj     if (node->loc != cval)
378638fd1498Szrj       {
378738fd1498Szrj 	cslot = set_slot_part (set, node->loc, cslot, cdv, 0,
378838fd1498Szrj 			       node->init, NULL_RTX);
378938fd1498Szrj 	if (GET_CODE (node->loc) == VALUE)
379038fd1498Szrj 	  {
379138fd1498Szrj 	    decl_or_value ndv = dv_from_value (node->loc);
379238fd1498Szrj 
379338fd1498Szrj 	    set_variable_part (set, cval, ndv, 0, node->init, NULL_RTX,
379438fd1498Szrj 			       NO_INSERT);
379538fd1498Szrj 
379638fd1498Szrj 	    if (canon_value_cmp (node->loc, val))
379738fd1498Szrj 	      {
379838fd1498Szrj 		/* If it could have been a local minimum, it's not any more,
379938fd1498Szrj 		   since it's now neighbor to cval, so it may have to push
380038fd1498Szrj 		   to it.  Conversely, if it wouldn't have prevailed over
380138fd1498Szrj 		   val, then whatever mark it has is fine: if it was to
380238fd1498Szrj 		   push, it will now push to a more canonical node, but if
380338fd1498Szrj 		   it wasn't, then it has already pushed any values it might
380438fd1498Szrj 		   have to.  */
380538fd1498Szrj 		VALUE_RECURSED_INTO (node->loc) = true;
380638fd1498Szrj 		/* Make sure we visit node->loc by ensuring we cval is
380738fd1498Szrj 		   visited too.  */
380838fd1498Szrj 		VALUE_RECURSED_INTO (cval) = true;
380938fd1498Szrj 	      }
381038fd1498Szrj 	    else if (!VALUE_RECURSED_INTO (node->loc))
381138fd1498Szrj 	      /* If we have no need to "recurse" into this node, it's
381238fd1498Szrj 		 already "canonicalized", so drop the link to the old
381338fd1498Szrj 		 parent.  */
381438fd1498Szrj 	      clobber_variable_part (set, cval, ndv, 0, NULL);
381538fd1498Szrj 	  }
381638fd1498Szrj 	else if (GET_CODE (node->loc) == REG)
381738fd1498Szrj 	  {
381838fd1498Szrj 	    attrs *list = set->regs[REGNO (node->loc)], **listp;
381938fd1498Szrj 
382038fd1498Szrj 	    /* Change an existing attribute referring to dv so that it
382138fd1498Szrj 	       refers to cdv, removing any duplicate this might
382238fd1498Szrj 	       introduce, and checking that no previous duplicates
382338fd1498Szrj 	       existed, all in a single pass.  */
382438fd1498Szrj 
382538fd1498Szrj 	    while (list)
382638fd1498Szrj 	      {
382738fd1498Szrj 		if (list->offset == 0
382838fd1498Szrj 		    && (dv_as_opaque (list->dv) == dv_as_opaque (dv)
382938fd1498Szrj 			|| dv_as_opaque (list->dv) == dv_as_opaque (cdv)))
383038fd1498Szrj 		  break;
383138fd1498Szrj 
383238fd1498Szrj 		list = list->next;
383338fd1498Szrj 	      }
383438fd1498Szrj 
383538fd1498Szrj 	    gcc_assert (list);
383638fd1498Szrj 	    if (dv_as_opaque (list->dv) == dv_as_opaque (dv))
383738fd1498Szrj 	      {
383838fd1498Szrj 		list->dv = cdv;
383938fd1498Szrj 		for (listp = &list->next; (list = *listp); listp = &list->next)
384038fd1498Szrj 		  {
384138fd1498Szrj 		    if (list->offset)
384238fd1498Szrj 		      continue;
384338fd1498Szrj 
384438fd1498Szrj 		    if (dv_as_opaque (list->dv) == dv_as_opaque (cdv))
384538fd1498Szrj 		      {
384638fd1498Szrj 			*listp = list->next;
384738fd1498Szrj 			delete list;
384838fd1498Szrj 			list = *listp;
384938fd1498Szrj 			break;
385038fd1498Szrj 		      }
385138fd1498Szrj 
385238fd1498Szrj 		    gcc_assert (dv_as_opaque (list->dv) != dv_as_opaque (dv));
385338fd1498Szrj 		  }
385438fd1498Szrj 	      }
385538fd1498Szrj 	    else if (dv_as_opaque (list->dv) == dv_as_opaque (cdv))
385638fd1498Szrj 	      {
385738fd1498Szrj 		for (listp = &list->next; (list = *listp); listp = &list->next)
385838fd1498Szrj 		  {
385938fd1498Szrj 		    if (list->offset)
386038fd1498Szrj 		      continue;
386138fd1498Szrj 
386238fd1498Szrj 		    if (dv_as_opaque (list->dv) == dv_as_opaque (dv))
386338fd1498Szrj 		      {
386438fd1498Szrj 			*listp = list->next;
386538fd1498Szrj 			delete list;
386638fd1498Szrj 			list = *listp;
386738fd1498Szrj 			break;
386838fd1498Szrj 		      }
386938fd1498Szrj 
387038fd1498Szrj 		    gcc_assert (dv_as_opaque (list->dv) != dv_as_opaque (cdv));
387138fd1498Szrj 		  }
387238fd1498Szrj 	      }
387338fd1498Szrj 	    else
387438fd1498Szrj 	      gcc_unreachable ();
387538fd1498Szrj 
387638fd1498Szrj 	    if (flag_checking)
387738fd1498Szrj 	      while (list)
387838fd1498Szrj 		{
387938fd1498Szrj 		  if (list->offset == 0
388038fd1498Szrj 		      && (dv_as_opaque (list->dv) == dv_as_opaque (dv)
388138fd1498Szrj 			  || dv_as_opaque (list->dv) == dv_as_opaque (cdv)))
388238fd1498Szrj 		    gcc_unreachable ();
388338fd1498Szrj 
388438fd1498Szrj 		  list = list->next;
388538fd1498Szrj 		}
388638fd1498Szrj 	  }
388738fd1498Szrj       }
388838fd1498Szrj 
388938fd1498Szrj   if (val)
389038fd1498Szrj     set_slot_part (set, val, cslot, cdv, 0,
389138fd1498Szrj 		   VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
389238fd1498Szrj 
389338fd1498Szrj   slot = clobber_slot_part (set, cval, slot, 0, NULL);
389438fd1498Szrj 
389538fd1498Szrj   /* Variable may have been unshared.  */
389638fd1498Szrj   var = *slot;
389738fd1498Szrj   gcc_checking_assert (var->n_var_parts && var->var_part[0].loc_chain->loc == cval
389838fd1498Szrj 		       && var->var_part[0].loc_chain->next == NULL);
389938fd1498Szrj 
390038fd1498Szrj   if (VALUE_RECURSED_INTO (cval))
390138fd1498Szrj     goto restart_with_cval;
390238fd1498Szrj 
390338fd1498Szrj   return 1;
390438fd1498Szrj }
390538fd1498Szrj 
390638fd1498Szrj /* Bind one-part variables to the canonical value in an equivalence
390738fd1498Szrj    set.  Not doing this causes dataflow convergence failure in rare
390838fd1498Szrj    circumstances, see PR42873.  Unfortunately we can't do this
390938fd1498Szrj    efficiently as part of canonicalize_values_star, since we may not
391038fd1498Szrj    have determined or even seen the canonical value of a set when we
391138fd1498Szrj    get to a variable that references another member of the set.  */
391238fd1498Szrj 
391338fd1498Szrj int
canonicalize_vars_star(variable ** slot,dataflow_set * set)391438fd1498Szrj canonicalize_vars_star (variable **slot, dataflow_set *set)
391538fd1498Szrj {
391638fd1498Szrj   variable *var = *slot;
391738fd1498Szrj   decl_or_value dv = var->dv;
391838fd1498Szrj   location_chain *node;
391938fd1498Szrj   rtx cval;
392038fd1498Szrj   decl_or_value cdv;
392138fd1498Szrj   variable **cslot;
392238fd1498Szrj   variable *cvar;
392338fd1498Szrj   location_chain *cnode;
392438fd1498Szrj 
392538fd1498Szrj   if (!var->onepart || var->onepart == ONEPART_VALUE)
392638fd1498Szrj     return 1;
392738fd1498Szrj 
392838fd1498Szrj   gcc_assert (var->n_var_parts == 1);
392938fd1498Szrj 
393038fd1498Szrj   node = var->var_part[0].loc_chain;
393138fd1498Szrj 
393238fd1498Szrj   if (GET_CODE (node->loc) != VALUE)
393338fd1498Szrj     return 1;
393438fd1498Szrj 
393538fd1498Szrj   gcc_assert (!node->next);
393638fd1498Szrj   cval = node->loc;
393738fd1498Szrj 
393838fd1498Szrj   /* Push values to the canonical one.  */
393938fd1498Szrj   cdv = dv_from_value (cval);
394038fd1498Szrj   cslot = shared_hash_find_slot_noinsert (set->vars, cdv);
394138fd1498Szrj   if (!cslot)
394238fd1498Szrj     return 1;
394338fd1498Szrj   cvar = *cslot;
394438fd1498Szrj   gcc_assert (cvar->n_var_parts == 1);
394538fd1498Szrj 
394638fd1498Szrj   cnode = cvar->var_part[0].loc_chain;
394738fd1498Szrj 
394838fd1498Szrj   /* CVAL is canonical if its value list contains non-VALUEs or VALUEs
394938fd1498Szrj      that are not “more canonical” than it.  */
395038fd1498Szrj   if (GET_CODE (cnode->loc) != VALUE
395138fd1498Szrj       || !canon_value_cmp (cnode->loc, cval))
395238fd1498Szrj     return 1;
395338fd1498Szrj 
395438fd1498Szrj   /* CVAL was found to be non-canonical.  Change the variable to point
395538fd1498Szrj      to the canonical VALUE.  */
395638fd1498Szrj   gcc_assert (!cnode->next);
395738fd1498Szrj   cval = cnode->loc;
395838fd1498Szrj 
395938fd1498Szrj   slot = set_slot_part (set, cval, slot, dv, 0,
396038fd1498Szrj 			node->init, node->set_src);
396138fd1498Szrj   clobber_slot_part (set, cval, slot, 0, node->set_src);
396238fd1498Szrj 
396338fd1498Szrj   return 1;
396438fd1498Szrj }
396538fd1498Szrj 
396638fd1498Szrj /* Combine variable or value in *S1SLOT (in DSM->cur) with the
396738fd1498Szrj    corresponding entry in DSM->src.  Multi-part variables are combined
396838fd1498Szrj    with variable_union, whereas onepart dvs are combined with
396938fd1498Szrj    intersection.  */
397038fd1498Szrj 
397138fd1498Szrj static int
variable_merge_over_cur(variable * s1var,struct dfset_merge * dsm)397238fd1498Szrj variable_merge_over_cur (variable *s1var, struct dfset_merge *dsm)
397338fd1498Szrj {
397438fd1498Szrj   dataflow_set *dst = dsm->dst;
397538fd1498Szrj   variable **dstslot;
397638fd1498Szrj   variable *s2var, *dvar = NULL;
397738fd1498Szrj   decl_or_value dv = s1var->dv;
397838fd1498Szrj   onepart_enum onepart = s1var->onepart;
397938fd1498Szrj   rtx val;
398038fd1498Szrj   hashval_t dvhash;
398138fd1498Szrj   location_chain *node, **nodep;
398238fd1498Szrj 
398338fd1498Szrj   /* If the incoming onepart variable has an empty location list, then
398438fd1498Szrj      the intersection will be just as empty.  For other variables,
398538fd1498Szrj      it's always union.  */
398638fd1498Szrj   gcc_checking_assert (s1var->n_var_parts
398738fd1498Szrj 		       && s1var->var_part[0].loc_chain);
398838fd1498Szrj 
398938fd1498Szrj   if (!onepart)
399038fd1498Szrj     return variable_union (s1var, dst);
399138fd1498Szrj 
399238fd1498Szrj   gcc_checking_assert (s1var->n_var_parts == 1);
399338fd1498Szrj 
399438fd1498Szrj   dvhash = dv_htab_hash (dv);
399538fd1498Szrj   if (dv_is_value_p (dv))
399638fd1498Szrj     val = dv_as_value (dv);
399738fd1498Szrj   else
399838fd1498Szrj     val = NULL;
399938fd1498Szrj 
400038fd1498Szrj   s2var = shared_hash_find_1 (dsm->src->vars, dv, dvhash);
400138fd1498Szrj   if (!s2var)
400238fd1498Szrj     {
400338fd1498Szrj       dst_can_be_shared = false;
400438fd1498Szrj       return 1;
400538fd1498Szrj     }
400638fd1498Szrj 
400738fd1498Szrj   dsm->src_onepart_cnt--;
400838fd1498Szrj   gcc_assert (s2var->var_part[0].loc_chain
400938fd1498Szrj 	      && s2var->onepart == onepart
401038fd1498Szrj 	      && s2var->n_var_parts == 1);
401138fd1498Szrj 
401238fd1498Szrj   dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
401338fd1498Szrj   if (dstslot)
401438fd1498Szrj     {
401538fd1498Szrj       dvar = *dstslot;
401638fd1498Szrj       gcc_assert (dvar->refcount == 1
401738fd1498Szrj 		  && dvar->onepart == onepart
401838fd1498Szrj 		  && dvar->n_var_parts == 1);
401938fd1498Szrj       nodep = &dvar->var_part[0].loc_chain;
402038fd1498Szrj     }
402138fd1498Szrj   else
402238fd1498Szrj     {
402338fd1498Szrj       nodep = &node;
402438fd1498Szrj       node = NULL;
402538fd1498Szrj     }
402638fd1498Szrj 
402738fd1498Szrj   if (!dstslot && !onepart_variable_different_p (s1var, s2var))
402838fd1498Szrj     {
402938fd1498Szrj       dstslot = shared_hash_find_slot_unshare_1 (&dst->vars, dv,
403038fd1498Szrj 						 dvhash, INSERT);
403138fd1498Szrj       *dstslot = dvar = s2var;
403238fd1498Szrj       dvar->refcount++;
403338fd1498Szrj     }
403438fd1498Szrj   else
403538fd1498Szrj     {
403638fd1498Szrj       dst_can_be_shared = false;
403738fd1498Szrj 
403838fd1498Szrj       intersect_loc_chains (val, nodep, dsm,
403938fd1498Szrj 			    s1var->var_part[0].loc_chain, s2var);
404038fd1498Szrj 
404138fd1498Szrj       if (!dstslot)
404238fd1498Szrj 	{
404338fd1498Szrj 	  if (node)
404438fd1498Szrj 	    {
404538fd1498Szrj 	      dvar = onepart_pool_allocate (onepart);
404638fd1498Szrj 	      dvar->dv = dv;
404738fd1498Szrj 	      dvar->refcount = 1;
404838fd1498Szrj 	      dvar->n_var_parts = 1;
404938fd1498Szrj 	      dvar->onepart = onepart;
405038fd1498Szrj 	      dvar->in_changed_variables = false;
405138fd1498Szrj 	      dvar->var_part[0].loc_chain = node;
405238fd1498Szrj 	      dvar->var_part[0].cur_loc = NULL;
405338fd1498Szrj 	      if (onepart)
405438fd1498Szrj 		VAR_LOC_1PAUX (dvar) = NULL;
405538fd1498Szrj 	      else
405638fd1498Szrj 		VAR_PART_OFFSET (dvar, 0) = 0;
405738fd1498Szrj 
405838fd1498Szrj 	      dstslot
405938fd1498Szrj 		= shared_hash_find_slot_unshare_1 (&dst->vars, dv, dvhash,
406038fd1498Szrj 						   INSERT);
406138fd1498Szrj 	      gcc_assert (!*dstslot);
406238fd1498Szrj 	      *dstslot = dvar;
406338fd1498Szrj 	    }
406438fd1498Szrj 	  else
406538fd1498Szrj 	    return 1;
406638fd1498Szrj 	}
406738fd1498Szrj     }
406838fd1498Szrj 
406938fd1498Szrj   nodep = &dvar->var_part[0].loc_chain;
407038fd1498Szrj   while ((node = *nodep))
407138fd1498Szrj     {
407238fd1498Szrj       location_chain **nextp = &node->next;
407338fd1498Szrj 
407438fd1498Szrj       if (GET_CODE (node->loc) == REG)
407538fd1498Szrj 	{
407638fd1498Szrj 	  attrs *list;
407738fd1498Szrj 
407838fd1498Szrj 	  for (list = dst->regs[REGNO (node->loc)]; list; list = list->next)
407938fd1498Szrj 	    if (GET_MODE (node->loc) == GET_MODE (list->loc)
408038fd1498Szrj 		&& dv_is_value_p (list->dv))
408138fd1498Szrj 	      break;
408238fd1498Szrj 
408338fd1498Szrj 	  if (!list)
408438fd1498Szrj 	    attrs_list_insert (&dst->regs[REGNO (node->loc)],
408538fd1498Szrj 			       dv, 0, node->loc);
408638fd1498Szrj 	  /* If this value became canonical for another value that had
408738fd1498Szrj 	     this register, we want to leave it alone.  */
408838fd1498Szrj 	  else if (dv_as_value (list->dv) != val)
408938fd1498Szrj 	    {
409038fd1498Szrj 	      dstslot = set_slot_part (dst, dv_as_value (list->dv),
409138fd1498Szrj 				       dstslot, dv, 0,
409238fd1498Szrj 				       node->init, NULL_RTX);
409338fd1498Szrj 	      dstslot = delete_slot_part (dst, node->loc, dstslot, 0);
409438fd1498Szrj 
409538fd1498Szrj 	      /* Since nextp points into the removed node, we can't
409638fd1498Szrj 		 use it.  The pointer to the next node moved to nodep.
409738fd1498Szrj 		 However, if the variable we're walking is unshared
409838fd1498Szrj 		 during our walk, we'll keep walking the location list
409938fd1498Szrj 		 of the previously-shared variable, in which case the
410038fd1498Szrj 		 node won't have been removed, and we'll want to skip
410138fd1498Szrj 		 it.  That's why we test *nodep here.  */
410238fd1498Szrj 	      if (*nodep != node)
410338fd1498Szrj 		nextp = nodep;
410438fd1498Szrj 	    }
410538fd1498Szrj 	}
410638fd1498Szrj       else
410738fd1498Szrj 	/* Canonicalization puts registers first, so we don't have to
410838fd1498Szrj 	   walk it all.  */
410938fd1498Szrj 	break;
411038fd1498Szrj       nodep = nextp;
411138fd1498Szrj     }
411238fd1498Szrj 
411338fd1498Szrj   if (dvar != *dstslot)
411438fd1498Szrj     dvar = *dstslot;
411538fd1498Szrj   nodep = &dvar->var_part[0].loc_chain;
411638fd1498Szrj 
411738fd1498Szrj   if (val)
411838fd1498Szrj     {
411938fd1498Szrj       /* Mark all referenced nodes for canonicalization, and make sure
412038fd1498Szrj 	 we have mutual equivalence links.  */
412138fd1498Szrj       VALUE_RECURSED_INTO (val) = true;
412238fd1498Szrj       for (node = *nodep; node; node = node->next)
412338fd1498Szrj 	if (GET_CODE (node->loc) == VALUE)
412438fd1498Szrj 	  {
412538fd1498Szrj 	    VALUE_RECURSED_INTO (node->loc) = true;
412638fd1498Szrj 	    set_variable_part (dst, val, dv_from_value (node->loc), 0,
412738fd1498Szrj 			       node->init, NULL, INSERT);
412838fd1498Szrj 	  }
412938fd1498Szrj 
413038fd1498Szrj       dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
413138fd1498Szrj       gcc_assert (*dstslot == dvar);
413238fd1498Szrj       canonicalize_values_star (dstslot, dst);
413338fd1498Szrj       gcc_checking_assert (dstslot
413438fd1498Szrj 			   == shared_hash_find_slot_noinsert_1 (dst->vars,
413538fd1498Szrj 								dv, dvhash));
413638fd1498Szrj       dvar = *dstslot;
413738fd1498Szrj     }
413838fd1498Szrj   else
413938fd1498Szrj     {
414038fd1498Szrj       bool has_value = false, has_other = false;
414138fd1498Szrj 
414238fd1498Szrj       /* If we have one value and anything else, we're going to
414338fd1498Szrj 	 canonicalize this, so make sure all values have an entry in
414438fd1498Szrj 	 the table and are marked for canonicalization.  */
414538fd1498Szrj       for (node = *nodep; node; node = node->next)
414638fd1498Szrj 	{
414738fd1498Szrj 	  if (GET_CODE (node->loc) == VALUE)
414838fd1498Szrj 	    {
414938fd1498Szrj 	      /* If this was marked during register canonicalization,
415038fd1498Szrj 		 we know we have to canonicalize values.  */
415138fd1498Szrj 	      if (has_value)
415238fd1498Szrj 		has_other = true;
415338fd1498Szrj 	      has_value = true;
415438fd1498Szrj 	      if (has_other)
415538fd1498Szrj 		break;
415638fd1498Szrj 	    }
415738fd1498Szrj 	  else
415838fd1498Szrj 	    {
415938fd1498Szrj 	      has_other = true;
416038fd1498Szrj 	      if (has_value)
416138fd1498Szrj 		break;
416238fd1498Szrj 	    }
416338fd1498Szrj 	}
416438fd1498Szrj 
416538fd1498Szrj       if (has_value && has_other)
416638fd1498Szrj 	{
416738fd1498Szrj 	  for (node = *nodep; node; node = node->next)
416838fd1498Szrj 	    {
416938fd1498Szrj 	      if (GET_CODE (node->loc) == VALUE)
417038fd1498Szrj 		{
417138fd1498Szrj 		  decl_or_value dv = dv_from_value (node->loc);
417238fd1498Szrj 		  variable **slot = NULL;
417338fd1498Szrj 
417438fd1498Szrj 		  if (shared_hash_shared (dst->vars))
417538fd1498Szrj 		    slot = shared_hash_find_slot_noinsert (dst->vars, dv);
417638fd1498Szrj 		  if (!slot)
417738fd1498Szrj 		    slot = shared_hash_find_slot_unshare (&dst->vars, dv,
417838fd1498Szrj 							  INSERT);
417938fd1498Szrj 		  if (!*slot)
418038fd1498Szrj 		    {
418138fd1498Szrj 		      variable *var = onepart_pool_allocate (ONEPART_VALUE);
418238fd1498Szrj 		      var->dv = dv;
418338fd1498Szrj 		      var->refcount = 1;
418438fd1498Szrj 		      var->n_var_parts = 1;
418538fd1498Szrj 		      var->onepart = ONEPART_VALUE;
418638fd1498Szrj 		      var->in_changed_variables = false;
418738fd1498Szrj 		      var->var_part[0].loc_chain = NULL;
418838fd1498Szrj 		      var->var_part[0].cur_loc = NULL;
418938fd1498Szrj 		      VAR_LOC_1PAUX (var) = NULL;
419038fd1498Szrj 		      *slot = var;
419138fd1498Szrj 		    }
419238fd1498Szrj 
419338fd1498Szrj 		  VALUE_RECURSED_INTO (node->loc) = true;
419438fd1498Szrj 		}
419538fd1498Szrj 	    }
419638fd1498Szrj 
419738fd1498Szrj 	  dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
419838fd1498Szrj 	  gcc_assert (*dstslot == dvar);
419938fd1498Szrj 	  canonicalize_values_star (dstslot, dst);
420038fd1498Szrj 	  gcc_checking_assert (dstslot
420138fd1498Szrj 			       == shared_hash_find_slot_noinsert_1 (dst->vars,
420238fd1498Szrj 								    dv, dvhash));
420338fd1498Szrj 	  dvar = *dstslot;
420438fd1498Szrj 	}
420538fd1498Szrj     }
420638fd1498Szrj 
420738fd1498Szrj   if (!onepart_variable_different_p (dvar, s2var))
420838fd1498Szrj     {
420938fd1498Szrj       variable_htab_free (dvar);
421038fd1498Szrj       *dstslot = dvar = s2var;
421138fd1498Szrj       dvar->refcount++;
421238fd1498Szrj     }
421338fd1498Szrj   else if (s2var != s1var && !onepart_variable_different_p (dvar, s1var))
421438fd1498Szrj     {
421538fd1498Szrj       variable_htab_free (dvar);
421638fd1498Szrj       *dstslot = dvar = s1var;
421738fd1498Szrj       dvar->refcount++;
421838fd1498Szrj       dst_can_be_shared = false;
421938fd1498Szrj     }
422038fd1498Szrj   else
422138fd1498Szrj     dst_can_be_shared = false;
422238fd1498Szrj 
422338fd1498Szrj   return 1;
422438fd1498Szrj }
422538fd1498Szrj 
422638fd1498Szrj /* Copy s2slot (in DSM->src) to DSM->dst if the variable is a
422738fd1498Szrj    multi-part variable.  Unions of multi-part variables and
422838fd1498Szrj    intersections of one-part ones will be handled in
422938fd1498Szrj    variable_merge_over_cur().  */
423038fd1498Szrj 
423138fd1498Szrj static int
variable_merge_over_src(variable * s2var,struct dfset_merge * dsm)423238fd1498Szrj variable_merge_over_src (variable *s2var, struct dfset_merge *dsm)
423338fd1498Szrj {
423438fd1498Szrj   dataflow_set *dst = dsm->dst;
423538fd1498Szrj   decl_or_value dv = s2var->dv;
423638fd1498Szrj 
423738fd1498Szrj   if (!s2var->onepart)
423838fd1498Szrj     {
423938fd1498Szrj       variable **dstp = shared_hash_find_slot (dst->vars, dv);
424038fd1498Szrj       *dstp = s2var;
424138fd1498Szrj       s2var->refcount++;
424238fd1498Szrj       return 1;
424338fd1498Szrj     }
424438fd1498Szrj 
424538fd1498Szrj   dsm->src_onepart_cnt++;
424638fd1498Szrj   return 1;
424738fd1498Szrj }
424838fd1498Szrj 
424938fd1498Szrj /* Combine dataflow set information from SRC2 into DST, using PDST
425038fd1498Szrj    to carry over information across passes.  */
425138fd1498Szrj 
425238fd1498Szrj static void
dataflow_set_merge(dataflow_set * dst,dataflow_set * src2)425338fd1498Szrj dataflow_set_merge (dataflow_set *dst, dataflow_set *src2)
425438fd1498Szrj {
425538fd1498Szrj   dataflow_set cur = *dst;
425638fd1498Szrj   dataflow_set *src1 = &cur;
425738fd1498Szrj   struct dfset_merge dsm;
425838fd1498Szrj   int i;
425938fd1498Szrj   size_t src1_elems, src2_elems;
426038fd1498Szrj   variable_iterator_type hi;
426138fd1498Szrj   variable *var;
426238fd1498Szrj 
426338fd1498Szrj   src1_elems = shared_hash_htab (src1->vars)->elements ();
426438fd1498Szrj   src2_elems = shared_hash_htab (src2->vars)->elements ();
426538fd1498Szrj   dataflow_set_init (dst);
426638fd1498Szrj   dst->stack_adjust = cur.stack_adjust;
426738fd1498Szrj   shared_hash_destroy (dst->vars);
426838fd1498Szrj   dst->vars = new shared_hash;
426938fd1498Szrj   dst->vars->refcount = 1;
427038fd1498Szrj   dst->vars->htab = new variable_table_type (MAX (src1_elems, src2_elems));
427138fd1498Szrj 
427238fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
427338fd1498Szrj     attrs_list_mpdv_union (&dst->regs[i], src1->regs[i], src2->regs[i]);
427438fd1498Szrj 
427538fd1498Szrj   dsm.dst = dst;
427638fd1498Szrj   dsm.src = src2;
427738fd1498Szrj   dsm.cur = src1;
427838fd1498Szrj   dsm.src_onepart_cnt = 0;
427938fd1498Szrj 
428038fd1498Szrj   FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.src->vars),
428138fd1498Szrj 			       var, variable, hi)
428238fd1498Szrj     variable_merge_over_src (var, &dsm);
428338fd1498Szrj   FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.cur->vars),
428438fd1498Szrj 			       var, variable, hi)
428538fd1498Szrj     variable_merge_over_cur (var, &dsm);
428638fd1498Szrj 
428738fd1498Szrj   if (dsm.src_onepart_cnt)
428838fd1498Szrj     dst_can_be_shared = false;
428938fd1498Szrj 
429038fd1498Szrj   dataflow_set_destroy (src1);
429138fd1498Szrj }
429238fd1498Szrj 
429338fd1498Szrj /* Mark register equivalences.  */
429438fd1498Szrj 
429538fd1498Szrj static void
dataflow_set_equiv_regs(dataflow_set * set)429638fd1498Szrj dataflow_set_equiv_regs (dataflow_set *set)
429738fd1498Szrj {
429838fd1498Szrj   int i;
429938fd1498Szrj   attrs *list, **listp;
430038fd1498Szrj 
430138fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
430238fd1498Szrj     {
430338fd1498Szrj       rtx canon[NUM_MACHINE_MODES];
430438fd1498Szrj 
430538fd1498Szrj       /* If the list is empty or one entry, no need to canonicalize
430638fd1498Szrj 	 anything.  */
430738fd1498Szrj       if (set->regs[i] == NULL || set->regs[i]->next == NULL)
430838fd1498Szrj 	continue;
430938fd1498Szrj 
431038fd1498Szrj       memset (canon, 0, sizeof (canon));
431138fd1498Szrj 
431238fd1498Szrj       for (list = set->regs[i]; list; list = list->next)
431338fd1498Szrj 	if (list->offset == 0 && dv_is_value_p (list->dv))
431438fd1498Szrj 	  {
431538fd1498Szrj 	    rtx val = dv_as_value (list->dv);
431638fd1498Szrj 	    rtx *cvalp = &canon[(int)GET_MODE (val)];
431738fd1498Szrj 	    rtx cval = *cvalp;
431838fd1498Szrj 
431938fd1498Szrj 	    if (canon_value_cmp (val, cval))
432038fd1498Szrj 	      *cvalp = val;
432138fd1498Szrj 	  }
432238fd1498Szrj 
432338fd1498Szrj       for (list = set->regs[i]; list; list = list->next)
432438fd1498Szrj 	if (list->offset == 0 && dv_onepart_p (list->dv))
432538fd1498Szrj 	  {
432638fd1498Szrj 	    rtx cval = canon[(int)GET_MODE (list->loc)];
432738fd1498Szrj 
432838fd1498Szrj 	    if (!cval)
432938fd1498Szrj 	      continue;
433038fd1498Szrj 
433138fd1498Szrj 	    if (dv_is_value_p (list->dv))
433238fd1498Szrj 	      {
433338fd1498Szrj 		rtx val = dv_as_value (list->dv);
433438fd1498Szrj 
433538fd1498Szrj 		if (val == cval)
433638fd1498Szrj 		  continue;
433738fd1498Szrj 
433838fd1498Szrj 		VALUE_RECURSED_INTO (val) = true;
433938fd1498Szrj 		set_variable_part (set, val, dv_from_value (cval), 0,
434038fd1498Szrj 				   VAR_INIT_STATUS_INITIALIZED,
434138fd1498Szrj 				   NULL, NO_INSERT);
434238fd1498Szrj 	      }
434338fd1498Szrj 
434438fd1498Szrj 	    VALUE_RECURSED_INTO (cval) = true;
434538fd1498Szrj 	    set_variable_part (set, cval, list->dv, 0,
434638fd1498Szrj 			       VAR_INIT_STATUS_INITIALIZED, NULL, NO_INSERT);
434738fd1498Szrj 	  }
434838fd1498Szrj 
434938fd1498Szrj       for (listp = &set->regs[i]; (list = *listp);
435038fd1498Szrj 	   listp = list ? &list->next : listp)
435138fd1498Szrj 	if (list->offset == 0 && dv_onepart_p (list->dv))
435238fd1498Szrj 	  {
435338fd1498Szrj 	    rtx cval = canon[(int)GET_MODE (list->loc)];
435438fd1498Szrj 	    variable **slot;
435538fd1498Szrj 
435638fd1498Szrj 	    if (!cval)
435738fd1498Szrj 	      continue;
435838fd1498Szrj 
435938fd1498Szrj 	    if (dv_is_value_p (list->dv))
436038fd1498Szrj 	      {
436138fd1498Szrj 		rtx val = dv_as_value (list->dv);
436238fd1498Szrj 		if (!VALUE_RECURSED_INTO (val))
436338fd1498Szrj 		  continue;
436438fd1498Szrj 	      }
436538fd1498Szrj 
436638fd1498Szrj 	    slot = shared_hash_find_slot_noinsert (set->vars, list->dv);
436738fd1498Szrj 	    canonicalize_values_star (slot, set);
436838fd1498Szrj 	    if (*listp != list)
436938fd1498Szrj 	      list = NULL;
437038fd1498Szrj 	  }
437138fd1498Szrj     }
437238fd1498Szrj }
437338fd1498Szrj 
437438fd1498Szrj /* Remove any redundant values in the location list of VAR, which must
437538fd1498Szrj    be unshared and 1-part.  */
437638fd1498Szrj 
437738fd1498Szrj static void
remove_duplicate_values(variable * var)437838fd1498Szrj remove_duplicate_values (variable *var)
437938fd1498Szrj {
438038fd1498Szrj   location_chain *node, **nodep;
438138fd1498Szrj 
438238fd1498Szrj   gcc_assert (var->onepart);
438338fd1498Szrj   gcc_assert (var->n_var_parts == 1);
438438fd1498Szrj   gcc_assert (var->refcount == 1);
438538fd1498Szrj 
438638fd1498Szrj   for (nodep = &var->var_part[0].loc_chain; (node = *nodep); )
438738fd1498Szrj     {
438838fd1498Szrj       if (GET_CODE (node->loc) == VALUE)
438938fd1498Szrj 	{
439038fd1498Szrj 	  if (VALUE_RECURSED_INTO (node->loc))
439138fd1498Szrj 	    {
439238fd1498Szrj 	      /* Remove duplicate value node.  */
439338fd1498Szrj 	      *nodep = node->next;
439438fd1498Szrj 	      delete node;
439538fd1498Szrj 	      continue;
439638fd1498Szrj 	    }
439738fd1498Szrj 	  else
439838fd1498Szrj 	    VALUE_RECURSED_INTO (node->loc) = true;
439938fd1498Szrj 	}
440038fd1498Szrj       nodep = &node->next;
440138fd1498Szrj     }
440238fd1498Szrj 
440338fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
440438fd1498Szrj     if (GET_CODE (node->loc) == VALUE)
440538fd1498Szrj       {
440638fd1498Szrj 	gcc_assert (VALUE_RECURSED_INTO (node->loc));
440738fd1498Szrj 	VALUE_RECURSED_INTO (node->loc) = false;
440838fd1498Szrj       }
440938fd1498Szrj }
441038fd1498Szrj 
441138fd1498Szrj 
441238fd1498Szrj /* Hash table iteration argument passed to variable_post_merge.  */
441338fd1498Szrj struct dfset_post_merge
441438fd1498Szrj {
441538fd1498Szrj   /* The new input set for the current block.  */
441638fd1498Szrj   dataflow_set *set;
441738fd1498Szrj   /* Pointer to the permanent input set for the current block, or
441838fd1498Szrj      NULL.  */
441938fd1498Szrj   dataflow_set **permp;
442038fd1498Szrj };
442138fd1498Szrj 
442238fd1498Szrj /* Create values for incoming expressions associated with one-part
442338fd1498Szrj    variables that don't have value numbers for them.  */
442438fd1498Szrj 
442538fd1498Szrj int
variable_post_merge_new_vals(variable ** slot,dfset_post_merge * dfpm)442638fd1498Szrj variable_post_merge_new_vals (variable **slot, dfset_post_merge *dfpm)
442738fd1498Szrj {
442838fd1498Szrj   dataflow_set *set = dfpm->set;
442938fd1498Szrj   variable *var = *slot;
443038fd1498Szrj   location_chain *node;
443138fd1498Szrj 
443238fd1498Szrj   if (!var->onepart || !var->n_var_parts)
443338fd1498Szrj     return 1;
443438fd1498Szrj 
443538fd1498Szrj   gcc_assert (var->n_var_parts == 1);
443638fd1498Szrj 
443738fd1498Szrj   if (dv_is_decl_p (var->dv))
443838fd1498Szrj     {
443938fd1498Szrj       bool check_dupes = false;
444038fd1498Szrj 
444138fd1498Szrj     restart:
444238fd1498Szrj       for (node = var->var_part[0].loc_chain; node; node = node->next)
444338fd1498Szrj 	{
444438fd1498Szrj 	  if (GET_CODE (node->loc) == VALUE)
444538fd1498Szrj 	    gcc_assert (!VALUE_RECURSED_INTO (node->loc));
444638fd1498Szrj 	  else if (GET_CODE (node->loc) == REG)
444738fd1498Szrj 	    {
444838fd1498Szrj 	      attrs *att, **attp, **curp = NULL;
444938fd1498Szrj 
445038fd1498Szrj 	      if (var->refcount != 1)
445138fd1498Szrj 		{
445238fd1498Szrj 		  slot = unshare_variable (set, slot, var,
445338fd1498Szrj 					   VAR_INIT_STATUS_INITIALIZED);
445438fd1498Szrj 		  var = *slot;
445538fd1498Szrj 		  goto restart;
445638fd1498Szrj 		}
445738fd1498Szrj 
445838fd1498Szrj 	      for (attp = &set->regs[REGNO (node->loc)]; (att = *attp);
445938fd1498Szrj 		   attp = &att->next)
446038fd1498Szrj 		if (att->offset == 0
446138fd1498Szrj 		    && GET_MODE (att->loc) == GET_MODE (node->loc))
446238fd1498Szrj 		  {
446338fd1498Szrj 		    if (dv_is_value_p (att->dv))
446438fd1498Szrj 		      {
446538fd1498Szrj 			rtx cval = dv_as_value (att->dv);
446638fd1498Szrj 			node->loc = cval;
446738fd1498Szrj 			check_dupes = true;
446838fd1498Szrj 			break;
446938fd1498Szrj 		      }
447038fd1498Szrj 		    else if (dv_as_opaque (att->dv) == dv_as_opaque (var->dv))
447138fd1498Szrj 		      curp = attp;
447238fd1498Szrj 		  }
447338fd1498Szrj 
447438fd1498Szrj 	      if (!curp)
447538fd1498Szrj 		{
447638fd1498Szrj 		  curp = attp;
447738fd1498Szrj 		  while (*curp)
447838fd1498Szrj 		    if ((*curp)->offset == 0
447938fd1498Szrj 			&& GET_MODE ((*curp)->loc) == GET_MODE (node->loc)
448038fd1498Szrj 			&& dv_as_opaque ((*curp)->dv) == dv_as_opaque (var->dv))
448138fd1498Szrj 		      break;
448238fd1498Szrj 		    else
448338fd1498Szrj 		      curp = &(*curp)->next;
448438fd1498Szrj 		  gcc_assert (*curp);
448538fd1498Szrj 		}
448638fd1498Szrj 
448738fd1498Szrj 	      if (!att)
448838fd1498Szrj 		{
448938fd1498Szrj 		  decl_or_value cdv;
449038fd1498Szrj 		  rtx cval;
449138fd1498Szrj 
449238fd1498Szrj 		  if (!*dfpm->permp)
449338fd1498Szrj 		    {
449438fd1498Szrj 		      *dfpm->permp = XNEW (dataflow_set);
449538fd1498Szrj 		      dataflow_set_init (*dfpm->permp);
449638fd1498Szrj 		    }
449738fd1498Szrj 
449838fd1498Szrj 		  for (att = (*dfpm->permp)->regs[REGNO (node->loc)];
449938fd1498Szrj 		       att; att = att->next)
450038fd1498Szrj 		    if (GET_MODE (att->loc) == GET_MODE (node->loc))
450138fd1498Szrj 		      {
450238fd1498Szrj 			gcc_assert (att->offset == 0
450338fd1498Szrj 				    && dv_is_value_p (att->dv));
450438fd1498Szrj 			val_reset (set, att->dv);
450538fd1498Szrj 			break;
450638fd1498Szrj 		      }
450738fd1498Szrj 
450838fd1498Szrj 		  if (att)
450938fd1498Szrj 		    {
451038fd1498Szrj 		      cdv = att->dv;
451138fd1498Szrj 		      cval = dv_as_value (cdv);
451238fd1498Szrj 		    }
451338fd1498Szrj 		  else
451438fd1498Szrj 		    {
451538fd1498Szrj 		      /* Create a unique value to hold this register,
451638fd1498Szrj 			 that ought to be found and reused in
451738fd1498Szrj 			 subsequent rounds.  */
451838fd1498Szrj 		      cselib_val *v;
451938fd1498Szrj 		      gcc_assert (!cselib_lookup (node->loc,
452038fd1498Szrj 						  GET_MODE (node->loc), 0,
452138fd1498Szrj 						  VOIDmode));
452238fd1498Szrj 		      v = cselib_lookup (node->loc, GET_MODE (node->loc), 1,
452338fd1498Szrj 					 VOIDmode);
452438fd1498Szrj 		      cselib_preserve_value (v);
452538fd1498Szrj 		      cselib_invalidate_rtx (node->loc);
452638fd1498Szrj 		      cval = v->val_rtx;
452738fd1498Szrj 		      cdv = dv_from_value (cval);
452838fd1498Szrj 		      if (dump_file)
452938fd1498Szrj 			fprintf (dump_file,
453038fd1498Szrj 				 "Created new value %u:%u for reg %i\n",
453138fd1498Szrj 				 v->uid, v->hash, REGNO (node->loc));
453238fd1498Szrj 		    }
453338fd1498Szrj 
453438fd1498Szrj 		  var_reg_decl_set (*dfpm->permp, node->loc,
453538fd1498Szrj 				    VAR_INIT_STATUS_INITIALIZED,
453638fd1498Szrj 				    cdv, 0, NULL, INSERT);
453738fd1498Szrj 
453838fd1498Szrj 		  node->loc = cval;
453938fd1498Szrj 		  check_dupes = true;
454038fd1498Szrj 		}
454138fd1498Szrj 
454238fd1498Szrj 	      /* Remove attribute referring to the decl, which now
454338fd1498Szrj 		 uses the value for the register, already existing or
454438fd1498Szrj 		 to be added when we bring perm in.  */
454538fd1498Szrj 	      att = *curp;
454638fd1498Szrj 	      *curp = att->next;
454738fd1498Szrj 	      delete att;
454838fd1498Szrj 	    }
454938fd1498Szrj 	}
455038fd1498Szrj 
455138fd1498Szrj       if (check_dupes)
455238fd1498Szrj 	remove_duplicate_values (var);
455338fd1498Szrj     }
455438fd1498Szrj 
455538fd1498Szrj   return 1;
455638fd1498Szrj }
455738fd1498Szrj 
455838fd1498Szrj /* Reset values in the permanent set that are not associated with the
455938fd1498Szrj    chosen expression.  */
456038fd1498Szrj 
456138fd1498Szrj int
variable_post_merge_perm_vals(variable ** pslot,dfset_post_merge * dfpm)456238fd1498Szrj variable_post_merge_perm_vals (variable **pslot, dfset_post_merge *dfpm)
456338fd1498Szrj {
456438fd1498Szrj   dataflow_set *set = dfpm->set;
456538fd1498Szrj   variable *pvar = *pslot, *var;
456638fd1498Szrj   location_chain *pnode;
456738fd1498Szrj   decl_or_value dv;
456838fd1498Szrj   attrs *att;
456938fd1498Szrj 
457038fd1498Szrj   gcc_assert (dv_is_value_p (pvar->dv)
457138fd1498Szrj 	      && pvar->n_var_parts == 1);
457238fd1498Szrj   pnode = pvar->var_part[0].loc_chain;
457338fd1498Szrj   gcc_assert (pnode
457438fd1498Szrj 	      && !pnode->next
457538fd1498Szrj 	      && REG_P (pnode->loc));
457638fd1498Szrj 
457738fd1498Szrj   dv = pvar->dv;
457838fd1498Szrj 
457938fd1498Szrj   var = shared_hash_find (set->vars, dv);
458038fd1498Szrj   if (var)
458138fd1498Szrj     {
458238fd1498Szrj       /* Although variable_post_merge_new_vals may have made decls
458338fd1498Szrj 	 non-star-canonical, values that pre-existed in canonical form
458438fd1498Szrj 	 remain canonical, and newly-created values reference a single
458538fd1498Szrj 	 REG, so they are canonical as well.  Since VAR has the
458638fd1498Szrj 	 location list for a VALUE, using find_loc_in_1pdv for it is
458738fd1498Szrj 	 fine, since VALUEs don't map back to DECLs.  */
458838fd1498Szrj       if (find_loc_in_1pdv (pnode->loc, var, shared_hash_htab (set->vars)))
458938fd1498Szrj 	return 1;
459038fd1498Szrj       val_reset (set, dv);
459138fd1498Szrj     }
459238fd1498Szrj 
459338fd1498Szrj   for (att = set->regs[REGNO (pnode->loc)]; att; att = att->next)
459438fd1498Szrj     if (att->offset == 0
459538fd1498Szrj 	&& GET_MODE (att->loc) == GET_MODE (pnode->loc)
459638fd1498Szrj 	&& dv_is_value_p (att->dv))
459738fd1498Szrj       break;
459838fd1498Szrj 
459938fd1498Szrj   /* If there is a value associated with this register already, create
460038fd1498Szrj      an equivalence.  */
460138fd1498Szrj   if (att && dv_as_value (att->dv) != dv_as_value (dv))
460238fd1498Szrj     {
460338fd1498Szrj       rtx cval = dv_as_value (att->dv);
460438fd1498Szrj       set_variable_part (set, cval, dv, 0, pnode->init, NULL, INSERT);
460538fd1498Szrj       set_variable_part (set, dv_as_value (dv), att->dv, 0, pnode->init,
460638fd1498Szrj 			 NULL, INSERT);
460738fd1498Szrj     }
460838fd1498Szrj   else if (!att)
460938fd1498Szrj     {
461038fd1498Szrj       attrs_list_insert (&set->regs[REGNO (pnode->loc)],
461138fd1498Szrj 			 dv, 0, pnode->loc);
461238fd1498Szrj       variable_union (pvar, set);
461338fd1498Szrj     }
461438fd1498Szrj 
461538fd1498Szrj   return 1;
461638fd1498Szrj }
461738fd1498Szrj 
461838fd1498Szrj /* Just checking stuff and registering register attributes for
461938fd1498Szrj    now.  */
462038fd1498Szrj 
462138fd1498Szrj static void
dataflow_post_merge_adjust(dataflow_set * set,dataflow_set ** permp)462238fd1498Szrj dataflow_post_merge_adjust (dataflow_set *set, dataflow_set **permp)
462338fd1498Szrj {
462438fd1498Szrj   struct dfset_post_merge dfpm;
462538fd1498Szrj 
462638fd1498Szrj   dfpm.set = set;
462738fd1498Szrj   dfpm.permp = permp;
462838fd1498Szrj 
462938fd1498Szrj   shared_hash_htab (set->vars)
463038fd1498Szrj     ->traverse <dfset_post_merge*, variable_post_merge_new_vals> (&dfpm);
463138fd1498Szrj   if (*permp)
463238fd1498Szrj     shared_hash_htab ((*permp)->vars)
463338fd1498Szrj       ->traverse <dfset_post_merge*, variable_post_merge_perm_vals> (&dfpm);
463438fd1498Szrj   shared_hash_htab (set->vars)
463538fd1498Szrj     ->traverse <dataflow_set *, canonicalize_values_star> (set);
463638fd1498Szrj   shared_hash_htab (set->vars)
463738fd1498Szrj     ->traverse <dataflow_set *, canonicalize_vars_star> (set);
463838fd1498Szrj }
463938fd1498Szrj 
464038fd1498Szrj /* Return a node whose loc is a MEM that refers to EXPR in the
464138fd1498Szrj    location list of a one-part variable or value VAR, or in that of
464238fd1498Szrj    any values recursively mentioned in the location lists.  */
464338fd1498Szrj 
464438fd1498Szrj static location_chain *
find_mem_expr_in_1pdv(tree expr,rtx val,variable_table_type * vars)464538fd1498Szrj find_mem_expr_in_1pdv (tree expr, rtx val, variable_table_type *vars)
464638fd1498Szrj {
464738fd1498Szrj   location_chain *node;
464838fd1498Szrj   decl_or_value dv;
464938fd1498Szrj   variable *var;
465038fd1498Szrj   location_chain *where = NULL;
465138fd1498Szrj 
465238fd1498Szrj   if (!val)
465338fd1498Szrj     return NULL;
465438fd1498Szrj 
465538fd1498Szrj   gcc_assert (GET_CODE (val) == VALUE
465638fd1498Szrj 	      && !VALUE_RECURSED_INTO (val));
465738fd1498Szrj 
465838fd1498Szrj   dv = dv_from_value (val);
465938fd1498Szrj   var = vars->find_with_hash (dv, dv_htab_hash (dv));
466038fd1498Szrj 
466138fd1498Szrj   if (!var)
466238fd1498Szrj     return NULL;
466338fd1498Szrj 
466438fd1498Szrj   gcc_assert (var->onepart);
466538fd1498Szrj 
466638fd1498Szrj   if (!var->n_var_parts)
466738fd1498Szrj     return NULL;
466838fd1498Szrj 
466938fd1498Szrj   VALUE_RECURSED_INTO (val) = true;
467038fd1498Szrj 
467138fd1498Szrj   for (node = var->var_part[0].loc_chain; node; node = node->next)
467238fd1498Szrj     if (MEM_P (node->loc)
467338fd1498Szrj 	&& MEM_EXPR (node->loc) == expr
467438fd1498Szrj 	&& int_mem_offset (node->loc) == 0)
467538fd1498Szrj       {
467638fd1498Szrj 	where = node;
467738fd1498Szrj 	break;
467838fd1498Szrj       }
467938fd1498Szrj     else if (GET_CODE (node->loc) == VALUE
468038fd1498Szrj 	     && !VALUE_RECURSED_INTO (node->loc)
468138fd1498Szrj 	     && (where = find_mem_expr_in_1pdv (expr, node->loc, vars)))
468238fd1498Szrj       break;
468338fd1498Szrj 
468438fd1498Szrj   VALUE_RECURSED_INTO (val) = false;
468538fd1498Szrj 
468638fd1498Szrj   return where;
468738fd1498Szrj }
468838fd1498Szrj 
468938fd1498Szrj /* Return TRUE if the value of MEM may vary across a call.  */
469038fd1498Szrj 
469138fd1498Szrj static bool
mem_dies_at_call(rtx mem)469238fd1498Szrj mem_dies_at_call (rtx mem)
469338fd1498Szrj {
469438fd1498Szrj   tree expr = MEM_EXPR (mem);
469538fd1498Szrj   tree decl;
469638fd1498Szrj 
469738fd1498Szrj   if (!expr)
469838fd1498Szrj     return true;
469938fd1498Szrj 
470038fd1498Szrj   decl = get_base_address (expr);
470138fd1498Szrj 
470238fd1498Szrj   if (!decl)
470338fd1498Szrj     return true;
470438fd1498Szrj 
470538fd1498Szrj   if (!DECL_P (decl))
470638fd1498Szrj     return true;
470738fd1498Szrj 
470838fd1498Szrj   return (may_be_aliased (decl)
470938fd1498Szrj 	  || (!TREE_READONLY (decl) && is_global_var (decl)));
471038fd1498Szrj }
471138fd1498Szrj 
471238fd1498Szrj /* Remove all MEMs from the location list of a hash table entry for a
471338fd1498Szrj    one-part variable, except those whose MEM attributes map back to
471438fd1498Szrj    the variable itself, directly or within a VALUE.  */
471538fd1498Szrj 
471638fd1498Szrj int
dataflow_set_preserve_mem_locs(variable ** slot,dataflow_set * set)471738fd1498Szrj dataflow_set_preserve_mem_locs (variable **slot, dataflow_set *set)
471838fd1498Szrj {
471938fd1498Szrj   variable *var = *slot;
472038fd1498Szrj 
472138fd1498Szrj   if (var->onepart == ONEPART_VDECL || var->onepart == ONEPART_DEXPR)
472238fd1498Szrj     {
472338fd1498Szrj       tree decl = dv_as_decl (var->dv);
472438fd1498Szrj       location_chain *loc, **locp;
472538fd1498Szrj       bool changed = false;
472638fd1498Szrj 
472738fd1498Szrj       if (!var->n_var_parts)
472838fd1498Szrj 	return 1;
472938fd1498Szrj 
473038fd1498Szrj       gcc_assert (var->n_var_parts == 1);
473138fd1498Szrj 
473238fd1498Szrj       if (shared_var_p (var, set->vars))
473338fd1498Szrj 	{
473438fd1498Szrj 	  for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
473538fd1498Szrj 	    {
473638fd1498Szrj 	      /* We want to remove dying MEMs that don't refer to DECL.  */
473738fd1498Szrj 	      if (GET_CODE (loc->loc) == MEM
473838fd1498Szrj 		  && (MEM_EXPR (loc->loc) != decl
473938fd1498Szrj 		      || int_mem_offset (loc->loc) != 0)
474038fd1498Szrj 		  && mem_dies_at_call (loc->loc))
474138fd1498Szrj 		break;
474238fd1498Szrj 	      /* We want to move here MEMs that do refer to DECL.  */
474338fd1498Szrj 	      else if (GET_CODE (loc->loc) == VALUE
474438fd1498Szrj 		       && find_mem_expr_in_1pdv (decl, loc->loc,
474538fd1498Szrj 						 shared_hash_htab (set->vars)))
474638fd1498Szrj 		break;
474738fd1498Szrj 	    }
474838fd1498Szrj 
474938fd1498Szrj 	  if (!loc)
475038fd1498Szrj 	    return 1;
475138fd1498Szrj 
475238fd1498Szrj 	  slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN);
475338fd1498Szrj 	  var = *slot;
475438fd1498Szrj 	  gcc_assert (var->n_var_parts == 1);
475538fd1498Szrj 	}
475638fd1498Szrj 
475738fd1498Szrj       for (locp = &var->var_part[0].loc_chain, loc = *locp;
475838fd1498Szrj 	   loc; loc = *locp)
475938fd1498Szrj 	{
476038fd1498Szrj 	  rtx old_loc = loc->loc;
476138fd1498Szrj 	  if (GET_CODE (old_loc) == VALUE)
476238fd1498Szrj 	    {
476338fd1498Szrj 	      location_chain *mem_node
476438fd1498Szrj 		= find_mem_expr_in_1pdv (decl, loc->loc,
476538fd1498Szrj 					 shared_hash_htab (set->vars));
476638fd1498Szrj 
476738fd1498Szrj 	      /* ??? This picks up only one out of multiple MEMs that
476838fd1498Szrj 		 refer to the same variable.  Do we ever need to be
476938fd1498Szrj 		 concerned about dealing with more than one, or, given
477038fd1498Szrj 		 that they should all map to the same variable
477138fd1498Szrj 		 location, their addresses will have been merged and
477238fd1498Szrj 		 they will be regarded as equivalent?  */
477338fd1498Szrj 	      if (mem_node)
477438fd1498Szrj 		{
477538fd1498Szrj 		  loc->loc = mem_node->loc;
477638fd1498Szrj 		  loc->set_src = mem_node->set_src;
477738fd1498Szrj 		  loc->init = MIN (loc->init, mem_node->init);
477838fd1498Szrj 		}
477938fd1498Szrj 	    }
478038fd1498Szrj 
478138fd1498Szrj 	  if (GET_CODE (loc->loc) != MEM
478238fd1498Szrj 	      || (MEM_EXPR (loc->loc) == decl
478338fd1498Szrj 		  && int_mem_offset (loc->loc) == 0)
478438fd1498Szrj 	      || !mem_dies_at_call (loc->loc))
478538fd1498Szrj 	    {
478638fd1498Szrj 	      if (old_loc != loc->loc && emit_notes)
478738fd1498Szrj 		{
478838fd1498Szrj 		  if (old_loc == var->var_part[0].cur_loc)
478938fd1498Szrj 		    {
479038fd1498Szrj 		      changed = true;
479138fd1498Szrj 		      var->var_part[0].cur_loc = NULL;
479238fd1498Szrj 		    }
479338fd1498Szrj 		}
479438fd1498Szrj 	      locp = &loc->next;
479538fd1498Szrj 	      continue;
479638fd1498Szrj 	    }
479738fd1498Szrj 
479838fd1498Szrj 	  if (emit_notes)
479938fd1498Szrj 	    {
480038fd1498Szrj 	      if (old_loc == var->var_part[0].cur_loc)
480138fd1498Szrj 		{
480238fd1498Szrj 		  changed = true;
480338fd1498Szrj 		  var->var_part[0].cur_loc = NULL;
480438fd1498Szrj 		}
480538fd1498Szrj 	    }
480638fd1498Szrj 	  *locp = loc->next;
480738fd1498Szrj 	  delete loc;
480838fd1498Szrj 	}
480938fd1498Szrj 
481038fd1498Szrj       if (!var->var_part[0].loc_chain)
481138fd1498Szrj 	{
481238fd1498Szrj 	  var->n_var_parts--;
481338fd1498Szrj 	  changed = true;
481438fd1498Szrj 	}
481538fd1498Szrj       if (changed)
481638fd1498Szrj 	variable_was_changed (var, set);
481738fd1498Szrj     }
481838fd1498Szrj 
481938fd1498Szrj   return 1;
482038fd1498Szrj }
482138fd1498Szrj 
482238fd1498Szrj /* Remove all MEMs from the location list of a hash table entry for a
482338fd1498Szrj    onepart variable.  */
482438fd1498Szrj 
482538fd1498Szrj int
dataflow_set_remove_mem_locs(variable ** slot,dataflow_set * set)482638fd1498Szrj dataflow_set_remove_mem_locs (variable **slot, dataflow_set *set)
482738fd1498Szrj {
482838fd1498Szrj   variable *var = *slot;
482938fd1498Szrj 
483038fd1498Szrj   if (var->onepart != NOT_ONEPART)
483138fd1498Szrj     {
483238fd1498Szrj       location_chain *loc, **locp;
483338fd1498Szrj       bool changed = false;
483438fd1498Szrj       rtx cur_loc;
483538fd1498Szrj 
483638fd1498Szrj       gcc_assert (var->n_var_parts == 1);
483738fd1498Szrj 
483838fd1498Szrj       if (shared_var_p (var, set->vars))
483938fd1498Szrj 	{
484038fd1498Szrj 	  for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
484138fd1498Szrj 	    if (GET_CODE (loc->loc) == MEM
484238fd1498Szrj 		&& mem_dies_at_call (loc->loc))
484338fd1498Szrj 	      break;
484438fd1498Szrj 
484538fd1498Szrj 	  if (!loc)
484638fd1498Szrj 	    return 1;
484738fd1498Szrj 
484838fd1498Szrj 	  slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN);
484938fd1498Szrj 	  var = *slot;
485038fd1498Szrj 	  gcc_assert (var->n_var_parts == 1);
485138fd1498Szrj 	}
485238fd1498Szrj 
485338fd1498Szrj       if (VAR_LOC_1PAUX (var))
485438fd1498Szrj 	cur_loc = VAR_LOC_FROM (var);
485538fd1498Szrj       else
485638fd1498Szrj 	cur_loc = var->var_part[0].cur_loc;
485738fd1498Szrj 
485838fd1498Szrj       for (locp = &var->var_part[0].loc_chain, loc = *locp;
485938fd1498Szrj 	   loc; loc = *locp)
486038fd1498Szrj 	{
486138fd1498Szrj 	  if (GET_CODE (loc->loc) != MEM
486238fd1498Szrj 	      || !mem_dies_at_call (loc->loc))
486338fd1498Szrj 	    {
486438fd1498Szrj 	      locp = &loc->next;
486538fd1498Szrj 	      continue;
486638fd1498Szrj 	    }
486738fd1498Szrj 
486838fd1498Szrj 	  *locp = loc->next;
486938fd1498Szrj 	  /* If we have deleted the location which was last emitted
487038fd1498Szrj 	     we have to emit new location so add the variable to set
487138fd1498Szrj 	     of changed variables.  */
487238fd1498Szrj 	  if (cur_loc == loc->loc)
487338fd1498Szrj 	    {
487438fd1498Szrj 	      changed = true;
487538fd1498Szrj 	      var->var_part[0].cur_loc = NULL;
487638fd1498Szrj 	      if (VAR_LOC_1PAUX (var))
487738fd1498Szrj 		VAR_LOC_FROM (var) = NULL;
487838fd1498Szrj 	    }
487938fd1498Szrj 	  delete loc;
488038fd1498Szrj 	}
488138fd1498Szrj 
488238fd1498Szrj       if (!var->var_part[0].loc_chain)
488338fd1498Szrj 	{
488438fd1498Szrj 	  var->n_var_parts--;
488538fd1498Szrj 	  changed = true;
488638fd1498Szrj 	}
488738fd1498Szrj       if (changed)
488838fd1498Szrj 	variable_was_changed (var, set);
488938fd1498Szrj     }
489038fd1498Szrj 
489138fd1498Szrj   return 1;
489238fd1498Szrj }
489338fd1498Szrj 
489438fd1498Szrj /* Remove all variable-location information about call-clobbered
489538fd1498Szrj    registers, as well as associations between MEMs and VALUEs.  */
489638fd1498Szrj 
489738fd1498Szrj static void
dataflow_set_clear_at_call(dataflow_set * set,rtx_insn * call_insn)489838fd1498Szrj dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
489938fd1498Szrj {
490038fd1498Szrj   unsigned int r;
490138fd1498Szrj   hard_reg_set_iterator hrsi;
490238fd1498Szrj   HARD_REG_SET invalidated_regs;
490338fd1498Szrj 
490438fd1498Szrj   get_call_reg_set_usage (call_insn, &invalidated_regs,
490538fd1498Szrj 			  regs_invalidated_by_call);
490638fd1498Szrj 
490738fd1498Szrj   EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
490838fd1498Szrj     var_regno_delete (set, r);
490938fd1498Szrj 
491038fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
491138fd1498Szrj     {
491238fd1498Szrj       set->traversed_vars = set->vars;
491338fd1498Szrj       shared_hash_htab (set->vars)
491438fd1498Szrj 	->traverse <dataflow_set *, dataflow_set_preserve_mem_locs> (set);
491538fd1498Szrj       set->traversed_vars = set->vars;
491638fd1498Szrj       shared_hash_htab (set->vars)
491738fd1498Szrj 	->traverse <dataflow_set *, dataflow_set_remove_mem_locs> (set);
491838fd1498Szrj       set->traversed_vars = NULL;
491938fd1498Szrj     }
492038fd1498Szrj }
492138fd1498Szrj 
492238fd1498Szrj static bool
variable_part_different_p(variable_part * vp1,variable_part * vp2)492338fd1498Szrj variable_part_different_p (variable_part *vp1, variable_part *vp2)
492438fd1498Szrj {
492538fd1498Szrj   location_chain *lc1, *lc2;
492638fd1498Szrj 
492738fd1498Szrj   for (lc1 = vp1->loc_chain; lc1; lc1 = lc1->next)
492838fd1498Szrj     {
492938fd1498Szrj       for (lc2 = vp2->loc_chain; lc2; lc2 = lc2->next)
493038fd1498Szrj 	{
493138fd1498Szrj 	  if (REG_P (lc1->loc) && REG_P (lc2->loc))
493238fd1498Szrj 	    {
493338fd1498Szrj 	      if (REGNO (lc1->loc) == REGNO (lc2->loc))
493438fd1498Szrj 		break;
493538fd1498Szrj 	    }
493638fd1498Szrj 	  if (rtx_equal_p (lc1->loc, lc2->loc))
493738fd1498Szrj 	    break;
493838fd1498Szrj 	}
493938fd1498Szrj       if (!lc2)
494038fd1498Szrj 	return true;
494138fd1498Szrj     }
494238fd1498Szrj   return false;
494338fd1498Szrj }
494438fd1498Szrj 
494538fd1498Szrj /* Return true if one-part variables VAR1 and VAR2 are different.
494638fd1498Szrj    They must be in canonical order.  */
494738fd1498Szrj 
494838fd1498Szrj static bool
onepart_variable_different_p(variable * var1,variable * var2)494938fd1498Szrj onepart_variable_different_p (variable *var1, variable *var2)
495038fd1498Szrj {
495138fd1498Szrj   location_chain *lc1, *lc2;
495238fd1498Szrj 
495338fd1498Szrj   if (var1 == var2)
495438fd1498Szrj     return false;
495538fd1498Szrj 
495638fd1498Szrj   gcc_assert (var1->n_var_parts == 1
495738fd1498Szrj 	      && var2->n_var_parts == 1);
495838fd1498Szrj 
495938fd1498Szrj   lc1 = var1->var_part[0].loc_chain;
496038fd1498Szrj   lc2 = var2->var_part[0].loc_chain;
496138fd1498Szrj 
496238fd1498Szrj   gcc_assert (lc1 && lc2);
496338fd1498Szrj 
496438fd1498Szrj   while (lc1 && lc2)
496538fd1498Szrj     {
496638fd1498Szrj       if (loc_cmp (lc1->loc, lc2->loc))
496738fd1498Szrj 	return true;
496838fd1498Szrj       lc1 = lc1->next;
496938fd1498Szrj       lc2 = lc2->next;
497038fd1498Szrj     }
497138fd1498Szrj 
497238fd1498Szrj   return lc1 != lc2;
497338fd1498Szrj }
497438fd1498Szrj 
497538fd1498Szrj /* Return true if one-part variables VAR1 and VAR2 are different.
497638fd1498Szrj    They must be in canonical order.  */
497738fd1498Szrj 
497838fd1498Szrj static void
dump_onepart_variable_differences(variable * var1,variable * var2)497938fd1498Szrj dump_onepart_variable_differences (variable *var1, variable *var2)
498038fd1498Szrj {
498138fd1498Szrj   location_chain *lc1, *lc2;
498238fd1498Szrj 
498338fd1498Szrj   gcc_assert (var1 != var2);
498438fd1498Szrj   gcc_assert (dump_file);
498538fd1498Szrj   gcc_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv));
498638fd1498Szrj   gcc_assert (var1->n_var_parts == 1
498738fd1498Szrj 	      && var2->n_var_parts == 1);
498838fd1498Szrj 
498938fd1498Szrj   lc1 = var1->var_part[0].loc_chain;
499038fd1498Szrj   lc2 = var2->var_part[0].loc_chain;
499138fd1498Szrj 
499238fd1498Szrj   gcc_assert (lc1 && lc2);
499338fd1498Szrj 
499438fd1498Szrj   while (lc1 && lc2)
499538fd1498Szrj     {
499638fd1498Szrj       switch (loc_cmp (lc1->loc, lc2->loc))
499738fd1498Szrj 	{
499838fd1498Szrj 	case -1:
499938fd1498Szrj 	  fprintf (dump_file, "removed: ");
500038fd1498Szrj 	  print_rtl_single (dump_file, lc1->loc);
500138fd1498Szrj 	  lc1 = lc1->next;
500238fd1498Szrj 	  continue;
500338fd1498Szrj 	case 0:
500438fd1498Szrj 	  break;
500538fd1498Szrj 	case 1:
500638fd1498Szrj 	  fprintf (dump_file, "added: ");
500738fd1498Szrj 	  print_rtl_single (dump_file, lc2->loc);
500838fd1498Szrj 	  lc2 = lc2->next;
500938fd1498Szrj 	  continue;
501038fd1498Szrj 	default:
501138fd1498Szrj 	  gcc_unreachable ();
501238fd1498Szrj 	}
501338fd1498Szrj       lc1 = lc1->next;
501438fd1498Szrj       lc2 = lc2->next;
501538fd1498Szrj     }
501638fd1498Szrj 
501738fd1498Szrj   while (lc1)
501838fd1498Szrj     {
501938fd1498Szrj       fprintf (dump_file, "removed: ");
502038fd1498Szrj       print_rtl_single (dump_file, lc1->loc);
502138fd1498Szrj       lc1 = lc1->next;
502238fd1498Szrj     }
502338fd1498Szrj 
502438fd1498Szrj   while (lc2)
502538fd1498Szrj     {
502638fd1498Szrj       fprintf (dump_file, "added: ");
502738fd1498Szrj       print_rtl_single (dump_file, lc2->loc);
502838fd1498Szrj       lc2 = lc2->next;
502938fd1498Szrj     }
503038fd1498Szrj }
503138fd1498Szrj 
503238fd1498Szrj /* Return true if variables VAR1 and VAR2 are different.  */
503338fd1498Szrj 
503438fd1498Szrj static bool
variable_different_p(variable * var1,variable * var2)503538fd1498Szrj variable_different_p (variable *var1, variable *var2)
503638fd1498Szrj {
503738fd1498Szrj   int i;
503838fd1498Szrj 
503938fd1498Szrj   if (var1 == var2)
504038fd1498Szrj     return false;
504138fd1498Szrj 
504238fd1498Szrj   if (var1->onepart != var2->onepart)
504338fd1498Szrj     return true;
504438fd1498Szrj 
504538fd1498Szrj   if (var1->n_var_parts != var2->n_var_parts)
504638fd1498Szrj     return true;
504738fd1498Szrj 
504838fd1498Szrj   if (var1->onepart && var1->n_var_parts)
504938fd1498Szrj     {
505038fd1498Szrj       gcc_checking_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv)
505138fd1498Szrj 			   && var1->n_var_parts == 1);
505238fd1498Szrj       /* One-part values have locations in a canonical order.  */
505338fd1498Szrj       return onepart_variable_different_p (var1, var2);
505438fd1498Szrj     }
505538fd1498Szrj 
505638fd1498Szrj   for (i = 0; i < var1->n_var_parts; i++)
505738fd1498Szrj     {
505838fd1498Szrj       if (VAR_PART_OFFSET (var1, i) != VAR_PART_OFFSET (var2, i))
505938fd1498Szrj 	return true;
506038fd1498Szrj       if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i]))
506138fd1498Szrj 	return true;
506238fd1498Szrj       if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i]))
506338fd1498Szrj 	return true;
506438fd1498Szrj     }
506538fd1498Szrj   return false;
506638fd1498Szrj }
506738fd1498Szrj 
506838fd1498Szrj /* Return true if dataflow sets OLD_SET and NEW_SET differ.  */
506938fd1498Szrj 
507038fd1498Szrj static bool
dataflow_set_different(dataflow_set * old_set,dataflow_set * new_set)507138fd1498Szrj dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
507238fd1498Szrj {
507338fd1498Szrj   variable_iterator_type hi;
507438fd1498Szrj   variable *var1;
507538fd1498Szrj   bool diffound = false;
507638fd1498Szrj   bool details = (dump_file && (dump_flags & TDF_DETAILS));
507738fd1498Szrj 
507838fd1498Szrj #define RETRUE					\
507938fd1498Szrj   do						\
508038fd1498Szrj     {						\
508138fd1498Szrj       if (!details)				\
508238fd1498Szrj 	return true;				\
508338fd1498Szrj       else					\
508438fd1498Szrj 	diffound = true;			\
508538fd1498Szrj     }						\
508638fd1498Szrj   while (0)
508738fd1498Szrj 
508838fd1498Szrj   if (old_set->vars == new_set->vars)
508938fd1498Szrj     return false;
509038fd1498Szrj 
509138fd1498Szrj   if (shared_hash_htab (old_set->vars)->elements ()
509238fd1498Szrj       != shared_hash_htab (new_set->vars)->elements ())
509338fd1498Szrj     RETRUE;
509438fd1498Szrj 
509538fd1498Szrj   FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (old_set->vars),
509638fd1498Szrj 			       var1, variable, hi)
509738fd1498Szrj     {
509838fd1498Szrj       variable_table_type *htab = shared_hash_htab (new_set->vars);
509938fd1498Szrj       variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv));
510038fd1498Szrj 
510138fd1498Szrj       if (!var2)
510238fd1498Szrj 	{
510338fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
510438fd1498Szrj 	    {
510538fd1498Szrj 	      fprintf (dump_file, "dataflow difference found: removal of:\n");
510638fd1498Szrj 	      dump_var (var1);
510738fd1498Szrj 	    }
510838fd1498Szrj 	  RETRUE;
510938fd1498Szrj 	}
511038fd1498Szrj       else if (variable_different_p (var1, var2))
511138fd1498Szrj 	{
511238fd1498Szrj 	  if (details)
511338fd1498Szrj 	    {
511438fd1498Szrj 	      fprintf (dump_file, "dataflow difference found: "
511538fd1498Szrj 		       "old and new follow:\n");
511638fd1498Szrj 	      dump_var (var1);
511738fd1498Szrj 	      if (dv_onepart_p (var1->dv))
511838fd1498Szrj 		dump_onepart_variable_differences (var1, var2);
511938fd1498Szrj 	      dump_var (var2);
512038fd1498Szrj 	    }
512138fd1498Szrj 	  RETRUE;
512238fd1498Szrj 	}
512338fd1498Szrj     }
512438fd1498Szrj 
512538fd1498Szrj   /* There's no need to traverse the second hashtab unless we want to
512638fd1498Szrj      print the details.  If both have the same number of elements and
512738fd1498Szrj      the second one had all entries found in the first one, then the
512838fd1498Szrj      second can't have any extra entries.  */
512938fd1498Szrj   if (!details)
513038fd1498Szrj     return diffound;
513138fd1498Szrj 
513238fd1498Szrj   FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (new_set->vars),
513338fd1498Szrj 			       var1, variable, hi)
513438fd1498Szrj     {
513538fd1498Szrj       variable_table_type *htab = shared_hash_htab (old_set->vars);
513638fd1498Szrj       variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv));
513738fd1498Szrj       if (!var2)
513838fd1498Szrj 	{
513938fd1498Szrj 	  if (details)
514038fd1498Szrj 	    {
514138fd1498Szrj 	      fprintf (dump_file, "dataflow difference found: addition of:\n");
514238fd1498Szrj 	      dump_var (var1);
514338fd1498Szrj 	    }
514438fd1498Szrj 	  RETRUE;
514538fd1498Szrj 	}
514638fd1498Szrj     }
514738fd1498Szrj 
514838fd1498Szrj #undef RETRUE
514938fd1498Szrj 
515038fd1498Szrj   return diffound;
515138fd1498Szrj }
515238fd1498Szrj 
515338fd1498Szrj /* Free the contents of dataflow set SET.  */
515438fd1498Szrj 
515538fd1498Szrj static void
dataflow_set_destroy(dataflow_set * set)515638fd1498Szrj dataflow_set_destroy (dataflow_set *set)
515738fd1498Szrj {
515838fd1498Szrj   int i;
515938fd1498Szrj 
516038fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
516138fd1498Szrj     attrs_list_clear (&set->regs[i]);
516238fd1498Szrj 
516338fd1498Szrj   shared_hash_destroy (set->vars);
516438fd1498Szrj   set->vars = NULL;
516538fd1498Szrj }
516638fd1498Szrj 
516738fd1498Szrj /* Return true if T is a tracked parameter with non-degenerate record type.  */
516838fd1498Szrj 
516938fd1498Szrj static bool
tracked_record_parameter_p(tree t)517038fd1498Szrj tracked_record_parameter_p (tree t)
517138fd1498Szrj {
517238fd1498Szrj   if (TREE_CODE (t) != PARM_DECL)
517338fd1498Szrj     return false;
517438fd1498Szrj 
517538fd1498Szrj   if (DECL_MODE (t) == BLKmode)
517638fd1498Szrj     return false;
517738fd1498Szrj 
517838fd1498Szrj   tree type = TREE_TYPE (t);
517938fd1498Szrj   if (TREE_CODE (type) != RECORD_TYPE)
518038fd1498Szrj     return false;
518138fd1498Szrj 
518238fd1498Szrj   if (TYPE_FIELDS (type) == NULL_TREE
518338fd1498Szrj       || DECL_CHAIN (TYPE_FIELDS (type)) == NULL_TREE)
518438fd1498Szrj     return false;
518538fd1498Szrj 
518638fd1498Szrj   return true;
518738fd1498Szrj }
518838fd1498Szrj 
518938fd1498Szrj /* Shall EXPR be tracked?  */
519038fd1498Szrj 
519138fd1498Szrj static bool
track_expr_p(tree expr,bool need_rtl)519238fd1498Szrj track_expr_p (tree expr, bool need_rtl)
519338fd1498Szrj {
519438fd1498Szrj   rtx decl_rtl;
519538fd1498Szrj   tree realdecl;
519638fd1498Szrj 
519738fd1498Szrj   if (TREE_CODE (expr) == DEBUG_EXPR_DECL)
519838fd1498Szrj     return DECL_RTL_SET_P (expr);
519938fd1498Szrj 
520038fd1498Szrj   /* If EXPR is not a parameter or a variable do not track it.  */
520138fd1498Szrj   if (!VAR_P (expr) && TREE_CODE (expr) != PARM_DECL)
520238fd1498Szrj     return 0;
520338fd1498Szrj 
520438fd1498Szrj   /* It also must have a name...  */
520538fd1498Szrj   if (!DECL_NAME (expr) && need_rtl)
520638fd1498Szrj     return 0;
520738fd1498Szrj 
520838fd1498Szrj   /* ... and a RTL assigned to it.  */
520938fd1498Szrj   decl_rtl = DECL_RTL_IF_SET (expr);
521038fd1498Szrj   if (!decl_rtl && need_rtl)
521138fd1498Szrj     return 0;
521238fd1498Szrj 
521338fd1498Szrj   /* If this expression is really a debug alias of some other declaration, we
521438fd1498Szrj      don't need to track this expression if the ultimate declaration is
521538fd1498Szrj      ignored.  */
521638fd1498Szrj   realdecl = expr;
521738fd1498Szrj   if (VAR_P (realdecl) && DECL_HAS_DEBUG_EXPR_P (realdecl))
521838fd1498Szrj     {
521938fd1498Szrj       realdecl = DECL_DEBUG_EXPR (realdecl);
522038fd1498Szrj       if (!DECL_P (realdecl))
522138fd1498Szrj 	{
522238fd1498Szrj 	  if (handled_component_p (realdecl)
522338fd1498Szrj 	      || (TREE_CODE (realdecl) == MEM_REF
522438fd1498Szrj 		  && TREE_CODE (TREE_OPERAND (realdecl, 0)) == ADDR_EXPR))
522538fd1498Szrj 	    {
522638fd1498Szrj 	      HOST_WIDE_INT bitsize, bitpos;
522738fd1498Szrj 	      bool reverse;
522838fd1498Szrj 	      tree innerdecl
522938fd1498Szrj 		= get_ref_base_and_extent_hwi (realdecl, &bitpos,
523038fd1498Szrj 					       &bitsize, &reverse);
523138fd1498Szrj 	      if (!innerdecl
523238fd1498Szrj 		  || !DECL_P (innerdecl)
523338fd1498Szrj 		  || DECL_IGNORED_P (innerdecl)
523438fd1498Szrj 		  /* Do not track declarations for parts of tracked record
523538fd1498Szrj 		     parameters since we want to track them as a whole.  */
523638fd1498Szrj 		  || tracked_record_parameter_p (innerdecl)
523738fd1498Szrj 		  || TREE_STATIC (innerdecl)
523838fd1498Szrj 		  || bitsize == 0
523938fd1498Szrj 		  || bitpos + bitsize > 256)
524038fd1498Szrj 		return 0;
524138fd1498Szrj 	      else
524238fd1498Szrj 		realdecl = expr;
524338fd1498Szrj 	    }
524438fd1498Szrj 	  else
524538fd1498Szrj 	    return 0;
524638fd1498Szrj 	}
524738fd1498Szrj     }
524838fd1498Szrj 
524938fd1498Szrj   /* Do not track EXPR if REALDECL it should be ignored for debugging
525038fd1498Szrj      purposes.  */
525138fd1498Szrj   if (DECL_IGNORED_P (realdecl))
525238fd1498Szrj     return 0;
525338fd1498Szrj 
525438fd1498Szrj   /* Do not track global variables until we are able to emit correct location
525538fd1498Szrj      list for them.  */
525638fd1498Szrj   if (TREE_STATIC (realdecl))
525738fd1498Szrj     return 0;
525838fd1498Szrj 
525938fd1498Szrj   /* When the EXPR is a DECL for alias of some variable (see example)
526038fd1498Szrj      the TREE_STATIC flag is not used.  Disable tracking all DECLs whose
526138fd1498Szrj      DECL_RTL contains SYMBOL_REF.
526238fd1498Szrj 
526338fd1498Szrj      Example:
526438fd1498Szrj      extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv")));
526538fd1498Szrj      char **_dl_argv;
526638fd1498Szrj   */
526738fd1498Szrj   if (decl_rtl && MEM_P (decl_rtl)
526838fd1498Szrj       && contains_symbol_ref_p (XEXP (decl_rtl, 0)))
526938fd1498Szrj     return 0;
527038fd1498Szrj 
527138fd1498Szrj   /* If RTX is a memory it should not be very large (because it would be
527238fd1498Szrj      an array or struct).  */
527338fd1498Szrj   if (decl_rtl && MEM_P (decl_rtl))
527438fd1498Szrj     {
527538fd1498Szrj       /* Do not track structures and arrays.  */
527638fd1498Szrj       if ((GET_MODE (decl_rtl) == BLKmode
527738fd1498Szrj 	   || AGGREGATE_TYPE_P (TREE_TYPE (realdecl)))
527838fd1498Szrj 	  && !tracked_record_parameter_p (realdecl))
527938fd1498Szrj 	return 0;
528038fd1498Szrj       if (MEM_SIZE_KNOWN_P (decl_rtl)
528138fd1498Szrj 	  && maybe_gt (MEM_SIZE (decl_rtl), MAX_VAR_PARTS))
528238fd1498Szrj 	return 0;
528338fd1498Szrj     }
528438fd1498Szrj 
528538fd1498Szrj   DECL_CHANGED (expr) = 0;
528638fd1498Szrj   DECL_CHANGED (realdecl) = 0;
528738fd1498Szrj   return 1;
528838fd1498Szrj }
528938fd1498Szrj 
529038fd1498Szrj /* Determine whether a given LOC refers to the same variable part as
529138fd1498Szrj    EXPR+OFFSET.  */
529238fd1498Szrj 
529338fd1498Szrj static bool
same_variable_part_p(rtx loc,tree expr,poly_int64 offset)529438fd1498Szrj same_variable_part_p (rtx loc, tree expr, poly_int64 offset)
529538fd1498Szrj {
529638fd1498Szrj   tree expr2;
529738fd1498Szrj   poly_int64 offset2;
529838fd1498Szrj 
529938fd1498Szrj   if (! DECL_P (expr))
530038fd1498Szrj     return false;
530138fd1498Szrj 
530238fd1498Szrj   if (REG_P (loc))
530338fd1498Szrj     {
530438fd1498Szrj       expr2 = REG_EXPR (loc);
530538fd1498Szrj       offset2 = REG_OFFSET (loc);
530638fd1498Szrj     }
530738fd1498Szrj   else if (MEM_P (loc))
530838fd1498Szrj     {
530938fd1498Szrj       expr2 = MEM_EXPR (loc);
531038fd1498Szrj       offset2 = int_mem_offset (loc);
531138fd1498Szrj     }
531238fd1498Szrj   else
531338fd1498Szrj     return false;
531438fd1498Szrj 
531538fd1498Szrj   if (! expr2 || ! DECL_P (expr2))
531638fd1498Szrj     return false;
531738fd1498Szrj 
531838fd1498Szrj   expr = var_debug_decl (expr);
531938fd1498Szrj   expr2 = var_debug_decl (expr2);
532038fd1498Szrj 
532138fd1498Szrj   return (expr == expr2 && known_eq (offset, offset2));
532238fd1498Szrj }
532338fd1498Szrj 
532438fd1498Szrj /* LOC is a REG or MEM that we would like to track if possible.
532538fd1498Szrj    If EXPR is null, we don't know what expression LOC refers to,
532638fd1498Szrj    otherwise it refers to EXPR + OFFSET.  STORE_REG_P is true if
532738fd1498Szrj    LOC is an lvalue register.
532838fd1498Szrj 
532938fd1498Szrj    Return true if EXPR is nonnull and if LOC, or some lowpart of it,
533038fd1498Szrj    is something we can track.  When returning true, store the mode of
533138fd1498Szrj    the lowpart we can track in *MODE_OUT (if nonnull) and its offset
533238fd1498Szrj    from EXPR in *OFFSET_OUT (if nonnull).  */
533338fd1498Szrj 
533438fd1498Szrj static bool
track_loc_p(rtx loc,tree expr,poly_int64 offset,bool store_reg_p,machine_mode * mode_out,HOST_WIDE_INT * offset_out)533538fd1498Szrj track_loc_p (rtx loc, tree expr, poly_int64 offset, bool store_reg_p,
533638fd1498Szrj 	     machine_mode *mode_out, HOST_WIDE_INT *offset_out)
533738fd1498Szrj {
533838fd1498Szrj   machine_mode mode;
533938fd1498Szrj 
534038fd1498Szrj   if (expr == NULL || !track_expr_p (expr, true))
534138fd1498Szrj     return false;
534238fd1498Szrj 
534338fd1498Szrj   /* If REG was a paradoxical subreg, its REG_ATTRS will describe the
534438fd1498Szrj      whole subreg, but only the old inner part is really relevant.  */
534538fd1498Szrj   mode = GET_MODE (loc);
534638fd1498Szrj   if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc)))
534738fd1498Szrj     {
534838fd1498Szrj       machine_mode pseudo_mode;
534938fd1498Szrj 
535038fd1498Szrj       pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc));
535138fd1498Szrj       if (paradoxical_subreg_p (mode, pseudo_mode))
535238fd1498Szrj 	{
535338fd1498Szrj 	  offset += byte_lowpart_offset (pseudo_mode, mode);
535438fd1498Szrj 	  mode = pseudo_mode;
535538fd1498Szrj 	}
535638fd1498Szrj     }
535738fd1498Szrj 
535838fd1498Szrj   /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself.
535938fd1498Szrj      Do the same if we are storing to a register and EXPR occupies
536038fd1498Szrj      the whole of register LOC; in that case, the whole of EXPR is
536138fd1498Szrj      being changed.  We exclude complex modes from the second case
536238fd1498Szrj      because the real and imaginary parts are represented as separate
536338fd1498Szrj      pseudo registers, even if the whole complex value fits into one
536438fd1498Szrj      hard register.  */
536538fd1498Szrj   if ((paradoxical_subreg_p (mode, DECL_MODE (expr))
536638fd1498Szrj        || (store_reg_p
536738fd1498Szrj 	   && !COMPLEX_MODE_P (DECL_MODE (expr))
536838fd1498Szrj 	   && hard_regno_nregs (REGNO (loc), DECL_MODE (expr)) == 1))
536938fd1498Szrj       && known_eq (offset + byte_lowpart_offset (DECL_MODE (expr), mode), 0))
537038fd1498Szrj     {
537138fd1498Szrj       mode = DECL_MODE (expr);
537238fd1498Szrj       offset = 0;
537338fd1498Szrj     }
537438fd1498Szrj 
537538fd1498Szrj   HOST_WIDE_INT const_offset;
537638fd1498Szrj   if (!track_offset_p (offset, &const_offset))
537738fd1498Szrj     return false;
537838fd1498Szrj 
537938fd1498Szrj   if (mode_out)
538038fd1498Szrj     *mode_out = mode;
538138fd1498Szrj   if (offset_out)
538238fd1498Szrj     *offset_out = const_offset;
538338fd1498Szrj   return true;
538438fd1498Szrj }
538538fd1498Szrj 
538638fd1498Szrj /* Return the MODE lowpart of LOC, or null if LOC is not something we
538738fd1498Szrj    want to track.  When returning nonnull, make sure that the attributes
538838fd1498Szrj    on the returned value are updated.  */
538938fd1498Szrj 
539038fd1498Szrj static rtx
var_lowpart(machine_mode mode,rtx loc)539138fd1498Szrj var_lowpart (machine_mode mode, rtx loc)
539238fd1498Szrj {
539338fd1498Szrj   unsigned int regno;
539438fd1498Szrj 
539538fd1498Szrj   if (GET_MODE (loc) == mode)
539638fd1498Szrj     return loc;
539738fd1498Szrj 
539838fd1498Szrj   if (!REG_P (loc) && !MEM_P (loc))
539938fd1498Szrj     return NULL;
540038fd1498Szrj 
540138fd1498Szrj   poly_uint64 offset = byte_lowpart_offset (mode, GET_MODE (loc));
540238fd1498Szrj 
540338fd1498Szrj   if (MEM_P (loc))
540438fd1498Szrj     return adjust_address_nv (loc, mode, offset);
540538fd1498Szrj 
540638fd1498Szrj   poly_uint64 reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc));
540738fd1498Szrj   regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc),
540838fd1498Szrj 					     reg_offset, mode);
540938fd1498Szrj   return gen_rtx_REG_offset (loc, mode, regno, offset);
541038fd1498Szrj }
541138fd1498Szrj 
541238fd1498Szrj /* Carry information about uses and stores while walking rtx.  */
541338fd1498Szrj 
541438fd1498Szrj struct count_use_info
541538fd1498Szrj {
541638fd1498Szrj   /* The insn where the RTX is.  */
541738fd1498Szrj   rtx_insn *insn;
541838fd1498Szrj 
541938fd1498Szrj   /* The basic block where insn is.  */
542038fd1498Szrj   basic_block bb;
542138fd1498Szrj 
542238fd1498Szrj   /* The array of n_sets sets in the insn, as determined by cselib.  */
542338fd1498Szrj   struct cselib_set *sets;
542438fd1498Szrj   int n_sets;
542538fd1498Szrj 
542638fd1498Szrj   /* True if we're counting stores, false otherwise.  */
542738fd1498Szrj   bool store_p;
542838fd1498Szrj };
542938fd1498Szrj 
543038fd1498Szrj /* Find a VALUE corresponding to X.   */
543138fd1498Szrj 
543238fd1498Szrj static inline cselib_val *
find_use_val(rtx x,machine_mode mode,struct count_use_info * cui)543338fd1498Szrj find_use_val (rtx x, machine_mode mode, struct count_use_info *cui)
543438fd1498Szrj {
543538fd1498Szrj   int i;
543638fd1498Szrj 
543738fd1498Szrj   if (cui->sets)
543838fd1498Szrj     {
543938fd1498Szrj       /* This is called after uses are set up and before stores are
544038fd1498Szrj 	 processed by cselib, so it's safe to look up srcs, but not
544138fd1498Szrj 	 dsts.  So we look up expressions that appear in srcs or in
544238fd1498Szrj 	 dest expressions, but we search the sets array for dests of
544338fd1498Szrj 	 stores.  */
544438fd1498Szrj       if (cui->store_p)
544538fd1498Szrj 	{
544638fd1498Szrj 	  /* Some targets represent memset and memcpy patterns
544738fd1498Szrj 	     by (set (mem:BLK ...) (reg:[QHSD]I ...)) or
544838fd1498Szrj 	     (set (mem:BLK ...) (const_int ...)) or
544938fd1498Szrj 	     (set (mem:BLK ...) (mem:BLK ...)).  Don't return anything
545038fd1498Szrj 	     in that case, otherwise we end up with mode mismatches.  */
545138fd1498Szrj 	  if (mode == BLKmode && MEM_P (x))
545238fd1498Szrj 	    return NULL;
545338fd1498Szrj 	  for (i = 0; i < cui->n_sets; i++)
545438fd1498Szrj 	    if (cui->sets[i].dest == x)
545538fd1498Szrj 	      return cui->sets[i].src_elt;
545638fd1498Szrj 	}
545738fd1498Szrj       else
545838fd1498Szrj 	return cselib_lookup (x, mode, 0, VOIDmode);
545938fd1498Szrj     }
546038fd1498Szrj 
546138fd1498Szrj   return NULL;
546238fd1498Szrj }
546338fd1498Szrj 
546438fd1498Szrj /* Replace all registers and addresses in an expression with VALUE
546538fd1498Szrj    expressions that map back to them, unless the expression is a
546638fd1498Szrj    register.  If no mapping is or can be performed, returns NULL.  */
546738fd1498Szrj 
546838fd1498Szrj static rtx
replace_expr_with_values(rtx loc)546938fd1498Szrj replace_expr_with_values (rtx loc)
547038fd1498Szrj {
547138fd1498Szrj   if (REG_P (loc) || GET_CODE (loc) == ENTRY_VALUE)
547238fd1498Szrj     return NULL;
547338fd1498Szrj   else if (MEM_P (loc))
547438fd1498Szrj     {
547538fd1498Szrj       cselib_val *addr = cselib_lookup (XEXP (loc, 0),
547638fd1498Szrj 					get_address_mode (loc), 0,
547738fd1498Szrj 					GET_MODE (loc));
547838fd1498Szrj       if (addr)
547938fd1498Szrj 	return replace_equiv_address_nv (loc, addr->val_rtx);
548038fd1498Szrj       else
548138fd1498Szrj 	return NULL;
548238fd1498Szrj     }
548338fd1498Szrj   else
548438fd1498Szrj     return cselib_subst_to_values (loc, VOIDmode);
548538fd1498Szrj }
548638fd1498Szrj 
548738fd1498Szrj /* Return true if X contains a DEBUG_EXPR.  */
548838fd1498Szrj 
548938fd1498Szrj static bool
rtx_debug_expr_p(const_rtx x)549038fd1498Szrj rtx_debug_expr_p (const_rtx x)
549138fd1498Szrj {
549238fd1498Szrj   subrtx_iterator::array_type array;
549338fd1498Szrj   FOR_EACH_SUBRTX (iter, array, x, ALL)
549438fd1498Szrj     if (GET_CODE (*iter) == DEBUG_EXPR)
549538fd1498Szrj       return true;
549638fd1498Szrj   return false;
549738fd1498Szrj }
549838fd1498Szrj 
549938fd1498Szrj /* Determine what kind of micro operation to choose for a USE.  Return
550038fd1498Szrj    MO_CLOBBER if no micro operation is to be generated.  */
550138fd1498Szrj 
550238fd1498Szrj static enum micro_operation_type
use_type(rtx loc,struct count_use_info * cui,machine_mode * modep)550338fd1498Szrj use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
550438fd1498Szrj {
550538fd1498Szrj   tree expr;
550638fd1498Szrj 
550738fd1498Szrj   if (cui && cui->sets)
550838fd1498Szrj     {
550938fd1498Szrj       if (GET_CODE (loc) == VAR_LOCATION)
551038fd1498Szrj 	{
551138fd1498Szrj 	  if (track_expr_p (PAT_VAR_LOCATION_DECL (loc), false))
551238fd1498Szrj 	    {
551338fd1498Szrj 	      rtx ploc = PAT_VAR_LOCATION_LOC (loc);
551438fd1498Szrj 	      if (! VAR_LOC_UNKNOWN_P (ploc))
551538fd1498Szrj 		{
551638fd1498Szrj 		  cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1,
551738fd1498Szrj 						   VOIDmode);
551838fd1498Szrj 
551938fd1498Szrj 		  /* ??? flag_float_store and volatile mems are never
552038fd1498Szrj 		     given values, but we could in theory use them for
552138fd1498Szrj 		     locations.  */
552238fd1498Szrj 		  gcc_assert (val || 1);
552338fd1498Szrj 		}
552438fd1498Szrj 	      return MO_VAL_LOC;
552538fd1498Szrj 	    }
552638fd1498Szrj 	  else
552738fd1498Szrj 	    return MO_CLOBBER;
552838fd1498Szrj 	}
552938fd1498Szrj 
553038fd1498Szrj       if (REG_P (loc) || MEM_P (loc))
553138fd1498Szrj 	{
553238fd1498Szrj 	  if (modep)
553338fd1498Szrj 	    *modep = GET_MODE (loc);
553438fd1498Szrj 	  if (cui->store_p)
553538fd1498Szrj 	    {
553638fd1498Szrj 	      if (REG_P (loc)
553738fd1498Szrj 		  || (find_use_val (loc, GET_MODE (loc), cui)
553838fd1498Szrj 		      && cselib_lookup (XEXP (loc, 0),
553938fd1498Szrj 					get_address_mode (loc), 0,
554038fd1498Szrj 					GET_MODE (loc))))
554138fd1498Szrj 		return MO_VAL_SET;
554238fd1498Szrj 	    }
554338fd1498Szrj 	  else
554438fd1498Szrj 	    {
554538fd1498Szrj 	      cselib_val *val = find_use_val (loc, GET_MODE (loc), cui);
554638fd1498Szrj 
554738fd1498Szrj 	      if (val && !cselib_preserved_value_p (val))
554838fd1498Szrj 		return MO_VAL_USE;
554938fd1498Szrj 	    }
555038fd1498Szrj 	}
555138fd1498Szrj     }
555238fd1498Szrj 
555338fd1498Szrj   if (REG_P (loc))
555438fd1498Szrj     {
555538fd1498Szrj       gcc_assert (REGNO (loc) < FIRST_PSEUDO_REGISTER);
555638fd1498Szrj 
555738fd1498Szrj       if (loc == cfa_base_rtx)
555838fd1498Szrj 	return MO_CLOBBER;
555938fd1498Szrj       expr = REG_EXPR (loc);
556038fd1498Szrj 
556138fd1498Szrj       if (!expr)
556238fd1498Szrj 	return MO_USE_NO_VAR;
556338fd1498Szrj       else if (target_for_debug_bind (var_debug_decl (expr)))
556438fd1498Szrj 	return MO_CLOBBER;
556538fd1498Szrj       else if (track_loc_p (loc, expr, REG_OFFSET (loc),
556638fd1498Szrj 			    false, modep, NULL))
556738fd1498Szrj 	return MO_USE;
556838fd1498Szrj       else
556938fd1498Szrj 	return MO_USE_NO_VAR;
557038fd1498Szrj     }
557138fd1498Szrj   else if (MEM_P (loc))
557238fd1498Szrj     {
557338fd1498Szrj       expr = MEM_EXPR (loc);
557438fd1498Szrj 
557538fd1498Szrj       if (!expr)
557638fd1498Szrj 	return MO_CLOBBER;
557738fd1498Szrj       else if (target_for_debug_bind (var_debug_decl (expr)))
557838fd1498Szrj 	return MO_CLOBBER;
557938fd1498Szrj       else if (track_loc_p (loc, expr, int_mem_offset (loc),
558038fd1498Szrj 			    false, modep, NULL)
558138fd1498Szrj 	       /* Multi-part variables shouldn't refer to one-part
558238fd1498Szrj 		  variable names such as VALUEs (never happens) or
558338fd1498Szrj 		  DEBUG_EXPRs (only happens in the presence of debug
558438fd1498Szrj 		  insns).  */
558538fd1498Szrj 	       && (!MAY_HAVE_DEBUG_BIND_INSNS
558638fd1498Szrj 		   || !rtx_debug_expr_p (XEXP (loc, 0))))
558738fd1498Szrj 	return MO_USE;
558838fd1498Szrj       else
558938fd1498Szrj 	return MO_CLOBBER;
559038fd1498Szrj     }
559138fd1498Szrj 
559238fd1498Szrj   return MO_CLOBBER;
559338fd1498Szrj }
559438fd1498Szrj 
559538fd1498Szrj /* Log to OUT information about micro-operation MOPT involving X in
559638fd1498Szrj    INSN of BB.  */
559738fd1498Szrj 
559838fd1498Szrj static inline void
log_op_type(rtx x,basic_block bb,rtx_insn * insn,enum micro_operation_type mopt,FILE * out)559938fd1498Szrj log_op_type (rtx x, basic_block bb, rtx_insn *insn,
560038fd1498Szrj 	     enum micro_operation_type mopt, FILE *out)
560138fd1498Szrj {
560238fd1498Szrj   fprintf (out, "bb %i op %i insn %i %s ",
560338fd1498Szrj 	   bb->index, VTI (bb)->mos.length (),
560438fd1498Szrj 	   INSN_UID (insn), micro_operation_type_name[mopt]);
560538fd1498Szrj   print_inline_rtx (out, x, 2);
560638fd1498Szrj   fputc ('\n', out);
560738fd1498Szrj }
560838fd1498Szrj 
560938fd1498Szrj /* Tell whether the CONCAT used to holds a VALUE and its location
561038fd1498Szrj    needs value resolution, i.e., an attempt of mapping the location
561138fd1498Szrj    back to other incoming values.  */
561238fd1498Szrj #define VAL_NEEDS_RESOLUTION(x) \
561338fd1498Szrj   (RTL_FLAG_CHECK1 ("VAL_NEEDS_RESOLUTION", (x), CONCAT)->volatil)
561438fd1498Szrj /* Whether the location in the CONCAT is a tracked expression, that
561538fd1498Szrj    should also be handled like a MO_USE.  */
561638fd1498Szrj #define VAL_HOLDS_TRACK_EXPR(x) \
561738fd1498Szrj   (RTL_FLAG_CHECK1 ("VAL_HOLDS_TRACK_EXPR", (x), CONCAT)->used)
561838fd1498Szrj /* Whether the location in the CONCAT should be handled like a MO_COPY
561938fd1498Szrj    as well.  */
562038fd1498Szrj #define VAL_EXPR_IS_COPIED(x) \
562138fd1498Szrj   (RTL_FLAG_CHECK1 ("VAL_EXPR_IS_COPIED", (x), CONCAT)->jump)
562238fd1498Szrj /* Whether the location in the CONCAT should be handled like a
562338fd1498Szrj    MO_CLOBBER as well.  */
562438fd1498Szrj #define VAL_EXPR_IS_CLOBBERED(x) \
562538fd1498Szrj   (RTL_FLAG_CHECK1 ("VAL_EXPR_IS_CLOBBERED", (x), CONCAT)->unchanging)
562638fd1498Szrj 
562738fd1498Szrj /* All preserved VALUEs.  */
562838fd1498Szrj static vec<rtx> preserved_values;
562938fd1498Szrj 
563038fd1498Szrj /* Ensure VAL is preserved and remember it in a vector for vt_emit_notes.  */
563138fd1498Szrj 
563238fd1498Szrj static void
preserve_value(cselib_val * val)563338fd1498Szrj preserve_value (cselib_val *val)
563438fd1498Szrj {
563538fd1498Szrj   cselib_preserve_value (val);
563638fd1498Szrj   preserved_values.safe_push (val->val_rtx);
563738fd1498Szrj }
563838fd1498Szrj 
563938fd1498Szrj /* Helper function for MO_VAL_LOC handling.  Return non-zero if
564038fd1498Szrj    any rtxes not suitable for CONST use not replaced by VALUEs
564138fd1498Szrj    are discovered.  */
564238fd1498Szrj 
564338fd1498Szrj static bool
non_suitable_const(const_rtx x)564438fd1498Szrj non_suitable_const (const_rtx x)
564538fd1498Szrj {
564638fd1498Szrj   subrtx_iterator::array_type array;
564738fd1498Szrj   FOR_EACH_SUBRTX (iter, array, x, ALL)
564838fd1498Szrj     {
564938fd1498Szrj       const_rtx x = *iter;
565038fd1498Szrj       switch (GET_CODE (x))
565138fd1498Szrj 	{
565238fd1498Szrj 	case REG:
565338fd1498Szrj 	case DEBUG_EXPR:
565438fd1498Szrj 	case PC:
565538fd1498Szrj 	case SCRATCH:
565638fd1498Szrj 	case CC0:
565738fd1498Szrj 	case ASM_INPUT:
565838fd1498Szrj 	case ASM_OPERANDS:
565938fd1498Szrj 	  return true;
566038fd1498Szrj 	case MEM:
566138fd1498Szrj 	  if (!MEM_READONLY_P (x))
566238fd1498Szrj 	    return true;
566338fd1498Szrj 	  break;
566438fd1498Szrj 	default:
566538fd1498Szrj 	  break;
566638fd1498Szrj 	}
566738fd1498Szrj     }
566838fd1498Szrj   return false;
566938fd1498Szrj }
567038fd1498Szrj 
567138fd1498Szrj /* Add uses (register and memory references) LOC which will be tracked
567238fd1498Szrj    to VTI (bb)->mos.  */
567338fd1498Szrj 
567438fd1498Szrj static void
add_uses(rtx loc,struct count_use_info * cui)567538fd1498Szrj add_uses (rtx loc, struct count_use_info *cui)
567638fd1498Szrj {
567738fd1498Szrj   machine_mode mode = VOIDmode;
567838fd1498Szrj   enum micro_operation_type type = use_type (loc, cui, &mode);
567938fd1498Szrj 
568038fd1498Szrj   if (type != MO_CLOBBER)
568138fd1498Szrj     {
568238fd1498Szrj       basic_block bb = cui->bb;
568338fd1498Szrj       micro_operation mo;
568438fd1498Szrj 
568538fd1498Szrj       mo.type = type;
568638fd1498Szrj       mo.u.loc = type == MO_USE ? var_lowpart (mode, loc) : loc;
568738fd1498Szrj       mo.insn = cui->insn;
568838fd1498Szrj 
568938fd1498Szrj       if (type == MO_VAL_LOC)
569038fd1498Szrj 	{
569138fd1498Szrj 	  rtx oloc = loc;
569238fd1498Szrj 	  rtx vloc = PAT_VAR_LOCATION_LOC (oloc);
569338fd1498Szrj 	  cselib_val *val;
569438fd1498Szrj 
569538fd1498Szrj 	  gcc_assert (cui->sets);
569638fd1498Szrj 
569738fd1498Szrj 	  if (MEM_P (vloc)
569838fd1498Szrj 	      && !REG_P (XEXP (vloc, 0))
569938fd1498Szrj 	      && !MEM_P (XEXP (vloc, 0)))
570038fd1498Szrj 	    {
570138fd1498Szrj 	      rtx mloc = vloc;
570238fd1498Szrj 	      machine_mode address_mode = get_address_mode (mloc);
570338fd1498Szrj 	      cselib_val *val
570438fd1498Szrj 		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
570538fd1498Szrj 				 GET_MODE (mloc));
570638fd1498Szrj 
570738fd1498Szrj 	      if (val && !cselib_preserved_value_p (val))
570838fd1498Szrj 		preserve_value (val);
570938fd1498Szrj 	    }
571038fd1498Szrj 
571138fd1498Szrj 	  if (CONSTANT_P (vloc)
571238fd1498Szrj 	      && (GET_CODE (vloc) != CONST || non_suitable_const (vloc)))
571338fd1498Szrj 	    /* For constants don't look up any value.  */;
571438fd1498Szrj 	  else if (!VAR_LOC_UNKNOWN_P (vloc) && !unsuitable_loc (vloc)
571538fd1498Szrj 		   && (val = find_use_val (vloc, GET_MODE (oloc), cui)))
571638fd1498Szrj 	    {
571738fd1498Szrj 	      machine_mode mode2;
571838fd1498Szrj 	      enum micro_operation_type type2;
571938fd1498Szrj 	      rtx nloc = NULL;
572038fd1498Szrj 	      bool resolvable = REG_P (vloc) || MEM_P (vloc);
572138fd1498Szrj 
572238fd1498Szrj 	      if (resolvable)
572338fd1498Szrj 		nloc = replace_expr_with_values (vloc);
572438fd1498Szrj 
572538fd1498Szrj 	      if (nloc)
572638fd1498Szrj 		{
572738fd1498Szrj 		  oloc = shallow_copy_rtx (oloc);
572838fd1498Szrj 		  PAT_VAR_LOCATION_LOC (oloc) = nloc;
572938fd1498Szrj 		}
573038fd1498Szrj 
573138fd1498Szrj 	      oloc = gen_rtx_CONCAT (mode, val->val_rtx, oloc);
573238fd1498Szrj 
573338fd1498Szrj 	      type2 = use_type (vloc, 0, &mode2);
573438fd1498Szrj 
573538fd1498Szrj 	      gcc_assert (type2 == MO_USE || type2 == MO_USE_NO_VAR
573638fd1498Szrj 			  || type2 == MO_CLOBBER);
573738fd1498Szrj 
573838fd1498Szrj 	      if (type2 == MO_CLOBBER
573938fd1498Szrj 		  && !cselib_preserved_value_p (val))
574038fd1498Szrj 		{
574138fd1498Szrj 		  VAL_NEEDS_RESOLUTION (oloc) = resolvable;
574238fd1498Szrj 		  preserve_value (val);
574338fd1498Szrj 		}
574438fd1498Szrj 	    }
574538fd1498Szrj 	  else if (!VAR_LOC_UNKNOWN_P (vloc))
574638fd1498Szrj 	    {
574738fd1498Szrj 	      oloc = shallow_copy_rtx (oloc);
574838fd1498Szrj 	      PAT_VAR_LOCATION_LOC (oloc) = gen_rtx_UNKNOWN_VAR_LOC ();
574938fd1498Szrj 	    }
575038fd1498Szrj 
575138fd1498Szrj 	  mo.u.loc = oloc;
575238fd1498Szrj 	}
575338fd1498Szrj       else if (type == MO_VAL_USE)
575438fd1498Szrj 	{
575538fd1498Szrj 	  machine_mode mode2 = VOIDmode;
575638fd1498Szrj 	  enum micro_operation_type type2;
575738fd1498Szrj 	  cselib_val *val = find_use_val (loc, GET_MODE (loc), cui);
575838fd1498Szrj 	  rtx vloc, oloc = loc, nloc;
575938fd1498Szrj 
576038fd1498Szrj 	  gcc_assert (cui->sets);
576138fd1498Szrj 
576238fd1498Szrj 	  if (MEM_P (oloc)
576338fd1498Szrj 	      && !REG_P (XEXP (oloc, 0))
576438fd1498Szrj 	      && !MEM_P (XEXP (oloc, 0)))
576538fd1498Szrj 	    {
576638fd1498Szrj 	      rtx mloc = oloc;
576738fd1498Szrj 	      machine_mode address_mode = get_address_mode (mloc);
576838fd1498Szrj 	      cselib_val *val
576938fd1498Szrj 		= cselib_lookup (XEXP (mloc, 0), address_mode, 0,
577038fd1498Szrj 				 GET_MODE (mloc));
577138fd1498Szrj 
577238fd1498Szrj 	      if (val && !cselib_preserved_value_p (val))
577338fd1498Szrj 		preserve_value (val);
577438fd1498Szrj 	    }
577538fd1498Szrj 
577638fd1498Szrj 	  type2 = use_type (loc, 0, &mode2);
577738fd1498Szrj 
577838fd1498Szrj 	  gcc_assert (type2 == MO_USE || type2 == MO_USE_NO_VAR
577938fd1498Szrj 		      || type2 == MO_CLOBBER);
578038fd1498Szrj 
578138fd1498Szrj 	  if (type2 == MO_USE)
578238fd1498Szrj 	    vloc = var_lowpart (mode2, loc);
578338fd1498Szrj 	  else
578438fd1498Szrj 	    vloc = oloc;
578538fd1498Szrj 
578638fd1498Szrj 	  /* The loc of a MO_VAL_USE may have two forms:
578738fd1498Szrj 
578838fd1498Szrj 	     (concat val src): val is at src, a value-based
578938fd1498Szrj 	     representation.
579038fd1498Szrj 
579138fd1498Szrj 	     (concat (concat val use) src): same as above, with use as
579238fd1498Szrj 	     the MO_USE tracked value, if it differs from src.
579338fd1498Szrj 
579438fd1498Szrj 	  */
579538fd1498Szrj 
579638fd1498Szrj 	  gcc_checking_assert (REG_P (loc) || MEM_P (loc));
579738fd1498Szrj 	  nloc = replace_expr_with_values (loc);
579838fd1498Szrj 	  if (!nloc)
579938fd1498Szrj 	    nloc = oloc;
580038fd1498Szrj 
580138fd1498Szrj 	  if (vloc != nloc)
580238fd1498Szrj 	    oloc = gen_rtx_CONCAT (mode2, val->val_rtx, vloc);
580338fd1498Szrj 	  else
580438fd1498Szrj 	    oloc = val->val_rtx;
580538fd1498Szrj 
580638fd1498Szrj 	  mo.u.loc = gen_rtx_CONCAT (mode, oloc, nloc);
580738fd1498Szrj 
580838fd1498Szrj 	  if (type2 == MO_USE)
580938fd1498Szrj 	    VAL_HOLDS_TRACK_EXPR (mo.u.loc) = 1;
581038fd1498Szrj 	  if (!cselib_preserved_value_p (val))
581138fd1498Szrj 	    {
581238fd1498Szrj 	      VAL_NEEDS_RESOLUTION (mo.u.loc) = 1;
581338fd1498Szrj 	      preserve_value (val);
581438fd1498Szrj 	    }
581538fd1498Szrj 	}
581638fd1498Szrj       else
581738fd1498Szrj 	gcc_assert (type == MO_USE || type == MO_USE_NO_VAR);
581838fd1498Szrj 
581938fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
582038fd1498Szrj 	log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file);
582138fd1498Szrj       VTI (bb)->mos.safe_push (mo);
582238fd1498Szrj     }
582338fd1498Szrj }
582438fd1498Szrj 
582538fd1498Szrj /* Helper function for finding all uses of REG/MEM in X in insn INSN.  */
582638fd1498Szrj 
582738fd1498Szrj static void
add_uses_1(rtx * x,void * cui)582838fd1498Szrj add_uses_1 (rtx *x, void *cui)
582938fd1498Szrj {
583038fd1498Szrj   subrtx_var_iterator::array_type array;
583138fd1498Szrj   FOR_EACH_SUBRTX_VAR (iter, array, *x, NONCONST)
583238fd1498Szrj     add_uses (*iter, (struct count_use_info *) cui);
583338fd1498Szrj }
583438fd1498Szrj 
583538fd1498Szrj /* This is the value used during expansion of locations.  We want it
583638fd1498Szrj    to be unbounded, so that variables expanded deep in a recursion
583738fd1498Szrj    nest are fully evaluated, so that their values are cached
583838fd1498Szrj    correctly.  We avoid recursion cycles through other means, and we
583938fd1498Szrj    don't unshare RTL, so excess complexity is not a problem.  */
584038fd1498Szrj #define EXPR_DEPTH (INT_MAX)
584138fd1498Szrj /* We use this to keep too-complex expressions from being emitted as
584238fd1498Szrj    location notes, and then to debug information.  Users can trade
584338fd1498Szrj    compile time for ridiculously complex expressions, although they're
584438fd1498Szrj    seldom useful, and they may often have to be discarded as not
584538fd1498Szrj    representable anyway.  */
584638fd1498Szrj #define EXPR_USE_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
584738fd1498Szrj 
584838fd1498Szrj /* Attempt to reverse the EXPR operation in the debug info and record
584938fd1498Szrj    it in the cselib table.  Say for reg1 = reg2 + 6 even when reg2 is
585038fd1498Szrj    no longer live we can express its value as VAL - 6.  */
585138fd1498Szrj 
585238fd1498Szrj static void
reverse_op(rtx val,const_rtx expr,rtx_insn * insn)585338fd1498Szrj reverse_op (rtx val, const_rtx expr, rtx_insn *insn)
585438fd1498Szrj {
585538fd1498Szrj   rtx src, arg, ret;
585638fd1498Szrj   cselib_val *v;
585738fd1498Szrj   struct elt_loc_list *l;
585838fd1498Szrj   enum rtx_code code;
585938fd1498Szrj   int count;
586038fd1498Szrj 
586138fd1498Szrj   if (GET_CODE (expr) != SET)
586238fd1498Szrj     return;
586338fd1498Szrj 
586438fd1498Szrj   if (!REG_P (SET_DEST (expr)) || GET_MODE (val) != GET_MODE (SET_DEST (expr)))
586538fd1498Szrj     return;
586638fd1498Szrj 
586738fd1498Szrj   src = SET_SRC (expr);
586838fd1498Szrj   switch (GET_CODE (src))
586938fd1498Szrj     {
587038fd1498Szrj     case PLUS:
587138fd1498Szrj     case MINUS:
587238fd1498Szrj     case XOR:
587338fd1498Szrj     case NOT:
587438fd1498Szrj     case NEG:
587538fd1498Szrj       if (!REG_P (XEXP (src, 0)))
587638fd1498Szrj 	return;
587738fd1498Szrj       break;
587838fd1498Szrj     case SIGN_EXTEND:
587938fd1498Szrj     case ZERO_EXTEND:
588038fd1498Szrj       if (!REG_P (XEXP (src, 0)) && !MEM_P (XEXP (src, 0)))
588138fd1498Szrj 	return;
588238fd1498Szrj       break;
588338fd1498Szrj     default:
588438fd1498Szrj       return;
588538fd1498Szrj     }
588638fd1498Szrj 
588738fd1498Szrj   if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx)
588838fd1498Szrj     return;
588938fd1498Szrj 
589038fd1498Szrj   v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0, VOIDmode);
589138fd1498Szrj   if (!v || !cselib_preserved_value_p (v))
589238fd1498Szrj     return;
589338fd1498Szrj 
589438fd1498Szrj   /* Use canonical V to avoid creating multiple redundant expressions
589538fd1498Szrj      for different VALUES equivalent to V.  */
589638fd1498Szrj   v = canonical_cselib_val (v);
589738fd1498Szrj 
589838fd1498Szrj   /* Adding a reverse op isn't useful if V already has an always valid
589938fd1498Szrj      location.  Ignore ENTRY_VALUE, while it is always constant, we should
590038fd1498Szrj      prefer non-ENTRY_VALUE locations whenever possible.  */
590138fd1498Szrj   for (l = v->locs, count = 0; l; l = l->next, count++)
590238fd1498Szrj     if (CONSTANT_P (l->loc)
590338fd1498Szrj 	&& (GET_CODE (l->loc) != CONST || !references_value_p (l->loc, 0)))
590438fd1498Szrj       return;
590538fd1498Szrj     /* Avoid creating too large locs lists.  */
590638fd1498Szrj     else if (count == PARAM_VALUE (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE))
590738fd1498Szrj       return;
590838fd1498Szrj 
590938fd1498Szrj   switch (GET_CODE (src))
591038fd1498Szrj     {
591138fd1498Szrj     case NOT:
591238fd1498Szrj     case NEG:
591338fd1498Szrj       if (GET_MODE (v->val_rtx) != GET_MODE (val))
591438fd1498Szrj 	return;
591538fd1498Szrj       ret = gen_rtx_fmt_e (GET_CODE (src), GET_MODE (val), val);
591638fd1498Szrj       break;
591738fd1498Szrj     case SIGN_EXTEND:
591838fd1498Szrj     case ZERO_EXTEND:
591938fd1498Szrj       ret = gen_lowpart_SUBREG (GET_MODE (v->val_rtx), val);
592038fd1498Szrj       break;
592138fd1498Szrj     case XOR:
592238fd1498Szrj       code = XOR;
592338fd1498Szrj       goto binary;
592438fd1498Szrj     case PLUS:
592538fd1498Szrj       code = MINUS;
592638fd1498Szrj       goto binary;
592738fd1498Szrj     case MINUS:
592838fd1498Szrj       code = PLUS;
592938fd1498Szrj       goto binary;
593038fd1498Szrj     binary:
593138fd1498Szrj       if (GET_MODE (v->val_rtx) != GET_MODE (val))
593238fd1498Szrj 	return;
593338fd1498Szrj       arg = XEXP (src, 1);
593438fd1498Szrj       if (!CONST_INT_P (arg) && GET_CODE (arg) != SYMBOL_REF)
593538fd1498Szrj 	{
593638fd1498Szrj 	  arg = cselib_expand_value_rtx (arg, scratch_regs, 5);
593738fd1498Szrj 	  if (arg == NULL_RTX)
593838fd1498Szrj 	    return;
593938fd1498Szrj 	  if (!CONST_INT_P (arg) && GET_CODE (arg) != SYMBOL_REF)
594038fd1498Szrj 	    return;
594138fd1498Szrj 	}
594238fd1498Szrj       ret = simplify_gen_binary (code, GET_MODE (val), val, arg);
594338fd1498Szrj       break;
594438fd1498Szrj     default:
594538fd1498Szrj       gcc_unreachable ();
594638fd1498Szrj     }
594738fd1498Szrj 
594838fd1498Szrj   cselib_add_permanent_equiv (v, ret, insn);
594938fd1498Szrj }
595038fd1498Szrj 
595138fd1498Szrj /* Add stores (register and memory references) LOC which will be tracked
595238fd1498Szrj    to VTI (bb)->mos.  EXPR is the RTL expression containing the store.
595338fd1498Szrj    CUIP->insn is instruction which the LOC is part of.  */
595438fd1498Szrj 
595538fd1498Szrj static void
add_stores(rtx loc,const_rtx expr,void * cuip)595638fd1498Szrj add_stores (rtx loc, const_rtx expr, void *cuip)
595738fd1498Szrj {
595838fd1498Szrj   machine_mode mode = VOIDmode, mode2;
595938fd1498Szrj   struct count_use_info *cui = (struct count_use_info *)cuip;
596038fd1498Szrj   basic_block bb = cui->bb;
596138fd1498Szrj   micro_operation mo;
596238fd1498Szrj   rtx oloc = loc, nloc, src = NULL;
596338fd1498Szrj   enum micro_operation_type type = use_type (loc, cui, &mode);
596438fd1498Szrj   bool track_p = false;
596538fd1498Szrj   cselib_val *v;
596638fd1498Szrj   bool resolve, preserve;
596738fd1498Szrj 
596838fd1498Szrj   if (type == MO_CLOBBER)
596938fd1498Szrj     return;
597038fd1498Szrj 
597138fd1498Szrj   mode2 = mode;
597238fd1498Szrj 
597338fd1498Szrj   if (REG_P (loc))
597438fd1498Szrj     {
597538fd1498Szrj       gcc_assert (loc != cfa_base_rtx);
597638fd1498Szrj       if ((GET_CODE (expr) == CLOBBER && type != MO_VAL_SET)
597738fd1498Szrj 	  || !(track_p = use_type (loc, NULL, &mode2) == MO_USE)
597838fd1498Szrj 	  || GET_CODE (expr) == CLOBBER)
597938fd1498Szrj 	{
598038fd1498Szrj 	  mo.type = MO_CLOBBER;
598138fd1498Szrj 	  mo.u.loc = loc;
598238fd1498Szrj 	  if (GET_CODE (expr) == SET
598338fd1498Szrj 	      && (SET_DEST (expr) == loc
598438fd1498Szrj 		  || (GET_CODE (SET_DEST (expr)) == STRICT_LOW_PART
598538fd1498Szrj 		      && XEXP (SET_DEST (expr), 0) == loc))
598638fd1498Szrj 	      && !unsuitable_loc (SET_SRC (expr))
598738fd1498Szrj 	      && find_use_val (loc, mode, cui))
598838fd1498Szrj 	    {
598938fd1498Szrj 	      gcc_checking_assert (type == MO_VAL_SET);
599038fd1498Szrj 	      mo.u.loc = gen_rtx_SET (loc, SET_SRC (expr));
599138fd1498Szrj 	    }
599238fd1498Szrj 	}
599338fd1498Szrj       else
599438fd1498Szrj 	{
599538fd1498Szrj 	  if (GET_CODE (expr) == SET
599638fd1498Szrj 	      && SET_DEST (expr) == loc
599738fd1498Szrj 	      && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
599838fd1498Szrj 	    src = var_lowpart (mode2, SET_SRC (expr));
599938fd1498Szrj 	  loc = var_lowpart (mode2, loc);
600038fd1498Szrj 
600138fd1498Szrj 	  if (src == NULL)
600238fd1498Szrj 	    {
600338fd1498Szrj 	      mo.type = MO_SET;
600438fd1498Szrj 	      mo.u.loc = loc;
600538fd1498Szrj 	    }
600638fd1498Szrj 	  else
600738fd1498Szrj 	    {
600838fd1498Szrj 	      rtx xexpr = gen_rtx_SET (loc, src);
600938fd1498Szrj 	      if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
601038fd1498Szrj 		{
601138fd1498Szrj 		  /* If this is an instruction copying (part of) a parameter
601238fd1498Szrj 		     passed by invisible reference to its register location,
601338fd1498Szrj 		     pretend it's a SET so that the initial memory location
601438fd1498Szrj 		     is discarded, as the parameter register can be reused
601538fd1498Szrj 		     for other purposes and we do not track locations based
601638fd1498Szrj 		     on generic registers.  */
601738fd1498Szrj 		  if (MEM_P (src)
601838fd1498Szrj 		      && REG_EXPR (loc)
601938fd1498Szrj 		      && TREE_CODE (REG_EXPR (loc)) == PARM_DECL
602038fd1498Szrj 		      && DECL_MODE (REG_EXPR (loc)) != BLKmode
602138fd1498Szrj 		      && MEM_P (DECL_INCOMING_RTL (REG_EXPR (loc)))
602238fd1498Szrj 		      && XEXP (DECL_INCOMING_RTL (REG_EXPR (loc)), 0)
602338fd1498Szrj 			 != arg_pointer_rtx)
602438fd1498Szrj 		    mo.type = MO_SET;
602538fd1498Szrj 		  else
602638fd1498Szrj 		    mo.type = MO_COPY;
602738fd1498Szrj 		}
602838fd1498Szrj 	      else
602938fd1498Szrj 		mo.type = MO_SET;
603038fd1498Szrj 	      mo.u.loc = xexpr;
603138fd1498Szrj 	    }
603238fd1498Szrj 	}
603338fd1498Szrj       mo.insn = cui->insn;
603438fd1498Szrj     }
603538fd1498Szrj   else if (MEM_P (loc)
603638fd1498Szrj 	   && ((track_p = use_type (loc, NULL, &mode2) == MO_USE)
603738fd1498Szrj 	       || cui->sets))
603838fd1498Szrj     {
603938fd1498Szrj       if (MEM_P (loc) && type == MO_VAL_SET
604038fd1498Szrj 	  && !REG_P (XEXP (loc, 0))
604138fd1498Szrj 	  && !MEM_P (XEXP (loc, 0)))
604238fd1498Szrj 	{
604338fd1498Szrj 	  rtx mloc = loc;
604438fd1498Szrj 	  machine_mode address_mode = get_address_mode (mloc);
604538fd1498Szrj 	  cselib_val *val = cselib_lookup (XEXP (mloc, 0),
604638fd1498Szrj 					   address_mode, 0,
604738fd1498Szrj 					   GET_MODE (mloc));
604838fd1498Szrj 
604938fd1498Szrj 	  if (val && !cselib_preserved_value_p (val))
605038fd1498Szrj 	    preserve_value (val);
605138fd1498Szrj 	}
605238fd1498Szrj 
605338fd1498Szrj       if (GET_CODE (expr) == CLOBBER || !track_p)
605438fd1498Szrj 	{
605538fd1498Szrj 	  mo.type = MO_CLOBBER;
605638fd1498Szrj 	  mo.u.loc = track_p ? var_lowpart (mode2, loc) : loc;
605738fd1498Szrj 	}
605838fd1498Szrj       else
605938fd1498Szrj 	{
606038fd1498Szrj 	  if (GET_CODE (expr) == SET
606138fd1498Szrj 	      && SET_DEST (expr) == loc
606238fd1498Szrj 	      && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
606338fd1498Szrj 	    src = var_lowpart (mode2, SET_SRC (expr));
606438fd1498Szrj 	  loc = var_lowpart (mode2, loc);
606538fd1498Szrj 
606638fd1498Szrj 	  if (src == NULL)
606738fd1498Szrj 	    {
606838fd1498Szrj 	      mo.type = MO_SET;
606938fd1498Szrj 	      mo.u.loc = loc;
607038fd1498Szrj 	    }
607138fd1498Szrj 	  else
607238fd1498Szrj 	    {
607338fd1498Szrj 	      rtx xexpr = gen_rtx_SET (loc, src);
607438fd1498Szrj 	      if (same_variable_part_p (SET_SRC (xexpr),
607538fd1498Szrj 					MEM_EXPR (loc),
607638fd1498Szrj 					int_mem_offset (loc)))
607738fd1498Szrj 		mo.type = MO_COPY;
607838fd1498Szrj 	      else
607938fd1498Szrj 		mo.type = MO_SET;
608038fd1498Szrj 	      mo.u.loc = xexpr;
608138fd1498Szrj 	    }
608238fd1498Szrj 	}
608338fd1498Szrj       mo.insn = cui->insn;
608438fd1498Szrj     }
608538fd1498Szrj   else
608638fd1498Szrj     return;
608738fd1498Szrj 
608838fd1498Szrj   if (type != MO_VAL_SET)
608938fd1498Szrj     goto log_and_return;
609038fd1498Szrj 
609138fd1498Szrj   v = find_use_val (oloc, mode, cui);
609238fd1498Szrj 
609338fd1498Szrj   if (!v)
609438fd1498Szrj     goto log_and_return;
609538fd1498Szrj 
609638fd1498Szrj   resolve = preserve = !cselib_preserved_value_p (v);
609738fd1498Szrj 
609838fd1498Szrj   /* We cannot track values for multiple-part variables, so we track only
609938fd1498Szrj      locations for tracked record parameters.  */
610038fd1498Szrj   if (track_p
610138fd1498Szrj       && REG_P (loc)
610238fd1498Szrj       && REG_EXPR (loc)
610338fd1498Szrj       && tracked_record_parameter_p (REG_EXPR (loc)))
610438fd1498Szrj     {
610538fd1498Szrj       /* Although we don't use the value here, it could be used later by the
610638fd1498Szrj 	 mere virtue of its existence as the operand of the reverse operation
610738fd1498Szrj 	 that gave rise to it (typically extension/truncation).  Make sure it
610838fd1498Szrj 	 is preserved as required by vt_expand_var_loc_chain.  */
610938fd1498Szrj       if (preserve)
611038fd1498Szrj 	preserve_value (v);
611138fd1498Szrj       goto log_and_return;
611238fd1498Szrj     }
611338fd1498Szrj 
611438fd1498Szrj   if (loc == stack_pointer_rtx
611538fd1498Szrj       && hard_frame_pointer_adjustment != -1
611638fd1498Szrj       && preserve)
611738fd1498Szrj     cselib_set_value_sp_based (v);
611838fd1498Szrj 
611938fd1498Szrj   nloc = replace_expr_with_values (oloc);
612038fd1498Szrj   if (nloc)
612138fd1498Szrj     oloc = nloc;
612238fd1498Szrj 
612338fd1498Szrj   if (GET_CODE (PATTERN (cui->insn)) == COND_EXEC)
612438fd1498Szrj     {
612538fd1498Szrj       cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode);
612638fd1498Szrj 
612738fd1498Szrj       if (oval == v)
612838fd1498Szrj 	return;
612938fd1498Szrj       gcc_assert (REG_P (oloc) || MEM_P (oloc));
613038fd1498Szrj 
613138fd1498Szrj       if (oval && !cselib_preserved_value_p (oval))
613238fd1498Szrj 	{
613338fd1498Szrj 	  micro_operation moa;
613438fd1498Szrj 
613538fd1498Szrj 	  preserve_value (oval);
613638fd1498Szrj 
613738fd1498Szrj 	  moa.type = MO_VAL_USE;
613838fd1498Szrj 	  moa.u.loc = gen_rtx_CONCAT (mode, oval->val_rtx, oloc);
613938fd1498Szrj 	  VAL_NEEDS_RESOLUTION (moa.u.loc) = 1;
614038fd1498Szrj 	  moa.insn = cui->insn;
614138fd1498Szrj 
614238fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
614338fd1498Szrj 	    log_op_type (moa.u.loc, cui->bb, cui->insn,
614438fd1498Szrj 			 moa.type, dump_file);
614538fd1498Szrj 	  VTI (bb)->mos.safe_push (moa);
614638fd1498Szrj 	}
614738fd1498Szrj 
614838fd1498Szrj       resolve = false;
614938fd1498Szrj     }
615038fd1498Szrj   else if (resolve && GET_CODE (mo.u.loc) == SET)
615138fd1498Szrj     {
615238fd1498Szrj       if (REG_P (SET_SRC (expr)) || MEM_P (SET_SRC (expr)))
615338fd1498Szrj 	nloc = replace_expr_with_values (SET_SRC (expr));
615438fd1498Szrj       else
615538fd1498Szrj 	nloc = NULL_RTX;
615638fd1498Szrj 
615738fd1498Szrj       /* Avoid the mode mismatch between oexpr and expr.  */
615838fd1498Szrj       if (!nloc && mode != mode2)
615938fd1498Szrj 	{
616038fd1498Szrj 	  nloc = SET_SRC (expr);
616138fd1498Szrj 	  gcc_assert (oloc == SET_DEST (expr));
616238fd1498Szrj 	}
616338fd1498Szrj 
616438fd1498Szrj       if (nloc && nloc != SET_SRC (mo.u.loc))
616538fd1498Szrj 	oloc = gen_rtx_SET (oloc, nloc);
616638fd1498Szrj       else
616738fd1498Szrj 	{
616838fd1498Szrj 	  if (oloc == SET_DEST (mo.u.loc))
616938fd1498Szrj 	    /* No point in duplicating.  */
617038fd1498Szrj 	    oloc = mo.u.loc;
617138fd1498Szrj 	  if (!REG_P (SET_SRC (mo.u.loc)))
617238fd1498Szrj 	    resolve = false;
617338fd1498Szrj 	}
617438fd1498Szrj     }
617538fd1498Szrj   else if (!resolve)
617638fd1498Szrj     {
617738fd1498Szrj       if (GET_CODE (mo.u.loc) == SET
617838fd1498Szrj 	  && oloc == SET_DEST (mo.u.loc))
617938fd1498Szrj 	/* No point in duplicating.  */
618038fd1498Szrj 	oloc = mo.u.loc;
618138fd1498Szrj     }
618238fd1498Szrj   else
618338fd1498Szrj     resolve = false;
618438fd1498Szrj 
618538fd1498Szrj   loc = gen_rtx_CONCAT (mode, v->val_rtx, oloc);
618638fd1498Szrj 
618738fd1498Szrj   if (mo.u.loc != oloc)
618838fd1498Szrj     loc = gen_rtx_CONCAT (GET_MODE (mo.u.loc), loc, mo.u.loc);
618938fd1498Szrj 
619038fd1498Szrj   /* The loc of a MO_VAL_SET may have various forms:
619138fd1498Szrj 
619238fd1498Szrj      (concat val dst): dst now holds val
619338fd1498Szrj 
619438fd1498Szrj      (concat val (set dst src)): dst now holds val, copied from src
619538fd1498Szrj 
619638fd1498Szrj      (concat (concat val dstv) dst): dst now holds val; dstv is dst
619738fd1498Szrj      after replacing mems and non-top-level regs with values.
619838fd1498Szrj 
619938fd1498Szrj      (concat (concat val dstv) (set dst src)): dst now holds val,
620038fd1498Szrj      copied from src.  dstv is a value-based representation of dst, if
620138fd1498Szrj      it differs from dst.  If resolution is needed, src is a REG, and
620238fd1498Szrj      its mode is the same as that of val.
620338fd1498Szrj 
620438fd1498Szrj      (concat (concat val (set dstv srcv)) (set dst src)): src
620538fd1498Szrj      copied to dst, holding val.  dstv and srcv are value-based
620638fd1498Szrj      representations of dst and src, respectively.
620738fd1498Szrj 
620838fd1498Szrj   */
620938fd1498Szrj 
621038fd1498Szrj   if (GET_CODE (PATTERN (cui->insn)) != COND_EXEC)
621138fd1498Szrj     reverse_op (v->val_rtx, expr, cui->insn);
621238fd1498Szrj 
621338fd1498Szrj   mo.u.loc = loc;
621438fd1498Szrj 
621538fd1498Szrj   if (track_p)
621638fd1498Szrj     VAL_HOLDS_TRACK_EXPR (loc) = 1;
621738fd1498Szrj   if (preserve)
621838fd1498Szrj     {
621938fd1498Szrj       VAL_NEEDS_RESOLUTION (loc) = resolve;
622038fd1498Szrj       preserve_value (v);
622138fd1498Szrj     }
622238fd1498Szrj   if (mo.type == MO_CLOBBER)
622338fd1498Szrj     VAL_EXPR_IS_CLOBBERED (loc) = 1;
622438fd1498Szrj   if (mo.type == MO_COPY)
622538fd1498Szrj     VAL_EXPR_IS_COPIED (loc) = 1;
622638fd1498Szrj 
622738fd1498Szrj   mo.type = MO_VAL_SET;
622838fd1498Szrj 
622938fd1498Szrj  log_and_return:
623038fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
623138fd1498Szrj     log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file);
623238fd1498Szrj   VTI (bb)->mos.safe_push (mo);
623338fd1498Szrj }
623438fd1498Szrj 
623538fd1498Szrj /* Arguments to the call.  */
623638fd1498Szrj static rtx call_arguments;
623738fd1498Szrj 
623838fd1498Szrj /* Compute call_arguments.  */
623938fd1498Szrj 
624038fd1498Szrj static void
prepare_call_arguments(basic_block bb,rtx_insn * insn)624138fd1498Szrj prepare_call_arguments (basic_block bb, rtx_insn *insn)
624238fd1498Szrj {
624338fd1498Szrj   rtx link, x, call;
624438fd1498Szrj   rtx prev, cur, next;
624538fd1498Szrj   rtx this_arg = NULL_RTX;
624638fd1498Szrj   tree type = NULL_TREE, t, fndecl = NULL_TREE;
624738fd1498Szrj   tree obj_type_ref = NULL_TREE;
624838fd1498Szrj   CUMULATIVE_ARGS args_so_far_v;
624938fd1498Szrj   cumulative_args_t args_so_far;
625038fd1498Szrj 
625138fd1498Szrj   memset (&args_so_far_v, 0, sizeof (args_so_far_v));
625238fd1498Szrj   args_so_far = pack_cumulative_args (&args_so_far_v);
625338fd1498Szrj   call = get_call_rtx_from (insn);
625438fd1498Szrj   if (call)
625538fd1498Szrj     {
625638fd1498Szrj       if (GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
625738fd1498Szrj 	{
625838fd1498Szrj 	  rtx symbol = XEXP (XEXP (call, 0), 0);
625938fd1498Szrj 	  if (SYMBOL_REF_DECL (symbol))
626038fd1498Szrj 	    fndecl = SYMBOL_REF_DECL (symbol);
626138fd1498Szrj 	}
626238fd1498Szrj       if (fndecl == NULL_TREE)
626338fd1498Szrj 	fndecl = MEM_EXPR (XEXP (call, 0));
626438fd1498Szrj       if (fndecl
626538fd1498Szrj 	  && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
626638fd1498Szrj 	  && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
626738fd1498Szrj 	fndecl = NULL_TREE;
626838fd1498Szrj       if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
626938fd1498Szrj 	type = TREE_TYPE (fndecl);
627038fd1498Szrj       if (fndecl && TREE_CODE (fndecl) != FUNCTION_DECL)
627138fd1498Szrj 	{
627238fd1498Szrj 	  if (TREE_CODE (fndecl) == INDIRECT_REF
627338fd1498Szrj 	      && TREE_CODE (TREE_OPERAND (fndecl, 0)) == OBJ_TYPE_REF)
627438fd1498Szrj 	    obj_type_ref = TREE_OPERAND (fndecl, 0);
627538fd1498Szrj 	  fndecl = NULL_TREE;
627638fd1498Szrj 	}
627738fd1498Szrj       if (type)
627838fd1498Szrj 	{
627938fd1498Szrj 	  for (t = TYPE_ARG_TYPES (type); t && t != void_list_node;
628038fd1498Szrj 	       t = TREE_CHAIN (t))
628138fd1498Szrj 	    if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
628238fd1498Szrj 		&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t))))
628338fd1498Szrj 	      break;
628438fd1498Szrj 	  if ((t == NULL || t == void_list_node) && obj_type_ref == NULL_TREE)
628538fd1498Szrj 	    type = NULL;
628638fd1498Szrj 	  else
628738fd1498Szrj 	    {
628838fd1498Szrj 	      int nargs ATTRIBUTE_UNUSED = list_length (TYPE_ARG_TYPES (type));
628938fd1498Szrj 	      link = CALL_INSN_FUNCTION_USAGE (insn);
629038fd1498Szrj #ifndef PCC_STATIC_STRUCT_RETURN
629138fd1498Szrj 	      if (aggregate_value_p (TREE_TYPE (type), type)
629238fd1498Szrj 		  && targetm.calls.struct_value_rtx (type, 0) == 0)
629338fd1498Szrj 		{
629438fd1498Szrj 		  tree struct_addr = build_pointer_type (TREE_TYPE (type));
629538fd1498Szrj 		  machine_mode mode = TYPE_MODE (struct_addr);
629638fd1498Szrj 		  rtx reg;
629738fd1498Szrj 		  INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
629838fd1498Szrj 					nargs + 1);
629938fd1498Szrj 		  reg = targetm.calls.function_arg (args_so_far, mode,
630038fd1498Szrj 						    struct_addr, true);
630138fd1498Szrj 		  targetm.calls.function_arg_advance (args_so_far, mode,
630238fd1498Szrj 						      struct_addr, true);
630338fd1498Szrj 		  if (reg == NULL_RTX)
630438fd1498Szrj 		    {
630538fd1498Szrj 		      for (; link; link = XEXP (link, 1))
630638fd1498Szrj 			if (GET_CODE (XEXP (link, 0)) == USE
630738fd1498Szrj 			    && MEM_P (XEXP (XEXP (link, 0), 0)))
630838fd1498Szrj 			  {
630938fd1498Szrj 			    link = XEXP (link, 1);
631038fd1498Szrj 			    break;
631138fd1498Szrj 			  }
631238fd1498Szrj 		    }
631338fd1498Szrj 		}
631438fd1498Szrj 	      else
631538fd1498Szrj #endif
631638fd1498Szrj 		INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
631738fd1498Szrj 				      nargs);
631838fd1498Szrj 	      if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
631938fd1498Szrj 		{
632038fd1498Szrj 		  machine_mode mode;
632138fd1498Szrj 		  t = TYPE_ARG_TYPES (type);
632238fd1498Szrj 		  mode = TYPE_MODE (TREE_VALUE (t));
632338fd1498Szrj 		  this_arg = targetm.calls.function_arg (args_so_far, mode,
632438fd1498Szrj 							 TREE_VALUE (t), true);
632538fd1498Szrj 		  if (this_arg && !REG_P (this_arg))
632638fd1498Szrj 		    this_arg = NULL_RTX;
632738fd1498Szrj 		  else if (this_arg == NULL_RTX)
632838fd1498Szrj 		    {
632938fd1498Szrj 		      for (; link; link = XEXP (link, 1))
633038fd1498Szrj 			if (GET_CODE (XEXP (link, 0)) == USE
633138fd1498Szrj 			    && MEM_P (XEXP (XEXP (link, 0), 0)))
633238fd1498Szrj 			  {
633338fd1498Szrj 			    this_arg = XEXP (XEXP (link, 0), 0);
633438fd1498Szrj 			    break;
633538fd1498Szrj 			  }
633638fd1498Szrj 		    }
633738fd1498Szrj 		}
633838fd1498Szrj 	    }
633938fd1498Szrj 	}
634038fd1498Szrj     }
634138fd1498Szrj   t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
634238fd1498Szrj 
634338fd1498Szrj   for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
634438fd1498Szrj     if (GET_CODE (XEXP (link, 0)) == USE)
634538fd1498Szrj       {
634638fd1498Szrj 	rtx item = NULL_RTX;
634738fd1498Szrj 	x = XEXP (XEXP (link, 0), 0);
634838fd1498Szrj 	if (GET_MODE (link) == VOIDmode
634938fd1498Szrj 	    || GET_MODE (link) == BLKmode
635038fd1498Szrj 	    || (GET_MODE (link) != GET_MODE (x)
635138fd1498Szrj 		&& ((GET_MODE_CLASS (GET_MODE (link)) != MODE_INT
635238fd1498Szrj 		     && GET_MODE_CLASS (GET_MODE (link)) != MODE_PARTIAL_INT)
635338fd1498Szrj 		    || (GET_MODE_CLASS (GET_MODE (x)) != MODE_INT
635438fd1498Szrj 			&& GET_MODE_CLASS (GET_MODE (x)) != MODE_PARTIAL_INT))))
635538fd1498Szrj 	  /* Can't do anything for these, if the original type mode
635638fd1498Szrj 	     isn't known or can't be converted.  */;
635738fd1498Szrj 	else if (REG_P (x))
635838fd1498Szrj 	  {
635938fd1498Szrj 	    cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
636038fd1498Szrj 	    scalar_int_mode mode;
636138fd1498Szrj 	    if (val && cselib_preserved_value_p (val))
636238fd1498Szrj 	      item = val->val_rtx;
636338fd1498Szrj 	    else if (is_a <scalar_int_mode> (GET_MODE (x), &mode))
636438fd1498Szrj 	      {
636538fd1498Szrj 		opt_scalar_int_mode mode_iter;
636638fd1498Szrj 		FOR_EACH_WIDER_MODE (mode_iter, mode)
636738fd1498Szrj 		  {
636838fd1498Szrj 		    mode = mode_iter.require ();
636938fd1498Szrj 		    if (GET_MODE_BITSIZE (mode) > BITS_PER_WORD)
637038fd1498Szrj 		      break;
637138fd1498Szrj 
637238fd1498Szrj 		    rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0);
637338fd1498Szrj 		    if (reg == NULL_RTX || !REG_P (reg))
637438fd1498Szrj 		      continue;
637538fd1498Szrj 		    val = cselib_lookup (reg, mode, 0, VOIDmode);
637638fd1498Szrj 		    if (val && cselib_preserved_value_p (val))
637738fd1498Szrj 		      {
637838fd1498Szrj 			item = val->val_rtx;
637938fd1498Szrj 			break;
638038fd1498Szrj 		      }
638138fd1498Szrj 		  }
638238fd1498Szrj 	      }
638338fd1498Szrj 	  }
638438fd1498Szrj 	else if (MEM_P (x))
638538fd1498Szrj 	  {
638638fd1498Szrj 	    rtx mem = x;
638738fd1498Szrj 	    cselib_val *val;
638838fd1498Szrj 
638938fd1498Szrj 	    if (!frame_pointer_needed)
639038fd1498Szrj 	      {
639138fd1498Szrj 		struct adjust_mem_data amd;
639238fd1498Szrj 		amd.mem_mode = VOIDmode;
639338fd1498Szrj 		amd.stack_adjust = -VTI (bb)->out.stack_adjust;
639438fd1498Szrj 		amd.store = true;
639538fd1498Szrj 		mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems,
639638fd1498Szrj 					       &amd);
639738fd1498Szrj 		gcc_assert (amd.side_effects.is_empty ());
639838fd1498Szrj 	      }
639938fd1498Szrj 	    val = cselib_lookup (mem, GET_MODE (mem), 0, VOIDmode);
640038fd1498Szrj 	    if (val && cselib_preserved_value_p (val))
640138fd1498Szrj 	      item = val->val_rtx;
640238fd1498Szrj 	    else if (GET_MODE_CLASS (GET_MODE (mem)) != MODE_INT
640338fd1498Szrj 		     && GET_MODE_CLASS (GET_MODE (mem)) != MODE_PARTIAL_INT)
640438fd1498Szrj 	      {
640538fd1498Szrj 		/* For non-integer stack argument see also if they weren't
640638fd1498Szrj 		   initialized by integers.  */
640738fd1498Szrj 		scalar_int_mode imode;
640838fd1498Szrj 		if (int_mode_for_mode (GET_MODE (mem)).exists (&imode)
640938fd1498Szrj 		    && imode != GET_MODE (mem))
641038fd1498Szrj 		  {
641138fd1498Szrj 		    val = cselib_lookup (adjust_address_nv (mem, imode, 0),
641238fd1498Szrj 					 imode, 0, VOIDmode);
641338fd1498Szrj 		    if (val && cselib_preserved_value_p (val))
641438fd1498Szrj 		      item = lowpart_subreg (GET_MODE (x), val->val_rtx,
641538fd1498Szrj 					     imode);
641638fd1498Szrj 		  }
641738fd1498Szrj 	      }
641838fd1498Szrj 	  }
641938fd1498Szrj 	if (item)
642038fd1498Szrj 	  {
642138fd1498Szrj 	    rtx x2 = x;
642238fd1498Szrj 	    if (GET_MODE (item) != GET_MODE (link))
642338fd1498Szrj 	      item = lowpart_subreg (GET_MODE (link), item, GET_MODE (item));
642438fd1498Szrj 	    if (GET_MODE (x2) != GET_MODE (link))
642538fd1498Szrj 	      x2 = lowpart_subreg (GET_MODE (link), x2, GET_MODE (x2));
642638fd1498Szrj 	    item = gen_rtx_CONCAT (GET_MODE (link), x2, item);
642738fd1498Szrj 	    call_arguments
642838fd1498Szrj 	      = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
642938fd1498Szrj 	  }
643038fd1498Szrj 	if (t && t != void_list_node)
643138fd1498Szrj 	  {
643238fd1498Szrj 	    tree argtype = TREE_VALUE (t);
643338fd1498Szrj 	    machine_mode mode = TYPE_MODE (argtype);
643438fd1498Szrj 	    rtx reg;
643538fd1498Szrj 	    if (pass_by_reference (&args_so_far_v, mode, argtype, true))
643638fd1498Szrj 	      {
643738fd1498Szrj 		argtype = build_pointer_type (argtype);
643838fd1498Szrj 		mode = TYPE_MODE (argtype);
643938fd1498Szrj 	      }
644038fd1498Szrj 	    reg = targetm.calls.function_arg (args_so_far, mode,
644138fd1498Szrj 					      argtype, true);
644238fd1498Szrj 	    if (TREE_CODE (argtype) == REFERENCE_TYPE
644338fd1498Szrj 		&& INTEGRAL_TYPE_P (TREE_TYPE (argtype))
644438fd1498Szrj 		&& reg
644538fd1498Szrj 		&& REG_P (reg)
644638fd1498Szrj 		&& GET_MODE (reg) == mode
644738fd1498Szrj 		&& (GET_MODE_CLASS (mode) == MODE_INT
644838fd1498Szrj 		    || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
644938fd1498Szrj 		&& REG_P (x)
645038fd1498Szrj 		&& REGNO (x) == REGNO (reg)
645138fd1498Szrj 		&& GET_MODE (x) == mode
645238fd1498Szrj 		&& item)
645338fd1498Szrj 	      {
645438fd1498Szrj 		machine_mode indmode
645538fd1498Szrj 		  = TYPE_MODE (TREE_TYPE (argtype));
645638fd1498Szrj 		rtx mem = gen_rtx_MEM (indmode, x);
645738fd1498Szrj 		cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
645838fd1498Szrj 		if (val && cselib_preserved_value_p (val))
645938fd1498Szrj 		  {
646038fd1498Szrj 		    item = gen_rtx_CONCAT (indmode, mem, val->val_rtx);
646138fd1498Szrj 		    call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
646238fd1498Szrj 							call_arguments);
646338fd1498Szrj 		  }
646438fd1498Szrj 		else
646538fd1498Szrj 		  {
646638fd1498Szrj 		    struct elt_loc_list *l;
646738fd1498Szrj 		    tree initial;
646838fd1498Szrj 
646938fd1498Szrj 		    /* Try harder, when passing address of a constant
647038fd1498Szrj 		       pool integer it can be easily read back.  */
647138fd1498Szrj 		    item = XEXP (item, 1);
647238fd1498Szrj 		    if (GET_CODE (item) == SUBREG)
647338fd1498Szrj 		      item = SUBREG_REG (item);
647438fd1498Szrj 		    gcc_assert (GET_CODE (item) == VALUE);
647538fd1498Szrj 		    val = CSELIB_VAL_PTR (item);
647638fd1498Szrj 		    for (l = val->locs; l; l = l->next)
647738fd1498Szrj 		      if (GET_CODE (l->loc) == SYMBOL_REF
647838fd1498Szrj 			  && TREE_CONSTANT_POOL_ADDRESS_P (l->loc)
647938fd1498Szrj 			  && SYMBOL_REF_DECL (l->loc)
648038fd1498Szrj 			  && DECL_INITIAL (SYMBOL_REF_DECL (l->loc)))
648138fd1498Szrj 			{
648238fd1498Szrj 			  initial = DECL_INITIAL (SYMBOL_REF_DECL (l->loc));
648338fd1498Szrj 			  if (tree_fits_shwi_p (initial))
648438fd1498Szrj 			    {
648538fd1498Szrj 			      item = GEN_INT (tree_to_shwi (initial));
648638fd1498Szrj 			      item = gen_rtx_CONCAT (indmode, mem, item);
648738fd1498Szrj 			      call_arguments
648838fd1498Szrj 				= gen_rtx_EXPR_LIST (VOIDmode, item,
648938fd1498Szrj 						     call_arguments);
649038fd1498Szrj 			    }
649138fd1498Szrj 			  break;
649238fd1498Szrj 			}
649338fd1498Szrj 		  }
649438fd1498Szrj 	      }
649538fd1498Szrj 	    targetm.calls.function_arg_advance (args_so_far, mode,
649638fd1498Szrj 						argtype, true);
649738fd1498Szrj 	    t = TREE_CHAIN (t);
649838fd1498Szrj 	  }
649938fd1498Szrj       }
650038fd1498Szrj 
650138fd1498Szrj   /* Add debug arguments.  */
650238fd1498Szrj   if (fndecl
650338fd1498Szrj       && TREE_CODE (fndecl) == FUNCTION_DECL
650438fd1498Szrj       && DECL_HAS_DEBUG_ARGS_P (fndecl))
650538fd1498Szrj     {
650638fd1498Szrj       vec<tree, va_gc> **debug_args = decl_debug_args_lookup (fndecl);
650738fd1498Szrj       if (debug_args)
650838fd1498Szrj 	{
650938fd1498Szrj 	  unsigned int ix;
651038fd1498Szrj 	  tree param;
651138fd1498Szrj 	  for (ix = 0; vec_safe_iterate (*debug_args, ix, &param); ix += 2)
651238fd1498Szrj 	    {
651338fd1498Szrj 	      rtx item;
651438fd1498Szrj 	      tree dtemp = (**debug_args)[ix + 1];
651538fd1498Szrj 	      machine_mode mode = DECL_MODE (dtemp);
651638fd1498Szrj 	      item = gen_rtx_DEBUG_PARAMETER_REF (mode, param);
651738fd1498Szrj 	      item = gen_rtx_CONCAT (mode, item, DECL_RTL_KNOWN_SET (dtemp));
651838fd1498Szrj 	      call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
651938fd1498Szrj 						  call_arguments);
652038fd1498Szrj 	    }
652138fd1498Szrj 	}
652238fd1498Szrj     }
652338fd1498Szrj 
652438fd1498Szrj   /* Reverse call_arguments chain.  */
652538fd1498Szrj   prev = NULL_RTX;
652638fd1498Szrj   for (cur = call_arguments; cur; cur = next)
652738fd1498Szrj     {
652838fd1498Szrj       next = XEXP (cur, 1);
652938fd1498Szrj       XEXP (cur, 1) = prev;
653038fd1498Szrj       prev = cur;
653138fd1498Szrj     }
653238fd1498Szrj   call_arguments = prev;
653338fd1498Szrj 
653438fd1498Szrj   x = get_call_rtx_from (insn);
653538fd1498Szrj   if (x)
653638fd1498Szrj     {
653738fd1498Szrj       x = XEXP (XEXP (x, 0), 0);
653838fd1498Szrj       if (GET_CODE (x) == SYMBOL_REF)
653938fd1498Szrj 	/* Don't record anything.  */;
654038fd1498Szrj       else if (CONSTANT_P (x))
654138fd1498Szrj 	{
654238fd1498Szrj 	  x = gen_rtx_CONCAT (GET_MODE (x) == VOIDmode ? Pmode : GET_MODE (x),
654338fd1498Szrj 			      pc_rtx, x);
654438fd1498Szrj 	  call_arguments
654538fd1498Szrj 	    = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
654638fd1498Szrj 	}
654738fd1498Szrj       else
654838fd1498Szrj 	{
654938fd1498Szrj 	  cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
655038fd1498Szrj 	  if (val && cselib_preserved_value_p (val))
655138fd1498Szrj 	    {
655238fd1498Szrj 	      x = gen_rtx_CONCAT (GET_MODE (x), pc_rtx, val->val_rtx);
655338fd1498Szrj 	      call_arguments
655438fd1498Szrj 		= gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
655538fd1498Szrj 	    }
655638fd1498Szrj 	}
655738fd1498Szrj     }
655838fd1498Szrj   if (this_arg)
655938fd1498Szrj     {
656038fd1498Szrj       machine_mode mode
656138fd1498Szrj 	= TYPE_MODE (TREE_TYPE (OBJ_TYPE_REF_EXPR (obj_type_ref)));
656238fd1498Szrj       rtx clobbered = gen_rtx_MEM (mode, this_arg);
656338fd1498Szrj       HOST_WIDE_INT token
656438fd1498Szrj 	= tree_to_shwi (OBJ_TYPE_REF_TOKEN (obj_type_ref));
656538fd1498Szrj       if (token)
656638fd1498Szrj 	clobbered = plus_constant (mode, clobbered,
656738fd1498Szrj 				   token * GET_MODE_SIZE (mode));
656838fd1498Szrj       clobbered = gen_rtx_MEM (mode, clobbered);
656938fd1498Szrj       x = gen_rtx_CONCAT (mode, gen_rtx_CLOBBER (VOIDmode, pc_rtx), clobbered);
657038fd1498Szrj       call_arguments
657138fd1498Szrj 	= gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
657238fd1498Szrj     }
657338fd1498Szrj }
657438fd1498Szrj 
657538fd1498Szrj /* Callback for cselib_record_sets_hook, that records as micro
657638fd1498Szrj    operations uses and stores in an insn after cselib_record_sets has
657738fd1498Szrj    analyzed the sets in an insn, but before it modifies the stored
657838fd1498Szrj    values in the internal tables, unless cselib_record_sets doesn't
657938fd1498Szrj    call it directly (perhaps because we're not doing cselib in the
658038fd1498Szrj    first place, in which case sets and n_sets will be 0).  */
658138fd1498Szrj 
658238fd1498Szrj static void
add_with_sets(rtx_insn * insn,struct cselib_set * sets,int n_sets)658338fd1498Szrj add_with_sets (rtx_insn *insn, struct cselib_set *sets, int n_sets)
658438fd1498Szrj {
658538fd1498Szrj   basic_block bb = BLOCK_FOR_INSN (insn);
658638fd1498Szrj   int n1, n2;
658738fd1498Szrj   struct count_use_info cui;
658838fd1498Szrj   micro_operation *mos;
658938fd1498Szrj 
659038fd1498Szrj   cselib_hook_called = true;
659138fd1498Szrj 
659238fd1498Szrj   cui.insn = insn;
659338fd1498Szrj   cui.bb = bb;
659438fd1498Szrj   cui.sets = sets;
659538fd1498Szrj   cui.n_sets = n_sets;
659638fd1498Szrj 
659738fd1498Szrj   n1 = VTI (bb)->mos.length ();
659838fd1498Szrj   cui.store_p = false;
659938fd1498Szrj   note_uses (&PATTERN (insn), add_uses_1, &cui);
660038fd1498Szrj   n2 = VTI (bb)->mos.length () - 1;
660138fd1498Szrj   mos = VTI (bb)->mos.address ();
660238fd1498Szrj 
660338fd1498Szrj   /* Order the MO_USEs to be before MO_USE_NO_VARs and MO_VAL_USE, and
660438fd1498Szrj      MO_VAL_LOC last.  */
660538fd1498Szrj   while (n1 < n2)
660638fd1498Szrj     {
660738fd1498Szrj       while (n1 < n2 && mos[n1].type == MO_USE)
660838fd1498Szrj 	n1++;
660938fd1498Szrj       while (n1 < n2 && mos[n2].type != MO_USE)
661038fd1498Szrj 	n2--;
661138fd1498Szrj       if (n1 < n2)
661238fd1498Szrj 	std::swap (mos[n1], mos[n2]);
661338fd1498Szrj     }
661438fd1498Szrj 
661538fd1498Szrj   n2 = VTI (bb)->mos.length () - 1;
661638fd1498Szrj   while (n1 < n2)
661738fd1498Szrj     {
661838fd1498Szrj       while (n1 < n2 && mos[n1].type != MO_VAL_LOC)
661938fd1498Szrj 	n1++;
662038fd1498Szrj       while (n1 < n2 && mos[n2].type == MO_VAL_LOC)
662138fd1498Szrj 	n2--;
662238fd1498Szrj       if (n1 < n2)
662338fd1498Szrj 	std::swap (mos[n1], mos[n2]);
662438fd1498Szrj     }
662538fd1498Szrj 
662638fd1498Szrj   if (CALL_P (insn))
662738fd1498Szrj     {
662838fd1498Szrj       micro_operation mo;
662938fd1498Szrj 
663038fd1498Szrj       mo.type = MO_CALL;
663138fd1498Szrj       mo.insn = insn;
663238fd1498Szrj       mo.u.loc = call_arguments;
663338fd1498Szrj       call_arguments = NULL_RTX;
663438fd1498Szrj 
663538fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
663638fd1498Szrj 	log_op_type (PATTERN (insn), bb, insn, mo.type, dump_file);
663738fd1498Szrj       VTI (bb)->mos.safe_push (mo);
663838fd1498Szrj     }
663938fd1498Szrj 
664038fd1498Szrj   n1 = VTI (bb)->mos.length ();
664138fd1498Szrj   /* This will record NEXT_INSN (insn), such that we can
664238fd1498Szrj      insert notes before it without worrying about any
664338fd1498Szrj      notes that MO_USEs might emit after the insn.  */
664438fd1498Szrj   cui.store_p = true;
664538fd1498Szrj   note_stores (PATTERN (insn), add_stores, &cui);
664638fd1498Szrj   n2 = VTI (bb)->mos.length () - 1;
664738fd1498Szrj   mos = VTI (bb)->mos.address ();
664838fd1498Szrj 
664938fd1498Szrj   /* Order the MO_VAL_USEs first (note_stores does nothing
665038fd1498Szrj      on DEBUG_INSNs, so there are no MO_VAL_LOCs from this
665138fd1498Szrj      insn), then MO_CLOBBERs, then MO_SET/MO_COPY/MO_VAL_SET.  */
665238fd1498Szrj   while (n1 < n2)
665338fd1498Szrj     {
665438fd1498Szrj       while (n1 < n2 && mos[n1].type == MO_VAL_USE)
665538fd1498Szrj 	n1++;
665638fd1498Szrj       while (n1 < n2 && mos[n2].type != MO_VAL_USE)
665738fd1498Szrj 	n2--;
665838fd1498Szrj       if (n1 < n2)
665938fd1498Szrj 	std::swap (mos[n1], mos[n2]);
666038fd1498Szrj     }
666138fd1498Szrj 
666238fd1498Szrj   n2 = VTI (bb)->mos.length () - 1;
666338fd1498Szrj   while (n1 < n2)
666438fd1498Szrj     {
666538fd1498Szrj       while (n1 < n2 && mos[n1].type == MO_CLOBBER)
666638fd1498Szrj 	n1++;
666738fd1498Szrj       while (n1 < n2 && mos[n2].type != MO_CLOBBER)
666838fd1498Szrj 	n2--;
666938fd1498Szrj       if (n1 < n2)
667038fd1498Szrj 	std::swap (mos[n1], mos[n2]);
667138fd1498Szrj     }
667238fd1498Szrj }
667338fd1498Szrj 
667438fd1498Szrj static enum var_init_status
find_src_status(dataflow_set * in,rtx src)667538fd1498Szrj find_src_status (dataflow_set *in, rtx src)
667638fd1498Szrj {
667738fd1498Szrj   tree decl = NULL_TREE;
667838fd1498Szrj   enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
667938fd1498Szrj 
668038fd1498Szrj   if (! flag_var_tracking_uninit)
668138fd1498Szrj     status = VAR_INIT_STATUS_INITIALIZED;
668238fd1498Szrj 
668338fd1498Szrj   if (src && REG_P (src))
668438fd1498Szrj     decl = var_debug_decl (REG_EXPR (src));
668538fd1498Szrj   else if (src && MEM_P (src))
668638fd1498Szrj     decl = var_debug_decl (MEM_EXPR (src));
668738fd1498Szrj 
668838fd1498Szrj   if (src && decl)
668938fd1498Szrj     status = get_init_value (in, src, dv_from_decl (decl));
669038fd1498Szrj 
669138fd1498Szrj   return status;
669238fd1498Szrj }
669338fd1498Szrj 
669438fd1498Szrj /* SRC is the source of an assignment.  Use SET to try to find what
669538fd1498Szrj    was ultimately assigned to SRC.  Return that value if known,
669638fd1498Szrj    otherwise return SRC itself.  */
669738fd1498Szrj 
669838fd1498Szrj static rtx
find_src_set_src(dataflow_set * set,rtx src)669938fd1498Szrj find_src_set_src (dataflow_set *set, rtx src)
670038fd1498Szrj {
670138fd1498Szrj   tree decl = NULL_TREE;   /* The variable being copied around.          */
670238fd1498Szrj   rtx set_src = NULL_RTX;  /* The value for "decl" stored in "src".      */
670338fd1498Szrj   variable *var;
670438fd1498Szrj   location_chain *nextp;
670538fd1498Szrj   int i;
670638fd1498Szrj   bool found;
670738fd1498Szrj 
670838fd1498Szrj   if (src && REG_P (src))
670938fd1498Szrj     decl = var_debug_decl (REG_EXPR (src));
671038fd1498Szrj   else if (src && MEM_P (src))
671138fd1498Szrj     decl = var_debug_decl (MEM_EXPR (src));
671238fd1498Szrj 
671338fd1498Szrj   if (src && decl)
671438fd1498Szrj     {
671538fd1498Szrj       decl_or_value dv = dv_from_decl (decl);
671638fd1498Szrj 
671738fd1498Szrj       var = shared_hash_find (set->vars, dv);
671838fd1498Szrj       if (var)
671938fd1498Szrj 	{
672038fd1498Szrj 	  found = false;
672138fd1498Szrj 	  for (i = 0; i < var->n_var_parts && !found; i++)
672238fd1498Szrj 	    for (nextp = var->var_part[i].loc_chain; nextp && !found;
672338fd1498Szrj 		 nextp = nextp->next)
672438fd1498Szrj 	      if (rtx_equal_p (nextp->loc, src))
672538fd1498Szrj 		{
672638fd1498Szrj 		  set_src = nextp->set_src;
672738fd1498Szrj 		  found = true;
672838fd1498Szrj 		}
672938fd1498Szrj 
673038fd1498Szrj 	}
673138fd1498Szrj     }
673238fd1498Szrj 
673338fd1498Szrj   return set_src;
673438fd1498Szrj }
673538fd1498Szrj 
673638fd1498Szrj /* Compute the changes of variable locations in the basic block BB.  */
673738fd1498Szrj 
673838fd1498Szrj static bool
compute_bb_dataflow(basic_block bb)673938fd1498Szrj compute_bb_dataflow (basic_block bb)
674038fd1498Szrj {
674138fd1498Szrj   unsigned int i;
674238fd1498Szrj   micro_operation *mo;
674338fd1498Szrj   bool changed;
674438fd1498Szrj   dataflow_set old_out;
674538fd1498Szrj   dataflow_set *in = &VTI (bb)->in;
674638fd1498Szrj   dataflow_set *out = &VTI (bb)->out;
674738fd1498Szrj 
674838fd1498Szrj   dataflow_set_init (&old_out);
674938fd1498Szrj   dataflow_set_copy (&old_out, out);
675038fd1498Szrj   dataflow_set_copy (out, in);
675138fd1498Szrj 
675238fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
675338fd1498Szrj     local_get_addr_cache = new hash_map<rtx, rtx>;
675438fd1498Szrj 
675538fd1498Szrj   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
675638fd1498Szrj     {
675738fd1498Szrj       rtx_insn *insn = mo->insn;
675838fd1498Szrj 
675938fd1498Szrj       switch (mo->type)
676038fd1498Szrj 	{
676138fd1498Szrj 	  case MO_CALL:
676238fd1498Szrj 	    dataflow_set_clear_at_call (out, insn);
676338fd1498Szrj 	    break;
676438fd1498Szrj 
676538fd1498Szrj 	  case MO_USE:
676638fd1498Szrj 	    {
676738fd1498Szrj 	      rtx loc = mo->u.loc;
676838fd1498Szrj 
676938fd1498Szrj 	      if (REG_P (loc))
677038fd1498Szrj 		var_reg_set (out, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL);
677138fd1498Szrj 	      else if (MEM_P (loc))
677238fd1498Szrj 		var_mem_set (out, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL);
677338fd1498Szrj 	    }
677438fd1498Szrj 	    break;
677538fd1498Szrj 
677638fd1498Szrj 	  case MO_VAL_LOC:
677738fd1498Szrj 	    {
677838fd1498Szrj 	      rtx loc = mo->u.loc;
677938fd1498Szrj 	      rtx val, vloc;
678038fd1498Szrj 	      tree var;
678138fd1498Szrj 
678238fd1498Szrj 	      if (GET_CODE (loc) == CONCAT)
678338fd1498Szrj 		{
678438fd1498Szrj 		  val = XEXP (loc, 0);
678538fd1498Szrj 		  vloc = XEXP (loc, 1);
678638fd1498Szrj 		}
678738fd1498Szrj 	      else
678838fd1498Szrj 		{
678938fd1498Szrj 		  val = NULL_RTX;
679038fd1498Szrj 		  vloc = loc;
679138fd1498Szrj 		}
679238fd1498Szrj 
679338fd1498Szrj 	      var = PAT_VAR_LOCATION_DECL (vloc);
679438fd1498Szrj 
679538fd1498Szrj 	      clobber_variable_part (out, NULL_RTX,
679638fd1498Szrj 				     dv_from_decl (var), 0, NULL_RTX);
679738fd1498Szrj 	      if (val)
679838fd1498Szrj 		{
679938fd1498Szrj 		  if (VAL_NEEDS_RESOLUTION (loc))
680038fd1498Szrj 		    val_resolve (out, val, PAT_VAR_LOCATION_LOC (vloc), insn);
680138fd1498Szrj 		  set_variable_part (out, val, dv_from_decl (var), 0,
680238fd1498Szrj 				     VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
680338fd1498Szrj 				     INSERT);
680438fd1498Szrj 		}
680538fd1498Szrj 	      else if (!VAR_LOC_UNKNOWN_P (PAT_VAR_LOCATION_LOC (vloc)))
680638fd1498Szrj 		set_variable_part (out, PAT_VAR_LOCATION_LOC (vloc),
680738fd1498Szrj 				   dv_from_decl (var), 0,
680838fd1498Szrj 				   VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
680938fd1498Szrj 				   INSERT);
681038fd1498Szrj 	    }
681138fd1498Szrj 	    break;
681238fd1498Szrj 
681338fd1498Szrj 	  case MO_VAL_USE:
681438fd1498Szrj 	    {
681538fd1498Szrj 	      rtx loc = mo->u.loc;
681638fd1498Szrj 	      rtx val, vloc, uloc;
681738fd1498Szrj 
681838fd1498Szrj 	      vloc = uloc = XEXP (loc, 1);
681938fd1498Szrj 	      val = XEXP (loc, 0);
682038fd1498Szrj 
682138fd1498Szrj 	      if (GET_CODE (val) == CONCAT)
682238fd1498Szrj 		{
682338fd1498Szrj 		  uloc = XEXP (val, 1);
682438fd1498Szrj 		  val = XEXP (val, 0);
682538fd1498Szrj 		}
682638fd1498Szrj 
682738fd1498Szrj 	      if (VAL_NEEDS_RESOLUTION (loc))
682838fd1498Szrj 		val_resolve (out, val, vloc, insn);
682938fd1498Szrj 	      else
683038fd1498Szrj 		val_store (out, val, uloc, insn, false);
683138fd1498Szrj 
683238fd1498Szrj 	      if (VAL_HOLDS_TRACK_EXPR (loc))
683338fd1498Szrj 		{
683438fd1498Szrj 		  if (GET_CODE (uloc) == REG)
683538fd1498Szrj 		    var_reg_set (out, uloc, VAR_INIT_STATUS_UNINITIALIZED,
683638fd1498Szrj 				 NULL);
683738fd1498Szrj 		  else if (GET_CODE (uloc) == MEM)
683838fd1498Szrj 		    var_mem_set (out, uloc, VAR_INIT_STATUS_UNINITIALIZED,
683938fd1498Szrj 				 NULL);
684038fd1498Szrj 		}
684138fd1498Szrj 	    }
684238fd1498Szrj 	    break;
684338fd1498Szrj 
684438fd1498Szrj 	  case MO_VAL_SET:
684538fd1498Szrj 	    {
684638fd1498Szrj 	      rtx loc = mo->u.loc;
684738fd1498Szrj 	      rtx val, vloc, uloc;
684838fd1498Szrj 	      rtx dstv, srcv;
684938fd1498Szrj 
685038fd1498Szrj 	      vloc = loc;
685138fd1498Szrj 	      uloc = XEXP (vloc, 1);
685238fd1498Szrj 	      val = XEXP (vloc, 0);
685338fd1498Szrj 	      vloc = uloc;
685438fd1498Szrj 
685538fd1498Szrj 	      if (GET_CODE (uloc) == SET)
685638fd1498Szrj 		{
685738fd1498Szrj 		  dstv = SET_DEST (uloc);
685838fd1498Szrj 		  srcv = SET_SRC (uloc);
685938fd1498Szrj 		}
686038fd1498Szrj 	      else
686138fd1498Szrj 		{
686238fd1498Szrj 		  dstv = uloc;
686338fd1498Szrj 		  srcv = NULL;
686438fd1498Szrj 		}
686538fd1498Szrj 
686638fd1498Szrj 	      if (GET_CODE (val) == CONCAT)
686738fd1498Szrj 		{
686838fd1498Szrj 		  dstv = vloc = XEXP (val, 1);
686938fd1498Szrj 		  val = XEXP (val, 0);
687038fd1498Szrj 		}
687138fd1498Szrj 
687238fd1498Szrj 	      if (GET_CODE (vloc) == SET)
687338fd1498Szrj 		{
687438fd1498Szrj 		  srcv = SET_SRC (vloc);
687538fd1498Szrj 
687638fd1498Szrj 		  gcc_assert (val != srcv);
687738fd1498Szrj 		  gcc_assert (vloc == uloc || VAL_NEEDS_RESOLUTION (loc));
687838fd1498Szrj 
687938fd1498Szrj 		  dstv = vloc = SET_DEST (vloc);
688038fd1498Szrj 
688138fd1498Szrj 		  if (VAL_NEEDS_RESOLUTION (loc))
688238fd1498Szrj 		    val_resolve (out, val, srcv, insn);
688338fd1498Szrj 		}
688438fd1498Szrj 	      else if (VAL_NEEDS_RESOLUTION (loc))
688538fd1498Szrj 		{
688638fd1498Szrj 		  gcc_assert (GET_CODE (uloc) == SET
688738fd1498Szrj 			      && GET_CODE (SET_SRC (uloc)) == REG);
688838fd1498Szrj 		  val_resolve (out, val, SET_SRC (uloc), insn);
688938fd1498Szrj 		}
689038fd1498Szrj 
689138fd1498Szrj 	      if (VAL_HOLDS_TRACK_EXPR (loc))
689238fd1498Szrj 		{
689338fd1498Szrj 		  if (VAL_EXPR_IS_CLOBBERED (loc))
689438fd1498Szrj 		    {
689538fd1498Szrj 		      if (REG_P (uloc))
689638fd1498Szrj 			var_reg_delete (out, uloc, true);
689738fd1498Szrj 		      else if (MEM_P (uloc))
689838fd1498Szrj 			{
689938fd1498Szrj 			  gcc_assert (MEM_P (dstv));
690038fd1498Szrj 			  gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (uloc));
690138fd1498Szrj 			  var_mem_delete (out, dstv, true);
690238fd1498Szrj 			}
690338fd1498Szrj 		    }
690438fd1498Szrj 		  else
690538fd1498Szrj 		    {
690638fd1498Szrj 		      bool copied_p = VAL_EXPR_IS_COPIED (loc);
690738fd1498Szrj 		      rtx src = NULL, dst = uloc;
690838fd1498Szrj 		      enum var_init_status status = VAR_INIT_STATUS_INITIALIZED;
690938fd1498Szrj 
691038fd1498Szrj 		      if (GET_CODE (uloc) == SET)
691138fd1498Szrj 			{
691238fd1498Szrj 			  src = SET_SRC (uloc);
691338fd1498Szrj 			  dst = SET_DEST (uloc);
691438fd1498Szrj 			}
691538fd1498Szrj 
691638fd1498Szrj 		      if (copied_p)
691738fd1498Szrj 			{
691838fd1498Szrj 			  if (flag_var_tracking_uninit)
691938fd1498Szrj 			    {
692038fd1498Szrj 			      status = find_src_status (in, src);
692138fd1498Szrj 
692238fd1498Szrj 			      if (status == VAR_INIT_STATUS_UNKNOWN)
692338fd1498Szrj 				status = find_src_status (out, src);
692438fd1498Szrj 			    }
692538fd1498Szrj 
692638fd1498Szrj 			  src = find_src_set_src (in, src);
692738fd1498Szrj 			}
692838fd1498Szrj 
692938fd1498Szrj 		      if (REG_P (dst))
693038fd1498Szrj 			var_reg_delete_and_set (out, dst, !copied_p,
693138fd1498Szrj 						status, srcv);
693238fd1498Szrj 		      else if (MEM_P (dst))
693338fd1498Szrj 			{
693438fd1498Szrj 			  gcc_assert (MEM_P (dstv));
693538fd1498Szrj 			  gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (dst));
693638fd1498Szrj 			  var_mem_delete_and_set (out, dstv, !copied_p,
693738fd1498Szrj 						  status, srcv);
693838fd1498Szrj 			}
693938fd1498Szrj 		    }
694038fd1498Szrj 		}
694138fd1498Szrj 	      else if (REG_P (uloc))
694238fd1498Szrj 		var_regno_delete (out, REGNO (uloc));
694338fd1498Szrj 	      else if (MEM_P (uloc))
694438fd1498Szrj 		{
694538fd1498Szrj 		  gcc_checking_assert (GET_CODE (vloc) == MEM);
694638fd1498Szrj 		  gcc_checking_assert (dstv == vloc);
694738fd1498Szrj 		  if (dstv != vloc)
694838fd1498Szrj 		    clobber_overlapping_mems (out, vloc);
694938fd1498Szrj 		}
695038fd1498Szrj 
695138fd1498Szrj 	      val_store (out, val, dstv, insn, true);
695238fd1498Szrj 	    }
695338fd1498Szrj 	    break;
695438fd1498Szrj 
695538fd1498Szrj 	  case MO_SET:
695638fd1498Szrj 	    {
695738fd1498Szrj 	      rtx loc = mo->u.loc;
695838fd1498Szrj 	      rtx set_src = NULL;
695938fd1498Szrj 
696038fd1498Szrj 	      if (GET_CODE (loc) == SET)
696138fd1498Szrj 		{
696238fd1498Szrj 		  set_src = SET_SRC (loc);
696338fd1498Szrj 		  loc = SET_DEST (loc);
696438fd1498Szrj 		}
696538fd1498Szrj 
696638fd1498Szrj 	      if (REG_P (loc))
696738fd1498Szrj 		var_reg_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
696838fd1498Szrj 					set_src);
696938fd1498Szrj 	      else if (MEM_P (loc))
697038fd1498Szrj 		var_mem_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
697138fd1498Szrj 					set_src);
697238fd1498Szrj 	    }
697338fd1498Szrj 	    break;
697438fd1498Szrj 
697538fd1498Szrj 	  case MO_COPY:
697638fd1498Szrj 	    {
697738fd1498Szrj 	      rtx loc = mo->u.loc;
697838fd1498Szrj 	      enum var_init_status src_status;
697938fd1498Szrj 	      rtx set_src = NULL;
698038fd1498Szrj 
698138fd1498Szrj 	      if (GET_CODE (loc) == SET)
698238fd1498Szrj 		{
698338fd1498Szrj 		  set_src = SET_SRC (loc);
698438fd1498Szrj 		  loc = SET_DEST (loc);
698538fd1498Szrj 		}
698638fd1498Szrj 
698738fd1498Szrj 	      if (! flag_var_tracking_uninit)
698838fd1498Szrj 		src_status = VAR_INIT_STATUS_INITIALIZED;
698938fd1498Szrj 	      else
699038fd1498Szrj 		{
699138fd1498Szrj 		  src_status = find_src_status (in, set_src);
699238fd1498Szrj 
699338fd1498Szrj 		  if (src_status == VAR_INIT_STATUS_UNKNOWN)
699438fd1498Szrj 		    src_status = find_src_status (out, set_src);
699538fd1498Szrj 		}
699638fd1498Szrj 
699738fd1498Szrj 	      set_src = find_src_set_src (in, set_src);
699838fd1498Szrj 
699938fd1498Szrj 	      if (REG_P (loc))
700038fd1498Szrj 		var_reg_delete_and_set (out, loc, false, src_status, set_src);
700138fd1498Szrj 	      else if (MEM_P (loc))
700238fd1498Szrj 		var_mem_delete_and_set (out, loc, false, src_status, set_src);
700338fd1498Szrj 	    }
700438fd1498Szrj 	    break;
700538fd1498Szrj 
700638fd1498Szrj 	  case MO_USE_NO_VAR:
700738fd1498Szrj 	    {
700838fd1498Szrj 	      rtx loc = mo->u.loc;
700938fd1498Szrj 
701038fd1498Szrj 	      if (REG_P (loc))
701138fd1498Szrj 		var_reg_delete (out, loc, false);
701238fd1498Szrj 	      else if (MEM_P (loc))
701338fd1498Szrj 		var_mem_delete (out, loc, false);
701438fd1498Szrj 	    }
701538fd1498Szrj 	    break;
701638fd1498Szrj 
701738fd1498Szrj 	  case MO_CLOBBER:
701838fd1498Szrj 	    {
701938fd1498Szrj 	      rtx loc = mo->u.loc;
702038fd1498Szrj 
702138fd1498Szrj 	      if (REG_P (loc))
702238fd1498Szrj 		var_reg_delete (out, loc, true);
702338fd1498Szrj 	      else if (MEM_P (loc))
702438fd1498Szrj 		var_mem_delete (out, loc, true);
702538fd1498Szrj 	    }
702638fd1498Szrj 	    break;
702738fd1498Szrj 
702838fd1498Szrj 	  case MO_ADJUST:
702938fd1498Szrj 	    out->stack_adjust += mo->u.adjust;
703038fd1498Szrj 	    break;
703138fd1498Szrj 	}
703238fd1498Szrj     }
703338fd1498Szrj 
703438fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
703538fd1498Szrj     {
703638fd1498Szrj       delete local_get_addr_cache;
703738fd1498Szrj       local_get_addr_cache = NULL;
703838fd1498Szrj 
703938fd1498Szrj       dataflow_set_equiv_regs (out);
704038fd1498Szrj       shared_hash_htab (out->vars)
704138fd1498Szrj 	->traverse <dataflow_set *, canonicalize_values_mark> (out);
704238fd1498Szrj       shared_hash_htab (out->vars)
704338fd1498Szrj 	->traverse <dataflow_set *, canonicalize_values_star> (out);
704438fd1498Szrj       if (flag_checking)
704538fd1498Szrj 	shared_hash_htab (out->vars)
704638fd1498Szrj 	  ->traverse <dataflow_set *, canonicalize_loc_order_check> (out);
704738fd1498Szrj     }
704838fd1498Szrj   changed = dataflow_set_different (&old_out, out);
704938fd1498Szrj   dataflow_set_destroy (&old_out);
705038fd1498Szrj   return changed;
705138fd1498Szrj }
705238fd1498Szrj 
705338fd1498Szrj /* Find the locations of variables in the whole function.  */
705438fd1498Szrj 
705538fd1498Szrj static bool
vt_find_locations(void)705638fd1498Szrj vt_find_locations (void)
705738fd1498Szrj {
705838fd1498Szrj   bb_heap_t *worklist = new bb_heap_t (LONG_MIN);
705938fd1498Szrj   bb_heap_t *pending = new bb_heap_t (LONG_MIN);
706038fd1498Szrj   sbitmap in_worklist, in_pending;
706138fd1498Szrj   basic_block bb;
706238fd1498Szrj   edge e;
706338fd1498Szrj   int *bb_order;
706438fd1498Szrj   int *rc_order;
706538fd1498Szrj   int i;
706638fd1498Szrj   int htabsz = 0;
706738fd1498Szrj   int htabmax = PARAM_VALUE (PARAM_MAX_VARTRACK_SIZE);
706838fd1498Szrj   bool success = true;
706938fd1498Szrj 
707038fd1498Szrj   timevar_push (TV_VAR_TRACKING_DATAFLOW);
707138fd1498Szrj   /* Compute reverse completion order of depth first search of the CFG
707238fd1498Szrj      so that the data-flow runs faster.  */
707338fd1498Szrj   rc_order = XNEWVEC (int, n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS);
707438fd1498Szrj   bb_order = XNEWVEC (int, last_basic_block_for_fn (cfun));
707538fd1498Szrj   pre_and_rev_post_order_compute (NULL, rc_order, false);
707638fd1498Szrj   for (i = 0; i < n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS; i++)
707738fd1498Szrj     bb_order[rc_order[i]] = i;
707838fd1498Szrj   free (rc_order);
707938fd1498Szrj 
708038fd1498Szrj   auto_sbitmap visited (last_basic_block_for_fn (cfun));
708138fd1498Szrj   in_worklist = sbitmap_alloc (last_basic_block_for_fn (cfun));
708238fd1498Szrj   in_pending = sbitmap_alloc (last_basic_block_for_fn (cfun));
708338fd1498Szrj   bitmap_clear (in_worklist);
708438fd1498Szrj 
708538fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
708638fd1498Szrj     pending->insert (bb_order[bb->index], bb);
708738fd1498Szrj   bitmap_ones (in_pending);
708838fd1498Szrj 
708938fd1498Szrj   while (success && !pending->empty ())
709038fd1498Szrj     {
709138fd1498Szrj       std::swap (worklist, pending);
709238fd1498Szrj       std::swap (in_worklist, in_pending);
709338fd1498Szrj 
709438fd1498Szrj       bitmap_clear (visited);
709538fd1498Szrj 
709638fd1498Szrj       while (!worklist->empty ())
709738fd1498Szrj 	{
709838fd1498Szrj 	  bb = worklist->extract_min ();
709938fd1498Szrj 	  bitmap_clear_bit (in_worklist, bb->index);
710038fd1498Szrj 	  gcc_assert (!bitmap_bit_p (visited, bb->index));
710138fd1498Szrj 	  if (!bitmap_bit_p (visited, bb->index))
710238fd1498Szrj 	    {
710338fd1498Szrj 	      bool changed;
710438fd1498Szrj 	      edge_iterator ei;
710538fd1498Szrj 	      int oldinsz, oldoutsz;
710638fd1498Szrj 
710738fd1498Szrj 	      bitmap_set_bit (visited, bb->index);
710838fd1498Szrj 
710938fd1498Szrj 	      if (VTI (bb)->in.vars)
711038fd1498Szrj 		{
711138fd1498Szrj 		  htabsz
711238fd1498Szrj 		    -= shared_hash_htab (VTI (bb)->in.vars)->size ()
711338fd1498Szrj 			+ shared_hash_htab (VTI (bb)->out.vars)->size ();
711438fd1498Szrj 		  oldinsz = shared_hash_htab (VTI (bb)->in.vars)->elements ();
711538fd1498Szrj 		  oldoutsz
711638fd1498Szrj 		    = shared_hash_htab (VTI (bb)->out.vars)->elements ();
711738fd1498Szrj 		}
711838fd1498Szrj 	      else
711938fd1498Szrj 		oldinsz = oldoutsz = 0;
712038fd1498Szrj 
712138fd1498Szrj 	      if (MAY_HAVE_DEBUG_BIND_INSNS)
712238fd1498Szrj 		{
712338fd1498Szrj 		  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
712438fd1498Szrj 		  bool first = true, adjust = false;
712538fd1498Szrj 
712638fd1498Szrj 		  /* Calculate the IN set as the intersection of
712738fd1498Szrj 		     predecessor OUT sets.  */
712838fd1498Szrj 
712938fd1498Szrj 		  dataflow_set_clear (in);
713038fd1498Szrj 		  dst_can_be_shared = true;
713138fd1498Szrj 
713238fd1498Szrj 		  FOR_EACH_EDGE (e, ei, bb->preds)
713338fd1498Szrj 		    if (!VTI (e->src)->flooded)
713438fd1498Szrj 		      gcc_assert (bb_order[bb->index]
713538fd1498Szrj 				  <= bb_order[e->src->index]);
713638fd1498Szrj 		    else if (first)
713738fd1498Szrj 		      {
713838fd1498Szrj 			dataflow_set_copy (in, &VTI (e->src)->out);
713938fd1498Szrj 			first_out = &VTI (e->src)->out;
714038fd1498Szrj 			first = false;
714138fd1498Szrj 		      }
714238fd1498Szrj 		    else
714338fd1498Szrj 		      {
714438fd1498Szrj 			dataflow_set_merge (in, &VTI (e->src)->out);
714538fd1498Szrj 			adjust = true;
714638fd1498Szrj 		      }
714738fd1498Szrj 
714838fd1498Szrj 		  if (adjust)
714938fd1498Szrj 		    {
715038fd1498Szrj 		      dataflow_post_merge_adjust (in, &VTI (bb)->permp);
715138fd1498Szrj 
715238fd1498Szrj 		      if (flag_checking)
715338fd1498Szrj 			/* Merge and merge_adjust should keep entries in
715438fd1498Szrj 			   canonical order.  */
715538fd1498Szrj 			shared_hash_htab (in->vars)
715638fd1498Szrj 			  ->traverse <dataflow_set *,
715738fd1498Szrj 				      canonicalize_loc_order_check> (in);
715838fd1498Szrj 
715938fd1498Szrj 		      if (dst_can_be_shared)
716038fd1498Szrj 			{
716138fd1498Szrj 			  shared_hash_destroy (in->vars);
716238fd1498Szrj 			  in->vars = shared_hash_copy (first_out->vars);
716338fd1498Szrj 			}
716438fd1498Szrj 		    }
716538fd1498Szrj 
716638fd1498Szrj 		  VTI (bb)->flooded = true;
716738fd1498Szrj 		}
716838fd1498Szrj 	      else
716938fd1498Szrj 		{
717038fd1498Szrj 		  /* Calculate the IN set as union of predecessor OUT sets.  */
717138fd1498Szrj 		  dataflow_set_clear (&VTI (bb)->in);
717238fd1498Szrj 		  FOR_EACH_EDGE (e, ei, bb->preds)
717338fd1498Szrj 		    dataflow_set_union (&VTI (bb)->in, &VTI (e->src)->out);
717438fd1498Szrj 		}
717538fd1498Szrj 
717638fd1498Szrj 	      changed = compute_bb_dataflow (bb);
717738fd1498Szrj 	      htabsz += shared_hash_htab (VTI (bb)->in.vars)->size ()
717838fd1498Szrj 			 + shared_hash_htab (VTI (bb)->out.vars)->size ();
717938fd1498Szrj 
718038fd1498Szrj 	      if (htabmax && htabsz > htabmax)
718138fd1498Szrj 		{
718238fd1498Szrj 		  if (MAY_HAVE_DEBUG_BIND_INSNS)
718338fd1498Szrj 		    inform (DECL_SOURCE_LOCATION (cfun->decl),
718438fd1498Szrj 			    "variable tracking size limit exceeded with "
718538fd1498Szrj 			    "-fvar-tracking-assignments, retrying without");
718638fd1498Szrj 		  else
718738fd1498Szrj 		    inform (DECL_SOURCE_LOCATION (cfun->decl),
718838fd1498Szrj 			    "variable tracking size limit exceeded");
718938fd1498Szrj 		  success = false;
719038fd1498Szrj 		  break;
719138fd1498Szrj 		}
719238fd1498Szrj 
719338fd1498Szrj 	      if (changed)
719438fd1498Szrj 		{
719538fd1498Szrj 		  FOR_EACH_EDGE (e, ei, bb->succs)
719638fd1498Szrj 		    {
719738fd1498Szrj 		      if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
719838fd1498Szrj 			continue;
719938fd1498Szrj 
720038fd1498Szrj 		      if (bitmap_bit_p (visited, e->dest->index))
720138fd1498Szrj 			{
720238fd1498Szrj 			  if (!bitmap_bit_p (in_pending, e->dest->index))
720338fd1498Szrj 			    {
720438fd1498Szrj 			      /* Send E->DEST to next round.  */
720538fd1498Szrj 			      bitmap_set_bit (in_pending, e->dest->index);
720638fd1498Szrj 			      pending->insert (bb_order[e->dest->index],
720738fd1498Szrj 					       e->dest);
720838fd1498Szrj 			    }
720938fd1498Szrj 			}
721038fd1498Szrj 		      else if (!bitmap_bit_p (in_worklist, e->dest->index))
721138fd1498Szrj 			{
721238fd1498Szrj 			  /* Add E->DEST to current round.  */
721338fd1498Szrj 			  bitmap_set_bit (in_worklist, e->dest->index);
721438fd1498Szrj 			  worklist->insert (bb_order[e->dest->index],
721538fd1498Szrj 					    e->dest);
721638fd1498Szrj 			}
721738fd1498Szrj 		    }
721838fd1498Szrj 		}
721938fd1498Szrj 
722038fd1498Szrj 	      if (dump_file)
722138fd1498Szrj 		fprintf (dump_file,
722238fd1498Szrj 			 "BB %i: in %i (was %i), out %i (was %i), rem %i + %i, tsz %i\n",
722338fd1498Szrj 			 bb->index,
722438fd1498Szrj 			 (int)shared_hash_htab (VTI (bb)->in.vars)->size (),
722538fd1498Szrj 			 oldinsz,
722638fd1498Szrj 			 (int)shared_hash_htab (VTI (bb)->out.vars)->size (),
722738fd1498Szrj 			 oldoutsz,
722838fd1498Szrj 			 (int)worklist->nodes (), (int)pending->nodes (),
722938fd1498Szrj 			 htabsz);
723038fd1498Szrj 
723138fd1498Szrj 	      if (dump_file && (dump_flags & TDF_DETAILS))
723238fd1498Szrj 		{
723338fd1498Szrj 		  fprintf (dump_file, "BB %i IN:\n", bb->index);
723438fd1498Szrj 		  dump_dataflow_set (&VTI (bb)->in);
723538fd1498Szrj 		  fprintf (dump_file, "BB %i OUT:\n", bb->index);
723638fd1498Szrj 		  dump_dataflow_set (&VTI (bb)->out);
723738fd1498Szrj 		}
723838fd1498Szrj 	    }
723938fd1498Szrj 	}
724038fd1498Szrj     }
724138fd1498Szrj 
724238fd1498Szrj   if (success && MAY_HAVE_DEBUG_BIND_INSNS)
724338fd1498Szrj     FOR_EACH_BB_FN (bb, cfun)
724438fd1498Szrj       gcc_assert (VTI (bb)->flooded);
724538fd1498Szrj 
724638fd1498Szrj   free (bb_order);
724738fd1498Szrj   delete worklist;
724838fd1498Szrj   delete pending;
724938fd1498Szrj   sbitmap_free (in_worklist);
725038fd1498Szrj   sbitmap_free (in_pending);
725138fd1498Szrj 
725238fd1498Szrj   timevar_pop (TV_VAR_TRACKING_DATAFLOW);
725338fd1498Szrj   return success;
725438fd1498Szrj }
725538fd1498Szrj 
725638fd1498Szrj /* Print the content of the LIST to dump file.  */
725738fd1498Szrj 
725838fd1498Szrj static void
dump_attrs_list(attrs * list)725938fd1498Szrj dump_attrs_list (attrs *list)
726038fd1498Szrj {
726138fd1498Szrj   for (; list; list = list->next)
726238fd1498Szrj     {
726338fd1498Szrj       if (dv_is_decl_p (list->dv))
726438fd1498Szrj 	print_mem_expr (dump_file, dv_as_decl (list->dv));
726538fd1498Szrj       else
726638fd1498Szrj 	print_rtl_single (dump_file, dv_as_value (list->dv));
726738fd1498Szrj       fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
726838fd1498Szrj     }
726938fd1498Szrj   fprintf (dump_file, "\n");
727038fd1498Szrj }
727138fd1498Szrj 
727238fd1498Szrj /* Print the information about variable *SLOT to dump file.  */
727338fd1498Szrj 
727438fd1498Szrj int
dump_var_tracking_slot(variable ** slot,void * data ATTRIBUTE_UNUSED)727538fd1498Szrj dump_var_tracking_slot (variable **slot, void *data ATTRIBUTE_UNUSED)
727638fd1498Szrj {
727738fd1498Szrj   variable *var = *slot;
727838fd1498Szrj 
727938fd1498Szrj   dump_var (var);
728038fd1498Szrj 
728138fd1498Szrj   /* Continue traversing the hash table.  */
728238fd1498Szrj   return 1;
728338fd1498Szrj }
728438fd1498Szrj 
728538fd1498Szrj /* Print the information about variable VAR to dump file.  */
728638fd1498Szrj 
728738fd1498Szrj static void
dump_var(variable * var)728838fd1498Szrj dump_var (variable *var)
728938fd1498Szrj {
729038fd1498Szrj   int i;
729138fd1498Szrj   location_chain *node;
729238fd1498Szrj 
729338fd1498Szrj   if (dv_is_decl_p (var->dv))
729438fd1498Szrj     {
729538fd1498Szrj       const_tree decl = dv_as_decl (var->dv);
729638fd1498Szrj 
729738fd1498Szrj       if (DECL_NAME (decl))
729838fd1498Szrj 	{
729938fd1498Szrj 	  fprintf (dump_file, "  name: %s",
730038fd1498Szrj 		   IDENTIFIER_POINTER (DECL_NAME (decl)));
730138fd1498Szrj 	  if (dump_flags & TDF_UID)
730238fd1498Szrj 	    fprintf (dump_file, "D.%u", DECL_UID (decl));
730338fd1498Szrj 	}
730438fd1498Szrj       else if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
730538fd1498Szrj 	fprintf (dump_file, "  name: D#%u", DEBUG_TEMP_UID (decl));
730638fd1498Szrj       else
730738fd1498Szrj 	fprintf (dump_file, "  name: D.%u", DECL_UID (decl));
730838fd1498Szrj       fprintf (dump_file, "\n");
730938fd1498Szrj     }
731038fd1498Szrj   else
731138fd1498Szrj     {
731238fd1498Szrj       fputc (' ', dump_file);
731338fd1498Szrj       print_rtl_single (dump_file, dv_as_value (var->dv));
731438fd1498Szrj     }
731538fd1498Szrj 
731638fd1498Szrj   for (i = 0; i < var->n_var_parts; i++)
731738fd1498Szrj     {
731838fd1498Szrj       fprintf (dump_file, "    offset %ld\n",
731938fd1498Szrj 	       (long)(var->onepart ? 0 : VAR_PART_OFFSET (var, i)));
732038fd1498Szrj       for (node = var->var_part[i].loc_chain; node; node = node->next)
732138fd1498Szrj 	{
732238fd1498Szrj 	  fprintf (dump_file, "      ");
732338fd1498Szrj 	  if (node->init == VAR_INIT_STATUS_UNINITIALIZED)
732438fd1498Szrj 	    fprintf (dump_file, "[uninit]");
732538fd1498Szrj 	  print_rtl_single (dump_file, node->loc);
732638fd1498Szrj 	}
732738fd1498Szrj     }
732838fd1498Szrj }
732938fd1498Szrj 
733038fd1498Szrj /* Print the information about variables from hash table VARS to dump file.  */
733138fd1498Szrj 
733238fd1498Szrj static void
dump_vars(variable_table_type * vars)733338fd1498Szrj dump_vars (variable_table_type *vars)
733438fd1498Szrj {
733538fd1498Szrj   if (vars->elements () > 0)
733638fd1498Szrj     {
733738fd1498Szrj       fprintf (dump_file, "Variables:\n");
733838fd1498Szrj       vars->traverse <void *, dump_var_tracking_slot> (NULL);
733938fd1498Szrj     }
734038fd1498Szrj }
734138fd1498Szrj 
734238fd1498Szrj /* Print the dataflow set SET to dump file.  */
734338fd1498Szrj 
734438fd1498Szrj static void
dump_dataflow_set(dataflow_set * set)734538fd1498Szrj dump_dataflow_set (dataflow_set *set)
734638fd1498Szrj {
734738fd1498Szrj   int i;
734838fd1498Szrj 
734938fd1498Szrj   fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
735038fd1498Szrj 	   set->stack_adjust);
735138fd1498Szrj   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
735238fd1498Szrj     {
735338fd1498Szrj       if (set->regs[i])
735438fd1498Szrj 	{
735538fd1498Szrj 	  fprintf (dump_file, "Reg %d:", i);
735638fd1498Szrj 	  dump_attrs_list (set->regs[i]);
735738fd1498Szrj 	}
735838fd1498Szrj     }
735938fd1498Szrj   dump_vars (shared_hash_htab (set->vars));
736038fd1498Szrj   fprintf (dump_file, "\n");
736138fd1498Szrj }
736238fd1498Szrj 
736338fd1498Szrj /* Print the IN and OUT sets for each basic block to dump file.  */
736438fd1498Szrj 
736538fd1498Szrj static void
dump_dataflow_sets(void)736638fd1498Szrj dump_dataflow_sets (void)
736738fd1498Szrj {
736838fd1498Szrj   basic_block bb;
736938fd1498Szrj 
737038fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
737138fd1498Szrj     {
737238fd1498Szrj       fprintf (dump_file, "\nBasic block %d:\n", bb->index);
737338fd1498Szrj       fprintf (dump_file, "IN:\n");
737438fd1498Szrj       dump_dataflow_set (&VTI (bb)->in);
737538fd1498Szrj       fprintf (dump_file, "OUT:\n");
737638fd1498Szrj       dump_dataflow_set (&VTI (bb)->out);
737738fd1498Szrj     }
737838fd1498Szrj }
737938fd1498Szrj 
738038fd1498Szrj /* Return the variable for DV in dropped_values, inserting one if
738138fd1498Szrj    requested with INSERT.  */
738238fd1498Szrj 
738338fd1498Szrj static inline variable *
variable_from_dropped(decl_or_value dv,enum insert_option insert)738438fd1498Szrj variable_from_dropped (decl_or_value dv, enum insert_option insert)
738538fd1498Szrj {
738638fd1498Szrj   variable **slot;
738738fd1498Szrj   variable *empty_var;
738838fd1498Szrj   onepart_enum onepart;
738938fd1498Szrj 
739038fd1498Szrj   slot = dropped_values->find_slot_with_hash (dv, dv_htab_hash (dv), insert);
739138fd1498Szrj 
739238fd1498Szrj   if (!slot)
739338fd1498Szrj     return NULL;
739438fd1498Szrj 
739538fd1498Szrj   if (*slot)
739638fd1498Szrj     return *slot;
739738fd1498Szrj 
739838fd1498Szrj   gcc_checking_assert (insert == INSERT);
739938fd1498Szrj 
740038fd1498Szrj   onepart = dv_onepart_p (dv);
740138fd1498Szrj 
740238fd1498Szrj   gcc_checking_assert (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR);
740338fd1498Szrj 
740438fd1498Szrj   empty_var = onepart_pool_allocate (onepart);
740538fd1498Szrj   empty_var->dv = dv;
740638fd1498Szrj   empty_var->refcount = 1;
740738fd1498Szrj   empty_var->n_var_parts = 0;
740838fd1498Szrj   empty_var->onepart = onepart;
740938fd1498Szrj   empty_var->in_changed_variables = false;
741038fd1498Szrj   empty_var->var_part[0].loc_chain = NULL;
741138fd1498Szrj   empty_var->var_part[0].cur_loc = NULL;
741238fd1498Szrj   VAR_LOC_1PAUX (empty_var) = NULL;
741338fd1498Szrj   set_dv_changed (dv, true);
741438fd1498Szrj 
741538fd1498Szrj   *slot = empty_var;
741638fd1498Szrj 
741738fd1498Szrj   return empty_var;
741838fd1498Szrj }
741938fd1498Szrj 
742038fd1498Szrj /* Recover the one-part aux from dropped_values.  */
742138fd1498Szrj 
742238fd1498Szrj static struct onepart_aux *
recover_dropped_1paux(variable * var)742338fd1498Szrj recover_dropped_1paux (variable *var)
742438fd1498Szrj {
742538fd1498Szrj   variable *dvar;
742638fd1498Szrj 
742738fd1498Szrj   gcc_checking_assert (var->onepart);
742838fd1498Szrj 
742938fd1498Szrj   if (VAR_LOC_1PAUX (var))
743038fd1498Szrj     return VAR_LOC_1PAUX (var);
743138fd1498Szrj 
743238fd1498Szrj   if (var->onepart == ONEPART_VDECL)
743338fd1498Szrj     return NULL;
743438fd1498Szrj 
743538fd1498Szrj   dvar = variable_from_dropped (var->dv, NO_INSERT);
743638fd1498Szrj 
743738fd1498Szrj   if (!dvar)
743838fd1498Szrj     return NULL;
743938fd1498Szrj 
744038fd1498Szrj   VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (dvar);
744138fd1498Szrj   VAR_LOC_1PAUX (dvar) = NULL;
744238fd1498Szrj 
744338fd1498Szrj   return VAR_LOC_1PAUX (var);
744438fd1498Szrj }
744538fd1498Szrj 
744638fd1498Szrj /* Add variable VAR to the hash table of changed variables and
744738fd1498Szrj    if it has no locations delete it from SET's hash table.  */
744838fd1498Szrj 
744938fd1498Szrj static void
variable_was_changed(variable * var,dataflow_set * set)745038fd1498Szrj variable_was_changed (variable *var, dataflow_set *set)
745138fd1498Szrj {
745238fd1498Szrj   hashval_t hash = dv_htab_hash (var->dv);
745338fd1498Szrj 
745438fd1498Szrj   if (emit_notes)
745538fd1498Szrj     {
745638fd1498Szrj       variable **slot;
745738fd1498Szrj 
745838fd1498Szrj       /* Remember this decl or VALUE has been added to changed_variables.  */
745938fd1498Szrj       set_dv_changed (var->dv, true);
746038fd1498Szrj 
746138fd1498Szrj       slot = changed_variables->find_slot_with_hash (var->dv, hash, INSERT);
746238fd1498Szrj 
746338fd1498Szrj       if (*slot)
746438fd1498Szrj 	{
746538fd1498Szrj 	  variable *old_var = *slot;
746638fd1498Szrj 	  gcc_assert (old_var->in_changed_variables);
746738fd1498Szrj 	  old_var->in_changed_variables = false;
746838fd1498Szrj 	  if (var != old_var && var->onepart)
746938fd1498Szrj 	    {
747038fd1498Szrj 	      /* Restore the auxiliary info from an empty variable
747138fd1498Szrj 		 previously created for changed_variables, so it is
747238fd1498Szrj 		 not lost.  */
747338fd1498Szrj 	      gcc_checking_assert (!VAR_LOC_1PAUX (var));
747438fd1498Szrj 	      VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (old_var);
747538fd1498Szrj 	      VAR_LOC_1PAUX (old_var) = NULL;
747638fd1498Szrj 	    }
747738fd1498Szrj 	  variable_htab_free (*slot);
747838fd1498Szrj 	}
747938fd1498Szrj 
748038fd1498Szrj       if (set && var->n_var_parts == 0)
748138fd1498Szrj 	{
748238fd1498Szrj 	  onepart_enum onepart = var->onepart;
748338fd1498Szrj 	  variable *empty_var = NULL;
748438fd1498Szrj 	  variable **dslot = NULL;
748538fd1498Szrj 
748638fd1498Szrj 	  if (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR)
748738fd1498Szrj 	    {
748838fd1498Szrj 	      dslot = dropped_values->find_slot_with_hash (var->dv,
748938fd1498Szrj 							   dv_htab_hash (var->dv),
749038fd1498Szrj 							   INSERT);
749138fd1498Szrj 	      empty_var = *dslot;
749238fd1498Szrj 
749338fd1498Szrj 	      if (empty_var)
749438fd1498Szrj 		{
749538fd1498Szrj 		  gcc_checking_assert (!empty_var->in_changed_variables);
749638fd1498Szrj 		  if (!VAR_LOC_1PAUX (var))
749738fd1498Szrj 		    {
749838fd1498Szrj 		      VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (empty_var);
749938fd1498Szrj 		      VAR_LOC_1PAUX (empty_var) = NULL;
750038fd1498Szrj 		    }
750138fd1498Szrj 		  else
750238fd1498Szrj 		    gcc_checking_assert (!VAR_LOC_1PAUX (empty_var));
750338fd1498Szrj 		}
750438fd1498Szrj 	    }
750538fd1498Szrj 
750638fd1498Szrj 	  if (!empty_var)
750738fd1498Szrj 	    {
750838fd1498Szrj 	      empty_var = onepart_pool_allocate (onepart);
750938fd1498Szrj 	      empty_var->dv = var->dv;
751038fd1498Szrj 	      empty_var->refcount = 1;
751138fd1498Szrj 	      empty_var->n_var_parts = 0;
751238fd1498Szrj 	      empty_var->onepart = onepart;
751338fd1498Szrj 	      if (dslot)
751438fd1498Szrj 		{
751538fd1498Szrj 		  empty_var->refcount++;
751638fd1498Szrj 		  *dslot = empty_var;
751738fd1498Szrj 		}
751838fd1498Szrj 	    }
751938fd1498Szrj 	  else
752038fd1498Szrj 	    empty_var->refcount++;
752138fd1498Szrj 	  empty_var->in_changed_variables = true;
752238fd1498Szrj 	  *slot = empty_var;
752338fd1498Szrj 	  if (onepart)
752438fd1498Szrj 	    {
752538fd1498Szrj 	      empty_var->var_part[0].loc_chain = NULL;
752638fd1498Szrj 	      empty_var->var_part[0].cur_loc = NULL;
752738fd1498Szrj 	      VAR_LOC_1PAUX (empty_var) = VAR_LOC_1PAUX (var);
752838fd1498Szrj 	      VAR_LOC_1PAUX (var) = NULL;
752938fd1498Szrj 	    }
753038fd1498Szrj 	  goto drop_var;
753138fd1498Szrj 	}
753238fd1498Szrj       else
753338fd1498Szrj 	{
753438fd1498Szrj 	  if (var->onepart && !VAR_LOC_1PAUX (var))
753538fd1498Szrj 	    recover_dropped_1paux (var);
753638fd1498Szrj 	  var->refcount++;
753738fd1498Szrj 	  var->in_changed_variables = true;
753838fd1498Szrj 	  *slot = var;
753938fd1498Szrj 	}
754038fd1498Szrj     }
754138fd1498Szrj   else
754238fd1498Szrj     {
754338fd1498Szrj       gcc_assert (set);
754438fd1498Szrj       if (var->n_var_parts == 0)
754538fd1498Szrj 	{
754638fd1498Szrj 	  variable **slot;
754738fd1498Szrj 
754838fd1498Szrj 	drop_var:
754938fd1498Szrj 	  slot = shared_hash_find_slot_noinsert (set->vars, var->dv);
755038fd1498Szrj 	  if (slot)
755138fd1498Szrj 	    {
755238fd1498Szrj 	      if (shared_hash_shared (set->vars))
755338fd1498Szrj 		slot = shared_hash_find_slot_unshare (&set->vars, var->dv,
755438fd1498Szrj 						      NO_INSERT);
755538fd1498Szrj 	      shared_hash_htab (set->vars)->clear_slot (slot);
755638fd1498Szrj 	    }
755738fd1498Szrj 	}
755838fd1498Szrj     }
755938fd1498Szrj }
756038fd1498Szrj 
756138fd1498Szrj /* Look for the index in VAR->var_part corresponding to OFFSET.
756238fd1498Szrj    Return -1 if not found.  If INSERTION_POINT is non-NULL, the
756338fd1498Szrj    referenced int will be set to the index that the part has or should
756438fd1498Szrj    have, if it should be inserted.  */
756538fd1498Szrj 
756638fd1498Szrj static inline int
find_variable_location_part(variable * var,HOST_WIDE_INT offset,int * insertion_point)756738fd1498Szrj find_variable_location_part (variable *var, HOST_WIDE_INT offset,
756838fd1498Szrj 			     int *insertion_point)
756938fd1498Szrj {
757038fd1498Szrj   int pos, low, high;
757138fd1498Szrj 
757238fd1498Szrj   if (var->onepart)
757338fd1498Szrj     {
757438fd1498Szrj       if (offset != 0)
757538fd1498Szrj 	return -1;
757638fd1498Szrj 
757738fd1498Szrj       if (insertion_point)
757838fd1498Szrj 	*insertion_point = 0;
757938fd1498Szrj 
758038fd1498Szrj       return var->n_var_parts - 1;
758138fd1498Szrj     }
758238fd1498Szrj 
758338fd1498Szrj   /* Find the location part.  */
758438fd1498Szrj   low = 0;
758538fd1498Szrj   high = var->n_var_parts;
758638fd1498Szrj   while (low != high)
758738fd1498Szrj     {
758838fd1498Szrj       pos = (low + high) / 2;
758938fd1498Szrj       if (VAR_PART_OFFSET (var, pos) < offset)
759038fd1498Szrj 	low = pos + 1;
759138fd1498Szrj       else
759238fd1498Szrj 	high = pos;
759338fd1498Szrj     }
759438fd1498Szrj   pos = low;
759538fd1498Szrj 
759638fd1498Szrj   if (insertion_point)
759738fd1498Szrj     *insertion_point = pos;
759838fd1498Szrj 
759938fd1498Szrj   if (pos < var->n_var_parts && VAR_PART_OFFSET (var, pos) == offset)
760038fd1498Szrj     return pos;
760138fd1498Szrj 
760238fd1498Szrj   return -1;
760338fd1498Szrj }
760438fd1498Szrj 
760538fd1498Szrj static variable **
set_slot_part(dataflow_set * set,rtx loc,variable ** slot,decl_or_value dv,HOST_WIDE_INT offset,enum var_init_status initialized,rtx set_src)760638fd1498Szrj set_slot_part (dataflow_set *set, rtx loc, variable **slot,
760738fd1498Szrj 	       decl_or_value dv, HOST_WIDE_INT offset,
760838fd1498Szrj 	       enum var_init_status initialized, rtx set_src)
760938fd1498Szrj {
761038fd1498Szrj   int pos;
761138fd1498Szrj   location_chain *node, *next;
761238fd1498Szrj   location_chain **nextp;
761338fd1498Szrj   variable *var;
761438fd1498Szrj   onepart_enum onepart;
761538fd1498Szrj 
761638fd1498Szrj   var = *slot;
761738fd1498Szrj 
761838fd1498Szrj   if (var)
761938fd1498Szrj     onepart = var->onepart;
762038fd1498Szrj   else
762138fd1498Szrj     onepart = dv_onepart_p (dv);
762238fd1498Szrj 
762338fd1498Szrj   gcc_checking_assert (offset == 0 || !onepart);
762438fd1498Szrj   gcc_checking_assert (loc != dv_as_opaque (dv));
762538fd1498Szrj 
762638fd1498Szrj   if (! flag_var_tracking_uninit)
762738fd1498Szrj     initialized = VAR_INIT_STATUS_INITIALIZED;
762838fd1498Szrj 
762938fd1498Szrj   if (!var)
763038fd1498Szrj     {
763138fd1498Szrj       /* Create new variable information.  */
763238fd1498Szrj       var = onepart_pool_allocate (onepart);
763338fd1498Szrj       var->dv = dv;
763438fd1498Szrj       var->refcount = 1;
763538fd1498Szrj       var->n_var_parts = 1;
763638fd1498Szrj       var->onepart = onepart;
763738fd1498Szrj       var->in_changed_variables = false;
763838fd1498Szrj       if (var->onepart)
763938fd1498Szrj 	VAR_LOC_1PAUX (var) = NULL;
764038fd1498Szrj       else
764138fd1498Szrj 	VAR_PART_OFFSET (var, 0) = offset;
764238fd1498Szrj       var->var_part[0].loc_chain = NULL;
764338fd1498Szrj       var->var_part[0].cur_loc = NULL;
764438fd1498Szrj       *slot = var;
764538fd1498Szrj       pos = 0;
764638fd1498Szrj       nextp = &var->var_part[0].loc_chain;
764738fd1498Szrj     }
764838fd1498Szrj   else if (onepart)
764938fd1498Szrj     {
765038fd1498Szrj       int r = -1, c = 0;
765138fd1498Szrj 
765238fd1498Szrj       gcc_assert (dv_as_opaque (var->dv) == dv_as_opaque (dv));
765338fd1498Szrj 
765438fd1498Szrj       pos = 0;
765538fd1498Szrj 
765638fd1498Szrj       if (GET_CODE (loc) == VALUE)
765738fd1498Szrj 	{
765838fd1498Szrj 	  for (nextp = &var->var_part[0].loc_chain; (node = *nextp);
765938fd1498Szrj 	       nextp = &node->next)
766038fd1498Szrj 	    if (GET_CODE (node->loc) == VALUE)
766138fd1498Szrj 	      {
766238fd1498Szrj 		if (node->loc == loc)
766338fd1498Szrj 		  {
766438fd1498Szrj 		    r = 0;
766538fd1498Szrj 		    break;
766638fd1498Szrj 		  }
766738fd1498Szrj 		if (canon_value_cmp (node->loc, loc))
766838fd1498Szrj 		  c++;
766938fd1498Szrj 		else
767038fd1498Szrj 		  {
767138fd1498Szrj 		    r = 1;
767238fd1498Szrj 		    break;
767338fd1498Szrj 		  }
767438fd1498Szrj 	      }
767538fd1498Szrj 	    else if (REG_P (node->loc) || MEM_P (node->loc))
767638fd1498Szrj 	      c++;
767738fd1498Szrj 	    else
767838fd1498Szrj 	      {
767938fd1498Szrj 		r = 1;
768038fd1498Szrj 		break;
768138fd1498Szrj 	      }
768238fd1498Szrj 	}
768338fd1498Szrj       else if (REG_P (loc))
768438fd1498Szrj 	{
768538fd1498Szrj 	  for (nextp = &var->var_part[0].loc_chain; (node = *nextp);
768638fd1498Szrj 	       nextp = &node->next)
768738fd1498Szrj 	    if (REG_P (node->loc))
768838fd1498Szrj 	      {
768938fd1498Szrj 		if (REGNO (node->loc) < REGNO (loc))
769038fd1498Szrj 		  c++;
769138fd1498Szrj 		else
769238fd1498Szrj 		  {
769338fd1498Szrj 		    if (REGNO (node->loc) == REGNO (loc))
769438fd1498Szrj 		      r = 0;
769538fd1498Szrj 		    else
769638fd1498Szrj 		      r = 1;
769738fd1498Szrj 		    break;
769838fd1498Szrj 		  }
769938fd1498Szrj 	      }
770038fd1498Szrj 	    else
770138fd1498Szrj 	      {
770238fd1498Szrj 		r = 1;
770338fd1498Szrj 		break;
770438fd1498Szrj 	      }
770538fd1498Szrj 	}
770638fd1498Szrj       else if (MEM_P (loc))
770738fd1498Szrj 	{
770838fd1498Szrj 	  for (nextp = &var->var_part[0].loc_chain; (node = *nextp);
770938fd1498Szrj 	       nextp = &node->next)
771038fd1498Szrj 	    if (REG_P (node->loc))
771138fd1498Szrj 	      c++;
771238fd1498Szrj 	    else if (MEM_P (node->loc))
771338fd1498Szrj 	      {
771438fd1498Szrj 		if ((r = loc_cmp (XEXP (node->loc, 0), XEXP (loc, 0))) >= 0)
771538fd1498Szrj 		  break;
771638fd1498Szrj 		else
771738fd1498Szrj 		  c++;
771838fd1498Szrj 	      }
771938fd1498Szrj 	    else
772038fd1498Szrj 	      {
772138fd1498Szrj 		r = 1;
772238fd1498Szrj 		break;
772338fd1498Szrj 	      }
772438fd1498Szrj 	}
772538fd1498Szrj       else
772638fd1498Szrj 	for (nextp = &var->var_part[0].loc_chain; (node = *nextp);
772738fd1498Szrj 	     nextp = &node->next)
772838fd1498Szrj 	  if ((r = loc_cmp (node->loc, loc)) >= 0)
772938fd1498Szrj 	    break;
773038fd1498Szrj 	  else
773138fd1498Szrj 	    c++;
773238fd1498Szrj 
773338fd1498Szrj       if (r == 0)
773438fd1498Szrj 	return slot;
773538fd1498Szrj 
773638fd1498Szrj       if (shared_var_p (var, set->vars))
773738fd1498Szrj 	{
773838fd1498Szrj 	  slot = unshare_variable (set, slot, var, initialized);
773938fd1498Szrj 	  var = *slot;
774038fd1498Szrj 	  for (nextp = &var->var_part[0].loc_chain; c;
774138fd1498Szrj 	       nextp = &(*nextp)->next)
774238fd1498Szrj 	    c--;
774338fd1498Szrj 	  gcc_assert ((!node && !*nextp) || node->loc == (*nextp)->loc);
774438fd1498Szrj 	}
774538fd1498Szrj     }
774638fd1498Szrj   else
774738fd1498Szrj     {
774838fd1498Szrj       int inspos = 0;
774938fd1498Szrj 
775038fd1498Szrj       gcc_assert (dv_as_decl (var->dv) == dv_as_decl (dv));
775138fd1498Szrj 
775238fd1498Szrj       pos = find_variable_location_part (var, offset, &inspos);
775338fd1498Szrj 
775438fd1498Szrj       if (pos >= 0)
775538fd1498Szrj 	{
775638fd1498Szrj 	  node = var->var_part[pos].loc_chain;
775738fd1498Szrj 
775838fd1498Szrj 	  if (node
775938fd1498Szrj 	      && ((REG_P (node->loc) && REG_P (loc)
776038fd1498Szrj 		   && REGNO (node->loc) == REGNO (loc))
776138fd1498Szrj 		  || rtx_equal_p (node->loc, loc)))
776238fd1498Szrj 	    {
776338fd1498Szrj 	      /* LOC is in the beginning of the chain so we have nothing
776438fd1498Szrj 		 to do.  */
776538fd1498Szrj 	      if (node->init < initialized)
776638fd1498Szrj 		node->init = initialized;
776738fd1498Szrj 	      if (set_src != NULL)
776838fd1498Szrj 		node->set_src = set_src;
776938fd1498Szrj 
777038fd1498Szrj 	      return slot;
777138fd1498Szrj 	    }
777238fd1498Szrj 	  else
777338fd1498Szrj 	    {
777438fd1498Szrj 	      /* We have to make a copy of a shared variable.  */
777538fd1498Szrj 	      if (shared_var_p (var, set->vars))
777638fd1498Szrj 		{
777738fd1498Szrj 		  slot = unshare_variable (set, slot, var, initialized);
777838fd1498Szrj 		  var = *slot;
777938fd1498Szrj 		}
778038fd1498Szrj 	    }
778138fd1498Szrj 	}
778238fd1498Szrj       else
778338fd1498Szrj 	{
778438fd1498Szrj 	  /* We have not found the location part, new one will be created.  */
778538fd1498Szrj 
778638fd1498Szrj 	  /* We have to make a copy of the shared variable.  */
778738fd1498Szrj 	  if (shared_var_p (var, set->vars))
778838fd1498Szrj 	    {
778938fd1498Szrj 	      slot = unshare_variable (set, slot, var, initialized);
779038fd1498Szrj 	      var = *slot;
779138fd1498Szrj 	    }
779238fd1498Szrj 
779338fd1498Szrj 	  /* We track only variables whose size is <= MAX_VAR_PARTS bytes
779438fd1498Szrj 	     thus there are at most MAX_VAR_PARTS different offsets.  */
779538fd1498Szrj 	  gcc_assert (var->n_var_parts < MAX_VAR_PARTS
779638fd1498Szrj 		      && (!var->n_var_parts || !onepart));
779738fd1498Szrj 
779838fd1498Szrj 	  /* We have to move the elements of array starting at index
779938fd1498Szrj 	     inspos to the next position.  */
780038fd1498Szrj 	  for (pos = var->n_var_parts; pos > inspos; pos--)
780138fd1498Szrj 	    var->var_part[pos] = var->var_part[pos - 1];
780238fd1498Szrj 
780338fd1498Szrj 	  var->n_var_parts++;
780438fd1498Szrj 	  gcc_checking_assert (!onepart);
780538fd1498Szrj 	  VAR_PART_OFFSET (var, pos) = offset;
780638fd1498Szrj 	  var->var_part[pos].loc_chain = NULL;
780738fd1498Szrj 	  var->var_part[pos].cur_loc = NULL;
780838fd1498Szrj 	}
780938fd1498Szrj 
781038fd1498Szrj       /* Delete the location from the list.  */
781138fd1498Szrj       nextp = &var->var_part[pos].loc_chain;
781238fd1498Szrj       for (node = var->var_part[pos].loc_chain; node; node = next)
781338fd1498Szrj 	{
781438fd1498Szrj 	  next = node->next;
781538fd1498Szrj 	  if ((REG_P (node->loc) && REG_P (loc)
781638fd1498Szrj 	       && REGNO (node->loc) == REGNO (loc))
781738fd1498Szrj 	      || rtx_equal_p (node->loc, loc))
781838fd1498Szrj 	    {
781938fd1498Szrj 	      /* Save these values, to assign to the new node, before
782038fd1498Szrj 		 deleting this one.  */
782138fd1498Szrj 	      if (node->init > initialized)
782238fd1498Szrj 		initialized = node->init;
782338fd1498Szrj 	      if (node->set_src != NULL && set_src == NULL)
782438fd1498Szrj 		set_src = node->set_src;
782538fd1498Szrj 	      if (var->var_part[pos].cur_loc == node->loc)
782638fd1498Szrj 		var->var_part[pos].cur_loc = NULL;
782738fd1498Szrj 	      delete node;
782838fd1498Szrj 	      *nextp = next;
782938fd1498Szrj 	      break;
783038fd1498Szrj 	    }
783138fd1498Szrj 	  else
783238fd1498Szrj 	    nextp = &node->next;
783338fd1498Szrj 	}
783438fd1498Szrj 
783538fd1498Szrj       nextp = &var->var_part[pos].loc_chain;
783638fd1498Szrj     }
783738fd1498Szrj 
783838fd1498Szrj   /* Add the location to the beginning.  */
783938fd1498Szrj   node = new location_chain;
784038fd1498Szrj   node->loc = loc;
784138fd1498Szrj   node->init = initialized;
784238fd1498Szrj   node->set_src = set_src;
784338fd1498Szrj   node->next = *nextp;
784438fd1498Szrj   *nextp = node;
784538fd1498Szrj 
784638fd1498Szrj   /* If no location was emitted do so.  */
784738fd1498Szrj   if (var->var_part[pos].cur_loc == NULL)
784838fd1498Szrj     variable_was_changed (var, set);
784938fd1498Szrj 
785038fd1498Szrj   return slot;
785138fd1498Szrj }
785238fd1498Szrj 
785338fd1498Szrj /* Set the part of variable's location in the dataflow set SET.  The
785438fd1498Szrj    variable part is specified by variable's declaration in DV and
785538fd1498Szrj    offset OFFSET and the part's location by LOC.  IOPT should be
785638fd1498Szrj    NO_INSERT if the variable is known to be in SET already and the
785738fd1498Szrj    variable hash table must not be resized, and INSERT otherwise.  */
785838fd1498Szrj 
785938fd1498Szrj static void
set_variable_part(dataflow_set * set,rtx loc,decl_or_value dv,HOST_WIDE_INT offset,enum var_init_status initialized,rtx set_src,enum insert_option iopt)786038fd1498Szrj set_variable_part (dataflow_set *set, rtx loc,
786138fd1498Szrj 		   decl_or_value dv, HOST_WIDE_INT offset,
786238fd1498Szrj 		   enum var_init_status initialized, rtx set_src,
786338fd1498Szrj 		   enum insert_option iopt)
786438fd1498Szrj {
786538fd1498Szrj   variable **slot;
786638fd1498Szrj 
786738fd1498Szrj   if (iopt == NO_INSERT)
786838fd1498Szrj     slot = shared_hash_find_slot_noinsert (set->vars, dv);
786938fd1498Szrj   else
787038fd1498Szrj     {
787138fd1498Szrj       slot = shared_hash_find_slot (set->vars, dv);
787238fd1498Szrj       if (!slot)
787338fd1498Szrj 	slot = shared_hash_find_slot_unshare (&set->vars, dv, iopt);
787438fd1498Szrj     }
787538fd1498Szrj   set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
787638fd1498Szrj }
787738fd1498Szrj 
787838fd1498Szrj /* Remove all recorded register locations for the given variable part
787938fd1498Szrj    from dataflow set SET, except for those that are identical to loc.
788038fd1498Szrj    The variable part is specified by variable's declaration or value
788138fd1498Szrj    DV and offset OFFSET.  */
788238fd1498Szrj 
788338fd1498Szrj static variable **
clobber_slot_part(dataflow_set * set,rtx loc,variable ** slot,HOST_WIDE_INT offset,rtx set_src)788438fd1498Szrj clobber_slot_part (dataflow_set *set, rtx loc, variable **slot,
788538fd1498Szrj 		   HOST_WIDE_INT offset, rtx set_src)
788638fd1498Szrj {
788738fd1498Szrj   variable *var = *slot;
788838fd1498Szrj   int pos = find_variable_location_part (var, offset, NULL);
788938fd1498Szrj 
789038fd1498Szrj   if (pos >= 0)
789138fd1498Szrj     {
789238fd1498Szrj       location_chain *node, *next;
789338fd1498Szrj 
789438fd1498Szrj       /* Remove the register locations from the dataflow set.  */
789538fd1498Szrj       next = var->var_part[pos].loc_chain;
789638fd1498Szrj       for (node = next; node; node = next)
789738fd1498Szrj 	{
789838fd1498Szrj 	  next = node->next;
789938fd1498Szrj 	  if (node->loc != loc
790038fd1498Szrj 	      && (!flag_var_tracking_uninit
790138fd1498Szrj 		  || !set_src
790238fd1498Szrj 		  || MEM_P (set_src)
790338fd1498Szrj 		  || !rtx_equal_p (set_src, node->set_src)))
790438fd1498Szrj 	    {
790538fd1498Szrj 	      if (REG_P (node->loc))
790638fd1498Szrj 		{
790738fd1498Szrj 		  attrs *anode, *anext;
790838fd1498Szrj 		  attrs **anextp;
790938fd1498Szrj 
791038fd1498Szrj 		  /* Remove the variable part from the register's
791138fd1498Szrj 		     list, but preserve any other variable parts
791238fd1498Szrj 		     that might be regarded as live in that same
791338fd1498Szrj 		     register.  */
791438fd1498Szrj 		  anextp = &set->regs[REGNO (node->loc)];
791538fd1498Szrj 		  for (anode = *anextp; anode; anode = anext)
791638fd1498Szrj 		    {
791738fd1498Szrj 		      anext = anode->next;
791838fd1498Szrj 		      if (dv_as_opaque (anode->dv) == dv_as_opaque (var->dv)
791938fd1498Szrj 			  && anode->offset == offset)
792038fd1498Szrj 			{
792138fd1498Szrj 			  delete anode;
792238fd1498Szrj 			  *anextp = anext;
792338fd1498Szrj 			}
792438fd1498Szrj 		      else
792538fd1498Szrj 			anextp = &anode->next;
792638fd1498Szrj 		    }
792738fd1498Szrj 		}
792838fd1498Szrj 
792938fd1498Szrj 	      slot = delete_slot_part (set, node->loc, slot, offset);
793038fd1498Szrj 	    }
793138fd1498Szrj 	}
793238fd1498Szrj     }
793338fd1498Szrj 
793438fd1498Szrj   return slot;
793538fd1498Szrj }
793638fd1498Szrj 
793738fd1498Szrj /* Remove all recorded register locations for the given variable part
793838fd1498Szrj    from dataflow set SET, except for those that are identical to loc.
793938fd1498Szrj    The variable part is specified by variable's declaration or value
794038fd1498Szrj    DV and offset OFFSET.  */
794138fd1498Szrj 
794238fd1498Szrj static void
clobber_variable_part(dataflow_set * set,rtx loc,decl_or_value dv,HOST_WIDE_INT offset,rtx set_src)794338fd1498Szrj clobber_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
794438fd1498Szrj 		       HOST_WIDE_INT offset, rtx set_src)
794538fd1498Szrj {
794638fd1498Szrj   variable **slot;
794738fd1498Szrj 
794838fd1498Szrj   if (!dv_as_opaque (dv)
794938fd1498Szrj       || (!dv_is_value_p (dv) && ! DECL_P (dv_as_decl (dv))))
795038fd1498Szrj     return;
795138fd1498Szrj 
795238fd1498Szrj   slot = shared_hash_find_slot_noinsert (set->vars, dv);
795338fd1498Szrj   if (!slot)
795438fd1498Szrj     return;
795538fd1498Szrj 
795638fd1498Szrj   clobber_slot_part (set, loc, slot, offset, set_src);
795738fd1498Szrj }
795838fd1498Szrj 
795938fd1498Szrj /* Delete the part of variable's location from dataflow set SET.  The
796038fd1498Szrj    variable part is specified by its SET->vars slot SLOT and offset
796138fd1498Szrj    OFFSET and the part's location by LOC.  */
796238fd1498Szrj 
796338fd1498Szrj static variable **
delete_slot_part(dataflow_set * set,rtx loc,variable ** slot,HOST_WIDE_INT offset)796438fd1498Szrj delete_slot_part (dataflow_set *set, rtx loc, variable **slot,
796538fd1498Szrj 		  HOST_WIDE_INT offset)
796638fd1498Szrj {
796738fd1498Szrj   variable *var = *slot;
796838fd1498Szrj   int pos = find_variable_location_part (var, offset, NULL);
796938fd1498Szrj 
797038fd1498Szrj   if (pos >= 0)
797138fd1498Szrj     {
797238fd1498Szrj       location_chain *node, *next;
797338fd1498Szrj       location_chain **nextp;
797438fd1498Szrj       bool changed;
797538fd1498Szrj       rtx cur_loc;
797638fd1498Szrj 
797738fd1498Szrj       if (shared_var_p (var, set->vars))
797838fd1498Szrj 	{
797938fd1498Szrj 	  /* If the variable contains the location part we have to
798038fd1498Szrj 	     make a copy of the variable.  */
798138fd1498Szrj 	  for (node = var->var_part[pos].loc_chain; node;
798238fd1498Szrj 	       node = node->next)
798338fd1498Szrj 	    {
798438fd1498Szrj 	      if ((REG_P (node->loc) && REG_P (loc)
798538fd1498Szrj 		   && REGNO (node->loc) == REGNO (loc))
798638fd1498Szrj 		  || rtx_equal_p (node->loc, loc))
798738fd1498Szrj 		{
798838fd1498Szrj 		  slot = unshare_variable (set, slot, var,
798938fd1498Szrj 					   VAR_INIT_STATUS_UNKNOWN);
799038fd1498Szrj 		  var = *slot;
799138fd1498Szrj 		  break;
799238fd1498Szrj 		}
799338fd1498Szrj 	    }
799438fd1498Szrj 	}
799538fd1498Szrj 
799638fd1498Szrj       if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var))
799738fd1498Szrj 	cur_loc = VAR_LOC_FROM (var);
799838fd1498Szrj       else
799938fd1498Szrj 	cur_loc = var->var_part[pos].cur_loc;
800038fd1498Szrj 
800138fd1498Szrj       /* Delete the location part.  */
800238fd1498Szrj       changed = false;
800338fd1498Szrj       nextp = &var->var_part[pos].loc_chain;
800438fd1498Szrj       for (node = *nextp; node; node = next)
800538fd1498Szrj 	{
800638fd1498Szrj 	  next = node->next;
800738fd1498Szrj 	  if ((REG_P (node->loc) && REG_P (loc)
800838fd1498Szrj 	       && REGNO (node->loc) == REGNO (loc))
800938fd1498Szrj 	      || rtx_equal_p (node->loc, loc))
801038fd1498Szrj 	    {
801138fd1498Szrj 	      /* If we have deleted the location which was last emitted
801238fd1498Szrj 		 we have to emit new location so add the variable to set
801338fd1498Szrj 		 of changed variables.  */
801438fd1498Szrj 	      if (cur_loc == node->loc)
801538fd1498Szrj 		{
801638fd1498Szrj 		  changed = true;
801738fd1498Szrj 		  var->var_part[pos].cur_loc = NULL;
801838fd1498Szrj 		  if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var))
801938fd1498Szrj 		    VAR_LOC_FROM (var) = NULL;
802038fd1498Szrj 		}
802138fd1498Szrj 	      delete node;
802238fd1498Szrj 	      *nextp = next;
802338fd1498Szrj 	      break;
802438fd1498Szrj 	    }
802538fd1498Szrj 	  else
802638fd1498Szrj 	    nextp = &node->next;
802738fd1498Szrj 	}
802838fd1498Szrj 
802938fd1498Szrj       if (var->var_part[pos].loc_chain == NULL)
803038fd1498Szrj 	{
803138fd1498Szrj 	  changed = true;
803238fd1498Szrj 	  var->n_var_parts--;
803338fd1498Szrj 	  while (pos < var->n_var_parts)
803438fd1498Szrj 	    {
803538fd1498Szrj 	      var->var_part[pos] = var->var_part[pos + 1];
803638fd1498Szrj 	      pos++;
803738fd1498Szrj 	    }
803838fd1498Szrj 	}
803938fd1498Szrj       if (changed)
804038fd1498Szrj 	variable_was_changed (var, set);
804138fd1498Szrj     }
804238fd1498Szrj 
804338fd1498Szrj   return slot;
804438fd1498Szrj }
804538fd1498Szrj 
804638fd1498Szrj /* Delete the part of variable's location from dataflow set SET.  The
804738fd1498Szrj    variable part is specified by variable's declaration or value DV
804838fd1498Szrj    and offset OFFSET and the part's location by LOC.  */
804938fd1498Szrj 
805038fd1498Szrj static void
delete_variable_part(dataflow_set * set,rtx loc,decl_or_value dv,HOST_WIDE_INT offset)805138fd1498Szrj delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
805238fd1498Szrj 		      HOST_WIDE_INT offset)
805338fd1498Szrj {
805438fd1498Szrj   variable **slot = shared_hash_find_slot_noinsert (set->vars, dv);
805538fd1498Szrj   if (!slot)
805638fd1498Szrj     return;
805738fd1498Szrj 
805838fd1498Szrj   delete_slot_part (set, loc, slot, offset);
805938fd1498Szrj }
806038fd1498Szrj 
806138fd1498Szrj 
806238fd1498Szrj /* Structure for passing some other parameters to function
806338fd1498Szrj    vt_expand_loc_callback.  */
806438fd1498Szrj struct expand_loc_callback_data
806538fd1498Szrj {
806638fd1498Szrj   /* The variables and values active at this point.  */
806738fd1498Szrj   variable_table_type *vars;
806838fd1498Szrj 
806938fd1498Szrj   /* Stack of values and debug_exprs under expansion, and their
807038fd1498Szrj      children.  */
807138fd1498Szrj   auto_vec<rtx, 4> expanding;
807238fd1498Szrj 
807338fd1498Szrj   /* Stack of values and debug_exprs whose expansion hit recursion
807438fd1498Szrj      cycles.  They will have VALUE_RECURSED_INTO marked when added to
807538fd1498Szrj      this list.  This flag will be cleared if any of its dependencies
807638fd1498Szrj      resolves to a valid location.  So, if the flag remains set at the
807738fd1498Szrj      end of the search, we know no valid location for this one can
807838fd1498Szrj      possibly exist.  */
807938fd1498Szrj   auto_vec<rtx, 4> pending;
808038fd1498Szrj 
808138fd1498Szrj   /* The maximum depth among the sub-expressions under expansion.
808238fd1498Szrj      Zero indicates no expansion so far.  */
808338fd1498Szrj   expand_depth depth;
808438fd1498Szrj };
808538fd1498Szrj 
808638fd1498Szrj /* Allocate the one-part auxiliary data structure for VAR, with enough
808738fd1498Szrj    room for COUNT dependencies.  */
808838fd1498Szrj 
808938fd1498Szrj static void
loc_exp_dep_alloc(variable * var,int count)809038fd1498Szrj loc_exp_dep_alloc (variable *var, int count)
809138fd1498Szrj {
809238fd1498Szrj   size_t allocsize;
809338fd1498Szrj 
809438fd1498Szrj   gcc_checking_assert (var->onepart);
809538fd1498Szrj 
809638fd1498Szrj   /* We can be called with COUNT == 0 to allocate the data structure
809738fd1498Szrj      without any dependencies, e.g. for the backlinks only.  However,
809838fd1498Szrj      if we are specifying a COUNT, then the dependency list must have
809938fd1498Szrj      been emptied before.  It would be possible to adjust pointers or
810038fd1498Szrj      force it empty here, but this is better done at an earlier point
810138fd1498Szrj      in the algorithm, so we instead leave an assertion to catch
810238fd1498Szrj      errors.  */
810338fd1498Szrj   gcc_checking_assert (!count
810438fd1498Szrj 		       || VAR_LOC_DEP_VEC (var) == NULL
810538fd1498Szrj 		       || VAR_LOC_DEP_VEC (var)->is_empty ());
810638fd1498Szrj 
810738fd1498Szrj   if (VAR_LOC_1PAUX (var) && VAR_LOC_DEP_VEC (var)->space (count))
810838fd1498Szrj     return;
810938fd1498Szrj 
811038fd1498Szrj   allocsize = offsetof (struct onepart_aux, deps)
811138fd1498Szrj 	      + vec<loc_exp_dep, va_heap, vl_embed>::embedded_size (count);
811238fd1498Szrj 
811338fd1498Szrj   if (VAR_LOC_1PAUX (var))
811438fd1498Szrj     {
811538fd1498Szrj       VAR_LOC_1PAUX (var) = XRESIZEVAR (struct onepart_aux,
811638fd1498Szrj 					VAR_LOC_1PAUX (var), allocsize);
811738fd1498Szrj       /* If the reallocation moves the onepaux structure, the
811838fd1498Szrj 	 back-pointer to BACKLINKS in the first list member will still
811938fd1498Szrj 	 point to its old location.  Adjust it.  */
812038fd1498Szrj       if (VAR_LOC_DEP_LST (var))
812138fd1498Szrj 	VAR_LOC_DEP_LST (var)->pprev = VAR_LOC_DEP_LSTP (var);
812238fd1498Szrj     }
812338fd1498Szrj   else
812438fd1498Szrj     {
812538fd1498Szrj       VAR_LOC_1PAUX (var) = XNEWVAR (struct onepart_aux, allocsize);
812638fd1498Szrj       *VAR_LOC_DEP_LSTP (var) = NULL;
812738fd1498Szrj       VAR_LOC_FROM (var) = NULL;
812838fd1498Szrj       VAR_LOC_DEPTH (var).complexity = 0;
812938fd1498Szrj       VAR_LOC_DEPTH (var).entryvals = 0;
813038fd1498Szrj     }
813138fd1498Szrj   VAR_LOC_DEP_VEC (var)->embedded_init (count);
813238fd1498Szrj }
813338fd1498Szrj 
813438fd1498Szrj /* Remove all entries from the vector of active dependencies of VAR,
813538fd1498Szrj    removing them from the back-links lists too.  */
813638fd1498Szrj 
813738fd1498Szrj static void
loc_exp_dep_clear(variable * var)813838fd1498Szrj loc_exp_dep_clear (variable *var)
813938fd1498Szrj {
814038fd1498Szrj   while (VAR_LOC_DEP_VEC (var) && !VAR_LOC_DEP_VEC (var)->is_empty ())
814138fd1498Szrj     {
814238fd1498Szrj       loc_exp_dep *led = &VAR_LOC_DEP_VEC (var)->last ();
814338fd1498Szrj       if (led->next)
814438fd1498Szrj 	led->next->pprev = led->pprev;
814538fd1498Szrj       if (led->pprev)
814638fd1498Szrj 	*led->pprev = led->next;
814738fd1498Szrj       VAR_LOC_DEP_VEC (var)->pop ();
814838fd1498Szrj     }
814938fd1498Szrj }
815038fd1498Szrj 
815138fd1498Szrj /* Insert an active dependency from VAR on X to the vector of
815238fd1498Szrj    dependencies, and add the corresponding back-link to X's list of
815338fd1498Szrj    back-links in VARS.  */
815438fd1498Szrj 
815538fd1498Szrj static void
loc_exp_insert_dep(variable * var,rtx x,variable_table_type * vars)815638fd1498Szrj loc_exp_insert_dep (variable *var, rtx x, variable_table_type *vars)
815738fd1498Szrj {
815838fd1498Szrj   decl_or_value dv;
815938fd1498Szrj   variable *xvar;
816038fd1498Szrj   loc_exp_dep *led;
816138fd1498Szrj 
816238fd1498Szrj   dv = dv_from_rtx (x);
816338fd1498Szrj 
816438fd1498Szrj   /* ??? Build a vector of variables parallel to EXPANDING, to avoid
816538fd1498Szrj      an additional look up?  */
816638fd1498Szrj   xvar = vars->find_with_hash (dv, dv_htab_hash (dv));
816738fd1498Szrj 
816838fd1498Szrj   if (!xvar)
816938fd1498Szrj     {
817038fd1498Szrj       xvar = variable_from_dropped (dv, NO_INSERT);
817138fd1498Szrj       gcc_checking_assert (xvar);
817238fd1498Szrj     }
817338fd1498Szrj 
817438fd1498Szrj   /* No point in adding the same backlink more than once.  This may
817538fd1498Szrj      arise if say the same value appears in two complex expressions in
817638fd1498Szrj      the same loc_list, or even more than once in a single
817738fd1498Szrj      expression.  */
817838fd1498Szrj   if (VAR_LOC_DEP_LST (xvar) && VAR_LOC_DEP_LST (xvar)->dv == var->dv)
817938fd1498Szrj     return;
818038fd1498Szrj 
818138fd1498Szrj   if (var->onepart == NOT_ONEPART)
818238fd1498Szrj     led = new loc_exp_dep;
818338fd1498Szrj   else
818438fd1498Szrj     {
818538fd1498Szrj       loc_exp_dep empty;
818638fd1498Szrj       memset (&empty, 0, sizeof (empty));
818738fd1498Szrj       VAR_LOC_DEP_VEC (var)->quick_push (empty);
818838fd1498Szrj       led = &VAR_LOC_DEP_VEC (var)->last ();
818938fd1498Szrj     }
819038fd1498Szrj   led->dv = var->dv;
819138fd1498Szrj   led->value = x;
819238fd1498Szrj 
819338fd1498Szrj   loc_exp_dep_alloc (xvar, 0);
819438fd1498Szrj   led->pprev = VAR_LOC_DEP_LSTP (xvar);
819538fd1498Szrj   led->next = *led->pprev;
819638fd1498Szrj   if (led->next)
819738fd1498Szrj     led->next->pprev = &led->next;
819838fd1498Szrj   *led->pprev = led;
819938fd1498Szrj }
820038fd1498Szrj 
820138fd1498Szrj /* Create active dependencies of VAR on COUNT values starting at
820238fd1498Szrj    VALUE, and corresponding back-links to the entries in VARS.  Return
820338fd1498Szrj    true if we found any pending-recursion results.  */
820438fd1498Szrj 
820538fd1498Szrj static bool
loc_exp_dep_set(variable * var,rtx result,rtx * value,int count,variable_table_type * vars)820638fd1498Szrj loc_exp_dep_set (variable *var, rtx result, rtx *value, int count,
820738fd1498Szrj 		 variable_table_type *vars)
820838fd1498Szrj {
820938fd1498Szrj   bool pending_recursion = false;
821038fd1498Szrj 
821138fd1498Szrj   gcc_checking_assert (VAR_LOC_DEP_VEC (var) == NULL
821238fd1498Szrj 		       || VAR_LOC_DEP_VEC (var)->is_empty ());
821338fd1498Szrj 
821438fd1498Szrj   /* Set up all dependencies from last_child (as set up at the end of
821538fd1498Szrj      the loop above) to the end.  */
821638fd1498Szrj   loc_exp_dep_alloc (var, count);
821738fd1498Szrj 
821838fd1498Szrj   while (count--)
821938fd1498Szrj     {
822038fd1498Szrj       rtx x = *value++;
822138fd1498Szrj 
822238fd1498Szrj       if (!pending_recursion)
822338fd1498Szrj 	pending_recursion = !result && VALUE_RECURSED_INTO (x);
822438fd1498Szrj 
822538fd1498Szrj       loc_exp_insert_dep (var, x, vars);
822638fd1498Szrj     }
822738fd1498Szrj 
822838fd1498Szrj   return pending_recursion;
822938fd1498Szrj }
823038fd1498Szrj 
823138fd1498Szrj /* Notify the back-links of IVAR that are pending recursion that we
823238fd1498Szrj    have found a non-NIL value for it, so they are cleared for another
823338fd1498Szrj    attempt to compute a current location.  */
823438fd1498Szrj 
823538fd1498Szrj static void
notify_dependents_of_resolved_value(variable * ivar,variable_table_type * vars)823638fd1498Szrj notify_dependents_of_resolved_value (variable *ivar, variable_table_type *vars)
823738fd1498Szrj {
823838fd1498Szrj   loc_exp_dep *led, *next;
823938fd1498Szrj 
824038fd1498Szrj   for (led = VAR_LOC_DEP_LST (ivar); led; led = next)
824138fd1498Szrj     {
824238fd1498Szrj       decl_or_value dv = led->dv;
824338fd1498Szrj       variable *var;
824438fd1498Szrj 
824538fd1498Szrj       next = led->next;
824638fd1498Szrj 
824738fd1498Szrj       if (dv_is_value_p (dv))
824838fd1498Szrj 	{
824938fd1498Szrj 	  rtx value = dv_as_value (dv);
825038fd1498Szrj 
825138fd1498Szrj 	  /* If we have already resolved it, leave it alone.  */
825238fd1498Szrj 	  if (!VALUE_RECURSED_INTO (value))
825338fd1498Szrj 	    continue;
825438fd1498Szrj 
825538fd1498Szrj 	  /* Check that VALUE_RECURSED_INTO, true from the test above,
825638fd1498Szrj 	     implies NO_LOC_P.  */
825738fd1498Szrj 	  gcc_checking_assert (NO_LOC_P (value));
825838fd1498Szrj 
825938fd1498Szrj 	  /* We won't notify variables that are being expanded,
826038fd1498Szrj 	     because their dependency list is cleared before
826138fd1498Szrj 	     recursing.  */
826238fd1498Szrj 	  NO_LOC_P (value) = false;
826338fd1498Szrj 	  VALUE_RECURSED_INTO (value) = false;
826438fd1498Szrj 
826538fd1498Szrj 	  gcc_checking_assert (dv_changed_p (dv));
826638fd1498Szrj 	}
826738fd1498Szrj       else
826838fd1498Szrj 	{
826938fd1498Szrj 	  gcc_checking_assert (dv_onepart_p (dv) != NOT_ONEPART);
827038fd1498Szrj 	  if (!dv_changed_p (dv))
827138fd1498Szrj 	    continue;
827238fd1498Szrj       }
827338fd1498Szrj 
827438fd1498Szrj       var = vars->find_with_hash (dv, dv_htab_hash (dv));
827538fd1498Szrj 
827638fd1498Szrj       if (!var)
827738fd1498Szrj 	var = variable_from_dropped (dv, NO_INSERT);
827838fd1498Szrj 
827938fd1498Szrj       if (var)
828038fd1498Szrj 	notify_dependents_of_resolved_value (var, vars);
828138fd1498Szrj 
828238fd1498Szrj       if (next)
828338fd1498Szrj 	next->pprev = led->pprev;
828438fd1498Szrj       if (led->pprev)
828538fd1498Szrj 	*led->pprev = next;
828638fd1498Szrj       led->next = NULL;
828738fd1498Szrj       led->pprev = NULL;
828838fd1498Szrj     }
828938fd1498Szrj }
829038fd1498Szrj 
829138fd1498Szrj static rtx vt_expand_loc_callback (rtx x, bitmap regs,
829238fd1498Szrj 				   int max_depth, void *data);
829338fd1498Szrj 
829438fd1498Szrj /* Return the combined depth, when one sub-expression evaluated to
829538fd1498Szrj    BEST_DEPTH and the previous known depth was SAVED_DEPTH.  */
829638fd1498Szrj 
829738fd1498Szrj static inline expand_depth
update_depth(expand_depth saved_depth,expand_depth best_depth)829838fd1498Szrj update_depth (expand_depth saved_depth, expand_depth best_depth)
829938fd1498Szrj {
830038fd1498Szrj   /* If we didn't find anything, stick with what we had.  */
830138fd1498Szrj   if (!best_depth.complexity)
830238fd1498Szrj     return saved_depth;
830338fd1498Szrj 
830438fd1498Szrj   /* If we found hadn't found anything, use the depth of the current
830538fd1498Szrj      expression.  Do NOT add one extra level, we want to compute the
830638fd1498Szrj      maximum depth among sub-expressions.  We'll increment it later,
830738fd1498Szrj      if appropriate.  */
830838fd1498Szrj   if (!saved_depth.complexity)
830938fd1498Szrj     return best_depth;
831038fd1498Szrj 
831138fd1498Szrj   /* Combine the entryval count so that regardless of which one we
831238fd1498Szrj      return, the entryval count is accurate.  */
831338fd1498Szrj   best_depth.entryvals = saved_depth.entryvals
831438fd1498Szrj     = best_depth.entryvals + saved_depth.entryvals;
831538fd1498Szrj 
831638fd1498Szrj   if (saved_depth.complexity < best_depth.complexity)
831738fd1498Szrj     return best_depth;
831838fd1498Szrj   else
831938fd1498Szrj     return saved_depth;
832038fd1498Szrj }
832138fd1498Szrj 
832238fd1498Szrj /* Expand VAR to a location RTX, updating its cur_loc.  Use REGS and
832338fd1498Szrj    DATA for cselib expand callback.  If PENDRECP is given, indicate in
832438fd1498Szrj    it whether any sub-expression couldn't be fully evaluated because
832538fd1498Szrj    it is pending recursion resolution.  */
832638fd1498Szrj 
832738fd1498Szrj static inline rtx
vt_expand_var_loc_chain(variable * var,bitmap regs,void * data,bool * pendrecp)832838fd1498Szrj vt_expand_var_loc_chain (variable *var, bitmap regs, void *data,
832938fd1498Szrj 			 bool *pendrecp)
833038fd1498Szrj {
833138fd1498Szrj   struct expand_loc_callback_data *elcd
833238fd1498Szrj     = (struct expand_loc_callback_data *) data;
833338fd1498Szrj   location_chain *loc, *next;
833438fd1498Szrj   rtx result = NULL;
833538fd1498Szrj   int first_child, result_first_child, last_child;
833638fd1498Szrj   bool pending_recursion;
833738fd1498Szrj   rtx loc_from = NULL;
833838fd1498Szrj   struct elt_loc_list *cloc = NULL;
833938fd1498Szrj   expand_depth depth = { 0, 0 }, saved_depth = elcd->depth;
834038fd1498Szrj   int wanted_entryvals, found_entryvals = 0;
834138fd1498Szrj 
834238fd1498Szrj   /* Clear all backlinks pointing at this, so that we're not notified
834338fd1498Szrj      while we're active.  */
834438fd1498Szrj   loc_exp_dep_clear (var);
834538fd1498Szrj 
834638fd1498Szrj  retry:
834738fd1498Szrj   if (var->onepart == ONEPART_VALUE)
834838fd1498Szrj     {
834938fd1498Szrj       cselib_val *val = CSELIB_VAL_PTR (dv_as_value (var->dv));
835038fd1498Szrj 
835138fd1498Szrj       gcc_checking_assert (cselib_preserved_value_p (val));
835238fd1498Szrj 
835338fd1498Szrj       cloc = val->locs;
835438fd1498Szrj     }
835538fd1498Szrj 
835638fd1498Szrj   first_child = result_first_child = last_child
835738fd1498Szrj     = elcd->expanding.length ();
835838fd1498Szrj 
835938fd1498Szrj   wanted_entryvals = found_entryvals;
836038fd1498Szrj 
836138fd1498Szrj   /* Attempt to expand each available location in turn.  */
836238fd1498Szrj   for (next = loc = var->n_var_parts ? var->var_part[0].loc_chain : NULL;
836338fd1498Szrj        loc || cloc; loc = next)
836438fd1498Szrj     {
836538fd1498Szrj       result_first_child = last_child;
836638fd1498Szrj 
836738fd1498Szrj       if (!loc)
836838fd1498Szrj 	{
836938fd1498Szrj 	  loc_from = cloc->loc;
837038fd1498Szrj 	  next = loc;
837138fd1498Szrj 	  cloc = cloc->next;
837238fd1498Szrj 	  if (unsuitable_loc (loc_from))
837338fd1498Szrj 	    continue;
837438fd1498Szrj 	}
837538fd1498Szrj       else
837638fd1498Szrj 	{
837738fd1498Szrj 	  loc_from = loc->loc;
837838fd1498Szrj 	  next = loc->next;
837938fd1498Szrj 	}
838038fd1498Szrj 
838138fd1498Szrj       gcc_checking_assert (!unsuitable_loc (loc_from));
838238fd1498Szrj 
838338fd1498Szrj       elcd->depth.complexity = elcd->depth.entryvals = 0;
838438fd1498Szrj       result = cselib_expand_value_rtx_cb (loc_from, regs, EXPR_DEPTH,
838538fd1498Szrj 					   vt_expand_loc_callback, data);
838638fd1498Szrj       last_child = elcd->expanding.length ();
838738fd1498Szrj 
838838fd1498Szrj       if (result)
838938fd1498Szrj 	{
839038fd1498Szrj 	  depth = elcd->depth;
839138fd1498Szrj 
839238fd1498Szrj 	  gcc_checking_assert (depth.complexity
839338fd1498Szrj 			       || result_first_child == last_child);
839438fd1498Szrj 
839538fd1498Szrj 	  if (last_child - result_first_child != 1)
839638fd1498Szrj 	    {
839738fd1498Szrj 	      if (!depth.complexity && GET_CODE (result) == ENTRY_VALUE)
839838fd1498Szrj 		depth.entryvals++;
839938fd1498Szrj 	      depth.complexity++;
840038fd1498Szrj 	    }
840138fd1498Szrj 
840238fd1498Szrj 	  if (depth.complexity <= EXPR_USE_DEPTH)
840338fd1498Szrj 	    {
840438fd1498Szrj 	      if (depth.entryvals <= wanted_entryvals)
840538fd1498Szrj 		break;
840638fd1498Szrj 	      else if (!found_entryvals || depth.entryvals < found_entryvals)
840738fd1498Szrj 		found_entryvals = depth.entryvals;
840838fd1498Szrj 	    }
840938fd1498Szrj 
841038fd1498Szrj 	  result = NULL;
841138fd1498Szrj 	}
841238fd1498Szrj 
841338fd1498Szrj       /* Set it up in case we leave the loop.  */
841438fd1498Szrj       depth.complexity = depth.entryvals = 0;
841538fd1498Szrj       loc_from = NULL;
841638fd1498Szrj       result_first_child = first_child;
841738fd1498Szrj     }
841838fd1498Szrj 
841938fd1498Szrj   if (!loc_from && wanted_entryvals < found_entryvals)
842038fd1498Szrj     {
842138fd1498Szrj       /* We found entries with ENTRY_VALUEs and skipped them.  Since
842238fd1498Szrj 	 we could not find any expansions without ENTRY_VALUEs, but we
842338fd1498Szrj 	 found at least one with them, go back and get an entry with
842438fd1498Szrj 	 the minimum number ENTRY_VALUE count that we found.  We could
842538fd1498Szrj 	 avoid looping, but since each sub-loc is already resolved,
842638fd1498Szrj 	 the re-expansion should be trivial.  ??? Should we record all
842738fd1498Szrj 	 attempted locs as dependencies, so that we retry the
842838fd1498Szrj 	 expansion should any of them change, in the hope it can give
842938fd1498Szrj 	 us a new entry without an ENTRY_VALUE?  */
843038fd1498Szrj       elcd->expanding.truncate (first_child);
843138fd1498Szrj       goto retry;
843238fd1498Szrj     }
843338fd1498Szrj 
843438fd1498Szrj   /* Register all encountered dependencies as active.  */
843538fd1498Szrj   pending_recursion = loc_exp_dep_set
843638fd1498Szrj     (var, result, elcd->expanding.address () + result_first_child,
843738fd1498Szrj      last_child - result_first_child, elcd->vars);
843838fd1498Szrj 
843938fd1498Szrj   elcd->expanding.truncate (first_child);
844038fd1498Szrj 
844138fd1498Szrj   /* Record where the expansion came from.  */
844238fd1498Szrj   gcc_checking_assert (!result || !pending_recursion);
844338fd1498Szrj   VAR_LOC_FROM (var) = loc_from;
844438fd1498Szrj   VAR_LOC_DEPTH (var) = depth;
844538fd1498Szrj 
844638fd1498Szrj   gcc_checking_assert (!depth.complexity == !result);
844738fd1498Szrj 
844838fd1498Szrj   elcd->depth = update_depth (saved_depth, depth);
844938fd1498Szrj 
845038fd1498Szrj   /* Indicate whether any of the dependencies are pending recursion
845138fd1498Szrj      resolution.  */
845238fd1498Szrj   if (pendrecp)
845338fd1498Szrj     *pendrecp = pending_recursion;
845438fd1498Szrj 
845538fd1498Szrj   if (!pendrecp || !pending_recursion)
845638fd1498Szrj     var->var_part[0].cur_loc = result;
845738fd1498Szrj 
845838fd1498Szrj   return result;
845938fd1498Szrj }
846038fd1498Szrj 
846138fd1498Szrj /* Callback for cselib_expand_value, that looks for expressions
846238fd1498Szrj    holding the value in the var-tracking hash tables.  Return X for
846338fd1498Szrj    standard processing, anything else is to be used as-is.  */
846438fd1498Szrj 
846538fd1498Szrj static rtx
vt_expand_loc_callback(rtx x,bitmap regs,int max_depth ATTRIBUTE_UNUSED,void * data)846638fd1498Szrj vt_expand_loc_callback (rtx x, bitmap regs,
846738fd1498Szrj 			int max_depth ATTRIBUTE_UNUSED,
846838fd1498Szrj 			void *data)
846938fd1498Szrj {
847038fd1498Szrj   struct expand_loc_callback_data *elcd
847138fd1498Szrj     = (struct expand_loc_callback_data *) data;
847238fd1498Szrj   decl_or_value dv;
847338fd1498Szrj   variable *var;
847438fd1498Szrj   rtx result, subreg;
847538fd1498Szrj   bool pending_recursion = false;
847638fd1498Szrj   bool from_empty = false;
847738fd1498Szrj 
847838fd1498Szrj   switch (GET_CODE (x))
847938fd1498Szrj     {
848038fd1498Szrj     case SUBREG:
848138fd1498Szrj       subreg = cselib_expand_value_rtx_cb (SUBREG_REG (x), regs,
848238fd1498Szrj 					   EXPR_DEPTH,
848338fd1498Szrj 					   vt_expand_loc_callback, data);
848438fd1498Szrj 
848538fd1498Szrj       if (!subreg)
848638fd1498Szrj 	return NULL;
848738fd1498Szrj 
848838fd1498Szrj       result = simplify_gen_subreg (GET_MODE (x), subreg,
848938fd1498Szrj 				    GET_MODE (SUBREG_REG (x)),
849038fd1498Szrj 				    SUBREG_BYTE (x));
849138fd1498Szrj 
849238fd1498Szrj       /* Invalid SUBREGs are ok in debug info.  ??? We could try
849338fd1498Szrj 	 alternate expansions for the VALUE as well.  */
849438fd1498Szrj       if (!result)
849538fd1498Szrj 	result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
849638fd1498Szrj 
849738fd1498Szrj       return result;
849838fd1498Szrj 
849938fd1498Szrj     case DEBUG_EXPR:
850038fd1498Szrj     case VALUE:
850138fd1498Szrj       dv = dv_from_rtx (x);
850238fd1498Szrj       break;
850338fd1498Szrj 
850438fd1498Szrj     default:
850538fd1498Szrj       return x;
850638fd1498Szrj     }
850738fd1498Szrj 
850838fd1498Szrj   elcd->expanding.safe_push (x);
850938fd1498Szrj 
851038fd1498Szrj   /* Check that VALUE_RECURSED_INTO implies NO_LOC_P.  */
851138fd1498Szrj   gcc_checking_assert (!VALUE_RECURSED_INTO (x) || NO_LOC_P (x));
851238fd1498Szrj 
851338fd1498Szrj   if (NO_LOC_P (x))
851438fd1498Szrj     {
851538fd1498Szrj       gcc_checking_assert (VALUE_RECURSED_INTO (x) || !dv_changed_p (dv));
851638fd1498Szrj       return NULL;
851738fd1498Szrj     }
851838fd1498Szrj 
851938fd1498Szrj   var = elcd->vars->find_with_hash (dv, dv_htab_hash (dv));
852038fd1498Szrj 
852138fd1498Szrj   if (!var)
852238fd1498Szrj     {
852338fd1498Szrj       from_empty = true;
852438fd1498Szrj       var = variable_from_dropped (dv, INSERT);
852538fd1498Szrj     }
852638fd1498Szrj 
852738fd1498Szrj   gcc_checking_assert (var);
852838fd1498Szrj 
852938fd1498Szrj   if (!dv_changed_p (dv))
853038fd1498Szrj     {
853138fd1498Szrj       gcc_checking_assert (!NO_LOC_P (x));
853238fd1498Szrj       gcc_checking_assert (var->var_part[0].cur_loc);
853338fd1498Szrj       gcc_checking_assert (VAR_LOC_1PAUX (var));
853438fd1498Szrj       gcc_checking_assert (VAR_LOC_1PAUX (var)->depth.complexity);
853538fd1498Szrj 
853638fd1498Szrj       elcd->depth = update_depth (elcd->depth, VAR_LOC_1PAUX (var)->depth);
853738fd1498Szrj 
853838fd1498Szrj       return var->var_part[0].cur_loc;
853938fd1498Szrj     }
854038fd1498Szrj 
854138fd1498Szrj   VALUE_RECURSED_INTO (x) = true;
854238fd1498Szrj   /* This is tentative, but it makes some tests simpler.  */
854338fd1498Szrj   NO_LOC_P (x) = true;
854438fd1498Szrj 
854538fd1498Szrj   gcc_checking_assert (var->n_var_parts == 1 || from_empty);
854638fd1498Szrj 
854738fd1498Szrj   result = vt_expand_var_loc_chain (var, regs, data, &pending_recursion);
854838fd1498Szrj 
854938fd1498Szrj   if (pending_recursion)
855038fd1498Szrj     {
855138fd1498Szrj       gcc_checking_assert (!result);
855238fd1498Szrj       elcd->pending.safe_push (x);
855338fd1498Szrj     }
855438fd1498Szrj   else
855538fd1498Szrj     {
855638fd1498Szrj       NO_LOC_P (x) = !result;
855738fd1498Szrj       VALUE_RECURSED_INTO (x) = false;
855838fd1498Szrj       set_dv_changed (dv, false);
855938fd1498Szrj 
856038fd1498Szrj       if (result)
856138fd1498Szrj 	notify_dependents_of_resolved_value (var, elcd->vars);
856238fd1498Szrj     }
856338fd1498Szrj 
856438fd1498Szrj   return result;
856538fd1498Szrj }
856638fd1498Szrj 
856738fd1498Szrj /* While expanding variables, we may encounter recursion cycles
856838fd1498Szrj    because of mutual (possibly indirect) dependencies between two
856938fd1498Szrj    particular variables (or values), say A and B.  If we're trying to
857038fd1498Szrj    expand A when we get to B, which in turn attempts to expand A, if
857138fd1498Szrj    we can't find any other expansion for B, we'll add B to this
857238fd1498Szrj    pending-recursion stack, and tentatively return NULL for its
857338fd1498Szrj    location.  This tentative value will be used for any other
857438fd1498Szrj    occurrences of B, unless A gets some other location, in which case
857538fd1498Szrj    it will notify B that it is worth another try at computing a
857638fd1498Szrj    location for it, and it will use the location computed for A then.
857738fd1498Szrj    At the end of the expansion, the tentative NULL locations become
857838fd1498Szrj    final for all members of PENDING that didn't get a notification.
857938fd1498Szrj    This function performs this finalization of NULL locations.  */
858038fd1498Szrj 
858138fd1498Szrj static void
resolve_expansions_pending_recursion(vec<rtx,va_heap> * pending)858238fd1498Szrj resolve_expansions_pending_recursion (vec<rtx, va_heap> *pending)
858338fd1498Szrj {
858438fd1498Szrj   while (!pending->is_empty ())
858538fd1498Szrj     {
858638fd1498Szrj       rtx x = pending->pop ();
858738fd1498Szrj       decl_or_value dv;
858838fd1498Szrj 
858938fd1498Szrj       if (!VALUE_RECURSED_INTO (x))
859038fd1498Szrj 	continue;
859138fd1498Szrj 
859238fd1498Szrj       gcc_checking_assert (NO_LOC_P (x));
859338fd1498Szrj       VALUE_RECURSED_INTO (x) = false;
859438fd1498Szrj       dv = dv_from_rtx (x);
859538fd1498Szrj       gcc_checking_assert (dv_changed_p (dv));
859638fd1498Szrj       set_dv_changed (dv, false);
859738fd1498Szrj     }
859838fd1498Szrj }
859938fd1498Szrj 
860038fd1498Szrj /* Initialize expand_loc_callback_data D with variable hash table V.
860138fd1498Szrj    It must be a macro because of alloca (vec stack).  */
860238fd1498Szrj #define INIT_ELCD(d, v)						\
860338fd1498Szrj   do								\
860438fd1498Szrj     {								\
860538fd1498Szrj       (d).vars = (v);						\
860638fd1498Szrj       (d).depth.complexity = (d).depth.entryvals = 0;		\
860738fd1498Szrj     }								\
860838fd1498Szrj   while (0)
860938fd1498Szrj /* Finalize expand_loc_callback_data D, resolved to location L.  */
861038fd1498Szrj #define FINI_ELCD(d, l)						\
861138fd1498Szrj   do								\
861238fd1498Szrj     {								\
861338fd1498Szrj       resolve_expansions_pending_recursion (&(d).pending);	\
861438fd1498Szrj       (d).pending.release ();					\
861538fd1498Szrj       (d).expanding.release ();					\
861638fd1498Szrj 								\
861738fd1498Szrj       if ((l) && MEM_P (l))					\
861838fd1498Szrj 	(l) = targetm.delegitimize_address (l);			\
861938fd1498Szrj     }								\
862038fd1498Szrj   while (0)
862138fd1498Szrj 
862238fd1498Szrj /* Expand VALUEs and DEBUG_EXPRs in LOC to a location, using the
862338fd1498Szrj    equivalences in VARS, updating their CUR_LOCs in the process.  */
862438fd1498Szrj 
862538fd1498Szrj static rtx
vt_expand_loc(rtx loc,variable_table_type * vars)862638fd1498Szrj vt_expand_loc (rtx loc, variable_table_type *vars)
862738fd1498Szrj {
862838fd1498Szrj   struct expand_loc_callback_data data;
862938fd1498Szrj   rtx result;
863038fd1498Szrj 
863138fd1498Szrj   if (!MAY_HAVE_DEBUG_BIND_INSNS)
863238fd1498Szrj     return loc;
863338fd1498Szrj 
863438fd1498Szrj   INIT_ELCD (data, vars);
863538fd1498Szrj 
863638fd1498Szrj   result = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
863738fd1498Szrj 				       vt_expand_loc_callback, &data);
863838fd1498Szrj 
863938fd1498Szrj   FINI_ELCD (data, result);
864038fd1498Szrj 
864138fd1498Szrj   return result;
864238fd1498Szrj }
864338fd1498Szrj 
864438fd1498Szrj /* Expand the one-part VARiable to a location, using the equivalences
864538fd1498Szrj    in VARS, updating their CUR_LOCs in the process.  */
864638fd1498Szrj 
864738fd1498Szrj static rtx
vt_expand_1pvar(variable * var,variable_table_type * vars)864838fd1498Szrj vt_expand_1pvar (variable *var, variable_table_type *vars)
864938fd1498Szrj {
865038fd1498Szrj   struct expand_loc_callback_data data;
865138fd1498Szrj   rtx loc;
865238fd1498Szrj 
865338fd1498Szrj   gcc_checking_assert (var->onepart && var->n_var_parts == 1);
865438fd1498Szrj 
865538fd1498Szrj   if (!dv_changed_p (var->dv))
865638fd1498Szrj     return var->var_part[0].cur_loc;
865738fd1498Szrj 
865838fd1498Szrj   INIT_ELCD (data, vars);
865938fd1498Szrj 
866038fd1498Szrj   loc = vt_expand_var_loc_chain (var, scratch_regs, &data, NULL);
866138fd1498Szrj 
866238fd1498Szrj   gcc_checking_assert (data.expanding.is_empty ());
866338fd1498Szrj 
866438fd1498Szrj   FINI_ELCD (data, loc);
866538fd1498Szrj 
866638fd1498Szrj   return loc;
866738fd1498Szrj }
866838fd1498Szrj 
866938fd1498Szrj /* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP.  DATA contains
867038fd1498Szrj    additional parameters: WHERE specifies whether the note shall be emitted
867138fd1498Szrj    before or after instruction INSN.  */
867238fd1498Szrj 
867338fd1498Szrj int
emit_note_insn_var_location(variable ** varp,emit_note_data * data)867438fd1498Szrj emit_note_insn_var_location (variable **varp, emit_note_data *data)
867538fd1498Szrj {
867638fd1498Szrj   variable *var = *varp;
867738fd1498Szrj   rtx_insn *insn = data->insn;
867838fd1498Szrj   enum emit_note_where where = data->where;
867938fd1498Szrj   variable_table_type *vars = data->vars;
868038fd1498Szrj   rtx_note *note;
868138fd1498Szrj   rtx note_vl;
868238fd1498Szrj   int i, j, n_var_parts;
868338fd1498Szrj   bool complete;
868438fd1498Szrj   enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
868538fd1498Szrj   HOST_WIDE_INT last_limit;
868638fd1498Szrj   tree type_size_unit;
868738fd1498Szrj   HOST_WIDE_INT offsets[MAX_VAR_PARTS];
868838fd1498Szrj   rtx loc[MAX_VAR_PARTS];
868938fd1498Szrj   tree decl;
869038fd1498Szrj   location_chain *lc;
869138fd1498Szrj 
869238fd1498Szrj   gcc_checking_assert (var->onepart == NOT_ONEPART
869338fd1498Szrj 		       || var->onepart == ONEPART_VDECL);
869438fd1498Szrj 
869538fd1498Szrj   decl = dv_as_decl (var->dv);
869638fd1498Szrj 
869738fd1498Szrj   complete = true;
869838fd1498Szrj   last_limit = 0;
869938fd1498Szrj   n_var_parts = 0;
870038fd1498Szrj   if (!var->onepart)
870138fd1498Szrj     for (i = 0; i < var->n_var_parts; i++)
870238fd1498Szrj       if (var->var_part[i].cur_loc == NULL && var->var_part[i].loc_chain)
870338fd1498Szrj 	var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
870438fd1498Szrj   for (i = 0; i < var->n_var_parts; i++)
870538fd1498Szrj     {
870638fd1498Szrj       machine_mode mode, wider_mode;
870738fd1498Szrj       rtx loc2;
870838fd1498Szrj       HOST_WIDE_INT offset, size, wider_size;
870938fd1498Szrj 
871038fd1498Szrj       if (i == 0 && var->onepart)
871138fd1498Szrj 	{
871238fd1498Szrj 	  gcc_checking_assert (var->n_var_parts == 1);
871338fd1498Szrj 	  offset = 0;
871438fd1498Szrj 	  initialized = VAR_INIT_STATUS_INITIALIZED;
871538fd1498Szrj 	  loc2 = vt_expand_1pvar (var, vars);
871638fd1498Szrj 	}
871738fd1498Szrj       else
871838fd1498Szrj 	{
871938fd1498Szrj 	  if (last_limit < VAR_PART_OFFSET (var, i))
872038fd1498Szrj 	    {
872138fd1498Szrj 	      complete = false;
872238fd1498Szrj 	      break;
872338fd1498Szrj 	    }
872438fd1498Szrj 	  else if (last_limit > VAR_PART_OFFSET (var, i))
872538fd1498Szrj 	    continue;
872638fd1498Szrj 	  offset = VAR_PART_OFFSET (var, i);
872738fd1498Szrj 	  loc2 = var->var_part[i].cur_loc;
872838fd1498Szrj 	  if (loc2 && GET_CODE (loc2) == MEM
872938fd1498Szrj 	      && GET_CODE (XEXP (loc2, 0)) == VALUE)
873038fd1498Szrj 	    {
873138fd1498Szrj 	      rtx depval = XEXP (loc2, 0);
873238fd1498Szrj 
873338fd1498Szrj 	      loc2 = vt_expand_loc (loc2, vars);
873438fd1498Szrj 
873538fd1498Szrj 	      if (loc2)
873638fd1498Szrj 		loc_exp_insert_dep (var, depval, vars);
873738fd1498Szrj 	    }
873838fd1498Szrj 	  if (!loc2)
873938fd1498Szrj 	    {
874038fd1498Szrj 	      complete = false;
874138fd1498Szrj 	      continue;
874238fd1498Szrj 	    }
874338fd1498Szrj 	  gcc_checking_assert (GET_CODE (loc2) != VALUE);
874438fd1498Szrj 	  for (lc = var->var_part[i].loc_chain; lc; lc = lc->next)
874538fd1498Szrj 	    if (var->var_part[i].cur_loc == lc->loc)
874638fd1498Szrj 	      {
874738fd1498Szrj 		initialized = lc->init;
874838fd1498Szrj 		break;
874938fd1498Szrj 	      }
875038fd1498Szrj 	  gcc_assert (lc);
875138fd1498Szrj 	}
875238fd1498Szrj 
875338fd1498Szrj       offsets[n_var_parts] = offset;
875438fd1498Szrj       if (!loc2)
875538fd1498Szrj 	{
875638fd1498Szrj 	  complete = false;
875738fd1498Szrj 	  continue;
875838fd1498Szrj 	}
875938fd1498Szrj       loc[n_var_parts] = loc2;
876038fd1498Szrj       mode = GET_MODE (var->var_part[i].cur_loc);
876138fd1498Szrj       if (mode == VOIDmode && var->onepart)
876238fd1498Szrj 	mode = DECL_MODE (decl);
876338fd1498Szrj       /* We ony track subparts of constant-sized objects, since at present
876438fd1498Szrj 	 there's no representation for polynomial pieces.  */
876538fd1498Szrj       if (!GET_MODE_SIZE (mode).is_constant (&size))
876638fd1498Szrj 	{
876738fd1498Szrj 	  complete = false;
876838fd1498Szrj 	  continue;
876938fd1498Szrj 	}
877038fd1498Szrj       last_limit = offsets[n_var_parts] + size;
877138fd1498Szrj 
877238fd1498Szrj       /* Attempt to merge adjacent registers or memory.  */
877338fd1498Szrj       for (j = i + 1; j < var->n_var_parts; j++)
877438fd1498Szrj 	if (last_limit <= VAR_PART_OFFSET (var, j))
877538fd1498Szrj 	  break;
877638fd1498Szrj       if (j < var->n_var_parts
877738fd1498Szrj 	  && GET_MODE_WIDER_MODE (mode).exists (&wider_mode)
877838fd1498Szrj 	  && GET_MODE_SIZE (wider_mode).is_constant (&wider_size)
877938fd1498Szrj 	  && var->var_part[j].cur_loc
878038fd1498Szrj 	  && mode == GET_MODE (var->var_part[j].cur_loc)
878138fd1498Szrj 	  && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
878238fd1498Szrj 	  && last_limit == (var->onepart ? 0 : VAR_PART_OFFSET (var, j))
878338fd1498Szrj 	  && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars))
878438fd1498Szrj 	  && GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
878538fd1498Szrj 	{
878638fd1498Szrj 	  rtx new_loc = NULL;
878738fd1498Szrj 
878838fd1498Szrj 	  if (REG_P (loc[n_var_parts])
878938fd1498Szrj 	      && hard_regno_nregs (REGNO (loc[n_var_parts]), mode) * 2
879038fd1498Szrj 		 == hard_regno_nregs (REGNO (loc[n_var_parts]), wider_mode)
879138fd1498Szrj 	      && end_hard_regno (mode, REGNO (loc[n_var_parts]))
879238fd1498Szrj 		 == REGNO (loc2))
879338fd1498Szrj 	    {
879438fd1498Szrj 	      if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
879538fd1498Szrj 		new_loc = simplify_subreg (wider_mode, loc[n_var_parts],
879638fd1498Szrj 					   mode, 0);
879738fd1498Szrj 	      else if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
879838fd1498Szrj 		new_loc = simplify_subreg (wider_mode, loc2, mode, 0);
879938fd1498Szrj 	      if (new_loc)
880038fd1498Szrj 		{
880138fd1498Szrj 		  if (!REG_P (new_loc)
880238fd1498Szrj 		      || REGNO (new_loc) != REGNO (loc[n_var_parts]))
880338fd1498Szrj 		    new_loc = NULL;
880438fd1498Szrj 		  else
880538fd1498Szrj 		    REG_ATTRS (new_loc) = REG_ATTRS (loc[n_var_parts]);
880638fd1498Szrj 		}
880738fd1498Szrj 	    }
880838fd1498Szrj 	  else if (MEM_P (loc[n_var_parts])
880938fd1498Szrj 		   && GET_CODE (XEXP (loc2, 0)) == PLUS
881038fd1498Szrj 		   && REG_P (XEXP (XEXP (loc2, 0), 0))
881138fd1498Szrj 		   && CONST_INT_P (XEXP (XEXP (loc2, 0), 1)))
881238fd1498Szrj 	    {
881338fd1498Szrj 	      if ((REG_P (XEXP (loc[n_var_parts], 0))
881438fd1498Szrj 		   && rtx_equal_p (XEXP (loc[n_var_parts], 0),
881538fd1498Szrj 				   XEXP (XEXP (loc2, 0), 0))
881638fd1498Szrj 		   && INTVAL (XEXP (XEXP (loc2, 0), 1)) == size)
881738fd1498Szrj 		  || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
881838fd1498Szrj 		      && CONST_INT_P (XEXP (XEXP (loc[n_var_parts], 0), 1))
881938fd1498Szrj 		      && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
882038fd1498Szrj 				      XEXP (XEXP (loc2, 0), 0))
882138fd1498Szrj 		      && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1)) + size
882238fd1498Szrj 			 == INTVAL (XEXP (XEXP (loc2, 0), 1))))
882338fd1498Szrj 		new_loc = adjust_address_nv (loc[n_var_parts],
882438fd1498Szrj 					     wider_mode, 0);
882538fd1498Szrj 	    }
882638fd1498Szrj 
882738fd1498Szrj 	  if (new_loc)
882838fd1498Szrj 	    {
882938fd1498Szrj 	      loc[n_var_parts] = new_loc;
883038fd1498Szrj 	      mode = wider_mode;
883138fd1498Szrj 	      last_limit = offsets[n_var_parts] + wider_size;
883238fd1498Szrj 	      i = j;
883338fd1498Szrj 	    }
883438fd1498Szrj 	}
883538fd1498Szrj       ++n_var_parts;
883638fd1498Szrj     }
883738fd1498Szrj   type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (decl));
883838fd1498Szrj   if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
883938fd1498Szrj     complete = false;
884038fd1498Szrj 
884138fd1498Szrj   if (! flag_var_tracking_uninit)
884238fd1498Szrj     initialized = VAR_INIT_STATUS_INITIALIZED;
884338fd1498Szrj 
884438fd1498Szrj   note_vl = NULL_RTX;
884538fd1498Szrj   if (!complete)
884638fd1498Szrj     note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, NULL_RTX, initialized);
884738fd1498Szrj   else if (n_var_parts == 1)
884838fd1498Szrj     {
884938fd1498Szrj       rtx expr_list;
885038fd1498Szrj 
885138fd1498Szrj       if (offsets[0] || GET_CODE (loc[0]) == PARALLEL)
885238fd1498Szrj 	expr_list = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
885338fd1498Szrj       else
885438fd1498Szrj 	expr_list = loc[0];
885538fd1498Szrj 
885638fd1498Szrj       note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list, initialized);
885738fd1498Szrj     }
885838fd1498Szrj   else if (n_var_parts)
885938fd1498Szrj     {
886038fd1498Szrj       rtx parallel;
886138fd1498Szrj 
886238fd1498Szrj       for (i = 0; i < n_var_parts; i++)
886338fd1498Szrj 	loc[i]
886438fd1498Szrj 	  = gen_rtx_EXPR_LIST (VOIDmode, loc[i], GEN_INT (offsets[i]));
886538fd1498Szrj 
886638fd1498Szrj       parallel = gen_rtx_PARALLEL (VOIDmode,
886738fd1498Szrj 				   gen_rtvec_v (n_var_parts, loc));
886838fd1498Szrj       note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl,
886938fd1498Szrj 				      parallel, initialized);
887038fd1498Szrj     }
887138fd1498Szrj 
887238fd1498Szrj   if (where != EMIT_NOTE_BEFORE_INSN)
887338fd1498Szrj     {
887438fd1498Szrj       note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
887538fd1498Szrj       if (where == EMIT_NOTE_AFTER_CALL_INSN)
887638fd1498Szrj 	NOTE_DURING_CALL_P (note) = true;
887738fd1498Szrj     }
887838fd1498Szrj   else
887938fd1498Szrj     {
888038fd1498Szrj       /* Make sure that the call related notes come first.  */
888138fd1498Szrj       while (NEXT_INSN (insn)
888238fd1498Szrj 	     && NOTE_P (insn)
888338fd1498Szrj 	     && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
888438fd1498Szrj 	     && NOTE_DURING_CALL_P (insn))
888538fd1498Szrj 	insn = NEXT_INSN (insn);
888638fd1498Szrj       if (NOTE_P (insn)
888738fd1498Szrj 	  && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
888838fd1498Szrj 	  && NOTE_DURING_CALL_P (insn))
888938fd1498Szrj 	note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
889038fd1498Szrj       else
889138fd1498Szrj 	note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
889238fd1498Szrj     }
889338fd1498Szrj   NOTE_VAR_LOCATION (note) = note_vl;
889438fd1498Szrj 
889538fd1498Szrj   set_dv_changed (var->dv, false);
889638fd1498Szrj   gcc_assert (var->in_changed_variables);
889738fd1498Szrj   var->in_changed_variables = false;
889838fd1498Szrj   changed_variables->clear_slot (varp);
889938fd1498Szrj 
890038fd1498Szrj   /* Continue traversing the hash table.  */
890138fd1498Szrj   return 1;
890238fd1498Szrj }
890338fd1498Szrj 
890438fd1498Szrj /* While traversing changed_variables, push onto DATA (a stack of RTX
890538fd1498Szrj    values) entries that aren't user variables.  */
890638fd1498Szrj 
890738fd1498Szrj int
var_track_values_to_stack(variable ** slot,vec<rtx,va_heap> * changed_values_stack)890838fd1498Szrj var_track_values_to_stack (variable **slot,
890938fd1498Szrj 			   vec<rtx, va_heap> *changed_values_stack)
891038fd1498Szrj {
891138fd1498Szrj   variable *var = *slot;
891238fd1498Szrj 
891338fd1498Szrj   if (var->onepart == ONEPART_VALUE)
891438fd1498Szrj     changed_values_stack->safe_push (dv_as_value (var->dv));
891538fd1498Szrj   else if (var->onepart == ONEPART_DEXPR)
891638fd1498Szrj     changed_values_stack->safe_push (DECL_RTL_KNOWN_SET (dv_as_decl (var->dv)));
891738fd1498Szrj 
891838fd1498Szrj   return 1;
891938fd1498Szrj }
892038fd1498Szrj 
892138fd1498Szrj /* Remove from changed_variables the entry whose DV corresponds to
892238fd1498Szrj    value or debug_expr VAL.  */
892338fd1498Szrj static void
remove_value_from_changed_variables(rtx val)892438fd1498Szrj remove_value_from_changed_variables (rtx val)
892538fd1498Szrj {
892638fd1498Szrj   decl_or_value dv = dv_from_rtx (val);
892738fd1498Szrj   variable **slot;
892838fd1498Szrj   variable *var;
892938fd1498Szrj 
893038fd1498Szrj   slot = changed_variables->find_slot_with_hash (dv, dv_htab_hash (dv),
893138fd1498Szrj 						NO_INSERT);
893238fd1498Szrj   var = *slot;
893338fd1498Szrj   var->in_changed_variables = false;
893438fd1498Szrj   changed_variables->clear_slot (slot);
893538fd1498Szrj }
893638fd1498Szrj 
893738fd1498Szrj /* If VAL (a value or debug_expr) has backlinks to variables actively
893838fd1498Szrj    dependent on it in HTAB or in CHANGED_VARIABLES, mark them as
893938fd1498Szrj    changed, adding to CHANGED_VALUES_STACK any dependencies that may
894038fd1498Szrj    have dependencies of their own to notify.  */
894138fd1498Szrj 
894238fd1498Szrj static void
notify_dependents_of_changed_value(rtx val,variable_table_type * htab,vec<rtx,va_heap> * changed_values_stack)894338fd1498Szrj notify_dependents_of_changed_value (rtx val, variable_table_type *htab,
894438fd1498Szrj 				    vec<rtx, va_heap> *changed_values_stack)
894538fd1498Szrj {
894638fd1498Szrj   variable **slot;
894738fd1498Szrj   variable *var;
894838fd1498Szrj   loc_exp_dep *led;
894938fd1498Szrj   decl_or_value dv = dv_from_rtx (val);
895038fd1498Szrj 
895138fd1498Szrj   slot = changed_variables->find_slot_with_hash (dv, dv_htab_hash (dv),
895238fd1498Szrj 						NO_INSERT);
895338fd1498Szrj   if (!slot)
895438fd1498Szrj     slot = htab->find_slot_with_hash (dv, dv_htab_hash (dv), NO_INSERT);
895538fd1498Szrj   if (!slot)
895638fd1498Szrj     slot = dropped_values->find_slot_with_hash (dv, dv_htab_hash (dv),
895738fd1498Szrj 						NO_INSERT);
895838fd1498Szrj   var = *slot;
895938fd1498Szrj 
896038fd1498Szrj   while ((led = VAR_LOC_DEP_LST (var)))
896138fd1498Szrj     {
896238fd1498Szrj       decl_or_value ldv = led->dv;
896338fd1498Szrj       variable *ivar;
896438fd1498Szrj 
896538fd1498Szrj       /* Deactivate and remove the backlink, as it was “used up”.  It
896638fd1498Szrj 	 makes no sense to attempt to notify the same entity again:
896738fd1498Szrj 	 either it will be recomputed and re-register an active
896838fd1498Szrj 	 dependency, or it will still have the changed mark.  */
896938fd1498Szrj       if (led->next)
897038fd1498Szrj 	led->next->pprev = led->pprev;
897138fd1498Szrj       if (led->pprev)
897238fd1498Szrj 	*led->pprev = led->next;
897338fd1498Szrj       led->next = NULL;
897438fd1498Szrj       led->pprev = NULL;
897538fd1498Szrj 
897638fd1498Szrj       if (dv_changed_p (ldv))
897738fd1498Szrj 	continue;
897838fd1498Szrj 
897938fd1498Szrj       switch (dv_onepart_p (ldv))
898038fd1498Szrj 	{
898138fd1498Szrj 	case ONEPART_VALUE:
898238fd1498Szrj 	case ONEPART_DEXPR:
898338fd1498Szrj 	  set_dv_changed (ldv, true);
898438fd1498Szrj 	  changed_values_stack->safe_push (dv_as_rtx (ldv));
898538fd1498Szrj 	  break;
898638fd1498Szrj 
898738fd1498Szrj 	case ONEPART_VDECL:
898838fd1498Szrj 	  ivar = htab->find_with_hash (ldv, dv_htab_hash (ldv));
898938fd1498Szrj 	  gcc_checking_assert (!VAR_LOC_DEP_LST (ivar));
899038fd1498Szrj 	  variable_was_changed (ivar, NULL);
899138fd1498Szrj 	  break;
899238fd1498Szrj 
899338fd1498Szrj 	case NOT_ONEPART:
899438fd1498Szrj 	  delete led;
899538fd1498Szrj 	  ivar = htab->find_with_hash (ldv, dv_htab_hash (ldv));
899638fd1498Szrj 	  if (ivar)
899738fd1498Szrj 	    {
899838fd1498Szrj 	      int i = ivar->n_var_parts;
899938fd1498Szrj 	      while (i--)
900038fd1498Szrj 		{
900138fd1498Szrj 		  rtx loc = ivar->var_part[i].cur_loc;
900238fd1498Szrj 
900338fd1498Szrj 		  if (loc && GET_CODE (loc) == MEM
900438fd1498Szrj 		      && XEXP (loc, 0) == val)
900538fd1498Szrj 		    {
900638fd1498Szrj 		      variable_was_changed (ivar, NULL);
900738fd1498Szrj 		      break;
900838fd1498Szrj 		    }
900938fd1498Szrj 		}
901038fd1498Szrj 	    }
901138fd1498Szrj 	  break;
901238fd1498Szrj 
901338fd1498Szrj 	default:
901438fd1498Szrj 	  gcc_unreachable ();
901538fd1498Szrj 	}
901638fd1498Szrj     }
901738fd1498Szrj }
901838fd1498Szrj 
901938fd1498Szrj /* Take out of changed_variables any entries that don't refer to use
902038fd1498Szrj    variables.  Back-propagate change notifications from values and
902138fd1498Szrj    debug_exprs to their active dependencies in HTAB or in
902238fd1498Szrj    CHANGED_VARIABLES.  */
902338fd1498Szrj 
902438fd1498Szrj static void
process_changed_values(variable_table_type * htab)902538fd1498Szrj process_changed_values (variable_table_type *htab)
902638fd1498Szrj {
902738fd1498Szrj   int i, n;
902838fd1498Szrj   rtx val;
902938fd1498Szrj   auto_vec<rtx, 20> changed_values_stack;
903038fd1498Szrj 
903138fd1498Szrj   /* Move values from changed_variables to changed_values_stack.  */
903238fd1498Szrj   changed_variables
903338fd1498Szrj     ->traverse <vec<rtx, va_heap>*, var_track_values_to_stack>
903438fd1498Szrj       (&changed_values_stack);
903538fd1498Szrj 
903638fd1498Szrj   /* Back-propagate change notifications in values while popping
903738fd1498Szrj      them from the stack.  */
903838fd1498Szrj   for (n = i = changed_values_stack.length ();
903938fd1498Szrj        i > 0; i = changed_values_stack.length ())
904038fd1498Szrj     {
904138fd1498Szrj       val = changed_values_stack.pop ();
904238fd1498Szrj       notify_dependents_of_changed_value (val, htab, &changed_values_stack);
904338fd1498Szrj 
904438fd1498Szrj       /* This condition will hold when visiting each of the entries
904538fd1498Szrj 	 originally in changed_variables.  We can't remove them
904638fd1498Szrj 	 earlier because this could drop the backlinks before we got a
904738fd1498Szrj 	 chance to use them.  */
904838fd1498Szrj       if (i == n)
904938fd1498Szrj 	{
905038fd1498Szrj 	  remove_value_from_changed_variables (val);
905138fd1498Szrj 	  n--;
905238fd1498Szrj 	}
905338fd1498Szrj     }
905438fd1498Szrj }
905538fd1498Szrj 
905638fd1498Szrj /* Emit NOTE_INSN_VAR_LOCATION note for each variable from a chain
905738fd1498Szrj    CHANGED_VARIABLES and delete this chain.  WHERE specifies whether
905838fd1498Szrj    the notes shall be emitted before of after instruction INSN.  */
905938fd1498Szrj 
906038fd1498Szrj static void
emit_notes_for_changes(rtx_insn * insn,enum emit_note_where where,shared_hash * vars)906138fd1498Szrj emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
906238fd1498Szrj 			shared_hash *vars)
906338fd1498Szrj {
906438fd1498Szrj   emit_note_data data;
906538fd1498Szrj   variable_table_type *htab = shared_hash_htab (vars);
906638fd1498Szrj 
906738fd1498Szrj   if (!changed_variables->elements ())
906838fd1498Szrj     return;
906938fd1498Szrj 
907038fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
907138fd1498Szrj     process_changed_values (htab);
907238fd1498Szrj 
907338fd1498Szrj   data.insn = insn;
907438fd1498Szrj   data.where = where;
907538fd1498Szrj   data.vars = htab;
907638fd1498Szrj 
907738fd1498Szrj   changed_variables
907838fd1498Szrj     ->traverse <emit_note_data*, emit_note_insn_var_location> (&data);
907938fd1498Szrj }
908038fd1498Szrj 
908138fd1498Szrj /* Add variable *SLOT to the chain CHANGED_VARIABLES if it differs from the
908238fd1498Szrj    same variable in hash table DATA or is not there at all.  */
908338fd1498Szrj 
908438fd1498Szrj int
emit_notes_for_differences_1(variable ** slot,variable_table_type * new_vars)908538fd1498Szrj emit_notes_for_differences_1 (variable **slot, variable_table_type *new_vars)
908638fd1498Szrj {
908738fd1498Szrj   variable *old_var, *new_var;
908838fd1498Szrj 
908938fd1498Szrj   old_var = *slot;
909038fd1498Szrj   new_var = new_vars->find_with_hash (old_var->dv, dv_htab_hash (old_var->dv));
909138fd1498Szrj 
909238fd1498Szrj   if (!new_var)
909338fd1498Szrj     {
909438fd1498Szrj       /* Variable has disappeared.  */
909538fd1498Szrj       variable *empty_var = NULL;
909638fd1498Szrj 
909738fd1498Szrj       if (old_var->onepart == ONEPART_VALUE
909838fd1498Szrj 	  || old_var->onepart == ONEPART_DEXPR)
909938fd1498Szrj 	{
910038fd1498Szrj 	  empty_var = variable_from_dropped (old_var->dv, NO_INSERT);
910138fd1498Szrj 	  if (empty_var)
910238fd1498Szrj 	    {
910338fd1498Szrj 	      gcc_checking_assert (!empty_var->in_changed_variables);
910438fd1498Szrj 	      if (!VAR_LOC_1PAUX (old_var))
910538fd1498Szrj 		{
910638fd1498Szrj 		  VAR_LOC_1PAUX (old_var) = VAR_LOC_1PAUX (empty_var);
910738fd1498Szrj 		  VAR_LOC_1PAUX (empty_var) = NULL;
910838fd1498Szrj 		}
910938fd1498Szrj 	      else
911038fd1498Szrj 		gcc_checking_assert (!VAR_LOC_1PAUX (empty_var));
911138fd1498Szrj 	    }
911238fd1498Szrj 	}
911338fd1498Szrj 
911438fd1498Szrj       if (!empty_var)
911538fd1498Szrj 	{
911638fd1498Szrj 	  empty_var = onepart_pool_allocate (old_var->onepart);
911738fd1498Szrj 	  empty_var->dv = old_var->dv;
911838fd1498Szrj 	  empty_var->refcount = 0;
911938fd1498Szrj 	  empty_var->n_var_parts = 0;
912038fd1498Szrj 	  empty_var->onepart = old_var->onepart;
912138fd1498Szrj 	  empty_var->in_changed_variables = false;
912238fd1498Szrj 	}
912338fd1498Szrj 
912438fd1498Szrj       if (empty_var->onepart)
912538fd1498Szrj 	{
912638fd1498Szrj 	  /* Propagate the auxiliary data to (ultimately)
912738fd1498Szrj 	     changed_variables.  */
912838fd1498Szrj 	  empty_var->var_part[0].loc_chain = NULL;
912938fd1498Szrj 	  empty_var->var_part[0].cur_loc = NULL;
913038fd1498Szrj 	  VAR_LOC_1PAUX (empty_var) = VAR_LOC_1PAUX (old_var);
913138fd1498Szrj 	  VAR_LOC_1PAUX (old_var) = NULL;
913238fd1498Szrj 	}
913338fd1498Szrj       variable_was_changed (empty_var, NULL);
913438fd1498Szrj       /* Continue traversing the hash table.  */
913538fd1498Szrj       return 1;
913638fd1498Szrj     }
913738fd1498Szrj   /* Update cur_loc and one-part auxiliary data, before new_var goes
913838fd1498Szrj      through variable_was_changed.  */
913938fd1498Szrj   if (old_var != new_var && new_var->onepart)
914038fd1498Szrj     {
914138fd1498Szrj       gcc_checking_assert (VAR_LOC_1PAUX (new_var) == NULL);
914238fd1498Szrj       VAR_LOC_1PAUX (new_var) = VAR_LOC_1PAUX (old_var);
914338fd1498Szrj       VAR_LOC_1PAUX (old_var) = NULL;
914438fd1498Szrj       new_var->var_part[0].cur_loc = old_var->var_part[0].cur_loc;
914538fd1498Szrj     }
914638fd1498Szrj   if (variable_different_p (old_var, new_var))
914738fd1498Szrj     variable_was_changed (new_var, NULL);
914838fd1498Szrj 
914938fd1498Szrj   /* Continue traversing the hash table.  */
915038fd1498Szrj   return 1;
915138fd1498Szrj }
915238fd1498Szrj 
915338fd1498Szrj /* Add variable *SLOT to the chain CHANGED_VARIABLES if it is not in hash
915438fd1498Szrj    table DATA.  */
915538fd1498Szrj 
915638fd1498Szrj int
emit_notes_for_differences_2(variable ** slot,variable_table_type * old_vars)915738fd1498Szrj emit_notes_for_differences_2 (variable **slot, variable_table_type *old_vars)
915838fd1498Szrj {
915938fd1498Szrj   variable *old_var, *new_var;
916038fd1498Szrj 
916138fd1498Szrj   new_var = *slot;
916238fd1498Szrj   old_var = old_vars->find_with_hash (new_var->dv, dv_htab_hash (new_var->dv));
916338fd1498Szrj   if (!old_var)
916438fd1498Szrj     {
916538fd1498Szrj       int i;
916638fd1498Szrj       for (i = 0; i < new_var->n_var_parts; i++)
916738fd1498Szrj 	new_var->var_part[i].cur_loc = NULL;
916838fd1498Szrj       variable_was_changed (new_var, NULL);
916938fd1498Szrj     }
917038fd1498Szrj 
917138fd1498Szrj   /* Continue traversing the hash table.  */
917238fd1498Szrj   return 1;
917338fd1498Szrj }
917438fd1498Szrj 
917538fd1498Szrj /* Emit notes before INSN for differences between dataflow sets OLD_SET and
917638fd1498Szrj    NEW_SET.  */
917738fd1498Szrj 
917838fd1498Szrj static void
emit_notes_for_differences(rtx_insn * insn,dataflow_set * old_set,dataflow_set * new_set)917938fd1498Szrj emit_notes_for_differences (rtx_insn *insn, dataflow_set *old_set,
918038fd1498Szrj 			    dataflow_set *new_set)
918138fd1498Szrj {
918238fd1498Szrj   shared_hash_htab (old_set->vars)
918338fd1498Szrj     ->traverse <variable_table_type *, emit_notes_for_differences_1>
918438fd1498Szrj       (shared_hash_htab (new_set->vars));
918538fd1498Szrj   shared_hash_htab (new_set->vars)
918638fd1498Szrj     ->traverse <variable_table_type *, emit_notes_for_differences_2>
918738fd1498Szrj       (shared_hash_htab (old_set->vars));
918838fd1498Szrj   emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, new_set->vars);
918938fd1498Szrj }
919038fd1498Szrj 
919138fd1498Szrj /* Return the next insn after INSN that is not a NOTE_INSN_VAR_LOCATION.  */
919238fd1498Szrj 
919338fd1498Szrj static rtx_insn *
next_non_note_insn_var_location(rtx_insn * insn)919438fd1498Szrj next_non_note_insn_var_location (rtx_insn *insn)
919538fd1498Szrj {
919638fd1498Szrj   while (insn)
919738fd1498Szrj     {
919838fd1498Szrj       insn = NEXT_INSN (insn);
919938fd1498Szrj       if (insn == 0
920038fd1498Szrj 	  || !NOTE_P (insn)
920138fd1498Szrj 	  || NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION)
920238fd1498Szrj 	break;
920338fd1498Szrj     }
920438fd1498Szrj 
920538fd1498Szrj   return insn;
920638fd1498Szrj }
920738fd1498Szrj 
920838fd1498Szrj /* Emit the notes for changes of location parts in the basic block BB.  */
920938fd1498Szrj 
921038fd1498Szrj static void
emit_notes_in_bb(basic_block bb,dataflow_set * set)921138fd1498Szrj emit_notes_in_bb (basic_block bb, dataflow_set *set)
921238fd1498Szrj {
921338fd1498Szrj   unsigned int i;
921438fd1498Szrj   micro_operation *mo;
921538fd1498Szrj 
921638fd1498Szrj   dataflow_set_clear (set);
921738fd1498Szrj   dataflow_set_copy (set, &VTI (bb)->in);
921838fd1498Szrj 
921938fd1498Szrj   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
922038fd1498Szrj     {
922138fd1498Szrj       rtx_insn *insn = mo->insn;
922238fd1498Szrj       rtx_insn *next_insn = next_non_note_insn_var_location (insn);
922338fd1498Szrj 
922438fd1498Szrj       switch (mo->type)
922538fd1498Szrj 	{
922638fd1498Szrj 	  case MO_CALL:
922738fd1498Szrj 	    dataflow_set_clear_at_call (set, insn);
922838fd1498Szrj 	    emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
922938fd1498Szrj 	    {
923038fd1498Szrj 	      rtx arguments = mo->u.loc, *p = &arguments;
923138fd1498Szrj 	      while (*p)
923238fd1498Szrj 		{
923338fd1498Szrj 		  XEXP (XEXP (*p, 0), 1)
923438fd1498Szrj 		    = vt_expand_loc (XEXP (XEXP (*p, 0), 1),
923538fd1498Szrj 				     shared_hash_htab (set->vars));
923638fd1498Szrj 		  /* If expansion is successful, keep it in the list.  */
923738fd1498Szrj 		  if (XEXP (XEXP (*p, 0), 1))
923838fd1498Szrj 		    {
923938fd1498Szrj 		      XEXP (XEXP (*p, 0), 1)
924038fd1498Szrj 			= copy_rtx_if_shared (XEXP (XEXP (*p, 0), 1));
924138fd1498Szrj 		      p = &XEXP (*p, 1);
924238fd1498Szrj 		    }
924338fd1498Szrj 		  /* Otherwise, if the following item is data_value for it,
924438fd1498Szrj 		     drop it too too.  */
924538fd1498Szrj 		  else if (XEXP (*p, 1)
924638fd1498Szrj 			   && REG_P (XEXP (XEXP (*p, 0), 0))
924738fd1498Szrj 			   && MEM_P (XEXP (XEXP (XEXP (*p, 1), 0), 0))
924838fd1498Szrj 			   && REG_P (XEXP (XEXP (XEXP (XEXP (*p, 1), 0), 0),
924938fd1498Szrj 					   0))
925038fd1498Szrj 			   && REGNO (XEXP (XEXP (*p, 0), 0))
925138fd1498Szrj 			      == REGNO (XEXP (XEXP (XEXP (XEXP (*p, 1), 0),
925238fd1498Szrj 						    0), 0)))
925338fd1498Szrj 		    *p = XEXP (XEXP (*p, 1), 1);
925438fd1498Szrj 		  /* Just drop this item.  */
925538fd1498Szrj 		  else
925638fd1498Szrj 		    *p = XEXP (*p, 1);
925738fd1498Szrj 		}
925838fd1498Szrj 	      add_reg_note (insn, REG_CALL_ARG_LOCATION, arguments);
925938fd1498Szrj 	    }
926038fd1498Szrj 	    break;
926138fd1498Szrj 
926238fd1498Szrj 	  case MO_USE:
926338fd1498Szrj 	    {
926438fd1498Szrj 	      rtx loc = mo->u.loc;
926538fd1498Szrj 
926638fd1498Szrj 	      if (REG_P (loc))
926738fd1498Szrj 		var_reg_set (set, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL);
926838fd1498Szrj 	      else
926938fd1498Szrj 		var_mem_set (set, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL);
927038fd1498Szrj 
927138fd1498Szrj 	      emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, set->vars);
927238fd1498Szrj 	    }
927338fd1498Szrj 	    break;
927438fd1498Szrj 
927538fd1498Szrj 	  case MO_VAL_LOC:
927638fd1498Szrj 	    {
927738fd1498Szrj 	      rtx loc = mo->u.loc;
927838fd1498Szrj 	      rtx val, vloc;
927938fd1498Szrj 	      tree var;
928038fd1498Szrj 
928138fd1498Szrj 	      if (GET_CODE (loc) == CONCAT)
928238fd1498Szrj 		{
928338fd1498Szrj 		  val = XEXP (loc, 0);
928438fd1498Szrj 		  vloc = XEXP (loc, 1);
928538fd1498Szrj 		}
928638fd1498Szrj 	      else
928738fd1498Szrj 		{
928838fd1498Szrj 		  val = NULL_RTX;
928938fd1498Szrj 		  vloc = loc;
929038fd1498Szrj 		}
929138fd1498Szrj 
929238fd1498Szrj 	      var = PAT_VAR_LOCATION_DECL (vloc);
929338fd1498Szrj 
929438fd1498Szrj 	      clobber_variable_part (set, NULL_RTX,
929538fd1498Szrj 				     dv_from_decl (var), 0, NULL_RTX);
929638fd1498Szrj 	      if (val)
929738fd1498Szrj 		{
929838fd1498Szrj 		  if (VAL_NEEDS_RESOLUTION (loc))
929938fd1498Szrj 		    val_resolve (set, val, PAT_VAR_LOCATION_LOC (vloc), insn);
930038fd1498Szrj 		  set_variable_part (set, val, dv_from_decl (var), 0,
930138fd1498Szrj 				     VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
930238fd1498Szrj 				     INSERT);
930338fd1498Szrj 		}
930438fd1498Szrj 	      else if (!VAR_LOC_UNKNOWN_P (PAT_VAR_LOCATION_LOC (vloc)))
930538fd1498Szrj 		set_variable_part (set, PAT_VAR_LOCATION_LOC (vloc),
930638fd1498Szrj 				   dv_from_decl (var), 0,
930738fd1498Szrj 				   VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
930838fd1498Szrj 				   INSERT);
930938fd1498Szrj 
931038fd1498Szrj 	      emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN, set->vars);
931138fd1498Szrj 	    }
931238fd1498Szrj 	    break;
931338fd1498Szrj 
931438fd1498Szrj 	  case MO_VAL_USE:
931538fd1498Szrj 	    {
931638fd1498Szrj 	      rtx loc = mo->u.loc;
931738fd1498Szrj 	      rtx val, vloc, uloc;
931838fd1498Szrj 
931938fd1498Szrj 	      vloc = uloc = XEXP (loc, 1);
932038fd1498Szrj 	      val = XEXP (loc, 0);
932138fd1498Szrj 
932238fd1498Szrj 	      if (GET_CODE (val) == CONCAT)
932338fd1498Szrj 		{
932438fd1498Szrj 		  uloc = XEXP (val, 1);
932538fd1498Szrj 		  val = XEXP (val, 0);
932638fd1498Szrj 		}
932738fd1498Szrj 
932838fd1498Szrj 	      if (VAL_NEEDS_RESOLUTION (loc))
932938fd1498Szrj 		val_resolve (set, val, vloc, insn);
933038fd1498Szrj 	      else
933138fd1498Szrj 		val_store (set, val, uloc, insn, false);
933238fd1498Szrj 
933338fd1498Szrj 	      if (VAL_HOLDS_TRACK_EXPR (loc))
933438fd1498Szrj 		{
933538fd1498Szrj 		  if (GET_CODE (uloc) == REG)
933638fd1498Szrj 		    var_reg_set (set, uloc, VAR_INIT_STATUS_UNINITIALIZED,
933738fd1498Szrj 				 NULL);
933838fd1498Szrj 		  else if (GET_CODE (uloc) == MEM)
933938fd1498Szrj 		    var_mem_set (set, uloc, VAR_INIT_STATUS_UNINITIALIZED,
934038fd1498Szrj 				 NULL);
934138fd1498Szrj 		}
934238fd1498Szrj 
934338fd1498Szrj 	      emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, set->vars);
934438fd1498Szrj 	    }
934538fd1498Szrj 	    break;
934638fd1498Szrj 
934738fd1498Szrj 	  case MO_VAL_SET:
934838fd1498Szrj 	    {
934938fd1498Szrj 	      rtx loc = mo->u.loc;
935038fd1498Szrj 	      rtx val, vloc, uloc;
935138fd1498Szrj 	      rtx dstv, srcv;
935238fd1498Szrj 
935338fd1498Szrj 	      vloc = loc;
935438fd1498Szrj 	      uloc = XEXP (vloc, 1);
935538fd1498Szrj 	      val = XEXP (vloc, 0);
935638fd1498Szrj 	      vloc = uloc;
935738fd1498Szrj 
935838fd1498Szrj 	      if (GET_CODE (uloc) == SET)
935938fd1498Szrj 		{
936038fd1498Szrj 		  dstv = SET_DEST (uloc);
936138fd1498Szrj 		  srcv = SET_SRC (uloc);
936238fd1498Szrj 		}
936338fd1498Szrj 	      else
936438fd1498Szrj 		{
936538fd1498Szrj 		  dstv = uloc;
936638fd1498Szrj 		  srcv = NULL;
936738fd1498Szrj 		}
936838fd1498Szrj 
936938fd1498Szrj 	      if (GET_CODE (val) == CONCAT)
937038fd1498Szrj 		{
937138fd1498Szrj 		  dstv = vloc = XEXP (val, 1);
937238fd1498Szrj 		  val = XEXP (val, 0);
937338fd1498Szrj 		}
937438fd1498Szrj 
937538fd1498Szrj 	      if (GET_CODE (vloc) == SET)
937638fd1498Szrj 		{
937738fd1498Szrj 		  srcv = SET_SRC (vloc);
937838fd1498Szrj 
937938fd1498Szrj 		  gcc_assert (val != srcv);
938038fd1498Szrj 		  gcc_assert (vloc == uloc || VAL_NEEDS_RESOLUTION (loc));
938138fd1498Szrj 
938238fd1498Szrj 		  dstv = vloc = SET_DEST (vloc);
938338fd1498Szrj 
938438fd1498Szrj 		  if (VAL_NEEDS_RESOLUTION (loc))
938538fd1498Szrj 		    val_resolve (set, val, srcv, insn);
938638fd1498Szrj 		}
938738fd1498Szrj 	      else if (VAL_NEEDS_RESOLUTION (loc))
938838fd1498Szrj 		{
938938fd1498Szrj 		  gcc_assert (GET_CODE (uloc) == SET
939038fd1498Szrj 			      && GET_CODE (SET_SRC (uloc)) == REG);
939138fd1498Szrj 		  val_resolve (set, val, SET_SRC (uloc), insn);
939238fd1498Szrj 		}
939338fd1498Szrj 
939438fd1498Szrj 	      if (VAL_HOLDS_TRACK_EXPR (loc))
939538fd1498Szrj 		{
939638fd1498Szrj 		  if (VAL_EXPR_IS_CLOBBERED (loc))
939738fd1498Szrj 		    {
939838fd1498Szrj 		      if (REG_P (uloc))
939938fd1498Szrj 			var_reg_delete (set, uloc, true);
940038fd1498Szrj 		      else if (MEM_P (uloc))
940138fd1498Szrj 			{
940238fd1498Szrj 			  gcc_assert (MEM_P (dstv));
940338fd1498Szrj 			  gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (uloc));
940438fd1498Szrj 			  var_mem_delete (set, dstv, true);
940538fd1498Szrj 			}
940638fd1498Szrj 		    }
940738fd1498Szrj 		  else
940838fd1498Szrj 		    {
940938fd1498Szrj 		      bool copied_p = VAL_EXPR_IS_COPIED (loc);
941038fd1498Szrj 		      rtx src = NULL, dst = uloc;
941138fd1498Szrj 		      enum var_init_status status = VAR_INIT_STATUS_INITIALIZED;
941238fd1498Szrj 
941338fd1498Szrj 		      if (GET_CODE (uloc) == SET)
941438fd1498Szrj 			{
941538fd1498Szrj 			  src = SET_SRC (uloc);
941638fd1498Szrj 			  dst = SET_DEST (uloc);
941738fd1498Szrj 			}
941838fd1498Szrj 
941938fd1498Szrj 		      if (copied_p)
942038fd1498Szrj 			{
942138fd1498Szrj 			  status = find_src_status (set, src);
942238fd1498Szrj 
942338fd1498Szrj 			  src = find_src_set_src (set, src);
942438fd1498Szrj 			}
942538fd1498Szrj 
942638fd1498Szrj 		      if (REG_P (dst))
942738fd1498Szrj 			var_reg_delete_and_set (set, dst, !copied_p,
942838fd1498Szrj 						status, srcv);
942938fd1498Szrj 		      else if (MEM_P (dst))
943038fd1498Szrj 			{
943138fd1498Szrj 			  gcc_assert (MEM_P (dstv));
943238fd1498Szrj 			  gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (dst));
943338fd1498Szrj 			  var_mem_delete_and_set (set, dstv, !copied_p,
943438fd1498Szrj 						  status, srcv);
943538fd1498Szrj 			}
943638fd1498Szrj 		    }
943738fd1498Szrj 		}
943838fd1498Szrj 	      else if (REG_P (uloc))
943938fd1498Szrj 		var_regno_delete (set, REGNO (uloc));
944038fd1498Szrj 	      else if (MEM_P (uloc))
944138fd1498Szrj 		{
944238fd1498Szrj 		  gcc_checking_assert (GET_CODE (vloc) == MEM);
944338fd1498Szrj 		  gcc_checking_assert (vloc == dstv);
944438fd1498Szrj 		  if (vloc != dstv)
944538fd1498Szrj 		    clobber_overlapping_mems (set, vloc);
944638fd1498Szrj 		}
944738fd1498Szrj 
944838fd1498Szrj 	      val_store (set, val, dstv, insn, true);
944938fd1498Szrj 
945038fd1498Szrj 	      emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
945138fd1498Szrj 				      set->vars);
945238fd1498Szrj 	    }
945338fd1498Szrj 	    break;
945438fd1498Szrj 
945538fd1498Szrj 	  case MO_SET:
945638fd1498Szrj 	    {
945738fd1498Szrj 	      rtx loc = mo->u.loc;
945838fd1498Szrj 	      rtx set_src = NULL;
945938fd1498Szrj 
946038fd1498Szrj 	      if (GET_CODE (loc) == SET)
946138fd1498Szrj 		{
946238fd1498Szrj 		  set_src = SET_SRC (loc);
946338fd1498Szrj 		  loc = SET_DEST (loc);
946438fd1498Szrj 		}
946538fd1498Szrj 
946638fd1498Szrj 	      if (REG_P (loc))
946738fd1498Szrj 		var_reg_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED,
946838fd1498Szrj 					set_src);
946938fd1498Szrj 	      else
947038fd1498Szrj 		var_mem_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED,
947138fd1498Szrj 					set_src);
947238fd1498Szrj 
947338fd1498Szrj 	      emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
947438fd1498Szrj 				      set->vars);
947538fd1498Szrj 	    }
947638fd1498Szrj 	    break;
947738fd1498Szrj 
947838fd1498Szrj 	  case MO_COPY:
947938fd1498Szrj 	    {
948038fd1498Szrj 	      rtx loc = mo->u.loc;
948138fd1498Szrj 	      enum var_init_status src_status;
948238fd1498Szrj 	      rtx set_src = NULL;
948338fd1498Szrj 
948438fd1498Szrj 	      if (GET_CODE (loc) == SET)
948538fd1498Szrj 		{
948638fd1498Szrj 		  set_src = SET_SRC (loc);
948738fd1498Szrj 		  loc = SET_DEST (loc);
948838fd1498Szrj 		}
948938fd1498Szrj 
949038fd1498Szrj 	      src_status = find_src_status (set, set_src);
949138fd1498Szrj 	      set_src = find_src_set_src (set, set_src);
949238fd1498Szrj 
949338fd1498Szrj 	      if (REG_P (loc))
949438fd1498Szrj 		var_reg_delete_and_set (set, loc, false, src_status, set_src);
949538fd1498Szrj 	      else
949638fd1498Szrj 		var_mem_delete_and_set (set, loc, false, src_status, set_src);
949738fd1498Szrj 
949838fd1498Szrj 	      emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
949938fd1498Szrj 				      set->vars);
950038fd1498Szrj 	    }
950138fd1498Szrj 	    break;
950238fd1498Szrj 
950338fd1498Szrj 	  case MO_USE_NO_VAR:
950438fd1498Szrj 	    {
950538fd1498Szrj 	      rtx loc = mo->u.loc;
950638fd1498Szrj 
950738fd1498Szrj 	      if (REG_P (loc))
950838fd1498Szrj 		var_reg_delete (set, loc, false);
950938fd1498Szrj 	      else
951038fd1498Szrj 		var_mem_delete (set, loc, false);
951138fd1498Szrj 
951238fd1498Szrj 	      emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN, set->vars);
951338fd1498Szrj 	    }
951438fd1498Szrj 	    break;
951538fd1498Szrj 
951638fd1498Szrj 	  case MO_CLOBBER:
951738fd1498Szrj 	    {
951838fd1498Szrj 	      rtx loc = mo->u.loc;
951938fd1498Szrj 
952038fd1498Szrj 	      if (REG_P (loc))
952138fd1498Szrj 		var_reg_delete (set, loc, true);
952238fd1498Szrj 	      else
952338fd1498Szrj 		var_mem_delete (set, loc, true);
952438fd1498Szrj 
952538fd1498Szrj 	      emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
952638fd1498Szrj 				      set->vars);
952738fd1498Szrj 	    }
952838fd1498Szrj 	    break;
952938fd1498Szrj 
953038fd1498Szrj 	  case MO_ADJUST:
953138fd1498Szrj 	    set->stack_adjust += mo->u.adjust;
953238fd1498Szrj 	    break;
953338fd1498Szrj 	}
953438fd1498Szrj     }
953538fd1498Szrj }
953638fd1498Szrj 
953738fd1498Szrj /* Emit notes for the whole function.  */
953838fd1498Szrj 
953938fd1498Szrj static void
vt_emit_notes(void)954038fd1498Szrj vt_emit_notes (void)
954138fd1498Szrj {
954238fd1498Szrj   basic_block bb;
954338fd1498Szrj   dataflow_set cur;
954438fd1498Szrj 
954538fd1498Szrj   gcc_assert (!changed_variables->elements ());
954638fd1498Szrj 
954738fd1498Szrj   /* Free memory occupied by the out hash tables, as they aren't used
954838fd1498Szrj      anymore.  */
954938fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
955038fd1498Szrj     dataflow_set_clear (&VTI (bb)->out);
955138fd1498Szrj 
955238fd1498Szrj   /* Enable emitting notes by functions (mainly by set_variable_part and
955338fd1498Szrj      delete_variable_part).  */
955438fd1498Szrj   emit_notes = true;
955538fd1498Szrj 
955638fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
955738fd1498Szrj     dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
955838fd1498Szrj 
955938fd1498Szrj   dataflow_set_init (&cur);
956038fd1498Szrj 
956138fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
956238fd1498Szrj     {
956338fd1498Szrj       /* Emit the notes for changes of variable locations between two
956438fd1498Szrj 	 subsequent basic blocks.  */
956538fd1498Szrj       emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
956638fd1498Szrj 
956738fd1498Szrj       if (MAY_HAVE_DEBUG_BIND_INSNS)
956838fd1498Szrj 	local_get_addr_cache = new hash_map<rtx, rtx>;
956938fd1498Szrj 
957038fd1498Szrj       /* Emit the notes for the changes in the basic block itself.  */
957138fd1498Szrj       emit_notes_in_bb (bb, &cur);
957238fd1498Szrj 
957338fd1498Szrj       if (MAY_HAVE_DEBUG_BIND_INSNS)
957438fd1498Szrj 	delete local_get_addr_cache;
957538fd1498Szrj       local_get_addr_cache = NULL;
957638fd1498Szrj 
957738fd1498Szrj       /* Free memory occupied by the in hash table, we won't need it
957838fd1498Szrj 	 again.  */
957938fd1498Szrj       dataflow_set_clear (&VTI (bb)->in);
958038fd1498Szrj     }
958138fd1498Szrj 
958238fd1498Szrj   if (flag_checking)
958338fd1498Szrj     shared_hash_htab (cur.vars)
958438fd1498Szrj       ->traverse <variable_table_type *, emit_notes_for_differences_1>
958538fd1498Szrj 	(shared_hash_htab (empty_shared_hash));
958638fd1498Szrj 
958738fd1498Szrj   dataflow_set_destroy (&cur);
958838fd1498Szrj 
958938fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
959038fd1498Szrj     delete dropped_values;
959138fd1498Szrj   dropped_values = NULL;
959238fd1498Szrj 
959338fd1498Szrj   emit_notes = false;
959438fd1498Szrj }
959538fd1498Szrj 
959638fd1498Szrj /* If there is a declaration and offset associated with register/memory RTL
959738fd1498Szrj    assign declaration to *DECLP and offset to *OFFSETP, and return true.  */
959838fd1498Szrj 
959938fd1498Szrj static bool
vt_get_decl_and_offset(rtx rtl,tree * declp,poly_int64 * offsetp)960038fd1498Szrj vt_get_decl_and_offset (rtx rtl, tree *declp, poly_int64 *offsetp)
960138fd1498Szrj {
960238fd1498Szrj   if (REG_P (rtl))
960338fd1498Szrj     {
960438fd1498Szrj       if (REG_ATTRS (rtl))
960538fd1498Szrj 	{
960638fd1498Szrj 	  *declp = REG_EXPR (rtl);
960738fd1498Szrj 	  *offsetp = REG_OFFSET (rtl);
960838fd1498Szrj 	  return true;
960938fd1498Szrj 	}
961038fd1498Szrj     }
961138fd1498Szrj   else if (GET_CODE (rtl) == PARALLEL)
961238fd1498Szrj     {
961338fd1498Szrj       tree decl = NULL_TREE;
961438fd1498Szrj       HOST_WIDE_INT offset = MAX_VAR_PARTS;
961538fd1498Szrj       int len = XVECLEN (rtl, 0), i;
961638fd1498Szrj 
961738fd1498Szrj       for (i = 0; i < len; i++)
961838fd1498Szrj 	{
961938fd1498Szrj 	  rtx reg = XEXP (XVECEXP (rtl, 0, i), 0);
962038fd1498Szrj 	  if (!REG_P (reg) || !REG_ATTRS (reg))
962138fd1498Szrj 	    break;
962238fd1498Szrj 	  if (!decl)
962338fd1498Szrj 	    decl = REG_EXPR (reg);
962438fd1498Szrj 	  if (REG_EXPR (reg) != decl)
962538fd1498Szrj 	    break;
962638fd1498Szrj 	  HOST_WIDE_INT this_offset;
962738fd1498Szrj 	  if (!track_offset_p (REG_OFFSET (reg), &this_offset))
962838fd1498Szrj 	    break;
962938fd1498Szrj 	  offset = MIN (offset, this_offset);
963038fd1498Szrj 	}
963138fd1498Szrj 
963238fd1498Szrj       if (i == len)
963338fd1498Szrj 	{
963438fd1498Szrj 	  *declp = decl;
963538fd1498Szrj 	  *offsetp = offset;
963638fd1498Szrj 	  return true;
963738fd1498Szrj 	}
963838fd1498Szrj     }
963938fd1498Szrj   else if (MEM_P (rtl))
964038fd1498Szrj     {
964138fd1498Szrj       if (MEM_ATTRS (rtl))
964238fd1498Szrj 	{
964338fd1498Szrj 	  *declp = MEM_EXPR (rtl);
964438fd1498Szrj 	  *offsetp = int_mem_offset (rtl);
964538fd1498Szrj 	  return true;
964638fd1498Szrj 	}
964738fd1498Szrj     }
964838fd1498Szrj   return false;
964938fd1498Szrj }
965038fd1498Szrj 
965138fd1498Szrj /* Record the value for the ENTRY_VALUE of RTL as a global equivalence
965238fd1498Szrj    of VAL.  */
965338fd1498Szrj 
965438fd1498Szrj static void
record_entry_value(cselib_val * val,rtx rtl)965538fd1498Szrj record_entry_value (cselib_val *val, rtx rtl)
965638fd1498Szrj {
965738fd1498Szrj   rtx ev = gen_rtx_ENTRY_VALUE (GET_MODE (rtl));
965838fd1498Szrj 
965938fd1498Szrj   ENTRY_VALUE_EXP (ev) = rtl;
966038fd1498Szrj 
966138fd1498Szrj   cselib_add_permanent_equiv (val, ev, get_insns ());
966238fd1498Szrj }
966338fd1498Szrj 
966438fd1498Szrj /* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK.  */
966538fd1498Szrj 
966638fd1498Szrj static void
vt_add_function_parameter(tree parm)966738fd1498Szrj vt_add_function_parameter (tree parm)
966838fd1498Szrj {
966938fd1498Szrj   rtx decl_rtl = DECL_RTL_IF_SET (parm);
967038fd1498Szrj   rtx incoming = DECL_INCOMING_RTL (parm);
967138fd1498Szrj   tree decl;
967238fd1498Szrj   machine_mode mode;
967338fd1498Szrj   poly_int64 offset;
967438fd1498Szrj   dataflow_set *out;
967538fd1498Szrj   decl_or_value dv;
967638fd1498Szrj   bool incoming_ok = true;
967738fd1498Szrj 
967838fd1498Szrj   if (TREE_CODE (parm) != PARM_DECL)
967938fd1498Szrj     return;
968038fd1498Szrj 
968138fd1498Szrj   if (!decl_rtl || !incoming)
968238fd1498Szrj     return;
968338fd1498Szrj 
968438fd1498Szrj   if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
968538fd1498Szrj     return;
968638fd1498Szrj 
968738fd1498Szrj   /* If there is a DRAP register or a pseudo in internal_arg_pointer,
968838fd1498Szrj      rewrite the incoming location of parameters passed on the stack
968938fd1498Szrj      into MEMs based on the argument pointer, so that incoming doesn't
969038fd1498Szrj      depend on a pseudo.  */
969138fd1498Szrj   if (MEM_P (incoming)
969238fd1498Szrj       && (XEXP (incoming, 0) == crtl->args.internal_arg_pointer
969338fd1498Szrj 	  || (GET_CODE (XEXP (incoming, 0)) == PLUS
969438fd1498Szrj 	      && XEXP (XEXP (incoming, 0), 0)
969538fd1498Szrj 		 == crtl->args.internal_arg_pointer
969638fd1498Szrj 	      && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
969738fd1498Szrj     {
969838fd1498Szrj       HOST_WIDE_INT off = -FIRST_PARM_OFFSET (current_function_decl);
969938fd1498Szrj       if (GET_CODE (XEXP (incoming, 0)) == PLUS)
970038fd1498Szrj 	off += INTVAL (XEXP (XEXP (incoming, 0), 1));
970138fd1498Szrj       incoming
970238fd1498Szrj 	= replace_equiv_address_nv (incoming,
970338fd1498Szrj 				    plus_constant (Pmode,
970438fd1498Szrj 						   arg_pointer_rtx, off));
970538fd1498Szrj     }
970638fd1498Szrj 
970738fd1498Szrj #ifdef HAVE_window_save
970838fd1498Szrj   /* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers.
970938fd1498Szrj      If the target machine has an explicit window save instruction, the
971038fd1498Szrj      actual entry value is the corresponding OUTGOING_REGNO instead.  */
971138fd1498Szrj   if (HAVE_window_save && !crtl->uses_only_leaf_regs)
971238fd1498Szrj     {
971338fd1498Szrj       if (REG_P (incoming)
971438fd1498Szrj 	  && HARD_REGISTER_P (incoming)
971538fd1498Szrj 	  && OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
971638fd1498Szrj 	{
971738fd1498Szrj 	  parm_reg p;
971838fd1498Szrj 	  p.incoming = incoming;
971938fd1498Szrj 	  incoming
972038fd1498Szrj 	    = gen_rtx_REG_offset (incoming, GET_MODE (incoming),
972138fd1498Szrj 				  OUTGOING_REGNO (REGNO (incoming)), 0);
972238fd1498Szrj 	  p.outgoing = incoming;
972338fd1498Szrj 	  vec_safe_push (windowed_parm_regs, p);
972438fd1498Szrj 	}
972538fd1498Szrj       else if (GET_CODE (incoming) == PARALLEL)
972638fd1498Szrj 	{
972738fd1498Szrj 	  rtx outgoing
972838fd1498Szrj 	    = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (incoming, 0)));
972938fd1498Szrj 	  int i;
973038fd1498Szrj 
973138fd1498Szrj 	  for (i = 0; i < XVECLEN (incoming, 0); i++)
973238fd1498Szrj 	    {
973338fd1498Szrj 	      rtx reg = XEXP (XVECEXP (incoming, 0, i), 0);
973438fd1498Szrj 	      parm_reg p;
973538fd1498Szrj 	      p.incoming = reg;
973638fd1498Szrj 	      reg = gen_rtx_REG_offset (reg, GET_MODE (reg),
973738fd1498Szrj 					OUTGOING_REGNO (REGNO (reg)), 0);
973838fd1498Szrj 	      p.outgoing = reg;
973938fd1498Szrj 	      XVECEXP (outgoing, 0, i)
974038fd1498Szrj 		= gen_rtx_EXPR_LIST (VOIDmode, reg,
974138fd1498Szrj 				     XEXP (XVECEXP (incoming, 0, i), 1));
974238fd1498Szrj 	      vec_safe_push (windowed_parm_regs, p);
974338fd1498Szrj 	    }
974438fd1498Szrj 
974538fd1498Szrj 	  incoming = outgoing;
974638fd1498Szrj 	}
974738fd1498Szrj       else if (MEM_P (incoming)
974838fd1498Szrj 	       && REG_P (XEXP (incoming, 0))
974938fd1498Szrj 	       && HARD_REGISTER_P (XEXP (incoming, 0)))
975038fd1498Szrj 	{
975138fd1498Szrj 	  rtx reg = XEXP (incoming, 0);
975238fd1498Szrj 	  if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
975338fd1498Szrj 	    {
975438fd1498Szrj 	      parm_reg p;
975538fd1498Szrj 	      p.incoming = reg;
975638fd1498Szrj 	      reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
975738fd1498Szrj 	      p.outgoing = reg;
975838fd1498Szrj 	      vec_safe_push (windowed_parm_regs, p);
975938fd1498Szrj 	      incoming = replace_equiv_address_nv (incoming, reg);
976038fd1498Szrj 	    }
976138fd1498Szrj 	}
976238fd1498Szrj     }
976338fd1498Szrj #endif
976438fd1498Szrj 
976538fd1498Szrj   if (!vt_get_decl_and_offset (incoming, &decl, &offset))
976638fd1498Szrj     {
976738fd1498Szrj       incoming_ok = false;
976838fd1498Szrj       if (MEM_P (incoming))
976938fd1498Szrj 	{
977038fd1498Szrj 	  /* This means argument is passed by invisible reference.  */
977138fd1498Szrj 	  offset = 0;
977238fd1498Szrj 	  decl = parm;
977338fd1498Szrj 	}
977438fd1498Szrj       else
977538fd1498Szrj 	{
977638fd1498Szrj 	  if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
977738fd1498Szrj 	    return;
977838fd1498Szrj 	  offset += byte_lowpart_offset (GET_MODE (incoming),
977938fd1498Szrj 					 GET_MODE (decl_rtl));
978038fd1498Szrj 	}
978138fd1498Szrj     }
978238fd1498Szrj 
978338fd1498Szrj   if (!decl)
978438fd1498Szrj     return;
978538fd1498Szrj 
978638fd1498Szrj   if (parm != decl)
978738fd1498Szrj     {
978838fd1498Szrj       /* If that DECL_RTL wasn't a pseudo that got spilled to
978938fd1498Szrj 	 memory, bail out.  Otherwise, the spill slot sharing code
979038fd1498Szrj 	 will force the memory to reference spill_slot_decl (%sfp),
979138fd1498Szrj 	 so we don't match above.  That's ok, the pseudo must have
979238fd1498Szrj 	 referenced the entire parameter, so just reset OFFSET.  */
979338fd1498Szrj       if (decl != get_spill_slot_decl (false))
979438fd1498Szrj         return;
979538fd1498Szrj       offset = 0;
979638fd1498Szrj     }
979738fd1498Szrj 
979838fd1498Szrj   HOST_WIDE_INT const_offset;
979938fd1498Szrj   if (!track_loc_p (incoming, parm, offset, false, &mode, &const_offset))
980038fd1498Szrj     return;
980138fd1498Szrj 
980238fd1498Szrj   out = &VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out;
980338fd1498Szrj 
980438fd1498Szrj   dv = dv_from_decl (parm);
980538fd1498Szrj 
980638fd1498Szrj   if (target_for_debug_bind (parm)
980738fd1498Szrj       /* We can't deal with these right now, because this kind of
980838fd1498Szrj 	 variable is single-part.  ??? We could handle parallels
980938fd1498Szrj 	 that describe multiple locations for the same single
981038fd1498Szrj 	 value, but ATM we don't.  */
981138fd1498Szrj       && GET_CODE (incoming) != PARALLEL)
981238fd1498Szrj     {
981338fd1498Szrj       cselib_val *val;
981438fd1498Szrj       rtx lowpart;
981538fd1498Szrj 
981638fd1498Szrj       /* ??? We shouldn't ever hit this, but it may happen because
981738fd1498Szrj 	 arguments passed by invisible reference aren't dealt with
981838fd1498Szrj 	 above: incoming-rtl will have Pmode rather than the
981938fd1498Szrj 	 expected mode for the type.  */
982038fd1498Szrj       if (const_offset)
982138fd1498Szrj 	return;
982238fd1498Szrj 
982338fd1498Szrj       lowpart = var_lowpart (mode, incoming);
982438fd1498Szrj       if (!lowpart)
982538fd1498Szrj 	return;
982638fd1498Szrj 
982738fd1498Szrj       val = cselib_lookup_from_insn (lowpart, mode, true,
982838fd1498Szrj 				     VOIDmode, get_insns ());
982938fd1498Szrj 
983038fd1498Szrj       /* ??? Float-typed values in memory are not handled by
983138fd1498Szrj 	 cselib.  */
983238fd1498Szrj       if (val)
983338fd1498Szrj 	{
983438fd1498Szrj 	  preserve_value (val);
983538fd1498Szrj 	  set_variable_part (out, val->val_rtx, dv, const_offset,
983638fd1498Szrj 			     VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
983738fd1498Szrj 	  dv = dv_from_value (val->val_rtx);
983838fd1498Szrj 	}
983938fd1498Szrj 
984038fd1498Szrj       if (MEM_P (incoming))
984138fd1498Szrj 	{
984238fd1498Szrj 	  val = cselib_lookup_from_insn (XEXP (incoming, 0), mode, true,
984338fd1498Szrj 					 VOIDmode, get_insns ());
984438fd1498Szrj 	  if (val)
984538fd1498Szrj 	    {
984638fd1498Szrj 	      preserve_value (val);
984738fd1498Szrj 	      incoming = replace_equiv_address_nv (incoming, val->val_rtx);
984838fd1498Szrj 	    }
984938fd1498Szrj 	}
985038fd1498Szrj     }
985138fd1498Szrj 
985238fd1498Szrj   if (REG_P (incoming))
985338fd1498Szrj     {
985438fd1498Szrj       incoming = var_lowpart (mode, incoming);
985538fd1498Szrj       gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
985638fd1498Szrj       attrs_list_insert (&out->regs[REGNO (incoming)], dv, const_offset,
985738fd1498Szrj 			 incoming);
985838fd1498Szrj       set_variable_part (out, incoming, dv, const_offset,
985938fd1498Szrj 			 VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
986038fd1498Szrj       if (dv_is_value_p (dv))
986138fd1498Szrj 	{
986238fd1498Szrj 	  record_entry_value (CSELIB_VAL_PTR (dv_as_value (dv)), incoming);
986338fd1498Szrj 	  if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
986438fd1498Szrj 	      && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
986538fd1498Szrj 	    {
986638fd1498Szrj 	      machine_mode indmode
986738fd1498Szrj 		= TYPE_MODE (TREE_TYPE (TREE_TYPE (parm)));
986838fd1498Szrj 	      rtx mem = gen_rtx_MEM (indmode, incoming);
986938fd1498Szrj 	      cselib_val *val = cselib_lookup_from_insn (mem, indmode, true,
987038fd1498Szrj 							 VOIDmode,
987138fd1498Szrj 							 get_insns ());
987238fd1498Szrj 	      if (val)
987338fd1498Szrj 		{
987438fd1498Szrj 		  preserve_value (val);
987538fd1498Szrj 		  record_entry_value (val, mem);
987638fd1498Szrj 		  set_variable_part (out, mem, dv_from_value (val->val_rtx), 0,
987738fd1498Szrj 				     VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
987838fd1498Szrj 		}
987938fd1498Szrj 	    }
988038fd1498Szrj 	}
988138fd1498Szrj     }
988238fd1498Szrj   else if (GET_CODE (incoming) == PARALLEL && !dv_onepart_p (dv))
988338fd1498Szrj     {
988438fd1498Szrj       int i;
988538fd1498Szrj 
988638fd1498Szrj       /* The following code relies on vt_get_decl_and_offset returning true for
988738fd1498Szrj 	 incoming, which might not be always the case.  */
988838fd1498Szrj       if (!incoming_ok)
988938fd1498Szrj 	return;
989038fd1498Szrj       for (i = 0; i < XVECLEN (incoming, 0); i++)
989138fd1498Szrj 	{
989238fd1498Szrj 	  rtx reg = XEXP (XVECEXP (incoming, 0, i), 0);
989338fd1498Szrj 	  /* vt_get_decl_and_offset has already checked that the offset
989438fd1498Szrj 	     is a valid variable part.  */
989538fd1498Szrj 	  const_offset = get_tracked_reg_offset (reg);
989638fd1498Szrj 	  gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER);
989738fd1498Szrj 	  attrs_list_insert (&out->regs[REGNO (reg)], dv, const_offset, reg);
989838fd1498Szrj 	  set_variable_part (out, reg, dv, const_offset,
989938fd1498Szrj 			     VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
990038fd1498Szrj 	}
990138fd1498Szrj     }
990238fd1498Szrj   else if (MEM_P (incoming))
990338fd1498Szrj     {
990438fd1498Szrj       incoming = var_lowpart (mode, incoming);
990538fd1498Szrj       set_variable_part (out, incoming, dv, const_offset,
990638fd1498Szrj 			 VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
990738fd1498Szrj     }
990838fd1498Szrj }
990938fd1498Szrj 
991038fd1498Szrj /* Insert function parameters to IN and OUT sets of ENTRY_BLOCK.  */
991138fd1498Szrj 
991238fd1498Szrj static void
vt_add_function_parameters(void)991338fd1498Szrj vt_add_function_parameters (void)
991438fd1498Szrj {
991538fd1498Szrj   tree parm;
991638fd1498Szrj 
991738fd1498Szrj   for (parm = DECL_ARGUMENTS (current_function_decl);
991838fd1498Szrj        parm; parm = DECL_CHAIN (parm))
991938fd1498Szrj     if (!POINTER_BOUNDS_P (parm))
992038fd1498Szrj       vt_add_function_parameter (parm);
992138fd1498Szrj 
992238fd1498Szrj   if (DECL_HAS_VALUE_EXPR_P (DECL_RESULT (current_function_decl)))
992338fd1498Szrj     {
992438fd1498Szrj       tree vexpr = DECL_VALUE_EXPR (DECL_RESULT (current_function_decl));
992538fd1498Szrj 
992638fd1498Szrj       if (TREE_CODE (vexpr) == INDIRECT_REF)
992738fd1498Szrj 	vexpr = TREE_OPERAND (vexpr, 0);
992838fd1498Szrj 
992938fd1498Szrj       if (TREE_CODE (vexpr) == PARM_DECL
993038fd1498Szrj 	  && DECL_ARTIFICIAL (vexpr)
993138fd1498Szrj 	  && !DECL_IGNORED_P (vexpr)
993238fd1498Szrj 	  && DECL_NAMELESS (vexpr))
993338fd1498Szrj 	vt_add_function_parameter (vexpr);
993438fd1498Szrj     }
993538fd1498Szrj }
993638fd1498Szrj 
993738fd1498Szrj /* Initialize cfa_base_rtx, create a preserved VALUE for it and
993838fd1498Szrj    ensure it isn't flushed during cselib_reset_table.
993938fd1498Szrj    Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
994038fd1498Szrj    has been eliminated.  */
994138fd1498Szrj 
994238fd1498Szrj static void
vt_init_cfa_base(void)994338fd1498Szrj vt_init_cfa_base (void)
994438fd1498Szrj {
994538fd1498Szrj   cselib_val *val;
994638fd1498Szrj 
994738fd1498Szrj #ifdef FRAME_POINTER_CFA_OFFSET
994838fd1498Szrj   cfa_base_rtx = frame_pointer_rtx;
994938fd1498Szrj   cfa_base_offset = -FRAME_POINTER_CFA_OFFSET (current_function_decl);
995038fd1498Szrj #else
995138fd1498Szrj   cfa_base_rtx = arg_pointer_rtx;
995238fd1498Szrj   cfa_base_offset = -ARG_POINTER_CFA_OFFSET (current_function_decl);
995338fd1498Szrj #endif
995438fd1498Szrj   if (cfa_base_rtx == hard_frame_pointer_rtx
995538fd1498Szrj       || !fixed_regs[REGNO (cfa_base_rtx)])
995638fd1498Szrj     {
995738fd1498Szrj       cfa_base_rtx = NULL_RTX;
995838fd1498Szrj       return;
995938fd1498Szrj     }
996038fd1498Szrj   if (!MAY_HAVE_DEBUG_BIND_INSNS)
996138fd1498Szrj     return;
996238fd1498Szrj 
996338fd1498Szrj   /* Tell alias analysis that cfa_base_rtx should share
996438fd1498Szrj      find_base_term value with stack pointer or hard frame pointer.  */
996538fd1498Szrj   if (!frame_pointer_needed)
996638fd1498Szrj     vt_equate_reg_base_value (cfa_base_rtx, stack_pointer_rtx);
996738fd1498Szrj   else if (!crtl->stack_realign_tried)
996838fd1498Szrj     vt_equate_reg_base_value (cfa_base_rtx, hard_frame_pointer_rtx);
996938fd1498Szrj 
997038fd1498Szrj   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
997138fd1498Szrj 				 VOIDmode, get_insns ());
997238fd1498Szrj   preserve_value (val);
997338fd1498Szrj   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
997438fd1498Szrj }
997538fd1498Szrj 
997638fd1498Szrj /* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
997738fd1498Szrj 
997838fd1498Szrj static rtx_insn *
reemit_marker_as_note(rtx_insn * insn)997938fd1498Szrj reemit_marker_as_note (rtx_insn *insn)
998038fd1498Szrj {
998138fd1498Szrj   gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
998238fd1498Szrj 
998338fd1498Szrj   enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
998438fd1498Szrj 
998538fd1498Szrj   switch (kind)
998638fd1498Szrj     {
998738fd1498Szrj     case NOTE_INSN_BEGIN_STMT:
998838fd1498Szrj     case NOTE_INSN_INLINE_ENTRY:
998938fd1498Szrj       {
999038fd1498Szrj 	rtx_insn *note = NULL;
999138fd1498Szrj 	if (cfun->debug_nonbind_markers)
999238fd1498Szrj 	  {
999338fd1498Szrj 	    note = emit_note_before (kind, insn);
999438fd1498Szrj 	    NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
999538fd1498Szrj 	  }
999638fd1498Szrj 	delete_insn (insn);
999738fd1498Szrj 	return note;
999838fd1498Szrj       }
999938fd1498Szrj 
1000038fd1498Szrj     default:
1000138fd1498Szrj       gcc_unreachable ();
1000238fd1498Szrj     }
1000338fd1498Szrj }
1000438fd1498Szrj 
1000538fd1498Szrj /* Allocate and initialize the data structures for variable tracking
1000638fd1498Szrj    and parse the RTL to get the micro operations.  */
1000738fd1498Szrj 
1000838fd1498Szrj static bool
vt_initialize(void)1000938fd1498Szrj vt_initialize (void)
1001038fd1498Szrj {
1001138fd1498Szrj   basic_block bb;
1001238fd1498Szrj   HOST_WIDE_INT fp_cfa_offset = -1;
1001338fd1498Szrj 
1001438fd1498Szrj   alloc_aux_for_blocks (sizeof (variable_tracking_info));
1001538fd1498Szrj 
1001638fd1498Szrj   empty_shared_hash = shared_hash_pool.allocate ();
1001738fd1498Szrj   empty_shared_hash->refcount = 1;
1001838fd1498Szrj   empty_shared_hash->htab = new variable_table_type (1);
1001938fd1498Szrj   changed_variables = new variable_table_type (10);
1002038fd1498Szrj 
1002138fd1498Szrj   /* Init the IN and OUT sets.  */
1002238fd1498Szrj   FOR_ALL_BB_FN (bb, cfun)
1002338fd1498Szrj     {
1002438fd1498Szrj       VTI (bb)->visited = false;
1002538fd1498Szrj       VTI (bb)->flooded = false;
1002638fd1498Szrj       dataflow_set_init (&VTI (bb)->in);
1002738fd1498Szrj       dataflow_set_init (&VTI (bb)->out);
1002838fd1498Szrj       VTI (bb)->permp = NULL;
1002938fd1498Szrj     }
1003038fd1498Szrj 
1003138fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
1003238fd1498Szrj     {
1003338fd1498Szrj       cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
1003438fd1498Szrj       scratch_regs = BITMAP_ALLOC (NULL);
1003538fd1498Szrj       preserved_values.create (256);
1003638fd1498Szrj       global_get_addr_cache = new hash_map<rtx, rtx>;
1003738fd1498Szrj     }
1003838fd1498Szrj   else
1003938fd1498Szrj     {
1004038fd1498Szrj       scratch_regs = NULL;
1004138fd1498Szrj       global_get_addr_cache = NULL;
1004238fd1498Szrj     }
1004338fd1498Szrj 
1004438fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
1004538fd1498Szrj     {
1004638fd1498Szrj       rtx reg, expr;
1004738fd1498Szrj       int ofst;
1004838fd1498Szrj       cselib_val *val;
1004938fd1498Szrj 
1005038fd1498Szrj #ifdef FRAME_POINTER_CFA_OFFSET
1005138fd1498Szrj       reg = frame_pointer_rtx;
1005238fd1498Szrj       ofst = FRAME_POINTER_CFA_OFFSET (current_function_decl);
1005338fd1498Szrj #else
1005438fd1498Szrj       reg = arg_pointer_rtx;
1005538fd1498Szrj       ofst = ARG_POINTER_CFA_OFFSET (current_function_decl);
1005638fd1498Szrj #endif
1005738fd1498Szrj 
1005838fd1498Szrj       ofst -= INCOMING_FRAME_SP_OFFSET;
1005938fd1498Szrj 
1006038fd1498Szrj       val = cselib_lookup_from_insn (reg, GET_MODE (reg), 1,
1006138fd1498Szrj 				     VOIDmode, get_insns ());
1006238fd1498Szrj       preserve_value (val);
1006338fd1498Szrj       if (reg != hard_frame_pointer_rtx && fixed_regs[REGNO (reg)])
1006438fd1498Szrj 	cselib_preserve_cfa_base_value (val, REGNO (reg));
1006538fd1498Szrj       expr = plus_constant (GET_MODE (stack_pointer_rtx),
1006638fd1498Szrj 			    stack_pointer_rtx, -ofst);
1006738fd1498Szrj       cselib_add_permanent_equiv (val, expr, get_insns ());
1006838fd1498Szrj 
1006938fd1498Szrj       if (ofst)
1007038fd1498Szrj 	{
1007138fd1498Szrj 	  val = cselib_lookup_from_insn (stack_pointer_rtx,
1007238fd1498Szrj 					 GET_MODE (stack_pointer_rtx), 1,
1007338fd1498Szrj 					 VOIDmode, get_insns ());
1007438fd1498Szrj 	  preserve_value (val);
1007538fd1498Szrj 	  expr = plus_constant (GET_MODE (reg), reg, ofst);
1007638fd1498Szrj 	  cselib_add_permanent_equiv (val, expr, get_insns ());
1007738fd1498Szrj 	}
1007838fd1498Szrj     }
1007938fd1498Szrj 
1008038fd1498Szrj   /* In order to factor out the adjustments made to the stack pointer or to
1008138fd1498Szrj      the hard frame pointer and thus be able to use DW_OP_fbreg operations
1008238fd1498Szrj      instead of individual location lists, we're going to rewrite MEMs based
1008338fd1498Szrj      on them into MEMs based on the CFA by de-eliminating stack_pointer_rtx
1008438fd1498Szrj      or hard_frame_pointer_rtx to the virtual CFA pointer frame_pointer_rtx
1008538fd1498Szrj      resp. arg_pointer_rtx.  We can do this either when there is no frame
1008638fd1498Szrj      pointer in the function and stack adjustments are consistent for all
1008738fd1498Szrj      basic blocks or when there is a frame pointer and no stack realignment.
1008838fd1498Szrj      But we first have to check that frame_pointer_rtx resp. arg_pointer_rtx
1008938fd1498Szrj      has been eliminated.  */
1009038fd1498Szrj   if (!frame_pointer_needed)
1009138fd1498Szrj     {
1009238fd1498Szrj       rtx reg, elim;
1009338fd1498Szrj 
1009438fd1498Szrj       if (!vt_stack_adjustments ())
1009538fd1498Szrj 	return false;
1009638fd1498Szrj 
1009738fd1498Szrj #ifdef FRAME_POINTER_CFA_OFFSET
1009838fd1498Szrj       reg = frame_pointer_rtx;
1009938fd1498Szrj #else
1010038fd1498Szrj       reg = arg_pointer_rtx;
1010138fd1498Szrj #endif
1010238fd1498Szrj       elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
1010338fd1498Szrj       if (elim != reg)
1010438fd1498Szrj 	{
1010538fd1498Szrj 	  if (GET_CODE (elim) == PLUS)
1010638fd1498Szrj 	    elim = XEXP (elim, 0);
1010738fd1498Szrj 	  if (elim == stack_pointer_rtx)
1010838fd1498Szrj 	    vt_init_cfa_base ();
1010938fd1498Szrj 	}
1011038fd1498Szrj     }
1011138fd1498Szrj   else if (!crtl->stack_realign_tried)
1011238fd1498Szrj     {
1011338fd1498Szrj       rtx reg, elim;
1011438fd1498Szrj 
1011538fd1498Szrj #ifdef FRAME_POINTER_CFA_OFFSET
1011638fd1498Szrj       reg = frame_pointer_rtx;
1011738fd1498Szrj       fp_cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl);
1011838fd1498Szrj #else
1011938fd1498Szrj       reg = arg_pointer_rtx;
1012038fd1498Szrj       fp_cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
1012138fd1498Szrj #endif
1012238fd1498Szrj       elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
1012338fd1498Szrj       if (elim != reg)
1012438fd1498Szrj 	{
1012538fd1498Szrj 	  if (GET_CODE (elim) == PLUS)
1012638fd1498Szrj 	    {
1012738fd1498Szrj 	      fp_cfa_offset -= INTVAL (XEXP (elim, 1));
1012838fd1498Szrj 	      elim = XEXP (elim, 0);
1012938fd1498Szrj 	    }
1013038fd1498Szrj 	  if (elim != hard_frame_pointer_rtx)
1013138fd1498Szrj 	    fp_cfa_offset = -1;
1013238fd1498Szrj 	}
1013338fd1498Szrj       else
1013438fd1498Szrj 	fp_cfa_offset = -1;
1013538fd1498Szrj     }
1013638fd1498Szrj 
1013738fd1498Szrj   /* If the stack is realigned and a DRAP register is used, we're going to
1013838fd1498Szrj      rewrite MEMs based on it representing incoming locations of parameters
1013938fd1498Szrj      passed on the stack into MEMs based on the argument pointer.  Although
1014038fd1498Szrj      we aren't going to rewrite other MEMs, we still need to initialize the
1014138fd1498Szrj      virtual CFA pointer in order to ensure that the argument pointer will
1014238fd1498Szrj      be seen as a constant throughout the function.
1014338fd1498Szrj 
1014438fd1498Szrj      ??? This doesn't work if FRAME_POINTER_CFA_OFFSET is defined.  */
1014538fd1498Szrj   else if (stack_realign_drap)
1014638fd1498Szrj     {
1014738fd1498Szrj       rtx reg, elim;
1014838fd1498Szrj 
1014938fd1498Szrj #ifdef FRAME_POINTER_CFA_OFFSET
1015038fd1498Szrj       reg = frame_pointer_rtx;
1015138fd1498Szrj #else
1015238fd1498Szrj       reg = arg_pointer_rtx;
1015338fd1498Szrj #endif
1015438fd1498Szrj       elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
1015538fd1498Szrj       if (elim != reg)
1015638fd1498Szrj 	{
1015738fd1498Szrj 	  if (GET_CODE (elim) == PLUS)
1015838fd1498Szrj 	    elim = XEXP (elim, 0);
1015938fd1498Szrj 	  if (elim == hard_frame_pointer_rtx)
1016038fd1498Szrj 	    vt_init_cfa_base ();
1016138fd1498Szrj 	}
1016238fd1498Szrj     }
1016338fd1498Szrj 
1016438fd1498Szrj   hard_frame_pointer_adjustment = -1;
1016538fd1498Szrj 
1016638fd1498Szrj   vt_add_function_parameters ();
1016738fd1498Szrj 
1016838fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
1016938fd1498Szrj     {
1017038fd1498Szrj       rtx_insn *insn;
1017138fd1498Szrj       HOST_WIDE_INT pre, post = 0;
1017238fd1498Szrj       basic_block first_bb, last_bb;
1017338fd1498Szrj 
1017438fd1498Szrj       if (MAY_HAVE_DEBUG_BIND_INSNS)
1017538fd1498Szrj 	{
1017638fd1498Szrj 	  cselib_record_sets_hook = add_with_sets;
1017738fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
1017838fd1498Szrj 	    fprintf (dump_file, "first value: %i\n",
1017938fd1498Szrj 		     cselib_get_next_uid ());
1018038fd1498Szrj 	}
1018138fd1498Szrj 
1018238fd1498Szrj       first_bb = bb;
1018338fd1498Szrj       for (;;)
1018438fd1498Szrj 	{
1018538fd1498Szrj 	  edge e;
1018638fd1498Szrj 	  if (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
1018738fd1498Szrj 	      || ! single_pred_p (bb->next_bb))
1018838fd1498Szrj 	    break;
1018938fd1498Szrj 	  e = find_edge (bb, bb->next_bb);
1019038fd1498Szrj 	  if (! e || (e->flags & EDGE_FALLTHRU) == 0)
1019138fd1498Szrj 	    break;
1019238fd1498Szrj 	  bb = bb->next_bb;
1019338fd1498Szrj 	}
1019438fd1498Szrj       last_bb = bb;
1019538fd1498Szrj 
1019638fd1498Szrj       /* Add the micro-operations to the vector.  */
1019738fd1498Szrj       FOR_BB_BETWEEN (bb, first_bb, last_bb->next_bb, next_bb)
1019838fd1498Szrj 	{
1019938fd1498Szrj 	  HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
1020038fd1498Szrj 	  VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
1020138fd1498Szrj 
1020238fd1498Szrj 	  rtx_insn *next;
1020338fd1498Szrj 	  FOR_BB_INSNS_SAFE (bb, insn, next)
1020438fd1498Szrj 	    {
1020538fd1498Szrj 	      if (INSN_P (insn))
1020638fd1498Szrj 		{
1020738fd1498Szrj 		  if (!frame_pointer_needed)
1020838fd1498Szrj 		    {
1020938fd1498Szrj 		      insn_stack_adjust_offset_pre_post (insn, &pre, &post);
1021038fd1498Szrj 		      if (pre)
1021138fd1498Szrj 			{
1021238fd1498Szrj 			  micro_operation mo;
1021338fd1498Szrj 			  mo.type = MO_ADJUST;
1021438fd1498Szrj 			  mo.u.adjust = pre;
1021538fd1498Szrj 			  mo.insn = insn;
1021638fd1498Szrj 			  if (dump_file && (dump_flags & TDF_DETAILS))
1021738fd1498Szrj 			    log_op_type (PATTERN (insn), bb, insn,
1021838fd1498Szrj 					 MO_ADJUST, dump_file);
1021938fd1498Szrj 			  VTI (bb)->mos.safe_push (mo);
1022038fd1498Szrj 			  VTI (bb)->out.stack_adjust += pre;
1022138fd1498Szrj 			}
1022238fd1498Szrj 		    }
1022338fd1498Szrj 
1022438fd1498Szrj 		  cselib_hook_called = false;
1022538fd1498Szrj 		  adjust_insn (bb, insn);
1022638fd1498Szrj 		  if (DEBUG_MARKER_INSN_P (insn))
1022738fd1498Szrj 		    {
1022838fd1498Szrj 		      reemit_marker_as_note (insn);
1022938fd1498Szrj 		      continue;
1023038fd1498Szrj 		    }
1023138fd1498Szrj 
1023238fd1498Szrj 		  if (MAY_HAVE_DEBUG_BIND_INSNS)
1023338fd1498Szrj 		    {
1023438fd1498Szrj 		      if (CALL_P (insn))
1023538fd1498Szrj 			prepare_call_arguments (bb, insn);
1023638fd1498Szrj 		      cselib_process_insn (insn);
1023738fd1498Szrj 		      if (dump_file && (dump_flags & TDF_DETAILS))
1023838fd1498Szrj 			{
1023938fd1498Szrj 			  print_rtl_single (dump_file, insn);
1024038fd1498Szrj 			  dump_cselib_table (dump_file);
1024138fd1498Szrj 			}
1024238fd1498Szrj 		    }
1024338fd1498Szrj 		  if (!cselib_hook_called)
1024438fd1498Szrj 		    add_with_sets (insn, 0, 0);
1024538fd1498Szrj 		  cancel_changes (0);
1024638fd1498Szrj 
1024738fd1498Szrj 		  if (!frame_pointer_needed && post)
1024838fd1498Szrj 		    {
1024938fd1498Szrj 		      micro_operation mo;
1025038fd1498Szrj 		      mo.type = MO_ADJUST;
1025138fd1498Szrj 		      mo.u.adjust = post;
1025238fd1498Szrj 		      mo.insn = insn;
1025338fd1498Szrj 		      if (dump_file && (dump_flags & TDF_DETAILS))
1025438fd1498Szrj 			log_op_type (PATTERN (insn), bb, insn,
1025538fd1498Szrj 				     MO_ADJUST, dump_file);
1025638fd1498Szrj 		      VTI (bb)->mos.safe_push (mo);
1025738fd1498Szrj 		      VTI (bb)->out.stack_adjust += post;
1025838fd1498Szrj 		    }
1025938fd1498Szrj 
1026038fd1498Szrj 		  if (fp_cfa_offset != -1
1026138fd1498Szrj 		      && hard_frame_pointer_adjustment == -1
1026238fd1498Szrj 		      && fp_setter_insn (insn))
1026338fd1498Szrj 		    {
1026438fd1498Szrj 		      vt_init_cfa_base ();
1026538fd1498Szrj 		      hard_frame_pointer_adjustment = fp_cfa_offset;
1026638fd1498Szrj 		      /* Disassociate sp from fp now.  */
1026738fd1498Szrj 		      if (MAY_HAVE_DEBUG_BIND_INSNS)
1026838fd1498Szrj 			{
1026938fd1498Szrj 			  cselib_val *v;
1027038fd1498Szrj 			  cselib_invalidate_rtx (stack_pointer_rtx);
1027138fd1498Szrj 			  v = cselib_lookup (stack_pointer_rtx, Pmode, 1,
1027238fd1498Szrj 					     VOIDmode);
1027338fd1498Szrj 			  if (v && !cselib_preserved_value_p (v))
1027438fd1498Szrj 			    {
1027538fd1498Szrj 			      cselib_set_value_sp_based (v);
1027638fd1498Szrj 			      preserve_value (v);
1027738fd1498Szrj 			    }
1027838fd1498Szrj 			}
1027938fd1498Szrj 		    }
1028038fd1498Szrj 		}
1028138fd1498Szrj 	    }
1028238fd1498Szrj 	  gcc_assert (offset == VTI (bb)->out.stack_adjust);
1028338fd1498Szrj 	}
1028438fd1498Szrj 
1028538fd1498Szrj       bb = last_bb;
1028638fd1498Szrj 
1028738fd1498Szrj       if (MAY_HAVE_DEBUG_BIND_INSNS)
1028838fd1498Szrj 	{
1028938fd1498Szrj 	  cselib_preserve_only_values ();
1029038fd1498Szrj 	  cselib_reset_table (cselib_get_next_uid ());
1029138fd1498Szrj 	  cselib_record_sets_hook = NULL;
1029238fd1498Szrj 	}
1029338fd1498Szrj     }
1029438fd1498Szrj 
1029538fd1498Szrj   hard_frame_pointer_adjustment = -1;
1029638fd1498Szrj   VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->flooded = true;
1029738fd1498Szrj   cfa_base_rtx = NULL_RTX;
1029838fd1498Szrj   return true;
1029938fd1498Szrj }
1030038fd1498Szrj 
1030138fd1498Szrj /* This is *not* reset after each function.  It gives each
1030238fd1498Szrj    NOTE_INSN_DELETED_DEBUG_LABEL in the entire compilation
1030338fd1498Szrj    a unique label number.  */
1030438fd1498Szrj 
1030538fd1498Szrj static int debug_label_num = 1;
1030638fd1498Szrj 
1030738fd1498Szrj /* Remove from the insn stream a single debug insn used for
1030838fd1498Szrj    variable tracking at assignments.  */
1030938fd1498Szrj 
1031038fd1498Szrj static inline void
delete_vta_debug_insn(rtx_insn * insn)1031138fd1498Szrj delete_vta_debug_insn (rtx_insn *insn)
1031238fd1498Szrj {
1031338fd1498Szrj   if (DEBUG_MARKER_INSN_P (insn))
1031438fd1498Szrj     {
1031538fd1498Szrj       reemit_marker_as_note (insn);
1031638fd1498Szrj       return;
1031738fd1498Szrj     }
1031838fd1498Szrj 
1031938fd1498Szrj   tree decl = INSN_VAR_LOCATION_DECL (insn);
1032038fd1498Szrj   if (TREE_CODE (decl) == LABEL_DECL
1032138fd1498Szrj       && DECL_NAME (decl)
1032238fd1498Szrj       && !DECL_RTL_SET_P (decl))
1032338fd1498Szrj     {
1032438fd1498Szrj       PUT_CODE (insn, NOTE);
1032538fd1498Szrj       NOTE_KIND (insn) = NOTE_INSN_DELETED_DEBUG_LABEL;
1032638fd1498Szrj       NOTE_DELETED_LABEL_NAME (insn)
1032738fd1498Szrj 	= IDENTIFIER_POINTER (DECL_NAME (decl));
1032838fd1498Szrj       SET_DECL_RTL (decl, insn);
1032938fd1498Szrj       CODE_LABEL_NUMBER (insn) = debug_label_num++;
1033038fd1498Szrj     }
1033138fd1498Szrj   else
1033238fd1498Szrj     delete_insn (insn);
1033338fd1498Szrj }
1033438fd1498Szrj 
1033538fd1498Szrj /* Remove from the insn stream all debug insns used for variable
1033638fd1498Szrj    tracking at assignments.  USE_CFG should be false if the cfg is no
1033738fd1498Szrj    longer usable.  */
1033838fd1498Szrj 
1033938fd1498Szrj void
delete_vta_debug_insns(bool use_cfg)1034038fd1498Szrj delete_vta_debug_insns (bool use_cfg)
1034138fd1498Szrj {
1034238fd1498Szrj   basic_block bb;
1034338fd1498Szrj   rtx_insn *insn, *next;
1034438fd1498Szrj 
1034538fd1498Szrj   if (!MAY_HAVE_DEBUG_INSNS)
1034638fd1498Szrj     return;
1034738fd1498Szrj 
1034838fd1498Szrj   if (use_cfg)
1034938fd1498Szrj     FOR_EACH_BB_FN (bb, cfun)
1035038fd1498Szrj       {
1035138fd1498Szrj 	FOR_BB_INSNS_SAFE (bb, insn, next)
1035238fd1498Szrj 	  if (DEBUG_INSN_P (insn))
1035338fd1498Szrj 	    delete_vta_debug_insn (insn);
1035438fd1498Szrj       }
1035538fd1498Szrj   else
1035638fd1498Szrj     for (insn = get_insns (); insn; insn = next)
1035738fd1498Szrj       {
1035838fd1498Szrj 	next = NEXT_INSN (insn);
1035938fd1498Szrj 	if (DEBUG_INSN_P (insn))
1036038fd1498Szrj 	  delete_vta_debug_insn (insn);
1036138fd1498Szrj       }
1036238fd1498Szrj }
1036338fd1498Szrj 
1036438fd1498Szrj /* Run a fast, BB-local only version of var tracking, to take care of
1036538fd1498Szrj    information that we don't do global analysis on, such that not all
1036638fd1498Szrj    information is lost.  If SKIPPED holds, we're skipping the global
1036738fd1498Szrj    pass entirely, so we should try to use information it would have
1036838fd1498Szrj    handled as well..  */
1036938fd1498Szrj 
1037038fd1498Szrj static void
vt_debug_insns_local(bool skipped ATTRIBUTE_UNUSED)1037138fd1498Szrj vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
1037238fd1498Szrj {
1037338fd1498Szrj   /* ??? Just skip it all for now.  */
1037438fd1498Szrj   delete_vta_debug_insns (true);
1037538fd1498Szrj }
1037638fd1498Szrj 
1037738fd1498Szrj /* Free the data structures needed for variable tracking.  */
1037838fd1498Szrj 
1037938fd1498Szrj static void
vt_finalize(void)1038038fd1498Szrj vt_finalize (void)
1038138fd1498Szrj {
1038238fd1498Szrj   basic_block bb;
1038338fd1498Szrj 
1038438fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
1038538fd1498Szrj     {
1038638fd1498Szrj       VTI (bb)->mos.release ();
1038738fd1498Szrj     }
1038838fd1498Szrj 
1038938fd1498Szrj   FOR_ALL_BB_FN (bb, cfun)
1039038fd1498Szrj     {
1039138fd1498Szrj       dataflow_set_destroy (&VTI (bb)->in);
1039238fd1498Szrj       dataflow_set_destroy (&VTI (bb)->out);
1039338fd1498Szrj       if (VTI (bb)->permp)
1039438fd1498Szrj 	{
1039538fd1498Szrj 	  dataflow_set_destroy (VTI (bb)->permp);
1039638fd1498Szrj 	  XDELETE (VTI (bb)->permp);
1039738fd1498Szrj 	}
1039838fd1498Szrj     }
1039938fd1498Szrj   free_aux_for_blocks ();
1040038fd1498Szrj   delete empty_shared_hash->htab;
1040138fd1498Szrj   empty_shared_hash->htab = NULL;
1040238fd1498Szrj   delete changed_variables;
1040338fd1498Szrj   changed_variables = NULL;
1040438fd1498Szrj   attrs_pool.release ();
1040538fd1498Szrj   var_pool.release ();
1040638fd1498Szrj   location_chain_pool.release ();
1040738fd1498Szrj   shared_hash_pool.release ();
1040838fd1498Szrj 
1040938fd1498Szrj   if (MAY_HAVE_DEBUG_BIND_INSNS)
1041038fd1498Szrj     {
1041138fd1498Szrj       if (global_get_addr_cache)
1041238fd1498Szrj 	delete global_get_addr_cache;
1041338fd1498Szrj       global_get_addr_cache = NULL;
1041438fd1498Szrj       loc_exp_dep_pool.release ();
1041538fd1498Szrj       valvar_pool.release ();
1041638fd1498Szrj       preserved_values.release ();
1041738fd1498Szrj       cselib_finish ();
1041838fd1498Szrj       BITMAP_FREE (scratch_regs);
1041938fd1498Szrj       scratch_regs = NULL;
1042038fd1498Szrj     }
1042138fd1498Szrj 
1042238fd1498Szrj #ifdef HAVE_window_save
1042338fd1498Szrj   vec_free (windowed_parm_regs);
1042438fd1498Szrj #endif
1042538fd1498Szrj 
1042638fd1498Szrj   if (vui_vec)
1042738fd1498Szrj     XDELETEVEC (vui_vec);
1042838fd1498Szrj   vui_vec = NULL;
1042938fd1498Szrj   vui_allocated = 0;
1043038fd1498Szrj }
1043138fd1498Szrj 
1043238fd1498Szrj /* The entry point to variable tracking pass.  */
1043338fd1498Szrj 
1043438fd1498Szrj static inline unsigned int
variable_tracking_main_1(void)1043538fd1498Szrj variable_tracking_main_1 (void)
1043638fd1498Szrj {
1043738fd1498Szrj   bool success;
1043838fd1498Szrj 
1043938fd1498Szrj   /* We won't be called as a separate pass if flag_var_tracking is not
1044038fd1498Szrj      set, but final may call us to turn debug markers into notes.  */
1044138fd1498Szrj   if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
1044238fd1498Szrj       || flag_var_tracking_assignments < 0
1044338fd1498Szrj       /* Var-tracking right now assumes the IR doesn't contain
1044438fd1498Szrj 	 any pseudos at this point.  */
1044538fd1498Szrj       || targetm.no_register_allocation)
1044638fd1498Szrj     {
1044738fd1498Szrj       delete_vta_debug_insns (true);
1044838fd1498Szrj       return 0;
1044938fd1498Szrj     }
1045038fd1498Szrj 
1045138fd1498Szrj   if (!flag_var_tracking)
1045238fd1498Szrj     return 0;
1045338fd1498Szrj 
1045438fd1498Szrj   if (n_basic_blocks_for_fn (cfun) > 500
1045538fd1498Szrj       && n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
1045638fd1498Szrj     {
1045738fd1498Szrj       vt_debug_insns_local (true);
1045838fd1498Szrj       return 0;
1045938fd1498Szrj     }
1046038fd1498Szrj 
1046138fd1498Szrj   mark_dfs_back_edges ();
1046238fd1498Szrj   if (!vt_initialize ())
1046338fd1498Szrj     {
1046438fd1498Szrj       vt_finalize ();
1046538fd1498Szrj       vt_debug_insns_local (true);
1046638fd1498Szrj       return 0;
1046738fd1498Szrj     }
1046838fd1498Szrj 
1046938fd1498Szrj   success = vt_find_locations ();
1047038fd1498Szrj 
1047138fd1498Szrj   if (!success && flag_var_tracking_assignments > 0)
1047238fd1498Szrj     {
1047338fd1498Szrj       vt_finalize ();
1047438fd1498Szrj 
1047538fd1498Szrj       delete_vta_debug_insns (true);
1047638fd1498Szrj 
1047738fd1498Szrj       /* This is later restored by our caller.  */
1047838fd1498Szrj       flag_var_tracking_assignments = 0;
1047938fd1498Szrj 
1048038fd1498Szrj       success = vt_initialize ();
1048138fd1498Szrj       gcc_assert (success);
1048238fd1498Szrj 
1048338fd1498Szrj       success = vt_find_locations ();
1048438fd1498Szrj     }
1048538fd1498Szrj 
1048638fd1498Szrj   if (!success)
1048738fd1498Szrj     {
1048838fd1498Szrj       vt_finalize ();
1048938fd1498Szrj       vt_debug_insns_local (false);
1049038fd1498Szrj       return 0;
1049138fd1498Szrj     }
1049238fd1498Szrj 
1049338fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
1049438fd1498Szrj     {
1049538fd1498Szrj       dump_dataflow_sets ();
1049638fd1498Szrj       dump_reg_info (dump_file);
1049738fd1498Szrj       dump_flow_info (dump_file, dump_flags);
1049838fd1498Szrj     }
1049938fd1498Szrj 
1050038fd1498Szrj   timevar_push (TV_VAR_TRACKING_EMIT);
1050138fd1498Szrj   vt_emit_notes ();
1050238fd1498Szrj   timevar_pop (TV_VAR_TRACKING_EMIT);
1050338fd1498Szrj 
1050438fd1498Szrj   vt_finalize ();
1050538fd1498Szrj   vt_debug_insns_local (false);
1050638fd1498Szrj   return 0;
1050738fd1498Szrj }
1050838fd1498Szrj 
1050938fd1498Szrj unsigned int
variable_tracking_main(void)1051038fd1498Szrj variable_tracking_main (void)
1051138fd1498Szrj {
1051238fd1498Szrj   unsigned int ret;
1051338fd1498Szrj   int save = flag_var_tracking_assignments;
1051438fd1498Szrj 
1051538fd1498Szrj   ret = variable_tracking_main_1 ();
1051638fd1498Szrj 
1051738fd1498Szrj   flag_var_tracking_assignments = save;
1051838fd1498Szrj 
1051938fd1498Szrj   return ret;
1052038fd1498Szrj }
1052138fd1498Szrj 
1052238fd1498Szrj namespace {
1052338fd1498Szrj 
1052438fd1498Szrj const pass_data pass_data_variable_tracking =
1052538fd1498Szrj {
1052638fd1498Szrj   RTL_PASS, /* type */
1052738fd1498Szrj   "vartrack", /* name */
1052838fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
1052938fd1498Szrj   TV_VAR_TRACKING, /* tv_id */
1053038fd1498Szrj   0, /* properties_required */
1053138fd1498Szrj   0, /* properties_provided */
1053238fd1498Szrj   0, /* properties_destroyed */
1053338fd1498Szrj   0, /* todo_flags_start */
1053438fd1498Szrj   0, /* todo_flags_finish */
1053538fd1498Szrj };
1053638fd1498Szrj 
1053738fd1498Szrj class pass_variable_tracking : public rtl_opt_pass
1053838fd1498Szrj {
1053938fd1498Szrj public:
pass_variable_tracking(gcc::context * ctxt)1054038fd1498Szrj   pass_variable_tracking (gcc::context *ctxt)
1054138fd1498Szrj     : rtl_opt_pass (pass_data_variable_tracking, ctxt)
1054238fd1498Szrj   {}
1054338fd1498Szrj 
1054438fd1498Szrj   /* opt_pass methods: */
gate(function *)1054538fd1498Szrj   virtual bool gate (function *)
1054638fd1498Szrj     {
1054738fd1498Szrj       return (flag_var_tracking && !targetm.delay_vartrack);
1054838fd1498Szrj     }
1054938fd1498Szrj 
execute(function *)1055038fd1498Szrj   virtual unsigned int execute (function *)
1055138fd1498Szrj     {
1055238fd1498Szrj       return variable_tracking_main ();
1055338fd1498Szrj     }
1055438fd1498Szrj 
1055538fd1498Szrj }; // class pass_variable_tracking
1055638fd1498Szrj 
1055738fd1498Szrj } // anon namespace
1055838fd1498Szrj 
1055938fd1498Szrj rtl_opt_pass *
make_pass_variable_tracking(gcc::context * ctxt)1056038fd1498Szrj make_pass_variable_tracking (gcc::context *ctxt)
1056138fd1498Szrj {
1056238fd1498Szrj   return new pass_variable_tracking (ctxt);
1056338fd1498Szrj }
10564