]>
Commit | Line | Data |
---|---|---|
014a1138 | 1 | /* Variable tracking routines for the GNU compiler. |
5624e564 | 2 | Copyright (C) 2002-2015 Free Software Foundation, Inc. |
014a1138 JZ |
3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published by | |
9dcd6f09 | 8 | the Free Software Foundation; either version 3, or (at your option) |
014a1138 JZ |
9 | any later version. |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
14 | License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
014a1138 JZ |
19 | |
20 | /* This file contains the variable tracking pass. It computes where | |
21 | variables are located (which registers or where in memory) at each position | |
22 | in instruction stream and emits notes describing the locations. | |
23 | Debug information (DWARF2 location lists) is finally generated from | |
24 | these notes. | |
25 | With this debug information, it is possible to show variables | |
26 | even when debugging optimized code. | |
27 | ||
28 | How does the variable tracking pass work? | |
29 | ||
30 | First, it scans RTL code for uses, stores and clobbers (register/memory | |
31 | references in instructions), for call insns and for stack adjustments | |
32 | separately for each basic block and saves them to an array of micro | |
33 | operations. | |
34 | The micro operations of one instruction are ordered so that | |
35 | pre-modifying stack adjustment < use < use with no var < call insn < | |
12c5ffe5 | 36 | < clobber < set < post-modifying stack adjustment |
014a1138 JZ |
37 | |
38 | Then, a forward dataflow analysis is performed to find out how locations | |
39 | of variables change through code and to propagate the variable locations | |
40 | along control flow graph. | |
41 | The IN set for basic block BB is computed as a union of OUT sets of BB's | |
42 | predecessors, the OUT set for BB is copied from the IN set for BB and | |
43 | is changed according to micro operations in BB. | |
44 | ||
45 | The IN and OUT sets for basic blocks consist of a current stack adjustment | |
46 | (used for adjusting offset of variables addressed using stack pointer), | |
47 | the table of structures describing the locations of parts of a variable | |
48 | and for each physical register a linked list for each physical register. | |
49 | The linked list is a list of variable parts stored in the register, | |
50 | i.e. it is a list of triplets (reg, decl, offset) where decl is | |
51 | REG_EXPR (reg) and offset is REG_OFFSET (reg). The linked list is used for | |
52 | effective deleting appropriate variable parts when we set or clobber the | |
53 | register. | |
54 | ||
55 | There may be more than one variable part in a register. The linked lists | |
56 | should be pretty short so it is a good data structure here. | |
57 | For example in the following code, register allocator may assign same | |
58 | register to variables A and B, and both of them are stored in the same | |
59 | register in CODE: | |
60 | ||
61 | if (cond) | |
62 | set A; | |
63 | else | |
64 | set B; | |
65 | CODE; | |
66 | if (cond) | |
67 | use A; | |
68 | else | |
69 | use B; | |
70 | ||
71 | Finally, the NOTE_INSN_VAR_LOCATION notes describing the variable locations | |
72 | are emitted to appropriate positions in RTL code. Each such a note describes | |
73 | the location of one variable at the point in instruction stream where the | |
74 | note is. There is no need to emit a note for each variable before each | |
75 | instruction, we only emit these notes where the location of variable changes | |
76 | (this means that we also emit notes for changes between the OUT set of the | |
77 | previous block and the IN set of the current block). | |
78 | ||
79 | The notes consist of two parts: | |
80 | 1. the declaration (from REG_EXPR or MEM_EXPR) | |
81 | 2. the location of a variable - it is either a simple register/memory | |
82 | reference (for simple variables, for example int), | |
83 | or a parallel of register/memory references (for a large variables | |
84 | which consist of several parts, for example long long). | |
85 | ||
86 | */ | |
87 | ||
88 | #include "config.h" | |
89 | #include "system.h" | |
90 | #include "coretypes.h" | |
91 | #include "tm.h" | |
92 | #include "rtl.h" | |
40e23961 MC |
93 | #include "input.h" |
94 | #include "alias.h" | |
95 | #include "symtab.h" | |
014a1138 | 96 | #include "tree.h" |
d8a2d370 DN |
97 | #include "varasm.h" |
98 | #include "stor-layout.h" | |
60393bbc | 99 | #include "predict.h" |
60393bbc | 100 | #include "hard-reg-set.h" |
60393bbc AM |
101 | #include "function.h" |
102 | #include "dominance.h" | |
103 | #include "cfg.h" | |
104 | #include "cfgrtl.h" | |
105 | #include "cfganal.h" | |
2fb9a547 | 106 | #include "basic-block.h" |
f42865cb | 107 | #include "tm_p.h" |
014a1138 | 108 | #include "flags.h" |
014a1138 JZ |
109 | #include "insn-config.h" |
110 | #include "reload.h" | |
111 | #include "sbitmap.h" | |
112 | #include "alloc-pool.h" | |
c938250d | 113 | #include "regs.h" |
36566b39 PK |
114 | #include "expmed.h" |
115 | #include "dojump.h" | |
116 | #include "explow.h" | |
117 | #include "calls.h" | |
118 | #include "emit-rtl.h" | |
119 | #include "stmt.h" | |
c938250d | 120 | #include "expr.h" |
ef330312 | 121 | #include "tree-pass.h" |
442b4905 AM |
122 | #include "bitmap.h" |
123 | #include "tree-dfa.h" | |
7a300452 | 124 | #include "tree-ssa.h" |
b5b8b0ac AO |
125 | #include "cselib.h" |
126 | #include "target.h" | |
ec8c3978 | 127 | #include "params.h" |
6764d92c | 128 | #include "diagnostic.h" |
cf835838 | 129 | #include "tree-pretty-print.h" |
457eeaae | 130 | #include "recog.h" |
4f498863 | 131 | #include "rtl-iter.h" |
7b69b603 ML |
132 | #include "fibonacci_heap.h" |
133 | ||
134 | typedef fibonacci_heap <long, basic_block_def> bb_heap_t; | |
135 | typedef fibonacci_node <long, basic_block_def> bb_heap_node_t; | |
014a1138 | 136 | |
a85caf9e JJ |
137 | /* var-tracking.c assumes that tree code with the same value as VALUE rtx code |
138 | has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl. | |
139 | Currently the value is the same as IDENTIFIER_NODE, which has such | |
140 | a property. If this compile time assertion ever fails, make sure that | |
141 | the new tree code that equals (int) VALUE has the same property. */ | |
142 | extern char check_value_val[(int) VALUE == (int) IDENTIFIER_NODE ? 1 : -1]; | |
143 | ||
014a1138 JZ |
144 | /* Type of micro operation. */ |
145 | enum micro_operation_type | |
146 | { | |
147 | MO_USE, /* Use location (REG or MEM). */ | |
148 | MO_USE_NO_VAR,/* Use location which is not associated with a variable | |
149 | or the variable is not trackable. */ | |
b5b8b0ac AO |
150 | MO_VAL_USE, /* Use location which is associated with a value. */ |
151 | MO_VAL_LOC, /* Use location which appears in a debug insn. */ | |
152 | MO_VAL_SET, /* Set location associated with a value. */ | |
014a1138 | 153 | MO_SET, /* Set location. */ |
ca787200 | 154 | MO_COPY, /* Copy the same portion of a variable from one |
96ff6c8c | 155 | location to another. */ |
014a1138 JZ |
156 | MO_CLOBBER, /* Clobber location. */ |
157 | MO_CALL, /* Call insn. */ | |
9ac97460 | 158 | MO_ADJUST /* Adjust stack pointer. */ |
b5b8b0ac AO |
159 | |
160 | }; | |
161 | ||
162 | static const char * const ATTRIBUTE_UNUSED | |
163 | micro_operation_type_name[] = { | |
164 | "MO_USE", | |
165 | "MO_USE_NO_VAR", | |
166 | "MO_VAL_USE", | |
167 | "MO_VAL_LOC", | |
168 | "MO_VAL_SET", | |
169 | "MO_SET", | |
170 | "MO_COPY", | |
171 | "MO_CLOBBER", | |
172 | "MO_CALL", | |
173 | "MO_ADJUST" | |
014a1138 JZ |
174 | }; |
175 | ||
b5b8b0ac AO |
176 | /* Where shall the note be emitted? BEFORE or AFTER the instruction. |
177 | Notes emitted as AFTER_CALL are to take effect during the call, | |
178 | rather than after the call. */ | |
014a1138 JZ |
179 | enum emit_note_where |
180 | { | |
181 | EMIT_NOTE_BEFORE_INSN, | |
b5b8b0ac AO |
182 | EMIT_NOTE_AFTER_INSN, |
183 | EMIT_NOTE_AFTER_CALL_INSN | |
014a1138 JZ |
184 | }; |
185 | ||
186 | /* Structure holding information about micro operation. */ | |
187 | typedef struct micro_operation_def | |
188 | { | |
189 | /* Type of micro operation. */ | |
190 | enum micro_operation_type type; | |
191 | ||
0de3e43f JJ |
192 | /* The instruction which the micro operation is in, for MO_USE, |
193 | MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent | |
194 | instruction or note in the original flow (before any var-tracking | |
195 | notes are inserted, to simplify emission of notes), for MO_SET | |
196 | and MO_CLOBBER. */ | |
598d62da | 197 | rtx_insn *insn; |
0de3e43f | 198 | |
014a1138 | 199 | union { |
b5b8b0ac AO |
200 | /* Location. For MO_SET and MO_COPY, this is the SET that |
201 | performs the assignment, if known, otherwise it is the target | |
202 | of the assignment. For MO_VAL_USE and MO_VAL_SET, it is a | |
203 | CONCAT of the VALUE and the LOC associated with it. For | |
204 | MO_VAL_LOC, it is a CONCAT of the VALUE and the VAR_LOCATION | |
205 | associated with it. */ | |
014a1138 JZ |
206 | rtx loc; |
207 | ||
208 | /* Stack adjustment. */ | |
209 | HOST_WIDE_INT adjust; | |
210 | } u; | |
014a1138 JZ |
211 | } micro_operation; |
212 | ||
0de3e43f | 213 | |
b5b8b0ac AO |
214 | /* A declaration of a variable, or an RTL value being handled like a |
215 | declaration. */ | |
216 | typedef void *decl_or_value; | |
217 | ||
013e5ef9 LC |
218 | /* Return true if a decl_or_value DV is a DECL or NULL. */ |
219 | static inline bool | |
220 | dv_is_decl_p (decl_or_value dv) | |
014a1138 | 221 | { |
013e5ef9 LC |
222 | return !dv || (int) TREE_CODE ((tree) dv) != (int) VALUE; |
223 | } | |
014a1138 | 224 | |
013e5ef9 LC |
225 | /* Return true if a decl_or_value is a VALUE rtl. */ |
226 | static inline bool | |
227 | dv_is_value_p (decl_or_value dv) | |
228 | { | |
229 | return dv && !dv_is_decl_p (dv); | |
230 | } | |
231 | ||
232 | /* Return the decl in the decl_or_value. */ | |
233 | static inline tree | |
234 | dv_as_decl (decl_or_value dv) | |
235 | { | |
236 | gcc_checking_assert (dv_is_decl_p (dv)); | |
237 | return (tree) dv; | |
238 | } | |
239 | ||
240 | /* Return the value in the decl_or_value. */ | |
241 | static inline rtx | |
242 | dv_as_value (decl_or_value dv) | |
243 | { | |
244 | gcc_checking_assert (dv_is_value_p (dv)); | |
245 | return (rtx)dv; | |
246 | } | |
247 | ||
248 | /* Return the opaque pointer in the decl_or_value. */ | |
249 | static inline void * | |
250 | dv_as_opaque (decl_or_value dv) | |
251 | { | |
252 | return dv; | |
253 | } | |
b5b8b0ac | 254 | |
014a1138 JZ |
255 | |
256 | /* Description of location of a part of a variable. The content of a physical | |
257 | register is described by a chain of these structures. | |
258 | The chains are pretty short (usually 1 or 2 elements) and thus | |
259 | chain is the best data structure. */ | |
260 | typedef struct attrs_def | |
261 | { | |
262 | /* Pointer to next member of the list. */ | |
263 | struct attrs_def *next; | |
264 | ||
265 | /* The rtx of register. */ | |
266 | rtx loc; | |
267 | ||
268 | /* The declaration corresponding to LOC. */ | |
b5b8b0ac | 269 | decl_or_value dv; |
014a1138 JZ |
270 | |
271 | /* Offset from start of DECL. */ | |
272 | HOST_WIDE_INT offset; | |
7e46899d ML |
273 | |
274 | /* Pool allocation new operator. */ | |
275 | inline void *operator new (size_t) | |
276 | { | |
277 | return pool.allocate (); | |
278 | } | |
279 | ||
280 | /* Delete operator utilizing pool allocation. */ | |
281 | inline void operator delete (void *ptr) | |
282 | { | |
283 | pool.remove ((attrs_def *) ptr); | |
284 | } | |
285 | ||
286 | /* Memory allocation pool. */ | |
287 | static pool_allocator<attrs_def> pool; | |
014a1138 JZ |
288 | } *attrs; |
289 | ||
014a1138 JZ |
290 | /* Structure for chaining the locations. */ |
291 | typedef struct location_chain_def | |
292 | { | |
293 | /* Next element in the chain. */ | |
294 | struct location_chain_def *next; | |
295 | ||
b5b8b0ac | 296 | /* The location (REG, MEM or VALUE). */ |
014a1138 | 297 | rtx loc; |
62760ffd CT |
298 | |
299 | /* The "value" stored in this location. */ | |
300 | rtx set_src; | |
301 | ||
302 | /* Initialized? */ | |
303 | enum var_init_status init; | |
7e46899d ML |
304 | |
305 | /* Pool allocation new operator. */ | |
306 | inline void *operator new (size_t) | |
307 | { | |
308 | return pool.allocate (); | |
309 | } | |
310 | ||
311 | /* Delete operator utilizing pool allocation. */ | |
312 | inline void operator delete (void *ptr) | |
313 | { | |
314 | pool.remove ((location_chain_def *) ptr); | |
315 | } | |
316 | ||
317 | /* Memory allocation pool. */ | |
318 | static pool_allocator<location_chain_def> pool; | |
014a1138 JZ |
319 | } *location_chain; |
320 | ||
09dbcd96 AO |
321 | /* A vector of loc_exp_dep holds the active dependencies of a one-part |
322 | DV on VALUEs, i.e., the VALUEs expanded so as to form the current | |
323 | location of DV. Each entry is also part of VALUE' s linked-list of | |
324 | backlinks back to DV. */ | |
325 | typedef struct loc_exp_dep_s | |
326 | { | |
327 | /* The dependent DV. */ | |
328 | decl_or_value dv; | |
329 | /* The dependency VALUE or DECL_DEBUG. */ | |
330 | rtx value; | |
331 | /* The next entry in VALUE's backlinks list. */ | |
332 | struct loc_exp_dep_s *next; | |
333 | /* A pointer to the pointer to this entry (head or prev's next) in | |
334 | the doubly-linked list. */ | |
335 | struct loc_exp_dep_s **pprev; | |
7e46899d ML |
336 | |
337 | /* Pool allocation new operator. */ | |
338 | inline void *operator new (size_t) | |
339 | { | |
340 | return pool.allocate (); | |
341 | } | |
342 | ||
343 | /* Delete operator utilizing pool allocation. */ | |
344 | inline void operator delete (void *ptr) | |
345 | { | |
346 | pool.remove ((loc_exp_dep_s *) ptr); | |
347 | } | |
348 | ||
349 | /* Memory allocation pool. */ | |
350 | static pool_allocator<loc_exp_dep_s> pool; | |
09dbcd96 AO |
351 | } loc_exp_dep; |
352 | ||
09dbcd96 | 353 | |
6a184afa AO |
354 | /* This data structure holds information about the depth of a variable |
355 | expansion. */ | |
356 | typedef struct expand_depth_struct | |
357 | { | |
358 | /* This measures the complexity of the expanded expression. It | |
359 | grows by one for each level of expansion that adds more than one | |
360 | operand. */ | |
361 | int complexity; | |
362 | /* This counts the number of ENTRY_VALUE expressions in an | |
363 | expansion. We want to minimize their use. */ | |
364 | int entryvals; | |
365 | } expand_depth; | |
366 | ||
09dbcd96 AO |
367 | /* This data structure is allocated for one-part variables at the time |
368 | of emitting notes. */ | |
369 | struct onepart_aux | |
370 | { | |
371 | /* Doubly-linked list of dependent DVs. These are DVs whose cur_loc | |
372 | computation used the expansion of this variable, and that ought | |
373 | to be notified should this variable change. If the DV's cur_loc | |
374 | expanded to NULL, all components of the loc list are regarded as | |
375 | active, so that any changes in them give us a chance to get a | |
376 | location. Otherwise, only components of the loc that expanded to | |
377 | non-NULL are regarded as active dependencies. */ | |
378 | loc_exp_dep *backlinks; | |
379 | /* This holds the LOC that was expanded into cur_loc. We need only | |
380 | mark a one-part variable as changed if the FROM loc is removed, | |
381 | or if it has no known location and a loc is added, or if it gets | |
382 | a change notification from any of its active dependencies. */ | |
383 | rtx from; | |
384 | /* The depth of the cur_loc expression. */ | |
6a184afa | 385 | expand_depth depth; |
09dbcd96 | 386 | /* Dependencies actively used when expand FROM into cur_loc. */ |
9771b263 | 387 | vec<loc_exp_dep, va_heap, vl_embed> deps; |
09dbcd96 AO |
388 | }; |
389 | ||
014a1138 JZ |
390 | /* Structure describing one part of variable. */ |
391 | typedef struct variable_part_def | |
392 | { | |
393 | /* Chain of locations of the part. */ | |
394 | location_chain loc_chain; | |
395 | ||
396 | /* Location which was last emitted to location list. */ | |
397 | rtx cur_loc; | |
398 | ||
09dbcd96 AO |
399 | union variable_aux |
400 | { | |
401 | /* The offset in the variable, if !var->onepart. */ | |
402 | HOST_WIDE_INT offset; | |
403 | ||
404 | /* Pointer to auxiliary data, if var->onepart and emit_notes. */ | |
405 | struct onepart_aux *onepaux; | |
406 | } aux; | |
014a1138 JZ |
407 | } variable_part; |
408 | ||
409 | /* Maximum number of location parts. */ | |
410 | #define MAX_VAR_PARTS 16 | |
411 | ||
09dbcd96 AO |
412 | /* Enumeration type used to discriminate various types of one-part |
413 | variables. */ | |
414 | typedef enum onepart_enum | |
415 | { | |
416 | /* Not a one-part variable. */ | |
417 | NOT_ONEPART = 0, | |
418 | /* A one-part DECL that is not a DEBUG_EXPR_DECL. */ | |
419 | ONEPART_VDECL = 1, | |
420 | /* A DEBUG_EXPR_DECL. */ | |
421 | ONEPART_DEXPR = 2, | |
422 | /* A VALUE. */ | |
423 | ONEPART_VALUE = 3 | |
424 | } onepart_enum_t; | |
425 | ||
014a1138 JZ |
426 | /* Structure describing where the variable is located. */ |
427 | typedef struct variable_def | |
428 | { | |
b5b8b0ac AO |
429 | /* The declaration of the variable, or an RTL value being handled |
430 | like a declaration. */ | |
431 | decl_or_value dv; | |
014a1138 | 432 | |
81f2eadb JZ |
433 | /* Reference count. */ |
434 | int refcount; | |
435 | ||
014a1138 | 436 | /* Number of variable parts. */ |
864ddef7 JJ |
437 | char n_var_parts; |
438 | ||
09dbcd96 AO |
439 | /* What type of DV this is, according to enum onepart_enum. */ |
440 | ENUM_BITFIELD (onepart_enum) onepart : CHAR_BIT; | |
864ddef7 JJ |
441 | |
442 | /* True if this variable_def struct is currently in the | |
443 | changed_variables hash table. */ | |
444 | bool in_changed_variables; | |
014a1138 JZ |
445 | |
446 | /* The variable parts. */ | |
b5b8b0ac | 447 | variable_part var_part[1]; |
014a1138 | 448 | } *variable; |
741ac903 | 449 | typedef const struct variable_def *const_variable; |
014a1138 | 450 | |
014a1138 JZ |
451 | /* Pointer to the BB's information specific to variable tracking pass. */ |
452 | #define VTI(BB) ((variable_tracking_info) (BB)->aux) | |
453 | ||
8c6c36a3 | 454 | /* Macro to access MEM_OFFSET as an HOST_WIDE_INT. Evaluates MEM twice. */ |
527210c4 | 455 | #define INT_MEM_OFFSET(mem) (MEM_OFFSET_KNOWN_P (mem) ? MEM_OFFSET (mem) : 0) |
8c6c36a3 | 456 | |
09dbcd96 AO |
457 | #if ENABLE_CHECKING && (GCC_VERSION >= 2007) |
458 | ||
459 | /* Access VAR's Ith part's offset, checking that it's not a one-part | |
460 | variable. */ | |
461 | #define VAR_PART_OFFSET(var, i) __extension__ \ | |
462 | (*({ variable const __v = (var); \ | |
463 | gcc_checking_assert (!__v->onepart); \ | |
464 | &__v->var_part[(i)].aux.offset; })) | |
465 | ||
466 | /* Access VAR's one-part auxiliary data, checking that it is a | |
467 | one-part variable. */ | |
468 | #define VAR_LOC_1PAUX(var) __extension__ \ | |
469 | (*({ variable const __v = (var); \ | |
470 | gcc_checking_assert (__v->onepart); \ | |
471 | &__v->var_part[0].aux.onepaux; })) | |
472 | ||
473 | #else | |
474 | #define VAR_PART_OFFSET(var, i) ((var)->var_part[(i)].aux.offset) | |
475 | #define VAR_LOC_1PAUX(var) ((var)->var_part[0].aux.onepaux) | |
476 | #endif | |
477 | ||
478 | /* These are accessor macros for the one-part auxiliary data. When | |
479 | convenient for users, they're guarded by tests that the data was | |
480 | allocated. */ | |
481 | #define VAR_LOC_DEP_LST(var) (VAR_LOC_1PAUX (var) \ | |
482 | ? VAR_LOC_1PAUX (var)->backlinks \ | |
483 | : NULL) | |
484 | #define VAR_LOC_DEP_LSTP(var) (VAR_LOC_1PAUX (var) \ | |
485 | ? &VAR_LOC_1PAUX (var)->backlinks \ | |
486 | : NULL) | |
487 | #define VAR_LOC_FROM(var) (VAR_LOC_1PAUX (var)->from) | |
488 | #define VAR_LOC_DEPTH(var) (VAR_LOC_1PAUX (var)->depth) | |
489 | #define VAR_LOC_DEP_VEC(var) (VAR_LOC_1PAUX (var) \ | |
490 | ? &VAR_LOC_1PAUX (var)->deps \ | |
491 | : NULL) | |
492 | ||
013e5ef9 LC |
493 | |
494 | ||
495 | typedef unsigned int dvuid; | |
496 | ||
497 | /* Return the uid of DV. */ | |
498 | ||
499 | static inline dvuid | |
500 | dv_uid (decl_or_value dv) | |
501 | { | |
502 | if (dv_is_value_p (dv)) | |
503 | return CSELIB_VAL_PTR (dv_as_value (dv))->uid; | |
504 | else | |
505 | return DECL_UID (dv_as_decl (dv)); | |
506 | } | |
507 | ||
508 | /* Compute the hash from the uid. */ | |
509 | ||
510 | static inline hashval_t | |
511 | dv_uid2hash (dvuid uid) | |
512 | { | |
513 | return uid; | |
514 | } | |
515 | ||
516 | /* The hash function for a mask table in a shared_htab chain. */ | |
517 | ||
518 | static inline hashval_t | |
519 | dv_htab_hash (decl_or_value dv) | |
520 | { | |
521 | return dv_uid2hash (dv_uid (dv)); | |
522 | } | |
523 | ||
524 | static void variable_htab_free (void *); | |
525 | ||
526 | /* Variable hashtable helpers. */ | |
527 | ||
528 | struct variable_hasher | |
529 | { | |
67f58944 TS |
530 | typedef variable_def *value_type; |
531 | typedef void *compare_type; | |
532 | static inline hashval_t hash (const variable_def *); | |
533 | static inline bool equal (const variable_def *, const void *); | |
534 | static inline void remove (variable_def *); | |
013e5ef9 LC |
535 | }; |
536 | ||
537 | /* The hash function for variable_htab, computes the hash value | |
538 | from the declaration of variable X. */ | |
539 | ||
540 | inline hashval_t | |
67f58944 | 541 | variable_hasher::hash (const variable_def *v) |
013e5ef9 LC |
542 | { |
543 | return dv_htab_hash (v->dv); | |
544 | } | |
545 | ||
546 | /* Compare the declaration of variable X with declaration Y. */ | |
547 | ||
548 | inline bool | |
67f58944 | 549 | variable_hasher::equal (const variable_def *v, const void *y) |
013e5ef9 LC |
550 | { |
551 | decl_or_value dv = CONST_CAST2 (decl_or_value, const void *, y); | |
552 | ||
553 | return (dv_as_opaque (v->dv) == dv_as_opaque (dv)); | |
554 | } | |
555 | ||
556 | /* Free the element of VARIABLE_HTAB (its type is struct variable_def). */ | |
557 | ||
558 | inline void | |
67f58944 | 559 | variable_hasher::remove (variable_def *var) |
013e5ef9 LC |
560 | { |
561 | variable_htab_free (var); | |
562 | } | |
563 | ||
c203e8a7 | 564 | typedef hash_table<variable_hasher> variable_table_type; |
013e5ef9 LC |
565 | typedef variable_table_type::iterator variable_iterator_type; |
566 | ||
567 | /* Structure for passing some other parameters to function | |
568 | emit_note_insn_var_location. */ | |
569 | typedef struct emit_note_data_def | |
570 | { | |
571 | /* The instruction which the note will be emitted before/after. */ | |
598d62da | 572 | rtx_insn *insn; |
013e5ef9 LC |
573 | |
574 | /* Where the note will be emitted (before/after insn)? */ | |
575 | enum emit_note_where where; | |
576 | ||
577 | /* The variables and values active at this point. */ | |
c203e8a7 | 578 | variable_table_type *vars; |
013e5ef9 LC |
579 | } emit_note_data; |
580 | ||
581 | /* Structure holding a refcounted hash table. If refcount > 1, | |
582 | it must be first unshared before modified. */ | |
583 | typedef struct shared_hash_def | |
584 | { | |
585 | /* Reference count. */ | |
586 | int refcount; | |
587 | ||
588 | /* Actual hash table. */ | |
c203e8a7 | 589 | variable_table_type *htab; |
7e46899d ML |
590 | |
591 | /* Pool allocation new operator. */ | |
592 | inline void *operator new (size_t) | |
593 | { | |
594 | return pool.allocate (); | |
595 | } | |
596 | ||
597 | /* Delete operator utilizing pool allocation. */ | |
598 | inline void operator delete (void *ptr) | |
599 | { | |
600 | pool.remove ((shared_hash_def *) ptr); | |
601 | } | |
602 | ||
603 | /* Memory allocation pool. */ | |
604 | static pool_allocator<shared_hash_def> pool; | |
013e5ef9 LC |
605 | } *shared_hash; |
606 | ||
607 | /* Structure holding the IN or OUT set for a basic block. */ | |
608 | typedef struct dataflow_set_def | |
609 | { | |
610 | /* Adjustment of stack offset. */ | |
611 | HOST_WIDE_INT stack_adjust; | |
612 | ||
613 | /* Attributes for registers (lists of attrs). */ | |
614 | attrs regs[FIRST_PSEUDO_REGISTER]; | |
615 | ||
616 | /* Variable locations. */ | |
617 | shared_hash vars; | |
618 | ||
619 | /* Vars that is being traversed. */ | |
620 | shared_hash traversed_vars; | |
621 | } dataflow_set; | |
622 | ||
623 | /* The structure (one for each basic block) containing the information | |
624 | needed for variable tracking. */ | |
625 | typedef struct variable_tracking_info_def | |
626 | { | |
627 | /* The vector of micro operations. */ | |
628 | vec<micro_operation> mos; | |
629 | ||
630 | /* The IN and OUT set for dataflow analysis. */ | |
631 | dataflow_set in; | |
632 | dataflow_set out; | |
633 | ||
634 | /* The permanent-in dataflow set for this block. This is used to | |
635 | hold values for which we had to compute entry values. ??? This | |
636 | should probably be dynamically allocated, to avoid using more | |
637 | memory in non-debug builds. */ | |
638 | dataflow_set *permp; | |
639 | ||
640 | /* Has the block been visited in DFS? */ | |
641 | bool visited; | |
642 | ||
643 | /* Has the block been flooded in VTA? */ | |
644 | bool flooded; | |
645 | ||
646 | } *variable_tracking_info; | |
647 | ||
014a1138 | 648 | /* Alloc pool for struct attrs_def. */ |
7e46899d | 649 | pool_allocator<attrs_def> attrs_def::pool ("attrs_def pool", 1024); |
014a1138 | 650 | |
b5b8b0ac | 651 | /* Alloc pool for struct variable_def with MAX_VAR_PARTS entries. */ |
7e46899d ML |
652 | |
653 | static pool_allocator<variable_def> var_pool | |
654 | ("variable_def pool", 64, | |
655 | (MAX_VAR_PARTS - 1) * sizeof (((variable)NULL)->var_part[0])); | |
014a1138 | 656 | |
b5b8b0ac | 657 | /* Alloc pool for struct variable_def with a single var_part entry. */ |
7e46899d ML |
658 | static pool_allocator<variable_def> valvar_pool |
659 | ("small variable_def pool", 256); | |
b5b8b0ac | 660 | |
014a1138 | 661 | /* Alloc pool for struct location_chain_def. */ |
7e46899d ML |
662 | pool_allocator<location_chain_def> location_chain_def::pool |
663 | ("location_chain_def pool", 1024); | |
014a1138 | 664 | |
d24686d7 | 665 | /* Alloc pool for struct shared_hash_def. */ |
7e46899d ML |
666 | pool_allocator<shared_hash_def> shared_hash_def::pool |
667 | ("shared_hash_def pool", 256); | |
d24686d7 | 668 | |
d05cae4a | 669 | /* Alloc pool for struct loc_exp_dep_s for NOT_ONEPART variables. */ |
7e46899d | 670 | pool_allocator<loc_exp_dep> loc_exp_dep::pool ("loc_exp_dep pool", 64); |
d05cae4a | 671 | |
014a1138 | 672 | /* Changed variables, notes will be emitted for them. */ |
c203e8a7 | 673 | static variable_table_type *changed_variables; |
014a1138 JZ |
674 | |
675 | /* Shall notes be emitted? */ | |
676 | static bool emit_notes; | |
677 | ||
09dbcd96 AO |
678 | /* Values whose dynamic location lists have gone empty, but whose |
679 | cselib location lists are still usable. Use this to hold the | |
680 | current location, the backlinks, etc, during emit_notes. */ | |
c203e8a7 | 681 | static variable_table_type *dropped_values; |
09dbcd96 | 682 | |
d24686d7 JJ |
683 | /* Empty shared hashtable. */ |
684 | static shared_hash empty_shared_hash; | |
685 | ||
b5b8b0ac AO |
686 | /* Scratch register bitmap used by cselib_expand_value_rtx. */ |
687 | static bitmap scratch_regs = NULL; | |
688 | ||
09dbcd96 | 689 | #ifdef HAVE_window_save |
12c5ffe5 EB |
690 | typedef struct GTY(()) parm_reg { |
691 | rtx outgoing; | |
692 | rtx incoming; | |
693 | } parm_reg_t; | |
694 | ||
12c5ffe5 EB |
695 | |
696 | /* Vector of windowed parameter registers, if any. */ | |
9771b263 | 697 | static vec<parm_reg_t, va_gc> *windowed_parm_regs = NULL; |
09dbcd96 | 698 | #endif |
12c5ffe5 | 699 | |
b5b8b0ac AO |
700 | /* Variable used to tell whether cselib_process_insn called our hook. */ |
701 | static bool cselib_hook_called; | |
702 | ||
014a1138 JZ |
703 | /* Local function prototypes. */ |
704 | static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *, | |
705 | HOST_WIDE_INT *); | |
598d62da | 706 | static void insn_stack_adjust_offset_pre_post (rtx_insn *, HOST_WIDE_INT *, |
014a1138 | 707 | HOST_WIDE_INT *); |
014a1138 | 708 | static bool vt_stack_adjustments (void); |
014a1138 JZ |
709 | |
710 | static void init_attrs_list_set (attrs *); | |
711 | static void attrs_list_clear (attrs *); | |
b5b8b0ac AO |
712 | static attrs attrs_list_member (attrs, decl_or_value, HOST_WIDE_INT); |
713 | static void attrs_list_insert (attrs *, decl_or_value, HOST_WIDE_INT, rtx); | |
014a1138 JZ |
714 | static void attrs_list_copy (attrs *, attrs); |
715 | static void attrs_list_union (attrs *, attrs); | |
716 | ||
013e5ef9 LC |
717 | static variable_def **unshare_variable (dataflow_set *set, variable_def **slot, |
718 | variable var, enum var_init_status); | |
c203e8a7 | 719 | static void vars_copy (variable_table_type *, variable_table_type *); |
ca787200 | 720 | static tree var_debug_decl (tree); |
62760ffd | 721 | static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx); |
b8698a0f | 722 | static void var_reg_delete_and_set (dataflow_set *, rtx, bool, |
62760ffd | 723 | enum var_init_status, rtx); |
ca787200 | 724 | static void var_reg_delete (dataflow_set *, rtx, bool); |
014a1138 | 725 | static void var_regno_delete (dataflow_set *, int); |
62760ffd | 726 | static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx); |
b8698a0f | 727 | static void var_mem_delete_and_set (dataflow_set *, rtx, bool, |
62760ffd | 728 | enum var_init_status, rtx); |
ca787200 | 729 | static void var_mem_delete (dataflow_set *, rtx, bool); |
014a1138 | 730 | |
d24686d7 | 731 | static void dataflow_set_init (dataflow_set *); |
014a1138 JZ |
732 | static void dataflow_set_clear (dataflow_set *); |
733 | static void dataflow_set_copy (dataflow_set *, dataflow_set *); | |
734 | static int variable_union_info_cmp_pos (const void *, const void *); | |
014a1138 | 735 | static void dataflow_set_union (dataflow_set *, dataflow_set *); |
c203e8a7 | 736 | static location_chain find_loc_in_1pdv (rtx, variable, variable_table_type *); |
b5b8b0ac AO |
737 | static bool canon_value_cmp (rtx, rtx); |
738 | static int loc_cmp (rtx, rtx); | |
014a1138 | 739 | static bool variable_part_different_p (variable_part *, variable_part *); |
b5b8b0ac | 740 | static bool onepart_variable_different_p (variable, variable); |
864ddef7 | 741 | static bool variable_different_p (variable, variable); |
014a1138 JZ |
742 | static bool dataflow_set_different (dataflow_set *, dataflow_set *); |
743 | static void dataflow_set_destroy (dataflow_set *); | |
744 | ||
745 | static bool contains_symbol_ref (rtx); | |
b5b8b0ac | 746 | static bool track_expr_p (tree, bool); |
ca787200 | 747 | static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT); |
014a1138 | 748 | static void add_uses_1 (rtx *, void *); |
7bc980e1 | 749 | static void add_stores (rtx, const_rtx, void *); |
014a1138 | 750 | static bool compute_bb_dataflow (basic_block); |
ec8c3978 | 751 | static bool vt_find_locations (void); |
014a1138 JZ |
752 | |
753 | static void dump_attrs_list (attrs); | |
4a4d4c08 | 754 | static void dump_var (variable); |
c203e8a7 | 755 | static void dump_vars (variable_table_type *); |
014a1138 JZ |
756 | static void dump_dataflow_set (dataflow_set *); |
757 | static void dump_dataflow_sets (void); | |
758 | ||
09dbcd96 | 759 | static void set_dv_changed (decl_or_value, bool); |
d24686d7 | 760 | static void variable_was_changed (variable, dataflow_set *); |
013e5ef9 LC |
761 | static variable_def **set_slot_part (dataflow_set *, rtx, variable_def **, |
762 | decl_or_value, HOST_WIDE_INT, | |
763 | enum var_init_status, rtx); | |
b5b8b0ac AO |
764 | static void set_variable_part (dataflow_set *, rtx, |
765 | decl_or_value, HOST_WIDE_INT, | |
766 | enum var_init_status, rtx, enum insert_option); | |
013e5ef9 LC |
767 | static variable_def **clobber_slot_part (dataflow_set *, rtx, |
768 | variable_def **, HOST_WIDE_INT, rtx); | |
b5b8b0ac AO |
769 | static void clobber_variable_part (dataflow_set *, rtx, |
770 | decl_or_value, HOST_WIDE_INT, rtx); | |
013e5ef9 LC |
771 | static variable_def **delete_slot_part (dataflow_set *, rtx, variable_def **, |
772 | HOST_WIDE_INT); | |
b5b8b0ac AO |
773 | static void delete_variable_part (dataflow_set *, rtx, |
774 | decl_or_value, HOST_WIDE_INT); | |
b5b8b0ac | 775 | static void emit_notes_in_bb (basic_block, dataflow_set *); |
014a1138 JZ |
776 | static void vt_emit_notes (void); |
777 | ||
778 | static bool vt_get_decl_and_offset (rtx, tree *, HOST_WIDE_INT *); | |
779 | static void vt_add_function_parameters (void); | |
457eeaae | 780 | static bool vt_initialize (void); |
014a1138 JZ |
781 | static void vt_finalize (void); |
782 | ||
41b9329e JJ |
783 | /* Callback for stack_adjust_offset_pre_post, called via for_each_inc_dec. */ |
784 | ||
785 | static int | |
786 | stack_adjust_offset_pre_post_cb (rtx, rtx op, rtx dest, rtx src, rtx srcoff, | |
787 | void *arg) | |
788 | { | |
789 | if (dest != stack_pointer_rtx) | |
790 | return 0; | |
791 | ||
792 | switch (GET_CODE (op)) | |
793 | { | |
794 | case PRE_INC: | |
795 | case PRE_DEC: | |
796 | ((HOST_WIDE_INT *)arg)[0] -= INTVAL (srcoff); | |
797 | return 0; | |
798 | case POST_INC: | |
799 | case POST_DEC: | |
800 | ((HOST_WIDE_INT *)arg)[1] -= INTVAL (srcoff); | |
801 | return 0; | |
802 | case PRE_MODIFY: | |
803 | case POST_MODIFY: | |
804 | /* We handle only adjustments by constant amount. */ | |
805 | gcc_assert (GET_CODE (src) == PLUS | |
806 | && CONST_INT_P (XEXP (src, 1)) | |
807 | && XEXP (src, 0) == stack_pointer_rtx); | |
808 | ((HOST_WIDE_INT *)arg)[GET_CODE (op) == POST_MODIFY] | |
809 | -= INTVAL (XEXP (src, 1)); | |
810 | return 0; | |
811 | default: | |
812 | gcc_unreachable (); | |
813 | } | |
814 | } | |
815 | ||
014a1138 JZ |
816 | /* Given a SET, calculate the amount of stack adjustment it contains |
817 | PRE- and POST-modifying stack pointer. | |
818 | This function is similar to stack_adjust_offset. */ | |
819 | ||
820 | static void | |
821 | stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INT *pre, | |
822 | HOST_WIDE_INT *post) | |
823 | { | |
824 | rtx src = SET_SRC (pattern); | |
825 | rtx dest = SET_DEST (pattern); | |
826 | enum rtx_code code; | |
827 | ||
828 | if (dest == stack_pointer_rtx) | |
829 | { | |
830 | /* (set (reg sp) (plus (reg sp) (const_int))) */ | |
831 | code = GET_CODE (src); | |
832 | if (! (code == PLUS || code == MINUS) | |
833 | || XEXP (src, 0) != stack_pointer_rtx | |
481683e1 | 834 | || !CONST_INT_P (XEXP (src, 1))) |
014a1138 JZ |
835 | return; |
836 | ||
837 | if (code == MINUS) | |
838 | *post += INTVAL (XEXP (src, 1)); | |
839 | else | |
840 | *post -= INTVAL (XEXP (src, 1)); | |
7e46899d | 841 | return; |
014a1138 | 842 | } |
41b9329e JJ |
843 | HOST_WIDE_INT res[2] = { 0, 0 }; |
844 | for_each_inc_dec (pattern, stack_adjust_offset_pre_post_cb, res); | |
845 | *pre += res[0]; | |
846 | *post += res[1]; | |
014a1138 JZ |
847 | } |
848 | ||
849 | /* Given an INSN, calculate the amount of stack adjustment it contains | |
850 | PRE- and POST-modifying stack pointer. */ | |
851 | ||
852 | static void | |
598d62da | 853 | insn_stack_adjust_offset_pre_post (rtx_insn *insn, HOST_WIDE_INT *pre, |
014a1138 JZ |
854 | HOST_WIDE_INT *post) |
855 | { | |
7d407433 BW |
856 | rtx pattern; |
857 | ||
014a1138 JZ |
858 | *pre = 0; |
859 | *post = 0; | |
860 | ||
7d407433 BW |
861 | pattern = PATTERN (insn); |
862 | if (RTX_FRAME_RELATED_P (insn)) | |
863 | { | |
864 | rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); | |
865 | if (expr) | |
866 | pattern = XEXP (expr, 0); | |
867 | } | |
868 | ||
869 | if (GET_CODE (pattern) == SET) | |
870 | stack_adjust_offset_pre_post (pattern, pre, post); | |
871 | else if (GET_CODE (pattern) == PARALLEL | |
872 | || GET_CODE (pattern) == SEQUENCE) | |
014a1138 JZ |
873 | { |
874 | int i; | |
875 | ||
876 | /* There may be stack adjustments inside compound insns. Search | |
877 | for them. */ | |
7d407433 BW |
878 | for ( i = XVECLEN (pattern, 0) - 1; i >= 0; i--) |
879 | if (GET_CODE (XVECEXP (pattern, 0, i)) == SET) | |
880 | stack_adjust_offset_pre_post (XVECEXP (pattern, 0, i), pre, post); | |
014a1138 JZ |
881 | } |
882 | } | |
883 | ||
014a1138 JZ |
884 | /* Compute stack adjustments for all blocks by traversing DFS tree. |
885 | Return true when the adjustments on all incoming edges are consistent. | |
f91a0beb | 886 | Heavily borrowed from pre_and_rev_post_order_compute. */ |
014a1138 JZ |
887 | |
888 | static bool | |
889 | vt_stack_adjustments (void) | |
890 | { | |
628f6a4e | 891 | edge_iterator *stack; |
014a1138 JZ |
892 | int sp; |
893 | ||
fb0840fc | 894 | /* Initialize entry block. */ |
fefa31b5 | 895 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->visited = true; |
41b9329e JJ |
896 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->in.stack_adjust |
897 | = INCOMING_FRAME_SP_OFFSET; | |
898 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out.stack_adjust | |
899 | = INCOMING_FRAME_SP_OFFSET; | |
014a1138 JZ |
900 | |
901 | /* Allocate stack for back-tracking up CFG. */ | |
0cae8d31 | 902 | stack = XNEWVEC (edge_iterator, n_basic_blocks_for_fn (cfun) + 1); |
014a1138 JZ |
903 | sp = 0; |
904 | ||
905 | /* Push the first edge on to the stack. */ | |
fefa31b5 | 906 | stack[sp++] = ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs); |
014a1138 JZ |
907 | |
908 | while (sp) | |
909 | { | |
628f6a4e | 910 | edge_iterator ei; |
014a1138 JZ |
911 | basic_block src; |
912 | basic_block dest; | |
913 | ||
914 | /* Look at the edge on the top of the stack. */ | |
628f6a4e BE |
915 | ei = stack[sp - 1]; |
916 | src = ei_edge (ei)->src; | |
917 | dest = ei_edge (ei)->dest; | |
014a1138 JZ |
918 | |
919 | /* Check if the edge destination has been visited yet. */ | |
920 | if (!VTI (dest)->visited) | |
921 | { | |
598d62da | 922 | rtx_insn *insn; |
457eeaae | 923 | HOST_WIDE_INT pre, post, offset; |
014a1138 | 924 | VTI (dest)->visited = true; |
457eeaae JJ |
925 | VTI (dest)->in.stack_adjust = offset = VTI (src)->out.stack_adjust; |
926 | ||
fefa31b5 | 927 | if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)) |
457eeaae JJ |
928 | for (insn = BB_HEAD (dest); |
929 | insn != NEXT_INSN (BB_END (dest)); | |
930 | insn = NEXT_INSN (insn)) | |
09dbcd96 AO |
931 | if (INSN_P (insn)) |
932 | { | |
933 | insn_stack_adjust_offset_pre_post (insn, &pre, &post); | |
934 | offset += pre + post; | |
935 | } | |
457eeaae JJ |
936 | |
937 | VTI (dest)->out.stack_adjust = offset; | |
014a1138 | 938 | |
628f6a4e | 939 | if (EDGE_COUNT (dest->succs) > 0) |
014a1138 JZ |
940 | /* Since the DEST node has been visited for the first |
941 | time, check its successors. */ | |
628f6a4e | 942 | stack[sp++] = ei_start (dest->succs); |
014a1138 JZ |
943 | } |
944 | else | |
945 | { | |
3489cc33 RS |
946 | /* We can end up with different stack adjustments for the exit block |
947 | of a shrink-wrapped function if stack_adjust_offset_pre_post | |
948 | doesn't understand the rtx pattern used to restore the stack | |
949 | pointer in the epilogue. For example, on s390(x), the stack | |
950 | pointer is often restored via a load-multiple instruction | |
951 | and so no stack_adjust offset is recorded for it. This means | |
952 | that the stack offset at the end of the epilogue block is the | |
953 | the same as the offset before the epilogue, whereas other paths | |
954 | to the exit block will have the correct stack_adjust. | |
955 | ||
956 | It is safe to ignore these differences because (a) we never | |
957 | use the stack_adjust for the exit block in this pass and | |
958 | (b) dwarf2cfi checks whether the CFA notes in a shrink-wrapped | |
959 | function are correct. | |
960 | ||
961 | We must check whether the adjustments on other edges are | |
962 | the same though. */ | |
963 | if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun) | |
964 | && VTI (dest)->in.stack_adjust != VTI (src)->out.stack_adjust) | |
014a1138 JZ |
965 | { |
966 | free (stack); | |
967 | return false; | |
968 | } | |
969 | ||
628f6a4e | 970 | if (! ei_one_before_end_p (ei)) |
014a1138 | 971 | /* Go to the next edge. */ |
628f6a4e | 972 | ei_next (&stack[sp - 1]); |
014a1138 JZ |
973 | else |
974 | /* Return to previous level if there are no more edges. */ | |
975 | sp--; | |
976 | } | |
977 | } | |
978 | ||
979 | free (stack); | |
980 | return true; | |
981 | } | |
982 | ||
cfd8c4b1 JJ |
983 | /* arg_pointer_rtx resp. frame_pointer_rtx if stack_pointer_rtx or |
984 | hard_frame_pointer_rtx is being mapped to it and offset for it. */ | |
985 | static rtx cfa_base_rtx; | |
986 | static HOST_WIDE_INT cfa_base_offset; | |
987 | ||
65773087 EB |
988 | /* Compute a CFA-based value for an ADJUSTMENT made to stack_pointer_rtx |
989 | or hard_frame_pointer_rtx. */ | |
014a1138 | 990 | |
cfd8c4b1 | 991 | static inline rtx |
457eeaae | 992 | compute_cfa_pointer (HOST_WIDE_INT adjustment) |
014a1138 | 993 | { |
0a81f074 | 994 | return plus_constant (Pmode, cfa_base_rtx, adjustment + cfa_base_offset); |
457eeaae JJ |
995 | } |
996 | ||
997 | /* Adjustment for hard_frame_pointer_rtx to cfa base reg, | |
998 | or -1 if the replacement shouldn't be done. */ | |
999 | static HOST_WIDE_INT hard_frame_pointer_adjustment = -1; | |
1000 | ||
1001 | /* Data for adjust_mems callback. */ | |
1002 | ||
1003 | struct adjust_mem_data | |
1004 | { | |
1005 | bool store; | |
ef4bddc2 | 1006 | machine_mode mem_mode; |
457eeaae | 1007 | HOST_WIDE_INT stack_adjust; |
2f33ff0a | 1008 | rtx_expr_list *side_effects; |
457eeaae JJ |
1009 | }; |
1010 | ||
b328e730 RS |
1011 | /* Helper for adjust_mems. Return true if X is suitable for |
1012 | transformation of wider mode arithmetics to narrower mode. */ | |
e9e00885 | 1013 | |
b328e730 RS |
1014 | static bool |
1015 | use_narrower_mode_test (rtx x, const_rtx subreg) | |
1016 | { | |
1017 | subrtx_var_iterator::array_type array; | |
1018 | FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST) | |
e9e00885 | 1019 | { |
b328e730 RS |
1020 | rtx x = *iter; |
1021 | if (CONSTANT_P (x)) | |
1022 | iter.skip_subrtxes (); | |
e9e00885 | 1023 | else |
b328e730 RS |
1024 | switch (GET_CODE (x)) |
1025 | { | |
1026 | case REG: | |
1027 | if (cselib_lookup (x, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode)) | |
1028 | return false; | |
1029 | if (!validate_subreg (GET_MODE (subreg), GET_MODE (x), x, | |
1030 | subreg_lowpart_offset (GET_MODE (subreg), | |
1031 | GET_MODE (x)))) | |
1032 | return false; | |
1033 | break; | |
1034 | case PLUS: | |
1035 | case MINUS: | |
1036 | case MULT: | |
1037 | break; | |
1038 | case ASHIFT: | |
1039 | iter.substitute (XEXP (x, 0)); | |
1040 | break; | |
1041 | default: | |
1042 | return false; | |
1043 | } | |
e9e00885 | 1044 | } |
b328e730 | 1045 | return true; |
e9e00885 JJ |
1046 | } |
1047 | ||
1048 | /* Transform X into narrower mode MODE from wider mode WMODE. */ | |
1049 | ||
1050 | static rtx | |
ef4bddc2 | 1051 | use_narrower_mode (rtx x, machine_mode mode, machine_mode wmode) |
e9e00885 JJ |
1052 | { |
1053 | rtx op0, op1; | |
1054 | if (CONSTANT_P (x)) | |
1055 | return lowpart_subreg (mode, x, wmode); | |
1056 | switch (GET_CODE (x)) | |
1057 | { | |
1058 | case REG: | |
1059 | return lowpart_subreg (mode, x, wmode); | |
1060 | case PLUS: | |
1061 | case MINUS: | |
1062 | case MULT: | |
1063 | op0 = use_narrower_mode (XEXP (x, 0), mode, wmode); | |
1064 | op1 = use_narrower_mode (XEXP (x, 1), mode, wmode); | |
1065 | return simplify_gen_binary (GET_CODE (x), mode, op0, op1); | |
1066 | case ASHIFT: | |
1067 | op0 = use_narrower_mode (XEXP (x, 0), mode, wmode); | |
26d83bcc JJ |
1068 | op1 = XEXP (x, 1); |
1069 | /* Ensure shift amount is not wider than mode. */ | |
1070 | if (GET_MODE (op1) == VOIDmode) | |
1071 | op1 = lowpart_subreg (mode, op1, wmode); | |
1072 | else if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (op1))) | |
1073 | op1 = lowpart_subreg (mode, op1, GET_MODE (op1)); | |
1074 | return simplify_gen_binary (ASHIFT, mode, op0, op1); | |
e9e00885 JJ |
1075 | default: |
1076 | gcc_unreachable (); | |
1077 | } | |
1078 | } | |
1079 | ||
457eeaae JJ |
1080 | /* Helper function for adjusting used MEMs. */ |
1081 | ||
1082 | static rtx | |
1083 | adjust_mems (rtx loc, const_rtx old_rtx, void *data) | |
1084 | { | |
1085 | struct adjust_mem_data *amd = (struct adjust_mem_data *) data; | |
1086 | rtx mem, addr = loc, tem; | |
ef4bddc2 | 1087 | machine_mode mem_mode_save; |
457eeaae JJ |
1088 | bool store_save; |
1089 | switch (GET_CODE (loc)) | |
1090 | { | |
1091 | case REG: | |
9de9cbaf JJ |
1092 | /* Don't do any sp or fp replacements outside of MEM addresses |
1093 | on the LHS. */ | |
1094 | if (amd->mem_mode == VOIDmode && amd->store) | |
457eeaae JJ |
1095 | return loc; |
1096 | if (loc == stack_pointer_rtx | |
cfd8c4b1 JJ |
1097 | && !frame_pointer_needed |
1098 | && cfa_base_rtx) | |
457eeaae JJ |
1099 | return compute_cfa_pointer (amd->stack_adjust); |
1100 | else if (loc == hard_frame_pointer_rtx | |
1101 | && frame_pointer_needed | |
cfd8c4b1 JJ |
1102 | && hard_frame_pointer_adjustment != -1 |
1103 | && cfa_base_rtx) | |
457eeaae | 1104 | return compute_cfa_pointer (hard_frame_pointer_adjustment); |
37d6a488 | 1105 | gcc_checking_assert (loc != virtual_incoming_args_rtx); |
457eeaae JJ |
1106 | return loc; |
1107 | case MEM: | |
1108 | mem = loc; | |
1109 | if (!amd->store) | |
1110 | { | |
1111 | mem = targetm.delegitimize_address (mem); | |
1112 | if (mem != loc && !MEM_P (mem)) | |
1113 | return simplify_replace_fn_rtx (mem, old_rtx, adjust_mems, data); | |
1114 | } | |
1115 | ||
1116 | addr = XEXP (mem, 0); | |
1117 | mem_mode_save = amd->mem_mode; | |
1118 | amd->mem_mode = GET_MODE (mem); | |
1119 | store_save = amd->store; | |
1120 | amd->store = false; | |
1121 | addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); | |
1122 | amd->store = store_save; | |
1123 | amd->mem_mode = mem_mode_save; | |
1124 | if (mem == loc) | |
1125 | addr = targetm.delegitimize_address (addr); | |
1126 | if (addr != XEXP (mem, 0)) | |
1127 | mem = replace_equiv_address_nv (mem, addr); | |
1128 | if (!amd->store) | |
1129 | mem = avoid_constant_pool_reference (mem); | |
1130 | return mem; | |
1131 | case PRE_INC: | |
1132 | case PRE_DEC: | |
1133 | addr = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0), | |
4789c0ce RS |
1134 | gen_int_mode (GET_CODE (loc) == PRE_INC |
1135 | ? GET_MODE_SIZE (amd->mem_mode) | |
1136 | : -GET_MODE_SIZE (amd->mem_mode), | |
1137 | GET_MODE (loc))); | |
457eeaae JJ |
1138 | case POST_INC: |
1139 | case POST_DEC: | |
1140 | if (addr == loc) | |
1141 | addr = XEXP (loc, 0); | |
1142 | gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode); | |
1143 | addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); | |
1144 | tem = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0), | |
4789c0ce RS |
1145 | gen_int_mode ((GET_CODE (loc) == PRE_INC |
1146 | || GET_CODE (loc) == POST_INC) | |
1147 | ? GET_MODE_SIZE (amd->mem_mode) | |
1148 | : -GET_MODE_SIZE (amd->mem_mode), | |
1149 | GET_MODE (loc))); | |
af116cae JJ |
1150 | store_save = amd->store; |
1151 | amd->store = false; | |
1152 | tem = simplify_replace_fn_rtx (tem, old_rtx, adjust_mems, data); | |
1153 | amd->store = store_save; | |
457eeaae | 1154 | amd->side_effects = alloc_EXPR_LIST (0, |
f7df4a84 | 1155 | gen_rtx_SET (XEXP (loc, 0), tem), |
457eeaae JJ |
1156 | amd->side_effects); |
1157 | return addr; | |
1158 | case PRE_MODIFY: | |
1159 | addr = XEXP (loc, 1); | |
1160 | case POST_MODIFY: | |
1161 | if (addr == loc) | |
1162 | addr = XEXP (loc, 0); | |
9a05b749 | 1163 | gcc_assert (amd->mem_mode != VOIDmode); |
457eeaae | 1164 | addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); |
af116cae JJ |
1165 | store_save = amd->store; |
1166 | amd->store = false; | |
1167 | tem = simplify_replace_fn_rtx (XEXP (loc, 1), old_rtx, | |
1168 | adjust_mems, data); | |
1169 | amd->store = store_save; | |
457eeaae | 1170 | amd->side_effects = alloc_EXPR_LIST (0, |
f7df4a84 | 1171 | gen_rtx_SET (XEXP (loc, 0), tem), |
457eeaae JJ |
1172 | amd->side_effects); |
1173 | return addr; | |
1174 | case SUBREG: | |
1175 | /* First try without delegitimization of whole MEMs and | |
1176 | avoid_constant_pool_reference, which is more likely to succeed. */ | |
1177 | store_save = amd->store; | |
1178 | amd->store = true; | |
1179 | addr = simplify_replace_fn_rtx (SUBREG_REG (loc), old_rtx, adjust_mems, | |
1180 | data); | |
1181 | amd->store = store_save; | |
1182 | mem = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); | |
1183 | if (mem == SUBREG_REG (loc)) | |
e9e00885 JJ |
1184 | { |
1185 | tem = loc; | |
1186 | goto finish_subreg; | |
1187 | } | |
457eeaae JJ |
1188 | tem = simplify_gen_subreg (GET_MODE (loc), mem, |
1189 | GET_MODE (SUBREG_REG (loc)), | |
1190 | SUBREG_BYTE (loc)); | |
1191 | if (tem) | |
e9e00885 | 1192 | goto finish_subreg; |
457eeaae JJ |
1193 | tem = simplify_gen_subreg (GET_MODE (loc), addr, |
1194 | GET_MODE (SUBREG_REG (loc)), | |
1195 | SUBREG_BYTE (loc)); | |
e9e00885 JJ |
1196 | if (tem == NULL_RTX) |
1197 | tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc)); | |
1198 | finish_subreg: | |
1199 | if (MAY_HAVE_DEBUG_INSNS | |
1200 | && GET_CODE (tem) == SUBREG | |
1201 | && (GET_CODE (SUBREG_REG (tem)) == PLUS | |
1202 | || GET_CODE (SUBREG_REG (tem)) == MINUS | |
1203 | || GET_CODE (SUBREG_REG (tem)) == MULT | |
1204 | || GET_CODE (SUBREG_REG (tem)) == ASHIFT) | |
50b6ee8b DD |
1205 | && (GET_MODE_CLASS (GET_MODE (tem)) == MODE_INT |
1206 | || GET_MODE_CLASS (GET_MODE (tem)) == MODE_PARTIAL_INT) | |
1207 | && (GET_MODE_CLASS (GET_MODE (SUBREG_REG (tem))) == MODE_INT | |
1208 | || GET_MODE_CLASS (GET_MODE (SUBREG_REG (tem))) == MODE_PARTIAL_INT) | |
1209 | && GET_MODE_PRECISION (GET_MODE (tem)) | |
1210 | < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (tem))) | |
e9e00885 | 1211 | && subreg_lowpart_p (tem) |
b328e730 | 1212 | && use_narrower_mode_test (SUBREG_REG (tem), tem)) |
e9e00885 JJ |
1213 | return use_narrower_mode (SUBREG_REG (tem), GET_MODE (tem), |
1214 | GET_MODE (SUBREG_REG (tem))); | |
1215 | return tem; | |
fcc71c6c JJ |
1216 | case ASM_OPERANDS: |
1217 | /* Don't do any replacements in second and following | |
1218 | ASM_OPERANDS of inline-asm with multiple sets. | |
1219 | ASM_OPERANDS_INPUT_VEC, ASM_OPERANDS_INPUT_CONSTRAINT_VEC | |
1220 | and ASM_OPERANDS_LABEL_VEC need to be equal between | |
1221 | all the ASM_OPERANDs in the insn and adjust_insn will | |
1222 | fix this up. */ | |
1223 | if (ASM_OPERANDS_OUTPUT_IDX (loc) != 0) | |
1224 | return loc; | |
1225 | break; | |
457eeaae JJ |
1226 | default: |
1227 | break; | |
1228 | } | |
1229 | return NULL_RTX; | |
1230 | } | |
1231 | ||
1232 | /* Helper function for replacement of uses. */ | |
1233 | ||
1234 | static void | |
1235 | adjust_mem_uses (rtx *x, void *data) | |
1236 | { | |
1237 | rtx new_x = simplify_replace_fn_rtx (*x, NULL_RTX, adjust_mems, data); | |
1238 | if (new_x != *x) | |
1239 | validate_change (NULL_RTX, x, new_x, true); | |
1240 | } | |
1241 | ||
1242 | /* Helper function for replacement of stores. */ | |
1243 | ||
1244 | static void | |
1245 | adjust_mem_stores (rtx loc, const_rtx expr, void *data) | |
1246 | { | |
1247 | if (MEM_P (loc)) | |
1248 | { | |
1249 | rtx new_dest = simplify_replace_fn_rtx (SET_DEST (expr), NULL_RTX, | |
1250 | adjust_mems, data); | |
1251 | if (new_dest != SET_DEST (expr)) | |
1252 | { | |
1253 | rtx xexpr = CONST_CAST_RTX (expr); | |
1254 | validate_change (NULL_RTX, &SET_DEST (xexpr), new_dest, true); | |
1255 | } | |
1256 | } | |
1257 | } | |
1258 | ||
1259 | /* Simplify INSN. Remove all {PRE,POST}_{INC,DEC,MODIFY} rtxes, | |
1260 | replace them with their value in the insn and add the side-effects | |
1261 | as other sets to the insn. */ | |
1262 | ||
1263 | static void | |
598d62da | 1264 | adjust_insn (basic_block bb, rtx_insn *insn) |
457eeaae JJ |
1265 | { |
1266 | struct adjust_mem_data amd; | |
1267 | rtx set; | |
12c5ffe5 EB |
1268 | |
1269 | #ifdef HAVE_window_save | |
1270 | /* If the target machine has an explicit window save instruction, the | |
1271 | transformation OUTGOING_REGNO -> INCOMING_REGNO is done there. */ | |
1272 | if (RTX_FRAME_RELATED_P (insn) | |
1273 | && find_reg_note (insn, REG_CFA_WINDOW_SAVE, NULL_RTX)) | |
1274 | { | |
9771b263 | 1275 | unsigned int i, nregs = vec_safe_length (windowed_parm_regs); |
12c5ffe5 EB |
1276 | rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2)); |
1277 | parm_reg_t *p; | |
1278 | ||
9771b263 | 1279 | FOR_EACH_VEC_SAFE_ELT (windowed_parm_regs, i, p) |
12c5ffe5 EB |
1280 | { |
1281 | XVECEXP (rtl, 0, i * 2) | |
f7df4a84 | 1282 | = gen_rtx_SET (p->incoming, p->outgoing); |
12c5ffe5 EB |
1283 | /* Do not clobber the attached DECL, but only the REG. */ |
1284 | XVECEXP (rtl, 0, i * 2 + 1) | |
1285 | = gen_rtx_CLOBBER (GET_MODE (p->outgoing), | |
1286 | gen_raw_REG (GET_MODE (p->outgoing), | |
1287 | REGNO (p->outgoing))); | |
1288 | } | |
1289 | ||
1290 | validate_change (NULL_RTX, &PATTERN (insn), rtl, true); | |
1291 | return; | |
1292 | } | |
1293 | #endif | |
1294 | ||
457eeaae JJ |
1295 | amd.mem_mode = VOIDmode; |
1296 | amd.stack_adjust = -VTI (bb)->out.stack_adjust; | |
2f33ff0a | 1297 | amd.side_effects = NULL; |
457eeaae JJ |
1298 | |
1299 | amd.store = true; | |
1300 | note_stores (PATTERN (insn), adjust_mem_stores, &amd); | |
1301 | ||
1302 | amd.store = false; | |
fcc71c6c JJ |
1303 | if (GET_CODE (PATTERN (insn)) == PARALLEL |
1304 | && asm_noperands (PATTERN (insn)) > 0 | |
1305 | && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) | |
1306 | { | |
1307 | rtx body, set0; | |
1308 | int i; | |
1309 | ||
1310 | /* inline-asm with multiple sets is tiny bit more complicated, | |
1311 | because the 3 vectors in ASM_OPERANDS need to be shared between | |
1312 | all ASM_OPERANDS in the instruction. adjust_mems will | |
1313 | not touch ASM_OPERANDS other than the first one, asm_noperands | |
1314 | test above needs to be called before that (otherwise it would fail) | |
1315 | and afterwards this code fixes it up. */ | |
1316 | note_uses (&PATTERN (insn), adjust_mem_uses, &amd); | |
1317 | body = PATTERN (insn); | |
1318 | set0 = XVECEXP (body, 0, 0); | |
1319 | gcc_checking_assert (GET_CODE (set0) == SET | |
1320 | && GET_CODE (SET_SRC (set0)) == ASM_OPERANDS | |
1321 | && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set0)) == 0); | |
1322 | for (i = 1; i < XVECLEN (body, 0); i++) | |
1323 | if (GET_CODE (XVECEXP (body, 0, i)) != SET) | |
1324 | break; | |
1325 | else | |
1326 | { | |
1327 | set = XVECEXP (body, 0, i); | |
1328 | gcc_checking_assert (GET_CODE (SET_SRC (set)) == ASM_OPERANDS | |
1329 | && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set)) | |
1330 | == i); | |
1331 | if (ASM_OPERANDS_INPUT_VEC (SET_SRC (set)) | |
1332 | != ASM_OPERANDS_INPUT_VEC (SET_SRC (set0)) | |
1333 | || ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set)) | |
1334 | != ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0)) | |
1335 | || ASM_OPERANDS_LABEL_VEC (SET_SRC (set)) | |
1336 | != ASM_OPERANDS_LABEL_VEC (SET_SRC (set0))) | |
1337 | { | |
1338 | rtx newsrc = shallow_copy_rtx (SET_SRC (set)); | |
1339 | ASM_OPERANDS_INPUT_VEC (newsrc) | |
1340 | = ASM_OPERANDS_INPUT_VEC (SET_SRC (set0)); | |
1341 | ASM_OPERANDS_INPUT_CONSTRAINT_VEC (newsrc) | |
1342 | = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0)); | |
1343 | ASM_OPERANDS_LABEL_VEC (newsrc) | |
1344 | = ASM_OPERANDS_LABEL_VEC (SET_SRC (set0)); | |
1345 | validate_change (NULL_RTX, &SET_SRC (set), newsrc, true); | |
1346 | } | |
1347 | } | |
1348 | } | |
1349 | else | |
1350 | note_uses (&PATTERN (insn), adjust_mem_uses, &amd); | |
457eeaae JJ |
1351 | |
1352 | /* For read-only MEMs containing some constant, prefer those | |
1353 | constants. */ | |
1354 | set = single_set (insn); | |
1355 | if (set && MEM_P (SET_SRC (set)) && MEM_READONLY_P (SET_SRC (set))) | |
1356 | { | |
1357 | rtx note = find_reg_equal_equiv_note (insn); | |
1358 | ||
1359 | if (note && CONSTANT_P (XEXP (note, 0))) | |
1360 | validate_change (NULL_RTX, &SET_SRC (set), XEXP (note, 0), true); | |
1361 | } | |
1362 | ||
1363 | if (amd.side_effects) | |
1364 | { | |
1365 | rtx *pat, new_pat, s; | |
1366 | int i, oldn, newn; | |
014a1138 | 1367 | |
457eeaae JJ |
1368 | pat = &PATTERN (insn); |
1369 | if (GET_CODE (*pat) == COND_EXEC) | |
1370 | pat = &COND_EXEC_CODE (*pat); | |
1371 | if (GET_CODE (*pat) == PARALLEL) | |
1372 | oldn = XVECLEN (*pat, 0); | |
1373 | else | |
1374 | oldn = 1; | |
1375 | for (s = amd.side_effects, newn = 0; s; newn++) | |
1376 | s = XEXP (s, 1); | |
1377 | new_pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (oldn + newn)); | |
1378 | if (GET_CODE (*pat) == PARALLEL) | |
1379 | for (i = 0; i < oldn; i++) | |
1380 | XVECEXP (new_pat, 0, i) = XVECEXP (*pat, 0, i); | |
1381 | else | |
1382 | XVECEXP (new_pat, 0, 0) = *pat; | |
1383 | for (s = amd.side_effects, i = oldn; i < oldn + newn; i++, s = XEXP (s, 1)) | |
1384 | XVECEXP (new_pat, 0, i) = XEXP (s, 0); | |
1385 | free_EXPR_LIST_list (&amd.side_effects); | |
1386 | validate_change (NULL_RTX, pat, new_pat, true); | |
1387 | } | |
014a1138 JZ |
1388 | } |
1389 | ||
09dbcd96 AO |
1390 | /* Return the DEBUG_EXPR of a DEBUG_EXPR_DECL or the VALUE in DV. */ |
1391 | static inline rtx | |
1392 | dv_as_rtx (decl_or_value dv) | |
1393 | { | |
1394 | tree decl; | |
1395 | ||
1396 | if (dv_is_value_p (dv)) | |
1397 | return dv_as_value (dv); | |
1398 | ||
1399 | decl = dv_as_decl (dv); | |
1400 | ||
1401 | gcc_checking_assert (TREE_CODE (decl) == DEBUG_EXPR_DECL); | |
1402 | return DECL_RTL_KNOWN_SET (decl); | |
1403 | } | |
1404 | ||
09dbcd96 AO |
1405 | /* Return nonzero if a decl_or_value must not have more than one |
1406 | variable part. The returned value discriminates among various | |
1407 | kinds of one-part DVs ccording to enum onepart_enum. */ | |
1408 | static inline onepart_enum_t | |
b5b8b0ac AO |
1409 | dv_onepart_p (decl_or_value dv) |
1410 | { | |
1411 | tree decl; | |
1412 | ||
1413 | if (!MAY_HAVE_DEBUG_INSNS) | |
09dbcd96 | 1414 | return NOT_ONEPART; |
b5b8b0ac AO |
1415 | |
1416 | if (dv_is_value_p (dv)) | |
09dbcd96 | 1417 | return ONEPART_VALUE; |
b5b8b0ac AO |
1418 | |
1419 | decl = dv_as_decl (dv); | |
1420 | ||
5a309965 | 1421 | if (TREE_CODE (decl) == DEBUG_EXPR_DECL) |
09dbcd96 | 1422 | return ONEPART_DEXPR; |
5a309965 | 1423 | |
09dbcd96 AO |
1424 | if (target_for_debug_bind (decl) != NULL_TREE) |
1425 | return ONEPART_VDECL; | |
1426 | ||
1427 | return NOT_ONEPART; | |
b5b8b0ac AO |
1428 | } |
1429 | ||
09dbcd96 | 1430 | /* Return the variable pool to be used for a dv of type ONEPART. */ |
7e46899d | 1431 | static inline pool_allocator <variable_def> & |
09dbcd96 | 1432 | onepart_pool (onepart_enum_t onepart) |
b5b8b0ac | 1433 | { |
09dbcd96 | 1434 | return onepart ? valvar_pool : var_pool; |
b5b8b0ac AO |
1435 | } |
1436 | ||
b5b8b0ac AO |
1437 | /* Build a decl_or_value out of a decl. */ |
1438 | static inline decl_or_value | |
1439 | dv_from_decl (tree decl) | |
1440 | { | |
1441 | decl_or_value dv; | |
b5b8b0ac | 1442 | dv = decl; |
77a74ed7 | 1443 | gcc_checking_assert (dv_is_decl_p (dv)); |
b5b8b0ac AO |
1444 | return dv; |
1445 | } | |
1446 | ||
1447 | /* Build a decl_or_value out of a value. */ | |
1448 | static inline decl_or_value | |
1449 | dv_from_value (rtx value) | |
1450 | { | |
1451 | decl_or_value dv; | |
b5b8b0ac | 1452 | dv = value; |
77a74ed7 | 1453 | gcc_checking_assert (dv_is_value_p (dv)); |
b5b8b0ac AO |
1454 | return dv; |
1455 | } | |
1456 | ||
09dbcd96 AO |
1457 | /* Return a value or the decl of a debug_expr as a decl_or_value. */ |
1458 | static inline decl_or_value | |
1459 | dv_from_rtx (rtx x) | |
1460 | { | |
1461 | decl_or_value dv; | |
1462 | ||
1463 | switch (GET_CODE (x)) | |
1464 | { | |
1465 | case DEBUG_EXPR: | |
1466 | dv = dv_from_decl (DEBUG_EXPR_TREE_DECL (x)); | |
1467 | gcc_checking_assert (DECL_RTL_KNOWN_SET (DEBUG_EXPR_TREE_DECL (x)) == x); | |
1468 | break; | |
1469 | ||
1470 | case VALUE: | |
1471 | dv = dv_from_value (x); | |
1472 | break; | |
1473 | ||
1474 | default: | |
1475 | gcc_unreachable (); | |
1476 | } | |
1477 | ||
1478 | return dv; | |
1479 | } | |
1480 | ||
6764d92c JJ |
1481 | extern void debug_dv (decl_or_value dv); |
1482 | ||
24e47c76 | 1483 | DEBUG_FUNCTION void |
6764d92c JJ |
1484 | debug_dv (decl_or_value dv) |
1485 | { | |
1486 | if (dv_is_value_p (dv)) | |
1487 | debug_rtx (dv_as_value (dv)); | |
1488 | else | |
1489 | debug_generic_stmt (dv_as_decl (dv)); | |
1490 | } | |
1491 | ||
09dbcd96 AO |
1492 | static void loc_exp_dep_clear (variable var); |
1493 | ||
014a1138 JZ |
1494 | /* Free the element of VARIABLE_HTAB (its type is struct variable_def). */ |
1495 | ||
1496 | static void | |
1497 | variable_htab_free (void *elem) | |
1498 | { | |
1499 | int i; | |
1500 | variable var = (variable) elem; | |
1501 | location_chain node, next; | |
1502 | ||
7a40b8b1 | 1503 | gcc_checking_assert (var->refcount > 0); |
81f2eadb JZ |
1504 | |
1505 | var->refcount--; | |
1506 | if (var->refcount > 0) | |
1507 | return; | |
1508 | ||
014a1138 JZ |
1509 | for (i = 0; i < var->n_var_parts; i++) |
1510 | { | |
1511 | for (node = var->var_part[i].loc_chain; node; node = next) | |
1512 | { | |
1513 | next = node->next; | |
7e46899d | 1514 | delete node; |
014a1138 JZ |
1515 | } |
1516 | var->var_part[i].loc_chain = NULL; | |
1517 | } | |
09dbcd96 AO |
1518 | if (var->onepart && VAR_LOC_1PAUX (var)) |
1519 | { | |
1520 | loc_exp_dep_clear (var); | |
1521 | if (VAR_LOC_DEP_LST (var)) | |
1522 | VAR_LOC_DEP_LST (var)->pprev = NULL; | |
1523 | XDELETE (VAR_LOC_1PAUX (var)); | |
1524 | /* These may be reused across functions, so reset | |
1525 | e.g. NO_LOC_P. */ | |
1526 | if (var->onepart == ONEPART_DEXPR) | |
1527 | set_dv_changed (var->dv, true); | |
1528 | } | |
7e46899d | 1529 | onepart_pool (var->onepart).remove (var); |
014a1138 JZ |
1530 | } |
1531 | ||
1532 | /* Initialize the set (array) SET of attrs to empty lists. */ | |
1533 | ||
1534 | static void | |
1535 | init_attrs_list_set (attrs *set) | |
1536 | { | |
1537 | int i; | |
1538 | ||
1539 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
1540 | set[i] = NULL; | |
1541 | } | |
1542 | ||
1543 | /* Make the list *LISTP empty. */ | |
1544 | ||
1545 | static void | |
1546 | attrs_list_clear (attrs *listp) | |
1547 | { | |
1548 | attrs list, next; | |
1549 | ||
1550 | for (list = *listp; list; list = next) | |
1551 | { | |
1552 | next = list->next; | |
7e46899d | 1553 | delete list; |
014a1138 JZ |
1554 | } |
1555 | *listp = NULL; | |
1556 | } | |
1557 | ||
1558 | /* Return true if the pair of DECL and OFFSET is the member of the LIST. */ | |
1559 | ||
1560 | static attrs | |
b5b8b0ac | 1561 | attrs_list_member (attrs list, decl_or_value dv, HOST_WIDE_INT offset) |
014a1138 JZ |
1562 | { |
1563 | for (; list; list = list->next) | |
b5b8b0ac | 1564 | if (dv_as_opaque (list->dv) == dv_as_opaque (dv) && list->offset == offset) |
014a1138 JZ |
1565 | return list; |
1566 | return NULL; | |
1567 | } | |
1568 | ||
1569 | /* Insert the triplet DECL, OFFSET, LOC to the list *LISTP. */ | |
1570 | ||
1571 | static void | |
b5b8b0ac AO |
1572 | attrs_list_insert (attrs *listp, decl_or_value dv, |
1573 | HOST_WIDE_INT offset, rtx loc) | |
014a1138 | 1574 | { |
7e46899d | 1575 | attrs list = new attrs_def; |
014a1138 | 1576 | list->loc = loc; |
b5b8b0ac | 1577 | list->dv = dv; |
014a1138 JZ |
1578 | list->offset = offset; |
1579 | list->next = *listp; | |
1580 | *listp = list; | |
1581 | } | |
1582 | ||
1583 | /* Copy all nodes from SRC and create a list *DSTP of the copies. */ | |
1584 | ||
1585 | static void | |
1586 | attrs_list_copy (attrs *dstp, attrs src) | |
1587 | { | |
014a1138 JZ |
1588 | attrs_list_clear (dstp); |
1589 | for (; src; src = src->next) | |
1590 | { | |
7e46899d | 1591 | attrs n = new attrs_def; |
014a1138 | 1592 | n->loc = src->loc; |
b5b8b0ac | 1593 | n->dv = src->dv; |
014a1138 JZ |
1594 | n->offset = src->offset; |
1595 | n->next = *dstp; | |
1596 | *dstp = n; | |
1597 | } | |
1598 | } | |
1599 | ||
1600 | /* Add all nodes from SRC which are not in *DSTP to *DSTP. */ | |
1601 | ||
1602 | static void | |
1603 | attrs_list_union (attrs *dstp, attrs src) | |
1604 | { | |
1605 | for (; src; src = src->next) | |
1606 | { | |
b5b8b0ac AO |
1607 | if (!attrs_list_member (*dstp, src->dv, src->offset)) |
1608 | attrs_list_insert (dstp, src->dv, src->offset, src->loc); | |
1609 | } | |
1610 | } | |
1611 | ||
1612 | /* Combine nodes that are not onepart nodes from SRC and SRC2 into | |
1613 | *DSTP. */ | |
1614 | ||
1615 | static void | |
1616 | attrs_list_mpdv_union (attrs *dstp, attrs src, attrs src2) | |
1617 | { | |
1618 | gcc_assert (!*dstp); | |
1619 | for (; src; src = src->next) | |
1620 | { | |
1621 | if (!dv_onepart_p (src->dv)) | |
1622 | attrs_list_insert (dstp, src->dv, src->offset, src->loc); | |
1623 | } | |
1624 | for (src = src2; src; src = src->next) | |
1625 | { | |
1626 | if (!dv_onepart_p (src->dv) | |
1627 | && !attrs_list_member (*dstp, src->dv, src->offset)) | |
1628 | attrs_list_insert (dstp, src->dv, src->offset, src->loc); | |
014a1138 JZ |
1629 | } |
1630 | } | |
1631 | ||
d24686d7 JJ |
1632 | /* Shared hashtable support. */ |
1633 | ||
1634 | /* Return true if VARS is shared. */ | |
1635 | ||
1636 | static inline bool | |
1637 | shared_hash_shared (shared_hash vars) | |
1638 | { | |
1639 | return vars->refcount > 1; | |
1640 | } | |
1641 | ||
1642 | /* Return the hash table for VARS. */ | |
1643 | ||
c203e8a7 | 1644 | static inline variable_table_type * |
d24686d7 JJ |
1645 | shared_hash_htab (shared_hash vars) |
1646 | { | |
1647 | return vars->htab; | |
1648 | } | |
1649 | ||
864ddef7 JJ |
1650 | /* Return true if VAR is shared, or maybe because VARS is shared. */ |
1651 | ||
1652 | static inline bool | |
1653 | shared_var_p (variable var, shared_hash vars) | |
1654 | { | |
1655 | /* Don't count an entry in the changed_variables table as a duplicate. */ | |
1656 | return ((var->refcount > 1 + (int) var->in_changed_variables) | |
1657 | || shared_hash_shared (vars)); | |
1658 | } | |
1659 | ||
d24686d7 JJ |
1660 | /* Copy variables into a new hash table. */ |
1661 | ||
1662 | static shared_hash | |
1663 | shared_hash_unshare (shared_hash vars) | |
1664 | { | |
7e46899d | 1665 | shared_hash new_vars = new shared_hash_def; |
d24686d7 JJ |
1666 | gcc_assert (vars->refcount > 1); |
1667 | new_vars->refcount = 1; | |
c203e8a7 | 1668 | new_vars->htab = new variable_table_type (vars->htab->elements () + 3); |
d24686d7 JJ |
1669 | vars_copy (new_vars->htab, vars->htab); |
1670 | vars->refcount--; | |
1671 | return new_vars; | |
1672 | } | |
1673 | ||
1674 | /* Increment reference counter on VARS and return it. */ | |
1675 | ||
1676 | static inline shared_hash | |
1677 | shared_hash_copy (shared_hash vars) | |
1678 | { | |
1679 | vars->refcount++; | |
1680 | return vars; | |
1681 | } | |
1682 | ||
1683 | /* Decrement reference counter and destroy hash table if not shared | |
1684 | anymore. */ | |
014a1138 JZ |
1685 | |
1686 | static void | |
d24686d7 | 1687 | shared_hash_destroy (shared_hash vars) |
014a1138 | 1688 | { |
7a40b8b1 | 1689 | gcc_checking_assert (vars->refcount > 0); |
d24686d7 JJ |
1690 | if (--vars->refcount == 0) |
1691 | { | |
c203e8a7 | 1692 | delete vars->htab; |
7e46899d | 1693 | delete vars; |
d24686d7 JJ |
1694 | } |
1695 | } | |
1696 | ||
b5b8b0ac | 1697 | /* Unshare *PVARS if shared and return slot for DV. If INS is |
d24686d7 JJ |
1698 | INSERT, insert it if not already present. */ |
1699 | ||
013e5ef9 | 1700 | static inline variable_def ** |
b5b8b0ac AO |
1701 | shared_hash_find_slot_unshare_1 (shared_hash *pvars, decl_or_value dv, |
1702 | hashval_t dvhash, enum insert_option ins) | |
d24686d7 JJ |
1703 | { |
1704 | if (shared_hash_shared (*pvars)) | |
1705 | *pvars = shared_hash_unshare (*pvars); | |
c203e8a7 | 1706 | return shared_hash_htab (*pvars)->find_slot_with_hash (dv, dvhash, ins); |
b5b8b0ac AO |
1707 | } |
1708 | ||
013e5ef9 | 1709 | static inline variable_def ** |
b5b8b0ac AO |
1710 | shared_hash_find_slot_unshare (shared_hash *pvars, decl_or_value dv, |
1711 | enum insert_option ins) | |
1712 | { | |
1713 | return shared_hash_find_slot_unshare_1 (pvars, dv, dv_htab_hash (dv), ins); | |
d24686d7 JJ |
1714 | } |
1715 | ||
b5b8b0ac | 1716 | /* Return slot for DV, if it is already present in the hash table. |
d24686d7 JJ |
1717 | If it is not present, insert it only VARS is not shared, otherwise |
1718 | return NULL. */ | |
1719 | ||
013e5ef9 | 1720 | static inline variable_def ** |
b5b8b0ac | 1721 | shared_hash_find_slot_1 (shared_hash vars, decl_or_value dv, hashval_t dvhash) |
d24686d7 | 1722 | { |
c203e8a7 TS |
1723 | return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash, |
1724 | shared_hash_shared (vars) | |
1725 | ? NO_INSERT : INSERT); | |
d24686d7 JJ |
1726 | } |
1727 | ||
013e5ef9 | 1728 | static inline variable_def ** |
b5b8b0ac AO |
1729 | shared_hash_find_slot (shared_hash vars, decl_or_value dv) |
1730 | { | |
1731 | return shared_hash_find_slot_1 (vars, dv, dv_htab_hash (dv)); | |
1732 | } | |
1733 | ||
1734 | /* Return slot for DV only if it is already present in the hash table. */ | |
1735 | ||
013e5ef9 | 1736 | static inline variable_def ** |
b5b8b0ac AO |
1737 | shared_hash_find_slot_noinsert_1 (shared_hash vars, decl_or_value dv, |
1738 | hashval_t dvhash) | |
1739 | { | |
c203e8a7 | 1740 | return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash, NO_INSERT); |
b5b8b0ac | 1741 | } |
d24686d7 | 1742 | |
013e5ef9 | 1743 | static inline variable_def ** |
b5b8b0ac | 1744 | shared_hash_find_slot_noinsert (shared_hash vars, decl_or_value dv) |
d24686d7 | 1745 | { |
b5b8b0ac | 1746 | return shared_hash_find_slot_noinsert_1 (vars, dv, dv_htab_hash (dv)); |
d24686d7 JJ |
1747 | } |
1748 | ||
b5b8b0ac | 1749 | /* Return variable for DV or NULL if not already present in the hash |
d24686d7 JJ |
1750 | table. */ |
1751 | ||
1752 | static inline variable | |
b5b8b0ac AO |
1753 | shared_hash_find_1 (shared_hash vars, decl_or_value dv, hashval_t dvhash) |
1754 | { | |
c203e8a7 | 1755 | return shared_hash_htab (vars)->find_with_hash (dv, dvhash); |
b5b8b0ac AO |
1756 | } |
1757 | ||
1758 | static inline variable | |
1759 | shared_hash_find (shared_hash vars, decl_or_value dv) | |
1760 | { | |
1761 | return shared_hash_find_1 (vars, dv, dv_htab_hash (dv)); | |
1762 | } | |
1763 | ||
b5b8b0ac AO |
1764 | /* Return true if TVAL is better than CVAL as a canonival value. We |
1765 | choose lowest-numbered VALUEs, using the RTX address as a | |
1766 | tie-breaker. The idea is to arrange them into a star topology, | |
1767 | such that all of them are at most one step away from the canonical | |
1768 | value, and the canonical value has backlinks to all of them, in | |
1769 | addition to all the actual locations. We don't enforce this | |
1770 | topology throughout the entire dataflow analysis, though. | |
1771 | */ | |
1772 | ||
1773 | static inline bool | |
1774 | canon_value_cmp (rtx tval, rtx cval) | |
1775 | { | |
1776 | return !cval | |
5440c0e7 | 1777 | || CSELIB_VAL_PTR (tval)->uid < CSELIB_VAL_PTR (cval)->uid; |
014a1138 JZ |
1778 | } |
1779 | ||
b5b8b0ac AO |
1780 | static bool dst_can_be_shared; |
1781 | ||
81f2eadb | 1782 | /* Return a copy of a variable VAR and insert it to dataflow set SET. */ |
014a1138 | 1783 | |
013e5ef9 LC |
1784 | static variable_def ** |
1785 | unshare_variable (dataflow_set *set, variable_def **slot, variable var, | |
62760ffd | 1786 | enum var_init_status initialized) |
014a1138 | 1787 | { |
81f2eadb | 1788 | variable new_var; |
014a1138 JZ |
1789 | int i; |
1790 | ||
7e46899d | 1791 | new_var = onepart_pool (var->onepart).allocate (); |
b5b8b0ac | 1792 | new_var->dv = var->dv; |
81f2eadb JZ |
1793 | new_var->refcount = 1; |
1794 | var->refcount--; | |
1795 | new_var->n_var_parts = var->n_var_parts; | |
09dbcd96 | 1796 | new_var->onepart = var->onepart; |
864ddef7 | 1797 | new_var->in_changed_variables = false; |
014a1138 | 1798 | |
7eb3f1f7 JJ |
1799 | if (! flag_var_tracking_uninit) |
1800 | initialized = VAR_INIT_STATUS_INITIALIZED; | |
1801 | ||
014a1138 JZ |
1802 | for (i = 0; i < var->n_var_parts; i++) |
1803 | { | |
11599d14 JZ |
1804 | location_chain node; |
1805 | location_chain *nextp; | |
014a1138 | 1806 | |
09dbcd96 AO |
1807 | if (i == 0 && var->onepart) |
1808 | { | |
1809 | /* One-part auxiliary data is only used while emitting | |
1810 | notes, so propagate it to the new variable in the active | |
1811 | dataflow set. If we're not emitting notes, this will be | |
1812 | a no-op. */ | |
1813 | gcc_checking_assert (!VAR_LOC_1PAUX (var) || emit_notes); | |
1814 | VAR_LOC_1PAUX (new_var) = VAR_LOC_1PAUX (var); | |
1815 | VAR_LOC_1PAUX (var) = NULL; | |
1816 | } | |
1817 | else | |
1818 | VAR_PART_OFFSET (new_var, i) = VAR_PART_OFFSET (var, i); | |
81f2eadb JZ |
1819 | nextp = &new_var->var_part[i].loc_chain; |
1820 | for (node = var->var_part[i].loc_chain; node; node = node->next) | |
014a1138 JZ |
1821 | { |
1822 | location_chain new_lc; | |
1823 | ||
7e46899d | 1824 | new_lc = new location_chain_def; |
014a1138 | 1825 | new_lc->next = NULL; |
62760ffd CT |
1826 | if (node->init > initialized) |
1827 | new_lc->init = node->init; | |
1828 | else | |
1829 | new_lc->init = initialized; | |
1830 | if (node->set_src && !(MEM_P (node->set_src))) | |
1831 | new_lc->set_src = node->set_src; | |
1832 | else | |
1833 | new_lc->set_src = NULL; | |
014a1138 JZ |
1834 | new_lc->loc = node->loc; |
1835 | ||
11599d14 JZ |
1836 | *nextp = new_lc; |
1837 | nextp = &new_lc->next; | |
014a1138 JZ |
1838 | } |
1839 | ||
864ddef7 | 1840 | new_var->var_part[i].cur_loc = var->var_part[i].cur_loc; |
014a1138 JZ |
1841 | } |
1842 | ||
b5b8b0ac AO |
1843 | dst_can_be_shared = false; |
1844 | if (shared_hash_shared (set->vars)) | |
1845 | slot = shared_hash_find_slot_unshare (&set->vars, var->dv, NO_INSERT); | |
1846 | else if (set->traversed_vars && set->vars != set->traversed_vars) | |
1847 | slot = shared_hash_find_slot_noinsert (set->vars, var->dv); | |
81f2eadb | 1848 | *slot = new_var; |
864ddef7 JJ |
1849 | if (var->in_changed_variables) |
1850 | { | |
013e5ef9 | 1851 | variable_def **cslot |
c203e8a7 TS |
1852 | = changed_variables->find_slot_with_hash (var->dv, |
1853 | dv_htab_hash (var->dv), | |
1854 | NO_INSERT); | |
864ddef7 JJ |
1855 | gcc_assert (*cslot == (void *) var); |
1856 | var->in_changed_variables = false; | |
1857 | variable_htab_free (var); | |
1858 | *cslot = new_var; | |
1859 | new_var->in_changed_variables = true; | |
1860 | } | |
b5b8b0ac | 1861 | return slot; |
81f2eadb JZ |
1862 | } |
1863 | ||
014a1138 JZ |
1864 | /* Copy all variables from hash table SRC to hash table DST. */ |
1865 | ||
1866 | static void | |
c203e8a7 | 1867 | vars_copy (variable_table_type *dst, variable_table_type *src) |
014a1138 | 1868 | { |
013e5ef9 | 1869 | variable_iterator_type hi; |
a6590c31 RG |
1870 | variable var; |
1871 | ||
c203e8a7 | 1872 | FOR_EACH_HASH_TABLE_ELEMENT (*src, var, variable, hi) |
a6590c31 | 1873 | { |
013e5ef9 | 1874 | variable_def **dstp; |
a6590c31 | 1875 | var->refcount++; |
c203e8a7 TS |
1876 | dstp = dst->find_slot_with_hash (var->dv, dv_htab_hash (var->dv), |
1877 | INSERT); | |
a6590c31 RG |
1878 | *dstp = var; |
1879 | } | |
014a1138 JZ |
1880 | } |
1881 | ||
ca787200 AO |
1882 | /* Map a decl to its main debug decl. */ |
1883 | ||
1884 | static inline tree | |
1885 | var_debug_decl (tree decl) | |
1886 | { | |
839b422f RB |
1887 | if (decl && TREE_CODE (decl) == VAR_DECL |
1888 | && DECL_HAS_DEBUG_EXPR_P (decl)) | |
dbb2a2cb JJ |
1889 | { |
1890 | tree debugdecl = DECL_DEBUG_EXPR (decl); | |
839b422f | 1891 | if (DECL_P (debugdecl)) |
dbb2a2cb JJ |
1892 | decl = debugdecl; |
1893 | } | |
ca787200 AO |
1894 | |
1895 | return decl; | |
1896 | } | |
1897 | ||
b5b8b0ac | 1898 | /* Set the register LOC to contain DV, OFFSET. */ |
dedc1e6d AO |
1899 | |
1900 | static void | |
b5b8b0ac AO |
1901 | var_reg_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized, |
1902 | decl_or_value dv, HOST_WIDE_INT offset, rtx set_src, | |
1903 | enum insert_option iopt) | |
dedc1e6d | 1904 | { |
ca787200 | 1905 | attrs node; |
b5b8b0ac | 1906 | bool decl_p = dv_is_decl_p (dv); |
ca787200 | 1907 | |
b5b8b0ac AO |
1908 | if (decl_p) |
1909 | dv = dv_from_decl (var_debug_decl (dv_as_decl (dv))); | |
dedc1e6d | 1910 | |
ca787200 | 1911 | for (node = set->regs[REGNO (loc)]; node; node = node->next) |
b5b8b0ac AO |
1912 | if (dv_as_opaque (node->dv) == dv_as_opaque (dv) |
1913 | && node->offset == offset) | |
ca787200 AO |
1914 | break; |
1915 | if (!node) | |
b5b8b0ac AO |
1916 | attrs_list_insert (&set->regs[REGNO (loc)], dv, offset, loc); |
1917 | set_variable_part (set, loc, dv, offset, initialized, set_src, iopt); | |
1918 | } | |
1919 | ||
1920 | /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */ | |
1921 | ||
1922 | static void | |
1923 | var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized, | |
1924 | rtx set_src) | |
1925 | { | |
1926 | tree decl = REG_EXPR (loc); | |
1927 | HOST_WIDE_INT offset = REG_OFFSET (loc); | |
1928 | ||
1929 | var_reg_decl_set (set, loc, initialized, | |
1930 | dv_from_decl (decl), offset, set_src, INSERT); | |
62760ffd CT |
1931 | } |
1932 | ||
32e8bb8e | 1933 | static enum var_init_status |
b5b8b0ac | 1934 | get_init_value (dataflow_set *set, rtx loc, decl_or_value dv) |
62760ffd | 1935 | { |
62760ffd CT |
1936 | variable var; |
1937 | int i; | |
32e8bb8e | 1938 | enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN; |
62760ffd CT |
1939 | |
1940 | if (! flag_var_tracking_uninit) | |
1941 | return VAR_INIT_STATUS_INITIALIZED; | |
1942 | ||
b5b8b0ac | 1943 | var = shared_hash_find (set->vars, dv); |
d24686d7 | 1944 | if (var) |
62760ffd | 1945 | { |
62760ffd CT |
1946 | for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++) |
1947 | { | |
1948 | location_chain nextp; | |
1949 | for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next) | |
1950 | if (rtx_equal_p (nextp->loc, loc)) | |
1951 | { | |
1952 | ret_val = nextp->init; | |
1953 | break; | |
1954 | } | |
1955 | } | |
1956 | } | |
1957 | ||
1958 | return ret_val; | |
dedc1e6d AO |
1959 | } |
1960 | ||
ca787200 AO |
1961 | /* Delete current content of register LOC in dataflow set SET and set |
1962 | the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If | |
1963 | MODIFY is true, any other live copies of the same variable part are | |
1964 | also deleted from the dataflow set, otherwise the variable part is | |
1965 | assumed to be copied from another location holding the same | |
1966 | part. */ | |
014a1138 JZ |
1967 | |
1968 | static void | |
b8698a0f | 1969 | var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify, |
62760ffd | 1970 | enum var_init_status initialized, rtx set_src) |
014a1138 | 1971 | { |
014a1138 JZ |
1972 | tree decl = REG_EXPR (loc); |
1973 | HOST_WIDE_INT offset = REG_OFFSET (loc); | |
11599d14 JZ |
1974 | attrs node, next; |
1975 | attrs *nextp; | |
014a1138 | 1976 | |
ca787200 AO |
1977 | decl = var_debug_decl (decl); |
1978 | ||
62760ffd | 1979 | if (initialized == VAR_INIT_STATUS_UNKNOWN) |
b5b8b0ac | 1980 | initialized = get_init_value (set, loc, dv_from_decl (decl)); |
62760ffd | 1981 | |
11599d14 JZ |
1982 | nextp = &set->regs[REGNO (loc)]; |
1983 | for (node = *nextp; node; node = next) | |
014a1138 JZ |
1984 | { |
1985 | next = node->next; | |
b5b8b0ac | 1986 | if (dv_as_opaque (node->dv) != decl || node->offset != offset) |
014a1138 | 1987 | { |
b5b8b0ac | 1988 | delete_variable_part (set, node->loc, node->dv, node->offset); |
7e46899d | 1989 | delete node; |
11599d14 | 1990 | *nextp = next; |
014a1138 JZ |
1991 | } |
1992 | else | |
1993 | { | |
1994 | node->loc = loc; | |
11599d14 | 1995 | nextp = &node->next; |
014a1138 JZ |
1996 | } |
1997 | } | |
ca787200 | 1998 | if (modify) |
b5b8b0ac | 1999 | clobber_variable_part (set, loc, dv_from_decl (decl), offset, set_src); |
62760ffd | 2000 | var_reg_set (set, loc, initialized, set_src); |
014a1138 JZ |
2001 | } |
2002 | ||
7d2a8452 AO |
2003 | /* Delete the association of register LOC in dataflow set SET with any |
2004 | variables that aren't onepart. If CLOBBER is true, also delete any | |
2005 | other live copies of the same variable part, and delete the | |
2006 | association with onepart dvs too. */ | |
014a1138 JZ |
2007 | |
2008 | static void | |
ca787200 | 2009 | var_reg_delete (dataflow_set *set, rtx loc, bool clobber) |
014a1138 | 2010 | { |
7d2a8452 | 2011 | attrs *nextp = &set->regs[REGNO (loc)]; |
014a1138 JZ |
2012 | attrs node, next; |
2013 | ||
ca787200 AO |
2014 | if (clobber) |
2015 | { | |
2016 | tree decl = REG_EXPR (loc); | |
2017 | HOST_WIDE_INT offset = REG_OFFSET (loc); | |
2018 | ||
2019 | decl = var_debug_decl (decl); | |
2020 | ||
b5b8b0ac | 2021 | clobber_variable_part (set, NULL, dv_from_decl (decl), offset, NULL); |
ca787200 AO |
2022 | } |
2023 | ||
7d2a8452 | 2024 | for (node = *nextp; node; node = next) |
014a1138 JZ |
2025 | { |
2026 | next = node->next; | |
7d2a8452 AO |
2027 | if (clobber || !dv_onepart_p (node->dv)) |
2028 | { | |
2029 | delete_variable_part (set, node->loc, node->dv, node->offset); | |
7e46899d | 2030 | delete node; |
7d2a8452 AO |
2031 | *nextp = next; |
2032 | } | |
2033 | else | |
2034 | nextp = &node->next; | |
014a1138 | 2035 | } |
014a1138 JZ |
2036 | } |
2037 | ||
2038 | /* Delete content of register with number REGNO in dataflow set SET. */ | |
2039 | ||
2040 | static void | |
2041 | var_regno_delete (dataflow_set *set, int regno) | |
2042 | { | |
2043 | attrs *reg = &set->regs[regno]; | |
2044 | attrs node, next; | |
2045 | ||
2046 | for (node = *reg; node; node = next) | |
2047 | { | |
2048 | next = node->next; | |
b5b8b0ac | 2049 | delete_variable_part (set, node->loc, node->dv, node->offset); |
7e46899d | 2050 | delete node; |
014a1138 JZ |
2051 | } |
2052 | *reg = NULL; | |
2053 | } | |
2054 | ||
af6236c1 AO |
2055 | /* Return true if I is the negated value of a power of two. */ |
2056 | static bool | |
2057 | negative_power_of_two_p (HOST_WIDE_INT i) | |
2058 | { | |
2059 | unsigned HOST_WIDE_INT x = -(unsigned HOST_WIDE_INT)i; | |
2060 | return x == (x & -x); | |
2061 | } | |
2062 | ||
61806a93 AO |
2063 | /* Strip constant offsets and alignments off of LOC. Return the base |
2064 | expression. */ | |
2065 | ||
2066 | static rtx | |
2067 | vt_get_canonicalize_base (rtx loc) | |
2068 | { | |
2069 | while ((GET_CODE (loc) == PLUS | |
2070 | || GET_CODE (loc) == AND) | |
2071 | && GET_CODE (XEXP (loc, 1)) == CONST_INT | |
2072 | && (GET_CODE (loc) != AND | |
af6236c1 | 2073 | || negative_power_of_two_p (INTVAL (XEXP (loc, 1))))) |
61806a93 AO |
2074 | loc = XEXP (loc, 0); |
2075 | ||
2076 | return loc; | |
2077 | } | |
2078 | ||
af6236c1 AO |
2079 | /* This caches canonicalized addresses for VALUEs, computed using |
2080 | information in the global cselib table. */ | |
b787e7a2 | 2081 | static hash_map<rtx, rtx> *global_get_addr_cache; |
af6236c1 AO |
2082 | |
2083 | /* This caches canonicalized addresses for VALUEs, computed using | |
2084 | information from the global cache and information pertaining to a | |
2085 | basic block being analyzed. */ | |
b787e7a2 | 2086 | static hash_map<rtx, rtx> *local_get_addr_cache; |
af6236c1 AO |
2087 | |
2088 | static rtx vt_canonicalize_addr (dataflow_set *, rtx); | |
2089 | ||
2090 | /* Return the canonical address for LOC, that must be a VALUE, using a | |
2091 | cached global equivalence or computing it and storing it in the | |
2092 | global cache. */ | |
2093 | ||
2094 | static rtx | |
2095 | get_addr_from_global_cache (rtx const loc) | |
2096 | { | |
2097 | rtx x; | |
af6236c1 AO |
2098 | |
2099 | gcc_checking_assert (GET_CODE (loc) == VALUE); | |
7e46899d | 2100 | |
b787e7a2 TS |
2101 | bool existed; |
2102 | rtx *slot = &global_get_addr_cache->get_or_insert (loc, &existed); | |
2103 | if (existed) | |
2104 | return *slot; | |
af6236c1 AO |
2105 | |
2106 | x = canon_rtx (get_addr (loc)); | |
2107 | ||
2108 | /* Tentative, avoiding infinite recursion. */ | |
2109 | *slot = x; | |
2110 | ||
2111 | if (x != loc) | |
2112 | { | |
2113 | rtx nx = vt_canonicalize_addr (NULL, x); | |
2114 | if (nx != x) | |
2115 | { | |
2116 | /* The table may have moved during recursion, recompute | |
2117 | SLOT. */ | |
b787e7a2 | 2118 | *global_get_addr_cache->get (loc) = x = nx; |
af6236c1 AO |
2119 | } |
2120 | } | |
2121 | ||
2122 | return x; | |
2123 | } | |
2124 | ||
2125 | /* Return the canonical address for LOC, that must be a VALUE, using a | |
2126 | cached local equivalence or computing it and storing it in the | |
2127 | local cache. */ | |
2128 | ||
2129 | static rtx | |
2130 | get_addr_from_local_cache (dataflow_set *set, rtx const loc) | |
2131 | { | |
2132 | rtx x; | |
af6236c1 AO |
2133 | decl_or_value dv; |
2134 | variable var; | |
2135 | location_chain l; | |
2136 | ||
2137 | gcc_checking_assert (GET_CODE (loc) == VALUE); | |
7e46899d | 2138 | |
b787e7a2 TS |
2139 | bool existed; |
2140 | rtx *slot = &local_get_addr_cache->get_or_insert (loc, &existed); | |
2141 | if (existed) | |
2142 | return *slot; | |
af6236c1 AO |
2143 | |
2144 | x = get_addr_from_global_cache (loc); | |
7e46899d | 2145 | |
af6236c1 AO |
2146 | /* Tentative, avoiding infinite recursion. */ |
2147 | *slot = x; | |
2148 | ||
2149 | /* Recurse to cache local expansion of X, or if we need to search | |
2150 | for a VALUE in the expansion. */ | |
2151 | if (x != loc) | |
2152 | { | |
2153 | rtx nx = vt_canonicalize_addr (set, x); | |
2154 | if (nx != x) | |
2155 | { | |
b787e7a2 | 2156 | slot = local_get_addr_cache->get (loc); |
af6236c1 AO |
2157 | *slot = x = nx; |
2158 | } | |
2159 | return x; | |
2160 | } | |
2161 | ||
2162 | dv = dv_from_rtx (x); | |
013e5ef9 | 2163 | var = shared_hash_find (set->vars, dv); |
af6236c1 AO |
2164 | if (!var) |
2165 | return x; | |
2166 | ||
2167 | /* Look for an improved equivalent expression. */ | |
2168 | for (l = var->var_part[0].loc_chain; l; l = l->next) | |
2169 | { | |
2170 | rtx base = vt_get_canonicalize_base (l->loc); | |
2171 | if (GET_CODE (base) == VALUE | |
2172 | && canon_value_cmp (base, loc)) | |
2173 | { | |
2174 | rtx nx = vt_canonicalize_addr (set, l->loc); | |
2175 | if (x != nx) | |
2176 | { | |
b787e7a2 | 2177 | slot = local_get_addr_cache->get (loc); |
af6236c1 AO |
2178 | *slot = x = nx; |
2179 | } | |
2180 | break; | |
2181 | } | |
2182 | } | |
2183 | ||
2184 | return x; | |
2185 | } | |
2186 | ||
61806a93 | 2187 | /* Canonicalize LOC using equivalences from SET in addition to those |
af6236c1 AO |
2188 | in the cselib static table. It expects a VALUE-based expression, |
2189 | and it will only substitute VALUEs with other VALUEs or | |
2190 | function-global equivalences, so that, if two addresses have base | |
2191 | VALUEs that are locally or globally related in ways that | |
2192 | memrefs_conflict_p cares about, they will both canonicalize to | |
2193 | expressions that have the same base VALUE. | |
2194 | ||
2195 | The use of VALUEs as canonical base addresses enables the canonical | |
2196 | RTXs to remain unchanged globally, if they resolve to a constant, | |
2197 | or throughout a basic block otherwise, so that they can be cached | |
2198 | and the cache needs not be invalidated when REGs, MEMs or such | |
2199 | change. */ | |
61806a93 AO |
2200 | |
2201 | static rtx | |
2202 | vt_canonicalize_addr (dataflow_set *set, rtx oloc) | |
2203 | { | |
2204 | HOST_WIDE_INT ofst = 0; | |
ef4bddc2 | 2205 | machine_mode mode = GET_MODE (oloc); |
af6236c1 AO |
2206 | rtx loc = oloc; |
2207 | rtx x; | |
2208 | bool retry = true; | |
61806a93 | 2209 | |
af6236c1 | 2210 | while (retry) |
61806a93 | 2211 | { |
af6236c1 AO |
2212 | while (GET_CODE (loc) == PLUS |
2213 | && GET_CODE (XEXP (loc, 1)) == CONST_INT) | |
61806a93 AO |
2214 | { |
2215 | ofst += INTVAL (XEXP (loc, 1)); | |
2216 | loc = XEXP (loc, 0); | |
61806a93 AO |
2217 | } |
2218 | ||
2219 | /* Alignment operations can't normally be combined, so just | |
2220 | canonicalize the base and we're done. We'll normally have | |
2221 | only one stack alignment anyway. */ | |
af6236c1 AO |
2222 | if (GET_CODE (loc) == AND |
2223 | && GET_CODE (XEXP (loc, 1)) == CONST_INT | |
2224 | && negative_power_of_two_p (INTVAL (XEXP (loc, 1)))) | |
61806a93 AO |
2225 | { |
2226 | x = vt_canonicalize_addr (set, XEXP (loc, 0)); | |
2227 | if (x != XEXP (loc, 0)) | |
2228 | loc = gen_rtx_AND (mode, x, XEXP (loc, 1)); | |
af6236c1 | 2229 | retry = false; |
61806a93 AO |
2230 | } |
2231 | ||
af6236c1 | 2232 | if (GET_CODE (loc) == VALUE) |
61806a93 | 2233 | { |
af6236c1 AO |
2234 | if (set) |
2235 | loc = get_addr_from_local_cache (set, loc); | |
2236 | else | |
2237 | loc = get_addr_from_global_cache (loc); | |
61806a93 | 2238 | |
af6236c1 AO |
2239 | /* Consolidate plus_constants. */ |
2240 | while (ofst && GET_CODE (loc) == PLUS | |
2241 | && GET_CODE (XEXP (loc, 1)) == CONST_INT) | |
61806a93 | 2242 | { |
af6236c1 AO |
2243 | ofst += INTVAL (XEXP (loc, 1)); |
2244 | loc = XEXP (loc, 0); | |
61806a93 | 2245 | } |
61806a93 | 2246 | |
af6236c1 AO |
2247 | retry = false; |
2248 | } | |
2249 | else | |
2250 | { | |
2251 | x = canon_rtx (loc); | |
2252 | if (retry) | |
2253 | retry = (x != loc); | |
2254 | loc = x; | |
2255 | } | |
61806a93 AO |
2256 | } |
2257 | ||
2258 | /* Add OFST back in. */ | |
2259 | if (ofst) | |
2260 | { | |
2261 | /* Don't build new RTL if we can help it. */ | |
2262 | if (GET_CODE (oloc) == PLUS | |
2263 | && XEXP (oloc, 0) == loc | |
2264 | && INTVAL (XEXP (oloc, 1)) == ofst) | |
2265 | return oloc; | |
2266 | ||
2267 | loc = plus_constant (mode, loc, ofst); | |
2268 | } | |
2269 | ||
2270 | return loc; | |
2271 | } | |
2272 | ||
61806a93 AO |
2273 | /* Return true iff there's a true dependence between MLOC and LOC. |
2274 | MADDR must be a canonicalized version of MLOC's address. */ | |
2275 | ||
2276 | static inline bool | |
2277 | vt_canon_true_dep (dataflow_set *set, rtx mloc, rtx maddr, rtx loc) | |
2278 | { | |
2279 | if (GET_CODE (loc) != MEM) | |
2280 | return false; | |
2281 | ||
af6236c1 AO |
2282 | rtx addr = vt_canonicalize_addr (set, XEXP (loc, 0)); |
2283 | if (!canon_true_dependence (mloc, GET_MODE (mloc), maddr, loc, addr)) | |
61806a93 AO |
2284 | return false; |
2285 | ||
61806a93 AO |
2286 | return true; |
2287 | } | |
2288 | ||
8cda8ad3 AO |
2289 | /* Hold parameters for the hashtab traversal function |
2290 | drop_overlapping_mem_locs, see below. */ | |
2291 | ||
2292 | struct overlapping_mems | |
2293 | { | |
2294 | dataflow_set *set; | |
2295 | rtx loc, addr; | |
2296 | }; | |
2297 | ||
2298 | /* Remove all MEMs that overlap with COMS->LOC from the location list | |
2299 | of a hash table entry for a value. COMS->ADDR must be a | |
2300 | canonicalized form of COMS->LOC's address, and COMS->LOC must be | |
2301 | canonicalized itself. */ | |
2302 | ||
013e5ef9 LC |
2303 | int |
2304 | drop_overlapping_mem_locs (variable_def **slot, overlapping_mems *coms) | |
8cda8ad3 | 2305 | { |
8cda8ad3 AO |
2306 | dataflow_set *set = coms->set; |
2307 | rtx mloc = coms->loc, addr = coms->addr; | |
013e5ef9 | 2308 | variable var = *slot; |
8cda8ad3 AO |
2309 | |
2310 | if (var->onepart == ONEPART_VALUE) | |
2311 | { | |
2312 | location_chain loc, *locp; | |
2313 | bool changed = false; | |
2314 | rtx cur_loc; | |
2315 | ||
2316 | gcc_assert (var->n_var_parts == 1); | |
2317 | ||
2318 | if (shared_var_p (var, set->vars)) | |
2319 | { | |
2320 | for (loc = var->var_part[0].loc_chain; loc; loc = loc->next) | |
61806a93 | 2321 | if (vt_canon_true_dep (set, mloc, addr, loc->loc)) |
8cda8ad3 AO |
2322 | break; |
2323 | ||
2324 | if (!loc) | |
2325 | return 1; | |
2326 | ||
2327 | slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN); | |
013e5ef9 | 2328 | var = *slot; |
8cda8ad3 AO |
2329 | gcc_assert (var->n_var_parts == 1); |
2330 | } | |
2331 | ||
2332 | if (VAR_LOC_1PAUX (var)) | |
2333 | cur_loc = VAR_LOC_FROM (var); | |
2334 | else | |
2335 | cur_loc = var->var_part[0].cur_loc; | |
2336 | ||
2337 | for (locp = &var->var_part[0].loc_chain, loc = *locp; | |
2338 | loc; loc = *locp) | |
2339 | { | |
61806a93 | 2340 | if (!vt_canon_true_dep (set, mloc, addr, loc->loc)) |
8cda8ad3 AO |
2341 | { |
2342 | locp = &loc->next; | |
2343 | continue; | |
2344 | } | |
2345 | ||
2346 | *locp = loc->next; | |
2347 | /* If we have deleted the location which was last emitted | |
2348 | we have to emit new location so add the variable to set | |
2349 | of changed variables. */ | |
2350 | if (cur_loc == loc->loc) | |
2351 | { | |
2352 | changed = true; | |
2353 | var->var_part[0].cur_loc = NULL; | |
2354 | if (VAR_LOC_1PAUX (var)) | |
2355 | VAR_LOC_FROM (var) = NULL; | |
2356 | } | |
7e46899d | 2357 | delete loc; |
8cda8ad3 AO |
2358 | } |
2359 | ||
2360 | if (!var->var_part[0].loc_chain) | |
2361 | { | |
2362 | var->n_var_parts--; | |
2363 | changed = true; | |
2364 | } | |
2365 | if (changed) | |
2366 | variable_was_changed (var, set); | |
2367 | } | |
2368 | ||
2369 | return 1; | |
2370 | } | |
2371 | ||
2372 | /* Remove from SET all VALUE bindings to MEMs that overlap with LOC. */ | |
2373 | ||
2374 | static void | |
2375 | clobber_overlapping_mems (dataflow_set *set, rtx loc) | |
2376 | { | |
2377 | struct overlapping_mems coms; | |
2378 | ||
af6236c1 AO |
2379 | gcc_checking_assert (GET_CODE (loc) == MEM); |
2380 | ||
8cda8ad3 AO |
2381 | coms.set = set; |
2382 | coms.loc = canon_rtx (loc); | |
61806a93 | 2383 | coms.addr = vt_canonicalize_addr (set, XEXP (loc, 0)); |
8cda8ad3 AO |
2384 | |
2385 | set->traversed_vars = set->vars; | |
013e5ef9 | 2386 | shared_hash_htab (set->vars) |
c203e8a7 | 2387 | ->traverse <overlapping_mems*, drop_overlapping_mem_locs> (&coms); |
8cda8ad3 AO |
2388 | set->traversed_vars = NULL; |
2389 | } | |
2390 | ||
b5b8b0ac AO |
2391 | /* Set the location of DV, OFFSET as the MEM LOC. */ |
2392 | ||
2393 | static void | |
2394 | var_mem_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized, | |
2395 | decl_or_value dv, HOST_WIDE_INT offset, rtx set_src, | |
2396 | enum insert_option iopt) | |
2397 | { | |
2398 | if (dv_is_decl_p (dv)) | |
2399 | dv = dv_from_decl (var_debug_decl (dv_as_decl (dv))); | |
2400 | ||
2401 | set_variable_part (set, loc, dv, offset, initialized, set_src, iopt); | |
2402 | } | |
2403 | ||
dedc1e6d AO |
2404 | /* Set the location part of variable MEM_EXPR (LOC) in dataflow set |
2405 | SET to LOC. | |
014a1138 JZ |
2406 | Adjust the address first if it is stack pointer based. */ |
2407 | ||
2408 | static void | |
b8698a0f | 2409 | var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized, |
62760ffd | 2410 | rtx set_src) |
014a1138 JZ |
2411 | { |
2412 | tree decl = MEM_EXPR (loc); | |
8c6c36a3 | 2413 | HOST_WIDE_INT offset = INT_MEM_OFFSET (loc); |
014a1138 | 2414 | |
b5b8b0ac AO |
2415 | var_mem_decl_set (set, loc, initialized, |
2416 | dv_from_decl (decl), offset, set_src, INSERT); | |
014a1138 JZ |
2417 | } |
2418 | ||
ca787200 AO |
2419 | /* Delete and set the location part of variable MEM_EXPR (LOC) in |
2420 | dataflow set SET to LOC. If MODIFY is true, any other live copies | |
2421 | of the same variable part are also deleted from the dataflow set, | |
2422 | otherwise the variable part is assumed to be copied from another | |
2423 | location holding the same part. | |
dedc1e6d AO |
2424 | Adjust the address first if it is stack pointer based. */ |
2425 | ||
2426 | static void | |
b8698a0f | 2427 | var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify, |
62760ffd | 2428 | enum var_init_status initialized, rtx set_src) |
dedc1e6d | 2429 | { |
ca787200 | 2430 | tree decl = MEM_EXPR (loc); |
8c6c36a3 | 2431 | HOST_WIDE_INT offset = INT_MEM_OFFSET (loc); |
ca787200 | 2432 | |
8cda8ad3 | 2433 | clobber_overlapping_mems (set, loc); |
ca787200 AO |
2434 | decl = var_debug_decl (decl); |
2435 | ||
62760ffd | 2436 | if (initialized == VAR_INIT_STATUS_UNKNOWN) |
b5b8b0ac | 2437 | initialized = get_init_value (set, loc, dv_from_decl (decl)); |
62760ffd | 2438 | |
ca787200 | 2439 | if (modify) |
b5b8b0ac | 2440 | clobber_variable_part (set, NULL, dv_from_decl (decl), offset, set_src); |
62760ffd | 2441 | var_mem_set (set, loc, initialized, set_src); |
dedc1e6d AO |
2442 | } |
2443 | ||
ca787200 AO |
2444 | /* Delete the location part LOC from dataflow set SET. If CLOBBER is |
2445 | true, also delete any other live copies of the same variable part. | |
014a1138 JZ |
2446 | Adjust the address first if it is stack pointer based. */ |
2447 | ||
2448 | static void | |
ca787200 | 2449 | var_mem_delete (dataflow_set *set, rtx loc, bool clobber) |
014a1138 JZ |
2450 | { |
2451 | tree decl = MEM_EXPR (loc); | |
8c6c36a3 | 2452 | HOST_WIDE_INT offset = INT_MEM_OFFSET (loc); |
014a1138 | 2453 | |
8cda8ad3 | 2454 | clobber_overlapping_mems (set, loc); |
ca787200 AO |
2455 | decl = var_debug_decl (decl); |
2456 | if (clobber) | |
b5b8b0ac AO |
2457 | clobber_variable_part (set, NULL, dv_from_decl (decl), offset, NULL); |
2458 | delete_variable_part (set, loc, dv_from_decl (decl), offset); | |
2459 | } | |
2460 | ||
09dbcd96 AO |
2461 | /* Return true if LOC should not be expanded for location expressions, |
2462 | or used in them. */ | |
2463 | ||
2464 | static inline bool | |
2465 | unsuitable_loc (rtx loc) | |
2466 | { | |
2467 | switch (GET_CODE (loc)) | |
2468 | { | |
2469 | case PC: | |
2470 | case SCRATCH: | |
2471 | case CC0: | |
2472 | case ASM_INPUT: | |
2473 | case ASM_OPERANDS: | |
2474 | return true; | |
2475 | ||
2476 | default: | |
2477 | return false; | |
2478 | } | |
2479 | } | |
2480 | ||
6f2ffb4b AO |
2481 | /* Bind VAL to LOC in SET. If MODIFIED, detach LOC from any values |
2482 | bound to it. */ | |
2483 | ||
2484 | static inline void | |
2485 | val_bind (dataflow_set *set, rtx val, rtx loc, bool modified) | |
2486 | { | |
2487 | if (REG_P (loc)) | |
2488 | { | |
2489 | if (modified) | |
2490 | var_regno_delete (set, REGNO (loc)); | |
2491 | var_reg_decl_set (set, loc, VAR_INIT_STATUS_INITIALIZED, | |
2492 | dv_from_value (val), 0, NULL_RTX, INSERT); | |
2493 | } | |
2494 | else if (MEM_P (loc)) | |
2495 | { | |
2496 | struct elt_loc_list *l = CSELIB_VAL_PTR (val)->locs; | |
2497 | ||
8cda8ad3 AO |
2498 | if (modified) |
2499 | clobber_overlapping_mems (set, loc); | |
2500 | ||
6f2ffb4b AO |
2501 | if (l && GET_CODE (l->loc) == VALUE) |
2502 | l = canonical_cselib_val (CSELIB_VAL_PTR (l->loc))->locs; | |
2503 | ||
2504 | /* If this MEM is a global constant, we don't need it in the | |
2505 | dynamic tables. ??? We should test this before emitting the | |
2506 | micro-op in the first place. */ | |
2507 | while (l) | |
2508 | if (GET_CODE (l->loc) == MEM && XEXP (l->loc, 0) == XEXP (loc, 0)) | |
2509 | break; | |
2510 | else | |
2511 | l = l->next; | |
2512 | ||
2513 | if (!l) | |
2514 | var_mem_decl_set (set, loc, VAR_INIT_STATUS_INITIALIZED, | |
2515 | dv_from_value (val), 0, NULL_RTX, INSERT); | |
2516 | } | |
2517 | else | |
2518 | { | |
2519 | /* Other kinds of equivalences are necessarily static, at least | |
2520 | so long as we do not perform substitutions while merging | |
2521 | expressions. */ | |
2522 | gcc_unreachable (); | |
2523 | set_variable_part (set, loc, dv_from_value (val), 0, | |
2524 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, INSERT); | |
2525 | } | |
2526 | } | |
2527 | ||
fb4cbb9f AO |
2528 | /* Bind a value to a location it was just stored in. If MODIFIED |
2529 | holds, assume the location was modified, detaching it from any | |
2530 | values bound to it. */ | |
b5b8b0ac AO |
2531 | |
2532 | static void | |
598d62da DM |
2533 | val_store (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn, |
2534 | bool modified) | |
b5b8b0ac AO |
2535 | { |
2536 | cselib_val *v = CSELIB_VAL_PTR (val); | |
2537 | ||
2538 | gcc_assert (cselib_preserved_value_p (v)); | |
2539 | ||
2540 | if (dump_file) | |
2541 | { | |
09dbcd96 | 2542 | fprintf (dump_file, "%i: ", insn ? INSN_UID (insn) : 0); |
b5b8b0ac | 2543 | print_inline_rtx (dump_file, loc, 0); |
09dbcd96 AO |
2544 | fprintf (dump_file, " evaluates to "); |
2545 | print_inline_rtx (dump_file, val, 0); | |
b5b8b0ac AO |
2546 | if (v->locs) |
2547 | { | |
2548 | struct elt_loc_list *l; | |
2549 | for (l = v->locs; l; l = l->next) | |
2550 | { | |
2551 | fprintf (dump_file, "\n%i: ", INSN_UID (l->setting_insn)); | |
2552 | print_inline_rtx (dump_file, l->loc, 0); | |
2553 | } | |
2554 | } | |
2555 | fprintf (dump_file, "\n"); | |
2556 | } | |
2557 | ||
09dbcd96 AO |
2558 | gcc_checking_assert (!unsuitable_loc (loc)); |
2559 | ||
6f2ffb4b | 2560 | val_bind (set, val, loc, modified); |
b5b8b0ac AO |
2561 | } |
2562 | ||
af6236c1 AO |
2563 | /* Clear (canonical address) slots that reference X. */ |
2564 | ||
b787e7a2 TS |
2565 | bool |
2566 | local_get_addr_clear_given_value (rtx const &, rtx *slot, rtx x) | |
af6236c1 | 2567 | { |
b787e7a2 | 2568 | if (vt_get_canonicalize_base (*slot) == x) |
af6236c1 AO |
2569 | *slot = NULL; |
2570 | return true; | |
2571 | } | |
2572 | ||
b5b8b0ac AO |
2573 | /* Reset this node, detaching all its equivalences. Return the slot |
2574 | in the variable hash table that holds dv, if there is one. */ | |
2575 | ||
2576 | static void | |
2577 | val_reset (dataflow_set *set, decl_or_value dv) | |
2578 | { | |
2579 | variable var = shared_hash_find (set->vars, dv) ; | |
2580 | location_chain node; | |
2581 | rtx cval; | |
2582 | ||
2583 | if (!var || !var->n_var_parts) | |
2584 | return; | |
2585 | ||
2586 | gcc_assert (var->n_var_parts == 1); | |
2587 | ||
e04faf24 | 2588 | if (var->onepart == ONEPART_VALUE) |
af6236c1 AO |
2589 | { |
2590 | rtx x = dv_as_value (dv); | |
7e46899d | 2591 | |
af6236c1 AO |
2592 | /* Relationships in the global cache don't change, so reset the |
2593 | local cache entry only. */ | |
b787e7a2 | 2594 | rtx *slot = local_get_addr_cache->get (x); |
af6236c1 AO |
2595 | if (slot) |
2596 | { | |
2597 | /* If the value resolved back to itself, odds are that other | |
2598 | values may have cached it too. These entries now refer | |
2599 | to the old X, so detach them too. Entries that used the | |
2600 | old X but resolved to something else remain ok as long as | |
2601 | that something else isn't also reset. */ | |
2602 | if (*slot == x) | |
b787e7a2 TS |
2603 | local_get_addr_cache |
2604 | ->traverse<rtx, local_get_addr_clear_given_value> (x); | |
af6236c1 AO |
2605 | *slot = NULL; |
2606 | } | |
2607 | } | |
2608 | ||
b5b8b0ac AO |
2609 | cval = NULL; |
2610 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
2611 | if (GET_CODE (node->loc) == VALUE | |
2612 | && canon_value_cmp (node->loc, cval)) | |
2613 | cval = node->loc; | |
2614 | ||
2615 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
2616 | if (GET_CODE (node->loc) == VALUE && cval != node->loc) | |
2617 | { | |
2618 | /* Redirect the equivalence link to the new canonical | |
2619 | value, or simply remove it if it would point at | |
2620 | itself. */ | |
2621 | if (cval) | |
2622 | set_variable_part (set, cval, dv_from_value (node->loc), | |
2623 | 0, node->init, node->set_src, NO_INSERT); | |
2624 | delete_variable_part (set, dv_as_value (dv), | |
2625 | dv_from_value (node->loc), 0); | |
2626 | } | |
2627 | ||
2628 | if (cval) | |
2629 | { | |
2630 | decl_or_value cdv = dv_from_value (cval); | |
2631 | ||
2632 | /* Keep the remaining values connected, accummulating links | |
2633 | in the canonical value. */ | |
2634 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
2635 | { | |
2636 | if (node->loc == cval) | |
2637 | continue; | |
2638 | else if (GET_CODE (node->loc) == REG) | |
2639 | var_reg_decl_set (set, node->loc, node->init, cdv, 0, | |
2640 | node->set_src, NO_INSERT); | |
2641 | else if (GET_CODE (node->loc) == MEM) | |
2642 | var_mem_decl_set (set, node->loc, node->init, cdv, 0, | |
2643 | node->set_src, NO_INSERT); | |
2644 | else | |
2645 | set_variable_part (set, node->loc, cdv, 0, | |
2646 | node->init, node->set_src, NO_INSERT); | |
2647 | } | |
2648 | } | |
2649 | ||
2650 | /* We remove this last, to make sure that the canonical value is not | |
2651 | removed to the point of requiring reinsertion. */ | |
2652 | if (cval) | |
2653 | delete_variable_part (set, dv_as_value (dv), dv_from_value (cval), 0); | |
2654 | ||
2655 | clobber_variable_part (set, NULL, dv, 0, NULL); | |
b5b8b0ac AO |
2656 | } |
2657 | ||
2658 | /* Find the values in a given location and map the val to another | |
2659 | value, if it is unique, or add the location as one holding the | |
2660 | value. */ | |
2661 | ||
2662 | static void | |
598d62da | 2663 | val_resolve (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn) |
b5b8b0ac AO |
2664 | { |
2665 | decl_or_value dv = dv_from_value (val); | |
2666 | ||
2667 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
2668 | { | |
2669 | if (insn) | |
2670 | fprintf (dump_file, "%i: ", INSN_UID (insn)); | |
2671 | else | |
2672 | fprintf (dump_file, "head: "); | |
2673 | print_inline_rtx (dump_file, val, 0); | |
2674 | fputs (" is at ", dump_file); | |
2675 | print_inline_rtx (dump_file, loc, 0); | |
2676 | fputc ('\n', dump_file); | |
2677 | } | |
2678 | ||
2679 | val_reset (set, dv); | |
2680 | ||
09dbcd96 AO |
2681 | gcc_checking_assert (!unsuitable_loc (loc)); |
2682 | ||
b5b8b0ac AO |
2683 | if (REG_P (loc)) |
2684 | { | |
2685 | attrs node, found = NULL; | |
2686 | ||
2687 | for (node = set->regs[REGNO (loc)]; node; node = node->next) | |
2688 | if (dv_is_value_p (node->dv) | |
2689 | && GET_MODE (dv_as_value (node->dv)) == GET_MODE (loc)) | |
2690 | { | |
2691 | found = node; | |
2692 | ||
2693 | /* Map incoming equivalences. ??? Wouldn't it be nice if | |
2694 | we just started sharing the location lists? Maybe a | |
2695 | circular list ending at the value itself or some | |
2696 | such. */ | |
2697 | set_variable_part (set, dv_as_value (node->dv), | |
2698 | dv_from_value (val), node->offset, | |
2699 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, INSERT); | |
2700 | set_variable_part (set, val, node->dv, node->offset, | |
2701 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, INSERT); | |
2702 | } | |
2703 | ||
2704 | /* If we didn't find any equivalence, we need to remember that | |
2705 | this value is held in the named register. */ | |
6f2ffb4b AO |
2706 | if (found) |
2707 | return; | |
b5b8b0ac | 2708 | } |
6f2ffb4b AO |
2709 | /* ??? Attempt to find and merge equivalent MEMs or other |
2710 | expressions too. */ | |
2711 | ||
2712 | val_bind (set, val, loc, false); | |
014a1138 JZ |
2713 | } |
2714 | ||
b8698a0f | 2715 | /* Initialize dataflow set SET to be empty. |
014a1138 JZ |
2716 | VARS_SIZE is the initial size of hash table VARS. */ |
2717 | ||
2718 | static void | |
d24686d7 | 2719 | dataflow_set_init (dataflow_set *set) |
014a1138 JZ |
2720 | { |
2721 | init_attrs_list_set (set->regs); | |
d24686d7 | 2722 | set->vars = shared_hash_copy (empty_shared_hash); |
014a1138 | 2723 | set->stack_adjust = 0; |
b5b8b0ac | 2724 | set->traversed_vars = NULL; |
014a1138 JZ |
2725 | } |
2726 | ||
2727 | /* Delete the contents of dataflow set SET. */ | |
2728 | ||
2729 | static void | |
2730 | dataflow_set_clear (dataflow_set *set) | |
2731 | { | |
2732 | int i; | |
2733 | ||
2734 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
2735 | attrs_list_clear (&set->regs[i]); | |
2736 | ||
d24686d7 JJ |
2737 | shared_hash_destroy (set->vars); |
2738 | set->vars = shared_hash_copy (empty_shared_hash); | |
014a1138 JZ |
2739 | } |
2740 | ||
2741 | /* Copy the contents of dataflow set SRC to DST. */ | |
2742 | ||
2743 | static void | |
2744 | dataflow_set_copy (dataflow_set *dst, dataflow_set *src) | |
2745 | { | |
2746 | int i; | |
2747 | ||
2748 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
2749 | attrs_list_copy (&dst->regs[i], src->regs[i]); | |
2750 | ||
d24686d7 JJ |
2751 | shared_hash_destroy (dst->vars); |
2752 | dst->vars = shared_hash_copy (src->vars); | |
014a1138 JZ |
2753 | dst->stack_adjust = src->stack_adjust; |
2754 | } | |
2755 | ||
2756 | /* Information for merging lists of locations for a given offset of variable. | |
2757 | */ | |
2758 | struct variable_union_info | |
2759 | { | |
2760 | /* Node of the location chain. */ | |
2761 | location_chain lc; | |
2762 | ||
2763 | /* The sum of positions in the input chains. */ | |
2764 | int pos; | |
2765 | ||
7eb3f1f7 | 2766 | /* The position in the chain of DST dataflow set. */ |
014a1138 JZ |
2767 | int pos_dst; |
2768 | }; | |
2769 | ||
7eb3f1f7 JJ |
2770 | /* Buffer for location list sorting and its allocated size. */ |
2771 | static struct variable_union_info *vui_vec; | |
2772 | static int vui_allocated; | |
2773 | ||
014a1138 JZ |
2774 | /* Compare function for qsort, order the structures by POS element. */ |
2775 | ||
2776 | static int | |
2777 | variable_union_info_cmp_pos (const void *n1, const void *n2) | |
2778 | { | |
3d9a9f94 KG |
2779 | const struct variable_union_info *const i1 = |
2780 | (const struct variable_union_info *) n1; | |
2781 | const struct variable_union_info *const i2 = | |
2782 | ( const struct variable_union_info *) n2; | |
014a1138 JZ |
2783 | |
2784 | if (i1->pos != i2->pos) | |
2785 | return i1->pos - i2->pos; | |
b8698a0f | 2786 | |
014a1138 JZ |
2787 | return (i1->pos_dst - i2->pos_dst); |
2788 | } | |
2789 | ||
2790 | /* Compute union of location parts of variable *SLOT and the same variable | |
2791 | from hash table DATA. Compute "sorted" union of the location chains | |
2792 | for common offsets, i.e. the locations of a variable part are sorted by | |
2793 | a priority where the priority is the sum of the positions in the 2 chains | |
2794 | (if a location is only in one list the position in the second list is | |
2795 | defined to be larger than the length of the chains). | |
2796 | When we are updating the location parts the newest location is in the | |
2797 | beginning of the chain, so when we do the described "sorted" union | |
2798 | we keep the newest locations in the beginning. */ | |
2799 | ||
2800 | static int | |
a6590c31 | 2801 | variable_union (variable src, dataflow_set *set) |
014a1138 | 2802 | { |
a6590c31 | 2803 | variable dst; |
013e5ef9 | 2804 | variable_def **dstp; |
014a1138 JZ |
2805 | int i, j, k; |
2806 | ||
b5b8b0ac | 2807 | dstp = shared_hash_find_slot (set->vars, src->dv); |
d24686d7 | 2808 | if (!dstp || !*dstp) |
014a1138 | 2809 | { |
81f2eadb JZ |
2810 | src->refcount++; |
2811 | ||
b5b8b0ac AO |
2812 | dst_can_be_shared = false; |
2813 | if (!dstp) | |
2814 | dstp = shared_hash_find_slot_unshare (&set->vars, src->dv, INSERT); | |
2815 | ||
2816 | *dstp = src; | |
2817 | ||
81f2eadb JZ |
2818 | /* Continue traversing the hash table. */ |
2819 | return 1; | |
014a1138 JZ |
2820 | } |
2821 | else | |
013e5ef9 | 2822 | dst = *dstp; |
014a1138 | 2823 | |
fbc848cc | 2824 | gcc_assert (src->n_var_parts); |
09dbcd96 | 2825 | gcc_checking_assert (src->onepart == dst->onepart); |
014a1138 | 2826 | |
b5b8b0ac AO |
2827 | /* We can combine one-part variables very efficiently, because their |
2828 | entries are in canonical order. */ | |
09dbcd96 | 2829 | if (src->onepart) |
b5b8b0ac AO |
2830 | { |
2831 | location_chain *nodep, dnode, snode; | |
2832 | ||
a6590c31 RG |
2833 | gcc_assert (src->n_var_parts == 1 |
2834 | && dst->n_var_parts == 1); | |
b5b8b0ac AO |
2835 | |
2836 | snode = src->var_part[0].loc_chain; | |
2837 | gcc_assert (snode); | |
2838 | ||
2839 | restart_onepart_unshared: | |
2840 | nodep = &dst->var_part[0].loc_chain; | |
2841 | dnode = *nodep; | |
2842 | gcc_assert (dnode); | |
2843 | ||
2844 | while (snode) | |
2845 | { | |
2846 | int r = dnode ? loc_cmp (dnode->loc, snode->loc) : 1; | |
2847 | ||
2848 | if (r > 0) | |
2849 | { | |
2850 | location_chain nnode; | |
2851 | ||
864ddef7 | 2852 | if (shared_var_p (dst, set->vars)) |
b5b8b0ac AO |
2853 | { |
2854 | dstp = unshare_variable (set, dstp, dst, | |
2855 | VAR_INIT_STATUS_INITIALIZED); | |
013e5ef9 | 2856 | dst = *dstp; |
b5b8b0ac AO |
2857 | goto restart_onepart_unshared; |
2858 | } | |
2859 | ||
7e46899d | 2860 | *nodep = nnode = new location_chain_def; |
b5b8b0ac AO |
2861 | nnode->loc = snode->loc; |
2862 | nnode->init = snode->init; | |
2863 | if (!snode->set_src || MEM_P (snode->set_src)) | |
2864 | nnode->set_src = NULL; | |
2865 | else | |
2866 | nnode->set_src = snode->set_src; | |
2867 | nnode->next = dnode; | |
2868 | dnode = nnode; | |
2869 | } | |
b5b8b0ac | 2870 | else if (r == 0) |
77a74ed7 | 2871 | gcc_checking_assert (rtx_equal_p (dnode->loc, snode->loc)); |
b5b8b0ac AO |
2872 | |
2873 | if (r >= 0) | |
2874 | snode = snode->next; | |
2875 | ||
2876 | nodep = &dnode->next; | |
2877 | dnode = *nodep; | |
2878 | } | |
2879 | ||
b5b8b0ac AO |
2880 | return 1; |
2881 | } | |
2882 | ||
09dbcd96 AO |
2883 | gcc_checking_assert (!src->onepart); |
2884 | ||
014a1138 JZ |
2885 | /* Count the number of location parts, result is K. */ |
2886 | for (i = 0, j = 0, k = 0; | |
2887 | i < src->n_var_parts && j < dst->n_var_parts; k++) | |
2888 | { | |
09dbcd96 | 2889 | if (VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j)) |
014a1138 JZ |
2890 | { |
2891 | i++; | |
2892 | j++; | |
2893 | } | |
09dbcd96 | 2894 | else if (VAR_PART_OFFSET (src, i) < VAR_PART_OFFSET (dst, j)) |
014a1138 JZ |
2895 | i++; |
2896 | else | |
2897 | j++; | |
2898 | } | |
81f2eadb JZ |
2899 | k += src->n_var_parts - i; |
2900 | k += dst->n_var_parts - j; | |
fbc848cc | 2901 | |
014a1138 JZ |
2902 | /* We track only variables whose size is <= MAX_VAR_PARTS bytes |
2903 | thus there are at most MAX_VAR_PARTS different offsets. */ | |
09dbcd96 | 2904 | gcc_checking_assert (dst->onepart ? k == 1 : k <= MAX_VAR_PARTS); |
014a1138 | 2905 | |
864ddef7 | 2906 | if (dst->n_var_parts != k && shared_var_p (dst, set->vars)) |
b5b8b0ac AO |
2907 | { |
2908 | dstp = unshare_variable (set, dstp, dst, VAR_INIT_STATUS_UNKNOWN); | |
013e5ef9 | 2909 | dst = *dstp; |
b5b8b0ac AO |
2910 | } |
2911 | ||
014a1138 JZ |
2912 | i = src->n_var_parts - 1; |
2913 | j = dst->n_var_parts - 1; | |
2914 | dst->n_var_parts = k; | |
2915 | ||
2916 | for (k--; k >= 0; k--) | |
2917 | { | |
81f2eadb | 2918 | location_chain node, node2; |
014a1138 JZ |
2919 | |
2920 | if (i >= 0 && j >= 0 | |
09dbcd96 | 2921 | && VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j)) |
014a1138 JZ |
2922 | { |
2923 | /* Compute the "sorted" union of the chains, i.e. the locations which | |
2924 | are in both chains go first, they are sorted by the sum of | |
2925 | positions in the chains. */ | |
2926 | int dst_l, src_l; | |
2927 | int ii, jj, n; | |
2928 | struct variable_union_info *vui; | |
81f2eadb JZ |
2929 | |
2930 | /* If DST is shared compare the location chains. | |
2931 | If they are different we will modify the chain in DST with | |
2932 | high probability so make a copy of DST. */ | |
864ddef7 | 2933 | if (shared_var_p (dst, set->vars)) |
81f2eadb JZ |
2934 | { |
2935 | for (node = src->var_part[i].loc_chain, | |
2936 | node2 = dst->var_part[j].loc_chain; node && node2; | |
2937 | node = node->next, node2 = node2->next) | |
2938 | { | |
f8cfc6aa JQ |
2939 | if (!((REG_P (node2->loc) |
2940 | && REG_P (node->loc) | |
81f2eadb JZ |
2941 | && REGNO (node2->loc) == REGNO (node->loc)) |
2942 | || rtx_equal_p (node2->loc, node->loc))) | |
e56f9152 MM |
2943 | { |
2944 | if (node2->init < node->init) | |
2945 | node2->init = node->init; | |
2946 | break; | |
2947 | } | |
81f2eadb JZ |
2948 | } |
2949 | if (node || node2) | |
b5b8b0ac AO |
2950 | { |
2951 | dstp = unshare_variable (set, dstp, dst, | |
2952 | VAR_INIT_STATUS_UNKNOWN); | |
2953 | dst = (variable)*dstp; | |
2954 | } | |
81f2eadb JZ |
2955 | } |
2956 | ||
014a1138 JZ |
2957 | src_l = 0; |
2958 | for (node = src->var_part[i].loc_chain; node; node = node->next) | |
2959 | src_l++; | |
2960 | dst_l = 0; | |
2961 | for (node = dst->var_part[j].loc_chain; node; node = node->next) | |
2962 | dst_l++; | |
014a1138 | 2963 | |
7eb3f1f7 | 2964 | if (dst_l == 1) |
014a1138 | 2965 | { |
7eb3f1f7 JJ |
2966 | /* The most common case, much simpler, no qsort is needed. */ |
2967 | location_chain dstnode = dst->var_part[j].loc_chain; | |
2968 | dst->var_part[k].loc_chain = dstnode; | |
c3284718 | 2969 | VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (dst, j); |
7eb3f1f7 JJ |
2970 | node2 = dstnode; |
2971 | for (node = src->var_part[i].loc_chain; node; node = node->next) | |
2972 | if (!((REG_P (dstnode->loc) | |
2973 | && REG_P (node->loc) | |
2974 | && REGNO (dstnode->loc) == REGNO (node->loc)) | |
2975 | || rtx_equal_p (dstnode->loc, node->loc))) | |
2976 | { | |
2977 | location_chain new_node; | |
2978 | ||
2979 | /* Copy the location from SRC. */ | |
7e46899d | 2980 | new_node = new location_chain_def; |
7eb3f1f7 JJ |
2981 | new_node->loc = node->loc; |
2982 | new_node->init = node->init; | |
2983 | if (!node->set_src || MEM_P (node->set_src)) | |
2984 | new_node->set_src = NULL; | |
2985 | else | |
2986 | new_node->set_src = node->set_src; | |
2987 | node2->next = new_node; | |
2988 | node2 = new_node; | |
2989 | } | |
2990 | node2->next = NULL; | |
014a1138 | 2991 | } |
7eb3f1f7 | 2992 | else |
014a1138 | 2993 | { |
7eb3f1f7 | 2994 | if (src_l + dst_l > vui_allocated) |
014a1138 | 2995 | { |
7eb3f1f7 JJ |
2996 | vui_allocated = MAX (vui_allocated * 2, src_l + dst_l); |
2997 | vui_vec = XRESIZEVEC (struct variable_union_info, vui_vec, | |
2998 | vui_allocated); | |
2999 | } | |
3000 | vui = vui_vec; | |
3001 | ||
3002 | /* Fill in the locations from DST. */ | |
3003 | for (node = dst->var_part[j].loc_chain, jj = 0; node; | |
3004 | node = node->next, jj++) | |
3005 | { | |
3006 | vui[jj].lc = node; | |
3007 | vui[jj].pos_dst = jj; | |
3008 | ||
3009 | /* Pos plus value larger than a sum of 2 valid positions. */ | |
3010 | vui[jj].pos = jj + src_l + dst_l; | |
3011 | } | |
3012 | ||
3013 | /* Fill in the locations from SRC. */ | |
3014 | n = dst_l; | |
3015 | for (node = src->var_part[i].loc_chain, ii = 0; node; | |
3016 | node = node->next, ii++) | |
3017 | { | |
3018 | /* Find location from NODE. */ | |
3019 | for (jj = 0; jj < dst_l; jj++) | |
014a1138 | 3020 | { |
7eb3f1f7 JJ |
3021 | if ((REG_P (vui[jj].lc->loc) |
3022 | && REG_P (node->loc) | |
3023 | && REGNO (vui[jj].lc->loc) == REGNO (node->loc)) | |
3024 | || rtx_equal_p (vui[jj].lc->loc, node->loc)) | |
3025 | { | |
3026 | vui[jj].pos = jj + ii; | |
3027 | break; | |
3028 | } | |
3029 | } | |
3030 | if (jj >= dst_l) /* The location has not been found. */ | |
3031 | { | |
3032 | location_chain new_node; | |
3033 | ||
3034 | /* Copy the location from SRC. */ | |
7e46899d | 3035 | new_node = new location_chain_def; |
7eb3f1f7 JJ |
3036 | new_node->loc = node->loc; |
3037 | new_node->init = node->init; | |
3038 | if (!node->set_src || MEM_P (node->set_src)) | |
3039 | new_node->set_src = NULL; | |
3040 | else | |
3041 | new_node->set_src = node->set_src; | |
3042 | vui[n].lc = new_node; | |
3043 | vui[n].pos_dst = src_l + dst_l; | |
3044 | vui[n].pos = ii + src_l + dst_l; | |
3045 | n++; | |
014a1138 JZ |
3046 | } |
3047 | } | |
7eb3f1f7 JJ |
3048 | |
3049 | if (dst_l == 2) | |
014a1138 | 3050 | { |
7eb3f1f7 JJ |
3051 | /* Special case still very common case. For dst_l == 2 |
3052 | all entries dst_l ... n-1 are sorted, with for i >= dst_l | |
3053 | vui[i].pos == i + src_l + dst_l. */ | |
3054 | if (vui[0].pos > vui[1].pos) | |
3055 | { | |
3056 | /* Order should be 1, 0, 2... */ | |
3057 | dst->var_part[k].loc_chain = vui[1].lc; | |
3058 | vui[1].lc->next = vui[0].lc; | |
3059 | if (n >= 3) | |
3060 | { | |
3061 | vui[0].lc->next = vui[2].lc; | |
3062 | vui[n - 1].lc->next = NULL; | |
3063 | } | |
3064 | else | |
3065 | vui[0].lc->next = NULL; | |
3066 | ii = 3; | |
3067 | } | |
62760ffd | 3068 | else |
7eb3f1f7 JJ |
3069 | { |
3070 | dst->var_part[k].loc_chain = vui[0].lc; | |
3071 | if (n >= 3 && vui[2].pos < vui[1].pos) | |
3072 | { | |
3073 | /* Order should be 0, 2, 1, 3... */ | |
3074 | vui[0].lc->next = vui[2].lc; | |
3075 | vui[2].lc->next = vui[1].lc; | |
3076 | if (n >= 4) | |
3077 | { | |
3078 | vui[1].lc->next = vui[3].lc; | |
3079 | vui[n - 1].lc->next = NULL; | |
3080 | } | |
3081 | else | |
3082 | vui[1].lc->next = NULL; | |
3083 | ii = 4; | |
3084 | } | |
3085 | else | |
3086 | { | |
3087 | /* Order should be 0, 1, 2... */ | |
3088 | ii = 1; | |
3089 | vui[n - 1].lc->next = NULL; | |
3090 | } | |
3091 | } | |
3092 | for (; ii < n; ii++) | |
3093 | vui[ii - 1].lc->next = vui[ii].lc; | |
3094 | } | |
3095 | else | |
3096 | { | |
3097 | qsort (vui, n, sizeof (struct variable_union_info), | |
3098 | variable_union_info_cmp_pos); | |
3099 | ||
3100 | /* Reconnect the nodes in sorted order. */ | |
3101 | for (ii = 1; ii < n; ii++) | |
3102 | vui[ii - 1].lc->next = vui[ii].lc; | |
3103 | vui[n - 1].lc->next = NULL; | |
3104 | dst->var_part[k].loc_chain = vui[0].lc; | |
014a1138 | 3105 | } |
014a1138 | 3106 | |
09dbcd96 | 3107 | VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (dst, j); |
7eb3f1f7 | 3108 | } |
014a1138 JZ |
3109 | i--; |
3110 | j--; | |
3111 | } | |
3112 | else if ((i >= 0 && j >= 0 | |
09dbcd96 | 3113 | && VAR_PART_OFFSET (src, i) < VAR_PART_OFFSET (dst, j)) |
014a1138 JZ |
3114 | || i < 0) |
3115 | { | |
3116 | dst->var_part[k] = dst->var_part[j]; | |
3117 | j--; | |
3118 | } | |
3119 | else if ((i >= 0 && j >= 0 | |
09dbcd96 | 3120 | && VAR_PART_OFFSET (src, i) > VAR_PART_OFFSET (dst, j)) |
014a1138 JZ |
3121 | || j < 0) |
3122 | { | |
11599d14 | 3123 | location_chain *nextp; |
014a1138 JZ |
3124 | |
3125 | /* Copy the chain from SRC. */ | |
11599d14 | 3126 | nextp = &dst->var_part[k].loc_chain; |
014a1138 JZ |
3127 | for (node = src->var_part[i].loc_chain; node; node = node->next) |
3128 | { | |
3129 | location_chain new_lc; | |
3130 | ||
7e46899d | 3131 | new_lc = new location_chain_def; |
014a1138 | 3132 | new_lc->next = NULL; |
62760ffd CT |
3133 | new_lc->init = node->init; |
3134 | if (!node->set_src || MEM_P (node->set_src)) | |
3135 | new_lc->set_src = NULL; | |
3136 | else | |
3137 | new_lc->set_src = node->set_src; | |
014a1138 JZ |
3138 | new_lc->loc = node->loc; |
3139 | ||
11599d14 JZ |
3140 | *nextp = new_lc; |
3141 | nextp = &new_lc->next; | |
014a1138 JZ |
3142 | } |
3143 | ||
09dbcd96 | 3144 | VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (src, i); |
014a1138 JZ |
3145 | i--; |
3146 | } | |
864ddef7 | 3147 | dst->var_part[k].cur_loc = NULL; |
014a1138 JZ |
3148 | } |
3149 | ||
7eb3f1f7 JJ |
3150 | if (flag_var_tracking_uninit) |
3151 | for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++) | |
3152 | { | |
3153 | location_chain node, node2; | |
3154 | for (node = src->var_part[i].loc_chain; node; node = node->next) | |
3155 | for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next) | |
3156 | if (rtx_equal_p (node->loc, node2->loc)) | |
3157 | { | |
3158 | if (node->init > node2->init) | |
3159 | node2->init = node->init; | |
3160 | } | |
3161 | } | |
62760ffd | 3162 | |
014a1138 JZ |
3163 | /* Continue traversing the hash table. */ |
3164 | return 1; | |
3165 | } | |
3166 | ||
3167 | /* Compute union of dataflow sets SRC and DST and store it to DST. */ | |
3168 | ||
3169 | static void | |
3170 | dataflow_set_union (dataflow_set *dst, dataflow_set *src) | |
3171 | { | |
3172 | int i; | |
3173 | ||
3174 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
3175 | attrs_list_union (&dst->regs[i], src->regs[i]); | |
3176 | ||
d24686d7 JJ |
3177 | if (dst->vars == empty_shared_hash) |
3178 | { | |
3179 | shared_hash_destroy (dst->vars); | |
3180 | dst->vars = shared_hash_copy (src->vars); | |
d24686d7 JJ |
3181 | } |
3182 | else | |
a6590c31 | 3183 | { |
013e5ef9 | 3184 | variable_iterator_type hi; |
a6590c31 RG |
3185 | variable var; |
3186 | ||
c203e8a7 | 3187 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (src->vars), |
013e5ef9 | 3188 | var, variable, hi) |
a6590c31 RG |
3189 | variable_union (var, dst); |
3190 | } | |
014a1138 JZ |
3191 | } |
3192 | ||
b5b8b0ac AO |
3193 | /* Whether the value is currently being expanded. */ |
3194 | #define VALUE_RECURSED_INTO(x) \ | |
0ca5af51 | 3195 | (RTL_FLAG_CHECK2 ("VALUE_RECURSED_INTO", (x), VALUE, DEBUG_EXPR)->used) |
09dbcd96 AO |
3196 | |
3197 | /* Whether no expansion was found, saving useless lookups. | |
3198 | It must only be set when VALUE_CHANGED is clear. */ | |
3199 | #define NO_LOC_P(x) \ | |
3200 | (RTL_FLAG_CHECK2 ("NO_LOC_P", (x), VALUE, DEBUG_EXPR)->return_val) | |
3201 | ||
3202 | /* Whether cur_loc in the value needs to be (re)computed. */ | |
b5b8b0ac AO |
3203 | #define VALUE_CHANGED(x) \ |
3204 | (RTL_FLAG_CHECK1 ("VALUE_CHANGED", (x), VALUE)->frame_related) | |
09dbcd96 | 3205 | /* Whether cur_loc in the decl needs to be (re)computed. */ |
b5b8b0ac | 3206 | #define DECL_CHANGED(x) TREE_VISITED (x) |
014a1138 | 3207 | |
09dbcd96 AO |
3208 | /* Record (if NEWV) that DV needs to have its cur_loc recomputed. For |
3209 | user DECLs, this means they're in changed_variables. Values and | |
3210 | debug exprs may be left with this flag set if no user variable | |
3211 | requires them to be evaluated. */ | |
014a1138 | 3212 | |
b5b8b0ac AO |
3213 | static inline void |
3214 | set_dv_changed (decl_or_value dv, bool newv) | |
3215 | { | |
09dbcd96 AO |
3216 | switch (dv_onepart_p (dv)) |
3217 | { | |
3218 | case ONEPART_VALUE: | |
3219 | if (newv) | |
3220 | NO_LOC_P (dv_as_value (dv)) = false; | |
3221 | VALUE_CHANGED (dv_as_value (dv)) = newv; | |
3222 | break; | |
3223 | ||
3224 | case ONEPART_DEXPR: | |
3225 | if (newv) | |
3226 | NO_LOC_P (DECL_RTL_KNOWN_SET (dv_as_decl (dv))) = false; | |
3227 | /* Fall through... */ | |
3228 | ||
3229 | default: | |
3230 | DECL_CHANGED (dv_as_decl (dv)) = newv; | |
3231 | break; | |
3232 | } | |
014a1138 JZ |
3233 | } |
3234 | ||
09dbcd96 | 3235 | /* Return true if DV needs to have its cur_loc recomputed. */ |
014a1138 | 3236 | |
b5b8b0ac AO |
3237 | static inline bool |
3238 | dv_changed_p (decl_or_value dv) | |
014a1138 | 3239 | { |
b5b8b0ac AO |
3240 | return (dv_is_value_p (dv) |
3241 | ? VALUE_CHANGED (dv_as_value (dv)) | |
3242 | : DECL_CHANGED (dv_as_decl (dv))); | |
014a1138 JZ |
3243 | } |
3244 | ||
60d7a09b | 3245 | /* Return a location list node whose loc is rtx_equal to LOC, in the |
b5b8b0ac | 3246 | location list of a one-part variable or value VAR, or in that of |
b933b33a AO |
3247 | any values recursively mentioned in the location lists. VARS must |
3248 | be in star-canonical form. */ | |
014a1138 | 3249 | |
b5b8b0ac | 3250 | static location_chain |
c203e8a7 | 3251 | find_loc_in_1pdv (rtx loc, variable var, variable_table_type *vars) |
014a1138 | 3252 | { |
b5b8b0ac | 3253 | location_chain node; |
13077931 | 3254 | enum rtx_code loc_code; |
014a1138 | 3255 | |
b5b8b0ac | 3256 | if (!var) |
b933b33a | 3257 | return NULL; |
014a1138 | 3258 | |
09dbcd96 | 3259 | gcc_checking_assert (var->onepart); |
014a1138 | 3260 | |
b5b8b0ac | 3261 | if (!var->n_var_parts) |
b933b33a | 3262 | return NULL; |
014a1138 | 3263 | |
77a74ed7 | 3264 | gcc_checking_assert (loc != dv_as_opaque (var->dv)); |
014a1138 | 3265 | |
13077931 | 3266 | loc_code = GET_CODE (loc); |
b5b8b0ac | 3267 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
13077931 | 3268 | { |
b933b33a AO |
3269 | decl_or_value dv; |
3270 | variable rvar; | |
3271 | ||
13077931 JJ |
3272 | if (GET_CODE (node->loc) != loc_code) |
3273 | { | |
3274 | if (GET_CODE (node->loc) != VALUE) | |
3275 | continue; | |
3276 | } | |
3277 | else if (loc == node->loc) | |
b933b33a | 3278 | return node; |
13077931 JJ |
3279 | else if (loc_code != VALUE) |
3280 | { | |
3281 | if (rtx_equal_p (loc, node->loc)) | |
b933b33a | 3282 | return node; |
13077931 JJ |
3283 | continue; |
3284 | } | |
b5b8b0ac | 3285 | |
b933b33a AO |
3286 | /* Since we're in star-canonical form, we don't need to visit |
3287 | non-canonical nodes: one-part variables and non-canonical | |
3288 | values would only point back to the canonical node. */ | |
3289 | if (dv_is_value_p (var->dv) | |
3290 | && !canon_value_cmp (node->loc, dv_as_value (var->dv))) | |
3291 | { | |
3292 | /* Skip all subsequent VALUEs. */ | |
3293 | while (node->next && GET_CODE (node->next->loc) == VALUE) | |
13077931 | 3294 | { |
b933b33a | 3295 | node = node->next; |
77a74ed7 NF |
3296 | gcc_checking_assert (!canon_value_cmp (node->loc, |
3297 | dv_as_value (var->dv))); | |
b933b33a AO |
3298 | if (loc == node->loc) |
3299 | return node; | |
13077931 | 3300 | } |
b933b33a | 3301 | continue; |
13077931 | 3302 | } |
014a1138 | 3303 | |
77a74ed7 NF |
3304 | gcc_checking_assert (node == var->var_part[0].loc_chain); |
3305 | gcc_checking_assert (!node->next); | |
b933b33a AO |
3306 | |
3307 | dv = dv_from_value (node->loc); | |
c203e8a7 | 3308 | rvar = vars->find_with_hash (dv, dv_htab_hash (dv)); |
b933b33a | 3309 | return find_loc_in_1pdv (loc, rvar, vars); |
0fa43fb7 AO |
3310 | } |
3311 | ||
09dbcd96 AO |
3312 | /* ??? Gotta look in cselib_val locations too. */ |
3313 | ||
b933b33a | 3314 | return NULL; |
b5b8b0ac | 3315 | } |
014a1138 | 3316 | |
b5b8b0ac AO |
3317 | /* Hash table iteration argument passed to variable_merge. */ |
3318 | struct dfset_merge | |
014a1138 | 3319 | { |
b5b8b0ac AO |
3320 | /* The set in which the merge is to be inserted. */ |
3321 | dataflow_set *dst; | |
3322 | /* The set that we're iterating in. */ | |
3323 | dataflow_set *cur; | |
3324 | /* The set that may contain the other dv we are to merge with. */ | |
3325 | dataflow_set *src; | |
3326 | /* Number of onepart dvs in src. */ | |
3327 | int src_onepart_cnt; | |
3328 | }; | |
014a1138 | 3329 | |
b5b8b0ac AO |
3330 | /* Insert LOC in *DNODE, if it's not there yet. The list must be in |
3331 | loc_cmp order, and it is maintained as such. */ | |
014a1138 JZ |
3332 | |
3333 | static void | |
b5b8b0ac AO |
3334 | insert_into_intersection (location_chain *nodep, rtx loc, |
3335 | enum var_init_status status) | |
014a1138 | 3336 | { |
b5b8b0ac AO |
3337 | location_chain node; |
3338 | int r; | |
014a1138 | 3339 | |
b5b8b0ac AO |
3340 | for (node = *nodep; node; nodep = &node->next, node = *nodep) |
3341 | if ((r = loc_cmp (node->loc, loc)) == 0) | |
3342 | { | |
3343 | node->init = MIN (node->init, status); | |
3344 | return; | |
3345 | } | |
3346 | else if (r > 0) | |
3347 | break; | |
014a1138 | 3348 | |
7e46899d | 3349 | node = new location_chain_def; |
b5b8b0ac AO |
3350 | |
3351 | node->loc = loc; | |
3352 | node->set_src = NULL; | |
3353 | node->init = status; | |
3354 | node->next = *nodep; | |
3355 | *nodep = node; | |
014a1138 JZ |
3356 | } |
3357 | ||
09dbcd96 | 3358 | /* Insert in DEST the intersection of the locations present in both |
b5b8b0ac AO |
3359 | S1NODE and S2VAR, directly or indirectly. S1NODE is from a |
3360 | variable in DSM->cur, whereas S2VAR is from DSM->src. dvar is in | |
3361 | DSM->dst. */ | |
014a1138 | 3362 | |
b5b8b0ac AO |
3363 | static void |
3364 | intersect_loc_chains (rtx val, location_chain *dest, struct dfset_merge *dsm, | |
3365 | location_chain s1node, variable s2var) | |
014a1138 | 3366 | { |
b5b8b0ac AO |
3367 | dataflow_set *s1set = dsm->cur; |
3368 | dataflow_set *s2set = dsm->src; | |
3369 | location_chain found; | |
014a1138 | 3370 | |
bb9862c6 JJ |
3371 | if (s2var) |
3372 | { | |
3373 | location_chain s2node; | |
3374 | ||
09dbcd96 | 3375 | gcc_checking_assert (s2var->onepart); |
bb9862c6 JJ |
3376 | |
3377 | if (s2var->n_var_parts) | |
3378 | { | |
bb9862c6 JJ |
3379 | s2node = s2var->var_part[0].loc_chain; |
3380 | ||
3381 | for (; s1node && s2node; | |
3382 | s1node = s1node->next, s2node = s2node->next) | |
3383 | if (s1node->loc != s2node->loc) | |
3384 | break; | |
3385 | else if (s1node->loc == val) | |
3386 | continue; | |
3387 | else | |
3388 | insert_into_intersection (dest, s1node->loc, | |
3389 | MIN (s1node->init, s2node->init)); | |
3390 | } | |
3391 | } | |
3392 | ||
b5b8b0ac | 3393 | for (; s1node; s1node = s1node->next) |
014a1138 | 3394 | { |
b5b8b0ac AO |
3395 | if (s1node->loc == val) |
3396 | continue; | |
3397 | ||
3398 | if ((found = find_loc_in_1pdv (s1node->loc, s2var, | |
3399 | shared_hash_htab (s2set->vars)))) | |
014a1138 | 3400 | { |
b5b8b0ac AO |
3401 | insert_into_intersection (dest, s1node->loc, |
3402 | MIN (s1node->init, found->init)); | |
3403 | continue; | |
014a1138 | 3404 | } |
b5b8b0ac AO |
3405 | |
3406 | if (GET_CODE (s1node->loc) == VALUE | |
3407 | && !VALUE_RECURSED_INTO (s1node->loc)) | |
014a1138 | 3408 | { |
b5b8b0ac AO |
3409 | decl_or_value dv = dv_from_value (s1node->loc); |
3410 | variable svar = shared_hash_find (s1set->vars, dv); | |
3411 | if (svar) | |
3412 | { | |
3413 | if (svar->n_var_parts == 1) | |
3414 | { | |
3415 | VALUE_RECURSED_INTO (s1node->loc) = true; | |
3416 | intersect_loc_chains (val, dest, dsm, | |
3417 | svar->var_part[0].loc_chain, | |
3418 | s2var); | |
3419 | VALUE_RECURSED_INTO (s1node->loc) = false; | |
3420 | } | |
3421 | } | |
014a1138 | 3422 | } |
014a1138 | 3423 | |
09dbcd96 AO |
3424 | /* ??? gotta look in cselib_val locations too. */ |
3425 | ||
b5b8b0ac AO |
3426 | /* ??? if the location is equivalent to any location in src, |
3427 | searched recursively | |
014a1138 | 3428 | |
b5b8b0ac | 3429 | add to dst the values needed to represent the equivalence |
014a1138 | 3430 | |
b5b8b0ac AO |
3431 | telling whether locations S is equivalent to another dv's |
3432 | location list: | |
014a1138 | 3433 | |
b5b8b0ac | 3434 | for each location D in the list |
014a1138 | 3435 | |
b5b8b0ac | 3436 | if S and D satisfy rtx_equal_p, then it is present |
014a1138 | 3437 | |
b5b8b0ac | 3438 | else if D is a value, recurse without cycles |
ac3bfd86 | 3439 | |
b5b8b0ac | 3440 | else if S and D have the same CODE and MODE |
af931390 | 3441 | |
b5b8b0ac | 3442 | for each operand oS and the corresponding oD |
014a1138 | 3443 | |
b5b8b0ac | 3444 | if oS and oD are not equivalent, then S an D are not equivalent |
014a1138 | 3445 | |
b5b8b0ac | 3446 | else if they are RTX vectors |
014a1138 | 3447 | |
b5b8b0ac AO |
3448 | if any vector oS element is not equivalent to its respective oD, |
3449 | then S and D are not equivalent | |
014a1138 | 3450 | |
b5b8b0ac AO |
3451 | */ |
3452 | ||
3453 | ||
3454 | } | |
014a1138 JZ |
3455 | } |
3456 | ||
b5b8b0ac AO |
3457 | /* Return -1 if X should be before Y in a location list for a 1-part |
3458 | variable, 1 if Y should be before X, and 0 if they're equivalent | |
3459 | and should not appear in the list. */ | |
ca787200 | 3460 | |
b5b8b0ac AO |
3461 | static int |
3462 | loc_cmp (rtx x, rtx y) | |
ca787200 | 3463 | { |
b5b8b0ac AO |
3464 | int i, j, r; |
3465 | RTX_CODE code = GET_CODE (x); | |
3466 | const char *fmt; | |
ca787200 | 3467 | |
b5b8b0ac AO |
3468 | if (x == y) |
3469 | return 0; | |
ca787200 | 3470 | |
b5b8b0ac | 3471 | if (REG_P (x)) |
ca787200 | 3472 | { |
b5b8b0ac AO |
3473 | if (!REG_P (y)) |
3474 | return -1; | |
3475 | gcc_assert (GET_MODE (x) == GET_MODE (y)); | |
3476 | if (REGNO (x) == REGNO (y)) | |
3477 | return 0; | |
3478 | else if (REGNO (x) < REGNO (y)) | |
3479 | return -1; | |
3480 | else | |
3481 | return 1; | |
ca787200 | 3482 | } |
b5b8b0ac AO |
3483 | |
3484 | if (REG_P (y)) | |
3485 | return 1; | |
3486 | ||
3487 | if (MEM_P (x)) | |
ca787200 | 3488 | { |
b5b8b0ac AO |
3489 | if (!MEM_P (y)) |
3490 | return -1; | |
3491 | gcc_assert (GET_MODE (x) == GET_MODE (y)); | |
3492 | return loc_cmp (XEXP (x, 0), XEXP (y, 0)); | |
ca787200 | 3493 | } |
ca787200 | 3494 | |
b5b8b0ac AO |
3495 | if (MEM_P (y)) |
3496 | return 1; | |
ca787200 | 3497 | |
b5b8b0ac AO |
3498 | if (GET_CODE (x) == VALUE) |
3499 | { | |
3500 | if (GET_CODE (y) != VALUE) | |
3501 | return -1; | |
0c5863c2 JJ |
3502 | /* Don't assert the modes are the same, that is true only |
3503 | when not recursing. (subreg:QI (value:SI 1:1) 0) | |
3504 | and (subreg:QI (value:DI 2:2) 0) can be compared, | |
3505 | even when the modes are different. */ | |
b5b8b0ac AO |
3506 | if (canon_value_cmp (x, y)) |
3507 | return -1; | |
3508 | else | |
3509 | return 1; | |
3510 | } | |
ca787200 | 3511 | |
b5b8b0ac AO |
3512 | if (GET_CODE (y) == VALUE) |
3513 | return 1; | |
ca787200 | 3514 | |
09dbcd96 AO |
3515 | /* Entry value is the least preferable kind of expression. */ |
3516 | if (GET_CODE (x) == ENTRY_VALUE) | |
3517 | { | |
3518 | if (GET_CODE (y) != ENTRY_VALUE) | |
3519 | return 1; | |
3520 | gcc_assert (GET_MODE (x) == GET_MODE (y)); | |
7fefb1d1 | 3521 | return loc_cmp (ENTRY_VALUE_EXP (x), ENTRY_VALUE_EXP (y)); |
09dbcd96 AO |
3522 | } |
3523 | ||
3524 | if (GET_CODE (y) == ENTRY_VALUE) | |
3525 | return -1; | |
3526 | ||
b5b8b0ac AO |
3527 | if (GET_CODE (x) == GET_CODE (y)) |
3528 | /* Compare operands below. */; | |
3529 | else if (GET_CODE (x) < GET_CODE (y)) | |
3530 | return -1; | |
3531 | else | |
3532 | return 1; | |
3533 | ||
3534 | gcc_assert (GET_MODE (x) == GET_MODE (y)); | |
3535 | ||
864ddef7 JJ |
3536 | if (GET_CODE (x) == DEBUG_EXPR) |
3537 | { | |
3538 | if (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x)) | |
3539 | < DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y))) | |
3540 | return -1; | |
77a74ed7 NF |
3541 | gcc_checking_assert (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x)) |
3542 | > DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y))); | |
864ddef7 JJ |
3543 | return 1; |
3544 | } | |
3545 | ||
b5b8b0ac AO |
3546 | fmt = GET_RTX_FORMAT (code); |
3547 | for (i = 0; i < GET_RTX_LENGTH (code); i++) | |
3548 | switch (fmt[i]) | |
3549 | { | |
3550 | case 'w': | |
3551 | if (XWINT (x, i) == XWINT (y, i)) | |
3552 | break; | |
3553 | else if (XWINT (x, i) < XWINT (y, i)) | |
3554 | return -1; | |
3555 | else | |
3556 | return 1; | |
3557 | ||
3558 | case 'n': | |
3559 | case 'i': | |
3560 | if (XINT (x, i) == XINT (y, i)) | |
3561 | break; | |
3562 | else if (XINT (x, i) < XINT (y, i)) | |
3563 | return -1; | |
3564 | else | |
3565 | return 1; | |
3566 | ||
3567 | case 'V': | |
3568 | case 'E': | |
3569 | /* Compare the vector length first. */ | |
3570 | if (XVECLEN (x, i) == XVECLEN (y, i)) | |
3571 | /* Compare the vectors elements. */; | |
3572 | else if (XVECLEN (x, i) < XVECLEN (y, i)) | |
3573 | return -1; | |
3574 | else | |
3575 | return 1; | |
3576 | ||
3577 | for (j = 0; j < XVECLEN (x, i); j++) | |
3578 | if ((r = loc_cmp (XVECEXP (x, i, j), | |
3579 | XVECEXP (y, i, j)))) | |
3580 | return r; | |
3581 | break; | |
3582 | ||
3583 | case 'e': | |
3584 | if ((r = loc_cmp (XEXP (x, i), XEXP (y, i)))) | |
3585 | return r; | |
3586 | break; | |
3587 | ||
3588 | case 'S': | |
3589 | case 's': | |
3590 | if (XSTR (x, i) == XSTR (y, i)) | |
3591 | break; | |
3592 | if (!XSTR (x, i)) | |
3593 | return -1; | |
3594 | if (!XSTR (y, i)) | |
3595 | return 1; | |
3596 | if ((r = strcmp (XSTR (x, i), XSTR (y, i))) == 0) | |
3597 | break; | |
3598 | else if (r < 0) | |
3599 | return -1; | |
3600 | else | |
3601 | return 1; | |
3602 | ||
3603 | case 'u': | |
3604 | /* These are just backpointers, so they don't matter. */ | |
3605 | break; | |
3606 | ||
3607 | case '0': | |
3608 | case 't': | |
3609 | break; | |
3610 | ||
3611 | /* It is believed that rtx's at this level will never | |
3612 | contain anything but integers and other rtx's, | |
3613 | except for within LABEL_REFs and SYMBOL_REFs. */ | |
3614 | default: | |
3615 | gcc_unreachable (); | |
3616 | } | |
807e902e KZ |
3617 | if (CONST_WIDE_INT_P (x)) |
3618 | { | |
3619 | /* Compare the vector length first. */ | |
3620 | if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y)) | |
3621 | return 1; | |
3622 | else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y)) | |
3623 | return -1; | |
3624 | ||
3625 | /* Compare the vectors elements. */; | |
3626 | for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--) | |
3627 | { | |
3628 | if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j)) | |
3629 | return -1; | |
3630 | if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j)) | |
3631 | return 1; | |
3632 | } | |
3633 | } | |
b5b8b0ac AO |
3634 | |
3635 | return 0; | |
3636 | } | |
3637 | ||
1feb8238 | 3638 | #if ENABLE_CHECKING |
b5b8b0ac AO |
3639 | /* Check the order of entries in one-part variables. */ |
3640 | ||
013e5ef9 LC |
3641 | int |
3642 | canonicalize_loc_order_check (variable_def **slot, | |
3643 | dataflow_set *data ATTRIBUTE_UNUSED) | |
b5b8b0ac | 3644 | { |
013e5ef9 | 3645 | variable var = *slot; |
b5b8b0ac AO |
3646 | location_chain node, next; |
3647 | ||
864ddef7 JJ |
3648 | #ifdef ENABLE_RTL_CHECKING |
3649 | int i; | |
3650 | for (i = 0; i < var->n_var_parts; i++) | |
3651 | gcc_assert (var->var_part[0].cur_loc == NULL); | |
09dbcd96 | 3652 | gcc_assert (!var->in_changed_variables); |
864ddef7 JJ |
3653 | #endif |
3654 | ||
09dbcd96 | 3655 | if (!var->onepart) |
b5b8b0ac AO |
3656 | return 1; |
3657 | ||
3658 | gcc_assert (var->n_var_parts == 1); | |
3659 | node = var->var_part[0].loc_chain; | |
3660 | gcc_assert (node); | |
3661 | ||
3662 | while ((next = node->next)) | |
3663 | { | |
3664 | gcc_assert (loc_cmp (node->loc, next->loc) < 0); | |
3665 | node = next; | |
3666 | } | |
3667 | ||
3668 | return 1; | |
3669 | } | |
3670 | #endif | |
3671 | ||
3672 | /* Mark with VALUE_RECURSED_INTO values that have neighbors that are | |
3673 | more likely to be chosen as canonical for an equivalence set. | |
3674 | Ensure less likely values can reach more likely neighbors, making | |
3675 | the connections bidirectional. */ | |
3676 | ||
013e5ef9 LC |
3677 | int |
3678 | canonicalize_values_mark (variable_def **slot, dataflow_set *set) | |
b5b8b0ac | 3679 | { |
013e5ef9 | 3680 | variable var = *slot; |
b5b8b0ac AO |
3681 | decl_or_value dv = var->dv; |
3682 | rtx val; | |
3683 | location_chain node; | |
3684 | ||
3685 | if (!dv_is_value_p (dv)) | |
3686 | return 1; | |
3687 | ||
7a40b8b1 | 3688 | gcc_checking_assert (var->n_var_parts == 1); |
b5b8b0ac AO |
3689 | |
3690 | val = dv_as_value (dv); | |
3691 | ||
3692 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
3693 | if (GET_CODE (node->loc) == VALUE) | |
3694 | { | |
3695 | if (canon_value_cmp (node->loc, val)) | |
3696 | VALUE_RECURSED_INTO (val) = true; | |
3697 | else | |
3698 | { | |
3699 | decl_or_value odv = dv_from_value (node->loc); | |
013e5ef9 LC |
3700 | variable_def **oslot; |
3701 | oslot = shared_hash_find_slot_noinsert (set->vars, odv); | |
b5b8b0ac | 3702 | |
649beb33 JL |
3703 | set_slot_part (set, val, oslot, odv, 0, |
3704 | node->init, NULL_RTX); | |
b5b8b0ac AO |
3705 | |
3706 | VALUE_RECURSED_INTO (node->loc) = true; | |
3707 | } | |
3708 | } | |
3709 | ||
3710 | return 1; | |
3711 | } | |
3712 | ||
3713 | /* Remove redundant entries from equivalence lists in onepart | |
3714 | variables, canonicalizing equivalence sets into star shapes. */ | |
3715 | ||
013e5ef9 LC |
3716 | int |
3717 | canonicalize_values_star (variable_def **slot, dataflow_set *set) | |
b5b8b0ac | 3718 | { |
013e5ef9 | 3719 | variable var = *slot; |
b5b8b0ac AO |
3720 | decl_or_value dv = var->dv; |
3721 | location_chain node; | |
3722 | decl_or_value cdv; | |
3723 | rtx val, cval; | |
013e5ef9 | 3724 | variable_def **cslot; |
b5b8b0ac AO |
3725 | bool has_value; |
3726 | bool has_marks; | |
3727 | ||
09dbcd96 | 3728 | if (!var->onepart) |
b5b8b0ac AO |
3729 | return 1; |
3730 | ||
7a40b8b1 | 3731 | gcc_checking_assert (var->n_var_parts == 1); |
b5b8b0ac AO |
3732 | |
3733 | if (dv_is_value_p (dv)) | |
3734 | { | |
3735 | cval = dv_as_value (dv); | |
3736 | if (!VALUE_RECURSED_INTO (cval)) | |
3737 | return 1; | |
3738 | VALUE_RECURSED_INTO (cval) = false; | |
3739 | } | |
3740 | else | |
3741 | cval = NULL_RTX; | |
3742 | ||
3743 | restart: | |
3744 | val = cval; | |
3745 | has_value = false; | |
3746 | has_marks = false; | |
3747 | ||
3748 | gcc_assert (var->n_var_parts == 1); | |
3749 | ||
3750 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
3751 | if (GET_CODE (node->loc) == VALUE) | |
3752 | { | |
3753 | has_value = true; | |
3754 | if (VALUE_RECURSED_INTO (node->loc)) | |
3755 | has_marks = true; | |
3756 | if (canon_value_cmp (node->loc, cval)) | |
3757 | cval = node->loc; | |
3758 | } | |
3759 | ||
3760 | if (!has_value) | |
3761 | return 1; | |
3762 | ||
3763 | if (cval == val) | |
3764 | { | |
3765 | if (!has_marks || dv_is_decl_p (dv)) | |
3766 | return 1; | |
3767 | ||
3768 | /* Keep it marked so that we revisit it, either after visiting a | |
3769 | child node, or after visiting a new parent that might be | |
3770 | found out. */ | |
3771 | VALUE_RECURSED_INTO (val) = true; | |
3772 | ||
3773 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
3774 | if (GET_CODE (node->loc) == VALUE | |
3775 | && VALUE_RECURSED_INTO (node->loc)) | |
3776 | { | |
3777 | cval = node->loc; | |
3778 | restart_with_cval: | |
3779 | VALUE_RECURSED_INTO (cval) = false; | |
3780 | dv = dv_from_value (cval); | |
3781 | slot = shared_hash_find_slot_noinsert (set->vars, dv); | |
3782 | if (!slot) | |
3783 | { | |
3784 | gcc_assert (dv_is_decl_p (var->dv)); | |
3785 | /* The canonical value was reset and dropped. | |
3786 | Remove it. */ | |
3787 | clobber_variable_part (set, NULL, var->dv, 0, NULL); | |
3788 | return 1; | |
3789 | } | |
013e5ef9 | 3790 | var = *slot; |
b5b8b0ac AO |
3791 | gcc_assert (dv_is_value_p (var->dv)); |
3792 | if (var->n_var_parts == 0) | |
3793 | return 1; | |
3794 | gcc_assert (var->n_var_parts == 1); | |
3795 | goto restart; | |
3796 | } | |
3797 | ||
3798 | VALUE_RECURSED_INTO (val) = false; | |
3799 | ||
3800 | return 1; | |
3801 | } | |
3802 | ||
3803 | /* Push values to the canonical one. */ | |
3804 | cdv = dv_from_value (cval); | |
3805 | cslot = shared_hash_find_slot_noinsert (set->vars, cdv); | |
3806 | ||
3807 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
3808 | if (node->loc != cval) | |
3809 | { | |
3810 | cslot = set_slot_part (set, node->loc, cslot, cdv, 0, | |
3811 | node->init, NULL_RTX); | |
3812 | if (GET_CODE (node->loc) == VALUE) | |
3813 | { | |
3814 | decl_or_value ndv = dv_from_value (node->loc); | |
3815 | ||
3816 | set_variable_part (set, cval, ndv, 0, node->init, NULL_RTX, | |
3817 | NO_INSERT); | |
3818 | ||
3819 | if (canon_value_cmp (node->loc, val)) | |
3820 | { | |
3821 | /* If it could have been a local minimum, it's not any more, | |
3822 | since it's now neighbor to cval, so it may have to push | |
3823 | to it. Conversely, if it wouldn't have prevailed over | |
3824 | val, then whatever mark it has is fine: if it was to | |
3825 | push, it will now push to a more canonical node, but if | |
3826 | it wasn't, then it has already pushed any values it might | |
3827 | have to. */ | |
3828 | VALUE_RECURSED_INTO (node->loc) = true; | |
3829 | /* Make sure we visit node->loc by ensuring we cval is | |
3830 | visited too. */ | |
3831 | VALUE_RECURSED_INTO (cval) = true; | |
3832 | } | |
3833 | else if (!VALUE_RECURSED_INTO (node->loc)) | |
3834 | /* If we have no need to "recurse" into this node, it's | |
3835 | already "canonicalized", so drop the link to the old | |
3836 | parent. */ | |
3837 | clobber_variable_part (set, cval, ndv, 0, NULL); | |
3838 | } | |
3839 | else if (GET_CODE (node->loc) == REG) | |
3840 | { | |
3841 | attrs list = set->regs[REGNO (node->loc)], *listp; | |
3842 | ||
3843 | /* Change an existing attribute referring to dv so that it | |
3844 | refers to cdv, removing any duplicate this might | |
3845 | introduce, and checking that no previous duplicates | |
3846 | existed, all in a single pass. */ | |
3847 | ||
3848 | while (list) | |
3849 | { | |
3850 | if (list->offset == 0 | |
3851 | && (dv_as_opaque (list->dv) == dv_as_opaque (dv) | |
3852 | || dv_as_opaque (list->dv) == dv_as_opaque (cdv))) | |
3853 | break; | |
3854 | ||
3855 | list = list->next; | |
3856 | } | |
3857 | ||
3858 | gcc_assert (list); | |
3859 | if (dv_as_opaque (list->dv) == dv_as_opaque (dv)) | |
3860 | { | |
3861 | list->dv = cdv; | |
3862 | for (listp = &list->next; (list = *listp); listp = &list->next) | |
3863 | { | |
3864 | if (list->offset) | |
3865 | continue; | |
3866 | ||
3867 | if (dv_as_opaque (list->dv) == dv_as_opaque (cdv)) | |
3868 | { | |
3869 | *listp = list->next; | |
7e46899d | 3870 | delete list; |
b5b8b0ac AO |
3871 | list = *listp; |
3872 | break; | |
3873 | } | |
3874 | ||
3875 | gcc_assert (dv_as_opaque (list->dv) != dv_as_opaque (dv)); | |
3876 | } | |
3877 | } | |
3878 | else if (dv_as_opaque (list->dv) == dv_as_opaque (cdv)) | |
3879 | { | |
3880 | for (listp = &list->next; (list = *listp); listp = &list->next) | |
3881 | { | |
3882 | if (list->offset) | |
3883 | continue; | |
3884 | ||
3885 | if (dv_as_opaque (list->dv) == dv_as_opaque (dv)) | |
3886 | { | |
3887 | *listp = list->next; | |
7e46899d | 3888 | delete list; |
b5b8b0ac AO |
3889 | list = *listp; |
3890 | break; | |
3891 | } | |
3892 | ||
3893 | gcc_assert (dv_as_opaque (list->dv) != dv_as_opaque (cdv)); | |
3894 | } | |
3895 | } | |
3896 | else | |
3897 | gcc_unreachable (); | |
3898 | ||
3899 | #if ENABLE_CHECKING | |
3900 | while (list) | |
3901 | { | |
3902 | if (list->offset == 0 | |
3903 | && (dv_as_opaque (list->dv) == dv_as_opaque (dv) | |
3904 | || dv_as_opaque (list->dv) == dv_as_opaque (cdv))) | |
3905 | gcc_unreachable (); | |
3906 | ||
3907 | list = list->next; | |
3908 | } | |
3909 | #endif | |
3910 | } | |
3911 | } | |
3912 | ||
3913 | if (val) | |
649beb33 JL |
3914 | set_slot_part (set, val, cslot, cdv, 0, |
3915 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX); | |
b5b8b0ac AO |
3916 | |
3917 | slot = clobber_slot_part (set, cval, slot, 0, NULL); | |
3918 | ||
3919 | /* Variable may have been unshared. */ | |
013e5ef9 | 3920 | var = *slot; |
7a40b8b1 JH |
3921 | gcc_checking_assert (var->n_var_parts && var->var_part[0].loc_chain->loc == cval |
3922 | && var->var_part[0].loc_chain->next == NULL); | |
b5b8b0ac AO |
3923 | |
3924 | if (VALUE_RECURSED_INTO (cval)) | |
3925 | goto restart_with_cval; | |
3926 | ||
3927 | return 1; | |
3928 | } | |
3929 | ||
e999b0c9 AO |
3930 | /* Bind one-part variables to the canonical value in an equivalence |
3931 | set. Not doing this causes dataflow convergence failure in rare | |
3932 | circumstances, see PR42873. Unfortunately we can't do this | |
3933 | efficiently as part of canonicalize_values_star, since we may not | |
3934 | have determined or even seen the canonical value of a set when we | |
3935 | get to a variable that references another member of the set. */ | |
3936 | ||
013e5ef9 LC |
3937 | int |
3938 | canonicalize_vars_star (variable_def **slot, dataflow_set *set) | |
e999b0c9 | 3939 | { |
013e5ef9 | 3940 | variable var = *slot; |
e999b0c9 AO |
3941 | decl_or_value dv = var->dv; |
3942 | location_chain node; | |
3943 | rtx cval; | |
3944 | decl_or_value cdv; | |
013e5ef9 | 3945 | variable_def **cslot; |
e999b0c9 AO |
3946 | variable cvar; |
3947 | location_chain cnode; | |
3948 | ||
09dbcd96 | 3949 | if (!var->onepart || var->onepart == ONEPART_VALUE) |
e999b0c9 AO |
3950 | return 1; |
3951 | ||
3952 | gcc_assert (var->n_var_parts == 1); | |
3953 | ||
3954 | node = var->var_part[0].loc_chain; | |
3955 | ||
3956 | if (GET_CODE (node->loc) != VALUE) | |
3957 | return 1; | |
3958 | ||
3959 | gcc_assert (!node->next); | |
3960 | cval = node->loc; | |
3961 | ||
3962 | /* Push values to the canonical one. */ | |
3963 | cdv = dv_from_value (cval); | |
3964 | cslot = shared_hash_find_slot_noinsert (set->vars, cdv); | |
3965 | if (!cslot) | |
3966 | return 1; | |
013e5ef9 | 3967 | cvar = *cslot; |
e999b0c9 AO |
3968 | gcc_assert (cvar->n_var_parts == 1); |
3969 | ||
3970 | cnode = cvar->var_part[0].loc_chain; | |
3971 | ||
3972 | /* CVAL is canonical if its value list contains non-VALUEs or VALUEs | |
3973 | that are not “more canonical” than it. */ | |
3974 | if (GET_CODE (cnode->loc) != VALUE | |
3975 | || !canon_value_cmp (cnode->loc, cval)) | |
3976 | return 1; | |
3977 | ||
3978 | /* CVAL was found to be non-canonical. Change the variable to point | |
3979 | to the canonical VALUE. */ | |
3980 | gcc_assert (!cnode->next); | |
3981 | cval = cnode->loc; | |
3982 | ||
3983 | slot = set_slot_part (set, cval, slot, dv, 0, | |
3984 | node->init, node->set_src); | |
649beb33 | 3985 | clobber_slot_part (set, cval, slot, 0, node->set_src); |
e999b0c9 AO |
3986 | |
3987 | return 1; | |
3988 | } | |
3989 | ||
b5b8b0ac AO |
3990 | /* Combine variable or value in *S1SLOT (in DSM->cur) with the |
3991 | corresponding entry in DSM->src. Multi-part variables are combined | |
3992 | with variable_union, whereas onepart dvs are combined with | |
3993 | intersection. */ | |
3994 | ||
3995 | static int | |
a6590c31 | 3996 | variable_merge_over_cur (variable s1var, struct dfset_merge *dsm) |
b5b8b0ac | 3997 | { |
b5b8b0ac | 3998 | dataflow_set *dst = dsm->dst; |
013e5ef9 | 3999 | variable_def **dstslot; |
b5b8b0ac AO |
4000 | variable s2var, dvar = NULL; |
4001 | decl_or_value dv = s1var->dv; | |
09dbcd96 | 4002 | onepart_enum_t onepart = s1var->onepart; |
b5b8b0ac AO |
4003 | rtx val; |
4004 | hashval_t dvhash; | |
4005 | location_chain node, *nodep; | |
4006 | ||
4007 | /* If the incoming onepart variable has an empty location list, then | |
4008 | the intersection will be just as empty. For other variables, | |
4009 | it's always union. */ | |
7a40b8b1 JH |
4010 | gcc_checking_assert (s1var->n_var_parts |
4011 | && s1var->var_part[0].loc_chain); | |
b5b8b0ac AO |
4012 | |
4013 | if (!onepart) | |
a6590c31 | 4014 | return variable_union (s1var, dst); |
b5b8b0ac | 4015 | |
09dbcd96 | 4016 | gcc_checking_assert (s1var->n_var_parts == 1); |
b5b8b0ac AO |
4017 | |
4018 | dvhash = dv_htab_hash (dv); | |
4019 | if (dv_is_value_p (dv)) | |
4020 | val = dv_as_value (dv); | |
4021 | else | |
4022 | val = NULL; | |
4023 | ||
4024 | s2var = shared_hash_find_1 (dsm->src->vars, dv, dvhash); | |
4025 | if (!s2var) | |
4026 | { | |
4027 | dst_can_be_shared = false; | |
4028 | return 1; | |
4029 | } | |
4030 | ||
4031 | dsm->src_onepart_cnt--; | |
a6590c31 | 4032 | gcc_assert (s2var->var_part[0].loc_chain |
09dbcd96 AO |
4033 | && s2var->onepart == onepart |
4034 | && s2var->n_var_parts == 1); | |
b5b8b0ac AO |
4035 | |
4036 | dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash); | |
4037 | if (dstslot) | |
4038 | { | |
013e5ef9 | 4039 | dvar = *dstslot; |
a6590c31 | 4040 | gcc_assert (dvar->refcount == 1 |
09dbcd96 AO |
4041 | && dvar->onepart == onepart |
4042 | && dvar->n_var_parts == 1); | |
b5b8b0ac AO |
4043 | nodep = &dvar->var_part[0].loc_chain; |
4044 | } | |
4045 | else | |
4046 | { | |
4047 | nodep = &node; | |
4048 | node = NULL; | |
4049 | } | |
4050 | ||
4051 | if (!dstslot && !onepart_variable_different_p (s1var, s2var)) | |
4052 | { | |
4053 | dstslot = shared_hash_find_slot_unshare_1 (&dst->vars, dv, | |
4054 | dvhash, INSERT); | |
4055 | *dstslot = dvar = s2var; | |
4056 | dvar->refcount++; | |
4057 | } | |
4058 | else | |
4059 | { | |
4060 | dst_can_be_shared = false; | |
4061 | ||
4062 | intersect_loc_chains (val, nodep, dsm, | |
4063 | s1var->var_part[0].loc_chain, s2var); | |
4064 | ||
4065 | if (!dstslot) | |
4066 | { | |
4067 | if (node) | |
4068 | { | |
7e46899d | 4069 | dvar = onepart_pool (onepart).allocate (); |
b5b8b0ac AO |
4070 | dvar->dv = dv; |
4071 | dvar->refcount = 1; | |
4072 | dvar->n_var_parts = 1; | |
09dbcd96 | 4073 | dvar->onepart = onepart; |
864ddef7 | 4074 | dvar->in_changed_variables = false; |
b5b8b0ac | 4075 | dvar->var_part[0].loc_chain = node; |
864ddef7 | 4076 | dvar->var_part[0].cur_loc = NULL; |
09dbcd96 AO |
4077 | if (onepart) |
4078 | VAR_LOC_1PAUX (dvar) = NULL; | |
4079 | else | |
4080 | VAR_PART_OFFSET (dvar, 0) = 0; | |
b5b8b0ac AO |
4081 | |
4082 | dstslot | |
4083 | = shared_hash_find_slot_unshare_1 (&dst->vars, dv, dvhash, | |
4084 | INSERT); | |
4085 | gcc_assert (!*dstslot); | |
4086 | *dstslot = dvar; | |
4087 | } | |
4088 | else | |
4089 | return 1; | |
4090 | } | |
4091 | } | |
4092 | ||
4093 | nodep = &dvar->var_part[0].loc_chain; | |
4094 | while ((node = *nodep)) | |
4095 | { | |
4096 | location_chain *nextp = &node->next; | |
4097 | ||
4098 | if (GET_CODE (node->loc) == REG) | |
4099 | { | |
4100 | attrs list; | |
4101 | ||
4102 | for (list = dst->regs[REGNO (node->loc)]; list; list = list->next) | |
4103 | if (GET_MODE (node->loc) == GET_MODE (list->loc) | |
4104 | && dv_is_value_p (list->dv)) | |
4105 | break; | |
4106 | ||
4107 | if (!list) | |
4108 | attrs_list_insert (&dst->regs[REGNO (node->loc)], | |
4109 | dv, 0, node->loc); | |
4110 | /* If this value became canonical for another value that had | |
4111 | this register, we want to leave it alone. */ | |
4112 | else if (dv_as_value (list->dv) != val) | |
4113 | { | |
4114 | dstslot = set_slot_part (dst, dv_as_value (list->dv), | |
4115 | dstslot, dv, 0, | |
4116 | node->init, NULL_RTX); | |
4117 | dstslot = delete_slot_part (dst, node->loc, dstslot, 0); | |
4118 | ||
4119 | /* Since nextp points into the removed node, we can't | |
4120 | use it. The pointer to the next node moved to nodep. | |
4121 | However, if the variable we're walking is unshared | |
4122 | during our walk, we'll keep walking the location list | |
4123 | of the previously-shared variable, in which case the | |
4124 | node won't have been removed, and we'll want to skip | |
4125 | it. That's why we test *nodep here. */ | |
4126 | if (*nodep != node) | |
4127 | nextp = nodep; | |
4128 | } | |
4129 | } | |
4130 | else | |
4131 | /* Canonicalization puts registers first, so we don't have to | |
4132 | walk it all. */ | |
4133 | break; | |
4134 | nodep = nextp; | |
4135 | } | |
4136 | ||
013e5ef9 LC |
4137 | if (dvar != *dstslot) |
4138 | dvar = *dstslot; | |
b5b8b0ac AO |
4139 | nodep = &dvar->var_part[0].loc_chain; |
4140 | ||
4141 | if (val) | |
4142 | { | |
4143 | /* Mark all referenced nodes for canonicalization, and make sure | |
4144 | we have mutual equivalence links. */ | |
4145 | VALUE_RECURSED_INTO (val) = true; | |
4146 | for (node = *nodep; node; node = node->next) | |
4147 | if (GET_CODE (node->loc) == VALUE) | |
4148 | { | |
4149 | VALUE_RECURSED_INTO (node->loc) = true; | |
4150 | set_variable_part (dst, val, dv_from_value (node->loc), 0, | |
4151 | node->init, NULL, INSERT); | |
4152 | } | |
4153 | ||
4154 | dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash); | |
4155 | gcc_assert (*dstslot == dvar); | |
4156 | canonicalize_values_star (dstslot, dst); | |
77a74ed7 NF |
4157 | gcc_checking_assert (dstslot |
4158 | == shared_hash_find_slot_noinsert_1 (dst->vars, | |
4159 | dv, dvhash)); | |
013e5ef9 | 4160 | dvar = *dstslot; |
b5b8b0ac AO |
4161 | } |
4162 | else | |
4163 | { | |
4164 | bool has_value = false, has_other = false; | |
4165 | ||
4166 | /* If we have one value and anything else, we're going to | |
4167 | canonicalize this, so make sure all values have an entry in | |
4168 | the table and are marked for canonicalization. */ | |
4169 | for (node = *nodep; node; node = node->next) | |
4170 | { | |
4171 | if (GET_CODE (node->loc) == VALUE) | |
4172 | { | |
4173 | /* If this was marked during register canonicalization, | |
4174 | we know we have to canonicalize values. */ | |
4175 | if (has_value) | |
4176 | has_other = true; | |
4177 | has_value = true; | |
4178 | if (has_other) | |
4179 | break; | |
4180 | } | |
4181 | else | |
4182 | { | |
4183 | has_other = true; | |
4184 | if (has_value) | |
4185 | break; | |
4186 | } | |
4187 | } | |
4188 | ||
4189 | if (has_value && has_other) | |
4190 | { | |
4191 | for (node = *nodep; node; node = node->next) | |
4192 | { | |
4193 | if (GET_CODE (node->loc) == VALUE) | |
4194 | { | |
4195 | decl_or_value dv = dv_from_value (node->loc); | |
013e5ef9 | 4196 | variable_def **slot = NULL; |
b5b8b0ac AO |
4197 | |
4198 | if (shared_hash_shared (dst->vars)) | |
4199 | slot = shared_hash_find_slot_noinsert (dst->vars, dv); | |
4200 | if (!slot) | |
4201 | slot = shared_hash_find_slot_unshare (&dst->vars, dv, | |
4202 | INSERT); | |
4203 | if (!*slot) | |
4204 | { | |
7e46899d | 4205 | variable var = onepart_pool (ONEPART_VALUE).allocate (); |
b5b8b0ac AO |
4206 | var->dv = dv; |
4207 | var->refcount = 1; | |
4208 | var->n_var_parts = 1; | |
09dbcd96 | 4209 | var->onepart = ONEPART_VALUE; |
864ddef7 | 4210 | var->in_changed_variables = false; |
b5b8b0ac AO |
4211 | var->var_part[0].loc_chain = NULL; |
4212 | var->var_part[0].cur_loc = NULL; | |
09dbcd96 | 4213 | VAR_LOC_1PAUX (var) = NULL; |
b5b8b0ac AO |
4214 | *slot = var; |
4215 | } | |
4216 | ||
4217 | VALUE_RECURSED_INTO (node->loc) = true; | |
4218 | } | |
4219 | } | |
4220 | ||
4221 | dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash); | |
4222 | gcc_assert (*dstslot == dvar); | |
4223 | canonicalize_values_star (dstslot, dst); | |
77a74ed7 NF |
4224 | gcc_checking_assert (dstslot |
4225 | == shared_hash_find_slot_noinsert_1 (dst->vars, | |
4226 | dv, dvhash)); | |
013e5ef9 | 4227 | dvar = *dstslot; |
b5b8b0ac AO |
4228 | } |
4229 | } | |
4230 | ||
4231 | if (!onepart_variable_different_p (dvar, s2var)) | |
4232 | { | |
4233 | variable_htab_free (dvar); | |
4234 | *dstslot = dvar = s2var; | |
4235 | dvar->refcount++; | |
4236 | } | |
4237 | else if (s2var != s1var && !onepart_variable_different_p (dvar, s1var)) | |
4238 | { | |
4239 | variable_htab_free (dvar); | |
4240 | *dstslot = dvar = s1var; | |
4241 | dvar->refcount++; | |
4242 | dst_can_be_shared = false; | |
4243 | } | |
4244 | else | |
864ddef7 | 4245 | dst_can_be_shared = false; |
b5b8b0ac AO |
4246 | |
4247 | return 1; | |
4248 | } | |
4249 | ||
60d7a09b AO |
4250 | /* Copy s2slot (in DSM->src) to DSM->dst if the variable is a |
4251 | multi-part variable. Unions of multi-part variables and | |
4252 | intersections of one-part ones will be handled in | |
4253 | variable_merge_over_cur(). */ | |
b5b8b0ac AO |
4254 | |
4255 | static int | |
a6590c31 | 4256 | variable_merge_over_src (variable s2var, struct dfset_merge *dsm) |
b5b8b0ac | 4257 | { |
b5b8b0ac | 4258 | dataflow_set *dst = dsm->dst; |
b5b8b0ac | 4259 | decl_or_value dv = s2var->dv; |
b5b8b0ac | 4260 | |
09dbcd96 | 4261 | if (!s2var->onepart) |
b5b8b0ac | 4262 | { |
013e5ef9 | 4263 | variable_def **dstp = shared_hash_find_slot (dst->vars, dv); |
b5b8b0ac AO |
4264 | *dstp = s2var; |
4265 | s2var->refcount++; | |
864ddef7 | 4266 | return 1; |
b5b8b0ac AO |
4267 | } |
4268 | ||
4269 | dsm->src_onepart_cnt++; | |
4270 | return 1; | |
4271 | } | |
4272 | ||
60d7a09b | 4273 | /* Combine dataflow set information from SRC2 into DST, using PDST |
b5b8b0ac AO |
4274 | to carry over information across passes. */ |
4275 | ||
4276 | static void | |
60d7a09b | 4277 | dataflow_set_merge (dataflow_set *dst, dataflow_set *src2) |
b5b8b0ac | 4278 | { |
60d7a09b AO |
4279 | dataflow_set cur = *dst; |
4280 | dataflow_set *src1 = &cur; | |
b5b8b0ac AO |
4281 | struct dfset_merge dsm; |
4282 | int i; | |
60d7a09b | 4283 | size_t src1_elems, src2_elems; |
013e5ef9 | 4284 | variable_iterator_type hi; |
a6590c31 | 4285 | variable var; |
b5b8b0ac | 4286 | |
c203e8a7 TS |
4287 | src1_elems = shared_hash_htab (src1->vars)->elements (); |
4288 | src2_elems = shared_hash_htab (src2->vars)->elements (); | |
b5b8b0ac | 4289 | dataflow_set_init (dst); |
60d7a09b | 4290 | dst->stack_adjust = cur.stack_adjust; |
b5b8b0ac | 4291 | shared_hash_destroy (dst->vars); |
7e46899d | 4292 | dst->vars = new shared_hash_def; |
b5b8b0ac | 4293 | dst->vars->refcount = 1; |
c203e8a7 | 4294 | dst->vars->htab = new variable_table_type (MAX (src1_elems, src2_elems)); |
b5b8b0ac AO |
4295 | |
4296 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
60d7a09b | 4297 | attrs_list_mpdv_union (&dst->regs[i], src1->regs[i], src2->regs[i]); |
b5b8b0ac AO |
4298 | |
4299 | dsm.dst = dst; | |
60d7a09b AO |
4300 | dsm.src = src2; |
4301 | dsm.cur = src1; | |
b5b8b0ac AO |
4302 | dsm.src_onepart_cnt = 0; |
4303 | ||
c203e8a7 | 4304 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.src->vars), |
013e5ef9 | 4305 | var, variable, hi) |
a6590c31 | 4306 | variable_merge_over_src (var, &dsm); |
c203e8a7 | 4307 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.cur->vars), |
013e5ef9 | 4308 | var, variable, hi) |
a6590c31 | 4309 | variable_merge_over_cur (var, &dsm); |
b5b8b0ac AO |
4310 | |
4311 | if (dsm.src_onepart_cnt) | |
4312 | dst_can_be_shared = false; | |
4313 | ||
60d7a09b | 4314 | dataflow_set_destroy (src1); |
b5b8b0ac AO |
4315 | } |
4316 | ||
4317 | /* Mark register equivalences. */ | |
4318 | ||
4319 | static void | |
4320 | dataflow_set_equiv_regs (dataflow_set *set) | |
4321 | { | |
4322 | int i; | |
4323 | attrs list, *listp; | |
4324 | ||
4325 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
4326 | { | |
4327 | rtx canon[NUM_MACHINE_MODES]; | |
4328 | ||
193d4c0f | 4329 | /* If the list is empty or one entry, no need to canonicalize |
e2cc3483 JJ |
4330 | anything. */ |
4331 | if (set->regs[i] == NULL || set->regs[i]->next == NULL) | |
193d4c0f JJ |
4332 | continue; |
4333 | ||
b5b8b0ac AO |
4334 | memset (canon, 0, sizeof (canon)); |
4335 | ||
4336 | for (list = set->regs[i]; list; list = list->next) | |
4337 | if (list->offset == 0 && dv_is_value_p (list->dv)) | |
4338 | { | |
4339 | rtx val = dv_as_value (list->dv); | |
4340 | rtx *cvalp = &canon[(int)GET_MODE (val)]; | |
4341 | rtx cval = *cvalp; | |
4342 | ||
4343 | if (canon_value_cmp (val, cval)) | |
4344 | *cvalp = val; | |
4345 | } | |
4346 | ||
4347 | for (list = set->regs[i]; list; list = list->next) | |
4348 | if (list->offset == 0 && dv_onepart_p (list->dv)) | |
4349 | { | |
4350 | rtx cval = canon[(int)GET_MODE (list->loc)]; | |
4351 | ||
4352 | if (!cval) | |
4353 | continue; | |
4354 | ||
4355 | if (dv_is_value_p (list->dv)) | |
4356 | { | |
4357 | rtx val = dv_as_value (list->dv); | |
4358 | ||
4359 | if (val == cval) | |
4360 | continue; | |
4361 | ||
4362 | VALUE_RECURSED_INTO (val) = true; | |
4363 | set_variable_part (set, val, dv_from_value (cval), 0, | |
4364 | VAR_INIT_STATUS_INITIALIZED, | |
4365 | NULL, NO_INSERT); | |
4366 | } | |
4367 | ||
4368 | VALUE_RECURSED_INTO (cval) = true; | |
4369 | set_variable_part (set, cval, list->dv, 0, | |
4370 | VAR_INIT_STATUS_INITIALIZED, NULL, NO_INSERT); | |
4371 | } | |
4372 | ||
4373 | for (listp = &set->regs[i]; (list = *listp); | |
4374 | listp = list ? &list->next : listp) | |
4375 | if (list->offset == 0 && dv_onepart_p (list->dv)) | |
4376 | { | |
4377 | rtx cval = canon[(int)GET_MODE (list->loc)]; | |
013e5ef9 | 4378 | variable_def **slot; |
b5b8b0ac AO |
4379 | |
4380 | if (!cval) | |
4381 | continue; | |
4382 | ||
4383 | if (dv_is_value_p (list->dv)) | |
4384 | { | |
4385 | rtx val = dv_as_value (list->dv); | |
4386 | if (!VALUE_RECURSED_INTO (val)) | |
4387 | continue; | |
4388 | } | |
4389 | ||
4390 | slot = shared_hash_find_slot_noinsert (set->vars, list->dv); | |
4391 | canonicalize_values_star (slot, set); | |
4392 | if (*listp != list) | |
4393 | list = NULL; | |
4394 | } | |
4395 | } | |
4396 | } | |
4397 | ||
4398 | /* Remove any redundant values in the location list of VAR, which must | |
4399 | be unshared and 1-part. */ | |
4400 | ||
4401 | static void | |
4402 | remove_duplicate_values (variable var) | |
4403 | { | |
4404 | location_chain node, *nodep; | |
4405 | ||
09dbcd96 | 4406 | gcc_assert (var->onepart); |
b5b8b0ac AO |
4407 | gcc_assert (var->n_var_parts == 1); |
4408 | gcc_assert (var->refcount == 1); | |
4409 | ||
4410 | for (nodep = &var->var_part[0].loc_chain; (node = *nodep); ) | |
4411 | { | |
4412 | if (GET_CODE (node->loc) == VALUE) | |
4413 | { | |
4414 | if (VALUE_RECURSED_INTO (node->loc)) | |
4415 | { | |
4416 | /* Remove duplicate value node. */ | |
4417 | *nodep = node->next; | |
7e46899d | 4418 | delete node; |
b5b8b0ac AO |
4419 | continue; |
4420 | } | |
4421 | else | |
4422 | VALUE_RECURSED_INTO (node->loc) = true; | |
4423 | } | |
4424 | nodep = &node->next; | |
4425 | } | |
4426 | ||
4427 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
4428 | if (GET_CODE (node->loc) == VALUE) | |
4429 | { | |
4430 | gcc_assert (VALUE_RECURSED_INTO (node->loc)); | |
4431 | VALUE_RECURSED_INTO (node->loc) = false; | |
4432 | } | |
4433 | } | |
4434 | ||
4435 | ||
4436 | /* Hash table iteration argument passed to variable_post_merge. */ | |
4437 | struct dfset_post_merge | |
4438 | { | |
4439 | /* The new input set for the current block. */ | |
4440 | dataflow_set *set; | |
4441 | /* Pointer to the permanent input set for the current block, or | |
4442 | NULL. */ | |
4443 | dataflow_set **permp; | |
4444 | }; | |
4445 | ||
4446 | /* Create values for incoming expressions associated with one-part | |
4447 | variables that don't have value numbers for them. */ | |
4448 | ||
013e5ef9 LC |
4449 | int |
4450 | variable_post_merge_new_vals (variable_def **slot, dfset_post_merge *dfpm) | |
b5b8b0ac | 4451 | { |
b5b8b0ac | 4452 | dataflow_set *set = dfpm->set; |
013e5ef9 | 4453 | variable var = *slot; |
b5b8b0ac AO |
4454 | location_chain node; |
4455 | ||
09dbcd96 | 4456 | if (!var->onepart || !var->n_var_parts) |
b5b8b0ac AO |
4457 | return 1; |
4458 | ||
4459 | gcc_assert (var->n_var_parts == 1); | |
4460 | ||
4461 | if (dv_is_decl_p (var->dv)) | |
4462 | { | |
4463 | bool check_dupes = false; | |
4464 | ||
4465 | restart: | |
4466 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
4467 | { | |
4468 | if (GET_CODE (node->loc) == VALUE) | |
4469 | gcc_assert (!VALUE_RECURSED_INTO (node->loc)); | |
4470 | else if (GET_CODE (node->loc) == REG) | |
4471 | { | |
4472 | attrs att, *attp, *curp = NULL; | |
4473 | ||
4474 | if (var->refcount != 1) | |
4475 | { | |
4476 | slot = unshare_variable (set, slot, var, | |
4477 | VAR_INIT_STATUS_INITIALIZED); | |
013e5ef9 | 4478 | var = *slot; |
b5b8b0ac AO |
4479 | goto restart; |
4480 | } | |
4481 | ||
4482 | for (attp = &set->regs[REGNO (node->loc)]; (att = *attp); | |
4483 | attp = &att->next) | |
4484 | if (att->offset == 0 | |
4485 | && GET_MODE (att->loc) == GET_MODE (node->loc)) | |
4486 | { | |
4487 | if (dv_is_value_p (att->dv)) | |
4488 | { | |
4489 | rtx cval = dv_as_value (att->dv); | |
4490 | node->loc = cval; | |
4491 | check_dupes = true; | |
4492 | break; | |
4493 | } | |
4494 | else if (dv_as_opaque (att->dv) == dv_as_opaque (var->dv)) | |
4495 | curp = attp; | |
4496 | } | |
4497 | ||
4498 | if (!curp) | |
4499 | { | |
4500 | curp = attp; | |
4501 | while (*curp) | |
4502 | if ((*curp)->offset == 0 | |
4503 | && GET_MODE ((*curp)->loc) == GET_MODE (node->loc) | |
4504 | && dv_as_opaque ((*curp)->dv) == dv_as_opaque (var->dv)) | |
4505 | break; | |
4506 | else | |
4507 | curp = &(*curp)->next; | |
4508 | gcc_assert (*curp); | |
4509 | } | |
4510 | ||
4511 | if (!att) | |
4512 | { | |
4513 | decl_or_value cdv; | |
4514 | rtx cval; | |
4515 | ||
4516 | if (!*dfpm->permp) | |
4517 | { | |
4518 | *dfpm->permp = XNEW (dataflow_set); | |
4519 | dataflow_set_init (*dfpm->permp); | |
4520 | } | |
4521 | ||
4522 | for (att = (*dfpm->permp)->regs[REGNO (node->loc)]; | |
4523 | att; att = att->next) | |
4524 | if (GET_MODE (att->loc) == GET_MODE (node->loc)) | |
4525 | { | |
a6590c31 RG |
4526 | gcc_assert (att->offset == 0 |
4527 | && dv_is_value_p (att->dv)); | |
b5b8b0ac AO |
4528 | val_reset (set, att->dv); |
4529 | break; | |
4530 | } | |
4531 | ||
4532 | if (att) | |
4533 | { | |
4534 | cdv = att->dv; | |
4535 | cval = dv_as_value (cdv); | |
4536 | } | |
4537 | else | |
4538 | { | |
4539 | /* Create a unique value to hold this register, | |
4540 | that ought to be found and reused in | |
4541 | subsequent rounds. */ | |
4542 | cselib_val *v; | |
4543 | gcc_assert (!cselib_lookup (node->loc, | |
4deef538 AO |
4544 | GET_MODE (node->loc), 0, |
4545 | VOIDmode)); | |
4546 | v = cselib_lookup (node->loc, GET_MODE (node->loc), 1, | |
4547 | VOIDmode); | |
b5b8b0ac AO |
4548 | cselib_preserve_value (v); |
4549 | cselib_invalidate_rtx (node->loc); | |
4550 | cval = v->val_rtx; | |
4551 | cdv = dv_from_value (cval); | |
4552 | if (dump_file) | |
4553 | fprintf (dump_file, | |
5440c0e7 AO |
4554 | "Created new value %u:%u for reg %i\n", |
4555 | v->uid, v->hash, REGNO (node->loc)); | |
b5b8b0ac AO |
4556 | } |
4557 | ||
4558 | var_reg_decl_set (*dfpm->permp, node->loc, | |
4559 | VAR_INIT_STATUS_INITIALIZED, | |
4560 | cdv, 0, NULL, INSERT); | |
4561 | ||
4562 | node->loc = cval; | |
4563 | check_dupes = true; | |
4564 | } | |
4565 | ||
4566 | /* Remove attribute referring to the decl, which now | |
4567 | uses the value for the register, already existing or | |
4568 | to be added when we bring perm in. */ | |
4569 | att = *curp; | |
4570 | *curp = att->next; | |
7e46899d | 4571 | delete att; |
b5b8b0ac AO |
4572 | } |
4573 | } | |
4574 | ||
4575 | if (check_dupes) | |
4576 | remove_duplicate_values (var); | |
4577 | } | |
4578 | ||
4579 | return 1; | |
4580 | } | |
4581 | ||
4582 | /* Reset values in the permanent set that are not associated with the | |
4583 | chosen expression. */ | |
4584 | ||
013e5ef9 LC |
4585 | int |
4586 | variable_post_merge_perm_vals (variable_def **pslot, dfset_post_merge *dfpm) | |
b5b8b0ac | 4587 | { |
b5b8b0ac | 4588 | dataflow_set *set = dfpm->set; |
013e5ef9 | 4589 | variable pvar = *pslot, var; |
b5b8b0ac AO |
4590 | location_chain pnode; |
4591 | decl_or_value dv; | |
4592 | attrs att; | |
4593 | ||
a6590c31 RG |
4594 | gcc_assert (dv_is_value_p (pvar->dv) |
4595 | && pvar->n_var_parts == 1); | |
b5b8b0ac | 4596 | pnode = pvar->var_part[0].loc_chain; |
a6590c31 RG |
4597 | gcc_assert (pnode |
4598 | && !pnode->next | |
4599 | && REG_P (pnode->loc)); | |
b5b8b0ac AO |
4600 | |
4601 | dv = pvar->dv; | |
4602 | ||
4603 | var = shared_hash_find (set->vars, dv); | |
4604 | if (var) | |
4605 | { | |
b933b33a AO |
4606 | /* Although variable_post_merge_new_vals may have made decls |
4607 | non-star-canonical, values that pre-existed in canonical form | |
4608 | remain canonical, and newly-created values reference a single | |
4609 | REG, so they are canonical as well. Since VAR has the | |
4610 | location list for a VALUE, using find_loc_in_1pdv for it is | |
4611 | fine, since VALUEs don't map back to DECLs. */ | |
b5b8b0ac AO |
4612 | if (find_loc_in_1pdv (pnode->loc, var, shared_hash_htab (set->vars))) |
4613 | return 1; | |
4614 | val_reset (set, dv); | |
4615 | } | |
4616 | ||
4617 | for (att = set->regs[REGNO (pnode->loc)]; att; att = att->next) | |
4618 | if (att->offset == 0 | |
4619 | && GET_MODE (att->loc) == GET_MODE (pnode->loc) | |
4620 | && dv_is_value_p (att->dv)) | |
4621 | break; | |
4622 | ||
4623 | /* If there is a value associated with this register already, create | |
4624 | an equivalence. */ | |
4625 | if (att && dv_as_value (att->dv) != dv_as_value (dv)) | |
4626 | { | |
4627 | rtx cval = dv_as_value (att->dv); | |
4628 | set_variable_part (set, cval, dv, 0, pnode->init, NULL, INSERT); | |
4629 | set_variable_part (set, dv_as_value (dv), att->dv, 0, pnode->init, | |
4630 | NULL, INSERT); | |
4631 | } | |
4632 | else if (!att) | |
4633 | { | |
4634 | attrs_list_insert (&set->regs[REGNO (pnode->loc)], | |
4635 | dv, 0, pnode->loc); | |
a6590c31 | 4636 | variable_union (pvar, set); |
b5b8b0ac AO |
4637 | } |
4638 | ||
4639 | return 1; | |
4640 | } | |
4641 | ||
4642 | /* Just checking stuff and registering register attributes for | |
4643 | now. */ | |
4644 | ||
4645 | static void | |
4646 | dataflow_post_merge_adjust (dataflow_set *set, dataflow_set **permp) | |
4647 | { | |
4648 | struct dfset_post_merge dfpm; | |
4649 | ||
4650 | dfpm.set = set; | |
4651 | dfpm.permp = permp; | |
4652 | ||
013e5ef9 | 4653 | shared_hash_htab (set->vars) |
c203e8a7 | 4654 | ->traverse <dfset_post_merge*, variable_post_merge_new_vals> (&dfpm); |
b5b8b0ac | 4655 | if (*permp) |
013e5ef9 | 4656 | shared_hash_htab ((*permp)->vars) |
c203e8a7 | 4657 | ->traverse <dfset_post_merge*, variable_post_merge_perm_vals> (&dfpm); |
013e5ef9 | 4658 | shared_hash_htab (set->vars) |
c203e8a7 | 4659 | ->traverse <dataflow_set *, canonicalize_values_star> (set); |
013e5ef9 | 4660 | shared_hash_htab (set->vars) |
c203e8a7 | 4661 | ->traverse <dataflow_set *, canonicalize_vars_star> (set); |
b5b8b0ac AO |
4662 | } |
4663 | ||
4664 | /* Return a node whose loc is a MEM that refers to EXPR in the | |
4665 | location list of a one-part variable or value VAR, or in that of | |
4666 | any values recursively mentioned in the location lists. */ | |
4667 | ||
4668 | static location_chain | |
c203e8a7 | 4669 | find_mem_expr_in_1pdv (tree expr, rtx val, variable_table_type *vars) |
b5b8b0ac AO |
4670 | { |
4671 | location_chain node; | |
4672 | decl_or_value dv; | |
4673 | variable var; | |
4674 | location_chain where = NULL; | |
4675 | ||
4676 | if (!val) | |
4677 | return NULL; | |
4678 | ||
a6590c31 RG |
4679 | gcc_assert (GET_CODE (val) == VALUE |
4680 | && !VALUE_RECURSED_INTO (val)); | |
b5b8b0ac AO |
4681 | |
4682 | dv = dv_from_value (val); | |
c203e8a7 | 4683 | var = vars->find_with_hash (dv, dv_htab_hash (dv)); |
b5b8b0ac AO |
4684 | |
4685 | if (!var) | |
4686 | return NULL; | |
4687 | ||
09dbcd96 | 4688 | gcc_assert (var->onepart); |
b5b8b0ac AO |
4689 | |
4690 | if (!var->n_var_parts) | |
4691 | return NULL; | |
4692 | ||
b5b8b0ac AO |
4693 | VALUE_RECURSED_INTO (val) = true; |
4694 | ||
4695 | for (node = var->var_part[0].loc_chain; node; node = node->next) | |
c46d001a EB |
4696 | if (MEM_P (node->loc) |
4697 | && MEM_EXPR (node->loc) == expr | |
4698 | && INT_MEM_OFFSET (node->loc) == 0) | |
b5b8b0ac AO |
4699 | { |
4700 | where = node; | |
4701 | break; | |
4702 | } | |
4703 | else if (GET_CODE (node->loc) == VALUE | |
4704 | && !VALUE_RECURSED_INTO (node->loc) | |
4705 | && (where = find_mem_expr_in_1pdv (expr, node->loc, vars))) | |
4706 | break; | |
4707 | ||
4708 | VALUE_RECURSED_INTO (val) = false; | |
4709 | ||
4710 | return where; | |
4711 | } | |
4712 | ||
4a4d4c08 AO |
4713 | /* Return TRUE if the value of MEM may vary across a call. */ |
4714 | ||
4715 | static bool | |
4716 | mem_dies_at_call (rtx mem) | |
4717 | { | |
4718 | tree expr = MEM_EXPR (mem); | |
4719 | tree decl; | |
4720 | ||
4721 | if (!expr) | |
4722 | return true; | |
4723 | ||
4724 | decl = get_base_address (expr); | |
4725 | ||
4726 | if (!decl) | |
4727 | return true; | |
4728 | ||
4729 | if (!DECL_P (decl)) | |
4730 | return true; | |
4731 | ||
4732 | return (may_be_aliased (decl) | |
4733 | || (!TREE_READONLY (decl) && is_global_var (decl))); | |
4734 | } | |
4735 | ||
b5b8b0ac AO |
4736 | /* Remove all MEMs from the location list of a hash table entry for a |
4737 | one-part variable, except those whose MEM attributes map back to | |
4a4d4c08 | 4738 | the variable itself, directly or within a VALUE. */ |
b5b8b0ac | 4739 | |
013e5ef9 LC |
4740 | int |
4741 | dataflow_set_preserve_mem_locs (variable_def **slot, dataflow_set *set) | |
b5b8b0ac | 4742 | { |
013e5ef9 | 4743 | variable var = *slot; |
b5b8b0ac | 4744 | |
09dbcd96 | 4745 | if (var->onepart == ONEPART_VDECL || var->onepart == ONEPART_DEXPR) |
b5b8b0ac AO |
4746 | { |
4747 | tree decl = dv_as_decl (var->dv); | |
4748 | location_chain loc, *locp; | |
864ddef7 | 4749 | bool changed = false; |
b5b8b0ac AO |
4750 | |
4751 | if (!var->n_var_parts) | |
4752 | return 1; | |
4753 | ||
4754 | gcc_assert (var->n_var_parts == 1); | |
4755 | ||
864ddef7 | 4756 | if (shared_var_p (var, set->vars)) |
b5b8b0ac AO |
4757 | { |
4758 | for (loc = var->var_part[0].loc_chain; loc; loc = loc->next) | |
4759 | { | |
c46d001a | 4760 | /* We want to remove dying MEMs that doesn't refer to DECL. */ |
b5b8b0ac AO |
4761 | if (GET_CODE (loc->loc) == MEM |
4762 | && (MEM_EXPR (loc->loc) != decl | |
c46d001a | 4763 | || INT_MEM_OFFSET (loc->loc) != 0) |
4a4d4c08 | 4764 | && !mem_dies_at_call (loc->loc)) |
b5b8b0ac | 4765 | break; |
4a4d4c08 | 4766 | /* We want to move here MEMs that do refer to DECL. */ |
b5b8b0ac AO |
4767 | else if (GET_CODE (loc->loc) == VALUE |
4768 | && find_mem_expr_in_1pdv (decl, loc->loc, | |
4769 | shared_hash_htab (set->vars))) | |
4a4d4c08 | 4770 | break; |
b5b8b0ac AO |
4771 | } |
4772 | ||
4773 | if (!loc) | |
4774 | return 1; | |
4775 | ||
4776 | slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN); | |
013e5ef9 | 4777 | var = *slot; |
b5b8b0ac AO |
4778 | gcc_assert (var->n_var_parts == 1); |
4779 | } | |
4780 | ||
4781 | for (locp = &var->var_part[0].loc_chain, loc = *locp; | |
4782 | loc; loc = *locp) | |
4783 | { | |
4784 | rtx old_loc = loc->loc; | |
4785 | if (GET_CODE (old_loc) == VALUE) | |
4786 | { | |
4787 | location_chain mem_node | |
4788 | = find_mem_expr_in_1pdv (decl, loc->loc, | |
4789 | shared_hash_htab (set->vars)); | |
4790 | ||
4791 | /* ??? This picks up only one out of multiple MEMs that | |
4792 | refer to the same variable. Do we ever need to be | |
4793 | concerned about dealing with more than one, or, given | |
4794 | that they should all map to the same variable | |
4795 | location, their addresses will have been merged and | |
4796 | they will be regarded as equivalent? */ | |
4797 | if (mem_node) | |
4798 | { | |
4799 | loc->loc = mem_node->loc; | |
4800 | loc->set_src = mem_node->set_src; | |
4801 | loc->init = MIN (loc->init, mem_node->init); | |
4802 | } | |
4803 | } | |
4804 | ||
4805 | if (GET_CODE (loc->loc) != MEM | |
4806 | || (MEM_EXPR (loc->loc) == decl | |
c46d001a | 4807 | && INT_MEM_OFFSET (loc->loc) == 0) |
4a4d4c08 | 4808 | || !mem_dies_at_call (loc->loc)) |
b5b8b0ac AO |
4809 | { |
4810 | if (old_loc != loc->loc && emit_notes) | |
4811 | { | |
864ddef7 JJ |
4812 | if (old_loc == var->var_part[0].cur_loc) |
4813 | { | |
4814 | changed = true; | |
4815 | var->var_part[0].cur_loc = NULL; | |
864ddef7 | 4816 | } |
b5b8b0ac AO |
4817 | } |
4818 | locp = &loc->next; | |
4819 | continue; | |
4820 | } | |
4821 | ||
4822 | if (emit_notes) | |
864ddef7 | 4823 | { |
864ddef7 JJ |
4824 | if (old_loc == var->var_part[0].cur_loc) |
4825 | { | |
4826 | changed = true; | |
4827 | var->var_part[0].cur_loc = NULL; | |
864ddef7 JJ |
4828 | } |
4829 | } | |
b5b8b0ac | 4830 | *locp = loc->next; |
7e46899d | 4831 | delete loc; |
b5b8b0ac AO |
4832 | } |
4833 | ||
4834 | if (!var->var_part[0].loc_chain) | |
4835 | { | |
4836 | var->n_var_parts--; | |
864ddef7 | 4837 | changed = true; |
b5b8b0ac | 4838 | } |
864ddef7 JJ |
4839 | if (changed) |
4840 | variable_was_changed (var, set); | |
b5b8b0ac AO |
4841 | } |
4842 | ||
4843 | return 1; | |
4844 | } | |
4845 | ||
4846 | /* Remove all MEMs from the location list of a hash table entry for a | |
4847 | value. */ | |
4848 | ||
013e5ef9 LC |
4849 | int |
4850 | dataflow_set_remove_mem_locs (variable_def **slot, dataflow_set *set) | |
b5b8b0ac | 4851 | { |
013e5ef9 | 4852 | variable var = *slot; |
b5b8b0ac | 4853 | |
09dbcd96 | 4854 | if (var->onepart == ONEPART_VALUE) |
b5b8b0ac AO |
4855 | { |
4856 | location_chain loc, *locp; | |
4857 | bool changed = false; | |
09dbcd96 | 4858 | rtx cur_loc; |
b5b8b0ac AO |
4859 | |
4860 | gcc_assert (var->n_var_parts == 1); | |
4861 | ||
864ddef7 | 4862 | if (shared_var_p (var, set->vars)) |
b5b8b0ac AO |
4863 | { |
4864 | for (loc = var->var_part[0].loc_chain; loc; loc = loc->next) | |
4a4d4c08 AO |
4865 | if (GET_CODE (loc->loc) == MEM |
4866 | && mem_dies_at_call (loc->loc)) | |
b5b8b0ac AO |
4867 | break; |
4868 | ||
4869 | if (!loc) | |
4870 | return 1; | |
4871 | ||
4872 | slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN); | |
013e5ef9 | 4873 | var = *slot; |
b5b8b0ac AO |
4874 | gcc_assert (var->n_var_parts == 1); |
4875 | } | |
4876 | ||
09dbcd96 AO |
4877 | if (VAR_LOC_1PAUX (var)) |
4878 | cur_loc = VAR_LOC_FROM (var); | |
4879 | else | |
4880 | cur_loc = var->var_part[0].cur_loc; | |
4881 | ||
b5b8b0ac AO |
4882 | for (locp = &var->var_part[0].loc_chain, loc = *locp; |
4883 | loc; loc = *locp) | |
4884 | { | |
4a4d4c08 AO |
4885 | if (GET_CODE (loc->loc) != MEM |
4886 | || !mem_dies_at_call (loc->loc)) | |
b5b8b0ac AO |
4887 | { |
4888 | locp = &loc->next; | |
4889 | continue; | |
4890 | } | |
4891 | ||
b5b8b0ac AO |
4892 | *locp = loc->next; |
4893 | /* If we have deleted the location which was last emitted | |
4894 | we have to emit new location so add the variable to set | |
4895 | of changed variables. */ | |
09dbcd96 | 4896 | if (cur_loc == loc->loc) |
864ddef7 JJ |
4897 | { |
4898 | changed = true; | |
4899 | var->var_part[0].cur_loc = NULL; | |
09dbcd96 AO |
4900 | if (VAR_LOC_1PAUX (var)) |
4901 | VAR_LOC_FROM (var) = NULL; | |
864ddef7 | 4902 | } |
7e46899d | 4903 | delete loc; |
b5b8b0ac AO |
4904 | } |
4905 | ||
4906 | if (!var->var_part[0].loc_chain) | |
4907 | { | |
4908 | var->n_var_parts--; | |
864ddef7 | 4909 | changed = true; |
b5b8b0ac AO |
4910 | } |
4911 | if (changed) | |
864ddef7 | 4912 | variable_was_changed (var, set); |
b5b8b0ac AO |
4913 | } |
4914 | ||
4915 | return 1; | |
4916 | } | |
4917 | ||
4918 | /* Remove all variable-location information about call-clobbered | |
4919 | registers, as well as associations between MEMs and VALUEs. */ | |
4920 | ||
4921 | static void | |
0f9f9784 | 4922 | dataflow_set_clear_at_call (dataflow_set *set) |
b5b8b0ac | 4923 | { |
c7fb4c7a SB |
4924 | unsigned int r; |
4925 | hard_reg_set_iterator hrsi; | |
b5b8b0ac | 4926 | |
0f9f9784 | 4927 | EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, r, hrsi) |
c7fb4c7a | 4928 | var_regno_delete (set, r); |
b5b8b0ac AO |
4929 | |
4930 | if (MAY_HAVE_DEBUG_INSNS) | |
4931 | { | |
4932 | set->traversed_vars = set->vars; | |
013e5ef9 | 4933 | shared_hash_htab (set->vars) |
c203e8a7 | 4934 | ->traverse <dataflow_set *, dataflow_set_preserve_mem_locs> (set); |
b5b8b0ac | 4935 | set->traversed_vars = set->vars; |
013e5ef9 | 4936 | shared_hash_htab (set->vars) |
c203e8a7 | 4937 | ->traverse <dataflow_set *, dataflow_set_remove_mem_locs> (set); |
b5b8b0ac AO |
4938 | set->traversed_vars = NULL; |
4939 | } | |
4940 | } | |
4941 | ||
b5b8b0ac AO |
4942 | static bool |
4943 | variable_part_different_p (variable_part *vp1, variable_part *vp2) | |
4944 | { | |
4945 | location_chain lc1, lc2; | |
4946 | ||
4947 | for (lc1 = vp1->loc_chain; lc1; lc1 = lc1->next) | |
4948 | { | |
4949 | for (lc2 = vp2->loc_chain; lc2; lc2 = lc2->next) | |
4950 | { | |
4951 | if (REG_P (lc1->loc) && REG_P (lc2->loc)) | |
4952 | { | |
4953 | if (REGNO (lc1->loc) == REGNO (lc2->loc)) | |
4954 | break; | |
4955 | } | |
4956 | if (rtx_equal_p (lc1->loc, lc2->loc)) | |
4957 | break; | |
4958 | } | |
4959 | if (!lc2) | |
4960 | return true; | |
4961 | } | |
4962 | return false; | |
4963 | } | |
4964 | ||
4965 | /* Return true if one-part variables VAR1 and VAR2 are different. | |
4966 | They must be in canonical order. */ | |
4967 | ||
4968 | static bool | |
4969 | onepart_variable_different_p (variable var1, variable var2) | |
4970 | { | |
4971 | location_chain lc1, lc2; | |
4972 | ||
4973 | if (var1 == var2) | |
4974 | return false; | |
4975 | ||
a6590c31 RG |
4976 | gcc_assert (var1->n_var_parts == 1 |
4977 | && var2->n_var_parts == 1); | |
b5b8b0ac AO |
4978 | |
4979 | lc1 = var1->var_part[0].loc_chain; | |
4980 | lc2 = var2->var_part[0].loc_chain; | |
4981 | ||
a6590c31 | 4982 | gcc_assert (lc1 && lc2); |
b5b8b0ac AO |
4983 | |
4984 | while (lc1 && lc2) | |
4985 | { | |
4986 | if (loc_cmp (lc1->loc, lc2->loc)) | |
4987 | return true; | |
4988 | lc1 = lc1->next; | |
4989 | lc2 = lc2->next; | |
4990 | } | |
4991 | ||
4992 | return lc1 != lc2; | |
4993 | } | |
4994 | ||
864ddef7 | 4995 | /* Return true if variables VAR1 and VAR2 are different. */ |
b5b8b0ac AO |
4996 | |
4997 | static bool | |
864ddef7 | 4998 | variable_different_p (variable var1, variable var2) |
b5b8b0ac AO |
4999 | { |
5000 | int i; | |
5001 | ||
5002 | if (var1 == var2) | |
5003 | return false; | |
5004 | ||
09dbcd96 AO |
5005 | if (var1->onepart != var2->onepart) |
5006 | return true; | |
5007 | ||
b5b8b0ac AO |
5008 | if (var1->n_var_parts != var2->n_var_parts) |
5009 | return true; | |
5010 | ||
09dbcd96 AO |
5011 | if (var1->onepart && var1->n_var_parts) |
5012 | { | |
5013 | gcc_checking_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv) | |
5014 | && var1->n_var_parts == 1); | |
5015 | /* One-part values have locations in a canonical order. */ | |
5016 | return onepart_variable_different_p (var1, var2); | |
5017 | } | |
5018 | ||
b5b8b0ac AO |
5019 | for (i = 0; i < var1->n_var_parts; i++) |
5020 | { | |
09dbcd96 | 5021 | if (VAR_PART_OFFSET (var1, i) != VAR_PART_OFFSET (var2, i)) |
b5b8b0ac | 5022 | return true; |
b5b8b0ac AO |
5023 | if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i])) |
5024 | return true; | |
5025 | if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i])) | |
5026 | return true; | |
5027 | } | |
5028 | return false; | |
5029 | } | |
5030 | ||
b5b8b0ac AO |
5031 | /* Return true if dataflow sets OLD_SET and NEW_SET differ. */ |
5032 | ||
5033 | static bool | |
5034 | dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set) | |
5035 | { | |
013e5ef9 | 5036 | variable_iterator_type hi; |
a6590c31 RG |
5037 | variable var1; |
5038 | ||
b5b8b0ac AO |
5039 | if (old_set->vars == new_set->vars) |
5040 | return false; | |
5041 | ||
c203e8a7 TS |
5042 | if (shared_hash_htab (old_set->vars)->elements () |
5043 | != shared_hash_htab (new_set->vars)->elements ()) | |
b5b8b0ac AO |
5044 | return true; |
5045 | ||
c203e8a7 | 5046 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (old_set->vars), |
013e5ef9 | 5047 | var1, variable, hi) |
a6590c31 | 5048 | { |
c203e8a7 TS |
5049 | variable_table_type *htab = shared_hash_htab (new_set->vars); |
5050 | variable var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv)); | |
a6590c31 RG |
5051 | if (!var2) |
5052 | { | |
5053 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
5054 | { | |
5055 | fprintf (dump_file, "dataflow difference found: removal of:\n"); | |
5056 | dump_var (var1); | |
5057 | } | |
5058 | return true; | |
5059 | } | |
5060 | ||
5061 | if (variable_different_p (var1, var2)) | |
5062 | { | |
5063 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
5064 | { | |
5065 | fprintf (dump_file, "dataflow difference found: " | |
5066 | "old and new follow:\n"); | |
5067 | dump_var (var1); | |
5068 | dump_var (var2); | |
5069 | } | |
5070 | return true; | |
5071 | } | |
5072 | } | |
b5b8b0ac | 5073 | |
b5b8b0ac AO |
5074 | /* No need to traverse the second hashtab, if both have the same number |
5075 | of elements and the second one had all entries found in the first one, | |
5076 | then it can't have any extra entries. */ | |
a6590c31 | 5077 | return false; |
b5b8b0ac AO |
5078 | } |
5079 | ||
5080 | /* Free the contents of dataflow set SET. */ | |
5081 | ||
5082 | static void | |
5083 | dataflow_set_destroy (dataflow_set *set) | |
5084 | { | |
5085 | int i; | |
5086 | ||
5087 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
5088 | attrs_list_clear (&set->regs[i]); | |
5089 | ||
5090 | shared_hash_destroy (set->vars); | |
5091 | set->vars = NULL; | |
5092 | } | |
5093 | ||
5094 | /* Return true if RTL X contains a SYMBOL_REF. */ | |
5095 | ||
5096 | static bool | |
5097 | contains_symbol_ref (rtx x) | |
5098 | { | |
5099 | const char *fmt; | |
5100 | RTX_CODE code; | |
5101 | int i; | |
5102 | ||
5103 | if (!x) | |
5104 | return false; | |
5105 | ||
5106 | code = GET_CODE (x); | |
5107 | if (code == SYMBOL_REF) | |
5108 | return true; | |
5109 | ||
5110 | fmt = GET_RTX_FORMAT (code); | |
5111 | for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) | |
5112 | { | |
5113 | if (fmt[i] == 'e') | |
5114 | { | |
5115 | if (contains_symbol_ref (XEXP (x, i))) | |
5116 | return true; | |
5117 | } | |
5118 | else if (fmt[i] == 'E') | |
5119 | { | |
5120 | int j; | |
5121 | for (j = 0; j < XVECLEN (x, i); j++) | |
5122 | if (contains_symbol_ref (XVECEXP (x, i, j))) | |
5123 | return true; | |
5124 | } | |
5125 | } | |
5126 | ||
5127 | return false; | |
5128 | } | |
5129 | ||
5130 | /* Shall EXPR be tracked? */ | |
5131 | ||
5132 | static bool | |
5133 | track_expr_p (tree expr, bool need_rtl) | |
5134 | { | |
5135 | rtx decl_rtl; | |
5136 | tree realdecl; | |
5137 | ||
0ca5af51 AO |
5138 | if (TREE_CODE (expr) == DEBUG_EXPR_DECL) |
5139 | return DECL_RTL_SET_P (expr); | |
5140 | ||
b5b8b0ac AO |
5141 | /* If EXPR is not a parameter or a variable do not track it. */ |
5142 | if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL) | |
5143 | return 0; | |
5144 | ||
5145 | /* It also must have a name... */ | |
2e957792 | 5146 | if (!DECL_NAME (expr) && need_rtl) |
b5b8b0ac AO |
5147 | return 0; |
5148 | ||
5149 | /* ... and a RTL assigned to it. */ | |
5150 | decl_rtl = DECL_RTL_IF_SET (expr); | |
5151 | if (!decl_rtl && need_rtl) | |
5152 | return 0; | |
b8698a0f L |
5153 | |
5154 | /* If this expression is really a debug alias of some other declaration, we | |
b5b8b0ac AO |
5155 | don't need to track this expression if the ultimate declaration is |
5156 | ignored. */ | |
5157 | realdecl = expr; | |
839b422f | 5158 | if (TREE_CODE (realdecl) == VAR_DECL && DECL_HAS_DEBUG_EXPR_P (realdecl)) |
b5b8b0ac AO |
5159 | { |
5160 | realdecl = DECL_DEBUG_EXPR (realdecl); | |
839b422f | 5161 | if (!DECL_P (realdecl)) |
823e9473 | 5162 | { |
9430b7ba JJ |
5163 | if (handled_component_p (realdecl) |
5164 | || (TREE_CODE (realdecl) == MEM_REF | |
5165 | && TREE_CODE (TREE_OPERAND (realdecl, 0)) == ADDR_EXPR)) | |
823e9473 JJ |
5166 | { |
5167 | HOST_WIDE_INT bitsize, bitpos, maxsize; | |
5168 | tree innerdecl | |
5169 | = get_ref_base_and_extent (realdecl, &bitpos, &bitsize, | |
5170 | &maxsize); | |
5171 | if (!DECL_P (innerdecl) | |
5172 | || DECL_IGNORED_P (innerdecl) | |
35af99b4 EB |
5173 | /* Do not track declarations for parts of tracked parameters |
5174 | since we want to track them as a whole instead. */ | |
5175 | || (TREE_CODE (innerdecl) == PARM_DECL | |
5176 | && DECL_MODE (innerdecl) != BLKmode | |
5177 | && TREE_CODE (TREE_TYPE (innerdecl)) != UNION_TYPE) | |
823e9473 JJ |
5178 | || TREE_STATIC (innerdecl) |
5179 | || bitsize <= 0 | |
5180 | || bitpos + bitsize > 256 | |
5181 | || bitsize != maxsize) | |
5182 | return 0; | |
5183 | else | |
5184 | realdecl = expr; | |
5185 | } | |
5186 | else | |
5187 | return 0; | |
5188 | } | |
b5b8b0ac AO |
5189 | } |
5190 | ||
5191 | /* Do not track EXPR if REALDECL it should be ignored for debugging | |
b8698a0f | 5192 | purposes. */ |
b5b8b0ac AO |
5193 | if (DECL_IGNORED_P (realdecl)) |
5194 | return 0; | |
5195 | ||
5196 | /* Do not track global variables until we are able to emit correct location | |
5197 | list for them. */ | |
5198 | if (TREE_STATIC (realdecl)) | |
5199 | return 0; | |
5200 | ||
5201 | /* When the EXPR is a DECL for alias of some variable (see example) | |
5202 | the TREE_STATIC flag is not used. Disable tracking all DECLs whose | |
5203 | DECL_RTL contains SYMBOL_REF. | |
5204 | ||
5205 | Example: | |
5206 | extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv"))); | |
5207 | char **_dl_argv; | |
5208 | */ | |
5209 | if (decl_rtl && MEM_P (decl_rtl) | |
5210 | && contains_symbol_ref (XEXP (decl_rtl, 0))) | |
5211 | return 0; | |
5212 | ||
5213 | /* If RTX is a memory it should not be very large (because it would be | |
5214 | an array or struct). */ | |
5215 | if (decl_rtl && MEM_P (decl_rtl)) | |
5216 | { | |
5217 | /* Do not track structures and arrays. */ | |
5218 | if (GET_MODE (decl_rtl) == BLKmode | |
5219 | || AGGREGATE_TYPE_P (TREE_TYPE (realdecl))) | |
5220 | return 0; | |
f5541398 RS |
5221 | if (MEM_SIZE_KNOWN_P (decl_rtl) |
5222 | && MEM_SIZE (decl_rtl) > MAX_VAR_PARTS) | |
b5b8b0ac AO |
5223 | return 0; |
5224 | } | |
5225 | ||
5226 | DECL_CHANGED (expr) = 0; | |
5227 | DECL_CHANGED (realdecl) = 0; | |
5228 | return 1; | |
5229 | } | |
5230 | ||
5231 | /* Determine whether a given LOC refers to the same variable part as | |
5232 | EXPR+OFFSET. */ | |
5233 | ||
5234 | static bool | |
5235 | same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset) | |
5236 | { | |
5237 | tree expr2; | |
5238 | HOST_WIDE_INT offset2; | |
5239 | ||
5240 | if (! DECL_P (expr)) | |
5241 | return false; | |
5242 | ||
5243 | if (REG_P (loc)) | |
5244 | { | |
5245 | expr2 = REG_EXPR (loc); | |
5246 | offset2 = REG_OFFSET (loc); | |
5247 | } | |
5248 | else if (MEM_P (loc)) | |
5249 | { | |
5250 | expr2 = MEM_EXPR (loc); | |
5251 | offset2 = INT_MEM_OFFSET (loc); | |
5252 | } | |
5253 | else | |
5254 | return false; | |
5255 | ||
5256 | if (! expr2 || ! DECL_P (expr2)) | |
5257 | return false; | |
5258 | ||
5259 | expr = var_debug_decl (expr); | |
5260 | expr2 = var_debug_decl (expr2); | |
5261 | ||
5262 | return (expr == expr2 && offset == offset2); | |
5263 | } | |
5264 | ||
5265 | /* LOC is a REG or MEM that we would like to track if possible. | |
38ae7651 RS |
5266 | If EXPR is null, we don't know what expression LOC refers to, |
5267 | otherwise it refers to EXPR + OFFSET. STORE_REG_P is true if | |
5268 | LOC is an lvalue register. | |
94a7682d | 5269 | |
38ae7651 RS |
5270 | Return true if EXPR is nonnull and if LOC, or some lowpart of it, |
5271 | is something we can track. When returning true, store the mode of | |
5272 | the lowpart we can track in *MODE_OUT (if nonnull) and its offset | |
5273 | from EXPR in *OFFSET_OUT (if nonnull). */ | |
94a7682d | 5274 | |
38ae7651 RS |
5275 | static bool |
5276 | track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p, | |
ef4bddc2 | 5277 | machine_mode *mode_out, HOST_WIDE_INT *offset_out) |
94a7682d | 5278 | { |
ef4bddc2 | 5279 | machine_mode mode; |
94a7682d | 5280 | |
b5b8b0ac | 5281 | if (expr == NULL || !track_expr_p (expr, true)) |
38ae7651 RS |
5282 | return false; |
5283 | ||
5284 | /* If REG was a paradoxical subreg, its REG_ATTRS will describe the | |
5285 | whole subreg, but only the old inner part is really relevant. */ | |
5286 | mode = GET_MODE (loc); | |
5287 | if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc))) | |
94a7682d | 5288 | { |
ef4bddc2 | 5289 | machine_mode pseudo_mode; |
94a7682d | 5290 | |
38ae7651 | 5291 | pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc)); |
94a7682d | 5292 | if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode)) |
38ae7651 RS |
5293 | { |
5294 | offset += byte_lowpart_offset (pseudo_mode, mode); | |
5295 | mode = pseudo_mode; | |
5296 | } | |
5297 | } | |
5298 | ||
5299 | /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself. | |
5300 | Do the same if we are storing to a register and EXPR occupies | |
5301 | the whole of register LOC; in that case, the whole of EXPR is | |
5302 | being changed. We exclude complex modes from the second case | |
5303 | because the real and imaginary parts are represented as separate | |
5304 | pseudo registers, even if the whole complex value fits into one | |
5305 | hard register. */ | |
5306 | if ((GET_MODE_SIZE (mode) > GET_MODE_SIZE (DECL_MODE (expr)) | |
5307 | || (store_reg_p | |
5308 | && !COMPLEX_MODE_P (DECL_MODE (expr)) | |
5309 | && hard_regno_nregs[REGNO (loc)][DECL_MODE (expr)] == 1)) | |
5310 | && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0) | |
5311 | { | |
5312 | mode = DECL_MODE (expr); | |
5313 | offset = 0; | |
94a7682d | 5314 | } |
38ae7651 RS |
5315 | |
5316 | if (offset < 0 || offset >= MAX_VAR_PARTS) | |
5317 | return false; | |
5318 | ||
5319 | if (mode_out) | |
5320 | *mode_out = mode; | |
5321 | if (offset_out) | |
5322 | *offset_out = offset; | |
5323 | return true; | |
94a7682d RS |
5324 | } |
5325 | ||
5326 | /* Return the MODE lowpart of LOC, or null if LOC is not something we | |
5327 | want to track. When returning nonnull, make sure that the attributes | |
5328 | on the returned value are updated. */ | |
5329 | ||
5330 | static rtx | |
ef4bddc2 | 5331 | var_lowpart (machine_mode mode, rtx loc) |
94a7682d | 5332 | { |
38ae7651 | 5333 | unsigned int offset, reg_offset, regno; |
94a7682d | 5334 | |
94a7682d RS |
5335 | if (GET_MODE (loc) == mode) |
5336 | return loc; | |
5337 | ||
1791f36f UB |
5338 | if (!REG_P (loc) && !MEM_P (loc)) |
5339 | return NULL; | |
5340 | ||
b5b8b0ac AO |
5341 | offset = byte_lowpart_offset (mode, GET_MODE (loc)); |
5342 | ||
5343 | if (MEM_P (loc)) | |
5344 | return adjust_address_nv (loc, mode, offset); | |
5345 | ||
5346 | reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc)); | |
5347 | regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc), | |
5348 | reg_offset, mode); | |
5349 | return gen_rtx_REG_offset (loc, mode, regno, offset); | |
5350 | } | |
5351 | ||
5352 | /* Carry information about uses and stores while walking rtx. */ | |
5353 | ||
5354 | struct count_use_info | |
5355 | { | |
5356 | /* The insn where the RTX is. */ | |
598d62da | 5357 | rtx_insn *insn; |
b5b8b0ac AO |
5358 | |
5359 | /* The basic block where insn is. */ | |
5360 | basic_block bb; | |
5361 | ||
5362 | /* The array of n_sets sets in the insn, as determined by cselib. */ | |
5363 | struct cselib_set *sets; | |
5364 | int n_sets; | |
5365 | ||
5366 | /* True if we're counting stores, false otherwise. */ | |
5367 | bool store_p; | |
5368 | }; | |
5369 | ||
5370 | /* Find a VALUE corresponding to X. */ | |
5371 | ||
5372 | static inline cselib_val * | |
ef4bddc2 | 5373 | find_use_val (rtx x, machine_mode mode, struct count_use_info *cui) |
b5b8b0ac AO |
5374 | { |
5375 | int i; | |
5376 | ||
5377 | if (cui->sets) | |
5378 | { | |
5379 | /* This is called after uses are set up and before stores are | |
c7148991 | 5380 | processed by cselib, so it's safe to look up srcs, but not |
b5b8b0ac AO |
5381 | dsts. So we look up expressions that appear in srcs or in |
5382 | dest expressions, but we search the sets array for dests of | |
5383 | stores. */ | |
5384 | if (cui->store_p) | |
5385 | { | |
c7148991 JJ |
5386 | /* Some targets represent memset and memcpy patterns |
5387 | by (set (mem:BLK ...) (reg:[QHSD]I ...)) or | |
5388 | (set (mem:BLK ...) (const_int ...)) or | |
5389 | (set (mem:BLK ...) (mem:BLK ...)). Don't return anything | |
5390 | in that case, otherwise we end up with mode mismatches. */ | |
5391 | if (mode == BLKmode && MEM_P (x)) | |
5392 | return NULL; | |
b5b8b0ac AO |
5393 | for (i = 0; i < cui->n_sets; i++) |
5394 | if (cui->sets[i].dest == x) | |
5395 | return cui->sets[i].src_elt; | |
5396 | } | |
5397 | else | |
4deef538 | 5398 | return cselib_lookup (x, mode, 0, VOIDmode); |
b5b8b0ac AO |
5399 | } |
5400 | ||
5401 | return NULL; | |
5402 | } | |
5403 | ||
5404 | /* Replace all registers and addresses in an expression with VALUE | |
5405 | expressions that map back to them, unless the expression is a | |
5406 | register. If no mapping is or can be performed, returns NULL. */ | |
5407 | ||
5408 | static rtx | |
5409 | replace_expr_with_values (rtx loc) | |
5410 | { | |
509f4495 | 5411 | if (REG_P (loc) || GET_CODE (loc) == ENTRY_VALUE) |
b5b8b0ac AO |
5412 | return NULL; |
5413 | else if (MEM_P (loc)) | |
5414 | { | |
457eeaae | 5415 | cselib_val *addr = cselib_lookup (XEXP (loc, 0), |
4deef538 AO |
5416 | get_address_mode (loc), 0, |
5417 | GET_MODE (loc)); | |
b5b8b0ac AO |
5418 | if (addr) |
5419 | return replace_equiv_address_nv (loc, addr->val_rtx); | |
5420 | else | |
5421 | return NULL; | |
5422 | } | |
5423 | else | |
4deef538 | 5424 | return cselib_subst_to_values (loc, VOIDmode); |
b5b8b0ac AO |
5425 | } |
5426 | ||
4f498863 | 5427 | /* Return true if X contains a DEBUG_EXPR. */ |
bfd5f9f5 | 5428 | |
4f498863 RS |
5429 | static bool |
5430 | rtx_debug_expr_p (const_rtx x) | |
bfd5f9f5 | 5431 | { |
4f498863 RS |
5432 | subrtx_iterator::array_type array; |
5433 | FOR_EACH_SUBRTX (iter, array, x, ALL) | |
5434 | if (GET_CODE (*iter) == DEBUG_EXPR) | |
5435 | return true; | |
5436 | return false; | |
bfd5f9f5 AO |
5437 | } |
5438 | ||
b5b8b0ac AO |
5439 | /* Determine what kind of micro operation to choose for a USE. Return |
5440 | MO_CLOBBER if no micro operation is to be generated. */ | |
5441 | ||
5442 | static enum micro_operation_type | |
ef4bddc2 | 5443 | use_type (rtx loc, struct count_use_info *cui, machine_mode *modep) |
b5b8b0ac AO |
5444 | { |
5445 | tree expr; | |
b5b8b0ac AO |
5446 | |
5447 | if (cui && cui->sets) | |
5448 | { | |
951d4497 | 5449 | if (GET_CODE (loc) == VAR_LOCATION) |
b5b8b0ac | 5450 | { |
951d4497 | 5451 | if (track_expr_p (PAT_VAR_LOCATION_DECL (loc), false)) |
b5b8b0ac | 5452 | { |
951d4497 | 5453 | rtx ploc = PAT_VAR_LOCATION_LOC (loc); |
457eeaae JJ |
5454 | if (! VAR_LOC_UNKNOWN_P (ploc)) |
5455 | { | |
4deef538 AO |
5456 | cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1, |
5457 | VOIDmode); | |
b5b8b0ac | 5458 | |
457eeaae JJ |
5459 | /* ??? flag_float_store and volatile mems are never |
5460 | given values, but we could in theory use them for | |
5461 | locations. */ | |
5462 | gcc_assert (val || 1); | |
5463 | } | |
b5b8b0ac AO |
5464 | return MO_VAL_LOC; |
5465 | } | |
5466 | else | |
5467 | return MO_CLOBBER; | |
5468 | } | |
5469 | ||
f827f659 | 5470 | if (REG_P (loc) || MEM_P (loc)) |
b5b8b0ac AO |
5471 | { |
5472 | if (modep) | |
951d4497 | 5473 | *modep = GET_MODE (loc); |
b5b8b0ac AO |
5474 | if (cui->store_p) |
5475 | { | |
951d4497 | 5476 | if (REG_P (loc) |
f827f659 | 5477 | || (find_use_val (loc, GET_MODE (loc), cui) |
457eeaae | 5478 | && cselib_lookup (XEXP (loc, 0), |
4deef538 AO |
5479 | get_address_mode (loc), 0, |
5480 | GET_MODE (loc)))) | |
b5b8b0ac AO |
5481 | return MO_VAL_SET; |
5482 | } | |
f827f659 AO |
5483 | else |
5484 | { | |
5485 | cselib_val *val = find_use_val (loc, GET_MODE (loc), cui); | |
5486 | ||
5487 | if (val && !cselib_preserved_value_p (val)) | |
5488 | return MO_VAL_USE; | |
5489 | } | |
b5b8b0ac AO |
5490 | } |
5491 | } | |
5492 | ||
951d4497 | 5493 | if (REG_P (loc)) |
b5b8b0ac | 5494 | { |
951d4497 | 5495 | gcc_assert (REGNO (loc) < FIRST_PSEUDO_REGISTER); |
b5b8b0ac | 5496 | |
457eeaae JJ |
5497 | if (loc == cfa_base_rtx) |
5498 | return MO_CLOBBER; | |
951d4497 | 5499 | expr = REG_EXPR (loc); |
b5b8b0ac AO |
5500 | |
5501 | if (!expr) | |
5502 | return MO_USE_NO_VAR; | |
5503 | else if (target_for_debug_bind (var_debug_decl (expr))) | |
5504 | return MO_CLOBBER; | |
951d4497 | 5505 | else if (track_loc_p (loc, expr, REG_OFFSET (loc), |
b5b8b0ac AO |
5506 | false, modep, NULL)) |
5507 | return MO_USE; | |
5508 | else | |
5509 | return MO_USE_NO_VAR; | |
5510 | } | |
951d4497 | 5511 | else if (MEM_P (loc)) |
b5b8b0ac | 5512 | { |
951d4497 | 5513 | expr = MEM_EXPR (loc); |
b5b8b0ac AO |
5514 | |
5515 | if (!expr) | |
5516 | return MO_CLOBBER; | |
5517 | else if (target_for_debug_bind (var_debug_decl (expr))) | |
5518 | return MO_CLOBBER; | |
951d4497 | 5519 | else if (track_loc_p (loc, expr, INT_MEM_OFFSET (loc), |
bfd5f9f5 AO |
5520 | false, modep, NULL) |
5521 | /* Multi-part variables shouldn't refer to one-part | |
5522 | variable names such as VALUEs (never happens) or | |
5523 | DEBUG_EXPRs (only happens in the presence of debug | |
5524 | insns). */ | |
5525 | && (!MAY_HAVE_DEBUG_INSNS | |
4f498863 | 5526 | || !rtx_debug_expr_p (XEXP (loc, 0)))) |
b5b8b0ac AO |
5527 | return MO_USE; |
5528 | else | |
5529 | return MO_CLOBBER; | |
5530 | } | |
5531 | ||
5532 | return MO_CLOBBER; | |
5533 | } | |
94a7682d | 5534 | |
b5b8b0ac AO |
5535 | /* Log to OUT information about micro-operation MOPT involving X in |
5536 | INSN of BB. */ | |
94a7682d | 5537 | |
b5b8b0ac | 5538 | static inline void |
598d62da | 5539 | log_op_type (rtx x, basic_block bb, rtx_insn *insn, |
b5b8b0ac AO |
5540 | enum micro_operation_type mopt, FILE *out) |
5541 | { | |
5542 | fprintf (out, "bb %i op %i insn %i %s ", | |
9771b263 | 5543 | bb->index, VTI (bb)->mos.length (), |
b5b8b0ac AO |
5544 | INSN_UID (insn), micro_operation_type_name[mopt]); |
5545 | print_inline_rtx (out, x, 2); | |
5546 | fputc ('\n', out); | |
94a7682d | 5547 | } |
ca787200 | 5548 | |
b5b8b0ac AO |
5549 | /* Tell whether the CONCAT used to holds a VALUE and its location |
5550 | needs value resolution, i.e., an attempt of mapping the location | |
5551 | back to other incoming values. */ | |
5552 | #define VAL_NEEDS_RESOLUTION(x) \ | |
5553 | (RTL_FLAG_CHECK1 ("VAL_NEEDS_RESOLUTION", (x), CONCAT)->volatil) | |
5554 | /* Whether the location in the CONCAT is a tracked expression, that | |
5555 | should also be handled like a MO_USE. */ | |
5556 | #define VAL_HOLDS_TRACK_EXPR(x) \ | |
5557 | (RTL_FLAG_CHECK1 ("VAL_HOLDS_TRACK_EXPR", (x), CONCAT)->used) | |
5558 | /* Whether the location in the CONCAT should be handled like a MO_COPY | |
5559 | as well. */ | |
5560 | #define VAL_EXPR_IS_COPIED(x) \ | |
5561 | (RTL_FLAG_CHECK1 ("VAL_EXPR_IS_COPIED", (x), CONCAT)->jump) | |
5562 | /* Whether the location in the CONCAT should be handled like a | |
5563 | MO_CLOBBER as well. */ | |
5564 | #define VAL_EXPR_IS_CLOBBERED(x) \ | |
5565 | (RTL_FLAG_CHECK1 ("VAL_EXPR_IS_CLOBBERED", (x), CONCAT)->unchanging) | |
5566 | ||
1feb8238 | 5567 | /* All preserved VALUEs. */ |
9771b263 | 5568 | static vec<rtx> preserved_values; |
1feb8238 | 5569 | |
0de3e43f | 5570 | /* Ensure VAL is preserved and remember it in a vector for vt_emit_notes. */ |
1feb8238 JJ |
5571 | |
5572 | static void | |
5573 | preserve_value (cselib_val *val) | |
5574 | { | |
5575 | cselib_preserve_value (val); | |
9771b263 | 5576 | preserved_values.safe_push (val->val_rtx); |
1feb8238 JJ |
5577 | } |
5578 | ||
5644a3d0 JJ |
5579 | /* Helper function for MO_VAL_LOC handling. Return non-zero if |
5580 | any rtxes not suitable for CONST use not replaced by VALUEs | |
5581 | are discovered. */ | |
5582 | ||
7e56c283 RS |
5583 | static bool |
5584 | non_suitable_const (const_rtx x) | |
5644a3d0 | 5585 | { |
7e56c283 RS |
5586 | subrtx_iterator::array_type array; |
5587 | FOR_EACH_SUBRTX (iter, array, x, ALL) | |
5644a3d0 | 5588 | { |
7e56c283 RS |
5589 | const_rtx x = *iter; |
5590 | switch (GET_CODE (x)) | |
5591 | { | |
5592 | case REG: | |
5593 | case DEBUG_EXPR: | |
5594 | case PC: | |
5595 | case SCRATCH: | |
5596 | case CC0: | |
5597 | case ASM_INPUT: | |
5598 | case ASM_OPERANDS: | |
5599 | return true; | |
5600 | case MEM: | |
5601 | if (!MEM_READONLY_P (x)) | |
5602 | return true; | |
5603 | break; | |
5604 | default: | |
5605 | break; | |
5606 | } | |
5644a3d0 | 5607 | } |
7e56c283 | 5608 | return false; |
5644a3d0 JJ |
5609 | } |
5610 | ||
014a1138 | 5611 | /* Add uses (register and memory references) LOC which will be tracked |
3b4459f9 | 5612 | to VTI (bb)->mos. */ |
014a1138 | 5613 | |
3b4459f9 RS |
5614 | static void |
5615 | add_uses (rtx loc, struct count_use_info *cui) | |
014a1138 | 5616 | { |
ef4bddc2 | 5617 | machine_mode mode = VOIDmode; |
b5b8b0ac | 5618 | enum micro_operation_type type = use_type (loc, cui, &mode); |
38ae7651 | 5619 | |
b5b8b0ac | 5620 | if (type != MO_CLOBBER) |
014a1138 | 5621 | { |
b5b8b0ac | 5622 | basic_block bb = cui->bb; |
0de3e43f | 5623 | micro_operation mo; |
014a1138 | 5624 | |
0de3e43f JJ |
5625 | mo.type = type; |
5626 | mo.u.loc = type == MO_USE ? var_lowpart (mode, loc) : loc; | |
5627 | mo.insn = cui->insn; | |
b5b8b0ac AO |
5628 | |
5629 | if (type == MO_VAL_LOC) | |
94a7682d | 5630 | { |
951d4497 | 5631 | rtx oloc = loc; |
b5b8b0ac AO |
5632 | rtx vloc = PAT_VAR_LOCATION_LOC (oloc); |
5633 | cselib_val *val; | |
5634 | ||
5635 | gcc_assert (cui->sets); | |
5636 | ||
5637 | if (MEM_P (vloc) | |
457eeaae | 5638 | && !REG_P (XEXP (vloc, 0)) |
09dbcd96 | 5639 | && !MEM_P (XEXP (vloc, 0))) |
b5b8b0ac AO |
5640 | { |
5641 | rtx mloc = vloc; | |
ef4bddc2 | 5642 | machine_mode address_mode = get_address_mode (mloc); |
d4ebfa65 | 5643 | cselib_val *val |
4deef538 AO |
5644 | = cselib_lookup (XEXP (mloc, 0), address_mode, 0, |
5645 | GET_MODE (mloc)); | |
b5b8b0ac AO |
5646 | |
5647 | if (val && !cselib_preserved_value_p (val)) | |
6f2ffb4b | 5648 | preserve_value (val); |
b5b8b0ac AO |
5649 | } |
5650 | ||
5644a3d0 | 5651 | if (CONSTANT_P (vloc) |
7e56c283 | 5652 | && (GET_CODE (vloc) != CONST || non_suitable_const (vloc))) |
5644a3d0 | 5653 | /* For constants don't look up any value. */; |
09dbcd96 | 5654 | else if (!VAR_LOC_UNKNOWN_P (vloc) && !unsuitable_loc (vloc) |
5644a3d0 | 5655 | && (val = find_use_val (vloc, GET_MODE (oloc), cui))) |
b5b8b0ac | 5656 | { |
ef4bddc2 | 5657 | machine_mode mode2; |
b5b8b0ac | 5658 | enum micro_operation_type type2; |
6f2ffb4b AO |
5659 | rtx nloc = NULL; |
5660 | bool resolvable = REG_P (vloc) || MEM_P (vloc); | |
5661 | ||
5662 | if (resolvable) | |
5663 | nloc = replace_expr_with_values (vloc); | |
b5b8b0ac AO |
5664 | |
5665 | if (nloc) | |
5666 | { | |
5667 | oloc = shallow_copy_rtx (oloc); | |
5668 | PAT_VAR_LOCATION_LOC (oloc) = nloc; | |
5669 | } | |
5670 | ||
5671 | oloc = gen_rtx_CONCAT (mode, val->val_rtx, oloc); | |
5672 | ||
951d4497 | 5673 | type2 = use_type (vloc, 0, &mode2); |
b5b8b0ac AO |
5674 | |
5675 | gcc_assert (type2 == MO_USE || type2 == MO_USE_NO_VAR | |
5676 | || type2 == MO_CLOBBER); | |
5677 | ||
5678 | if (type2 == MO_CLOBBER | |
5679 | && !cselib_preserved_value_p (val)) | |
5680 | { | |
6f2ffb4b | 5681 | VAL_NEEDS_RESOLUTION (oloc) = resolvable; |
1feb8238 | 5682 | preserve_value (val); |
b5b8b0ac AO |
5683 | } |
5684 | } | |
5685 | else if (!VAR_LOC_UNKNOWN_P (vloc)) | |
5686 | { | |
5687 | oloc = shallow_copy_rtx (oloc); | |
5688 | PAT_VAR_LOCATION_LOC (oloc) = gen_rtx_UNKNOWN_VAR_LOC (); | |
5689 | } | |
5690 | ||
0de3e43f | 5691 | mo.u.loc = oloc; |
94a7682d | 5692 | } |
b5b8b0ac | 5693 | else if (type == MO_VAL_USE) |
94a7682d | 5694 | { |
ef4bddc2 | 5695 | machine_mode mode2 = VOIDmode; |
b5b8b0ac | 5696 | enum micro_operation_type type2; |
951d4497 AO |
5697 | cselib_val *val = find_use_val (loc, GET_MODE (loc), cui); |
5698 | rtx vloc, oloc = loc, nloc; | |
b5b8b0ac AO |
5699 | |
5700 | gcc_assert (cui->sets); | |
5701 | ||
5702 | if (MEM_P (oloc) | |
457eeaae | 5703 | && !REG_P (XEXP (oloc, 0)) |
09dbcd96 | 5704 | && !MEM_P (XEXP (oloc, 0))) |
b5b8b0ac AO |
5705 | { |
5706 | rtx mloc = oloc; | |
ef4bddc2 | 5707 | machine_mode address_mode = get_address_mode (mloc); |
d4ebfa65 | 5708 | cselib_val *val |
4deef538 | 5709 | = cselib_lookup (XEXP (mloc, 0), address_mode, 0, |
09dbcd96 | 5710 | GET_MODE (mloc)); |
b5b8b0ac AO |
5711 | |
5712 | if (val && !cselib_preserved_value_p (val)) | |
6f2ffb4b | 5713 | preserve_value (val); |
b5b8b0ac AO |
5714 | } |
5715 | ||
5716 | type2 = use_type (loc, 0, &mode2); | |
5717 | ||
5718 | gcc_assert (type2 == MO_USE || type2 == MO_USE_NO_VAR | |
5719 | || type2 == MO_CLOBBER); | |
5720 | ||
5721 | if (type2 == MO_USE) | |
951d4497 | 5722 | vloc = var_lowpart (mode2, loc); |
b5b8b0ac AO |
5723 | else |
5724 | vloc = oloc; | |
5725 | ||
5726 | /* The loc of a MO_VAL_USE may have two forms: | |
5727 | ||
5728 | (concat val src): val is at src, a value-based | |
5729 | representation. | |
5730 | ||
5731 | (concat (concat val use) src): same as above, with use as | |
5732 | the MO_USE tracked value, if it differs from src. | |
5733 | ||
5734 | */ | |
5735 | ||
6f2ffb4b | 5736 | gcc_checking_assert (REG_P (loc) || MEM_P (loc)); |
951d4497 | 5737 | nloc = replace_expr_with_values (loc); |
b5b8b0ac AO |
5738 | if (!nloc) |
5739 | nloc = oloc; | |
5740 | ||
5741 | if (vloc != nloc) | |
5742 | oloc = gen_rtx_CONCAT (mode2, val->val_rtx, vloc); | |
5743 | else | |
5744 | oloc = val->val_rtx; | |
5745 | ||
0de3e43f | 5746 | mo.u.loc = gen_rtx_CONCAT (mode, oloc, nloc); |
b5b8b0ac AO |
5747 | |
5748 | if (type2 == MO_USE) | |
0de3e43f | 5749 | VAL_HOLDS_TRACK_EXPR (mo.u.loc) = 1; |
b5b8b0ac AO |
5750 | if (!cselib_preserved_value_p (val)) |
5751 | { | |
0de3e43f | 5752 | VAL_NEEDS_RESOLUTION (mo.u.loc) = 1; |
1feb8238 | 5753 | preserve_value (val); |
b5b8b0ac | 5754 | } |
94a7682d | 5755 | } |
b5b8b0ac AO |
5756 | else |
5757 | gcc_assert (type == MO_USE || type == MO_USE_NO_VAR); | |
014a1138 | 5758 | |
b5b8b0ac | 5759 | if (dump_file && (dump_flags & TDF_DETAILS)) |
0de3e43f | 5760 | log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file); |
9771b263 | 5761 | VTI (bb)->mos.safe_push (mo); |
014a1138 | 5762 | } |
014a1138 JZ |
5763 | } |
5764 | ||
5765 | /* Helper function for finding all uses of REG/MEM in X in insn INSN. */ | |
5766 | ||
5767 | static void | |
b5b8b0ac | 5768 | add_uses_1 (rtx *x, void *cui) |
014a1138 | 5769 | { |
3b4459f9 RS |
5770 | subrtx_var_iterator::array_type array; |
5771 | FOR_EACH_SUBRTX_VAR (iter, array, *x, NONCONST) | |
5772 | add_uses (*iter, (struct count_use_info *) cui); | |
014a1138 JZ |
5773 | } |
5774 | ||
09dbcd96 AO |
5775 | /* This is the value used during expansion of locations. We want it |
5776 | to be unbounded, so that variables expanded deep in a recursion | |
5777 | nest are fully evaluated, so that their values are cached | |
5778 | correctly. We avoid recursion cycles through other means, and we | |
5779 | don't unshare RTL, so excess complexity is not a problem. */ | |
5780 | #define EXPR_DEPTH (INT_MAX) | |
5781 | /* We use this to keep too-complex expressions from being emitted as | |
5782 | location notes, and then to debug information. Users can trade | |
5783 | compile time for ridiculously complex expressions, although they're | |
5784 | seldom useful, and they may often have to be discarded as not | |
5785 | representable anyway. */ | |
5786 | #define EXPR_USE_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH)) | |
f0686e78 | 5787 | |
6f2ffb4b AO |
5788 | /* Attempt to reverse the EXPR operation in the debug info and record |
5789 | it in the cselib table. Say for reg1 = reg2 + 6 even when reg2 is | |
5790 | no longer live we can express its value as VAL - 6. */ | |
0c5863c2 | 5791 | |
6f2ffb4b | 5792 | static void |
598d62da | 5793 | reverse_op (rtx val, const_rtx expr, rtx_insn *insn) |
0c5863c2 JJ |
5794 | { |
5795 | rtx src, arg, ret; | |
5796 | cselib_val *v; | |
ae25db45 | 5797 | struct elt_loc_list *l; |
0c5863c2 | 5798 | enum rtx_code code; |
8ab1d2e9 | 5799 | int count; |
0c5863c2 JJ |
5800 | |
5801 | if (GET_CODE (expr) != SET) | |
6f2ffb4b | 5802 | return; |
0c5863c2 JJ |
5803 | |
5804 | if (!REG_P (SET_DEST (expr)) || GET_MODE (val) != GET_MODE (SET_DEST (expr))) | |
6f2ffb4b | 5805 | return; |
0c5863c2 JJ |
5806 | |
5807 | src = SET_SRC (expr); | |
5808 | switch (GET_CODE (src)) | |
5809 | { | |
5810 | case PLUS: | |
5811 | case MINUS: | |
5812 | case XOR: | |
5813 | case NOT: | |
5814 | case NEG: | |
370ae599 | 5815 | if (!REG_P (XEXP (src, 0))) |
6f2ffb4b | 5816 | return; |
370ae599 | 5817 | break; |
0c5863c2 JJ |
5818 | case SIGN_EXTEND: |
5819 | case ZERO_EXTEND: | |
370ae599 | 5820 | if (!REG_P (XEXP (src, 0)) && !MEM_P (XEXP (src, 0))) |
6f2ffb4b | 5821 | return; |
0c5863c2 JJ |
5822 | break; |
5823 | default: | |
6f2ffb4b | 5824 | return; |
0c5863c2 JJ |
5825 | } |
5826 | ||
370ae599 | 5827 | if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx) |
6f2ffb4b | 5828 | return; |
0c5863c2 | 5829 | |
4deef538 | 5830 | v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0, VOIDmode); |
0c5863c2 | 5831 | if (!v || !cselib_preserved_value_p (v)) |
6f2ffb4b | 5832 | return; |
0c5863c2 | 5833 | |
0e224656 AO |
5834 | /* Use canonical V to avoid creating multiple redundant expressions |
5835 | for different VALUES equivalent to V. */ | |
5836 | v = canonical_cselib_val (v); | |
5837 | ||
ae25db45 JJ |
5838 | /* Adding a reverse op isn't useful if V already has an always valid |
5839 | location. Ignore ENTRY_VALUE, while it is always constant, we should | |
5840 | prefer non-ENTRY_VALUE locations whenever possible. */ | |
8ab1d2e9 | 5841 | for (l = v->locs, count = 0; l; l = l->next, count++) |
ae25db45 JJ |
5842 | if (CONSTANT_P (l->loc) |
5843 | && (GET_CODE (l->loc) != CONST || !references_value_p (l->loc, 0))) | |
5844 | return; | |
8ab1d2e9 JJ |
5845 | /* Avoid creating too large locs lists. */ |
5846 | else if (count == PARAM_VALUE (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE)) | |
5847 | return; | |
ae25db45 | 5848 | |
0c5863c2 JJ |
5849 | switch (GET_CODE (src)) |
5850 | { | |
5851 | case NOT: | |
5852 | case NEG: | |
5853 | if (GET_MODE (v->val_rtx) != GET_MODE (val)) | |
6f2ffb4b | 5854 | return; |
0c5863c2 JJ |
5855 | ret = gen_rtx_fmt_e (GET_CODE (src), GET_MODE (val), val); |
5856 | break; | |
5857 | case SIGN_EXTEND: | |
5858 | case ZERO_EXTEND: | |
5859 | ret = gen_lowpart_SUBREG (GET_MODE (v->val_rtx), val); | |
5860 | break; | |
5861 | case XOR: | |
5862 | code = XOR; | |
5863 | goto binary; | |
5864 | case PLUS: | |
5865 | code = MINUS; | |
5866 | goto binary; | |
5867 | case MINUS: | |
5868 | code = PLUS; | |
5869 | goto binary; | |
5870 | binary: | |
5871 | if (GET_MODE (v->val_rtx) != GET_MODE (val)) | |
6f2ffb4b | 5872 | return; |
0c5863c2 JJ |
5873 | arg = XEXP (src, 1); |
5874 | if (!CONST_INT_P (arg) && GET_CODE (arg) != SYMBOL_REF) | |
5875 | { | |
d5b6cc25 | 5876 | arg = cselib_expand_value_rtx (arg, scratch_regs, 5); |
0c5863c2 | 5877 | if (arg == NULL_RTX) |
6f2ffb4b | 5878 | return; |
0c5863c2 | 5879 | if (!CONST_INT_P (arg) && GET_CODE (arg) != SYMBOL_REF) |
6f2ffb4b | 5880 | return; |
0c5863c2 JJ |
5881 | } |
5882 | ret = simplify_gen_binary (code, GET_MODE (val), val, arg); | |
5883 | if (ret == val) | |
5884 | /* Ensure ret isn't VALUE itself (which can happen e.g. for | |
5885 | (plus (reg1) (reg2)) when reg2 is known to be 0), as that | |
5886 | breaks a lot of routines during var-tracking. */ | |
5887 | ret = gen_rtx_fmt_ee (PLUS, GET_MODE (val), val, const0_rtx); | |
5888 | break; | |
5889 | default: | |
5890 | gcc_unreachable (); | |
5891 | } | |
5892 | ||
6f2ffb4b | 5893 | cselib_add_permanent_equiv (v, ret, insn); |
0c5863c2 JJ |
5894 | } |
5895 | ||
014a1138 | 5896 | /* Add stores (register and memory references) LOC which will be tracked |
b5b8b0ac AO |
5897 | to VTI (bb)->mos. EXPR is the RTL expression containing the store. |
5898 | CUIP->insn is instruction which the LOC is part of. */ | |
014a1138 JZ |
5899 | |
5900 | static void | |
b5b8b0ac | 5901 | add_stores (rtx loc, const_rtx expr, void *cuip) |
014a1138 | 5902 | { |
ef4bddc2 | 5903 | machine_mode mode = VOIDmode, mode2; |
b5b8b0ac AO |
5904 | struct count_use_info *cui = (struct count_use_info *)cuip; |
5905 | basic_block bb = cui->bb; | |
0de3e43f | 5906 | micro_operation mo; |
b5b8b0ac | 5907 | rtx oloc = loc, nloc, src = NULL; |
951d4497 | 5908 | enum micro_operation_type type = use_type (loc, cui, &mode); |
b5b8b0ac AO |
5909 | bool track_p = false; |
5910 | cselib_val *v; | |
5911 | bool resolve, preserve; | |
5912 | ||
5913 | if (type == MO_CLOBBER) | |
5914 | return; | |
5915 | ||
5916 | mode2 = mode; | |
38ae7651 | 5917 | |
f8cfc6aa | 5918 | if (REG_P (loc)) |
014a1138 | 5919 | { |
457eeaae | 5920 | gcc_assert (loc != cfa_base_rtx); |
b5b8b0ac | 5921 | if ((GET_CODE (expr) == CLOBBER && type != MO_VAL_SET) |
951d4497 | 5922 | || !(track_p = use_type (loc, NULL, &mode2) == MO_USE) |
b5b8b0ac | 5923 | || GET_CODE (expr) == CLOBBER) |
94a7682d | 5924 | { |
0de3e43f JJ |
5925 | mo.type = MO_CLOBBER; |
5926 | mo.u.loc = loc; | |
2b1c5433 JJ |
5927 | if (GET_CODE (expr) == SET |
5928 | && SET_DEST (expr) == loc | |
09dbcd96 AO |
5929 | && !unsuitable_loc (SET_SRC (expr)) |
5930 | && find_use_val (loc, mode, cui)) | |
2b1c5433 JJ |
5931 | { |
5932 | gcc_checking_assert (type == MO_VAL_SET); | |
f7df4a84 | 5933 | mo.u.loc = gen_rtx_SET (loc, SET_SRC (expr)); |
2b1c5433 | 5934 | } |
94a7682d | 5935 | } |
ca787200 | 5936 | else |
94a7682d | 5937 | { |
2b1c5433 JJ |
5938 | if (GET_CODE (expr) == SET |
5939 | && SET_DEST (expr) == loc | |
5940 | && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS) | |
457eeaae | 5941 | src = var_lowpart (mode2, SET_SRC (expr)); |
b5b8b0ac | 5942 | loc = var_lowpart (mode2, loc); |
94a7682d RS |
5943 | |
5944 | if (src == NULL) | |
5945 | { | |
0de3e43f JJ |
5946 | mo.type = MO_SET; |
5947 | mo.u.loc = loc; | |
94a7682d RS |
5948 | } |
5949 | else | |
5950 | { | |
f7df4a84 | 5951 | rtx xexpr = gen_rtx_SET (loc, src); |
94a7682d | 5952 | if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc))) |
f7e088e7 EB |
5953 | { |
5954 | /* If this is an instruction copying (part of) a parameter | |
5955 | passed by invisible reference to its register location, | |
5956 | pretend it's a SET so that the initial memory location | |
5957 | is discarded, as the parameter register can be reused | |
5958 | for other purposes and we do not track locations based | |
5959 | on generic registers. */ | |
5960 | if (MEM_P (src) | |
5961 | && REG_EXPR (loc) | |
5962 | && TREE_CODE (REG_EXPR (loc)) == PARM_DECL | |
5963 | && DECL_MODE (REG_EXPR (loc)) != BLKmode | |
5964 | && MEM_P (DECL_INCOMING_RTL (REG_EXPR (loc))) | |
5965 | && XEXP (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) | |
5966 | != arg_pointer_rtx) | |
5967 | mo.type = MO_SET; | |
5968 | else | |
5969 | mo.type = MO_COPY; | |
5970 | } | |
94a7682d | 5971 | else |
0de3e43f JJ |
5972 | mo.type = MO_SET; |
5973 | mo.u.loc = xexpr; | |
94a7682d RS |
5974 | } |
5975 | } | |
0de3e43f | 5976 | mo.insn = cui->insn; |
014a1138 | 5977 | } |
3c0cb5de | 5978 | else if (MEM_P (loc) |
951d4497 | 5979 | && ((track_p = use_type (loc, NULL, &mode2) == MO_USE) |
b5b8b0ac | 5980 | || cui->sets)) |
014a1138 | 5981 | { |
b5b8b0ac | 5982 | if (MEM_P (loc) && type == MO_VAL_SET |
457eeaae | 5983 | && !REG_P (XEXP (loc, 0)) |
09dbcd96 | 5984 | && !MEM_P (XEXP (loc, 0))) |
b5b8b0ac AO |
5985 | { |
5986 | rtx mloc = loc; | |
ef4bddc2 | 5987 | machine_mode address_mode = get_address_mode (mloc); |
457eeaae | 5988 | cselib_val *val = cselib_lookup (XEXP (mloc, 0), |
4deef538 AO |
5989 | address_mode, 0, |
5990 | GET_MODE (mloc)); | |
b5b8b0ac AO |
5991 | |
5992 | if (val && !cselib_preserved_value_p (val)) | |
6f2ffb4b | 5993 | preserve_value (val); |
b5b8b0ac | 5994 | } |
014a1138 | 5995 | |
b5b8b0ac | 5996 | if (GET_CODE (expr) == CLOBBER || !track_p) |
94a7682d | 5997 | { |
0de3e43f JJ |
5998 | mo.type = MO_CLOBBER; |
5999 | mo.u.loc = track_p ? var_lowpart (mode2, loc) : loc; | |
94a7682d RS |
6000 | } |
6001 | else | |
6002 | { | |
2b1c5433 JJ |
6003 | if (GET_CODE (expr) == SET |
6004 | && SET_DEST (expr) == loc | |
6005 | && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS) | |
457eeaae | 6006 | src = var_lowpart (mode2, SET_SRC (expr)); |
b5b8b0ac | 6007 | loc = var_lowpart (mode2, loc); |
94a7682d RS |
6008 | |
6009 | if (src == NULL) | |
6010 | { | |
0de3e43f JJ |
6011 | mo.type = MO_SET; |
6012 | mo.u.loc = loc; | |
94a7682d RS |
6013 | } |
6014 | else | |
6015 | { | |
f7df4a84 | 6016 | rtx xexpr = gen_rtx_SET (loc, src); |
00ee9f44 | 6017 | if (same_variable_part_p (SET_SRC (xexpr), |
ca787200 | 6018 | MEM_EXPR (loc), |
8c6c36a3 | 6019 | INT_MEM_OFFSET (loc))) |
0de3e43f | 6020 | mo.type = MO_COPY; |
94a7682d | 6021 | else |
0de3e43f JJ |
6022 | mo.type = MO_SET; |
6023 | mo.u.loc = xexpr; | |
94a7682d RS |
6024 | } |
6025 | } | |
0de3e43f | 6026 | mo.insn = cui->insn; |
b5b8b0ac AO |
6027 | } |
6028 | else | |
6029 | return; | |
6030 | ||
6031 | if (type != MO_VAL_SET) | |
6032 | goto log_and_return; | |
6033 | ||
b5cd2a02 EB |
6034 | v = find_use_val (oloc, mode, cui); |
6035 | ||
6036 | if (!v) | |
6037 | goto log_and_return; | |
6038 | ||
6039 | resolve = preserve = !cselib_preserved_value_p (v); | |
6040 | ||
35af99b4 EB |
6041 | /* We cannot track values for multiple-part variables, so we track only |
6042 | locations for tracked parameters passed either by invisible reference | |
6043 | or directly in multiple locations. */ | |
6044 | if (track_p | |
6045 | && REG_P (loc) | |
6046 | && REG_EXPR (loc) | |
6047 | && TREE_CODE (REG_EXPR (loc)) == PARM_DECL | |
6048 | && DECL_MODE (REG_EXPR (loc)) != BLKmode | |
8263440b | 6049 | && TREE_CODE (TREE_TYPE (REG_EXPR (loc))) != UNION_TYPE |
35af99b4 EB |
6050 | && ((MEM_P (DECL_INCOMING_RTL (REG_EXPR (loc))) |
6051 | && XEXP (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) != arg_pointer_rtx) | |
6052 | || (GET_CODE (DECL_INCOMING_RTL (REG_EXPR (loc))) == PARALLEL | |
6053 | && XVECLEN (DECL_INCOMING_RTL (REG_EXPR (loc)), 0) > 1))) | |
b5cd2a02 EB |
6054 | { |
6055 | /* Although we don't use the value here, it could be used later by the | |
6056 | mere virtue of its existence as the operand of the reverse operation | |
6057 | that gave rise to it (typically extension/truncation). Make sure it | |
6058 | is preserved as required by vt_expand_var_loc_chain. */ | |
6059 | if (preserve) | |
6060 | preserve_value (v); | |
6061 | goto log_and_return; | |
6062 | } | |
b5b8b0ac | 6063 | |
0fe03ac3 JJ |
6064 | if (loc == stack_pointer_rtx |
6065 | && hard_frame_pointer_adjustment != -1 | |
6066 | && preserve) | |
6067 | cselib_set_value_sp_based (v); | |
6068 | ||
b5b8b0ac AO |
6069 | nloc = replace_expr_with_values (oloc); |
6070 | if (nloc) | |
6071 | oloc = nloc; | |
6072 | ||
cbdd7479 AO |
6073 | if (GET_CODE (PATTERN (cui->insn)) == COND_EXEC) |
6074 | { | |
4deef538 | 6075 | cselib_val *oval = cselib_lookup (oloc, GET_MODE (oloc), 0, VOIDmode); |
cbdd7479 | 6076 | |
0ca59830 JM |
6077 | if (oval == v) |
6078 | return; | |
cbdd7479 AO |
6079 | gcc_assert (REG_P (oloc) || MEM_P (oloc)); |
6080 | ||
cbd65133 | 6081 | if (oval && !cselib_preserved_value_p (oval)) |
cbdd7479 | 6082 | { |
0de3e43f | 6083 | micro_operation moa; |
cbdd7479 | 6084 | |
1feb8238 | 6085 | preserve_value (oval); |
cbdd7479 | 6086 | |
0de3e43f JJ |
6087 | moa.type = MO_VAL_USE; |
6088 | moa.u.loc = gen_rtx_CONCAT (mode, oval->val_rtx, oloc); | |
6089 | VAL_NEEDS_RESOLUTION (moa.u.loc) = 1; | |
6090 | moa.insn = cui->insn; | |
cbdd7479 AO |
6091 | |
6092 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
0de3e43f JJ |
6093 | log_op_type (moa.u.loc, cui->bb, cui->insn, |
6094 | moa.type, dump_file); | |
9771b263 | 6095 | VTI (bb)->mos.safe_push (moa); |
cbdd7479 AO |
6096 | } |
6097 | ||
6098 | resolve = false; | |
6099 | } | |
0de3e43f | 6100 | else if (resolve && GET_CODE (mo.u.loc) == SET) |
b5b8b0ac | 6101 | { |
6f2ffb4b AO |
6102 | if (REG_P (SET_SRC (expr)) || MEM_P (SET_SRC (expr))) |
6103 | nloc = replace_expr_with_values (SET_SRC (expr)); | |
6104 | else | |
6105 | nloc = NULL_RTX; | |
00ee9f44 AO |
6106 | |
6107 | /* Avoid the mode mismatch between oexpr and expr. */ | |
6108 | if (!nloc && mode != mode2) | |
6109 | { | |
457eeaae | 6110 | nloc = SET_SRC (expr); |
00ee9f44 AO |
6111 | gcc_assert (oloc == SET_DEST (expr)); |
6112 | } | |
b5b8b0ac | 6113 | |
6f2ffb4b | 6114 | if (nloc && nloc != SET_SRC (mo.u.loc)) |
f7df4a84 | 6115 | oloc = gen_rtx_SET (oloc, nloc); |
b5b8b0ac AO |
6116 | else |
6117 | { | |
0de3e43f | 6118 | if (oloc == SET_DEST (mo.u.loc)) |
b5b8b0ac | 6119 | /* No point in duplicating. */ |
0de3e43f JJ |
6120 | oloc = mo.u.loc; |
6121 | if (!REG_P (SET_SRC (mo.u.loc))) | |
b5b8b0ac AO |
6122 | resolve = false; |
6123 | } | |
6124 | } | |
6125 | else if (!resolve) | |
6126 | { | |
0de3e43f JJ |
6127 | if (GET_CODE (mo.u.loc) == SET |
6128 | && oloc == SET_DEST (mo.u.loc)) | |
b5b8b0ac | 6129 | /* No point in duplicating. */ |
0de3e43f | 6130 | oloc = mo.u.loc; |
b5b8b0ac AO |
6131 | } |
6132 | else | |
6133 | resolve = false; | |
6134 | ||
6135 | loc = gen_rtx_CONCAT (mode, v->val_rtx, oloc); | |
6136 | ||
0de3e43f JJ |
6137 | if (mo.u.loc != oloc) |
6138 | loc = gen_rtx_CONCAT (GET_MODE (mo.u.loc), loc, mo.u.loc); | |
b5b8b0ac AO |
6139 | |
6140 | /* The loc of a MO_VAL_SET may have various forms: | |
6141 | ||
6142 | (concat val dst): dst now holds val | |
6143 | ||
6144 | (concat val (set dst src)): dst now holds val, copied from src | |
6145 | ||
6146 | (concat (concat val dstv) dst): dst now holds val; dstv is dst | |
6147 | after replacing mems and non-top-level regs with values. | |
6148 | ||
6149 | (concat (concat val dstv) (set dst src)): dst now holds val, | |
6150 | copied from src. dstv is a value-based representation of dst, if | |
00ee9f44 AO |
6151 | it differs from dst. If resolution is needed, src is a REG, and |
6152 | its mode is the same as that of val. | |
b5b8b0ac AO |
6153 | |
6154 | (concat (concat val (set dstv srcv)) (set dst src)): src | |
6155 | copied to dst, holding val. dstv and srcv are value-based | |
6156 | representations of dst and src, respectively. | |
6157 | ||
6158 | */ | |
6159 | ||
0c5863c2 | 6160 | if (GET_CODE (PATTERN (cui->insn)) != COND_EXEC) |
6f2ffb4b | 6161 | reverse_op (v->val_rtx, expr, cui->insn); |
0c5863c2 | 6162 | |
0de3e43f | 6163 | mo.u.loc = loc; |
b5b8b0ac AO |
6164 | |
6165 | if (track_p) | |
6166 | VAL_HOLDS_TRACK_EXPR (loc) = 1; | |
6167 | if (preserve) | |
6168 | { | |
6169 | VAL_NEEDS_RESOLUTION (loc) = resolve; | |
1feb8238 | 6170 | preserve_value (v); |
b5b8b0ac | 6171 | } |
0de3e43f | 6172 | if (mo.type == MO_CLOBBER) |
b5b8b0ac | 6173 | VAL_EXPR_IS_CLOBBERED (loc) = 1; |
0de3e43f | 6174 | if (mo.type == MO_COPY) |
b5b8b0ac AO |
6175 | VAL_EXPR_IS_COPIED (loc) = 1; |
6176 | ||
0de3e43f | 6177 | mo.type = MO_VAL_SET; |
b5b8b0ac AO |
6178 | |
6179 | log_and_return: | |
6180 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
0de3e43f | 6181 | log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file); |
9771b263 | 6182 | VTI (bb)->mos.safe_push (mo); |
b5b8b0ac AO |
6183 | } |
6184 | ||
2b1c5433 JJ |
6185 | /* Arguments to the call. */ |
6186 | static rtx call_arguments; | |
6187 | ||
6188 | /* Compute call_arguments. */ | |
6189 | ||
6190 | static void | |
598d62da | 6191 | prepare_call_arguments (basic_block bb, rtx_insn *insn) |
2b1c5433 | 6192 | { |
da4fdf2d | 6193 | rtx link, x, call; |
2b1c5433 | 6194 | rtx prev, cur, next; |
325f5379 JJ |
6195 | rtx this_arg = NULL_RTX; |
6196 | tree type = NULL_TREE, t, fndecl = NULL_TREE; | |
6197 | tree obj_type_ref = NULL_TREE; | |
d5cc9181 JR |
6198 | CUMULATIVE_ARGS args_so_far_v; |
6199 | cumulative_args_t args_so_far; | |
2b1c5433 | 6200 | |
d5cc9181 JR |
6201 | memset (&args_so_far_v, 0, sizeof (args_so_far_v)); |
6202 | args_so_far = pack_cumulative_args (&args_so_far_v); | |
da4fdf2d SB |
6203 | call = get_call_rtx_from (insn); |
6204 | if (call) | |
2b1c5433 | 6205 | { |
325f5379 JJ |
6206 | if (GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF) |
6207 | { | |
6208 | rtx symbol = XEXP (XEXP (call, 0), 0); | |
6209 | if (SYMBOL_REF_DECL (symbol)) | |
6210 | fndecl = SYMBOL_REF_DECL (symbol); | |
6211 | } | |
6212 | if (fndecl == NULL_TREE) | |
6213 | fndecl = MEM_EXPR (XEXP (call, 0)); | |
6214 | if (fndecl | |
6215 | && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE | |
6216 | && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE) | |
6217 | fndecl = NULL_TREE; | |
6218 | if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl))) | |
6219 | type = TREE_TYPE (fndecl); | |
6220 | if (fndecl && TREE_CODE (fndecl) != FUNCTION_DECL) | |
6221 | { | |
6222 | if (TREE_CODE (fndecl) == INDIRECT_REF | |
6223 | && TREE_CODE (TREE_OPERAND (fndecl, 0)) == OBJ_TYPE_REF) | |
6224 | obj_type_ref = TREE_OPERAND (fndecl, 0); | |
6225 | fndecl = NULL_TREE; | |
6226 | } | |
6227 | if (type) | |
2b1c5433 | 6228 | { |
2b1c5433 JJ |
6229 | for (t = TYPE_ARG_TYPES (type); t && t != void_list_node; |
6230 | t = TREE_CHAIN (t)) | |
6231 | if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE | |
6232 | && INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t)))) | |
6233 | break; | |
325f5379 | 6234 | if ((t == NULL || t == void_list_node) && obj_type_ref == NULL_TREE) |
2b1c5433 JJ |
6235 | type = NULL; |
6236 | else | |
325f5379 | 6237 | { |
e42348b8 | 6238 | int nargs ATTRIBUTE_UNUSED = list_length (TYPE_ARG_TYPES (type)); |
325f5379 JJ |
6239 | link = CALL_INSN_FUNCTION_USAGE (insn); |
6240 | #ifndef PCC_STATIC_STRUCT_RETURN | |
6241 | if (aggregate_value_p (TREE_TYPE (type), type) | |
6242 | && targetm.calls.struct_value_rtx (type, 0) == 0) | |
6243 | { | |
6244 | tree struct_addr = build_pointer_type (TREE_TYPE (type)); | |
ef4bddc2 | 6245 | machine_mode mode = TYPE_MODE (struct_addr); |
325f5379 | 6246 | rtx reg; |
d5cc9181 | 6247 | INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl, |
325f5379 | 6248 | nargs + 1); |
d5cc9181 | 6249 | reg = targetm.calls.function_arg (args_so_far, mode, |
325f5379 | 6250 | struct_addr, true); |
d5cc9181 | 6251 | targetm.calls.function_arg_advance (args_so_far, mode, |
325f5379 JJ |
6252 | struct_addr, true); |
6253 | if (reg == NULL_RTX) | |
6254 | { | |
6255 | for (; link; link = XEXP (link, 1)) | |
6256 | if (GET_CODE (XEXP (link, 0)) == USE | |
6257 | && MEM_P (XEXP (XEXP (link, 0), 0))) | |
6258 | { | |
6259 | link = XEXP (link, 1); | |
6260 | break; | |
6261 | } | |
6262 | } | |
6263 | } | |
325f5379 | 6264 | else |
3becc47b | 6265 | #endif |
d5cc9181 | 6266 | INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl, |
325f5379 JJ |
6267 | nargs); |
6268 | if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node) | |
6269 | { | |
ef4bddc2 | 6270 | machine_mode mode; |
325f5379 JJ |
6271 | t = TYPE_ARG_TYPES (type); |
6272 | mode = TYPE_MODE (TREE_VALUE (t)); | |
d5cc9181 | 6273 | this_arg = targetm.calls.function_arg (args_so_far, mode, |
325f5379 JJ |
6274 | TREE_VALUE (t), true); |
6275 | if (this_arg && !REG_P (this_arg)) | |
6276 | this_arg = NULL_RTX; | |
6277 | else if (this_arg == NULL_RTX) | |
6278 | { | |
6279 | for (; link; link = XEXP (link, 1)) | |
6280 | if (GET_CODE (XEXP (link, 0)) == USE | |
6281 | && MEM_P (XEXP (XEXP (link, 0), 0))) | |
6282 | { | |
6283 | this_arg = XEXP (XEXP (link, 0), 0); | |
6284 | break; | |
6285 | } | |
6286 | } | |
6287 | } | |
6288 | } | |
2b1c5433 JJ |
6289 | } |
6290 | } | |
6291 | t = type ? TYPE_ARG_TYPES (type) : NULL_TREE; | |
6292 | ||
6293 | for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1)) | |
6294 | if (GET_CODE (XEXP (link, 0)) == USE) | |
6295 | { | |
6296 | rtx item = NULL_RTX; | |
6297 | x = XEXP (XEXP (link, 0), 0); | |
7d810276 JJ |
6298 | if (GET_MODE (link) == VOIDmode |
6299 | || GET_MODE (link) == BLKmode | |
6300 | || (GET_MODE (link) != GET_MODE (x) | |
50b6ee8b DD |
6301 | && ((GET_MODE_CLASS (GET_MODE (link)) != MODE_INT |
6302 | && GET_MODE_CLASS (GET_MODE (link)) != MODE_PARTIAL_INT) | |
6303 | || (GET_MODE_CLASS (GET_MODE (x)) != MODE_INT | |
6304 | && GET_MODE_CLASS (GET_MODE (x)) != MODE_PARTIAL_INT)))) | |
7d810276 JJ |
6305 | /* Can't do anything for these, if the original type mode |
6306 | isn't known or can't be converted. */; | |
6307 | else if (REG_P (x)) | |
2b1c5433 JJ |
6308 | { |
6309 | cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode); | |
6310 | if (val && cselib_preserved_value_p (val)) | |
7d810276 | 6311 | item = val->val_rtx; |
50b6ee8b DD |
6312 | else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT |
6313 | || GET_MODE_CLASS (GET_MODE (x)) == MODE_PARTIAL_INT) | |
2b1c5433 | 6314 | { |
ef4bddc2 | 6315 | machine_mode mode = GET_MODE (x); |
2b1c5433 JJ |
6316 | |
6317 | while ((mode = GET_MODE_WIDER_MODE (mode)) != VOIDmode | |
6318 | && GET_MODE_BITSIZE (mode) <= BITS_PER_WORD) | |
6319 | { | |
6320 | rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0); | |
6321 | ||
6322 | if (reg == NULL_RTX || !REG_P (reg)) | |
6323 | continue; | |
6324 | val = cselib_lookup (reg, mode, 0, VOIDmode); | |
6325 | if (val && cselib_preserved_value_p (val)) | |
6326 | { | |
7d810276 | 6327 | item = val->val_rtx; |
2b1c5433 JJ |
6328 | break; |
6329 | } | |
6330 | } | |
6331 | } | |
6332 | } | |
6333 | else if (MEM_P (x)) | |
6334 | { | |
6335 | rtx mem = x; | |
6336 | cselib_val *val; | |
6337 | ||
6338 | if (!frame_pointer_needed) | |
6339 | { | |
6340 | struct adjust_mem_data amd; | |
6341 | amd.mem_mode = VOIDmode; | |
6342 | amd.stack_adjust = -VTI (bb)->out.stack_adjust; | |
2f33ff0a | 6343 | amd.side_effects = NULL; |
2b1c5433 JJ |
6344 | amd.store = true; |
6345 | mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems, | |
6346 | &amd); | |
6347 | gcc_assert (amd.side_effects == NULL_RTX); | |
6348 | } | |
6349 | val = cselib_lookup (mem, GET_MODE (mem), 0, VOIDmode); | |
6350 | if (val && cselib_preserved_value_p (val)) | |
7d810276 | 6351 | item = val->val_rtx; |
50b6ee8b DD |
6352 | else if (GET_MODE_CLASS (GET_MODE (mem)) != MODE_INT |
6353 | && GET_MODE_CLASS (GET_MODE (mem)) != MODE_PARTIAL_INT) | |
4fe249e7 JJ |
6354 | { |
6355 | /* For non-integer stack argument see also if they weren't | |
6356 | initialized by integers. */ | |
ef4bddc2 | 6357 | machine_mode imode = int_mode_for_mode (GET_MODE (mem)); |
4fe249e7 JJ |
6358 | if (imode != GET_MODE (mem) && imode != BLKmode) |
6359 | { | |
6360 | val = cselib_lookup (adjust_address_nv (mem, imode, 0), | |
6361 | imode, 0, VOIDmode); | |
6362 | if (val && cselib_preserved_value_p (val)) | |
7d810276 JJ |
6363 | item = lowpart_subreg (GET_MODE (x), val->val_rtx, |
6364 | imode); | |
4fe249e7 JJ |
6365 | } |
6366 | } | |
2b1c5433 JJ |
6367 | } |
6368 | if (item) | |
7d810276 JJ |
6369 | { |
6370 | rtx x2 = x; | |
6371 | if (GET_MODE (item) != GET_MODE (link)) | |
6372 | item = lowpart_subreg (GET_MODE (link), item, GET_MODE (item)); | |
6373 | if (GET_MODE (x2) != GET_MODE (link)) | |
6374 | x2 = lowpart_subreg (GET_MODE (link), x2, GET_MODE (x2)); | |
6375 | item = gen_rtx_CONCAT (GET_MODE (link), x2, item); | |
6376 | call_arguments | |
6377 | = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments); | |
6378 | } | |
2b1c5433 JJ |
6379 | if (t && t != void_list_node) |
6380 | { | |
db3ed0b3 | 6381 | tree argtype = TREE_VALUE (t); |
ef4bddc2 | 6382 | machine_mode mode = TYPE_MODE (argtype); |
db3ed0b3 | 6383 | rtx reg; |
d5cc9181 | 6384 | if (pass_by_reference (&args_so_far_v, mode, argtype, true)) |
db3ed0b3 JJ |
6385 | { |
6386 | argtype = build_pointer_type (argtype); | |
6387 | mode = TYPE_MODE (argtype); | |
6388 | } | |
d5cc9181 | 6389 | reg = targetm.calls.function_arg (args_so_far, mode, |
db3ed0b3 JJ |
6390 | argtype, true); |
6391 | if (TREE_CODE (argtype) == REFERENCE_TYPE | |
6392 | && INTEGRAL_TYPE_P (TREE_TYPE (argtype)) | |
2b1c5433 JJ |
6393 | && reg |
6394 | && REG_P (reg) | |
6395 | && GET_MODE (reg) == mode | |
50b6ee8b DD |
6396 | && (GET_MODE_CLASS (mode) == MODE_INT |
6397 | || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT) | |
2b1c5433 JJ |
6398 | && REG_P (x) |
6399 | && REGNO (x) == REGNO (reg) | |
6400 | && GET_MODE (x) == mode | |
6401 | && item) | |
6402 | { | |
ef4bddc2 | 6403 | machine_mode indmode |
db3ed0b3 | 6404 | = TYPE_MODE (TREE_TYPE (argtype)); |
2b1c5433 JJ |
6405 | rtx mem = gen_rtx_MEM (indmode, x); |
6406 | cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode); | |
6407 | if (val && cselib_preserved_value_p (val)) | |
6408 | { | |
6409 | item = gen_rtx_CONCAT (indmode, mem, val->val_rtx); | |
6410 | call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, | |
6411 | call_arguments); | |
6412 | } | |
6413 | else | |
6414 | { | |
6415 | struct elt_loc_list *l; | |
6416 | tree initial; | |
6417 | ||
6418 | /* Try harder, when passing address of a constant | |
6419 | pool integer it can be easily read back. */ | |
fe58e02b L |
6420 | item = XEXP (item, 1); |
6421 | if (GET_CODE (item) == SUBREG) | |
6422 | item = SUBREG_REG (item); | |
6423 | gcc_assert (GET_CODE (item) == VALUE); | |
6424 | val = CSELIB_VAL_PTR (item); | |
2b1c5433 JJ |
6425 | for (l = val->locs; l; l = l->next) |
6426 | if (GET_CODE (l->loc) == SYMBOL_REF | |
6427 | && TREE_CONSTANT_POOL_ADDRESS_P (l->loc) | |
6428 | && SYMBOL_REF_DECL (l->loc) | |
6429 | && DECL_INITIAL (SYMBOL_REF_DECL (l->loc))) | |
6430 | { | |
6431 | initial = DECL_INITIAL (SYMBOL_REF_DECL (l->loc)); | |
9541ffee | 6432 | if (tree_fits_shwi_p (initial)) |
2b1c5433 | 6433 | { |
9439e9a1 | 6434 | item = GEN_INT (tree_to_shwi (initial)); |
2b1c5433 JJ |
6435 | item = gen_rtx_CONCAT (indmode, mem, item); |
6436 | call_arguments | |
6437 | = gen_rtx_EXPR_LIST (VOIDmode, item, | |
6438 | call_arguments); | |
6439 | } | |
6440 | break; | |
6441 | } | |
6442 | } | |
6443 | } | |
d5cc9181 | 6444 | targetm.calls.function_arg_advance (args_so_far, mode, |
db3ed0b3 | 6445 | argtype, true); |
2b1c5433 JJ |
6446 | t = TREE_CHAIN (t); |
6447 | } | |
6448 | } | |
6449 | ||
ddb555ed JJ |
6450 | /* Add debug arguments. */ |
6451 | if (fndecl | |
6452 | && TREE_CODE (fndecl) == FUNCTION_DECL | |
6453 | && DECL_HAS_DEBUG_ARGS_P (fndecl)) | |
6454 | { | |
9771b263 | 6455 | vec<tree, va_gc> **debug_args = decl_debug_args_lookup (fndecl); |
ddb555ed JJ |
6456 | if (debug_args) |
6457 | { | |
6458 | unsigned int ix; | |
6459 | tree param; | |
9771b263 | 6460 | for (ix = 0; vec_safe_iterate (*debug_args, ix, ¶m); ix += 2) |
ddb555ed JJ |
6461 | { |
6462 | rtx item; | |
9771b263 | 6463 | tree dtemp = (**debug_args)[ix + 1]; |
ef4bddc2 | 6464 | machine_mode mode = DECL_MODE (dtemp); |
ddb555ed | 6465 | item = gen_rtx_DEBUG_PARAMETER_REF (mode, param); |
09dbcd96 | 6466 | item = gen_rtx_CONCAT (mode, item, DECL_RTL_KNOWN_SET (dtemp)); |
ddb555ed JJ |
6467 | call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, |
6468 | call_arguments); | |
6469 | } | |
6470 | } | |
6471 | } | |
6472 | ||
2b1c5433 JJ |
6473 | /* Reverse call_arguments chain. */ |
6474 | prev = NULL_RTX; | |
6475 | for (cur = call_arguments; cur; cur = next) | |
6476 | { | |
6477 | next = XEXP (cur, 1); | |
6478 | XEXP (cur, 1) = prev; | |
6479 | prev = cur; | |
6480 | } | |
6481 | call_arguments = prev; | |
6482 | ||
da4fdf2d SB |
6483 | x = get_call_rtx_from (insn); |
6484 | if (x) | |
2b1c5433 JJ |
6485 | { |
6486 | x = XEXP (XEXP (x, 0), 0); | |
8b29c87a JJ |
6487 | if (GET_CODE (x) == SYMBOL_REF) |
6488 | /* Don't record anything. */; | |
6489 | else if (CONSTANT_P (x)) | |
6490 | { | |
6491 | x = gen_rtx_CONCAT (GET_MODE (x) == VOIDmode ? Pmode : GET_MODE (x), | |
6492 | pc_rtx, x); | |
6493 | call_arguments | |
6494 | = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments); | |
6495 | } | |
6496 | else | |
2b1c5433 JJ |
6497 | { |
6498 | cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode); | |
6499 | if (val && cselib_preserved_value_p (val)) | |
6500 | { | |
6501 | x = gen_rtx_CONCAT (GET_MODE (x), pc_rtx, val->val_rtx); | |
6502 | call_arguments | |
6503 | = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments); | |
6504 | } | |
6505 | } | |
6506 | } | |
325f5379 JJ |
6507 | if (this_arg) |
6508 | { | |
ef4bddc2 | 6509 | machine_mode mode |
325f5379 JJ |
6510 | = TYPE_MODE (TREE_TYPE (OBJ_TYPE_REF_EXPR (obj_type_ref))); |
6511 | rtx clobbered = gen_rtx_MEM (mode, this_arg); | |
6512 | HOST_WIDE_INT token | |
9439e9a1 | 6513 | = tree_to_shwi (OBJ_TYPE_REF_TOKEN (obj_type_ref)); |
325f5379 | 6514 | if (token) |
0a81f074 RS |
6515 | clobbered = plus_constant (mode, clobbered, |
6516 | token * GET_MODE_SIZE (mode)); | |
325f5379 JJ |
6517 | clobbered = gen_rtx_MEM (mode, clobbered); |
6518 | x = gen_rtx_CONCAT (mode, gen_rtx_CLOBBER (VOIDmode, pc_rtx), clobbered); | |
6519 | call_arguments | |
6520 | = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments); | |
6521 | } | |
2b1c5433 JJ |
6522 | } |
6523 | ||
b5b8b0ac AO |
6524 | /* Callback for cselib_record_sets_hook, that records as micro |
6525 | operations uses and stores in an insn after cselib_record_sets has | |
6526 | analyzed the sets in an insn, but before it modifies the stored | |
6527 | values in the internal tables, unless cselib_record_sets doesn't | |
6528 | call it directly (perhaps because we're not doing cselib in the | |
6529 | first place, in which case sets and n_sets will be 0). */ | |
6530 | ||
6531 | static void | |
46665961 | 6532 | add_with_sets (rtx_insn *insn, struct cselib_set *sets, int n_sets) |
b5b8b0ac AO |
6533 | { |
6534 | basic_block bb = BLOCK_FOR_INSN (insn); | |
6535 | int n1, n2; | |
6536 | struct count_use_info cui; | |
0de3e43f | 6537 | micro_operation *mos; |
b5b8b0ac AO |
6538 | |
6539 | cselib_hook_called = true; | |
6540 | ||
6541 | cui.insn = insn; | |
6542 | cui.bb = bb; | |
6543 | cui.sets = sets; | |
6544 | cui.n_sets = n_sets; | |
6545 | ||
9771b263 | 6546 | n1 = VTI (bb)->mos.length (); |
b5b8b0ac AO |
6547 | cui.store_p = false; |
6548 | note_uses (&PATTERN (insn), add_uses_1, &cui); | |
9771b263 DN |
6549 | n2 = VTI (bb)->mos.length () - 1; |
6550 | mos = VTI (bb)->mos.address (); | |
b5b8b0ac | 6551 | |
7168dc47 AO |
6552 | /* Order the MO_USEs to be before MO_USE_NO_VARs and MO_VAL_USE, and |
6553 | MO_VAL_LOC last. */ | |
b5b8b0ac AO |
6554 | while (n1 < n2) |
6555 | { | |
0de3e43f | 6556 | while (n1 < n2 && mos[n1].type == MO_USE) |
b5b8b0ac | 6557 | n1++; |
0de3e43f | 6558 | while (n1 < n2 && mos[n2].type != MO_USE) |
b5b8b0ac AO |
6559 | n2--; |
6560 | if (n1 < n2) | |
fab27f52 | 6561 | std::swap (mos[n1], mos[n2]); |
7168dc47 AO |
6562 | } |
6563 | ||
9771b263 | 6564 | n2 = VTI (bb)->mos.length () - 1; |
7168dc47 AO |
6565 | while (n1 < n2) |
6566 | { | |
0de3e43f | 6567 | while (n1 < n2 && mos[n1].type != MO_VAL_LOC) |
7168dc47 | 6568 | n1++; |
0de3e43f | 6569 | while (n1 < n2 && mos[n2].type == MO_VAL_LOC) |
7168dc47 AO |
6570 | n2--; |
6571 | if (n1 < n2) | |
fab27f52 | 6572 | std::swap (mos[n1], mos[n2]); |
b5b8b0ac AO |
6573 | } |
6574 | ||
6575 | if (CALL_P (insn)) | |
6576 | { | |
0de3e43f | 6577 | micro_operation mo; |
b5b8b0ac | 6578 | |
0de3e43f JJ |
6579 | mo.type = MO_CALL; |
6580 | mo.insn = insn; | |
2b1c5433 JJ |
6581 | mo.u.loc = call_arguments; |
6582 | call_arguments = NULL_RTX; | |
b5b8b0ac AO |
6583 | |
6584 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
0de3e43f | 6585 | log_op_type (PATTERN (insn), bb, insn, mo.type, dump_file); |
9771b263 | 6586 | VTI (bb)->mos.safe_push (mo); |
b5b8b0ac AO |
6587 | } |
6588 | ||
9771b263 | 6589 | n1 = VTI (bb)->mos.length (); |
b5b8b0ac AO |
6590 | /* This will record NEXT_INSN (insn), such that we can |
6591 | insert notes before it without worrying about any | |
6592 | notes that MO_USEs might emit after the insn. */ | |
6593 | cui.store_p = true; | |
6594 | note_stores (PATTERN (insn), add_stores, &cui); | |
9771b263 DN |
6595 | n2 = VTI (bb)->mos.length () - 1; |
6596 | mos = VTI (bb)->mos.address (); | |
b5b8b0ac | 6597 | |
0de3e43f JJ |
6598 | /* Order the MO_VAL_USEs first (note_stores does nothing |
6599 | on DEBUG_INSNs, so there are no MO_VAL_LOCs from this | |
6600 | insn), then MO_CLOBBERs, then MO_SET/MO_COPY/MO_VAL_SET. */ | |
b5b8b0ac AO |
6601 | while (n1 < n2) |
6602 | { | |
0de3e43f | 6603 | while (n1 < n2 && mos[n1].type == MO_VAL_USE) |
b5b8b0ac | 6604 | n1++; |
0de3e43f | 6605 | while (n1 < n2 && mos[n2].type != MO_VAL_USE) |
b5b8b0ac AO |
6606 | n2--; |
6607 | if (n1 < n2) | |
fab27f52 | 6608 | std::swap (mos[n1], mos[n2]); |
0de3e43f JJ |
6609 | } |
6610 | ||
9771b263 | 6611 | n2 = VTI (bb)->mos.length () - 1; |
0de3e43f JJ |
6612 | while (n1 < n2) |
6613 | { | |
6614 | while (n1 < n2 && mos[n1].type == MO_CLOBBER) | |
6615 | n1++; | |
6616 | while (n1 < n2 && mos[n2].type != MO_CLOBBER) | |
6617 | n2--; | |
6618 | if (n1 < n2) | |
fab27f52 | 6619 | std::swap (mos[n1], mos[n2]); |
014a1138 JZ |
6620 | } |
6621 | } | |
6622 | ||
62760ffd | 6623 | static enum var_init_status |
94a7682d | 6624 | find_src_status (dataflow_set *in, rtx src) |
62760ffd | 6625 | { |
62760ffd CT |
6626 | tree decl = NULL_TREE; |
6627 | enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED; | |
6628 | ||
6629 | if (! flag_var_tracking_uninit) | |
6630 | status = VAR_INIT_STATUS_INITIALIZED; | |
6631 | ||
0ef0421e | 6632 | if (src && REG_P (src)) |
62760ffd | 6633 | decl = var_debug_decl (REG_EXPR (src)); |
0ef0421e | 6634 | else if (src && MEM_P (src)) |
62760ffd CT |
6635 | decl = var_debug_decl (MEM_EXPR (src)); |
6636 | ||
6637 | if (src && decl) | |
b5b8b0ac | 6638 | status = get_init_value (in, src, dv_from_decl (decl)); |
62760ffd CT |
6639 | |
6640 | return status; | |
6641 | } | |
6642 | ||
94a7682d RS |
6643 | /* SRC is the source of an assignment. Use SET to try to find what |
6644 | was ultimately assigned to SRC. Return that value if known, | |
6645 | otherwise return SRC itself. */ | |
62760ffd CT |
6646 | |
6647 | static rtx | |
94a7682d | 6648 | find_src_set_src (dataflow_set *set, rtx src) |
62760ffd CT |
6649 | { |
6650 | tree decl = NULL_TREE; /* The variable being copied around. */ | |
62760ffd | 6651 | rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */ |
62760ffd CT |
6652 | variable var; |
6653 | location_chain nextp; | |
6654 | int i; | |
6655 | bool found; | |
6656 | ||
0ef0421e | 6657 | if (src && REG_P (src)) |
62760ffd | 6658 | decl = var_debug_decl (REG_EXPR (src)); |
0ef0421e | 6659 | else if (src && MEM_P (src)) |
62760ffd CT |
6660 | decl = var_debug_decl (MEM_EXPR (src)); |
6661 | ||
6662 | if (src && decl) | |
6663 | { | |
b5b8b0ac AO |
6664 | decl_or_value dv = dv_from_decl (decl); |
6665 | ||
6666 | var = shared_hash_find (set->vars, dv); | |
d24686d7 | 6667 | if (var) |
62760ffd | 6668 | { |
62760ffd CT |
6669 | found = false; |
6670 | for (i = 0; i < var->n_var_parts && !found; i++) | |
b8698a0f | 6671 | for (nextp = var->var_part[i].loc_chain; nextp && !found; |
62760ffd CT |
6672 | nextp = nextp->next) |
6673 | if (rtx_equal_p (nextp->loc, src)) | |
6674 | { | |
6675 | set_src = nextp->set_src; | |
6676 | found = true; | |
6677 | } | |
b8698a0f | 6678 | |
62760ffd CT |
6679 | } |
6680 | } | |
6681 | ||
6682 | return set_src; | |
6683 | } | |
6684 | ||
b5b8b0ac AO |
6685 | /* Compute the changes of variable locations in the basic block BB. */ |
6686 | ||
6687 | static bool | |
6688 | compute_bb_dataflow (basic_block bb) | |
6689 | { | |
0de3e43f JJ |
6690 | unsigned int i; |
6691 | micro_operation *mo; | |
b5b8b0ac AO |
6692 | bool changed; |
6693 | dataflow_set old_out; | |
6694 | dataflow_set *in = &VTI (bb)->in; | |
6695 | dataflow_set *out = &VTI (bb)->out; | |
6696 | ||
6697 | dataflow_set_init (&old_out); | |
6698 | dataflow_set_copy (&old_out, out); | |
6699 | dataflow_set_copy (out, in); | |
6700 | ||
af6236c1 | 6701 | if (MAY_HAVE_DEBUG_INSNS) |
b787e7a2 | 6702 | local_get_addr_cache = new hash_map<rtx, rtx>; |
af6236c1 | 6703 | |
9771b263 | 6704 | FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo) |
b5b8b0ac | 6705 | { |
598d62da | 6706 | rtx_insn *insn = mo->insn; |
b5b8b0ac | 6707 | |
0de3e43f | 6708 | switch (mo->type) |
b5b8b0ac AO |
6709 | { |
6710 | case MO_CALL: | |
0f9f9784 | 6711 | dataflow_set_clear_at_call (out); |
b5b8b0ac AO |
6712 | break; |
6713 | ||
6714 | case MO_USE: | |
6715 | { | |
0de3e43f | 6716 | rtx loc = mo->u.loc; |
b5b8b0ac AO |
6717 | |
6718 | if (REG_P (loc)) | |
6719 | var_reg_set (out, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL); | |
6720 | else if (MEM_P (loc)) | |
6721 | var_mem_set (out, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL); | |
6722 | } | |
6723 | break; | |
6724 | ||
6725 | case MO_VAL_LOC: | |
6726 | { | |
0de3e43f | 6727 | rtx loc = mo->u.loc; |
b5b8b0ac AO |
6728 | rtx val, vloc; |
6729 | tree var; | |
6730 | ||
6731 | if (GET_CODE (loc) == CONCAT) | |
6732 | { | |
6733 | val = XEXP (loc, 0); | |
6734 | vloc = XEXP (loc, 1); | |
6735 | } | |
6736 | else | |
6737 | { | |
6738 | val = NULL_RTX; | |
6739 | vloc = loc; | |
6740 | } | |
6741 | ||
6742 | var = PAT_VAR_LOCATION_DECL (vloc); | |
6743 | ||
6744 | clobber_variable_part (out, NULL_RTX, | |
6745 | dv_from_decl (var), 0, NULL_RTX); | |
6746 | if (val) | |
6747 | { | |
6748 | if (VAL_NEEDS_RESOLUTION (loc)) | |
6749 | val_resolve (out, val, PAT_VAR_LOCATION_LOC (vloc), insn); | |
6750 | set_variable_part (out, val, dv_from_decl (var), 0, | |
6751 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, | |
6752 | INSERT); | |
6753 | } | |
5644a3d0 JJ |
6754 | else if (!VAR_LOC_UNKNOWN_P (PAT_VAR_LOCATION_LOC (vloc))) |
6755 | set_variable_part (out, PAT_VAR_LOCATION_LOC (vloc), | |
6756 | dv_from_decl (var), 0, | |
6757 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, | |
6758 | INSERT); | |
b5b8b0ac AO |
6759 | } |
6760 | break; | |
6761 | ||
6762 | case MO_VAL_USE: | |
6763 | { | |
0de3e43f | 6764 | rtx loc = mo->u.loc; |
b5b8b0ac AO |
6765 | rtx val, vloc, uloc; |
6766 | ||
6767 | vloc = uloc = XEXP (loc, 1); | |
6768 | val = XEXP (loc, 0); | |
6769 | ||
6770 | if (GET_CODE (val) == CONCAT) | |
6771 | { | |
6772 | uloc = XEXP (val, 1); | |
6773 | val = XEXP (val, 0); | |
6774 | } | |
6775 | ||
6776 | if (VAL_NEEDS_RESOLUTION (loc)) | |
6777 | val_resolve (out, val, vloc, insn); | |
fb4cbb9f AO |
6778 | else |
6779 | val_store (out, val, uloc, insn, false); | |
b5b8b0ac AO |
6780 | |
6781 | if (VAL_HOLDS_TRACK_EXPR (loc)) | |
6782 | { | |
6783 | if (GET_CODE (uloc) == REG) | |
6784 | var_reg_set (out, uloc, VAR_INIT_STATUS_UNINITIALIZED, | |
6785 | NULL); | |
6786 | else if (GET_CODE (uloc) == MEM) | |
6787 | var_mem_set (out, uloc, VAR_INIT_STATUS_UNINITIALIZED, | |
6788 | NULL); | |
6789 | } | |
6790 | } | |
6791 | break; | |
6792 | ||
6793 | case MO_VAL_SET: | |
6794 | { | |
0de3e43f | 6795 | rtx loc = mo->u.loc; |
6f2ffb4b | 6796 | rtx val, vloc, uloc; |
d05cae4a | 6797 | rtx dstv, srcv; |
b5b8b0ac | 6798 | |
0c5863c2 | 6799 | vloc = loc; |
0c5863c2 JJ |
6800 | uloc = XEXP (vloc, 1); |
6801 | val = XEXP (vloc, 0); | |
6802 | vloc = uloc; | |
b5b8b0ac | 6803 | |
d05cae4a AO |
6804 | if (GET_CODE (uloc) == SET) |
6805 | { | |
6806 | dstv = SET_DEST (uloc); | |
6807 | srcv = SET_SRC (uloc); | |
6808 | } | |
6809 | else | |
6810 | { | |
6811 | dstv = uloc; | |
6812 | srcv = NULL; | |
6813 | } | |
6814 | ||
b5b8b0ac AO |
6815 | if (GET_CODE (val) == CONCAT) |
6816 | { | |
d05cae4a | 6817 | dstv = vloc = XEXP (val, 1); |
b5b8b0ac AO |
6818 | val = XEXP (val, 0); |
6819 | } | |
6820 | ||
6821 | if (GET_CODE (vloc) == SET) | |
6822 | { | |
d05cae4a | 6823 | srcv = SET_SRC (vloc); |
b5b8b0ac | 6824 | |
d05cae4a | 6825 | gcc_assert (val != srcv); |
b5b8b0ac AO |
6826 | gcc_assert (vloc == uloc || VAL_NEEDS_RESOLUTION (loc)); |
6827 | ||
d05cae4a | 6828 | dstv = vloc = SET_DEST (vloc); |
b5b8b0ac AO |
6829 | |
6830 | if (VAL_NEEDS_RESOLUTION (loc)) | |
d05cae4a | 6831 | val_resolve (out, val, srcv, insn); |
b5b8b0ac AO |
6832 | } |
6833 | else if (VAL_NEEDS_RESOLUTION (loc)) | |
6834 | { | |
6835 | gcc_assert (GET_CODE (uloc) == SET | |
6836 | && GET_CODE (SET_SRC (uloc)) == REG); | |
6837 | val_resolve (out, val, SET_SRC (uloc), insn); | |
6838 | } | |
6839 | ||
6840 | if (VAL_HOLDS_TRACK_EXPR (loc)) | |
6841 | { | |
6842 | if (VAL_EXPR_IS_CLOBBERED (loc)) | |
6843 | { | |
6844 | if (REG_P (uloc)) | |
6845 | var_reg_delete (out, uloc, true); | |
6846 | else if (MEM_P (uloc)) | |
d05cae4a AO |
6847 | { |
6848 | gcc_assert (MEM_P (dstv)); | |
6849 | gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (uloc)); | |
6850 | var_mem_delete (out, dstv, true); | |
6851 | } | |
b5b8b0ac AO |
6852 | } |
6853 | else | |
6854 | { | |
6855 | bool copied_p = VAL_EXPR_IS_COPIED (loc); | |
d05cae4a | 6856 | rtx src = NULL, dst = uloc; |
b5b8b0ac AO |
6857 | enum var_init_status status = VAR_INIT_STATUS_INITIALIZED; |
6858 | ||
6859 | if (GET_CODE (uloc) == SET) | |
6860 | { | |
d05cae4a AO |
6861 | src = SET_SRC (uloc); |
6862 | dst = SET_DEST (uloc); | |
b5b8b0ac | 6863 | } |
014a1138 | 6864 | |
b5b8b0ac AO |
6865 | if (copied_p) |
6866 | { | |
6867 | if (flag_var_tracking_uninit) | |
6868 | { | |
d05cae4a | 6869 | status = find_src_status (in, src); |
014a1138 | 6870 | |
b5b8b0ac | 6871 | if (status == VAR_INIT_STATUS_UNKNOWN) |
d05cae4a | 6872 | status = find_src_status (out, src); |
b5b8b0ac | 6873 | } |
014a1138 | 6874 | |
d05cae4a | 6875 | src = find_src_set_src (in, src); |
b5b8b0ac | 6876 | } |
014a1138 | 6877 | |
d05cae4a AO |
6878 | if (REG_P (dst)) |
6879 | var_reg_delete_and_set (out, dst, !copied_p, | |
6880 | status, srcv); | |
6881 | else if (MEM_P (dst)) | |
6882 | { | |
6883 | gcc_assert (MEM_P (dstv)); | |
6884 | gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (dst)); | |
6885 | var_mem_delete_and_set (out, dstv, !copied_p, | |
6886 | status, srcv); | |
6887 | } | |
b5b8b0ac AO |
6888 | } |
6889 | } | |
6890 | else if (REG_P (uloc)) | |
6891 | var_regno_delete (out, REGNO (uloc)); | |
8cda8ad3 | 6892 | else if (MEM_P (uloc)) |
af6236c1 AO |
6893 | { |
6894 | gcc_checking_assert (GET_CODE (vloc) == MEM); | |
6895 | gcc_checking_assert (dstv == vloc); | |
6896 | if (dstv != vloc) | |
6897 | clobber_overlapping_mems (out, vloc); | |
6898 | } | |
dedc1e6d | 6899 | |
d05cae4a | 6900 | val_store (out, val, dstv, insn, true); |
dedc1e6d AO |
6901 | } |
6902 | break; | |
6903 | ||
014a1138 JZ |
6904 | case MO_SET: |
6905 | { | |
0de3e43f | 6906 | rtx loc = mo->u.loc; |
94a7682d | 6907 | rtx set_src = NULL; |
62760ffd | 6908 | |
94a7682d | 6909 | if (GET_CODE (loc) == SET) |
62760ffd | 6910 | { |
94a7682d RS |
6911 | set_src = SET_SRC (loc); |
6912 | loc = SET_DEST (loc); | |
62760ffd | 6913 | } |
014a1138 | 6914 | |
f8cfc6aa | 6915 | if (REG_P (loc)) |
62760ffd CT |
6916 | var_reg_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED, |
6917 | set_src); | |
ca787200 | 6918 | else if (MEM_P (loc)) |
62760ffd CT |
6919 | var_mem_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED, |
6920 | set_src); | |
ca787200 AO |
6921 | } |
6922 | break; | |
6923 | ||
6924 | case MO_COPY: | |
6925 | { | |
0de3e43f | 6926 | rtx loc = mo->u.loc; |
62760ffd | 6927 | enum var_init_status src_status; |
94a7682d RS |
6928 | rtx set_src = NULL; |
6929 | ||
6930 | if (GET_CODE (loc) == SET) | |
6931 | { | |
6932 | set_src = SET_SRC (loc); | |
6933 | loc = SET_DEST (loc); | |
6934 | } | |
62760ffd CT |
6935 | |
6936 | if (! flag_var_tracking_uninit) | |
6937 | src_status = VAR_INIT_STATUS_INITIALIZED; | |
6938 | else | |
7eb3f1f7 JJ |
6939 | { |
6940 | src_status = find_src_status (in, set_src); | |
62760ffd | 6941 | |
7eb3f1f7 JJ |
6942 | if (src_status == VAR_INIT_STATUS_UNKNOWN) |
6943 | src_status = find_src_status (out, set_src); | |
6944 | } | |
62760ffd | 6945 | |
94a7682d | 6946 | set_src = find_src_set_src (in, set_src); |
ca787200 AO |
6947 | |
6948 | if (REG_P (loc)) | |
62760ffd | 6949 | var_reg_delete_and_set (out, loc, false, src_status, set_src); |
3c0cb5de | 6950 | else if (MEM_P (loc)) |
62760ffd | 6951 | var_mem_delete_and_set (out, loc, false, src_status, set_src); |
014a1138 JZ |
6952 | } |
6953 | break; | |
6954 | ||
6955 | case MO_USE_NO_VAR: | |
ca787200 | 6956 | { |
0de3e43f | 6957 | rtx loc = mo->u.loc; |
ca787200 AO |
6958 | |
6959 | if (REG_P (loc)) | |
6960 | var_reg_delete (out, loc, false); | |
6961 | else if (MEM_P (loc)) | |
6962 | var_mem_delete (out, loc, false); | |
6963 | } | |
6964 | break; | |
6965 | ||
014a1138 JZ |
6966 | case MO_CLOBBER: |
6967 | { | |
0de3e43f | 6968 | rtx loc = mo->u.loc; |
014a1138 | 6969 | |
f8cfc6aa | 6970 | if (REG_P (loc)) |
ca787200 | 6971 | var_reg_delete (out, loc, true); |
3c0cb5de | 6972 | else if (MEM_P (loc)) |
ca787200 | 6973 | var_mem_delete (out, loc, true); |
014a1138 JZ |
6974 | } |
6975 | break; | |
6976 | ||
6977 | case MO_ADJUST: | |
0de3e43f | 6978 | out->stack_adjust += mo->u.adjust; |
014a1138 JZ |
6979 | break; |
6980 | } | |
6981 | } | |
6982 | ||
b5b8b0ac AO |
6983 | if (MAY_HAVE_DEBUG_INSNS) |
6984 | { | |
b787e7a2 | 6985 | delete local_get_addr_cache; |
af6236c1 AO |
6986 | local_get_addr_cache = NULL; |
6987 | ||
b5b8b0ac | 6988 | dataflow_set_equiv_regs (out); |
013e5ef9 | 6989 | shared_hash_htab (out->vars) |
c203e8a7 | 6990 | ->traverse <dataflow_set *, canonicalize_values_mark> (out); |
013e5ef9 | 6991 | shared_hash_htab (out->vars) |
c203e8a7 | 6992 | ->traverse <dataflow_set *, canonicalize_values_star> (out); |
b5b8b0ac | 6993 | #if ENABLE_CHECKING |
013e5ef9 | 6994 | shared_hash_htab (out->vars) |
c203e8a7 | 6995 | ->traverse <dataflow_set *, canonicalize_loc_order_check> (out); |
b5b8b0ac AO |
6996 | #endif |
6997 | } | |
014a1138 JZ |
6998 | changed = dataflow_set_different (&old_out, out); |
6999 | dataflow_set_destroy (&old_out); | |
7000 | return changed; | |
7001 | } | |
7002 | ||
7003 | /* Find the locations of variables in the whole function. */ | |
7004 | ||
ec8c3978 | 7005 | static bool |
014a1138 JZ |
7006 | vt_find_locations (void) |
7007 | { | |
7b69b603 ML |
7008 | bb_heap_t *worklist = new bb_heap_t (LONG_MIN); |
7009 | bb_heap_t *pending = new bb_heap_t (LONG_MIN); | |
fab27f52 | 7010 | sbitmap visited, in_worklist, in_pending; |
014a1138 JZ |
7011 | basic_block bb; |
7012 | edge e; | |
7013 | int *bb_order; | |
7014 | int *rc_order; | |
7015 | int i; | |
b5b8b0ac | 7016 | int htabsz = 0; |
ec8c3978 JJ |
7017 | int htabmax = PARAM_VALUE (PARAM_MAX_VARTRACK_SIZE); |
7018 | bool success = true; | |
014a1138 | 7019 | |
f029db69 | 7020 | timevar_push (TV_VAR_TRACKING_DATAFLOW); |
e04faf24 | 7021 | /* Compute reverse completion order of depth first search of the CFG |
014a1138 | 7022 | so that the data-flow runs faster. */ |
e04faf24 | 7023 | rc_order = XNEWVEC (int, n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS); |
8b1c6fd7 | 7024 | bb_order = XNEWVEC (int, last_basic_block_for_fn (cfun)); |
e04faf24 RB |
7025 | pre_and_rev_post_order_compute (NULL, rc_order, false); |
7026 | for (i = 0; i < n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS; i++) | |
014a1138 JZ |
7027 | bb_order[rc_order[i]] = i; |
7028 | free (rc_order); | |
7029 | ||
8b1c6fd7 DM |
7030 | visited = sbitmap_alloc (last_basic_block_for_fn (cfun)); |
7031 | in_worklist = sbitmap_alloc (last_basic_block_for_fn (cfun)); | |
7032 | in_pending = sbitmap_alloc (last_basic_block_for_fn (cfun)); | |
f61e445a | 7033 | bitmap_clear (in_worklist); |
014a1138 | 7034 | |
11cd3bed | 7035 | FOR_EACH_BB_FN (bb, cfun) |
7b69b603 | 7036 | pending->insert (bb_order[bb->index], bb); |
f61e445a | 7037 | bitmap_ones (in_pending); |
014a1138 | 7038 | |
7b69b603 | 7039 | while (success && !pending->empty ()) |
014a1138 | 7040 | { |
fab27f52 MM |
7041 | std::swap (worklist, pending); |
7042 | std::swap (in_worklist, in_pending); | |
014a1138 | 7043 | |
f61e445a | 7044 | bitmap_clear (visited); |
014a1138 | 7045 | |
7b69b603 | 7046 | while (!worklist->empty ()) |
014a1138 | 7047 | { |
7b69b603 | 7048 | bb = worklist->extract_min (); |
d7c028c0 LC |
7049 | bitmap_clear_bit (in_worklist, bb->index); |
7050 | gcc_assert (!bitmap_bit_p (visited, bb->index)); | |
7051 | if (!bitmap_bit_p (visited, bb->index)) | |
014a1138 JZ |
7052 | { |
7053 | bool changed; | |
628f6a4e | 7054 | edge_iterator ei; |
b5b8b0ac | 7055 | int oldinsz, oldoutsz; |
014a1138 | 7056 | |
d7c028c0 | 7057 | bitmap_set_bit (visited, bb->index); |
014a1138 | 7058 | |
ec8c3978 | 7059 | if (VTI (bb)->in.vars) |
b5b8b0ac AO |
7060 | { |
7061 | htabsz | |
c203e8a7 TS |
7062 | -= shared_hash_htab (VTI (bb)->in.vars)->size () |
7063 | + shared_hash_htab (VTI (bb)->out.vars)->size (); | |
7064 | oldinsz = shared_hash_htab (VTI (bb)->in.vars)->elements (); | |
7065 | oldoutsz | |
7066 | = shared_hash_htab (VTI (bb)->out.vars)->elements (); | |
b5b8b0ac AO |
7067 | } |
7068 | else | |
7069 | oldinsz = oldoutsz = 0; | |
7070 | ||
7071 | if (MAY_HAVE_DEBUG_INSNS) | |
7072 | { | |
7073 | dataflow_set *in = &VTI (bb)->in, *first_out = NULL; | |
7074 | bool first = true, adjust = false; | |
7075 | ||
7076 | /* Calculate the IN set as the intersection of | |
7077 | predecessor OUT sets. */ | |
7078 | ||
7079 | dataflow_set_clear (in); | |
7080 | dst_can_be_shared = true; | |
7081 | ||
7082 | FOR_EACH_EDGE (e, ei, bb->preds) | |
7083 | if (!VTI (e->src)->flooded) | |
7084 | gcc_assert (bb_order[bb->index] | |
7085 | <= bb_order[e->src->index]); | |
7086 | else if (first) | |
7087 | { | |
7088 | dataflow_set_copy (in, &VTI (e->src)->out); | |
7089 | first_out = &VTI (e->src)->out; | |
7090 | first = false; | |
7091 | } | |
7092 | else | |
7093 | { | |
7094 | dataflow_set_merge (in, &VTI (e->src)->out); | |
7095 | adjust = true; | |
7096 | } | |
7097 | ||
7098 | if (adjust) | |
7099 | { | |
7100 | dataflow_post_merge_adjust (in, &VTI (bb)->permp); | |
7101 | #if ENABLE_CHECKING | |
7102 | /* Merge and merge_adjust should keep entries in | |
7103 | canonical order. */ | |
013e5ef9 | 7104 | shared_hash_htab (in->vars) |
c203e8a7 TS |
7105 | ->traverse <dataflow_set *, |
7106 | canonicalize_loc_order_check> (in); | |
b5b8b0ac AO |
7107 | #endif |
7108 | if (dst_can_be_shared) | |
7109 | { | |
7110 | shared_hash_destroy (in->vars); | |
7111 | in->vars = shared_hash_copy (first_out->vars); | |
7112 | } | |
7113 | } | |
7114 | ||
7115 | VTI (bb)->flooded = true; | |
7116 | } | |
7117 | else | |
014a1138 | 7118 | { |
b5b8b0ac AO |
7119 | /* Calculate the IN set as union of predecessor OUT sets. */ |
7120 | dataflow_set_clear (&VTI (bb)->in); | |
7121 | FOR_EACH_EDGE (e, ei, bb->preds) | |
7122 | dataflow_set_union (&VTI (bb)->in, &VTI (e->src)->out); | |
014a1138 JZ |
7123 | } |
7124 | ||
7125 | changed = compute_bb_dataflow (bb); | |
c203e8a7 TS |
7126 | htabsz += shared_hash_htab (VTI (bb)->in.vars)->size () |
7127 | + shared_hash_htab (VTI (bb)->out.vars)->size (); | |
ec8c3978 JJ |
7128 | |
7129 | if (htabmax && htabsz > htabmax) | |
7130 | { | |
7131 | if (MAY_HAVE_DEBUG_INSNS) | |
7132 | inform (DECL_SOURCE_LOCATION (cfun->decl), | |
7133 | "variable tracking size limit exceeded with " | |
7134 | "-fvar-tracking-assignments, retrying without"); | |
7135 | else | |
7136 | inform (DECL_SOURCE_LOCATION (cfun->decl), | |
7137 | "variable tracking size limit exceeded"); | |
7138 | success = false; | |
7139 | break; | |
7140 | } | |
b5b8b0ac | 7141 | |
014a1138 JZ |
7142 | if (changed) |
7143 | { | |
628f6a4e | 7144 | FOR_EACH_EDGE (e, ei, bb->succs) |
014a1138 | 7145 | { |
fefa31b5 | 7146 | if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)) |
014a1138 JZ |
7147 | continue; |
7148 | ||
d7c028c0 | 7149 | if (bitmap_bit_p (visited, e->dest->index)) |
014a1138 | 7150 | { |
d7c028c0 | 7151 | if (!bitmap_bit_p (in_pending, e->dest->index)) |
014a1138 JZ |
7152 | { |
7153 | /* Send E->DEST to next round. */ | |
d7c028c0 | 7154 | bitmap_set_bit (in_pending, e->dest->index); |
7b69b603 ML |
7155 | pending->insert (bb_order[e->dest->index], |
7156 | e->dest); | |
014a1138 JZ |
7157 | } |
7158 | } | |
d7c028c0 | 7159 | else if (!bitmap_bit_p (in_worklist, e->dest->index)) |
014a1138 JZ |
7160 | { |
7161 | /* Add E->DEST to current round. */ | |
d7c028c0 | 7162 | bitmap_set_bit (in_worklist, e->dest->index); |
7b69b603 ML |
7163 | worklist->insert (bb_order[e->dest->index], |
7164 | e->dest); | |
014a1138 JZ |
7165 | } |
7166 | } | |
7167 | } | |
b5b8b0ac AO |
7168 | |
7169 | if (dump_file) | |
7170 | fprintf (dump_file, | |
7171 | "BB %i: in %i (was %i), out %i (was %i), rem %i + %i, tsz %i\n", | |
7172 | bb->index, | |
c203e8a7 | 7173 | (int)shared_hash_htab (VTI (bb)->in.vars)->size (), |
b5b8b0ac | 7174 | oldinsz, |
c203e8a7 | 7175 | (int)shared_hash_htab (VTI (bb)->out.vars)->size (), |
b5b8b0ac | 7176 | oldoutsz, |
7b69b603 ML |
7177 | (int)worklist->nodes (), (int)pending->nodes (), |
7178 | htabsz); | |
b5b8b0ac AO |
7179 | |
7180 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
7181 | { | |
7182 | fprintf (dump_file, "BB %i IN:\n", bb->index); | |
7183 | dump_dataflow_set (&VTI (bb)->in); | |
7184 | fprintf (dump_file, "BB %i OUT:\n", bb->index); | |
7185 | dump_dataflow_set (&VTI (bb)->out); | |
7186 | } | |
014a1138 JZ |
7187 | } |
7188 | } | |
7189 | } | |
7190 | ||
ec8c3978 | 7191 | if (success && MAY_HAVE_DEBUG_INSNS) |
11cd3bed | 7192 | FOR_EACH_BB_FN (bb, cfun) |
b5b8b0ac AO |
7193 | gcc_assert (VTI (bb)->flooded); |
7194 | ||
014a1138 | 7195 | free (bb_order); |
7b69b603 ML |
7196 | delete worklist; |
7197 | delete pending; | |
014a1138 JZ |
7198 | sbitmap_free (visited); |
7199 | sbitmap_free (in_worklist); | |
7200 | sbitmap_free (in_pending); | |
ec8c3978 | 7201 | |
f029db69 | 7202 | timevar_pop (TV_VAR_TRACKING_DATAFLOW); |
ec8c3978 | 7203 | return success; |
014a1138 JZ |
7204 | } |
7205 | ||
7206 | /* Print the content of the LIST to dump file. */ | |
7207 | ||
7208 | static void | |
7209 | dump_attrs_list (attrs list) | |
7210 | { | |
7211 | for (; list; list = list->next) | |
7212 | { | |
b5b8b0ac AO |
7213 | if (dv_is_decl_p (list->dv)) |
7214 | print_mem_expr (dump_file, dv_as_decl (list->dv)); | |
7215 | else | |
7216 | print_rtl_single (dump_file, dv_as_value (list->dv)); | |
30e6f306 | 7217 | fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset); |
014a1138 | 7218 | } |
c263766c | 7219 | fprintf (dump_file, "\n"); |
014a1138 JZ |
7220 | } |
7221 | ||
7222 | /* Print the information about variable *SLOT to dump file. */ | |
7223 | ||
013e5ef9 LC |
7224 | int |
7225 | dump_var_tracking_slot (variable_def **slot, void *data ATTRIBUTE_UNUSED) | |
b5b8b0ac | 7226 | { |
013e5ef9 | 7227 | variable var = *slot; |
b5b8b0ac | 7228 | |
4a4d4c08 | 7229 | dump_var (var); |
b5b8b0ac AO |
7230 | |
7231 | /* Continue traversing the hash table. */ | |
7232 | return 1; | |
7233 | } | |
7234 | ||
7235 | /* Print the information about variable VAR to dump file. */ | |
7236 | ||
7237 | static void | |
4a4d4c08 | 7238 | dump_var (variable var) |
014a1138 | 7239 | { |
014a1138 JZ |
7240 | int i; |
7241 | location_chain node; | |
7242 | ||
b5b8b0ac AO |
7243 | if (dv_is_decl_p (var->dv)) |
7244 | { | |
7245 | const_tree decl = dv_as_decl (var->dv); | |
7246 | ||
7247 | if (DECL_NAME (decl)) | |
6764d92c JJ |
7248 | { |
7249 | fprintf (dump_file, " name: %s", | |
7250 | IDENTIFIER_POINTER (DECL_NAME (decl))); | |
7251 | if (dump_flags & TDF_UID) | |
7252 | fprintf (dump_file, "D.%u", DECL_UID (decl)); | |
7253 | } | |
7254 | else if (TREE_CODE (decl) == DEBUG_EXPR_DECL) | |
7255 | fprintf (dump_file, " name: D#%u", DEBUG_TEMP_UID (decl)); | |
b5b8b0ac AO |
7256 | else |
7257 | fprintf (dump_file, " name: D.%u", DECL_UID (decl)); | |
6764d92c | 7258 | fprintf (dump_file, "\n"); |
b5b8b0ac | 7259 | } |
e56f9152 | 7260 | else |
b5b8b0ac AO |
7261 | { |
7262 | fputc (' ', dump_file); | |
7263 | print_rtl_single (dump_file, dv_as_value (var->dv)); | |
7264 | } | |
e56f9152 | 7265 | |
014a1138 JZ |
7266 | for (i = 0; i < var->n_var_parts; i++) |
7267 | { | |
c263766c | 7268 | fprintf (dump_file, " offset %ld\n", |
09dbcd96 | 7269 | (long)(var->onepart ? 0 : VAR_PART_OFFSET (var, i))); |
014a1138 JZ |
7270 | for (node = var->var_part[i].loc_chain; node; node = node->next) |
7271 | { | |
c263766c | 7272 | fprintf (dump_file, " "); |
62760ffd CT |
7273 | if (node->init == VAR_INIT_STATUS_UNINITIALIZED) |
7274 | fprintf (dump_file, "[uninit]"); | |
c263766c | 7275 | print_rtl_single (dump_file, node->loc); |
014a1138 JZ |
7276 | } |
7277 | } | |
014a1138 JZ |
7278 | } |
7279 | ||
7280 | /* Print the information about variables from hash table VARS to dump file. */ | |
7281 | ||
7282 | static void | |
c203e8a7 | 7283 | dump_vars (variable_table_type *vars) |
014a1138 | 7284 | { |
c203e8a7 | 7285 | if (vars->elements () > 0) |
014a1138 | 7286 | { |
c263766c | 7287 | fprintf (dump_file, "Variables:\n"); |
c203e8a7 | 7288 | vars->traverse <void *, dump_var_tracking_slot> (NULL); |
014a1138 JZ |
7289 | } |
7290 | } | |
7291 | ||
7292 | /* Print the dataflow set SET to dump file. */ | |
7293 | ||
7294 | static void | |
7295 | dump_dataflow_set (dataflow_set *set) | |
7296 | { | |
7297 | int i; | |
7298 | ||
30e6f306 RH |
7299 | fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n", |
7300 | set->stack_adjust); | |
d3067303 | 7301 | for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) |
014a1138 JZ |
7302 | { |
7303 | if (set->regs[i]) | |
7304 | { | |
c263766c | 7305 | fprintf (dump_file, "Reg %d:", i); |
014a1138 JZ |
7306 | dump_attrs_list (set->regs[i]); |
7307 | } | |
7308 | } | |
d24686d7 | 7309 | dump_vars (shared_hash_htab (set->vars)); |
c263766c | 7310 | fprintf (dump_file, "\n"); |
014a1138 JZ |
7311 | } |
7312 | ||
7313 | /* Print the IN and OUT sets for each basic block to dump file. */ | |
7314 | ||
7315 | static void | |
7316 | dump_dataflow_sets (void) | |
7317 | { | |
7318 | basic_block bb; | |
7319 | ||
11cd3bed | 7320 | FOR_EACH_BB_FN (bb, cfun) |
014a1138 | 7321 | { |
c263766c RH |
7322 | fprintf (dump_file, "\nBasic block %d:\n", bb->index); |
7323 | fprintf (dump_file, "IN:\n"); | |
014a1138 | 7324 | dump_dataflow_set (&VTI (bb)->in); |
c263766c | 7325 | fprintf (dump_file, "OUT:\n"); |
014a1138 JZ |
7326 | dump_dataflow_set (&VTI (bb)->out); |
7327 | } | |
7328 | } | |
7329 | ||
09dbcd96 AO |
7330 | /* Return the variable for DV in dropped_values, inserting one if |
7331 | requested with INSERT. */ | |
7332 | ||
7333 | static inline variable | |
7334 | variable_from_dropped (decl_or_value dv, enum insert_option insert) | |
7335 | { | |
013e5ef9 | 7336 | variable_def **slot; |
09dbcd96 AO |
7337 | variable empty_var; |
7338 | onepart_enum_t onepart; | |
7339 | ||
c203e8a7 | 7340 | slot = dropped_values->find_slot_with_hash (dv, dv_htab_hash (dv), insert); |
09dbcd96 AO |
7341 | |
7342 | if (!slot) | |
7343 | return NULL; | |
7344 | ||
7345 | if (*slot) | |
013e5ef9 | 7346 | return *slot; |
09dbcd96 AO |
7347 | |
7348 | gcc_checking_assert (insert == INSERT); | |
7349 | ||
7350 | onepart = dv_onepart_p (dv); | |
7351 | ||
7352 | gcc_checking_assert (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR); | |
7353 | ||
7e46899d | 7354 | empty_var = onepart_pool (onepart).allocate (); |
09dbcd96 AO |
7355 | empty_var->dv = dv; |
7356 | empty_var->refcount = 1; | |
7357 | empty_var->n_var_parts = 0; | |
7358 | empty_var->onepart = onepart; | |
7359 | empty_var->in_changed_variables = false; | |
7360 | empty_var->var_part[0].loc_chain = NULL; | |
7361 | empty_var->var_part[0].cur_loc = NULL; | |
7362 | VAR_LOC_1PAUX (empty_var) = NULL; | |
7363 | set_dv_changed (dv, true); | |
7364 | ||
7365 | *slot = empty_var; | |
7366 | ||
7367 | return empty_var; | |
7368 | } | |
7369 | ||
7370 | /* Recover the one-part aux from dropped_values. */ | |
7371 | ||
7372 | static struct onepart_aux * | |
7373 | recover_dropped_1paux (variable var) | |
7374 | { | |
7375 | variable dvar; | |
7376 | ||
7377 | gcc_checking_assert (var->onepart); | |
7378 | ||
7379 | if (VAR_LOC_1PAUX (var)) | |
7380 | return VAR_LOC_1PAUX (var); | |
7381 | ||
7382 | if (var->onepart == ONEPART_VDECL) | |
7383 | return NULL; | |
7384 | ||
7385 | dvar = variable_from_dropped (var->dv, NO_INSERT); | |
7386 | ||
7387 | if (!dvar) | |
7388 | return NULL; | |
7389 | ||
7390 | VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (dvar); | |
7391 | VAR_LOC_1PAUX (dvar) = NULL; | |
7392 | ||
7393 | return VAR_LOC_1PAUX (var); | |
7394 | } | |
7395 | ||
7396 | /* Add variable VAR to the hash table of changed variables and | |
d24686d7 | 7397 | if it has no locations delete it from SET's hash table. */ |
014a1138 JZ |
7398 | |
7399 | static void | |
d24686d7 | 7400 | variable_was_changed (variable var, dataflow_set *set) |
014a1138 | 7401 | { |
b5b8b0ac | 7402 | hashval_t hash = dv_htab_hash (var->dv); |
014a1138 JZ |
7403 | |
7404 | if (emit_notes) | |
7405 | { | |
013e5ef9 | 7406 | variable_def **slot; |
b5b8b0ac AO |
7407 | |
7408 | /* Remember this decl or VALUE has been added to changed_variables. */ | |
7409 | set_dv_changed (var->dv, true); | |
014a1138 | 7410 | |
c203e8a7 | 7411 | slot = changed_variables->find_slot_with_hash (var->dv, hash, INSERT); |
014a1138 | 7412 | |
864ddef7 JJ |
7413 | if (*slot) |
7414 | { | |
013e5ef9 | 7415 | variable old_var = *slot; |
864ddef7 JJ |
7416 | gcc_assert (old_var->in_changed_variables); |
7417 | old_var->in_changed_variables = false; | |
09dbcd96 AO |
7418 | if (var != old_var && var->onepart) |
7419 | { | |
7420 | /* Restore the auxiliary info from an empty variable | |
7421 | previously created for changed_variables, so it is | |
7422 | not lost. */ | |
7423 | gcc_checking_assert (!VAR_LOC_1PAUX (var)); | |
7424 | VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (old_var); | |
7425 | VAR_LOC_1PAUX (old_var) = NULL; | |
7426 | } | |
864ddef7 JJ |
7427 | variable_htab_free (*slot); |
7428 | } | |
09dbcd96 | 7429 | |
d24686d7 | 7430 | if (set && var->n_var_parts == 0) |
014a1138 | 7431 | { |
09dbcd96 AO |
7432 | onepart_enum_t onepart = var->onepart; |
7433 | variable empty_var = NULL; | |
013e5ef9 | 7434 | variable_def **dslot = NULL; |
014a1138 | 7435 | |
09dbcd96 AO |
7436 | if (onepart == ONEPART_VALUE || onepart == ONEPART_DEXPR) |
7437 | { | |
c203e8a7 TS |
7438 | dslot = dropped_values->find_slot_with_hash (var->dv, |
7439 | dv_htab_hash (var->dv), | |
7440 | INSERT); | |
013e5ef9 | 7441 | empty_var = *dslot; |
09dbcd96 AO |
7442 | |
7443 | if (empty_var) | |
7444 | { | |
7445 | gcc_checking_assert (!empty_var->in_changed_variables); | |
7446 | if (!VAR_LOC_1PAUX (var)) | |
7447 | { | |
7448 | VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (empty_var); | |
7449 | VAR_LOC_1PAUX (empty_var) = NULL; | |
7450 | } | |
7451 | else | |
7452 | gcc_checking_assert (!VAR_LOC_1PAUX (empty_var)); | |
7453 | } | |
7454 | } | |
7455 | ||
7456 | if (!empty_var) | |
7457 | { | |
7e46899d | 7458 | empty_var = onepart_pool (onepart).allocate (); |
09dbcd96 AO |
7459 | empty_var->dv = var->dv; |
7460 | empty_var->refcount = 1; | |
7461 | empty_var->n_var_parts = 0; | |
7462 | empty_var->onepart = onepart; | |
7463 | if (dslot) | |
7464 | { | |
7465 | empty_var->refcount++; | |
7466 | *dslot = empty_var; | |
7467 | } | |
7468 | } | |
7469 | else | |
7470 | empty_var->refcount++; | |
864ddef7 | 7471 | empty_var->in_changed_variables = true; |
014a1138 | 7472 | *slot = empty_var; |
09dbcd96 AO |
7473 | if (onepart) |
7474 | { | |
7475 | empty_var->var_part[0].loc_chain = NULL; | |
7476 | empty_var->var_part[0].cur_loc = NULL; | |
7477 | VAR_LOC_1PAUX (empty_var) = VAR_LOC_1PAUX (var); | |
7478 | VAR_LOC_1PAUX (var) = NULL; | |
7479 | } | |
d24686d7 | 7480 | goto drop_var; |
014a1138 JZ |
7481 | } |
7482 | else | |
7483 | { | |
09dbcd96 AO |
7484 | if (var->onepart && !VAR_LOC_1PAUX (var)) |
7485 | recover_dropped_1paux (var); | |
d24686d7 | 7486 | var->refcount++; |
864ddef7 | 7487 | var->in_changed_variables = true; |
014a1138 JZ |
7488 | *slot = var; |
7489 | } | |
7490 | } | |
7491 | else | |
7492 | { | |
d24686d7 | 7493 | gcc_assert (set); |
014a1138 JZ |
7494 | if (var->n_var_parts == 0) |
7495 | { | |
013e5ef9 | 7496 | variable_def **slot; |
d24686d7 JJ |
7497 | |
7498 | drop_var: | |
b5b8b0ac | 7499 | slot = shared_hash_find_slot_noinsert (set->vars, var->dv); |
014a1138 | 7500 | if (slot) |
d24686d7 JJ |
7501 | { |
7502 | if (shared_hash_shared (set->vars)) | |
b5b8b0ac | 7503 | slot = shared_hash_find_slot_unshare (&set->vars, var->dv, |
d24686d7 | 7504 | NO_INSERT); |
c203e8a7 | 7505 | shared_hash_htab (set->vars)->clear_slot (slot); |
d24686d7 | 7506 | } |
014a1138 JZ |
7507 | } |
7508 | } | |
7509 | } | |
7510 | ||
ca787200 AO |
7511 | /* Look for the index in VAR->var_part corresponding to OFFSET. |
7512 | Return -1 if not found. If INSERTION_POINT is non-NULL, the | |
7513 | referenced int will be set to the index that the part has or should | |
7514 | have, if it should be inserted. */ | |
7515 | ||
7516 | static inline int | |
7517 | find_variable_location_part (variable var, HOST_WIDE_INT offset, | |
7518 | int *insertion_point) | |
7519 | { | |
7520 | int pos, low, high; | |
7521 | ||
09dbcd96 AO |
7522 | if (var->onepart) |
7523 | { | |
7524 | if (offset != 0) | |
7525 | return -1; | |
7526 | ||
7527 | if (insertion_point) | |
7528 | *insertion_point = 0; | |
7529 | ||
7530 | return var->n_var_parts - 1; | |
7531 | } | |
7532 | ||
ca787200 AO |
7533 | /* Find the location part. */ |
7534 | low = 0; | |
7535 | high = var->n_var_parts; | |
7536 | while (low != high) | |
7537 | { | |
7538 | pos = (low + high) / 2; | |
09dbcd96 | 7539 | if (VAR_PART_OFFSET (var, pos) < offset) |
ca787200 AO |
7540 | low = pos + 1; |
7541 | else | |
7542 | high = pos; | |
7543 | } | |
7544 | pos = low; | |
7545 | ||
7546 | if (insertion_point) | |
7547 | *insertion_point = pos; | |
7548 | ||
09dbcd96 | 7549 | if (pos < var->n_var_parts && VAR_PART_OFFSET (var, pos) == offset) |
ca787200 AO |
7550 | return pos; |
7551 | ||
7552 | return -1; | |
7553 | } | |
7554 | ||
013e5ef9 LC |
7555 | static variable_def ** |
7556 | set_slot_part (dataflow_set *set, rtx loc, variable_def **slot, | |
b5b8b0ac AO |
7557 | decl_or_value dv, HOST_WIDE_INT offset, |
7558 | enum var_init_status initialized, rtx set_src) | |
014a1138 | 7559 | { |
ca787200 | 7560 | int pos; |
11599d14 JZ |
7561 | location_chain node, next; |
7562 | location_chain *nextp; | |
014a1138 | 7563 | variable var; |
09dbcd96 | 7564 | onepart_enum_t onepart; |
b5b8b0ac | 7565 | |
013e5ef9 | 7566 | var = *slot; |
d24686d7 | 7567 | |
09dbcd96 AO |
7568 | if (var) |
7569 | onepart = var->onepart; | |
7570 | else | |
7571 | onepart = dv_onepart_p (dv); | |
7572 | ||
7573 | gcc_checking_assert (offset == 0 || !onepart); | |
7574 | gcc_checking_assert (loc != dv_as_opaque (dv)); | |
7575 | ||
7eb3f1f7 JJ |
7576 | if (! flag_var_tracking_uninit) |
7577 | initialized = VAR_INIT_STATUS_INITIALIZED; | |
7578 | ||
b5b8b0ac | 7579 | if (!var) |
014a1138 JZ |
7580 | { |
7581 | /* Create new variable information. */ | |
7e46899d | 7582 | var = onepart_pool (onepart).allocate (); |
b5b8b0ac | 7583 | var->dv = dv; |
81f2eadb | 7584 | var->refcount = 1; |
014a1138 | 7585 | var->n_var_parts = 1; |
09dbcd96 | 7586 | var->onepart = onepart; |
864ddef7 | 7587 | var->in_changed_variables = false; |
09dbcd96 AO |
7588 | if (var->onepart) |
7589 | VAR_LOC_1PAUX (var) = NULL; | |
7590 | else | |
7591 | VAR_PART_OFFSET (var, 0) = offset; | |
014a1138 JZ |
7592 | var->var_part[0].loc_chain = NULL; |
7593 | var->var_part[0].cur_loc = NULL; | |
7594 | *slot = var; | |
7595 | pos = 0; | |
b5b8b0ac | 7596 | nextp = &var->var_part[0].loc_chain; |
b5b8b0ac AO |
7597 | } |
7598 | else if (onepart) | |
7599 | { | |
7600 | int r = -1, c = 0; | |
7601 | ||
7602 | gcc_assert (dv_as_opaque (var->dv) == dv_as_opaque (dv)); | |
7603 | ||
7604 | pos = 0; | |
7605 | ||
7606 | if (GET_CODE (loc) == VALUE) | |
7607 | { | |
7608 | for (nextp = &var->var_part[0].loc_chain; (node = *nextp); | |
7609 | nextp = &node->next) | |
7610 | if (GET_CODE (node->loc) == VALUE) | |
7611 | { | |
7612 | if (node->loc == loc) | |
7613 | { | |
7614 | r = 0; | |
7615 | break; | |
7616 | } | |
7617 | if (canon_value_cmp (node->loc, loc)) | |
7618 | c++; | |
7619 | else | |
7620 | { | |
7621 | r = 1; | |
7622 | break; | |
7623 | } | |
7624 | } | |
7625 | else if (REG_P (node->loc) || MEM_P (node->loc)) | |
7626 | c++; | |
7627 | else | |
7628 | { | |
7629 | r = 1; | |
7630 | break; | |
7631 | } | |
7632 | } | |
7633 | else if (REG_P (loc)) | |
7634 | { | |
7635 | for (nextp = &var->var_part[0].loc_chain; (node = *nextp); | |
7636 | nextp = &node->next) | |
7637 | if (REG_P (node->loc)) | |
7638 | { | |
7639 | if (REGNO (node->loc) < REGNO (loc)) | |
7640 | c++; | |
7641 | else | |
7642 | { | |
7643 | if (REGNO (node->loc) == REGNO (loc)) | |
7644 | r = 0; | |
7645 | else | |
7646 | r = 1; | |
7647 | break; | |
7648 | } | |
7649 | } | |
7650 | else | |
7651 | { | |
7652 | r = 1; | |
7653 | break; | |
7654 | } | |
7655 | } | |
7656 | else if (MEM_P (loc)) | |
7657 | { | |
7658 | for (nextp = &var->var_part[0].loc_chain; (node = *nextp); | |
7659 | nextp = &node->next) | |
7660 | if (REG_P (node->loc)) | |
7661 | c++; | |
7662 | else if (MEM_P (node->loc)) | |
7663 | { | |
7664 | if ((r = loc_cmp (XEXP (node->loc, 0), XEXP (loc, 0))) >= 0) | |
7665 | break; | |
7666 | else | |
7667 | c++; | |
7668 | } | |
7669 | else | |
7670 | { | |
7671 | r = 1; | |
7672 | break; | |
7673 | } | |
7674 | } | |
7675 | else | |
7676 | for (nextp = &var->var_part[0].loc_chain; (node = *nextp); | |
7677 | nextp = &node->next) | |
7678 | if ((r = loc_cmp (node->loc, loc)) >= 0) | |
7679 | break; | |
7680 | else | |
7681 | c++; | |
7682 | ||
7683 | if (r == 0) | |
7684 | return slot; | |
7685 | ||
864ddef7 | 7686 | if (shared_var_p (var, set->vars)) |
b5b8b0ac AO |
7687 | { |
7688 | slot = unshare_variable (set, slot, var, initialized); | |
013e5ef9 | 7689 | var = *slot; |
b5b8b0ac AO |
7690 | for (nextp = &var->var_part[0].loc_chain; c; |
7691 | nextp = &(*nextp)->next) | |
7692 | c--; | |
7693 | gcc_assert ((!node && !*nextp) || node->loc == (*nextp)->loc); | |
7694 | } | |
014a1138 JZ |
7695 | } |
7696 | else | |
7697 | { | |
ca787200 AO |
7698 | int inspos = 0; |
7699 | ||
b5b8b0ac | 7700 | gcc_assert (dv_as_decl (var->dv) == dv_as_decl (dv)); |
014a1138 | 7701 | |
ca787200 | 7702 | pos = find_variable_location_part (var, offset, &inspos); |
014a1138 | 7703 | |
ca787200 | 7704 | if (pos >= 0) |
014a1138 | 7705 | { |
81f2eadb JZ |
7706 | node = var->var_part[pos].loc_chain; |
7707 | ||
7708 | if (node | |
f8cfc6aa | 7709 | && ((REG_P (node->loc) && REG_P (loc) |
81f2eadb JZ |
7710 | && REGNO (node->loc) == REGNO (loc)) |
7711 | || rtx_equal_p (node->loc, loc))) | |
7712 | { | |
7713 | /* LOC is in the beginning of the chain so we have nothing | |
7714 | to do. */ | |
62760ffd CT |
7715 | if (node->init < initialized) |
7716 | node->init = initialized; | |
7717 | if (set_src != NULL) | |
7718 | node->set_src = set_src; | |
7719 | ||
b5b8b0ac | 7720 | return slot; |
81f2eadb JZ |
7721 | } |
7722 | else | |
7723 | { | |
7724 | /* We have to make a copy of a shared variable. */ | |
864ddef7 | 7725 | if (shared_var_p (var, set->vars)) |
b5b8b0ac AO |
7726 | { |
7727 | slot = unshare_variable (set, slot, var, initialized); | |
013e5ef9 | 7728 | var = *slot; |
b5b8b0ac | 7729 | } |
81f2eadb JZ |
7730 | } |
7731 | } | |
7732 | else | |
7733 | { | |
7734 | /* We have not found the location part, new one will be created. */ | |
7735 | ||
7736 | /* We have to make a copy of the shared variable. */ | |
864ddef7 | 7737 | if (shared_var_p (var, set->vars)) |
b5b8b0ac AO |
7738 | { |
7739 | slot = unshare_variable (set, slot, var, initialized); | |
013e5ef9 | 7740 | var = *slot; |
b5b8b0ac | 7741 | } |
014a1138 | 7742 | |
014a1138 JZ |
7743 | /* We track only variables whose size is <= MAX_VAR_PARTS bytes |
7744 | thus there are at most MAX_VAR_PARTS different offsets. */ | |
b5b8b0ac | 7745 | gcc_assert (var->n_var_parts < MAX_VAR_PARTS |
09dbcd96 | 7746 | && (!var->n_var_parts || !onepart)); |
014a1138 | 7747 | |
ca787200 AO |
7748 | /* We have to move the elements of array starting at index |
7749 | inspos to the next position. */ | |
7750 | for (pos = var->n_var_parts; pos > inspos; pos--) | |
7751 | var->var_part[pos] = var->var_part[pos - 1]; | |
014a1138 JZ |
7752 | |
7753 | var->n_var_parts++; | |
09dbcd96 AO |
7754 | gcc_checking_assert (!onepart); |
7755 | VAR_PART_OFFSET (var, pos) = offset; | |
014a1138 JZ |
7756 | var->var_part[pos].loc_chain = NULL; |
7757 | var->var_part[pos].cur_loc = NULL; | |
7758 | } | |
014a1138 | 7759 | |
b5b8b0ac AO |
7760 | /* Delete the location from the list. */ |
7761 | nextp = &var->var_part[pos].loc_chain; | |
7762 | for (node = var->var_part[pos].loc_chain; node; node = next) | |
014a1138 | 7763 | { |
b5b8b0ac AO |
7764 | next = node->next; |
7765 | if ((REG_P (node->loc) && REG_P (loc) | |
7766 | && REGNO (node->loc) == REGNO (loc)) | |
7767 | || rtx_equal_p (node->loc, loc)) | |
7768 | { | |
7769 | /* Save these values, to assign to the new node, before | |
7770 | deleting this one. */ | |
7771 | if (node->init > initialized) | |
7772 | initialized = node->init; | |
7773 | if (node->set_src != NULL && set_src == NULL) | |
7774 | set_src = node->set_src; | |
864ddef7 | 7775 | if (var->var_part[pos].cur_loc == node->loc) |
09dbcd96 | 7776 | var->var_part[pos].cur_loc = NULL; |
7e46899d | 7777 | delete node; |
b5b8b0ac AO |
7778 | *nextp = next; |
7779 | break; | |
7780 | } | |
7781 | else | |
7782 | nextp = &node->next; | |
014a1138 | 7783 | } |
b5b8b0ac AO |
7784 | |
7785 | nextp = &var->var_part[pos].loc_chain; | |
014a1138 JZ |
7786 | } |
7787 | ||
7788 | /* Add the location to the beginning. */ | |
7e46899d | 7789 | node = new location_chain_def; |
014a1138 | 7790 | node->loc = loc; |
62760ffd CT |
7791 | node->init = initialized; |
7792 | node->set_src = set_src; | |
b5b8b0ac AO |
7793 | node->next = *nextp; |
7794 | *nextp = node; | |
7795 | ||
014a1138 JZ |
7796 | /* If no location was emitted do so. */ |
7797 | if (var->var_part[pos].cur_loc == NULL) | |
864ddef7 | 7798 | variable_was_changed (var, set); |
b5b8b0ac AO |
7799 | |
7800 | return slot; | |
014a1138 JZ |
7801 | } |
7802 | ||
b5b8b0ac AO |
7803 | /* Set the part of variable's location in the dataflow set SET. The |
7804 | variable part is specified by variable's declaration in DV and | |
7805 | offset OFFSET and the part's location by LOC. IOPT should be | |
7806 | NO_INSERT if the variable is known to be in SET already and the | |
7807 | variable hash table must not be resized, and INSERT otherwise. */ | |
ca787200 AO |
7808 | |
7809 | static void | |
b5b8b0ac AO |
7810 | set_variable_part (dataflow_set *set, rtx loc, |
7811 | decl_or_value dv, HOST_WIDE_INT offset, | |
7812 | enum var_init_status initialized, rtx set_src, | |
7813 | enum insert_option iopt) | |
ca787200 | 7814 | { |
013e5ef9 | 7815 | variable_def **slot; |
ca787200 | 7816 | |
b5b8b0ac AO |
7817 | if (iopt == NO_INSERT) |
7818 | slot = shared_hash_find_slot_noinsert (set->vars, dv); | |
7819 | else | |
7820 | { | |
7821 | slot = shared_hash_find_slot (set->vars, dv); | |
7822 | if (!slot) | |
7823 | slot = shared_hash_find_slot_unshare (&set->vars, dv, iopt); | |
7824 | } | |
649beb33 | 7825 | set_slot_part (set, loc, slot, dv, offset, initialized, set_src); |
b5b8b0ac | 7826 | } |
ca787200 | 7827 | |
b5b8b0ac AO |
7828 | /* Remove all recorded register locations for the given variable part |
7829 | from dataflow set SET, except for those that are identical to loc. | |
7830 | The variable part is specified by variable's declaration or value | |
7831 | DV and offset OFFSET. */ | |
7832 | ||
013e5ef9 LC |
7833 | static variable_def ** |
7834 | clobber_slot_part (dataflow_set *set, rtx loc, variable_def **slot, | |
b5b8b0ac AO |
7835 | HOST_WIDE_INT offset, rtx set_src) |
7836 | { | |
013e5ef9 | 7837 | variable var = *slot; |
b5b8b0ac AO |
7838 | int pos = find_variable_location_part (var, offset, NULL); |
7839 | ||
7840 | if (pos >= 0) | |
ca787200 | 7841 | { |
b5b8b0ac | 7842 | location_chain node, next; |
ca787200 | 7843 | |
b5b8b0ac AO |
7844 | /* Remove the register locations from the dataflow set. */ |
7845 | next = var->var_part[pos].loc_chain; | |
7846 | for (node = next; node; node = next) | |
ca787200 | 7847 | { |
b5b8b0ac AO |
7848 | next = node->next; |
7849 | if (node->loc != loc | |
7850 | && (!flag_var_tracking_uninit | |
7851 | || !set_src | |
7852 | || MEM_P (set_src) | |
7853 | || !rtx_equal_p (set_src, node->set_src))) | |
ca787200 | 7854 | { |
b5b8b0ac | 7855 | if (REG_P (node->loc)) |
d3067303 | 7856 | { |
b5b8b0ac AO |
7857 | attrs anode, anext; |
7858 | attrs *anextp; | |
7859 | ||
7860 | /* Remove the variable part from the register's | |
7861 | list, but preserve any other variable parts | |
7862 | that might be regarded as live in that same | |
7863 | register. */ | |
7864 | anextp = &set->regs[REGNO (node->loc)]; | |
7865 | for (anode = *anextp; anode; anode = anext) | |
d3067303 | 7866 | { |
b5b8b0ac AO |
7867 | anext = anode->next; |
7868 | if (dv_as_opaque (anode->dv) == dv_as_opaque (var->dv) | |
7869 | && anode->offset == offset) | |
d3067303 | 7870 | { |
7e46899d | 7871 | delete anode; |
b5b8b0ac | 7872 | *anextp = anext; |
d3067303 | 7873 | } |
b5b8b0ac AO |
7874 | else |
7875 | anextp = &anode->next; | |
d3067303 | 7876 | } |
b5b8b0ac AO |
7877 | } |
7878 | ||
7879 | slot = delete_slot_part (set, node->loc, slot, offset); | |
7880 | } | |
7881 | } | |
7882 | } | |
7883 | ||
7884 | return slot; | |
7885 | } | |
7886 | ||
7887 | /* Remove all recorded register locations for the given variable part | |
7888 | from dataflow set SET, except for those that are identical to loc. | |
7889 | The variable part is specified by variable's declaration or value | |
7890 | DV and offset OFFSET. */ | |
7891 | ||
7892 | static void | |
7893 | clobber_variable_part (dataflow_set *set, rtx loc, decl_or_value dv, | |
7894 | HOST_WIDE_INT offset, rtx set_src) | |
7895 | { | |
013e5ef9 | 7896 | variable_def **slot; |
b5b8b0ac AO |
7897 | |
7898 | if (!dv_as_opaque (dv) | |
7899 | || (!dv_is_value_p (dv) && ! DECL_P (dv_as_decl (dv)))) | |
7900 | return; | |
7901 | ||
7902 | slot = shared_hash_find_slot_noinsert (set->vars, dv); | |
7903 | if (!slot) | |
7904 | return; | |
7905 | ||
649beb33 | 7906 | clobber_slot_part (set, loc, slot, offset, set_src); |
b5b8b0ac | 7907 | } |
d3067303 | 7908 | |
b5b8b0ac AO |
7909 | /* Delete the part of variable's location from dataflow set SET. The |
7910 | variable part is specified by its SET->vars slot SLOT and offset | |
7911 | OFFSET and the part's location by LOC. */ | |
7912 | ||
013e5ef9 LC |
7913 | static variable_def ** |
7914 | delete_slot_part (dataflow_set *set, rtx loc, variable_def **slot, | |
b5b8b0ac AO |
7915 | HOST_WIDE_INT offset) |
7916 | { | |
013e5ef9 | 7917 | variable var = *slot; |
b5b8b0ac AO |
7918 | int pos = find_variable_location_part (var, offset, NULL); |
7919 | ||
7920 | if (pos >= 0) | |
7921 | { | |
7922 | location_chain node, next; | |
7923 | location_chain *nextp; | |
7924 | bool changed; | |
09dbcd96 | 7925 | rtx cur_loc; |
b5b8b0ac | 7926 | |
864ddef7 | 7927 | if (shared_var_p (var, set->vars)) |
b5b8b0ac AO |
7928 | { |
7929 | /* If the variable contains the location part we have to | |
7930 | make a copy of the variable. */ | |
7931 | for (node = var->var_part[pos].loc_chain; node; | |
7932 | node = node->next) | |
7933 | { | |
7934 | if ((REG_P (node->loc) && REG_P (loc) | |
7935 | && REGNO (node->loc) == REGNO (loc)) | |
7936 | || rtx_equal_p (node->loc, loc)) | |
7937 | { | |
7938 | slot = unshare_variable (set, slot, var, | |
7939 | VAR_INIT_STATUS_UNKNOWN); | |
013e5ef9 | 7940 | var = *slot; |
b5b8b0ac | 7941 | break; |
d3067303 | 7942 | } |
ca787200 AO |
7943 | } |
7944 | } | |
b5b8b0ac | 7945 | |
09dbcd96 AO |
7946 | if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var)) |
7947 | cur_loc = VAR_LOC_FROM (var); | |
7948 | else | |
7949 | cur_loc = var->var_part[pos].cur_loc; | |
7950 | ||
b5b8b0ac | 7951 | /* Delete the location part. */ |
864ddef7 | 7952 | changed = false; |
b5b8b0ac AO |
7953 | nextp = &var->var_part[pos].loc_chain; |
7954 | for (node = *nextp; node; node = next) | |
7955 | { | |
7956 | next = node->next; | |
7957 | if ((REG_P (node->loc) && REG_P (loc) | |
7958 | && REGNO (node->loc) == REGNO (loc)) | |
7959 | || rtx_equal_p (node->loc, loc)) | |
7960 | { | |
864ddef7 JJ |
7961 | /* If we have deleted the location which was last emitted |
7962 | we have to emit new location so add the variable to set | |
7963 | of changed variables. */ | |
09dbcd96 | 7964 | if (cur_loc == node->loc) |
864ddef7 JJ |
7965 | { |
7966 | changed = true; | |
7967 | var->var_part[pos].cur_loc = NULL; | |
09dbcd96 AO |
7968 | if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var)) |
7969 | VAR_LOC_FROM (var) = NULL; | |
864ddef7 | 7970 | } |
7e46899d | 7971 | delete node; |
b5b8b0ac AO |
7972 | *nextp = next; |
7973 | break; | |
7974 | } | |
7975 | else | |
7976 | nextp = &node->next; | |
7977 | } | |
7978 | ||
b5b8b0ac AO |
7979 | if (var->var_part[pos].loc_chain == NULL) |
7980 | { | |
864ddef7 | 7981 | changed = true; |
b5b8b0ac | 7982 | var->n_var_parts--; |
b5b8b0ac AO |
7983 | while (pos < var->n_var_parts) |
7984 | { | |
7985 | var->var_part[pos] = var->var_part[pos + 1]; | |
7986 | pos++; | |
7987 | } | |
7988 | } | |
7989 | if (changed) | |
7990 | variable_was_changed (var, set); | |
7991 | } | |
7992 | ||
7993 | return slot; | |
7994 | } | |
7995 | ||
7996 | /* Delete the part of variable's location from dataflow set SET. The | |
7997 | variable part is specified by variable's declaration or value DV | |
7998 | and offset OFFSET and the part's location by LOC. */ | |
7999 | ||
8000 | static void | |
8001 | delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv, | |
8002 | HOST_WIDE_INT offset) | |
8003 | { | |
013e5ef9 | 8004 | variable_def **slot = shared_hash_find_slot_noinsert (set->vars, dv); |
b5b8b0ac AO |
8005 | if (!slot) |
8006 | return; | |
8007 | ||
649beb33 | 8008 | delete_slot_part (set, loc, slot, offset); |
b5b8b0ac AO |
8009 | } |
8010 | ||
09dbcd96 | 8011 | |
864ddef7 JJ |
8012 | /* Structure for passing some other parameters to function |
8013 | vt_expand_loc_callback. */ | |
8014 | struct expand_loc_callback_data | |
8015 | { | |
8016 | /* The variables and values active at this point. */ | |
c203e8a7 | 8017 | variable_table_type *vars; |
864ddef7 | 8018 | |
09dbcd96 AO |
8019 | /* Stack of values and debug_exprs under expansion, and their |
8020 | children. */ | |
00f96dc9 | 8021 | auto_vec<rtx, 4> expanding; |
09dbcd96 AO |
8022 | |
8023 | /* Stack of values and debug_exprs whose expansion hit recursion | |
8024 | cycles. They will have VALUE_RECURSED_INTO marked when added to | |
8025 | this list. This flag will be cleared if any of its dependencies | |
8026 | resolves to a valid location. So, if the flag remains set at the | |
8027 | end of the search, we know no valid location for this one can | |
8028 | possibly exist. */ | |
00f96dc9 | 8029 | auto_vec<rtx, 4> pending; |
09dbcd96 AO |
8030 | |
8031 | /* The maximum depth among the sub-expressions under expansion. | |
8032 | Zero indicates no expansion so far. */ | |
6a184afa | 8033 | expand_depth depth; |
864ddef7 JJ |
8034 | }; |
8035 | ||
09dbcd96 AO |
8036 | /* Allocate the one-part auxiliary data structure for VAR, with enough |
8037 | room for COUNT dependencies. */ | |
8038 | ||
8039 | static void | |
8040 | loc_exp_dep_alloc (variable var, int count) | |
8041 | { | |
8042 | size_t allocsize; | |
8043 | ||
8044 | gcc_checking_assert (var->onepart); | |
8045 | ||
8046 | /* We can be called with COUNT == 0 to allocate the data structure | |
8047 | without any dependencies, e.g. for the backlinks only. However, | |
8048 | if we are specifying a COUNT, then the dependency list must have | |
8049 | been emptied before. It would be possible to adjust pointers or | |
8050 | force it empty here, but this is better done at an earlier point | |
8051 | in the algorithm, so we instead leave an assertion to catch | |
8052 | errors. */ | |
8053 | gcc_checking_assert (!count | |
9771b263 DN |
8054 | || VAR_LOC_DEP_VEC (var) == NULL |
8055 | || VAR_LOC_DEP_VEC (var)->is_empty ()); | |
09dbcd96 | 8056 | |
9771b263 | 8057 | if (VAR_LOC_1PAUX (var) && VAR_LOC_DEP_VEC (var)->space (count)) |
09dbcd96 AO |
8058 | return; |
8059 | ||
8060 | allocsize = offsetof (struct onepart_aux, deps) | |
9771b263 | 8061 | + vec<loc_exp_dep, va_heap, vl_embed>::embedded_size (count); |
09dbcd96 AO |
8062 | |
8063 | if (VAR_LOC_1PAUX (var)) | |
8064 | { | |
8065 | VAR_LOC_1PAUX (var) = XRESIZEVAR (struct onepart_aux, | |
8066 | VAR_LOC_1PAUX (var), allocsize); | |
8067 | /* If the reallocation moves the onepaux structure, the | |
8068 | back-pointer to BACKLINKS in the first list member will still | |
8069 | point to its old location. Adjust it. */ | |
8070 | if (VAR_LOC_DEP_LST (var)) | |
8071 | VAR_LOC_DEP_LST (var)->pprev = VAR_LOC_DEP_LSTP (var); | |
8072 | } | |
8073 | else | |
8074 | { | |
8075 | VAR_LOC_1PAUX (var) = XNEWVAR (struct onepart_aux, allocsize); | |
8076 | *VAR_LOC_DEP_LSTP (var) = NULL; | |
8077 | VAR_LOC_FROM (var) = NULL; | |
6a184afa AO |
8078 | VAR_LOC_DEPTH (var).complexity = 0; |
8079 | VAR_LOC_DEPTH (var).entryvals = 0; | |
09dbcd96 | 8080 | } |
9771b263 | 8081 | VAR_LOC_DEP_VEC (var)->embedded_init (count); |
09dbcd96 AO |
8082 | } |
8083 | ||
8084 | /* Remove all entries from the vector of active dependencies of VAR, | |
8085 | removing them from the back-links lists too. */ | |
8086 | ||
8087 | static void | |
8088 | loc_exp_dep_clear (variable var) | |
8089 | { | |
9771b263 | 8090 | while (VAR_LOC_DEP_VEC (var) && !VAR_LOC_DEP_VEC (var)->is_empty ()) |
09dbcd96 | 8091 | { |
9771b263 | 8092 | loc_exp_dep *led = &VAR_LOC_DEP_VEC (var)->last (); |
09dbcd96 AO |
8093 | if (led->next) |
8094 | led->next->pprev = led->pprev; | |
8095 | if (led->pprev) | |
8096 | *led->pprev = led->next; | |
9771b263 | 8097 | VAR_LOC_DEP_VEC (var)->pop (); |
09dbcd96 AO |
8098 | } |
8099 | } | |
8100 | ||
8101 | /* Insert an active dependency from VAR on X to the vector of | |
8102 | dependencies, and add the corresponding back-link to X's list of | |
8103 | back-links in VARS. */ | |
8104 | ||
8105 | static void | |
c203e8a7 | 8106 | loc_exp_insert_dep (variable var, rtx x, variable_table_type *vars) |
09dbcd96 AO |
8107 | { |
8108 | decl_or_value dv; | |
8109 | variable xvar; | |
8110 | loc_exp_dep *led; | |
8111 | ||
8112 | dv = dv_from_rtx (x); | |
8113 | ||
8114 | /* ??? Build a vector of variables parallel to EXPANDING, to avoid | |
8115 | an additional look up? */ | |
c203e8a7 | 8116 | xvar = vars->find_with_hash (dv, dv_htab_hash (dv)); |
09dbcd96 AO |
8117 | |
8118 | if (!xvar) | |
8119 | { | |
8120 | xvar = variable_from_dropped (dv, NO_INSERT); | |
8121 | gcc_checking_assert (xvar); | |
8122 | } | |
8123 | ||
8124 | /* No point in adding the same backlink more than once. This may | |
8125 | arise if say the same value appears in two complex expressions in | |
8126 | the same loc_list, or even more than once in a single | |
8127 | expression. */ | |
8128 | if (VAR_LOC_DEP_LST (xvar) && VAR_LOC_DEP_LST (xvar)->dv == var->dv) | |
8129 | return; | |
8130 | ||
d05cae4a | 8131 | if (var->onepart == NOT_ONEPART) |
7e46899d | 8132 | led = new loc_exp_dep; |
d05cae4a AO |
8133 | else |
8134 | { | |
f32682ca DN |
8135 | loc_exp_dep empty; |
8136 | memset (&empty, 0, sizeof (empty)); | |
9771b263 DN |
8137 | VAR_LOC_DEP_VEC (var)->quick_push (empty); |
8138 | led = &VAR_LOC_DEP_VEC (var)->last (); | |
d05cae4a | 8139 | } |
09dbcd96 AO |
8140 | led->dv = var->dv; |
8141 | led->value = x; | |
8142 | ||
8143 | loc_exp_dep_alloc (xvar, 0); | |
8144 | led->pprev = VAR_LOC_DEP_LSTP (xvar); | |
8145 | led->next = *led->pprev; | |
8146 | if (led->next) | |
8147 | led->next->pprev = &led->next; | |
8148 | *led->pprev = led; | |
8149 | } | |
8150 | ||
8151 | /* Create active dependencies of VAR on COUNT values starting at | |
8152 | VALUE, and corresponding back-links to the entries in VARS. Return | |
8153 | true if we found any pending-recursion results. */ | |
8154 | ||
8155 | static bool | |
013e5ef9 | 8156 | loc_exp_dep_set (variable var, rtx result, rtx *value, int count, |
c203e8a7 | 8157 | variable_table_type *vars) |
09dbcd96 AO |
8158 | { |
8159 | bool pending_recursion = false; | |
8160 | ||
9771b263 DN |
8161 | gcc_checking_assert (VAR_LOC_DEP_VEC (var) == NULL |
8162 | || VAR_LOC_DEP_VEC (var)->is_empty ()); | |
09dbcd96 AO |
8163 | |
8164 | /* Set up all dependencies from last_child (as set up at the end of | |
8165 | the loop above) to the end. */ | |
8166 | loc_exp_dep_alloc (var, count); | |
8167 | ||
8168 | while (count--) | |
8169 | { | |
8170 | rtx x = *value++; | |
8171 | ||
8172 | if (!pending_recursion) | |
8173 | pending_recursion = !result && VALUE_RECURSED_INTO (x); | |
8174 | ||
8175 | loc_exp_insert_dep (var, x, vars); | |
8176 | } | |
8177 | ||
8178 | return pending_recursion; | |
8179 | } | |
8180 | ||
8181 | /* Notify the back-links of IVAR that are pending recursion that we | |
8182 | have found a non-NIL value for it, so they are cleared for another | |
8183 | attempt to compute a current location. */ | |
8184 | ||
8185 | static void | |
c203e8a7 | 8186 | notify_dependents_of_resolved_value (variable ivar, variable_table_type *vars) |
09dbcd96 AO |
8187 | { |
8188 | loc_exp_dep *led, *next; | |
8189 | ||
8190 | for (led = VAR_LOC_DEP_LST (ivar); led; led = next) | |
8191 | { | |
8192 | decl_or_value dv = led->dv; | |
8193 | variable var; | |
8194 | ||
8195 | next = led->next; | |
8196 | ||
8197 | if (dv_is_value_p (dv)) | |
8198 | { | |
8199 | rtx value = dv_as_value (dv); | |
8200 | ||
8201 | /* If we have already resolved it, leave it alone. */ | |
8202 | if (!VALUE_RECURSED_INTO (value)) | |
8203 | continue; | |
8204 | ||
8205 | /* Check that VALUE_RECURSED_INTO, true from the test above, | |
8206 | implies NO_LOC_P. */ | |
8207 | gcc_checking_assert (NO_LOC_P (value)); | |
8208 | ||
8209 | /* We won't notify variables that are being expanded, | |
8210 | because their dependency list is cleared before | |
8211 | recursing. */ | |
6f2ffb4b | 8212 | NO_LOC_P (value) = false; |
09dbcd96 AO |
8213 | VALUE_RECURSED_INTO (value) = false; |
8214 | ||
8215 | gcc_checking_assert (dv_changed_p (dv)); | |
8216 | } | |
d05cae4a AO |
8217 | else |
8218 | { | |
8219 | gcc_checking_assert (dv_onepart_p (dv) != NOT_ONEPART); | |
8220 | if (!dv_changed_p (dv)) | |
8221 | continue; | |
8222 | } | |
09dbcd96 | 8223 | |
c203e8a7 | 8224 | var = vars->find_with_hash (dv, dv_htab_hash (dv)); |
09dbcd96 AO |
8225 | |
8226 | if (!var) | |
8227 | var = variable_from_dropped (dv, NO_INSERT); | |
8228 | ||
8229 | if (var) | |
8230 | notify_dependents_of_resolved_value (var, vars); | |
8231 | ||
8232 | if (next) | |
8233 | next->pprev = led->pprev; | |
8234 | if (led->pprev) | |
8235 | *led->pprev = next; | |
8236 | led->next = NULL; | |
8237 | led->pprev = NULL; | |
8238 | } | |
8239 | } | |
8240 | ||
8241 | static rtx vt_expand_loc_callback (rtx x, bitmap regs, | |
8242 | int max_depth, void *data); | |
8243 | ||
8244 | /* Return the combined depth, when one sub-expression evaluated to | |
8245 | BEST_DEPTH and the previous known depth was SAVED_DEPTH. */ | |
8246 | ||
6a184afa AO |
8247 | static inline expand_depth |
8248 | update_depth (expand_depth saved_depth, expand_depth best_depth) | |
09dbcd96 AO |
8249 | { |
8250 | /* If we didn't find anything, stick with what we had. */ | |
6a184afa | 8251 | if (!best_depth.complexity) |
09dbcd96 AO |
8252 | return saved_depth; |
8253 | ||
8254 | /* If we found hadn't found anything, use the depth of the current | |
8255 | expression. Do NOT add one extra level, we want to compute the | |
8256 | maximum depth among sub-expressions. We'll increment it later, | |
8257 | if appropriate. */ | |
6a184afa | 8258 | if (!saved_depth.complexity) |
09dbcd96 AO |
8259 | return best_depth; |
8260 | ||
6a184afa AO |
8261 | /* Combine the entryval count so that regardless of which one we |
8262 | return, the entryval count is accurate. */ | |
8263 | best_depth.entryvals = saved_depth.entryvals | |
8264 | = best_depth.entryvals + saved_depth.entryvals; | |
8265 | ||
8266 | if (saved_depth.complexity < best_depth.complexity) | |
09dbcd96 AO |
8267 | return best_depth; |
8268 | else | |
8269 | return saved_depth; | |
8270 | } | |
8271 | ||
8272 | /* Expand VAR to a location RTX, updating its cur_loc. Use REGS and | |
8273 | DATA for cselib expand callback. If PENDRECP is given, indicate in | |
8274 | it whether any sub-expression couldn't be fully evaluated because | |
8275 | it is pending recursion resolution. */ | |
8276 | ||
8277 | static inline rtx | |
8278 | vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp) | |
8279 | { | |
8280 | struct expand_loc_callback_data *elcd | |
8281 | = (struct expand_loc_callback_data *) data; | |
8282 | location_chain loc, next; | |
8283 | rtx result = NULL; | |
8284 | int first_child, result_first_child, last_child; | |
8285 | bool pending_recursion; | |
8286 | rtx loc_from = NULL; | |
8287 | struct elt_loc_list *cloc = NULL; | |
6a184afa AO |
8288 | expand_depth depth = { 0, 0 }, saved_depth = elcd->depth; |
8289 | int wanted_entryvals, found_entryvals = 0; | |
09dbcd96 AO |
8290 | |
8291 | /* Clear all backlinks pointing at this, so that we're not notified | |
8292 | while we're active. */ | |
8293 | loc_exp_dep_clear (var); | |
8294 | ||
6a184afa | 8295 | retry: |
09dbcd96 AO |
8296 | if (var->onepart == ONEPART_VALUE) |
8297 | { | |
8298 | cselib_val *val = CSELIB_VAL_PTR (dv_as_value (var->dv)); | |
8299 | ||
8300 | gcc_checking_assert (cselib_preserved_value_p (val)); | |
8301 | ||
8302 | cloc = val->locs; | |
8303 | } | |
8304 | ||
8305 | first_child = result_first_child = last_child | |
9771b263 | 8306 | = elcd->expanding.length (); |
09dbcd96 | 8307 | |
6a184afa AO |
8308 | wanted_entryvals = found_entryvals; |
8309 | ||
09dbcd96 AO |
8310 | /* Attempt to expand each available location in turn. */ |
8311 | for (next = loc = var->n_var_parts ? var->var_part[0].loc_chain : NULL; | |
8312 | loc || cloc; loc = next) | |
8313 | { | |
8314 | result_first_child = last_child; | |
8315 | ||
6a184afa | 8316 | if (!loc) |
09dbcd96 AO |
8317 | { |
8318 | loc_from = cloc->loc; | |
8319 | next = loc; | |
8320 | cloc = cloc->next; | |
8321 | if (unsuitable_loc (loc_from)) | |
8322 | continue; | |
8323 | } | |
8324 | else | |
8325 | { | |
8326 | loc_from = loc->loc; | |
8327 | next = loc->next; | |
8328 | } | |
8329 | ||
8330 | gcc_checking_assert (!unsuitable_loc (loc_from)); | |
8331 | ||
6a184afa | 8332 | elcd->depth.complexity = elcd->depth.entryvals = 0; |
09dbcd96 AO |
8333 | result = cselib_expand_value_rtx_cb (loc_from, regs, EXPR_DEPTH, |
8334 | vt_expand_loc_callback, data); | |
9771b263 | 8335 | last_child = elcd->expanding.length (); |
09dbcd96 AO |
8336 | |
8337 | if (result) | |
8338 | { | |
8339 | depth = elcd->depth; | |
8340 | ||
6a184afa AO |
8341 | gcc_checking_assert (depth.complexity |
8342 | || result_first_child == last_child); | |
09dbcd96 AO |
8343 | |
8344 | if (last_child - result_first_child != 1) | |
6a184afa AO |
8345 | { |
8346 | if (!depth.complexity && GET_CODE (result) == ENTRY_VALUE) | |
8347 | depth.entryvals++; | |
8348 | depth.complexity++; | |
8349 | } | |
09dbcd96 | 8350 | |
6a184afa AO |
8351 | if (depth.complexity <= EXPR_USE_DEPTH) |
8352 | { | |
8353 | if (depth.entryvals <= wanted_entryvals) | |
8354 | break; | |
8355 | else if (!found_entryvals || depth.entryvals < found_entryvals) | |
8356 | found_entryvals = depth.entryvals; | |
8357 | } | |
09dbcd96 AO |
8358 | |
8359 | result = NULL; | |
8360 | } | |
8361 | ||
8362 | /* Set it up in case we leave the loop. */ | |
6a184afa | 8363 | depth.complexity = depth.entryvals = 0; |
09dbcd96 AO |
8364 | loc_from = NULL; |
8365 | result_first_child = first_child; | |
8366 | } | |
8367 | ||
6a184afa AO |
8368 | if (!loc_from && wanted_entryvals < found_entryvals) |
8369 | { | |
8370 | /* We found entries with ENTRY_VALUEs and skipped them. Since | |
8371 | we could not find any expansions without ENTRY_VALUEs, but we | |
8372 | found at least one with them, go back and get an entry with | |
8373 | the minimum number ENTRY_VALUE count that we found. We could | |
8374 | avoid looping, but since each sub-loc is already resolved, | |
8375 | the re-expansion should be trivial. ??? Should we record all | |
8376 | attempted locs as dependencies, so that we retry the | |
8377 | expansion should any of them change, in the hope it can give | |
8378 | us a new entry without an ENTRY_VALUE? */ | |
9771b263 | 8379 | elcd->expanding.truncate (first_child); |
6a184afa AO |
8380 | goto retry; |
8381 | } | |
8382 | ||
09dbcd96 AO |
8383 | /* Register all encountered dependencies as active. */ |
8384 | pending_recursion = loc_exp_dep_set | |
9771b263 | 8385 | (var, result, elcd->expanding.address () + result_first_child, |
09dbcd96 AO |
8386 | last_child - result_first_child, elcd->vars); |
8387 | ||
9771b263 | 8388 | elcd->expanding.truncate (first_child); |
09dbcd96 AO |
8389 | |
8390 | /* Record where the expansion came from. */ | |
8391 | gcc_checking_assert (!result || !pending_recursion); | |
8392 | VAR_LOC_FROM (var) = loc_from; | |
8393 | VAR_LOC_DEPTH (var) = depth; | |
8394 | ||
6a184afa | 8395 | gcc_checking_assert (!depth.complexity == !result); |
5a9fbcf1 | 8396 | |
09dbcd96 AO |
8397 | elcd->depth = update_depth (saved_depth, depth); |
8398 | ||
8399 | /* Indicate whether any of the dependencies are pending recursion | |
8400 | resolution. */ | |
8401 | if (pendrecp) | |
8402 | *pendrecp = pending_recursion; | |
8403 | ||
8404 | if (!pendrecp || !pending_recursion) | |
8405 | var->var_part[0].cur_loc = result; | |
8406 | ||
8407 | return result; | |
8408 | } | |
8409 | ||
b5b8b0ac | 8410 | /* Callback for cselib_expand_value, that looks for expressions |
0b7e34d7 AO |
8411 | holding the value in the var-tracking hash tables. Return X for |
8412 | standard processing, anything else is to be used as-is. */ | |
b5b8b0ac AO |
8413 | |
8414 | static rtx | |
09dbcd96 AO |
8415 | vt_expand_loc_callback (rtx x, bitmap regs, |
8416 | int max_depth ATTRIBUTE_UNUSED, | |
8417 | void *data) | |
b5b8b0ac | 8418 | { |
864ddef7 JJ |
8419 | struct expand_loc_callback_data *elcd |
8420 | = (struct expand_loc_callback_data *) data; | |
b5b8b0ac AO |
8421 | decl_or_value dv; |
8422 | variable var; | |
09dbcd96 AO |
8423 | rtx result, subreg; |
8424 | bool pending_recursion = false; | |
8425 | bool from_empty = false; | |
b5b8b0ac | 8426 | |
0ca5af51 | 8427 | switch (GET_CODE (x)) |
0b7e34d7 | 8428 | { |
0ca5af51 | 8429 | case SUBREG: |
0b7e34d7 | 8430 | subreg = cselib_expand_value_rtx_cb (SUBREG_REG (x), regs, |
09dbcd96 | 8431 | EXPR_DEPTH, |
0b7e34d7 AO |
8432 | vt_expand_loc_callback, data); |
8433 | ||
8434 | if (!subreg) | |
8435 | return NULL; | |
8436 | ||
8437 | result = simplify_gen_subreg (GET_MODE (x), subreg, | |
8438 | GET_MODE (SUBREG_REG (x)), | |
8439 | SUBREG_BYTE (x)); | |
8440 | ||
8441 | /* Invalid SUBREGs are ok in debug info. ??? We could try | |
8442 | alternate expansions for the VALUE as well. */ | |
864ddef7 | 8443 | if (!result) |
0b7e34d7 AO |
8444 | result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x)); |
8445 | ||
8446 | return result; | |
0b7e34d7 | 8447 | |
0ca5af51 | 8448 | case DEBUG_EXPR: |
0ca5af51 | 8449 | case VALUE: |
09dbcd96 | 8450 | dv = dv_from_rtx (x); |
0ca5af51 AO |
8451 | break; |
8452 | ||
8453 | default: | |
8454 | return x; | |
8455 | } | |
b5b8b0ac | 8456 | |
9771b263 | 8457 | elcd->expanding.safe_push (x); |
09dbcd96 AO |
8458 | |
8459 | /* Check that VALUE_RECURSED_INTO implies NO_LOC_P. */ | |
8460 | gcc_checking_assert (!VALUE_RECURSED_INTO (x) || NO_LOC_P (x)); | |
8461 | ||
8462 | if (NO_LOC_P (x)) | |
6f2ffb4b AO |
8463 | { |
8464 | gcc_checking_assert (VALUE_RECURSED_INTO (x) || !dv_changed_p (dv)); | |
8465 | return NULL; | |
8466 | } | |
b5b8b0ac | 8467 | |
c203e8a7 | 8468 | var = elcd->vars->find_with_hash (dv, dv_htab_hash (dv)); |
b5b8b0ac AO |
8469 | |
8470 | if (!var) | |
864ddef7 | 8471 | { |
09dbcd96 AO |
8472 | from_empty = true; |
8473 | var = variable_from_dropped (dv, INSERT); | |
864ddef7 | 8474 | } |
b5b8b0ac | 8475 | |
09dbcd96 AO |
8476 | gcc_checking_assert (var); |
8477 | ||
8478 | if (!dv_changed_p (dv)) | |
864ddef7 | 8479 | { |
09dbcd96 AO |
8480 | gcc_checking_assert (!NO_LOC_P (x)); |
8481 | gcc_checking_assert (var->var_part[0].cur_loc); | |
8482 | gcc_checking_assert (VAR_LOC_1PAUX (var)); | |
6a184afa | 8483 | gcc_checking_assert (VAR_LOC_1PAUX (var)->depth.complexity); |
b5b8b0ac | 8484 | |
09dbcd96 AO |
8485 | elcd->depth = update_depth (elcd->depth, VAR_LOC_1PAUX (var)->depth); |
8486 | ||
8487 | return var->var_part[0].cur_loc; | |
8488 | } | |
b5b8b0ac AO |
8489 | |
8490 | VALUE_RECURSED_INTO (x) = true; | |
09dbcd96 AO |
8491 | /* This is tentative, but it makes some tests simpler. */ |
8492 | NO_LOC_P (x) = true; | |
b5b8b0ac | 8493 | |
09dbcd96 AO |
8494 | gcc_checking_assert (var->n_var_parts == 1 || from_empty); |
8495 | ||
8496 | result = vt_expand_var_loc_chain (var, regs, data, &pending_recursion); | |
8497 | ||
8498 | if (pending_recursion) | |
b5b8b0ac | 8499 | { |
09dbcd96 | 8500 | gcc_checking_assert (!result); |
9771b263 | 8501 | elcd->pending.safe_push (x); |
864ddef7 | 8502 | } |
2b1c5433 | 8503 | else |
864ddef7 | 8504 | { |
09dbcd96 AO |
8505 | NO_LOC_P (x) = !result; |
8506 | VALUE_RECURSED_INTO (x) = false; | |
8507 | set_dv_changed (dv, false); | |
8508 | ||
8509 | if (result) | |
8510 | notify_dependents_of_resolved_value (var, elcd->vars); | |
ca787200 | 8511 | } |
b5b8b0ac | 8512 | |
09dbcd96 | 8513 | return result; |
ca787200 AO |
8514 | } |
8515 | ||
09dbcd96 AO |
8516 | /* While expanding variables, we may encounter recursion cycles |
8517 | because of mutual (possibly indirect) dependencies between two | |
8518 | particular variables (or values), say A and B. If we're trying to | |
8519 | expand A when we get to B, which in turn attempts to expand A, if | |
8520 | we can't find any other expansion for B, we'll add B to this | |
8521 | pending-recursion stack, and tentatively return NULL for its | |
8522 | location. This tentative value will be used for any other | |
8523 | occurrences of B, unless A gets some other location, in which case | |
8524 | it will notify B that it is worth another try at computing a | |
8525 | location for it, and it will use the location computed for A then. | |
8526 | At the end of the expansion, the tentative NULL locations become | |
8527 | final for all members of PENDING that didn't get a notification. | |
8528 | This function performs this finalization of NULL locations. */ | |
8529 | ||
8530 | static void | |
ff4c81cc | 8531 | resolve_expansions_pending_recursion (vec<rtx, va_heap> *pending) |
09dbcd96 | 8532 | { |
ff4c81cc | 8533 | while (!pending->is_empty ()) |
09dbcd96 | 8534 | { |
ff4c81cc | 8535 | rtx x = pending->pop (); |
09dbcd96 AO |
8536 | decl_or_value dv; |
8537 | ||
8538 | if (!VALUE_RECURSED_INTO (x)) | |
8539 | continue; | |
8540 | ||
8541 | gcc_checking_assert (NO_LOC_P (x)); | |
8542 | VALUE_RECURSED_INTO (x) = false; | |
8543 | dv = dv_from_rtx (x); | |
8544 | gcc_checking_assert (dv_changed_p (dv)); | |
8545 | set_dv_changed (dv, false); | |
8546 | } | |
8547 | } | |
8548 | ||
8549 | /* Initialize expand_loc_callback_data D with variable hash table V. | |
9771b263 | 8550 | It must be a macro because of alloca (vec stack). */ |
09dbcd96 AO |
8551 | #define INIT_ELCD(d, v) \ |
8552 | do \ | |
8553 | { \ | |
8554 | (d).vars = (v); \ | |
6a184afa | 8555 | (d).depth.complexity = (d).depth.entryvals = 0; \ |
09dbcd96 AO |
8556 | } \ |
8557 | while (0) | |
8558 | /* Finalize expand_loc_callback_data D, resolved to location L. */ | |
8559 | #define FINI_ELCD(d, l) \ | |
8560 | do \ | |
8561 | { \ | |
ff4c81cc | 8562 | resolve_expansions_pending_recursion (&(d).pending); \ |
9771b263 DN |
8563 | (d).pending.release (); \ |
8564 | (d).expanding.release (); \ | |
09dbcd96 AO |
8565 | \ |
8566 | if ((l) && MEM_P (l)) \ | |
8567 | (l) = targetm.delegitimize_address (l); \ | |
8568 | } \ | |
8569 | while (0) | |
8570 | ||
8571 | /* Expand VALUEs and DEBUG_EXPRs in LOC to a location, using the | |
8572 | equivalences in VARS, updating their CUR_LOCs in the process. */ | |
014a1138 | 8573 | |
b5b8b0ac | 8574 | static rtx |
c203e8a7 | 8575 | vt_expand_loc (rtx loc, variable_table_type *vars) |
014a1138 | 8576 | { |
864ddef7 | 8577 | struct expand_loc_callback_data data; |
09dbcd96 | 8578 | rtx result; |
864ddef7 | 8579 | |
b5b8b0ac AO |
8580 | if (!MAY_HAVE_DEBUG_INSNS) |
8581 | return loc; | |
81f2eadb | 8582 | |
09dbcd96 | 8583 | INIT_ELCD (data, vars); |
014a1138 | 8584 | |
09dbcd96 AO |
8585 | result = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH, |
8586 | vt_expand_loc_callback, &data); | |
8587 | ||
8588 | FINI_ELCD (data, result); | |
8589 | ||
8590 | return result; | |
014a1138 JZ |
8591 | } |
8592 | ||
09dbcd96 AO |
8593 | /* Expand the one-part VARiable to a location, using the equivalences |
8594 | in VARS, updating their CUR_LOCs in the process. */ | |
864ddef7 | 8595 | |
09dbcd96 | 8596 | static rtx |
c203e8a7 | 8597 | vt_expand_1pvar (variable var, variable_table_type *vars) |
864ddef7 JJ |
8598 | { |
8599 | struct expand_loc_callback_data data; | |
09dbcd96 AO |
8600 | rtx loc; |
8601 | ||
8602 | gcc_checking_assert (var->onepart && var->n_var_parts == 1); | |
8603 | ||
8604 | if (!dv_changed_p (var->dv)) | |
8605 | return var->var_part[0].cur_loc; | |
8606 | ||
8607 | INIT_ELCD (data, vars); | |
8608 | ||
8609 | loc = vt_expand_var_loc_chain (var, scratch_regs, &data, NULL); | |
8610 | ||
9771b263 | 8611 | gcc_checking_assert (data.expanding.is_empty ()); |
09dbcd96 AO |
8612 | |
8613 | FINI_ELCD (data, loc); | |
864ddef7 | 8614 | |
09dbcd96 | 8615 | return loc; |
864ddef7 JJ |
8616 | } |
8617 | ||
014a1138 JZ |
8618 | /* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP. DATA contains |
8619 | additional parameters: WHERE specifies whether the note shall be emitted | |
b5b8b0ac | 8620 | before or after instruction INSN. */ |
014a1138 | 8621 | |
013e5ef9 LC |
8622 | int |
8623 | emit_note_insn_var_location (variable_def **varp, emit_note_data *data) | |
014a1138 | 8624 | { |
013e5ef9 | 8625 | variable var = *varp; |
598d62da | 8626 | rtx_insn *insn = data->insn; |
013e5ef9 | 8627 | enum emit_note_where where = data->where; |
c203e8a7 | 8628 | variable_table_type *vars = data->vars; |
66e8df53 DM |
8629 | rtx_note *note; |
8630 | rtx note_vl; | |
c938250d | 8631 | int i, j, n_var_parts; |
014a1138 | 8632 | bool complete; |
62760ffd | 8633 | enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED; |
014a1138 JZ |
8634 | HOST_WIDE_INT last_limit; |
8635 | tree type_size_unit; | |
c938250d JJ |
8636 | HOST_WIDE_INT offsets[MAX_VAR_PARTS]; |
8637 | rtx loc[MAX_VAR_PARTS]; | |
b5b8b0ac | 8638 | tree decl; |
864ddef7 | 8639 | location_chain lc; |
014a1138 | 8640 | |
09dbcd96 AO |
8641 | gcc_checking_assert (var->onepart == NOT_ONEPART |
8642 | || var->onepart == ONEPART_VDECL); | |
b5b8b0ac AO |
8643 | |
8644 | decl = dv_as_decl (var->dv); | |
8645 | ||
014a1138 JZ |
8646 | complete = true; |
8647 | last_limit = 0; | |
c938250d | 8648 | n_var_parts = 0; |
09dbcd96 AO |
8649 | if (!var->onepart) |
8650 | for (i = 0; i < var->n_var_parts; i++) | |
8651 | if (var->var_part[i].cur_loc == NULL && var->var_part[i].loc_chain) | |
8652 | var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc; | |
014a1138 JZ |
8653 | for (i = 0; i < var->n_var_parts; i++) |
8654 | { | |
ef4bddc2 | 8655 | machine_mode mode, wider_mode; |
b5b8b0ac | 8656 | rtx loc2; |
09dbcd96 | 8657 | HOST_WIDE_INT offset; |
c938250d | 8658 | |
09dbcd96 | 8659 | if (i == 0 && var->onepart) |
014a1138 | 8660 | { |
09dbcd96 AO |
8661 | gcc_checking_assert (var->n_var_parts == 1); |
8662 | offset = 0; | |
8663 | initialized = VAR_INIT_STATUS_INITIALIZED; | |
8664 | loc2 = vt_expand_1pvar (var, vars); | |
014a1138 | 8665 | } |
09dbcd96 | 8666 | else |
864ddef7 | 8667 | { |
09dbcd96 AO |
8668 | if (last_limit < VAR_PART_OFFSET (var, i)) |
8669 | { | |
8670 | complete = false; | |
8671 | break; | |
8672 | } | |
8673 | else if (last_limit > VAR_PART_OFFSET (var, i)) | |
8674 | continue; | |
8675 | offset = VAR_PART_OFFSET (var, i); | |
d05cae4a AO |
8676 | loc2 = var->var_part[i].cur_loc; |
8677 | if (loc2 && GET_CODE (loc2) == MEM | |
8678 | && GET_CODE (XEXP (loc2, 0)) == VALUE) | |
8679 | { | |
8680 | rtx depval = XEXP (loc2, 0); | |
8681 | ||
8682 | loc2 = vt_expand_loc (loc2, vars); | |
8683 | ||
8684 | if (loc2) | |
8685 | loc_exp_insert_dep (var, depval, vars); | |
8686 | } | |
8687 | if (!loc2) | |
09dbcd96 AO |
8688 | { |
8689 | complete = false; | |
8690 | continue; | |
8691 | } | |
d05cae4a | 8692 | gcc_checking_assert (GET_CODE (loc2) != VALUE); |
09dbcd96 AO |
8693 | for (lc = var->var_part[i].loc_chain; lc; lc = lc->next) |
8694 | if (var->var_part[i].cur_loc == lc->loc) | |
8695 | { | |
8696 | initialized = lc->init; | |
8697 | break; | |
8698 | } | |
8699 | gcc_assert (lc); | |
864ddef7 | 8700 | } |
09dbcd96 AO |
8701 | |
8702 | offsets[n_var_parts] = offset; | |
b5b8b0ac AO |
8703 | if (!loc2) |
8704 | { | |
8705 | complete = false; | |
8706 | continue; | |
8707 | } | |
8708 | loc[n_var_parts] = loc2; | |
864ddef7 | 8709 | mode = GET_MODE (var->var_part[i].cur_loc); |
09dbcd96 | 8710 | if (mode == VOIDmode && var->onepart) |
5644a3d0 | 8711 | mode = DECL_MODE (decl); |
c938250d JJ |
8712 | last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode); |
8713 | ||
8714 | /* Attempt to merge adjacent registers or memory. */ | |
8715 | wider_mode = GET_MODE_WIDER_MODE (mode); | |
8716 | for (j = i + 1; j < var->n_var_parts; j++) | |
09dbcd96 | 8717 | if (last_limit <= VAR_PART_OFFSET (var, j)) |
c938250d JJ |
8718 | break; |
8719 | if (j < var->n_var_parts | |
8720 | && wider_mode != VOIDmode | |
864ddef7 JJ |
8721 | && var->var_part[j].cur_loc |
8722 | && mode == GET_MODE (var->var_part[j].cur_loc) | |
7cf72011 | 8723 | && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts])) |
09dbcd96 AO |
8724 | && last_limit == (var->onepart ? 0 : VAR_PART_OFFSET (var, j)) |
8725 | && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars)) | |
864ddef7 | 8726 | && GET_CODE (loc[n_var_parts]) == GET_CODE (loc2)) |
c938250d JJ |
8727 | { |
8728 | rtx new_loc = NULL; | |
c938250d JJ |
8729 | |
8730 | if (REG_P (loc[n_var_parts]) | |
8731 | && hard_regno_nregs[REGNO (loc[n_var_parts])][mode] * 2 | |
8732 | == hard_regno_nregs[REGNO (loc[n_var_parts])][wider_mode] | |
09e18274 | 8733 | && end_hard_regno (mode, REGNO (loc[n_var_parts])) |
c938250d JJ |
8734 | == REGNO (loc2)) |
8735 | { | |
8736 | if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN) | |
8737 | new_loc = simplify_subreg (wider_mode, loc[n_var_parts], | |
8738 | mode, 0); | |
8739 | else if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN) | |
8740 | new_loc = simplify_subreg (wider_mode, loc2, mode, 0); | |
8741 | if (new_loc) | |
8742 | { | |
8743 | if (!REG_P (new_loc) | |
8744 | || REGNO (new_loc) != REGNO (loc[n_var_parts])) | |
8745 | new_loc = NULL; | |
8746 | else | |
8747 | REG_ATTRS (new_loc) = REG_ATTRS (loc[n_var_parts]); | |
8748 | } | |
8749 | } | |
8750 | else if (MEM_P (loc[n_var_parts]) | |
8751 | && GET_CODE (XEXP (loc2, 0)) == PLUS | |
481683e1 SZ |
8752 | && REG_P (XEXP (XEXP (loc2, 0), 0)) |
8753 | && CONST_INT_P (XEXP (XEXP (loc2, 0), 1))) | |
c938250d | 8754 | { |
481683e1 | 8755 | if ((REG_P (XEXP (loc[n_var_parts], 0)) |
c938250d JJ |
8756 | && rtx_equal_p (XEXP (loc[n_var_parts], 0), |
8757 | XEXP (XEXP (loc2, 0), 0)) | |
8758 | && INTVAL (XEXP (XEXP (loc2, 0), 1)) | |
8759 | == GET_MODE_SIZE (mode)) | |
8760 | || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS | |
481683e1 | 8761 | && CONST_INT_P (XEXP (XEXP (loc[n_var_parts], 0), 1)) |
c938250d JJ |
8762 | && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0), |
8763 | XEXP (XEXP (loc2, 0), 0)) | |
8764 | && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1)) | |
8765 | + GET_MODE_SIZE (mode) | |
8766 | == INTVAL (XEXP (XEXP (loc2, 0), 1)))) | |
8767 | new_loc = adjust_address_nv (loc[n_var_parts], | |
8768 | wider_mode, 0); | |
8769 | } | |
8770 | ||
8771 | if (new_loc) | |
8772 | { | |
8773 | loc[n_var_parts] = new_loc; | |
8774 | mode = wider_mode; | |
8775 | last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode); | |
8776 | i = j; | |
8777 | } | |
8778 | } | |
8779 | ++n_var_parts; | |
014a1138 | 8780 | } |
b5b8b0ac | 8781 | type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (decl)); |
014a1138 JZ |
8782 | if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit)) |
8783 | complete = false; | |
8784 | ||
62760ffd CT |
8785 | if (! flag_var_tracking_uninit) |
8786 | initialized = VAR_INIT_STATUS_INITIALIZED; | |
8787 | ||
864ddef7 | 8788 | note_vl = NULL_RTX; |
014a1138 | 8789 | if (!complete) |
fcc74520 | 8790 | note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, NULL_RTX, initialized); |
c938250d | 8791 | else if (n_var_parts == 1) |
014a1138 | 8792 | { |
e80691a0 JJ |
8793 | rtx expr_list; |
8794 | ||
8795 | if (offsets[0] || GET_CODE (loc[0]) == PARALLEL) | |
8796 | expr_list = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0])); | |
8797 | else | |
8798 | expr_list = loc[0]; | |
014a1138 | 8799 | |
fcc74520 | 8800 | note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list, initialized); |
014a1138 | 8801 | } |
c938250d | 8802 | else if (n_var_parts) |
014a1138 | 8803 | { |
014a1138 JZ |
8804 | rtx parallel; |
8805 | ||
c938250d JJ |
8806 | for (i = 0; i < n_var_parts; i++) |
8807 | loc[i] | |
8808 | = gen_rtx_EXPR_LIST (VOIDmode, loc[i], GEN_INT (offsets[i])); | |
8809 | ||
014a1138 | 8810 | parallel = gen_rtx_PARALLEL (VOIDmode, |
c938250d | 8811 | gen_rtvec_v (n_var_parts, loc)); |
864ddef7 | 8812 | note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, |
fcc74520 | 8813 | parallel, initialized); |
014a1138 JZ |
8814 | } |
8815 | ||
864ddef7 JJ |
8816 | if (where != EMIT_NOTE_BEFORE_INSN) |
8817 | { | |
c3583c4a | 8818 | note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn); |
864ddef7 JJ |
8819 | if (where == EMIT_NOTE_AFTER_CALL_INSN) |
8820 | NOTE_DURING_CALL_P (note) = true; | |
8821 | } | |
8822 | else | |
8784e5ac AK |
8823 | { |
8824 | /* Make sure that the call related notes come first. */ | |
8825 | while (NEXT_INSN (insn) | |
8826 | && NOTE_P (insn) | |
65cca5de JJ |
8827 | && ((NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION |
8828 | && NOTE_DURING_CALL_P (insn)) | |
8829 | || NOTE_KIND (insn) == NOTE_INSN_CALL_ARG_LOCATION)) | |
8784e5ac | 8830 | insn = NEXT_INSN (insn); |
65cca5de JJ |
8831 | if (NOTE_P (insn) |
8832 | && ((NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION | |
8833 | && NOTE_DURING_CALL_P (insn)) | |
8834 | || NOTE_KIND (insn) == NOTE_INSN_CALL_ARG_LOCATION)) | |
8784e5ac AK |
8835 | note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn); |
8836 | else | |
c3583c4a | 8837 | note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn); |
8784e5ac | 8838 | } |
864ddef7 JJ |
8839 | NOTE_VAR_LOCATION (note) = note_vl; |
8840 | ||
b5b8b0ac | 8841 | set_dv_changed (var->dv, false); |
864ddef7 JJ |
8842 | gcc_assert (var->in_changed_variables); |
8843 | var->in_changed_variables = false; | |
c203e8a7 | 8844 | changed_variables->clear_slot (varp); |
014a1138 | 8845 | |
014a1138 JZ |
8846 | /* Continue traversing the hash table. */ |
8847 | return 1; | |
8848 | } | |
8849 | ||
09dbcd96 AO |
8850 | /* While traversing changed_variables, push onto DATA (a stack of RTX |
8851 | values) entries that aren't user variables. */ | |
b5b8b0ac | 8852 | |
013e5ef9 LC |
8853 | int |
8854 | var_track_values_to_stack (variable_def **slot, | |
ff4c81cc | 8855 | vec<rtx, va_heap> *changed_values_stack) |
09dbcd96 | 8856 | { |
013e5ef9 | 8857 | variable var = *slot; |
1feb8238 | 8858 | |
09dbcd96 | 8859 | if (var->onepart == ONEPART_VALUE) |
9771b263 | 8860 | changed_values_stack->safe_push (dv_as_value (var->dv)); |
09dbcd96 | 8861 | else if (var->onepart == ONEPART_DEXPR) |
9771b263 | 8862 | changed_values_stack->safe_push (DECL_RTL_KNOWN_SET (dv_as_decl (var->dv))); |
1feb8238 | 8863 | |
09dbcd96 AO |
8864 | return 1; |
8865 | } | |
1feb8238 | 8866 | |
09dbcd96 AO |
8867 | /* Remove from changed_variables the entry whose DV corresponds to |
8868 | value or debug_expr VAL. */ | |
1feb8238 | 8869 | static void |
09dbcd96 | 8870 | remove_value_from_changed_variables (rtx val) |
1feb8238 | 8871 | { |
09dbcd96 | 8872 | decl_or_value dv = dv_from_rtx (val); |
013e5ef9 | 8873 | variable_def **slot; |
09dbcd96 | 8874 | variable var; |
1feb8238 | 8875 | |
c203e8a7 | 8876 | slot = changed_variables->find_slot_with_hash (dv, dv_htab_hash (dv), |
013e5ef9 LC |
8877 | NO_INSERT); |
8878 | var = *slot; | |
09dbcd96 | 8879 | var->in_changed_variables = false; |
c203e8a7 | 8880 | changed_variables->clear_slot (slot); |
1feb8238 JJ |
8881 | } |
8882 | ||
09dbcd96 AO |
8883 | /* If VAL (a value or debug_expr) has backlinks to variables actively |
8884 | dependent on it in HTAB or in CHANGED_VARIABLES, mark them as | |
8885 | changed, adding to CHANGED_VALUES_STACK any dependencies that may | |
8886 | have dependencies of their own to notify. */ | |
b5b8b0ac | 8887 | |
09dbcd96 | 8888 | static void |
c203e8a7 | 8889 | notify_dependents_of_changed_value (rtx val, variable_table_type *htab, |
ff4c81cc | 8890 | vec<rtx, va_heap> *changed_values_stack) |
b5b8b0ac | 8891 | { |
013e5ef9 | 8892 | variable_def **slot; |
09dbcd96 AO |
8893 | variable var; |
8894 | loc_exp_dep *led; | |
8895 | decl_or_value dv = dv_from_rtx (val); | |
b5b8b0ac | 8896 | |
c203e8a7 | 8897 | slot = changed_variables->find_slot_with_hash (dv, dv_htab_hash (dv), |
013e5ef9 | 8898 | NO_INSERT); |
09dbcd96 | 8899 | if (!slot) |
c203e8a7 | 8900 | slot = htab->find_slot_with_hash (dv, dv_htab_hash (dv), NO_INSERT); |
09dbcd96 | 8901 | if (!slot) |
c203e8a7 TS |
8902 | slot = dropped_values->find_slot_with_hash (dv, dv_htab_hash (dv), |
8903 | NO_INSERT); | |
013e5ef9 | 8904 | var = *slot; |
09dbcd96 AO |
8905 | |
8906 | while ((led = VAR_LOC_DEP_LST (var))) | |
8907 | { | |
8908 | decl_or_value ldv = led->dv; | |
09dbcd96 | 8909 | variable ivar; |
b5b8b0ac | 8910 | |
09dbcd96 AO |
8911 | /* Deactivate and remove the backlink, as it was “used up”. It |
8912 | makes no sense to attempt to notify the same entity again: | |
8913 | either it will be recomputed and re-register an active | |
8914 | dependency, or it will still have the changed mark. */ | |
8915 | if (led->next) | |
8916 | led->next->pprev = led->pprev; | |
8917 | if (led->pprev) | |
8918 | *led->pprev = led->next; | |
8919 | led->next = NULL; | |
8920 | led->pprev = NULL; | |
b5b8b0ac | 8921 | |
09dbcd96 AO |
8922 | if (dv_changed_p (ldv)) |
8923 | continue; | |
8924 | ||
8925 | switch (dv_onepart_p (ldv)) | |
8926 | { | |
8927 | case ONEPART_VALUE: | |
8928 | case ONEPART_DEXPR: | |
8929 | set_dv_changed (ldv, true); | |
9771b263 | 8930 | changed_values_stack->safe_push (dv_as_rtx (ldv)); |
09dbcd96 AO |
8931 | break; |
8932 | ||
d05cae4a | 8933 | case ONEPART_VDECL: |
c203e8a7 | 8934 | ivar = htab->find_with_hash (ldv, dv_htab_hash (ldv)); |
09dbcd96 AO |
8935 | gcc_checking_assert (!VAR_LOC_DEP_LST (ivar)); |
8936 | variable_was_changed (ivar, NULL); | |
8937 | break; | |
d05cae4a AO |
8938 | |
8939 | case NOT_ONEPART: | |
7e46899d | 8940 | delete led; |
c203e8a7 | 8941 | ivar = htab->find_with_hash (ldv, dv_htab_hash (ldv)); |
d05cae4a AO |
8942 | if (ivar) |
8943 | { | |
8944 | int i = ivar->n_var_parts; | |
8945 | while (i--) | |
8946 | { | |
8947 | rtx loc = ivar->var_part[i].cur_loc; | |
8948 | ||
8949 | if (loc && GET_CODE (loc) == MEM | |
8950 | && XEXP (loc, 0) == val) | |
8951 | { | |
8952 | variable_was_changed (ivar, NULL); | |
8953 | break; | |
8954 | } | |
8955 | } | |
8956 | } | |
8957 | break; | |
8958 | ||
8959 | default: | |
8960 | gcc_unreachable (); | |
09dbcd96 AO |
8961 | } |
8962 | } | |
b5b8b0ac AO |
8963 | } |
8964 | ||
09dbcd96 AO |
8965 | /* Take out of changed_variables any entries that don't refer to use |
8966 | variables. Back-propagate change notifications from values and | |
8967 | debug_exprs to their active dependencies in HTAB or in | |
8968 | CHANGED_VARIABLES. */ | |
864ddef7 | 8969 | |
09dbcd96 | 8970 | static void |
c203e8a7 | 8971 | process_changed_values (variable_table_type *htab) |
864ddef7 | 8972 | { |
09dbcd96 AO |
8973 | int i, n; |
8974 | rtx val; | |
00f96dc9 | 8975 | auto_vec<rtx, 20> changed_values_stack; |
864ddef7 | 8976 | |
09dbcd96 | 8977 | /* Move values from changed_variables to changed_values_stack. */ |
013e5ef9 | 8978 | changed_variables |
c203e8a7 | 8979 | ->traverse <vec<rtx, va_heap>*, var_track_values_to_stack> |
013e5ef9 | 8980 | (&changed_values_stack); |
864ddef7 | 8981 | |
09dbcd96 AO |
8982 | /* Back-propagate change notifications in values while popping |
8983 | them from the stack. */ | |
9771b263 DN |
8984 | for (n = i = changed_values_stack.length (); |
8985 | i > 0; i = changed_values_stack.length ()) | |
864ddef7 | 8986 | { |
9771b263 | 8987 | val = changed_values_stack.pop (); |
09dbcd96 AO |
8988 | notify_dependents_of_changed_value (val, htab, &changed_values_stack); |
8989 | ||
8990 | /* This condition will hold when visiting each of the entries | |
8991 | originally in changed_variables. We can't remove them | |
8992 | earlier because this could drop the backlinks before we got a | |
8993 | chance to use them. */ | |
8994 | if (i == n) | |
864ddef7 | 8995 | { |
09dbcd96 AO |
8996 | remove_value_from_changed_variables (val); |
8997 | n--; | |
864ddef7 | 8998 | } |
864ddef7 | 8999 | } |
864ddef7 JJ |
9000 | } |
9001 | ||
014a1138 | 9002 | /* Emit NOTE_INSN_VAR_LOCATION note for each variable from a chain |
09dbcd96 AO |
9003 | CHANGED_VARIABLES and delete this chain. WHERE specifies whether |
9004 | the notes shall be emitted before of after instruction INSN. */ | |
014a1138 JZ |
9005 | |
9006 | static void | |
598d62da | 9007 | emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where, |
b5b8b0ac | 9008 | shared_hash vars) |
014a1138 JZ |
9009 | { |
9010 | emit_note_data data; | |
c203e8a7 | 9011 | variable_table_type *htab = shared_hash_htab (vars); |
b5b8b0ac | 9012 | |
c203e8a7 | 9013 | if (!changed_variables->elements ()) |
b5b8b0ac AO |
9014 | return; |
9015 | ||
9016 | if (MAY_HAVE_DEBUG_INSNS) | |
09dbcd96 | 9017 | process_changed_values (htab); |
014a1138 JZ |
9018 | |
9019 | data.insn = insn; | |
9020 | data.where = where; | |
b5b8b0ac AO |
9021 | data.vars = htab; |
9022 | ||
013e5ef9 | 9023 | changed_variables |
c203e8a7 | 9024 | ->traverse <emit_note_data*, emit_note_insn_var_location> (&data); |
014a1138 JZ |
9025 | } |
9026 | ||
9027 | /* Add variable *SLOT to the chain CHANGED_VARIABLES if it differs from the | |
9028 | same variable in hash table DATA or is not there at all. */ | |
9029 | ||
013e5ef9 | 9030 | int |
c203e8a7 | 9031 | emit_notes_for_differences_1 (variable_def **slot, variable_table_type *new_vars) |
014a1138 | 9032 | { |
014a1138 JZ |
9033 | variable old_var, new_var; |
9034 | ||
013e5ef9 | 9035 | old_var = *slot; |
c203e8a7 | 9036 | new_var = new_vars->find_with_hash (old_var->dv, dv_htab_hash (old_var->dv)); |
014a1138 JZ |
9037 | |
9038 | if (!new_var) | |
9039 | { | |
9040 | /* Variable has disappeared. */ | |
09dbcd96 | 9041 | variable empty_var = NULL; |
b5b8b0ac | 9042 | |
09dbcd96 AO |
9043 | if (old_var->onepart == ONEPART_VALUE |
9044 | || old_var->onepart == ONEPART_DEXPR) | |
b5b8b0ac | 9045 | { |
09dbcd96 AO |
9046 | empty_var = variable_from_dropped (old_var->dv, NO_INSERT); |
9047 | if (empty_var) | |
b5b8b0ac | 9048 | { |
09dbcd96 AO |
9049 | gcc_checking_assert (!empty_var->in_changed_variables); |
9050 | if (!VAR_LOC_1PAUX (old_var)) | |
9051 | { | |
9052 | VAR_LOC_1PAUX (old_var) = VAR_LOC_1PAUX (empty_var); | |
9053 | VAR_LOC_1PAUX (empty_var) = NULL; | |
9054 | } | |
9055 | else | |
9056 | gcc_checking_assert (!VAR_LOC_1PAUX (empty_var)); | |
b5b8b0ac | 9057 | } |
b5b8b0ac | 9058 | } |
09dbcd96 AO |
9059 | |
9060 | if (!empty_var) | |
864ddef7 | 9061 | { |
7e46899d | 9062 | empty_var = onepart_pool (old_var->onepart).allocate (); |
09dbcd96 AO |
9063 | empty_var->dv = old_var->dv; |
9064 | empty_var->refcount = 0; | |
9065 | empty_var->n_var_parts = 0; | |
9066 | empty_var->onepart = old_var->onepart; | |
9067 | empty_var->in_changed_variables = false; | |
9068 | } | |
864ddef7 | 9069 | |
09dbcd96 AO |
9070 | if (empty_var->onepart) |
9071 | { | |
9072 | /* Propagate the auxiliary data to (ultimately) | |
9073 | changed_variables. */ | |
9074 | empty_var->var_part[0].loc_chain = NULL; | |
9075 | empty_var->var_part[0].cur_loc = NULL; | |
9076 | VAR_LOC_1PAUX (empty_var) = VAR_LOC_1PAUX (old_var); | |
9077 | VAR_LOC_1PAUX (old_var) = NULL; | |
864ddef7 | 9078 | } |
09dbcd96 AO |
9079 | variable_was_changed (empty_var, NULL); |
9080 | /* Continue traversing the hash table. */ | |
9081 | return 1; | |
9082 | } | |
9083 | /* Update cur_loc and one-part auxiliary data, before new_var goes | |
9084 | through variable_was_changed. */ | |
9085 | if (old_var != new_var && new_var->onepart) | |
9086 | { | |
9087 | gcc_checking_assert (VAR_LOC_1PAUX (new_var) == NULL); | |
9088 | VAR_LOC_1PAUX (new_var) = VAR_LOC_1PAUX (old_var); | |
9089 | VAR_LOC_1PAUX (old_var) = NULL; | |
9090 | new_var->var_part[0].cur_loc = old_var->var_part[0].cur_loc; | |
864ddef7 | 9091 | } |
09dbcd96 AO |
9092 | if (variable_different_p (old_var, new_var)) |
9093 | variable_was_changed (new_var, NULL); | |
014a1138 JZ |
9094 | |
9095 | /* Continue traversing the hash table. */ | |
9096 | return 1; | |
9097 | } | |
9098 | ||
9099 | /* Add variable *SLOT to the chain CHANGED_VARIABLES if it is not in hash | |
9100 | table DATA. */ | |
9101 | ||
013e5ef9 | 9102 | int |
c203e8a7 | 9103 | emit_notes_for_differences_2 (variable_def **slot, variable_table_type *old_vars) |
014a1138 | 9104 | { |
014a1138 JZ |
9105 | variable old_var, new_var; |
9106 | ||
013e5ef9 | 9107 | new_var = *slot; |
c203e8a7 | 9108 | old_var = old_vars->find_with_hash (new_var->dv, dv_htab_hash (new_var->dv)); |
014a1138 JZ |
9109 | if (!old_var) |
9110 | { | |
864ddef7 | 9111 | int i; |
864ddef7 JJ |
9112 | for (i = 0; i < new_var->n_var_parts; i++) |
9113 | new_var->var_part[i].cur_loc = NULL; | |
014a1138 JZ |
9114 | variable_was_changed (new_var, NULL); |
9115 | } | |
9116 | ||
9117 | /* Continue traversing the hash table. */ | |
9118 | return 1; | |
9119 | } | |
9120 | ||
9121 | /* Emit notes before INSN for differences between dataflow sets OLD_SET and | |
9122 | NEW_SET. */ | |
9123 | ||
9124 | static void | |
598d62da | 9125 | emit_notes_for_differences (rtx_insn *insn, dataflow_set *old_set, |
014a1138 JZ |
9126 | dataflow_set *new_set) |
9127 | { | |
013e5ef9 | 9128 | shared_hash_htab (old_set->vars) |
c203e8a7 | 9129 | ->traverse <variable_table_type *, emit_notes_for_differences_1> |
013e5ef9 LC |
9130 | (shared_hash_htab (new_set->vars)); |
9131 | shared_hash_htab (new_set->vars) | |
c203e8a7 | 9132 | ->traverse <variable_table_type *, emit_notes_for_differences_2> |
013e5ef9 | 9133 | (shared_hash_htab (old_set->vars)); |
b5b8b0ac | 9134 | emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, new_set->vars); |
014a1138 JZ |
9135 | } |
9136 | ||
12c5ffe5 EB |
9137 | /* Return the next insn after INSN that is not a NOTE_INSN_VAR_LOCATION. */ |
9138 | ||
598d62da DM |
9139 | static rtx_insn * |
9140 | next_non_note_insn_var_location (rtx_insn *insn) | |
12c5ffe5 EB |
9141 | { |
9142 | while (insn) | |
9143 | { | |
9144 | insn = NEXT_INSN (insn); | |
c3583c4a JJ |
9145 | if (insn == 0 |
9146 | || !NOTE_P (insn) | |
9147 | || NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION) | |
12c5ffe5 EB |
9148 | break; |
9149 | } | |
9150 | ||
9151 | return insn; | |
9152 | } | |
9153 | ||
014a1138 JZ |
9154 | /* Emit the notes for changes of location parts in the basic block BB. */ |
9155 | ||
9156 | static void | |
b5b8b0ac | 9157 | emit_notes_in_bb (basic_block bb, dataflow_set *set) |
014a1138 | 9158 | { |
0de3e43f JJ |
9159 | unsigned int i; |
9160 | micro_operation *mo; | |
014a1138 | 9161 | |
b5b8b0ac AO |
9162 | dataflow_set_clear (set); |
9163 | dataflow_set_copy (set, &VTI (bb)->in); | |
014a1138 | 9164 | |
9771b263 | 9165 | FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo) |
014a1138 | 9166 | { |
598d62da DM |
9167 | rtx_insn *insn = mo->insn; |
9168 | rtx_insn *next_insn = next_non_note_insn_var_location (insn); | |
014a1138 | 9169 | |
0de3e43f | 9170 | switch (mo->type) |
014a1138 JZ |
9171 | { |
9172 | case MO_CALL: | |
0f9f9784 | 9173 | dataflow_set_clear_at_call (set); |
b5b8b0ac | 9174 | emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars); |
2b1c5433 | 9175 | { |
66e8df53 DM |
9176 | rtx arguments = mo->u.loc, *p = &arguments; |
9177 | rtx_note *note; | |
2b1c5433 JJ |
9178 | while (*p) |
9179 | { | |
9180 | XEXP (XEXP (*p, 0), 1) | |
9181 | = vt_expand_loc (XEXP (XEXP (*p, 0), 1), | |
09dbcd96 | 9182 | shared_hash_htab (set->vars)); |
2b1c5433 JJ |
9183 | /* If expansion is successful, keep it in the list. */ |
9184 | if (XEXP (XEXP (*p, 0), 1)) | |
9185 | p = &XEXP (*p, 1); | |
9186 | /* Otherwise, if the following item is data_value for it, | |
9187 | drop it too too. */ | |
9188 | else if (XEXP (*p, 1) | |
9189 | && REG_P (XEXP (XEXP (*p, 0), 0)) | |
9190 | && MEM_P (XEXP (XEXP (XEXP (*p, 1), 0), 0)) | |
9191 | && REG_P (XEXP (XEXP (XEXP (XEXP (*p, 1), 0), 0), | |
9192 | 0)) | |
9193 | && REGNO (XEXP (XEXP (*p, 0), 0)) | |
9194 | == REGNO (XEXP (XEXP (XEXP (XEXP (*p, 1), 0), | |
9195 | 0), 0))) | |
9196 | *p = XEXP (XEXP (*p, 1), 1); | |
9197 | /* Just drop this item. */ | |
9198 | else | |
9199 | *p = XEXP (*p, 1); | |
9200 | } | |
c3583c4a | 9201 | note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn); |
2b1c5433 JJ |
9202 | NOTE_VAR_LOCATION (note) = arguments; |
9203 | } | |
b5b8b0ac AO |
9204 | break; |
9205 | ||
9206 | case MO_USE: | |
014a1138 | 9207 | { |
0de3e43f | 9208 | rtx loc = mo->u.loc; |
014a1138 | 9209 | |
b5b8b0ac AO |
9210 | if (REG_P (loc)) |
9211 | var_reg_set (set, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL); | |
9212 | else | |
9213 | var_mem_set (set, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL); | |
9214 | ||
f7e088e7 | 9215 | emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, set->vars); |
014a1138 JZ |
9216 | } |
9217 | break; | |
9218 | ||
b5b8b0ac | 9219 | case MO_VAL_LOC: |
dedc1e6d | 9220 | { |
0de3e43f | 9221 | rtx loc = mo->u.loc; |
b5b8b0ac AO |
9222 | rtx val, vloc; |
9223 | tree var; | |
7eb3f1f7 | 9224 | |
b5b8b0ac AO |
9225 | if (GET_CODE (loc) == CONCAT) |
9226 | { | |
9227 | val = XEXP (loc, 0); | |
9228 | vloc = XEXP (loc, 1); | |
9229 | } | |
dedc1e6d | 9230 | else |
b5b8b0ac AO |
9231 | { |
9232 | val = NULL_RTX; | |
9233 | vloc = loc; | |
9234 | } | |
9235 | ||
9236 | var = PAT_VAR_LOCATION_DECL (vloc); | |
9237 | ||
9238 | clobber_variable_part (set, NULL_RTX, | |
9239 | dv_from_decl (var), 0, NULL_RTX); | |
9240 | if (val) | |
9241 | { | |
9242 | if (VAL_NEEDS_RESOLUTION (loc)) | |
9243 | val_resolve (set, val, PAT_VAR_LOCATION_LOC (vloc), insn); | |
9244 | set_variable_part (set, val, dv_from_decl (var), 0, | |
9245 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, | |
9246 | INSERT); | |
9247 | } | |
5644a3d0 JJ |
9248 | else if (!VAR_LOC_UNKNOWN_P (PAT_VAR_LOCATION_LOC (vloc))) |
9249 | set_variable_part (set, PAT_VAR_LOCATION_LOC (vloc), | |
9250 | dv_from_decl (var), 0, | |
9251 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX, | |
9252 | INSERT); | |
b5b8b0ac AO |
9253 | |
9254 | emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN, set->vars); | |
9255 | } | |
9256 | break; | |
9257 | ||
9258 | case MO_VAL_USE: | |
9259 | { | |
0de3e43f | 9260 | rtx loc = mo->u.loc; |
b5b8b0ac AO |
9261 | rtx val, vloc, uloc; |
9262 | ||
9263 | vloc = uloc = XEXP (loc, 1); | |
9264 | val = XEXP (loc, 0); | |
9265 | ||
9266 | if (GET_CODE (val) == CONCAT) | |
9267 | { | |
9268 | uloc = XEXP (val, 1); | |
9269 | val = XEXP (val, 0); | |
9270 | } | |
9271 | ||
9272 | if (VAL_NEEDS_RESOLUTION (loc)) | |
9273 | val_resolve (set, val, vloc, insn); | |
fb4cbb9f AO |
9274 | else |
9275 | val_store (set, val, uloc, insn, false); | |
b5b8b0ac AO |
9276 | |
9277 | if (VAL_HOLDS_TRACK_EXPR (loc)) | |
9278 | { | |
9279 | if (GET_CODE (uloc) == REG) | |
9280 | var_reg_set (set, uloc, VAR_INIT_STATUS_UNINITIALIZED, | |
9281 | NULL); | |
9282 | else if (GET_CODE (uloc) == MEM) | |
9283 | var_mem_set (set, uloc, VAR_INIT_STATUS_UNINITIALIZED, | |
9284 | NULL); | |
9285 | } | |
9286 | ||
9287 | emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, set->vars); | |
9288 | } | |
9289 | break; | |
9290 | ||
9291 | case MO_VAL_SET: | |
9292 | { | |
0de3e43f | 9293 | rtx loc = mo->u.loc; |
6f2ffb4b | 9294 | rtx val, vloc, uloc; |
d05cae4a | 9295 | rtx dstv, srcv; |
dedc1e6d | 9296 | |
0c5863c2 | 9297 | vloc = loc; |
0c5863c2 JJ |
9298 | uloc = XEXP (vloc, 1); |
9299 | val = XEXP (vloc, 0); | |
9300 | vloc = uloc; | |
b5b8b0ac | 9301 | |
d05cae4a AO |
9302 | if (GET_CODE (uloc) == SET) |
9303 | { | |
9304 | dstv = SET_DEST (uloc); | |
9305 | srcv = SET_SRC (uloc); | |
9306 | } | |
9307 | else | |
9308 | { | |
9309 | dstv = uloc; | |
9310 | srcv = NULL; | |
9311 | } | |
9312 | ||
b5b8b0ac AO |
9313 | if (GET_CODE (val) == CONCAT) |
9314 | { | |
d05cae4a | 9315 | dstv = vloc = XEXP (val, 1); |
b5b8b0ac AO |
9316 | val = XEXP (val, 0); |
9317 | } | |
9318 | ||
9319 | if (GET_CODE (vloc) == SET) | |
9320 | { | |
d05cae4a | 9321 | srcv = SET_SRC (vloc); |
b5b8b0ac | 9322 | |
d05cae4a | 9323 | gcc_assert (val != srcv); |
b5b8b0ac AO |
9324 | gcc_assert (vloc == uloc || VAL_NEEDS_RESOLUTION (loc)); |
9325 | ||
d05cae4a | 9326 | dstv = vloc = SET_DEST (vloc); |
b5b8b0ac AO |
9327 | |
9328 | if (VAL_NEEDS_RESOLUTION (loc)) | |
d05cae4a | 9329 | val_resolve (set, val, srcv, insn); |
b5b8b0ac AO |
9330 | } |
9331 | else if (VAL_NEEDS_RESOLUTION (loc)) | |
9332 | { | |
9333 | gcc_assert (GET_CODE (uloc) == SET | |
9334 | && GET_CODE (SET_SRC (uloc)) == REG); | |
9335 | val_resolve (set, val, SET_SRC (uloc), insn); | |
9336 | } | |
9337 | ||
9338 | if (VAL_HOLDS_TRACK_EXPR (loc)) | |
9339 | { | |
9340 | if (VAL_EXPR_IS_CLOBBERED (loc)) | |
9341 | { | |
9342 | if (REG_P (uloc)) | |
9343 | var_reg_delete (set, uloc, true); | |
9344 | else if (MEM_P (uloc)) | |
d05cae4a AO |
9345 | { |
9346 | gcc_assert (MEM_P (dstv)); | |
9347 | gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (uloc)); | |
9348 | var_mem_delete (set, dstv, true); | |
9349 | } | |
b5b8b0ac AO |
9350 | } |
9351 | else | |
9352 | { | |
9353 | bool copied_p = VAL_EXPR_IS_COPIED (loc); | |
d05cae4a | 9354 | rtx src = NULL, dst = uloc; |
b5b8b0ac AO |
9355 | enum var_init_status status = VAR_INIT_STATUS_INITIALIZED; |
9356 | ||
9357 | if (GET_CODE (uloc) == SET) | |
9358 | { | |
d05cae4a AO |
9359 | src = SET_SRC (uloc); |
9360 | dst = SET_DEST (uloc); | |
b5b8b0ac AO |
9361 | } |
9362 | ||
9363 | if (copied_p) | |
9364 | { | |
d05cae4a | 9365 | status = find_src_status (set, src); |
b5b8b0ac | 9366 | |
d05cae4a | 9367 | src = find_src_set_src (set, src); |
b5b8b0ac AO |
9368 | } |
9369 | ||
d05cae4a AO |
9370 | if (REG_P (dst)) |
9371 | var_reg_delete_and_set (set, dst, !copied_p, | |
9372 | status, srcv); | |
9373 | else if (MEM_P (dst)) | |
9374 | { | |
9375 | gcc_assert (MEM_P (dstv)); | |
9376 | gcc_assert (MEM_ATTRS (dstv) == MEM_ATTRS (dst)); | |
9377 | var_mem_delete_and_set (set, dstv, !copied_p, | |
9378 | status, srcv); | |
9379 | } | |
b5b8b0ac AO |
9380 | } |
9381 | } | |
9382 | else if (REG_P (uloc)) | |
9383 | var_regno_delete (set, REGNO (uloc)); | |
8cda8ad3 | 9384 | else if (MEM_P (uloc)) |
af6236c1 AO |
9385 | { |
9386 | gcc_checking_assert (GET_CODE (vloc) == MEM); | |
9387 | gcc_checking_assert (vloc == dstv); | |
9388 | if (vloc != dstv) | |
9389 | clobber_overlapping_mems (set, vloc); | |
9390 | } | |
b5b8b0ac | 9391 | |
d05cae4a | 9392 | val_store (set, val, dstv, insn, true); |
b5b8b0ac | 9393 | |
12c5ffe5 | 9394 | emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN, |
b5b8b0ac | 9395 | set->vars); |
dedc1e6d AO |
9396 | } |
9397 | break; | |
9398 | ||
014a1138 JZ |
9399 | case MO_SET: |
9400 | { | |
0de3e43f | 9401 | rtx loc = mo->u.loc; |
94a7682d | 9402 | rtx set_src = NULL; |
62760ffd | 9403 | |
94a7682d | 9404 | if (GET_CODE (loc) == SET) |
62760ffd | 9405 | { |
94a7682d RS |
9406 | set_src = SET_SRC (loc); |
9407 | loc = SET_DEST (loc); | |
62760ffd | 9408 | } |
014a1138 | 9409 | |
f8cfc6aa | 9410 | if (REG_P (loc)) |
b5b8b0ac | 9411 | var_reg_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED, |
62760ffd | 9412 | set_src); |
014a1138 | 9413 | else |
b5b8b0ac | 9414 | var_mem_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED, |
62760ffd | 9415 | set_src); |
ca787200 | 9416 | |
12c5ffe5 | 9417 | emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN, |
b5b8b0ac | 9418 | set->vars); |
ca787200 AO |
9419 | } |
9420 | break; | |
9421 | ||
9422 | case MO_COPY: | |
9423 | { | |
0de3e43f | 9424 | rtx loc = mo->u.loc; |
62760ffd | 9425 | enum var_init_status src_status; |
94a7682d RS |
9426 | rtx set_src = NULL; |
9427 | ||
9428 | if (GET_CODE (loc) == SET) | |
9429 | { | |
9430 | set_src = SET_SRC (loc); | |
9431 | loc = SET_DEST (loc); | |
9432 | } | |
62760ffd | 9433 | |
b5b8b0ac AO |
9434 | src_status = find_src_status (set, set_src); |
9435 | set_src = find_src_set_src (set, set_src); | |
ca787200 AO |
9436 | |
9437 | if (REG_P (loc)) | |
b5b8b0ac | 9438 | var_reg_delete_and_set (set, loc, false, src_status, set_src); |
ca787200 | 9439 | else |
b5b8b0ac | 9440 | var_mem_delete_and_set (set, loc, false, src_status, set_src); |
014a1138 | 9441 | |
12c5ffe5 | 9442 | emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN, |
b5b8b0ac | 9443 | set->vars); |
014a1138 JZ |
9444 | } |
9445 | break; | |
9446 | ||
9447 | case MO_USE_NO_VAR: | |
014a1138 | 9448 | { |
0de3e43f | 9449 | rtx loc = mo->u.loc; |
014a1138 | 9450 | |
f8cfc6aa | 9451 | if (REG_P (loc)) |
b5b8b0ac | 9452 | var_reg_delete (set, loc, false); |
014a1138 | 9453 | else |
b5b8b0ac | 9454 | var_mem_delete (set, loc, false); |
ca787200 | 9455 | |
b5b8b0ac | 9456 | emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN, set->vars); |
ca787200 AO |
9457 | } |
9458 | break; | |
014a1138 | 9459 | |
ca787200 AO |
9460 | case MO_CLOBBER: |
9461 | { | |
0de3e43f | 9462 | rtx loc = mo->u.loc; |
ca787200 AO |
9463 | |
9464 | if (REG_P (loc)) | |
b5b8b0ac | 9465 | var_reg_delete (set, loc, true); |
dedc1e6d | 9466 | else |
b5b8b0ac | 9467 | var_mem_delete (set, loc, true); |
ca787200 | 9468 | |
12c5ffe5 | 9469 | emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN, |
b5b8b0ac | 9470 | set->vars); |
014a1138 JZ |
9471 | } |
9472 | break; | |
9473 | ||
9474 | case MO_ADJUST: | |
0de3e43f | 9475 | set->stack_adjust += mo->u.adjust; |
014a1138 JZ |
9476 | break; |
9477 | } | |
9478 | } | |
014a1138 JZ |
9479 | } |
9480 | ||
9481 | /* Emit notes for the whole function. */ | |
9482 | ||
9483 | static void | |
9484 | vt_emit_notes (void) | |
9485 | { | |
9486 | basic_block bb; | |
b5b8b0ac | 9487 | dataflow_set cur; |
014a1138 | 9488 | |
c203e8a7 | 9489 | gcc_assert (!changed_variables->elements ()); |
014a1138 | 9490 | |
b5b8b0ac AO |
9491 | /* Free memory occupied by the out hash tables, as they aren't used |
9492 | anymore. */ | |
11cd3bed | 9493 | FOR_EACH_BB_FN (bb, cfun) |
b5b8b0ac AO |
9494 | dataflow_set_clear (&VTI (bb)->out); |
9495 | ||
014a1138 JZ |
9496 | /* Enable emitting notes by functions (mainly by set_variable_part and |
9497 | delete_variable_part). */ | |
9498 | emit_notes = true; | |
9499 | ||
b5b8b0ac | 9500 | if (MAY_HAVE_DEBUG_INSNS) |
d05cae4a | 9501 | { |
c203e8a7 | 9502 | dropped_values = new variable_table_type (cselib_get_next_uid () * 2); |
d05cae4a | 9503 | } |
b5b8b0ac AO |
9504 | |
9505 | dataflow_set_init (&cur); | |
014a1138 | 9506 | |
11cd3bed | 9507 | FOR_EACH_BB_FN (bb, cfun) |
014a1138 JZ |
9508 | { |
9509 | /* Emit the notes for changes of variable locations between two | |
9510 | subsequent basic blocks. */ | |
b5b8b0ac | 9511 | emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in); |
014a1138 | 9512 | |
af6236c1 | 9513 | if (MAY_HAVE_DEBUG_INSNS) |
b787e7a2 | 9514 | local_get_addr_cache = new hash_map<rtx, rtx>; |
af6236c1 | 9515 | |
014a1138 | 9516 | /* Emit the notes for the changes in the basic block itself. */ |
b5b8b0ac | 9517 | emit_notes_in_bb (bb, &cur); |
014a1138 | 9518 | |
af6236c1 | 9519 | if (MAY_HAVE_DEBUG_INSNS) |
b787e7a2 | 9520 | delete local_get_addr_cache; |
af6236c1 AO |
9521 | local_get_addr_cache = NULL; |
9522 | ||
b5b8b0ac AO |
9523 | /* Free memory occupied by the in hash table, we won't need it |
9524 | again. */ | |
9525 | dataflow_set_clear (&VTI (bb)->in); | |
014a1138 | 9526 | } |
b5b8b0ac | 9527 | #ifdef ENABLE_CHECKING |
013e5ef9 | 9528 | shared_hash_htab (cur.vars) |
c203e8a7 | 9529 | ->traverse <variable_table_type *, emit_notes_for_differences_1> |
013e5ef9 | 9530 | (shared_hash_htab (empty_shared_hash)); |
b5b8b0ac AO |
9531 | #endif |
9532 | dataflow_set_destroy (&cur); | |
9533 | ||
9534 | if (MAY_HAVE_DEBUG_INSNS) | |
c203e8a7 TS |
9535 | delete dropped_values; |
9536 | dropped_values = NULL; | |
b5b8b0ac | 9537 | |
014a1138 JZ |
9538 | emit_notes = false; |
9539 | } | |
9540 | ||
9541 | /* If there is a declaration and offset associated with register/memory RTL | |
9542 | assign declaration to *DECLP and offset to *OFFSETP, and return true. */ | |
9543 | ||
9544 | static bool | |
9545 | vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp) | |
9546 | { | |
f8cfc6aa | 9547 | if (REG_P (rtl)) |
014a1138 JZ |
9548 | { |
9549 | if (REG_ATTRS (rtl)) | |
9550 | { | |
9551 | *declp = REG_EXPR (rtl); | |
9552 | *offsetp = REG_OFFSET (rtl); | |
9553 | return true; | |
9554 | } | |
9555 | } | |
35af99b4 EB |
9556 | else if (GET_CODE (rtl) == PARALLEL) |
9557 | { | |
9558 | tree decl = NULL_TREE; | |
9559 | HOST_WIDE_INT offset = MAX_VAR_PARTS; | |
9560 | int len = XVECLEN (rtl, 0), i; | |
9561 | ||
9562 | for (i = 0; i < len; i++) | |
9563 | { | |
9564 | rtx reg = XEXP (XVECEXP (rtl, 0, i), 0); | |
9565 | if (!REG_P (reg) || !REG_ATTRS (reg)) | |
9566 | break; | |
9567 | if (!decl) | |
9568 | decl = REG_EXPR (reg); | |
9569 | if (REG_EXPR (reg) != decl) | |
9570 | break; | |
9571 | if (REG_OFFSET (reg) < offset) | |
9572 | offset = REG_OFFSET (reg); | |
9573 | } | |
9574 | ||
9575 | if (i == len) | |
9576 | { | |
9577 | *declp = decl; | |
9578 | *offsetp = offset; | |
9579 | return true; | |
9580 | } | |
9581 | } | |
3c0cb5de | 9582 | else if (MEM_P (rtl)) |
014a1138 JZ |
9583 | { |
9584 | if (MEM_ATTRS (rtl)) | |
9585 | { | |
9586 | *declp = MEM_EXPR (rtl); | |
8c6c36a3 | 9587 | *offsetp = INT_MEM_OFFSET (rtl); |
014a1138 JZ |
9588 | return true; |
9589 | } | |
9590 | } | |
9591 | return false; | |
9592 | } | |
9593 | ||
6f2ffb4b AO |
9594 | /* Record the value for the ENTRY_VALUE of RTL as a global equivalence |
9595 | of VAL. */ | |
ebdc0d4b JJ |
9596 | |
9597 | static void | |
6f2ffb4b | 9598 | record_entry_value (cselib_val *val, rtx rtl) |
09dbcd96 AO |
9599 | { |
9600 | rtx ev = gen_rtx_ENTRY_VALUE (GET_MODE (rtl)); | |
09dbcd96 AO |
9601 | |
9602 | ENTRY_VALUE_EXP (ev) = rtl; | |
9603 | ||
6f2ffb4b | 9604 | cselib_add_permanent_equiv (val, ev, get_insns ()); |
ebdc0d4b JJ |
9605 | } |
9606 | ||
8dcfef8f | 9607 | /* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK. */ |
014a1138 JZ |
9608 | |
9609 | static void | |
8dcfef8f | 9610 | vt_add_function_parameter (tree parm) |
014a1138 | 9611 | { |
8dcfef8f AO |
9612 | rtx decl_rtl = DECL_RTL_IF_SET (parm); |
9613 | rtx incoming = DECL_INCOMING_RTL (parm); | |
9614 | tree decl; | |
ef4bddc2 | 9615 | machine_mode mode; |
8dcfef8f AO |
9616 | HOST_WIDE_INT offset; |
9617 | dataflow_set *out; | |
9618 | decl_or_value dv; | |
014a1138 | 9619 | |
8dcfef8f AO |
9620 | if (TREE_CODE (parm) != PARM_DECL) |
9621 | return; | |
014a1138 | 9622 | |
8dcfef8f AO |
9623 | if (!decl_rtl || !incoming) |
9624 | return; | |
014a1138 | 9625 | |
8dcfef8f AO |
9626 | if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode) |
9627 | return; | |
014a1138 | 9628 | |
2b9d5ad7 AO |
9629 | /* If there is a DRAP register or a pseudo in internal_arg_pointer, |
9630 | rewrite the incoming location of parameters passed on the stack | |
9631 | into MEMs based on the argument pointer, so that incoming doesn't | |
9632 | depend on a pseudo. */ | |
80060f7a | 9633 | if (MEM_P (incoming) |
80060f7a JJ |
9634 | && (XEXP (incoming, 0) == crtl->args.internal_arg_pointer |
9635 | || (GET_CODE (XEXP (incoming, 0)) == PLUS | |
9636 | && XEXP (XEXP (incoming, 0), 0) | |
9637 | == crtl->args.internal_arg_pointer | |
9638 | && CONST_INT_P (XEXP (XEXP (incoming, 0), 1))))) | |
9639 | { | |
9640 | HOST_WIDE_INT off = -FIRST_PARM_OFFSET (current_function_decl); | |
9641 | if (GET_CODE (XEXP (incoming, 0)) == PLUS) | |
9642 | off += INTVAL (XEXP (XEXP (incoming, 0), 1)); | |
9643 | incoming | |
9644 | = replace_equiv_address_nv (incoming, | |
0a81f074 RS |
9645 | plus_constant (Pmode, |
9646 | arg_pointer_rtx, off)); | |
80060f7a JJ |
9647 | } |
9648 | ||
12c5ffe5 EB |
9649 | #ifdef HAVE_window_save |
9650 | /* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers. | |
9651 | If the target machine has an explicit window save instruction, the | |
9652 | actual entry value is the corresponding OUTGOING_REGNO instead. */ | |
499f32e8 | 9653 | if (HAVE_window_save && !crtl->uses_only_leaf_regs) |
12c5ffe5 | 9654 | { |
499f32e8 DM |
9655 | if (REG_P (incoming) |
9656 | && HARD_REGISTER_P (incoming) | |
9657 | && OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming)) | |
12c5ffe5 | 9658 | { |
4595475a | 9659 | parm_reg_t p; |
499f32e8 DM |
9660 | p.incoming = incoming; |
9661 | incoming | |
9662 | = gen_rtx_REG_offset (incoming, GET_MODE (incoming), | |
9663 | OUTGOING_REGNO (REGNO (incoming)), 0); | |
9664 | p.outgoing = incoming; | |
9771b263 | 9665 | vec_safe_push (windowed_parm_regs, p); |
499f32e8 | 9666 | } |
35af99b4 EB |
9667 | else if (GET_CODE (incoming) == PARALLEL) |
9668 | { | |
9669 | rtx outgoing | |
9670 | = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (incoming, 0))); | |
9671 | int i; | |
9672 | ||
9673 | for (i = 0; i < XVECLEN (incoming, 0); i++) | |
9674 | { | |
9675 | rtx reg = XEXP (XVECEXP (incoming, 0, i), 0); | |
9676 | parm_reg_t p; | |
9677 | p.incoming = reg; | |
9678 | reg = gen_rtx_REG_offset (reg, GET_MODE (reg), | |
9679 | OUTGOING_REGNO (REGNO (reg)), 0); | |
9680 | p.outgoing = reg; | |
9681 | XVECEXP (outgoing, 0, i) | |
9682 | = gen_rtx_EXPR_LIST (VOIDmode, reg, | |
9683 | XEXP (XVECEXP (incoming, 0, i), 1)); | |
9684 | vec_safe_push (windowed_parm_regs, p); | |
9685 | } | |
9686 | ||
9687 | incoming = outgoing; | |
9688 | } | |
499f32e8 DM |
9689 | else if (MEM_P (incoming) |
9690 | && REG_P (XEXP (incoming, 0)) | |
9691 | && HARD_REGISTER_P (XEXP (incoming, 0))) | |
9692 | { | |
9693 | rtx reg = XEXP (incoming, 0); | |
9694 | if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg)) | |
9695 | { | |
9696 | parm_reg_t p; | |
9697 | p.incoming = reg; | |
9698 | reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg))); | |
9699 | p.outgoing = reg; | |
9700 | vec_safe_push (windowed_parm_regs, p); | |
9701 | incoming = replace_equiv_address_nv (incoming, reg); | |
9702 | } | |
12c5ffe5 EB |
9703 | } |
9704 | } | |
9705 | #endif | |
9706 | ||
8dcfef8f AO |
9707 | if (!vt_get_decl_and_offset (incoming, &decl, &offset)) |
9708 | { | |
f7e088e7 | 9709 | if (MEM_P (incoming)) |
38ae7651 | 9710 | { |
8dcfef8f AO |
9711 | /* This means argument is passed by invisible reference. */ |
9712 | offset = 0; | |
9713 | decl = parm; | |
38ae7651 | 9714 | } |
8dcfef8f | 9715 | else |
3d7e23f6 | 9716 | { |
8dcfef8f AO |
9717 | if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset)) |
9718 | return; | |
9719 | offset += byte_lowpart_offset (GET_MODE (incoming), | |
9720 | GET_MODE (decl_rtl)); | |
3d7e23f6 | 9721 | } |
8dcfef8f | 9722 | } |
014a1138 | 9723 | |
8dcfef8f AO |
9724 | if (!decl) |
9725 | return; | |
9726 | ||
9727 | if (parm != decl) | |
9728 | { | |
ee84cd37 MP |
9729 | /* If that DECL_RTL wasn't a pseudo that got spilled to |
9730 | memory, bail out. Otherwise, the spill slot sharing code | |
9731 | will force the memory to reference spill_slot_decl (%sfp), | |
9732 | so we don't match above. That's ok, the pseudo must have | |
9733 | referenced the entire parameter, so just reset OFFSET. */ | |
9734 | if (decl != get_spill_slot_decl (false)) | |
9735 | return; | |
8dcfef8f AO |
9736 | offset = 0; |
9737 | } | |
38ae7651 | 9738 | |
8dcfef8f AO |
9739 | if (!track_loc_p (incoming, parm, offset, false, &mode, &offset)) |
9740 | return; | |
014a1138 | 9741 | |
fefa31b5 | 9742 | out = &VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out; |
b5b8b0ac | 9743 | |
8dcfef8f | 9744 | dv = dv_from_decl (parm); |
b5b8b0ac | 9745 | |
8dcfef8f AO |
9746 | if (target_for_debug_bind (parm) |
9747 | /* We can't deal with these right now, because this kind of | |
9748 | variable is single-part. ??? We could handle parallels | |
9749 | that describe multiple locations for the same single | |
9750 | value, but ATM we don't. */ | |
9751 | && GET_CODE (incoming) != PARALLEL) | |
9752 | { | |
9753 | cselib_val *val; | |
75a5b7dd | 9754 | rtx lowpart; |
b5b8b0ac | 9755 | |
8dcfef8f AO |
9756 | /* ??? We shouldn't ever hit this, but it may happen because |
9757 | arguments passed by invisible reference aren't dealt with | |
9758 | above: incoming-rtl will have Pmode rather than the | |
9759 | expected mode for the type. */ | |
9760 | if (offset) | |
9761 | return; | |
b5b8b0ac | 9762 | |
75a5b7dd AO |
9763 | lowpart = var_lowpart (mode, incoming); |
9764 | if (!lowpart) | |
9765 | return; | |
9766 | ||
9767 | val = cselib_lookup_from_insn (lowpart, mode, true, | |
2b1c5433 | 9768 | VOIDmode, get_insns ()); |
b5b8b0ac | 9769 | |
8dcfef8f AO |
9770 | /* ??? Float-typed values in memory are not handled by |
9771 | cselib. */ | |
9772 | if (val) | |
014a1138 | 9773 | { |
8dcfef8f AO |
9774 | preserve_value (val); |
9775 | set_variable_part (out, val->val_rtx, dv, offset, | |
b5b8b0ac | 9776 | VAR_INIT_STATUS_INITIALIZED, NULL, INSERT); |
8dcfef8f | 9777 | dv = dv_from_value (val->val_rtx); |
38ae7651 | 9778 | } |
de2c775d AO |
9779 | |
9780 | if (MEM_P (incoming)) | |
9781 | { | |
9782 | val = cselib_lookup_from_insn (XEXP (incoming, 0), mode, true, | |
9783 | VOIDmode, get_insns ()); | |
9784 | if (val) | |
9785 | { | |
9786 | preserve_value (val); | |
9787 | incoming = replace_equiv_address_nv (incoming, val->val_rtx); | |
9788 | } | |
9789 | } | |
014a1138 | 9790 | } |
b5b8b0ac | 9791 | |
8dcfef8f AO |
9792 | if (REG_P (incoming)) |
9793 | { | |
9794 | incoming = var_lowpart (mode, incoming); | |
9795 | gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER); | |
9796 | attrs_list_insert (&out->regs[REGNO (incoming)], dv, offset, | |
9797 | incoming); | |
9798 | set_variable_part (out, incoming, dv, offset, | |
9799 | VAR_INIT_STATUS_INITIALIZED, NULL, INSERT); | |
2b1c5433 JJ |
9800 | if (dv_is_value_p (dv)) |
9801 | { | |
6f2ffb4b | 9802 | record_entry_value (CSELIB_VAL_PTR (dv_as_value (dv)), incoming); |
2b1c5433 JJ |
9803 | if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE |
9804 | && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm)))) | |
9805 | { | |
ef4bddc2 | 9806 | machine_mode indmode |
2b1c5433 JJ |
9807 | = TYPE_MODE (TREE_TYPE (TREE_TYPE (parm))); |
9808 | rtx mem = gen_rtx_MEM (indmode, incoming); | |
09dbcd96 AO |
9809 | cselib_val *val = cselib_lookup_from_insn (mem, indmode, true, |
9810 | VOIDmode, | |
9811 | get_insns ()); | |
2b1c5433 JJ |
9812 | if (val) |
9813 | { | |
9814 | preserve_value (val); | |
6f2ffb4b | 9815 | record_entry_value (val, mem); |
09dbcd96 AO |
9816 | set_variable_part (out, mem, dv_from_value (val->val_rtx), 0, |
9817 | VAR_INIT_STATUS_INITIALIZED, NULL, INSERT); | |
2b1c5433 JJ |
9818 | } |
9819 | } | |
9820 | } | |
8dcfef8f | 9821 | } |
35af99b4 EB |
9822 | else if (GET_CODE (incoming) == PARALLEL && !dv_onepart_p (dv)) |
9823 | { | |
9824 | int i; | |
9825 | ||
9826 | for (i = 0; i < XVECLEN (incoming, 0); i++) | |
9827 | { | |
9828 | rtx reg = XEXP (XVECEXP (incoming, 0, i), 0); | |
9829 | offset = REG_OFFSET (reg); | |
9830 | gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER); | |
9831 | attrs_list_insert (&out->regs[REGNO (reg)], dv, offset, reg); | |
9832 | set_variable_part (out, reg, dv, offset, | |
9833 | VAR_INIT_STATUS_INITIALIZED, NULL, INSERT); | |
9834 | } | |
9835 | } | |
8dcfef8f AO |
9836 | else if (MEM_P (incoming)) |
9837 | { | |
9838 | incoming = var_lowpart (mode, incoming); | |
9839 | set_variable_part (out, incoming, dv, offset, | |
9840 | VAR_INIT_STATUS_INITIALIZED, NULL, INSERT); | |
9841 | } | |
9842 | } | |
9843 | ||
9844 | /* Insert function parameters to IN and OUT sets of ENTRY_BLOCK. */ | |
9845 | ||
9846 | static void | |
9847 | vt_add_function_parameters (void) | |
9848 | { | |
9849 | tree parm; | |
9850 | ||
9851 | for (parm = DECL_ARGUMENTS (current_function_decl); | |
9852 | parm; parm = DECL_CHAIN (parm)) | |
d5e254e1 IE |
9853 | if (!POINTER_BOUNDS_P (parm)) |
9854 | vt_add_function_parameter (parm); | |
8dcfef8f AO |
9855 | |
9856 | if (DECL_HAS_VALUE_EXPR_P (DECL_RESULT (current_function_decl))) | |
9857 | { | |
9858 | tree vexpr = DECL_VALUE_EXPR (DECL_RESULT (current_function_decl)); | |
9859 | ||
9860 | if (TREE_CODE (vexpr) == INDIRECT_REF) | |
9861 | vexpr = TREE_OPERAND (vexpr, 0); | |
9862 | ||
9863 | if (TREE_CODE (vexpr) == PARM_DECL | |
9864 | && DECL_ARTIFICIAL (vexpr) | |
9865 | && !DECL_IGNORED_P (vexpr) | |
9866 | && DECL_NAMELESS (vexpr)) | |
9867 | vt_add_function_parameter (vexpr); | |
9868 | } | |
014a1138 JZ |
9869 | } |
9870 | ||
457eeaae JJ |
9871 | /* Initialize cfa_base_rtx, create a preserved VALUE for it and |
9872 | ensure it isn't flushed during cselib_reset_table. | |
9873 | Can be called only if frame_pointer_rtx resp. arg_pointer_rtx | |
9874 | has been eliminated. */ | |
9875 | ||
9876 | static void | |
9877 | vt_init_cfa_base (void) | |
9878 | { | |
9879 | cselib_val *val; | |
9880 | ||
9881 | #ifdef FRAME_POINTER_CFA_OFFSET | |
9882 | cfa_base_rtx = frame_pointer_rtx; | |
cfd8c4b1 | 9883 | cfa_base_offset = -FRAME_POINTER_CFA_OFFSET (current_function_decl); |
457eeaae JJ |
9884 | #else |
9885 | cfa_base_rtx = arg_pointer_rtx; | |
cfd8c4b1 | 9886 | cfa_base_offset = -ARG_POINTER_CFA_OFFSET (current_function_decl); |
457eeaae | 9887 | #endif |
f0c12fcc JJ |
9888 | if (cfa_base_rtx == hard_frame_pointer_rtx |
9889 | || !fixed_regs[REGNO (cfa_base_rtx)]) | |
9890 | { | |
9891 | cfa_base_rtx = NULL_RTX; | |
9892 | return; | |
9893 | } | |
457eeaae JJ |
9894 | if (!MAY_HAVE_DEBUG_INSNS) |
9895 | return; | |
9896 | ||
61630b27 JJ |
9897 | /* Tell alias analysis that cfa_base_rtx should share |
9898 | find_base_term value with stack pointer or hard frame pointer. */ | |
80060f7a JJ |
9899 | if (!frame_pointer_needed) |
9900 | vt_equate_reg_base_value (cfa_base_rtx, stack_pointer_rtx); | |
9901 | else if (!crtl->stack_realign_tried) | |
9902 | vt_equate_reg_base_value (cfa_base_rtx, hard_frame_pointer_rtx); | |
9903 | ||
109f4af3 | 9904 | val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1, |
4deef538 | 9905 | VOIDmode, get_insns ()); |
457eeaae | 9906 | preserve_value (val); |
9de9cbaf | 9907 | cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx)); |
457eeaae JJ |
9908 | } |
9909 | ||
014a1138 JZ |
9910 | /* Allocate and initialize the data structures for variable tracking |
9911 | and parse the RTL to get the micro operations. */ | |
9912 | ||
457eeaae | 9913 | static bool |
014a1138 JZ |
9914 | vt_initialize (void) |
9915 | { | |
d459f870 | 9916 | basic_block bb; |
457eeaae | 9917 | HOST_WIDE_INT fp_cfa_offset = -1; |
014a1138 JZ |
9918 | |
9919 | alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def)); | |
9920 | ||
7e46899d | 9921 | empty_shared_hash = new shared_hash_def; |
457eeaae | 9922 | empty_shared_hash->refcount = 1; |
c203e8a7 TS |
9923 | empty_shared_hash->htab = new variable_table_type (1); |
9924 | changed_variables = new variable_table_type (10); | |
457eeaae JJ |
9925 | |
9926 | /* Init the IN and OUT sets. */ | |
04a90bec | 9927 | FOR_ALL_BB_FN (bb, cfun) |
457eeaae JJ |
9928 | { |
9929 | VTI (bb)->visited = false; | |
9930 | VTI (bb)->flooded = false; | |
9931 | dataflow_set_init (&VTI (bb)->in); | |
9932 | dataflow_set_init (&VTI (bb)->out); | |
9933 | VTI (bb)->permp = NULL; | |
9934 | } | |
9935 | ||
9936 | if (MAY_HAVE_DEBUG_INSNS) | |
9937 | { | |
9938 | cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS); | |
b5b8b0ac | 9939 | scratch_regs = BITMAP_ALLOC (NULL); |
9771b263 | 9940 | preserved_values.create (256); |
b787e7a2 | 9941 | global_get_addr_cache = new hash_map<rtx, rtx>; |
b5b8b0ac AO |
9942 | } |
9943 | else | |
9944 | { | |
9945 | scratch_regs = NULL; | |
af6236c1 | 9946 | global_get_addr_cache = NULL; |
b5b8b0ac AO |
9947 | } |
9948 | ||
48b00503 AO |
9949 | if (MAY_HAVE_DEBUG_INSNS) |
9950 | { | |
9951 | rtx reg, expr; | |
9952 | int ofst; | |
9953 | cselib_val *val; | |
9954 | ||
9955 | #ifdef FRAME_POINTER_CFA_OFFSET | |
9956 | reg = frame_pointer_rtx; | |
9957 | ofst = FRAME_POINTER_CFA_OFFSET (current_function_decl); | |
9958 | #else | |
9959 | reg = arg_pointer_rtx; | |
9960 | ofst = ARG_POINTER_CFA_OFFSET (current_function_decl); | |
9961 | #endif | |
9962 | ||
9963 | ofst -= INCOMING_FRAME_SP_OFFSET; | |
9964 | ||
9965 | val = cselib_lookup_from_insn (reg, GET_MODE (reg), 1, | |
9966 | VOIDmode, get_insns ()); | |
9967 | preserve_value (val); | |
2e084917 AO |
9968 | if (reg != hard_frame_pointer_rtx && fixed_regs[REGNO (reg)]) |
9969 | cselib_preserve_cfa_base_value (val, REGNO (reg)); | |
48b00503 AO |
9970 | expr = plus_constant (GET_MODE (stack_pointer_rtx), |
9971 | stack_pointer_rtx, -ofst); | |
9972 | cselib_add_permanent_equiv (val, expr, get_insns ()); | |
9973 | ||
9974 | if (ofst) | |
9975 | { | |
9976 | val = cselib_lookup_from_insn (stack_pointer_rtx, | |
9977 | GET_MODE (stack_pointer_rtx), 1, | |
9978 | VOIDmode, get_insns ()); | |
9979 | preserve_value (val); | |
9980 | expr = plus_constant (GET_MODE (reg), reg, ofst); | |
9981 | cselib_add_permanent_equiv (val, expr, get_insns ()); | |
9982 | } | |
9983 | } | |
9984 | ||
65773087 EB |
9985 | /* In order to factor out the adjustments made to the stack pointer or to |
9986 | the hard frame pointer and thus be able to use DW_OP_fbreg operations | |
9987 | instead of individual location lists, we're going to rewrite MEMs based | |
9988 | on them into MEMs based on the CFA by de-eliminating stack_pointer_rtx | |
9989 | or hard_frame_pointer_rtx to the virtual CFA pointer frame_pointer_rtx | |
9990 | resp. arg_pointer_rtx. We can do this either when there is no frame | |
9991 | pointer in the function and stack adjustments are consistent for all | |
9992 | basic blocks or when there is a frame pointer and no stack realignment. | |
9993 | But we first have to check that frame_pointer_rtx resp. arg_pointer_rtx | |
9994 | has been eliminated. */ | |
457eeaae JJ |
9995 | if (!frame_pointer_needed) |
9996 | { | |
9997 | rtx reg, elim; | |
9998 | ||
9999 | if (!vt_stack_adjustments ()) | |
10000 | return false; | |
10001 | ||
10002 | #ifdef FRAME_POINTER_CFA_OFFSET | |
10003 | reg = frame_pointer_rtx; | |
10004 | #else | |
10005 | reg = arg_pointer_rtx; | |
10006 | #endif | |
10007 | elim = eliminate_regs (reg, VOIDmode, NULL_RTX); | |
10008 | if (elim != reg) | |
10009 | { | |
10010 | if (GET_CODE (elim) == PLUS) | |
10011 | elim = XEXP (elim, 0); | |
10012 | if (elim == stack_pointer_rtx) | |
10013 | vt_init_cfa_base (); | |
10014 | } | |
10015 | } | |
10016 | else if (!crtl->stack_realign_tried) | |
10017 | { | |
10018 | rtx reg, elim; | |
10019 | ||
10020 | #ifdef FRAME_POINTER_CFA_OFFSET | |
10021 | reg = frame_pointer_rtx; | |
10022 | fp_cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl); | |
10023 | #else | |
10024 | reg = arg_pointer_rtx; | |
10025 | fp_cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl); | |
10026 | #endif | |
10027 | elim = eliminate_regs (reg, VOIDmode, NULL_RTX); | |
10028 | if (elim != reg) | |
10029 | { | |
10030 | if (GET_CODE (elim) == PLUS) | |
10031 | { | |
10032 | fp_cfa_offset -= INTVAL (XEXP (elim, 1)); | |
10033 | elim = XEXP (elim, 0); | |
10034 | } | |
10035 | if (elim != hard_frame_pointer_rtx) | |
10036 | fp_cfa_offset = -1; | |
457eeaae | 10037 | } |
65773087 EB |
10038 | else |
10039 | fp_cfa_offset = -1; | |
457eeaae | 10040 | } |
65773087 | 10041 | |
80060f7a JJ |
10042 | /* If the stack is realigned and a DRAP register is used, we're going to |
10043 | rewrite MEMs based on it representing incoming locations of parameters | |
10044 | passed on the stack into MEMs based on the argument pointer. Although | |
10045 | we aren't going to rewrite other MEMs, we still need to initialize the | |
10046 | virtual CFA pointer in order to ensure that the argument pointer will | |
10047 | be seen as a constant throughout the function. | |
10048 | ||
10049 | ??? This doesn't work if FRAME_POINTER_CFA_OFFSET is defined. */ | |
10050 | else if (stack_realign_drap) | |
10051 | { | |
10052 | rtx reg, elim; | |
10053 | ||
10054 | #ifdef FRAME_POINTER_CFA_OFFSET | |
10055 | reg = frame_pointer_rtx; | |
10056 | #else | |
10057 | reg = arg_pointer_rtx; | |
10058 | #endif | |
10059 | elim = eliminate_regs (reg, VOIDmode, NULL_RTX); | |
10060 | if (elim != reg) | |
10061 | { | |
10062 | if (GET_CODE (elim) == PLUS) | |
10063 | elim = XEXP (elim, 0); | |
10064 | if (elim == hard_frame_pointer_rtx) | |
10065 | vt_init_cfa_base (); | |
10066 | } | |
10067 | } | |
10068 | ||
457eeaae JJ |
10069 | hard_frame_pointer_adjustment = -1; |
10070 | ||
2b1c5433 JJ |
10071 | vt_add_function_parameters (); |
10072 | ||
11cd3bed | 10073 | FOR_EACH_BB_FN (bb, cfun) |
014a1138 | 10074 | { |
598d62da | 10075 | rtx_insn *insn; |
7b39f38b | 10076 | HOST_WIDE_INT pre, post = 0; |
d9a6979d | 10077 | basic_block first_bb, last_bb; |
b5b8b0ac AO |
10078 | |
10079 | if (MAY_HAVE_DEBUG_INSNS) | |
10080 | { | |
0de3e43f | 10081 | cselib_record_sets_hook = add_with_sets; |
b5b8b0ac AO |
10082 | if (dump_file && (dump_flags & TDF_DETAILS)) |
10083 | fprintf (dump_file, "first value: %i\n", | |
5440c0e7 | 10084 | cselib_get_next_uid ()); |
b5b8b0ac | 10085 | } |
014a1138 | 10086 | |
d9a6979d JJ |
10087 | first_bb = bb; |
10088 | for (;;) | |
10089 | { | |
10090 | edge e; | |
fefa31b5 | 10091 | if (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun) |
d9a6979d JJ |
10092 | || ! single_pred_p (bb->next_bb)) |
10093 | break; | |
10094 | e = find_edge (bb, bb->next_bb); | |
10095 | if (! e || (e->flags & EDGE_FALLTHRU) == 0) | |
10096 | break; | |
10097 | bb = bb->next_bb; | |
10098 | } | |
10099 | last_bb = bb; | |
10100 | ||
0de3e43f | 10101 | /* Add the micro-operations to the vector. */ |
d9a6979d | 10102 | FOR_BB_BETWEEN (bb, first_bb, last_bb->next_bb, next_bb) |
014a1138 | 10103 | { |
457eeaae JJ |
10104 | HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust; |
10105 | VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust; | |
d9a6979d JJ |
10106 | for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb)); |
10107 | insn = NEXT_INSN (insn)) | |
014a1138 | 10108 | { |
d9a6979d | 10109 | if (INSN_P (insn)) |
014a1138 | 10110 | { |
d9a6979d | 10111 | if (!frame_pointer_needed) |
b5b8b0ac | 10112 | { |
d9a6979d JJ |
10113 | insn_stack_adjust_offset_pre_post (insn, &pre, &post); |
10114 | if (pre) | |
10115 | { | |
0de3e43f JJ |
10116 | micro_operation mo; |
10117 | mo.type = MO_ADJUST; | |
10118 | mo.u.adjust = pre; | |
10119 | mo.insn = insn; | |
d9a6979d JJ |
10120 | if (dump_file && (dump_flags & TDF_DETAILS)) |
10121 | log_op_type (PATTERN (insn), bb, insn, | |
10122 | MO_ADJUST, dump_file); | |
9771b263 | 10123 | VTI (bb)->mos.safe_push (mo); |
457eeaae | 10124 | VTI (bb)->out.stack_adjust += pre; |
d9a6979d | 10125 | } |
014a1138 | 10126 | } |
014a1138 | 10127 | |
d9a6979d | 10128 | cselib_hook_called = false; |
457eeaae | 10129 | adjust_insn (bb, insn); |
d9a6979d | 10130 | if (MAY_HAVE_DEBUG_INSNS) |
014a1138 | 10131 | { |
2b1c5433 JJ |
10132 | if (CALL_P (insn)) |
10133 | prepare_call_arguments (bb, insn); | |
d9a6979d JJ |
10134 | cselib_process_insn (insn); |
10135 | if (dump_file && (dump_flags & TDF_DETAILS)) | |
10136 | { | |
10137 | print_rtl_single (dump_file, insn); | |
10138 | dump_cselib_table (dump_file); | |
10139 | } | |
014a1138 | 10140 | } |
d9a6979d JJ |
10141 | if (!cselib_hook_called) |
10142 | add_with_sets (insn, 0, 0); | |
457eeaae | 10143 | cancel_changes (0); |
014a1138 | 10144 | |
d9a6979d JJ |
10145 | if (!frame_pointer_needed && post) |
10146 | { | |
0de3e43f JJ |
10147 | micro_operation mo; |
10148 | mo.type = MO_ADJUST; | |
10149 | mo.u.adjust = post; | |
10150 | mo.insn = insn; | |
d9a6979d JJ |
10151 | if (dump_file && (dump_flags & TDF_DETAILS)) |
10152 | log_op_type (PATTERN (insn), bb, insn, | |
10153 | MO_ADJUST, dump_file); | |
9771b263 | 10154 | VTI (bb)->mos.safe_push (mo); |
457eeaae JJ |
10155 | VTI (bb)->out.stack_adjust += post; |
10156 | } | |
10157 | ||
d459f870 | 10158 | if (fp_cfa_offset != -1 |
457eeaae | 10159 | && hard_frame_pointer_adjustment == -1 |
40155239 | 10160 | && fp_setter_insn (insn)) |
457eeaae JJ |
10161 | { |
10162 | vt_init_cfa_base (); | |
10163 | hard_frame_pointer_adjustment = fp_cfa_offset; | |
0fe03ac3 JJ |
10164 | /* Disassociate sp from fp now. */ |
10165 | if (MAY_HAVE_DEBUG_INSNS) | |
10166 | { | |
10167 | cselib_val *v; | |
10168 | cselib_invalidate_rtx (stack_pointer_rtx); | |
10169 | v = cselib_lookup (stack_pointer_rtx, Pmode, 1, | |
10170 | VOIDmode); | |
10171 | if (v && !cselib_preserved_value_p (v)) | |
10172 | { | |
10173 | cselib_set_value_sp_based (v); | |
10174 | preserve_value (v); | |
10175 | } | |
10176 | } | |
d9a6979d | 10177 | } |
014a1138 JZ |
10178 | } |
10179 | } | |
457eeaae | 10180 | gcc_assert (offset == VTI (bb)->out.stack_adjust); |
014a1138 | 10181 | } |
d9a6979d JJ |
10182 | |
10183 | bb = last_bb; | |
10184 | ||
b5b8b0ac AO |
10185 | if (MAY_HAVE_DEBUG_INSNS) |
10186 | { | |
0de3e43f JJ |
10187 | cselib_preserve_only_values (); |
10188 | cselib_reset_table (cselib_get_next_uid ()); | |
b5b8b0ac AO |
10189 | cselib_record_sets_hook = NULL; |
10190 | } | |
014a1138 JZ |
10191 | } |
10192 | ||
457eeaae | 10193 | hard_frame_pointer_adjustment = -1; |
fefa31b5 | 10194 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->flooded = true; |
457eeaae JJ |
10195 | cfa_base_rtx = NULL_RTX; |
10196 | return true; | |
014a1138 JZ |
10197 | } |
10198 | ||
5619e52c JJ |
10199 | /* This is *not* reset after each function. It gives each |
10200 | NOTE_INSN_DELETED_DEBUG_LABEL in the entire compilation | |
10201 | a unique label number. */ | |
10202 | ||
10203 | static int debug_label_num = 1; | |
10204 | ||
b5b8b0ac AO |
10205 | /* Get rid of all debug insns from the insn stream. */ |
10206 | ||
10207 | static void | |
10208 | delete_debug_insns (void) | |
10209 | { | |
10210 | basic_block bb; | |
598d62da | 10211 | rtx_insn *insn, *next; |
b5b8b0ac AO |
10212 | |
10213 | if (!MAY_HAVE_DEBUG_INSNS) | |
10214 | return; | |
10215 | ||
11cd3bed | 10216 | FOR_EACH_BB_FN (bb, cfun) |
b5b8b0ac AO |
10217 | { |
10218 | FOR_BB_INSNS_SAFE (bb, insn, next) | |
10219 | if (DEBUG_INSN_P (insn)) | |
5619e52c JJ |
10220 | { |
10221 | tree decl = INSN_VAR_LOCATION_DECL (insn); | |
10222 | if (TREE_CODE (decl) == LABEL_DECL | |
10223 | && DECL_NAME (decl) | |
10224 | && !DECL_RTL_SET_P (decl)) | |
10225 | { | |
10226 | PUT_CODE (insn, NOTE); | |
10227 | NOTE_KIND (insn) = NOTE_INSN_DELETED_DEBUG_LABEL; | |
10228 | NOTE_DELETED_LABEL_NAME (insn) | |
10229 | = IDENTIFIER_POINTER (DECL_NAME (decl)); | |
10230 | SET_DECL_RTL (decl, insn); | |
10231 | CODE_LABEL_NUMBER (insn) = debug_label_num++; | |
10232 | } | |
10233 | else | |
10234 | delete_insn (insn); | |
10235 | } | |
b5b8b0ac AO |
10236 | } |
10237 | } | |
10238 | ||
10239 | /* Run a fast, BB-local only version of var tracking, to take care of | |
10240 | information that we don't do global analysis on, such that not all | |
10241 | information is lost. If SKIPPED holds, we're skipping the global | |
10242 | pass entirely, so we should try to use information it would have | |
10243 | handled as well.. */ | |
10244 | ||
10245 | static void | |
10246 | vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED) | |
10247 | { | |
10248 | /* ??? Just skip it all for now. */ | |
10249 | delete_debug_insns (); | |
10250 | } | |
10251 | ||
014a1138 JZ |
10252 | /* Free the data structures needed for variable tracking. */ |
10253 | ||
10254 | static void | |
10255 | vt_finalize (void) | |
10256 | { | |
10257 | basic_block bb; | |
10258 | ||
11cd3bed | 10259 | FOR_EACH_BB_FN (bb, cfun) |
014a1138 | 10260 | { |
9771b263 | 10261 | VTI (bb)->mos.release (); |
014a1138 JZ |
10262 | } |
10263 | ||
04a90bec | 10264 | FOR_ALL_BB_FN (bb, cfun) |
014a1138 JZ |
10265 | { |
10266 | dataflow_set_destroy (&VTI (bb)->in); | |
10267 | dataflow_set_destroy (&VTI (bb)->out); | |
b5b8b0ac AO |
10268 | if (VTI (bb)->permp) |
10269 | { | |
10270 | dataflow_set_destroy (VTI (bb)->permp); | |
10271 | XDELETE (VTI (bb)->permp); | |
10272 | } | |
014a1138 JZ |
10273 | } |
10274 | free_aux_for_blocks (); | |
c203e8a7 TS |
10275 | delete empty_shared_hash->htab; |
10276 | empty_shared_hash->htab = NULL; | |
10277 | delete changed_variables; | |
10278 | changed_variables = NULL; | |
7e46899d ML |
10279 | attrs_def::pool.release (); |
10280 | var_pool.release (); | |
10281 | location_chain_def::pool.release (); | |
10282 | shared_hash_def::pool.release (); | |
b5b8b0ac AO |
10283 | |
10284 | if (MAY_HAVE_DEBUG_INSNS) | |
10285 | { | |
af6236c1 | 10286 | if (global_get_addr_cache) |
b787e7a2 | 10287 | delete global_get_addr_cache; |
af6236c1 | 10288 | global_get_addr_cache = NULL; |
7e46899d ML |
10289 | loc_exp_dep::pool.release (); |
10290 | valvar_pool.release (); | |
9771b263 | 10291 | preserved_values.release (); |
b5b8b0ac AO |
10292 | cselib_finish (); |
10293 | BITMAP_FREE (scratch_regs); | |
10294 | scratch_regs = NULL; | |
10295 | } | |
10296 | ||
09dbcd96 | 10297 | #ifdef HAVE_window_save |
9771b263 | 10298 | vec_free (windowed_parm_regs); |
09dbcd96 | 10299 | #endif |
8b9b2275 | 10300 | |
7eb3f1f7 | 10301 | if (vui_vec) |
b5b8b0ac | 10302 | XDELETEVEC (vui_vec); |
7eb3f1f7 JJ |
10303 | vui_vec = NULL; |
10304 | vui_allocated = 0; | |
014a1138 JZ |
10305 | } |
10306 | ||
10307 | /* The entry point to variable tracking pass. */ | |
10308 | ||
ec8c3978 JJ |
10309 | static inline unsigned int |
10310 | variable_tracking_main_1 (void) | |
014a1138 | 10311 | { |
ec8c3978 JJ |
10312 | bool success; |
10313 | ||
d00dce27 JJ |
10314 | if (flag_var_tracking_assignments < 0 |
10315 | /* Var-tracking right now assumes the IR doesn't contain | |
10316 | any pseudos at this point. */ | |
10317 | || targetm.no_register_allocation) | |
b5b8b0ac AO |
10318 | { |
10319 | delete_debug_insns (); | |
10320 | return 0; | |
10321 | } | |
10322 | ||
0cae8d31 | 10323 | if (n_basic_blocks_for_fn (cfun) > 500 && |
dc936fb2 | 10324 | n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20) |
b5b8b0ac AO |
10325 | { |
10326 | vt_debug_insns_local (true); | |
10327 | return 0; | |
10328 | } | |
014a1138 JZ |
10329 | |
10330 | mark_dfs_back_edges (); | |
457eeaae | 10331 | if (!vt_initialize ()) |
014a1138 | 10332 | { |
457eeaae JJ |
10333 | vt_finalize (); |
10334 | vt_debug_insns_local (true); | |
10335 | return 0; | |
014a1138 JZ |
10336 | } |
10337 | ||
ec8c3978 JJ |
10338 | success = vt_find_locations (); |
10339 | ||
10340 | if (!success && flag_var_tracking_assignments > 0) | |
10341 | { | |
10342 | vt_finalize (); | |
10343 | ||
10344 | delete_debug_insns (); | |
10345 | ||
10346 | /* This is later restored by our caller. */ | |
10347 | flag_var_tracking_assignments = 0; | |
10348 | ||
457eeaae JJ |
10349 | success = vt_initialize (); |
10350 | gcc_assert (success); | |
ec8c3978 JJ |
10351 | |
10352 | success = vt_find_locations (); | |
10353 | } | |
10354 | ||
10355 | if (!success) | |
10356 | { | |
10357 | vt_finalize (); | |
10358 | vt_debug_insns_local (false); | |
10359 | return 0; | |
10360 | } | |
014a1138 | 10361 | |
5b4fdb20 | 10362 | if (dump_file && (dump_flags & TDF_DETAILS)) |
014a1138 JZ |
10363 | { |
10364 | dump_dataflow_sets (); | |
532aafad | 10365 | dump_reg_info (dump_file); |
5b4fdb20 | 10366 | dump_flow_info (dump_file, dump_flags); |
014a1138 JZ |
10367 | } |
10368 | ||
f029db69 | 10369 | timevar_push (TV_VAR_TRACKING_EMIT); |
b5b8b0ac | 10370 | vt_emit_notes (); |
f029db69 | 10371 | timevar_pop (TV_VAR_TRACKING_EMIT); |
b5b8b0ac | 10372 | |
014a1138 | 10373 | vt_finalize (); |
b5b8b0ac | 10374 | vt_debug_insns_local (false); |
c2924966 | 10375 | return 0; |
014a1138 | 10376 | } |
ec8c3978 JJ |
10377 | |
10378 | unsigned int | |
10379 | variable_tracking_main (void) | |
10380 | { | |
10381 | unsigned int ret; | |
10382 | int save = flag_var_tracking_assignments; | |
10383 | ||
10384 | ret = variable_tracking_main_1 (); | |
10385 | ||
10386 | flag_var_tracking_assignments = save; | |
10387 | ||
10388 | return ret; | |
10389 | } | |
ef330312 | 10390 | \f |
27a4cd48 DM |
10391 | namespace { |
10392 | ||
10393 | const pass_data pass_data_variable_tracking = | |
10394 | { | |
10395 | RTL_PASS, /* type */ | |
10396 | "vartrack", /* name */ | |
10397 | OPTGROUP_NONE, /* optinfo_flags */ | |
27a4cd48 DM |
10398 | TV_VAR_TRACKING, /* tv_id */ |
10399 | 0, /* properties_required */ | |
10400 | 0, /* properties_provided */ | |
10401 | 0, /* properties_destroyed */ | |
10402 | 0, /* todo_flags_start */ | |
3bea341f | 10403 | 0, /* todo_flags_finish */ |
ef330312 | 10404 | }; |
27a4cd48 DM |
10405 | |
10406 | class pass_variable_tracking : public rtl_opt_pass | |
10407 | { | |
10408 | public: | |
c3284718 RS |
10409 | pass_variable_tracking (gcc::context *ctxt) |
10410 | : rtl_opt_pass (pass_data_variable_tracking, ctxt) | |
27a4cd48 DM |
10411 | {} |
10412 | ||
10413 | /* opt_pass methods: */ | |
1a3d085c TS |
10414 | virtual bool gate (function *) |
10415 | { | |
10416 | return (flag_var_tracking && !targetm.delay_vartrack); | |
10417 | } | |
10418 | ||
be55bfe6 TS |
10419 | virtual unsigned int execute (function *) |
10420 | { | |
10421 | return variable_tracking_main (); | |
10422 | } | |
27a4cd48 DM |
10423 | |
10424 | }; // class pass_variable_tracking | |
10425 | ||
10426 | } // anon namespace | |
10427 | ||
10428 | rtl_opt_pass * | |
10429 | make_pass_variable_tracking (gcc::context *ctxt) | |
10430 | { | |
10431 | return new pass_variable_tracking (ctxt); | |
10432 | } |