File: | build/gcc/var-tracking.cc |
Warning: | line 8398, column 8 Value stored to 'next' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Variable tracking routines for the GNU compiler. |
2 | Copyright (C) 2002-2023 Free Software Foundation, Inc. |
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 |
8 | the Free Software Foundation; either version 3, or (at your option) |
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 |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ |
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 < |
36 | < clobber < set < post-modifying stack adjustment |
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 "backend.h" |
92 | #include "target.h" |
93 | #include "rtl.h" |
94 | #include "tree.h" |
95 | #include "cfghooks.h" |
96 | #include "alloc-pool.h" |
97 | #include "tree-pass.h" |
98 | #include "memmodel.h" |
99 | #include "tm_p.h" |
100 | #include "insn-config.h" |
101 | #include "regs.h" |
102 | #include "emit-rtl.h" |
103 | #include "recog.h" |
104 | #include "diagnostic.h" |
105 | #include "varasm.h" |
106 | #include "stor-layout.h" |
107 | #include "cfgrtl.h" |
108 | #include "cfganal.h" |
109 | #include "reload.h" |
110 | #include "calls.h" |
111 | #include "tree-dfa.h" |
112 | #include "tree-ssa.h" |
113 | #include "cselib.h" |
114 | #include "tree-pretty-print.h" |
115 | #include "rtl-iter.h" |
116 | #include "fibonacci_heap.h" |
117 | #include "print-rtl.h" |
118 | #include "function-abi.h" |
119 | |
120 | typedef fibonacci_heap <long, basic_block_def> bb_heap_t; |
121 | |
122 | /* var-tracking.cc assumes that tree code with the same value as VALUE rtx code |
123 | has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl. |
124 | Currently the value is the same as IDENTIFIER_NODE, which has such |
125 | a property. If this compile time assertion ever fails, make sure that |
126 | the new tree code that equals (int) VALUE has the same property. */ |
127 | extern char check_value_val[(int) VALUE == (int) IDENTIFIER_NODE ? 1 : -1]; |
128 | |
129 | /* Type of micro operation. */ |
130 | enum micro_operation_type |
131 | { |
132 | MO_USE, /* Use location (REG or MEM). */ |
133 | MO_USE_NO_VAR,/* Use location which is not associated with a variable |
134 | or the variable is not trackable. */ |
135 | MO_VAL_USE, /* Use location which is associated with a value. */ |
136 | MO_VAL_LOC, /* Use location which appears in a debug insn. */ |
137 | MO_VAL_SET, /* Set location associated with a value. */ |
138 | MO_SET, /* Set location. */ |
139 | MO_COPY, /* Copy the same portion of a variable from one |
140 | location to another. */ |
141 | MO_CLOBBER, /* Clobber location. */ |
142 | MO_CALL, /* Call insn. */ |
143 | MO_ADJUST /* Adjust stack pointer. */ |
144 | |
145 | }; |
146 | |
147 | static const char * const ATTRIBUTE_UNUSED__attribute__ ((__unused__)) |
148 | micro_operation_type_name[] = { |
149 | "MO_USE", |
150 | "MO_USE_NO_VAR", |
151 | "MO_VAL_USE", |
152 | "MO_VAL_LOC", |
153 | "MO_VAL_SET", |
154 | "MO_SET", |
155 | "MO_COPY", |
156 | "MO_CLOBBER", |
157 | "MO_CALL", |
158 | "MO_ADJUST" |
159 | }; |
160 | |
161 | /* Where shall the note be emitted? BEFORE or AFTER the instruction. |
162 | Notes emitted as AFTER_CALL are to take effect during the call, |
163 | rather than after the call. */ |
164 | enum emit_note_where |
165 | { |
166 | EMIT_NOTE_BEFORE_INSN, |
167 | EMIT_NOTE_AFTER_INSN, |
168 | EMIT_NOTE_AFTER_CALL_INSN |
169 | }; |
170 | |
171 | /* Structure holding information about micro operation. */ |
172 | struct micro_operation |
173 | { |
174 | /* Type of micro operation. */ |
175 | enum micro_operation_type type; |
176 | |
177 | /* The instruction which the micro operation is in, for MO_USE, |
178 | MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent |
179 | instruction or note in the original flow (before any var-tracking |
180 | notes are inserted, to simplify emission of notes), for MO_SET |
181 | and MO_CLOBBER. */ |
182 | rtx_insn *insn; |
183 | |
184 | union { |
185 | /* Location. For MO_SET and MO_COPY, this is the SET that |
186 | performs the assignment, if known, otherwise it is the target |
187 | of the assignment. For MO_VAL_USE and MO_VAL_SET, it is a |
188 | CONCAT of the VALUE and the LOC associated with it. For |
189 | MO_VAL_LOC, it is a CONCAT of the VALUE and the VAR_LOCATION |
190 | associated with it. */ |
191 | rtx loc; |
192 | |
193 | /* Stack adjustment. */ |
194 | HOST_WIDE_INTlong adjust; |
195 | } u; |
196 | }; |
197 | |
198 | |
199 | /* A declaration of a variable, or an RTL value being handled like a |
200 | declaration. */ |
201 | typedef void *decl_or_value; |
202 | |
203 | /* Return true if a decl_or_value DV is a DECL or NULL. */ |
204 | static inline bool |
205 | dv_is_decl_p (decl_or_value dv) |
206 | { |
207 | return !dv || (int) TREE_CODE ((tree) dv)((enum tree_code) ((tree) dv)->base.code) != (int) VALUE; |
208 | } |
209 | |
210 | /* Return true if a decl_or_value is a VALUE rtl. */ |
211 | static inline bool |
212 | dv_is_value_p (decl_or_value dv) |
213 | { |
214 | return dv && !dv_is_decl_p (dv); |
215 | } |
216 | |
217 | /* Return the decl in the decl_or_value. */ |
218 | static inline tree |
219 | dv_as_decl (decl_or_value dv) |
220 | { |
221 | gcc_checking_assert (dv_is_decl_p (dv))((void)(!(dv_is_decl_p (dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 221, __FUNCTION__), 0 : 0)); |
222 | return (tree) dv; |
223 | } |
224 | |
225 | /* Return the value in the decl_or_value. */ |
226 | static inline rtx |
227 | dv_as_value (decl_or_value dv) |
228 | { |
229 | gcc_checking_assert (dv_is_value_p (dv))((void)(!(dv_is_value_p (dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 229, __FUNCTION__), 0 : 0)); |
230 | return (rtx)dv; |
231 | } |
232 | |
233 | /* Return the opaque pointer in the decl_or_value. */ |
234 | static inline void * |
235 | dv_as_opaque (decl_or_value dv) |
236 | { |
237 | return dv; |
238 | } |
239 | |
240 | |
241 | /* Description of location of a part of a variable. The content of a physical |
242 | register is described by a chain of these structures. |
243 | The chains are pretty short (usually 1 or 2 elements) and thus |
244 | chain is the best data structure. */ |
245 | struct attrs |
246 | { |
247 | /* Pointer to next member of the list. */ |
248 | attrs *next; |
249 | |
250 | /* The rtx of register. */ |
251 | rtx loc; |
252 | |
253 | /* The declaration corresponding to LOC. */ |
254 | decl_or_value dv; |
255 | |
256 | /* Offset from start of DECL. */ |
257 | HOST_WIDE_INTlong offset; |
258 | }; |
259 | |
260 | /* Structure for chaining the locations. */ |
261 | struct location_chain |
262 | { |
263 | /* Next element in the chain. */ |
264 | location_chain *next; |
265 | |
266 | /* The location (REG, MEM or VALUE). */ |
267 | rtx loc; |
268 | |
269 | /* The "value" stored in this location. */ |
270 | rtx set_src; |
271 | |
272 | /* Initialized? */ |
273 | enum var_init_status init; |
274 | }; |
275 | |
276 | /* A vector of loc_exp_dep holds the active dependencies of a one-part |
277 | DV on VALUEs, i.e., the VALUEs expanded so as to form the current |
278 | location of DV. Each entry is also part of VALUE' s linked-list of |
279 | backlinks back to DV. */ |
280 | struct loc_exp_dep |
281 | { |
282 | /* The dependent DV. */ |
283 | decl_or_value dv; |
284 | /* The dependency VALUE or DECL_DEBUG. */ |
285 | rtx value; |
286 | /* The next entry in VALUE's backlinks list. */ |
287 | struct loc_exp_dep *next; |
288 | /* A pointer to the pointer to this entry (head or prev's next) in |
289 | the doubly-linked list. */ |
290 | struct loc_exp_dep **pprev; |
291 | }; |
292 | |
293 | |
294 | /* This data structure holds information about the depth of a variable |
295 | expansion. */ |
296 | struct expand_depth |
297 | { |
298 | /* This measures the complexity of the expanded expression. It |
299 | grows by one for each level of expansion that adds more than one |
300 | operand. */ |
301 | int complexity; |
302 | /* This counts the number of ENTRY_VALUE expressions in an |
303 | expansion. We want to minimize their use. */ |
304 | int entryvals; |
305 | }; |
306 | |
307 | /* Type for dependencies actively used when expand FROM into cur_loc. */ |
308 | typedef vec<loc_exp_dep, va_heap, vl_embed> deps_vec; |
309 | |
310 | /* This data structure is allocated for one-part variables at the time |
311 | of emitting notes. */ |
312 | struct onepart_aux |
313 | { |
314 | /* Doubly-linked list of dependent DVs. These are DVs whose cur_loc |
315 | computation used the expansion of this variable, and that ought |
316 | to be notified should this variable change. If the DV's cur_loc |
317 | expanded to NULL, all components of the loc list are regarded as |
318 | active, so that any changes in them give us a chance to get a |
319 | location. Otherwise, only components of the loc that expanded to |
320 | non-NULL are regarded as active dependencies. */ |
321 | loc_exp_dep *backlinks; |
322 | /* This holds the LOC that was expanded into cur_loc. We need only |
323 | mark a one-part variable as changed if the FROM loc is removed, |
324 | or if it has no known location and a loc is added, or if it gets |
325 | a change notification from any of its active dependencies. */ |
326 | rtx from; |
327 | /* The depth of the cur_loc expression. */ |
328 | expand_depth depth; |
329 | /* Dependencies actively used when expand FROM into cur_loc. */ |
330 | deps_vec deps; |
331 | }; |
332 | |
333 | /* Structure describing one part of variable. */ |
334 | struct variable_part |
335 | { |
336 | /* Chain of locations of the part. */ |
337 | location_chain *loc_chain; |
338 | |
339 | /* Location which was last emitted to location list. */ |
340 | rtx cur_loc; |
341 | |
342 | union variable_aux |
343 | { |
344 | /* The offset in the variable, if !var->onepart. */ |
345 | HOST_WIDE_INTlong offset; |
346 | |
347 | /* Pointer to auxiliary data, if var->onepart and emit_notes. */ |
348 | struct onepart_aux *onepaux; |
349 | } aux; |
350 | }; |
351 | |
352 | /* Maximum number of location parts. */ |
353 | #define MAX_VAR_PARTS16 16 |
354 | |
355 | /* Enumeration type used to discriminate various types of one-part |
356 | variables. */ |
357 | enum onepart_enum |
358 | { |
359 | /* Not a one-part variable. */ |
360 | NOT_ONEPART = 0, |
361 | /* A one-part DECL that is not a DEBUG_EXPR_DECL. */ |
362 | ONEPART_VDECL = 1, |
363 | /* A DEBUG_EXPR_DECL. */ |
364 | ONEPART_DEXPR = 2, |
365 | /* A VALUE. */ |
366 | ONEPART_VALUE = 3 |
367 | }; |
368 | |
369 | /* Structure describing where the variable is located. */ |
370 | struct variable |
371 | { |
372 | /* The declaration of the variable, or an RTL value being handled |
373 | like a declaration. */ |
374 | decl_or_value dv; |
375 | |
376 | /* Reference count. */ |
377 | int refcount; |
378 | |
379 | /* Number of variable parts. */ |
380 | char n_var_parts; |
381 | |
382 | /* What type of DV this is, according to enum onepart_enum. */ |
383 | ENUM_BITFIELD (onepart_enum)enum onepart_enum onepart : CHAR_BIT8; |
384 | |
385 | /* True if this variable_def struct is currently in the |
386 | changed_variables hash table. */ |
387 | bool in_changed_variables; |
388 | |
389 | /* The variable parts. */ |
390 | variable_part var_part[1]; |
391 | }; |
392 | |
393 | /* Pointer to the BB's information specific to variable tracking pass. */ |
394 | #define VTI(BB)((variable_tracking_info *) (BB)->aux) ((variable_tracking_info *) (BB)->aux) |
395 | |
396 | /* Return MEM_OFFSET (MEM) as a HOST_WIDE_INT, or 0 if we can't. */ |
397 | |
398 | static inline HOST_WIDE_INTlong |
399 | int_mem_offset (const_rtx mem) |
400 | { |
401 | HOST_WIDE_INTlong offset; |
402 | if (MEM_OFFSET_KNOWN_P (mem)(get_mem_attrs (mem)->offset_known_p) && MEM_OFFSET (mem)(get_mem_attrs (mem)->offset).is_constant (&offset)) |
403 | return offset; |
404 | return 0; |
405 | } |
406 | |
407 | #if CHECKING_P1 && (GCC_VERSION(4 * 1000 + 2) >= 2007) |
408 | |
409 | /* Access VAR's Ith part's offset, checking that it's not a one-part |
410 | variable. */ |
411 | #define VAR_PART_OFFSET(var, i)__extension__ (*({ variable *const __v = (var); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 411, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) __extension__ \ |
412 | (*({ variable *const __v = (var); \ |
413 | gcc_checking_assert (!__v->onepart)((void)(!(!__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 413, __FUNCTION__), 0 : 0)); \ |
414 | &__v->var_part[(i)].aux.offset; })) |
415 | |
416 | /* Access VAR's one-part auxiliary data, checking that it is a |
417 | one-part variable. */ |
418 | #define VAR_LOC_1PAUX(var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 418, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) __extension__ \ |
419 | (*({ variable *const __v = (var); \ |
420 | gcc_checking_assert (__v->onepart)((void)(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 420, __FUNCTION__), 0 : 0)); \ |
421 | &__v->var_part[0].aux.onepaux; })) |
422 | |
423 | #else |
424 | #define VAR_PART_OFFSET(var, i)__extension__ (*({ variable *const __v = (var); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 424, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) ((var)->var_part[(i)].aux.offset) |
425 | #define VAR_LOC_1PAUX(var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 425, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) ((var)->var_part[0].aux.onepaux) |
426 | #endif |
427 | |
428 | /* These are accessor macros for the one-part auxiliary data. When |
429 | convenient for users, they're guarded by tests that the data was |
430 | allocated. */ |
431 | #define VAR_LOC_DEP_LST(var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 431, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) ? __extension__ (*({ variable *const __v = (var); ((void )(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 431, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->backlinks : nullptr) (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 431, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) \ |
432 | ? VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 432, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->backlinks \ |
433 | : NULLnullptr) |
434 | #define VAR_LOC_DEP_LSTP(var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 434, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) ? &__extension__ (*({ variable *const __v = (var); ( (void)(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 434, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->backlinks : nullptr) (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 434, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) \ |
435 | ? &VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 435, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->backlinks \ |
436 | : NULLnullptr) |
437 | #define VAR_LOC_FROM(var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 437, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->from) (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 437, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->from) |
438 | #define VAR_LOC_DEPTH(var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 438, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->depth) (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 438, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->depth) |
439 | #define VAR_LOC_DEP_VEC(var)var_loc_dep_vec (var) var_loc_dep_vec (var) |
440 | |
441 | /* Implements the VAR_LOC_DEP_VEC above as a function to work around |
442 | a bogus -Wnonnull (PR c/95554). */ |
443 | |
444 | static inline deps_vec* |
445 | var_loc_dep_vec (variable *var) |
446 | { |
447 | return VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 447, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; })) ? &VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 447, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux.onepaux ; }))->deps : NULLnullptr; |
448 | } |
449 | |
450 | |
451 | typedef unsigned int dvuid; |
452 | |
453 | /* Return the uid of DV. */ |
454 | |
455 | static inline dvuid |
456 | dv_uid (decl_or_value dv) |
457 | { |
458 | if (dv_is_value_p (dv)) |
459 | return CSELIB_VAL_PTR (dv_as_value (dv))(((dv_as_value (dv))->u.fld[0]).rt_cselib)->uid; |
460 | else |
461 | return DECL_UID (dv_as_decl (dv))((contains_struct_check ((dv_as_decl (dv)), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 461, __FUNCTION__))->decl_minimal.uid); |
462 | } |
463 | |
464 | /* Compute the hash from the uid. */ |
465 | |
466 | static inline hashval_t |
467 | dv_uid2hash (dvuid uid) |
468 | { |
469 | return uid; |
470 | } |
471 | |
472 | /* The hash function for a mask table in a shared_htab chain. */ |
473 | |
474 | static inline hashval_t |
475 | dv_htab_hash (decl_or_value dv) |
476 | { |
477 | return dv_uid2hash (dv_uid (dv)); |
478 | } |
479 | |
480 | static void variable_htab_free (void *); |
481 | |
482 | /* Variable hashtable helpers. */ |
483 | |
484 | struct variable_hasher : pointer_hash <variable> |
485 | { |
486 | typedef void *compare_type; |
487 | static inline hashval_t hash (const variable *); |
488 | static inline bool equal (const variable *, const void *); |
489 | static inline void remove (variable *); |
490 | }; |
491 | |
492 | /* The hash function for variable_htab, computes the hash value |
493 | from the declaration of variable X. */ |
494 | |
495 | inline hashval_t |
496 | variable_hasher::hash (const variable *v) |
497 | { |
498 | return dv_htab_hash (v->dv); |
499 | } |
500 | |
501 | /* Compare the declaration of variable X with declaration Y. */ |
502 | |
503 | inline bool |
504 | variable_hasher::equal (const variable *v, const void *y) |
505 | { |
506 | decl_or_value dv = CONST_CAST2 (decl_or_value, const void *, y)(const_cast<decl_or_value> (y)); |
507 | |
508 | return (dv_as_opaque (v->dv) == dv_as_opaque (dv)); |
509 | } |
510 | |
511 | /* Free the element of VARIABLE_HTAB (its type is struct variable_def). */ |
512 | |
513 | inline void |
514 | variable_hasher::remove (variable *var) |
515 | { |
516 | variable_htab_free (var); |
517 | } |
518 | |
519 | typedef hash_table<variable_hasher> variable_table_type; |
520 | typedef variable_table_type::iterator variable_iterator_type; |
521 | |
522 | /* Structure for passing some other parameters to function |
523 | emit_note_insn_var_location. */ |
524 | struct emit_note_data |
525 | { |
526 | /* The instruction which the note will be emitted before/after. */ |
527 | rtx_insn *insn; |
528 | |
529 | /* Where the note will be emitted (before/after insn)? */ |
530 | enum emit_note_where where; |
531 | |
532 | /* The variables and values active at this point. */ |
533 | variable_table_type *vars; |
534 | }; |
535 | |
536 | /* Structure holding a refcounted hash table. If refcount > 1, |
537 | it must be first unshared before modified. */ |
538 | struct shared_hash |
539 | { |
540 | /* Reference count. */ |
541 | int refcount; |
542 | |
543 | /* Actual hash table. */ |
544 | variable_table_type *htab; |
545 | }; |
546 | |
547 | /* Structure holding the IN or OUT set for a basic block. */ |
548 | struct dataflow_set |
549 | { |
550 | /* Adjustment of stack offset. */ |
551 | HOST_WIDE_INTlong stack_adjust; |
552 | |
553 | /* Attributes for registers (lists of attrs). */ |
554 | attrs *regs[FIRST_PSEUDO_REGISTER76]; |
555 | |
556 | /* Variable locations. */ |
557 | shared_hash *vars; |
558 | |
559 | /* Vars that is being traversed. */ |
560 | shared_hash *traversed_vars; |
561 | }; |
562 | |
563 | /* The structure (one for each basic block) containing the information |
564 | needed for variable tracking. */ |
565 | struct variable_tracking_info |
566 | { |
567 | /* The vector of micro operations. */ |
568 | vec<micro_operation> mos; |
569 | |
570 | /* The IN and OUT set for dataflow analysis. */ |
571 | dataflow_set in; |
572 | dataflow_set out; |
573 | |
574 | /* The permanent-in dataflow set for this block. This is used to |
575 | hold values for which we had to compute entry values. ??? This |
576 | should probably be dynamically allocated, to avoid using more |
577 | memory in non-debug builds. */ |
578 | dataflow_set *permp; |
579 | |
580 | /* Has the block been visited in DFS? */ |
581 | bool visited; |
582 | |
583 | /* Has the block been flooded in VTA? */ |
584 | bool flooded; |
585 | |
586 | }; |
587 | |
588 | /* Alloc pool for struct attrs_def. */ |
589 | object_allocator<attrs> attrs_pool ("attrs pool"); |
590 | |
591 | /* Alloc pool for struct variable_def with MAX_VAR_PARTS entries. */ |
592 | |
593 | static pool_allocator var_pool |
594 | ("variable_def pool", sizeof (variable) + |
595 | (MAX_VAR_PARTS16 - 1) * sizeof (((variable *)NULLnullptr)->var_part[0])); |
596 | |
597 | /* Alloc pool for struct variable_def with a single var_part entry. */ |
598 | static pool_allocator valvar_pool |
599 | ("small variable_def pool", sizeof (variable)); |
600 | |
601 | /* Alloc pool for struct location_chain. */ |
602 | static object_allocator<location_chain> location_chain_pool |
603 | ("location_chain pool"); |
604 | |
605 | /* Alloc pool for struct shared_hash. */ |
606 | static object_allocator<shared_hash> shared_hash_pool ("shared_hash pool"); |
607 | |
608 | /* Alloc pool for struct loc_exp_dep_s for NOT_ONEPART variables. */ |
609 | object_allocator<loc_exp_dep> loc_exp_dep_pool ("loc_exp_dep pool"); |
610 | |
611 | /* Changed variables, notes will be emitted for them. */ |
612 | static variable_table_type *changed_variables; |
613 | |
614 | /* Shall notes be emitted? */ |
615 | static bool emit_notes; |
616 | |
617 | /* Values whose dynamic location lists have gone empty, but whose |
618 | cselib location lists are still usable. Use this to hold the |
619 | current location, the backlinks, etc, during emit_notes. */ |
620 | static variable_table_type *dropped_values; |
621 | |
622 | /* Empty shared hashtable. */ |
623 | static shared_hash *empty_shared_hash; |
624 | |
625 | /* Scratch register bitmap used by cselib_expand_value_rtx. */ |
626 | static bitmap scratch_regs = NULLnullptr; |
627 | |
628 | #ifdef HAVE_window_save |
629 | struct GTY(()) parm_reg { |
630 | rtx outgoing; |
631 | rtx incoming; |
632 | }; |
633 | |
634 | |
635 | /* Vector of windowed parameter registers, if any. */ |
636 | static vec<parm_reg, va_gc> *windowed_parm_regs = NULLnullptr; |
637 | #endif |
638 | |
639 | /* Variable used to tell whether cselib_process_insn called our hook. */ |
640 | static bool cselib_hook_called; |
641 | |
642 | /* Local function prototypes. */ |
643 | static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INTlong *, |
644 | HOST_WIDE_INTlong *); |
645 | static void insn_stack_adjust_offset_pre_post (rtx_insn *, HOST_WIDE_INTlong *, |
646 | HOST_WIDE_INTlong *); |
647 | static bool vt_stack_adjustments (void); |
648 | |
649 | static void init_attrs_list_set (attrs **); |
650 | static void attrs_list_clear (attrs **); |
651 | static attrs *attrs_list_member (attrs *, decl_or_value, HOST_WIDE_INTlong); |
652 | static void attrs_list_insert (attrs **, decl_or_value, HOST_WIDE_INTlong, rtx); |
653 | static void attrs_list_copy (attrs **, attrs *); |
654 | static void attrs_list_union (attrs **, attrs *); |
655 | |
656 | static variable **unshare_variable (dataflow_set *set, variable **slot, |
657 | variable *var, enum var_init_status); |
658 | static void vars_copy (variable_table_type *, variable_table_type *); |
659 | static tree var_debug_decl (tree); |
660 | static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx); |
661 | static void var_reg_delete_and_set (dataflow_set *, rtx, bool, |
662 | enum var_init_status, rtx); |
663 | static void var_reg_delete (dataflow_set *, rtx, bool); |
664 | static void var_regno_delete (dataflow_set *, int); |
665 | static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx); |
666 | static void var_mem_delete_and_set (dataflow_set *, rtx, bool, |
667 | enum var_init_status, rtx); |
668 | static void var_mem_delete (dataflow_set *, rtx, bool); |
669 | |
670 | static void dataflow_set_init (dataflow_set *); |
671 | static void dataflow_set_clear (dataflow_set *); |
672 | static void dataflow_set_copy (dataflow_set *, dataflow_set *); |
673 | static int variable_union_info_cmp_pos (const void *, const void *); |
674 | static void dataflow_set_union (dataflow_set *, dataflow_set *); |
675 | static location_chain *find_loc_in_1pdv (rtx, variable *, |
676 | variable_table_type *); |
677 | static bool canon_value_cmp (rtx, rtx); |
678 | static int loc_cmp (rtx, rtx); |
679 | static bool variable_part_different_p (variable_part *, variable_part *); |
680 | static bool onepart_variable_different_p (variable *, variable *); |
681 | static bool variable_different_p (variable *, variable *); |
682 | static bool dataflow_set_different (dataflow_set *, dataflow_set *); |
683 | static void dataflow_set_destroy (dataflow_set *); |
684 | |
685 | static bool track_expr_p (tree, bool); |
686 | static void add_uses_1 (rtx *, void *); |
687 | static void add_stores (rtx, const_rtx, void *); |
688 | static bool compute_bb_dataflow (basic_block); |
689 | static bool vt_find_locations (void); |
690 | |
691 | static void dump_attrs_list (attrs *); |
692 | static void dump_var (variable *); |
693 | static void dump_vars (variable_table_type *); |
694 | static void dump_dataflow_set (dataflow_set *); |
695 | static void dump_dataflow_sets (void); |
696 | |
697 | static void set_dv_changed (decl_or_value, bool); |
698 | static void variable_was_changed (variable *, dataflow_set *); |
699 | static variable **set_slot_part (dataflow_set *, rtx, variable **, |
700 | decl_or_value, HOST_WIDE_INTlong, |
701 | enum var_init_status, rtx); |
702 | static void set_variable_part (dataflow_set *, rtx, |
703 | decl_or_value, HOST_WIDE_INTlong, |
704 | enum var_init_status, rtx, enum insert_option); |
705 | static variable **clobber_slot_part (dataflow_set *, rtx, |
706 | variable **, HOST_WIDE_INTlong, rtx); |
707 | static void clobber_variable_part (dataflow_set *, rtx, |
708 | decl_or_value, HOST_WIDE_INTlong, rtx); |
709 | static variable **delete_slot_part (dataflow_set *, rtx, variable **, |
710 | HOST_WIDE_INTlong); |
711 | static void delete_variable_part (dataflow_set *, rtx, |
712 | decl_or_value, HOST_WIDE_INTlong); |
713 | static void emit_notes_in_bb (basic_block, dataflow_set *); |
714 | static void vt_emit_notes (void); |
715 | |
716 | static void vt_add_function_parameters (void); |
717 | static bool vt_initialize (void); |
718 | static void vt_finalize (void); |
719 | |
720 | /* Callback for stack_adjust_offset_pre_post, called via for_each_inc_dec. */ |
721 | |
722 | static int |
723 | stack_adjust_offset_pre_post_cb (rtx, rtx op, rtx dest, rtx src, rtx srcoff, |
724 | void *arg) |
725 | { |
726 | if (dest != stack_pointer_rtx((this_target_rtl->x_global_rtl)[GR_STACK_POINTER])) |
727 | return 0; |
728 | |
729 | switch (GET_CODE (op)((enum rtx_code) (op)->code)) |
730 | { |
731 | case PRE_INC: |
732 | case PRE_DEC: |
733 | ((HOST_WIDE_INTlong *)arg)[0] -= INTVAL (srcoff)((srcoff)->u.hwint[0]); |
734 | return 0; |
735 | case POST_INC: |
736 | case POST_DEC: |
737 | ((HOST_WIDE_INTlong *)arg)[1] -= INTVAL (srcoff)((srcoff)->u.hwint[0]); |
738 | return 0; |
739 | case PRE_MODIFY: |
740 | case POST_MODIFY: |
741 | /* We handle only adjustments by constant amount. */ |
742 | gcc_assert (GET_CODE (src) == PLUS((void)(!(((enum rtx_code) (src)->code) == PLUS && (((enum rtx_code) ((((src)->u.fld[1]).rt_rtx))->code) == CONST_INT) && (((src)->u.fld[0]).rt_rtx) == ((this_target_rtl ->x_global_rtl)[GR_STACK_POINTER])) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 744, __FUNCTION__), 0 : 0)) |
743 | && CONST_INT_P (XEXP (src, 1))((void)(!(((enum rtx_code) (src)->code) == PLUS && (((enum rtx_code) ((((src)->u.fld[1]).rt_rtx))->code) == CONST_INT) && (((src)->u.fld[0]).rt_rtx) == ((this_target_rtl ->x_global_rtl)[GR_STACK_POINTER])) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 744, __FUNCTION__), 0 : 0)) |
744 | && XEXP (src, 0) == stack_pointer_rtx)((void)(!(((enum rtx_code) (src)->code) == PLUS && (((enum rtx_code) ((((src)->u.fld[1]).rt_rtx))->code) == CONST_INT) && (((src)->u.fld[0]).rt_rtx) == ((this_target_rtl ->x_global_rtl)[GR_STACK_POINTER])) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 744, __FUNCTION__), 0 : 0)); |
745 | ((HOST_WIDE_INTlong *)arg)[GET_CODE (op)((enum rtx_code) (op)->code) == POST_MODIFY] |
746 | -= INTVAL (XEXP (src, 1))(((((src)->u.fld[1]).rt_rtx))->u.hwint[0]); |
747 | return 0; |
748 | default: |
749 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 749, __FUNCTION__)); |
750 | } |
751 | } |
752 | |
753 | /* Given a SET, calculate the amount of stack adjustment it contains |
754 | PRE- and POST-modifying stack pointer. |
755 | This function is similar to stack_adjust_offset. */ |
756 | |
757 | static void |
758 | stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INTlong *pre, |
759 | HOST_WIDE_INTlong *post) |
760 | { |
761 | rtx src = SET_SRC (pattern)(((pattern)->u.fld[1]).rt_rtx); |
762 | rtx dest = SET_DEST (pattern)(((pattern)->u.fld[0]).rt_rtx); |
763 | enum rtx_code code; |
764 | |
765 | if (dest == stack_pointer_rtx((this_target_rtl->x_global_rtl)[GR_STACK_POINTER])) |
766 | { |
767 | /* (set (reg sp) (plus (reg sp) (const_int))) */ |
768 | code = GET_CODE (src)((enum rtx_code) (src)->code); |
769 | if (! (code == PLUS || code == MINUS) |
770 | || XEXP (src, 0)(((src)->u.fld[0]).rt_rtx) != stack_pointer_rtx((this_target_rtl->x_global_rtl)[GR_STACK_POINTER]) |
771 | || !CONST_INT_P (XEXP (src, 1))(((enum rtx_code) ((((src)->u.fld[1]).rt_rtx))->code) == CONST_INT)) |
772 | return; |
773 | |
774 | if (code == MINUS) |
775 | *post += INTVAL (XEXP (src, 1))(((((src)->u.fld[1]).rt_rtx))->u.hwint[0]); |
776 | else |
777 | *post -= INTVAL (XEXP (src, 1))(((((src)->u.fld[1]).rt_rtx))->u.hwint[0]); |
778 | return; |
779 | } |
780 | HOST_WIDE_INTlong res[2] = { 0, 0 }; |
781 | for_each_inc_dec (pattern, stack_adjust_offset_pre_post_cb, res); |
782 | *pre += res[0]; |
783 | *post += res[1]; |
784 | } |
785 | |
786 | /* Given an INSN, calculate the amount of stack adjustment it contains |
787 | PRE- and POST-modifying stack pointer. */ |
788 | |
789 | static void |
790 | insn_stack_adjust_offset_pre_post (rtx_insn *insn, HOST_WIDE_INTlong *pre, |
791 | HOST_WIDE_INTlong *post) |
792 | { |
793 | rtx pattern; |
794 | |
795 | *pre = 0; |
796 | *post = 0; |
797 | |
798 | pattern = PATTERN (insn); |
799 | if (RTX_FRAME_RELATED_P (insn)(__extension__ ({ __typeof ((insn)) const _rtx = ((insn)); if (((enum rtx_code) (_rtx)->code) != DEBUG_INSN && ( (enum rtx_code) (_rtx)->code) != INSN && ((enum rtx_code ) (_rtx)->code) != CALL_INSN && ((enum rtx_code) ( _rtx)->code) != JUMP_INSN && ((enum rtx_code) (_rtx )->code) != BARRIER && ((enum rtx_code) (_rtx)-> code) != SET) rtl_check_failed_flag ("RTX_FRAME_RELATED_P",_rtx , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 799, __FUNCTION__); _rtx; })->frame_related)) |
800 | { |
801 | rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX(rtx) 0); |
802 | if (expr) |
803 | pattern = XEXP (expr, 0)(((expr)->u.fld[0]).rt_rtx); |
804 | } |
805 | |
806 | if (GET_CODE (pattern)((enum rtx_code) (pattern)->code) == SET) |
807 | stack_adjust_offset_pre_post (pattern, pre, post); |
808 | else if (GET_CODE (pattern)((enum rtx_code) (pattern)->code) == PARALLEL |
809 | || GET_CODE (pattern)((enum rtx_code) (pattern)->code) == SEQUENCE) |
810 | { |
811 | int i; |
812 | |
813 | /* There may be stack adjustments inside compound insns. Search |
814 | for them. */ |
815 | for ( i = XVECLEN (pattern, 0)(((((pattern)->u.fld[0]).rt_rtvec))->num_elem) - 1; i >= 0; i--) |
816 | if (GET_CODE (XVECEXP (pattern, 0, i))((enum rtx_code) ((((((pattern)->u.fld[0]).rt_rtvec))-> elem[i]))->code) == SET) |
817 | stack_adjust_offset_pre_post (XVECEXP (pattern, 0, i)(((((pattern)->u.fld[0]).rt_rtvec))->elem[i]), pre, post); |
818 | } |
819 | } |
820 | |
821 | /* Compute stack adjustments for all blocks by traversing DFS tree. |
822 | Return true when the adjustments on all incoming edges are consistent. |
823 | Heavily borrowed from pre_and_rev_post_order_compute. */ |
824 | |
825 | static bool |
826 | vt_stack_adjustments (void) |
827 | { |
828 | edge_iterator *stack; |
829 | int sp; |
830 | |
831 | /* Initialize entry block. */ |
832 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))((variable_tracking_info *) ((((cfun + 0))->cfg->x_entry_block_ptr ))->aux)->visited = true; |
833 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))((variable_tracking_info *) ((((cfun + 0))->cfg->x_entry_block_ptr ))->aux)->in.stack_adjust |
834 | = INCOMING_FRAME_SP_OFFSET((cfun + 0)->machine->func_type == TYPE_EXCEPTION ? 2 * (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4) : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); |
835 | VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))((variable_tracking_info *) ((((cfun + 0))->cfg->x_entry_block_ptr ))->aux)->out.stack_adjust |
836 | = INCOMING_FRAME_SP_OFFSET((cfun + 0)->machine->func_type == TYPE_EXCEPTION ? 2 * (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4) : (((global_options.x_ix86_isa_flags & (1UL << 1)) != 0) ? 8 : 4)); |
837 | |
838 | /* Allocate stack for back-tracking up CFG. */ |
839 | stack = XNEWVEC (edge_iterator, n_basic_blocks_for_fn (cfun) + 1)((edge_iterator *) xmalloc (sizeof (edge_iterator) * ((((cfun + 0))->cfg->x_n_basic_blocks) + 1))); |
840 | sp = 0; |
841 | |
842 | /* Push the first edge on to the stack. */ |
843 | stack[sp++] = ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)ei_start_1 (&((((cfun + 0))->cfg->x_entry_block_ptr )->succs)); |
844 | |
845 | while (sp) |
846 | { |
847 | edge_iterator ei; |
848 | basic_block src; |
849 | basic_block dest; |
850 | |
851 | /* Look at the edge on the top of the stack. */ |
852 | ei = stack[sp - 1]; |
853 | src = ei_edge (ei)->src; |
854 | dest = ei_edge (ei)->dest; |
855 | |
856 | /* Check if the edge destination has been visited yet. */ |
857 | if (!VTI (dest)((variable_tracking_info *) (dest)->aux)->visited) |
858 | { |
859 | rtx_insn *insn; |
860 | HOST_WIDE_INTlong pre, post, offset; |
861 | VTI (dest)((variable_tracking_info *) (dest)->aux)->visited = true; |
862 | VTI (dest)((variable_tracking_info *) (dest)->aux)->in.stack_adjust = offset = VTI (src)((variable_tracking_info *) (src)->aux)->out.stack_adjust; |
863 | |
864 | if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)(((cfun + 0))->cfg->x_exit_block_ptr)) |
865 | for (insn = BB_HEAD (dest)(dest)->il.x.head_; |
866 | insn != NEXT_INSN (BB_END (dest)(dest)->il.x.rtl->end_); |
867 | insn = NEXT_INSN (insn)) |
868 | if (INSN_P (insn)(((((enum rtx_code) (insn)->code) == INSN) || (((enum rtx_code ) (insn)->code) == JUMP_INSN) || (((enum rtx_code) (insn)-> code) == CALL_INSN)) || (((enum rtx_code) (insn)->code) == DEBUG_INSN))) |
869 | { |
870 | insn_stack_adjust_offset_pre_post (insn, &pre, &post); |
871 | offset += pre + post; |
872 | } |
873 | |
874 | VTI (dest)((variable_tracking_info *) (dest)->aux)->out.stack_adjust = offset; |
875 | |
876 | if (EDGE_COUNT (dest->succs)vec_safe_length (dest->succs) > 0) |
877 | /* Since the DEST node has been visited for the first |
878 | time, check its successors. */ |
879 | stack[sp++] = ei_start (dest->succs)ei_start_1 (&(dest->succs)); |
880 | } |
881 | else |
882 | { |
883 | /* We can end up with different stack adjustments for the exit block |
884 | of a shrink-wrapped function if stack_adjust_offset_pre_post |
885 | doesn't understand the rtx pattern used to restore the stack |
886 | pointer in the epilogue. For example, on s390(x), the stack |
887 | pointer is often restored via a load-multiple instruction |
888 | and so no stack_adjust offset is recorded for it. This means |
889 | that the stack offset at the end of the epilogue block is the |
890 | same as the offset before the epilogue, whereas other paths |
891 | to the exit block will have the correct stack_adjust. |
892 | |
893 | It is safe to ignore these differences because (a) we never |
894 | use the stack_adjust for the exit block in this pass and |
895 | (b) dwarf2cfi checks whether the CFA notes in a shrink-wrapped |
896 | function are correct. |
897 | |
898 | We must check whether the adjustments on other edges are |
899 | the same though. */ |
900 | if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun)(((cfun + 0))->cfg->x_exit_block_ptr) |
901 | && VTI (dest)((variable_tracking_info *) (dest)->aux)->in.stack_adjust != VTI (src)((variable_tracking_info *) (src)->aux)->out.stack_adjust) |
902 | { |
903 | free (stack); |
904 | return false; |
905 | } |
906 | |
907 | if (! ei_one_before_end_p (ei)) |
908 | /* Go to the next edge. */ |
909 | ei_next (&stack[sp - 1]); |
910 | else |
911 | /* Return to previous level if there are no more edges. */ |
912 | sp--; |
913 | } |
914 | } |
915 | |
916 | free (stack); |
917 | return true; |
918 | } |
919 | |
920 | /* arg_pointer_rtx resp. frame_pointer_rtx if stack_pointer_rtx or |
921 | hard_frame_pointer_rtx is being mapped to it and offset for it. */ |
922 | static rtx cfa_base_rtx; |
923 | static HOST_WIDE_INTlong cfa_base_offset; |
924 | |
925 | /* Compute a CFA-based value for an ADJUSTMENT made to stack_pointer_rtx |
926 | or hard_frame_pointer_rtx. */ |
927 | |
928 | static inline rtx |
929 | compute_cfa_pointer (poly_int64 adjustment) |
930 | { |
931 | return plus_constant (Pmode(global_options.x_ix86_pmode == PMODE_DI ? (scalar_int_mode ( (scalar_int_mode::from_int) E_DImode)) : (scalar_int_mode ((scalar_int_mode ::from_int) E_SImode))), cfa_base_rtx, adjustment + cfa_base_offset); |
932 | } |
933 | |
934 | /* Adjustment for hard_frame_pointer_rtx to cfa base reg, |
935 | or -1 if the replacement shouldn't be done. */ |
936 | static poly_int64 hard_frame_pointer_adjustment = -1; |
937 | |
938 | /* Data for adjust_mems callback. */ |
939 | |
940 | class adjust_mem_data |
941 | { |
942 | public: |
943 | bool store; |
944 | machine_mode mem_mode; |
945 | HOST_WIDE_INTlong stack_adjust; |
946 | auto_vec<rtx> side_effects; |
947 | }; |
948 | |
949 | /* Helper for adjust_mems. Return true if X is suitable for |
950 | transformation of wider mode arithmetics to narrower mode. */ |
951 | |
952 | static bool |
953 | use_narrower_mode_test (rtx x, const_rtx subreg) |
954 | { |
955 | subrtx_var_iterator::array_type array; |
956 | FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST)for (subrtx_var_iterator iter (array, x, rtx_nonconst_subrtx_bounds ); !iter.at_end (); iter.next ()) |
957 | { |
958 | rtx x = *iter; |
959 | if (CONSTANT_P (x)((rtx_class[(int) (((enum rtx_code) (x)->code))]) == RTX_CONST_OBJ )) |
960 | iter.skip_subrtxes (); |
961 | else |
962 | switch (GET_CODE (x)((enum rtx_code) (x)->code)) |
963 | { |
964 | case REG: |
965 | if (cselib_lookup (x, GET_MODE (SUBREG_REG (subreg))((machine_mode) ((((subreg)->u.fld[0]).rt_rtx))->mode), 0, VOIDmode((void) 0, E_VOIDmode))) |
966 | return false; |
967 | if (!validate_subreg (GET_MODE (subreg)((machine_mode) (subreg)->mode), GET_MODE (x)((machine_mode) (x)->mode), x, |
968 | subreg_lowpart_offset (GET_MODE (subreg)((machine_mode) (subreg)->mode), |
969 | GET_MODE (x)((machine_mode) (x)->mode)))) |
970 | return false; |
971 | break; |
972 | case PLUS: |
973 | case MINUS: |
974 | case MULT: |
975 | break; |
976 | case ASHIFT: |
977 | if (GET_MODE (XEXP (x, 1))((machine_mode) ((((x)->u.fld[1]).rt_rtx))->mode) != VOIDmode((void) 0, E_VOIDmode)) |
978 | { |
979 | enum machine_mode mode = GET_MODE (subreg)((machine_mode) (subreg)->mode); |
980 | rtx op1 = XEXP (x, 1)(((x)->u.fld[1]).rt_rtx); |
981 | enum machine_mode op1_mode = GET_MODE (op1)((machine_mode) (op1)->mode); |
982 | if (GET_MODE_PRECISION (as_a <scalar_int_mode> (mode)) |
983 | < GET_MODE_PRECISION (as_a <scalar_int_mode> (op1_mode))) |
984 | { |
985 | poly_uint64 byte = subreg_lowpart_offset (mode, op1_mode); |
986 | if (GET_CODE (op1)((enum rtx_code) (op1)->code) == SUBREG || GET_CODE (op1)((enum rtx_code) (op1)->code) == CONCAT) |
987 | { |
988 | if (!simplify_subreg (mode, op1, op1_mode, byte)) |
989 | return false; |
990 | } |
991 | else if (!validate_subreg (mode, op1_mode, op1, byte)) |
992 | return false; |
993 | } |
994 | } |
995 | iter.substitute (XEXP (x, 0)(((x)->u.fld[0]).rt_rtx)); |
996 | break; |
997 | default: |
998 | return false; |
999 | } |
1000 | } |
1001 | return true; |
1002 | } |
1003 | |
1004 | /* Transform X into narrower mode MODE from wider mode WMODE. */ |
1005 | |
1006 | static rtx |
1007 | use_narrower_mode (rtx x, scalar_int_mode mode, scalar_int_mode wmode) |
1008 | { |
1009 | rtx op0, op1; |
1010 | if (CONSTANT_P (x)((rtx_class[(int) (((enum rtx_code) (x)->code))]) == RTX_CONST_OBJ )) |
1011 | return lowpart_subreg (mode, x, wmode); |
1012 | switch (GET_CODE (x)((enum rtx_code) (x)->code)) |
1013 | { |
1014 | case REG: |
1015 | return lowpart_subreg (mode, x, wmode); |
1016 | case PLUS: |
1017 | case MINUS: |
1018 | case MULT: |
1019 | op0 = use_narrower_mode (XEXP (x, 0)(((x)->u.fld[0]).rt_rtx), mode, wmode); |
1020 | op1 = use_narrower_mode (XEXP (x, 1)(((x)->u.fld[1]).rt_rtx), mode, wmode); |
1021 | return simplify_gen_binary (GET_CODE (x)((enum rtx_code) (x)->code), mode, op0, op1); |
1022 | case ASHIFT: |
1023 | op0 = use_narrower_mode (XEXP (x, 0)(((x)->u.fld[0]).rt_rtx), mode, wmode); |
1024 | op1 = XEXP (x, 1)(((x)->u.fld[1]).rt_rtx); |
1025 | /* Ensure shift amount is not wider than mode. */ |
1026 | if (GET_MODE (op1)((machine_mode) (op1)->mode) == VOIDmode((void) 0, E_VOIDmode)) |
1027 | op1 = lowpart_subreg (mode, op1, wmode); |
1028 | else if (GET_MODE_PRECISION (mode) |
1029 | < GET_MODE_PRECISION (as_a <scalar_int_mode> (GET_MODE (op1)((machine_mode) (op1)->mode)))) |
1030 | op1 = lowpart_subreg (mode, op1, GET_MODE (op1)((machine_mode) (op1)->mode)); |
1031 | return simplify_gen_binary (ASHIFT, mode, op0, op1); |
1032 | default: |
1033 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1033, __FUNCTION__)); |
1034 | } |
1035 | } |
1036 | |
1037 | /* Helper function for adjusting used MEMs. */ |
1038 | |
1039 | static rtx |
1040 | adjust_mems (rtx loc, const_rtx old_rtx, void *data) |
1041 | { |
1042 | class adjust_mem_data *amd = (class adjust_mem_data *) data; |
1043 | rtx mem, addr = loc, tem; |
1044 | machine_mode mem_mode_save; |
1045 | bool store_save; |
1046 | scalar_int_mode tem_mode, tem_subreg_mode; |
1047 | poly_int64 size; |
1048 | switch (GET_CODE (loc)((enum rtx_code) (loc)->code)) |
1049 | { |
1050 | case REG: |
1051 | /* Don't do any sp or fp replacements outside of MEM addresses |
1052 | on the LHS. */ |
1053 | if (amd->mem_mode == VOIDmode((void) 0, E_VOIDmode) && amd->store) |
1054 | return loc; |
1055 | if (loc == stack_pointer_rtx((this_target_rtl->x_global_rtl)[GR_STACK_POINTER]) |
1056 | && !frame_pointer_needed((&x_rtl)->frame_pointer_needed) |
1057 | && cfa_base_rtx) |
1058 | return compute_cfa_pointer (amd->stack_adjust); |
1059 | else if (loc == hard_frame_pointer_rtx((this_target_rtl->x_global_rtl)[GR_HARD_FRAME_POINTER]) |
1060 | && frame_pointer_needed((&x_rtl)->frame_pointer_needed) |
1061 | && maybe_ne (hard_frame_pointer_adjustment, -1) |
1062 | && cfa_base_rtx) |
1063 | return compute_cfa_pointer (hard_frame_pointer_adjustment); |
1064 | gcc_checking_assert (loc != virtual_incoming_args_rtx)((void)(!(loc != ((this_target_rtl->x_global_rtl)[GR_VIRTUAL_INCOMING_ARGS ])) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1064, __FUNCTION__), 0 : 0)); |
1065 | return loc; |
1066 | case MEM: |
1067 | mem = loc; |
1068 | if (!amd->store) |
1069 | { |
1070 | mem = targetm.delegitimize_address (mem); |
1071 | if (mem != loc && !MEM_P (mem)(((enum rtx_code) (mem)->code) == MEM)) |
1072 | return simplify_replace_fn_rtx (mem, old_rtx, adjust_mems, data); |
1073 | } |
1074 | |
1075 | addr = XEXP (mem, 0)(((mem)->u.fld[0]).rt_rtx); |
1076 | mem_mode_save = amd->mem_mode; |
1077 | amd->mem_mode = GET_MODE (mem)((machine_mode) (mem)->mode); |
1078 | store_save = amd->store; |
1079 | amd->store = false; |
1080 | addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); |
1081 | amd->store = store_save; |
1082 | amd->mem_mode = mem_mode_save; |
1083 | if (mem == loc) |
1084 | addr = targetm.delegitimize_address (addr); |
1085 | if (addr != XEXP (mem, 0)(((mem)->u.fld[0]).rt_rtx)) |
1086 | mem = replace_equiv_address_nv (mem, addr); |
1087 | if (!amd->store) |
1088 | mem = avoid_constant_pool_reference (mem); |
1089 | return mem; |
1090 | case PRE_INC: |
1091 | case PRE_DEC: |
1092 | size = GET_MODE_SIZE (amd->mem_mode); |
1093 | addr = plus_constant (GET_MODE (loc)((machine_mode) (loc)->mode), XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx), |
1094 | GET_CODE (loc)((enum rtx_code) (loc)->code) == PRE_INC ? size : -size); |
1095 | /* FALLTHRU */ |
1096 | case POST_INC: |
1097 | case POST_DEC: |
1098 | if (addr == loc) |
1099 | addr = XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx); |
1100 | gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode)((void)(!(amd->mem_mode != ((void) 0, E_VOIDmode) && amd->mem_mode != ((void) 0, E_BLKmode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1100, __FUNCTION__), 0 : 0)); |
1101 | addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); |
1102 | size = GET_MODE_SIZE (amd->mem_mode); |
1103 | tem = plus_constant (GET_MODE (loc)((machine_mode) (loc)->mode), XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx), |
1104 | (GET_CODE (loc)((enum rtx_code) (loc)->code) == PRE_INC |
1105 | || GET_CODE (loc)((enum rtx_code) (loc)->code) == POST_INC) ? size : -size); |
1106 | store_save = amd->store; |
1107 | amd->store = false; |
1108 | tem = simplify_replace_fn_rtx (tem, old_rtx, adjust_mems, data); |
1109 | amd->store = store_save; |
1110 | amd->side_effects.safe_push (gen_rtx_SET (XEXP (loc, 0), tem)gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), (((((loc )->u.fld[0]).rt_rtx))), ((tem)) )); |
1111 | return addr; |
1112 | case PRE_MODIFY: |
1113 | addr = XEXP (loc, 1)(((loc)->u.fld[1]).rt_rtx); |
1114 | /* FALLTHRU */ |
1115 | case POST_MODIFY: |
1116 | if (addr == loc) |
1117 | addr = XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx); |
1118 | gcc_assert (amd->mem_mode != VOIDmode)((void)(!(amd->mem_mode != ((void) 0, E_VOIDmode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1118, __FUNCTION__), 0 : 0)); |
1119 | addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); |
1120 | store_save = amd->store; |
1121 | amd->store = false; |
1122 | tem = simplify_replace_fn_rtx (XEXP (loc, 1)(((loc)->u.fld[1]).rt_rtx), old_rtx, |
1123 | adjust_mems, data); |
1124 | amd->store = store_save; |
1125 | amd->side_effects.safe_push (gen_rtx_SET (XEXP (loc, 0), tem)gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), (((((loc )->u.fld[0]).rt_rtx))), ((tem)) )); |
1126 | return addr; |
1127 | case SUBREG: |
1128 | /* First try without delegitimization of whole MEMs and |
1129 | avoid_constant_pool_reference, which is more likely to succeed. */ |
1130 | store_save = amd->store; |
1131 | amd->store = true; |
1132 | addr = simplify_replace_fn_rtx (SUBREG_REG (loc)(((loc)->u.fld[0]).rt_rtx), old_rtx, adjust_mems, |
1133 | data); |
1134 | amd->store = store_save; |
1135 | mem = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data); |
1136 | if (mem == SUBREG_REG (loc)(((loc)->u.fld[0]).rt_rtx)) |
1137 | { |
1138 | tem = loc; |
1139 | goto finish_subreg; |
1140 | } |
1141 | tem = simplify_gen_subreg (GET_MODE (loc)((machine_mode) (loc)->mode), mem, |
1142 | GET_MODE (SUBREG_REG (loc))((machine_mode) ((((loc)->u.fld[0]).rt_rtx))->mode), |
1143 | SUBREG_BYTE (loc)(((loc)->u.fld[1]).rt_subreg)); |
1144 | if (tem) |
1145 | goto finish_subreg; |
1146 | tem = simplify_gen_subreg (GET_MODE (loc)((machine_mode) (loc)->mode), addr, |
1147 | GET_MODE (SUBREG_REG (loc))((machine_mode) ((((loc)->u.fld[0]).rt_rtx))->mode), |
1148 | SUBREG_BYTE (loc)(((loc)->u.fld[1]).rt_subreg)); |
1149 | if (tem == NULL_RTX(rtx) 0) |
1150 | tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc))gen_rtx_fmt_ep_stat ((SUBREG), ((((machine_mode) (loc)->mode ))), ((addr)), (((((loc)->u.fld[1]).rt_subreg))) ); |
1151 | finish_subreg: |
1152 | if (MAY_HAVE_DEBUG_BIND_INSNSglobal_options.x_flag_var_tracking_assignments |
1153 | && GET_CODE (tem)((enum rtx_code) (tem)->code) == SUBREG |
1154 | && (GET_CODE (SUBREG_REG (tem))((enum rtx_code) ((((tem)->u.fld[0]).rt_rtx))->code) == PLUS |
1155 | || GET_CODE (SUBREG_REG (tem))((enum rtx_code) ((((tem)->u.fld[0]).rt_rtx))->code) == MINUS |
1156 | || GET_CODE (SUBREG_REG (tem))((enum rtx_code) ((((tem)->u.fld[0]).rt_rtx))->code) == MULT |
1157 | || GET_CODE (SUBREG_REG (tem))((enum rtx_code) ((((tem)->u.fld[0]).rt_rtx))->code) == ASHIFT) |
1158 | && is_a <scalar_int_mode> (GET_MODE (tem)((machine_mode) (tem)->mode), &tem_mode) |
1159 | && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (tem))((machine_mode) ((((tem)->u.fld[0]).rt_rtx))->mode), |
1160 | &tem_subreg_mode) |
1161 | && (GET_MODE_PRECISION (tem_mode) |
1162 | < GET_MODE_PRECISION (tem_subreg_mode)) |
1163 | && subreg_lowpart_p (tem) |
1164 | && use_narrower_mode_test (SUBREG_REG (tem)(((tem)->u.fld[0]).rt_rtx), tem)) |
1165 | return use_narrower_mode (SUBREG_REG (tem)(((tem)->u.fld[0]).rt_rtx), tem_mode, tem_subreg_mode); |
1166 | return tem; |
1167 | case ASM_OPERANDS: |
1168 | /* Don't do any replacements in second and following |
1169 | ASM_OPERANDS of inline-asm with multiple sets. |
1170 | ASM_OPERANDS_INPUT_VEC, ASM_OPERANDS_INPUT_CONSTRAINT_VEC |
1171 | and ASM_OPERANDS_LABEL_VEC need to be equal between |
1172 | all the ASM_OPERANDs in the insn and adjust_insn will |
1173 | fix this up. */ |
1174 | if (ASM_OPERANDS_OUTPUT_IDX (loc)(((loc)->u.fld[2]).rt_int) != 0) |
1175 | return loc; |
1176 | break; |
1177 | default: |
1178 | break; |
1179 | } |
1180 | return NULL_RTX(rtx) 0; |
1181 | } |
1182 | |
1183 | /* Helper function for replacement of uses. */ |
1184 | |
1185 | static void |
1186 | adjust_mem_uses (rtx *x, void *data) |
1187 | { |
1188 | rtx new_x = simplify_replace_fn_rtx (*x, NULL_RTX(rtx) 0, adjust_mems, data); |
1189 | if (new_x != *x) |
1190 | validate_change (NULL_RTX(rtx) 0, x, new_x, true); |
1191 | } |
1192 | |
1193 | /* Helper function for replacement of stores. */ |
1194 | |
1195 | static void |
1196 | adjust_mem_stores (rtx loc, const_rtx expr, void *data) |
1197 | { |
1198 | if (MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
1199 | { |
1200 | rtx new_dest = simplify_replace_fn_rtx (SET_DEST (expr)(((expr)->u.fld[0]).rt_rtx), NULL_RTX(rtx) 0, |
1201 | adjust_mems, data); |
1202 | if (new_dest != SET_DEST (expr)(((expr)->u.fld[0]).rt_rtx)) |
1203 | { |
1204 | rtx xexpr = CONST_CAST_RTX (expr)(const_cast<struct rtx_def *> (((expr)))); |
1205 | validate_change (NULL_RTX(rtx) 0, &SET_DEST (xexpr)(((xexpr)->u.fld[0]).rt_rtx), new_dest, true); |
1206 | } |
1207 | } |
1208 | } |
1209 | |
1210 | /* Simplify INSN. Remove all {PRE,POST}_{INC,DEC,MODIFY} rtxes, |
1211 | replace them with their value in the insn and add the side-effects |
1212 | as other sets to the insn. */ |
1213 | |
1214 | static void |
1215 | adjust_insn (basic_block bb, rtx_insn *insn) |
1216 | { |
1217 | rtx set; |
1218 | |
1219 | #ifdef HAVE_window_save |
1220 | /* If the target machine has an explicit window save instruction, the |
1221 | transformation OUTGOING_REGNO -> INCOMING_REGNO is done there. */ |
1222 | if (RTX_FRAME_RELATED_P (insn)(__extension__ ({ __typeof ((insn)) const _rtx = ((insn)); if (((enum rtx_code) (_rtx)->code) != DEBUG_INSN && ( (enum rtx_code) (_rtx)->code) != INSN && ((enum rtx_code ) (_rtx)->code) != CALL_INSN && ((enum rtx_code) ( _rtx)->code) != JUMP_INSN && ((enum rtx_code) (_rtx )->code) != BARRIER && ((enum rtx_code) (_rtx)-> code) != SET) rtl_check_failed_flag ("RTX_FRAME_RELATED_P",_rtx , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1222, __FUNCTION__); _rtx; })->frame_related) |
1223 | && find_reg_note (insn, REG_CFA_WINDOW_SAVE, NULL_RTX(rtx) 0)) |
1224 | { |
1225 | unsigned int i, nregs = vec_safe_length (windowed_parm_regs); |
1226 | rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2))gen_rtx_fmt_E_stat ((PARALLEL), ((((void) 0, E_VOIDmode))), ( (rtvec_alloc (nregs * 2))) ); |
1227 | parm_reg *p; |
1228 | |
1229 | FOR_EACH_VEC_SAFE_ELT (windowed_parm_regs, i, p)for (i = 0; vec_safe_iterate ((windowed_parm_regs), (i), & (p)); ++(i)) |
1230 | { |
1231 | XVECEXP (rtl, 0, i * 2)(((((rtl)->u.fld[0]).rt_rtvec))->elem[i * 2]) |
1232 | = gen_rtx_SET (p->incoming, p->outgoing)gen_rtx_fmt_ee_stat ((SET), (((void) 0, E_VOIDmode)), ((p-> incoming)), ((p->outgoing)) ); |
1233 | /* Do not clobber the attached DECL, but only the REG. */ |
1234 | XVECEXP (rtl, 0, i * 2 + 1)(((((rtl)->u.fld[0]).rt_rtvec))->elem[i * 2 + 1]) |
1235 | = gen_rtx_CLOBBER (GET_MODE (p->outgoing),gen_rtx_fmt_e_stat ((CLOBBER), ((((machine_mode) (p->outgoing )->mode))), ((gen_raw_REG (((machine_mode) (p->outgoing )->mode), (rhs_regno(p->outgoing))))) ) |
1236 | gen_raw_REG (GET_MODE (p->outgoing),gen_rtx_fmt_e_stat ((CLOBBER), ((((machine_mode) (p->outgoing )->mode))), ((gen_raw_REG (((machine_mode) (p->outgoing )->mode), (rhs_regno(p->outgoing))))) ) |
1237 | REGNO (p->outgoing)))gen_rtx_fmt_e_stat ((CLOBBER), ((((machine_mode) (p->outgoing )->mode))), ((gen_raw_REG (((machine_mode) (p->outgoing )->mode), (rhs_regno(p->outgoing))))) ); |
1238 | } |
1239 | |
1240 | validate_change (NULL_RTX(rtx) 0, &PATTERN (insn), rtl, true); |
1241 | return; |
1242 | } |
1243 | #endif |
1244 | |
1245 | adjust_mem_data amd; |
1246 | amd.mem_mode = VOIDmode((void) 0, E_VOIDmode); |
1247 | amd.stack_adjust = -VTI (bb)((variable_tracking_info *) (bb)->aux)->out.stack_adjust; |
1248 | |
1249 | amd.store = true; |
1250 | note_stores (insn, adjust_mem_stores, &amd); |
1251 | |
1252 | amd.store = false; |
1253 | if (GET_CODE (PATTERN (insn))((enum rtx_code) (PATTERN (insn))->code) == PARALLEL |
1254 | && asm_noperands (PATTERN (insn)) > 0 |
1255 | && GET_CODE (XVECEXP (PATTERN (insn), 0, 0))((enum rtx_code) ((((((PATTERN (insn))->u.fld[0]).rt_rtvec ))->elem[0]))->code) == SET) |
1256 | { |
1257 | rtx body, set0; |
1258 | int i; |
1259 | |
1260 | /* inline-asm with multiple sets is tiny bit more complicated, |
1261 | because the 3 vectors in ASM_OPERANDS need to be shared between |
1262 | all ASM_OPERANDS in the instruction. adjust_mems will |
1263 | not touch ASM_OPERANDS other than the first one, asm_noperands |
1264 | test above needs to be called before that (otherwise it would fail) |
1265 | and afterwards this code fixes it up. */ |
1266 | note_uses (&PATTERN (insn), adjust_mem_uses, &amd); |
1267 | body = PATTERN (insn); |
1268 | set0 = XVECEXP (body, 0, 0)(((((body)->u.fld[0]).rt_rtvec))->elem[0]); |
1269 | gcc_checking_assert (GET_CODE (set0) == SET((void)(!(((enum rtx_code) (set0)->code) == SET && ((enum rtx_code) ((((set0)->u.fld[1]).rt_rtx))->code) == ASM_OPERANDS && ((((((set0)->u.fld[1]).rt_rtx))-> u.fld[2]).rt_int) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1271, __FUNCTION__), 0 : 0)) |
1270 | && GET_CODE (SET_SRC (set0)) == ASM_OPERANDS((void)(!(((enum rtx_code) (set0)->code) == SET && ((enum rtx_code) ((((set0)->u.fld[1]).rt_rtx))->code) == ASM_OPERANDS && ((((((set0)->u.fld[1]).rt_rtx))-> u.fld[2]).rt_int) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1271, __FUNCTION__), 0 : 0)) |
1271 | && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set0)) == 0)((void)(!(((enum rtx_code) (set0)->code) == SET && ((enum rtx_code) ((((set0)->u.fld[1]).rt_rtx))->code) == ASM_OPERANDS && ((((((set0)->u.fld[1]).rt_rtx))-> u.fld[2]).rt_int) == 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1271, __FUNCTION__), 0 : 0)); |
1272 | for (i = 1; i < XVECLEN (body, 0)(((((body)->u.fld[0]).rt_rtvec))->num_elem); i++) |
1273 | if (GET_CODE (XVECEXP (body, 0, i))((enum rtx_code) ((((((body)->u.fld[0]).rt_rtvec))->elem [i]))->code) != SET) |
1274 | break; |
1275 | else |
1276 | { |
1277 | set = XVECEXP (body, 0, i)(((((body)->u.fld[0]).rt_rtvec))->elem[i]); |
1278 | gcc_checking_assert (GET_CODE (SET_SRC (set)) == ASM_OPERANDS((void)(!(((enum rtx_code) ((((set)->u.fld[1]).rt_rtx))-> code) == ASM_OPERANDS && ((((((set)->u.fld[1]).rt_rtx ))->u.fld[2]).rt_int) == i) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1280, __FUNCTION__), 0 : 0)) |
1279 | && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set))((void)(!(((enum rtx_code) ((((set)->u.fld[1]).rt_rtx))-> code) == ASM_OPERANDS && ((((((set)->u.fld[1]).rt_rtx ))->u.fld[2]).rt_int) == i) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1280, __FUNCTION__), 0 : 0)) |
1280 | == i)((void)(!(((enum rtx_code) ((((set)->u.fld[1]).rt_rtx))-> code) == ASM_OPERANDS && ((((((set)->u.fld[1]).rt_rtx ))->u.fld[2]).rt_int) == i) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1280, __FUNCTION__), 0 : 0)); |
1281 | if (ASM_OPERANDS_INPUT_VEC (SET_SRC (set))((((((set)->u.fld[1]).rt_rtx))->u.fld[3]).rt_rtvec) |
1282 | != ASM_OPERANDS_INPUT_VEC (SET_SRC (set0))((((((set0)->u.fld[1]).rt_rtx))->u.fld[3]).rt_rtvec) |
1283 | || ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set))((((((set)->u.fld[1]).rt_rtx))->u.fld[4]).rt_rtvec) |
1284 | != ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0))((((((set0)->u.fld[1]).rt_rtx))->u.fld[4]).rt_rtvec) |
1285 | || ASM_OPERANDS_LABEL_VEC (SET_SRC (set))((((((set)->u.fld[1]).rt_rtx))->u.fld[5]).rt_rtvec) |
1286 | != ASM_OPERANDS_LABEL_VEC (SET_SRC (set0))((((((set0)->u.fld[1]).rt_rtx))->u.fld[5]).rt_rtvec)) |
1287 | { |
1288 | rtx newsrc = shallow_copy_rtx (SET_SRC (set)(((set)->u.fld[1]).rt_rtx)); |
1289 | ASM_OPERANDS_INPUT_VEC (newsrc)(((newsrc)->u.fld[3]).rt_rtvec) |
1290 | = ASM_OPERANDS_INPUT_VEC (SET_SRC (set0))((((((set0)->u.fld[1]).rt_rtx))->u.fld[3]).rt_rtvec); |
1291 | ASM_OPERANDS_INPUT_CONSTRAINT_VEC (newsrc)(((newsrc)->u.fld[4]).rt_rtvec) |
1292 | = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0))((((((set0)->u.fld[1]).rt_rtx))->u.fld[4]).rt_rtvec); |
1293 | ASM_OPERANDS_LABEL_VEC (newsrc)(((newsrc)->u.fld[5]).rt_rtvec) |
1294 | = ASM_OPERANDS_LABEL_VEC (SET_SRC (set0))((((((set0)->u.fld[1]).rt_rtx))->u.fld[5]).rt_rtvec); |
1295 | validate_change (NULL_RTX(rtx) 0, &SET_SRC (set)(((set)->u.fld[1]).rt_rtx), newsrc, true); |
1296 | } |
1297 | } |
1298 | } |
1299 | else |
1300 | note_uses (&PATTERN (insn), adjust_mem_uses, &amd); |
1301 | |
1302 | /* For read-only MEMs containing some constant, prefer those |
1303 | constants. */ |
1304 | set = single_set (insn); |
1305 | if (set && MEM_P (SET_SRC (set))(((enum rtx_code) ((((set)->u.fld[1]).rt_rtx))->code) == MEM) && MEM_READONLY_P (SET_SRC (set))(__extension__ ({ __typeof (((((set)->u.fld[1]).rt_rtx))) const _rtx = (((((set)->u.fld[1]).rt_rtx))); if (((enum rtx_code ) (_rtx)->code) != MEM) rtl_check_failed_flag ("MEM_READONLY_P" , _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1305, __FUNCTION__); _rtx; })->unchanging)) |
1306 | { |
1307 | rtx note = find_reg_equal_equiv_note (insn); |
1308 | |
1309 | if (note && CONSTANT_P (XEXP (note, 0))((rtx_class[(int) (((enum rtx_code) ((((note)->u.fld[0]).rt_rtx ))->code))]) == RTX_CONST_OBJ)) |
1310 | validate_change (NULL_RTX(rtx) 0, &SET_SRC (set)(((set)->u.fld[1]).rt_rtx), XEXP (note, 0)(((note)->u.fld[0]).rt_rtx), true); |
1311 | } |
1312 | |
1313 | if (!amd.side_effects.is_empty ()) |
1314 | { |
1315 | rtx *pat, new_pat; |
1316 | int i, oldn; |
1317 | |
1318 | pat = &PATTERN (insn); |
1319 | if (GET_CODE (*pat)((enum rtx_code) (*pat)->code) == COND_EXEC) |
1320 | pat = &COND_EXEC_CODE (*pat)(((*pat)->u.fld[1]).rt_rtx); |
1321 | if (GET_CODE (*pat)((enum rtx_code) (*pat)->code) == PARALLEL) |
1322 | oldn = XVECLEN (*pat, 0)(((((*pat)->u.fld[0]).rt_rtvec))->num_elem); |
1323 | else |
1324 | oldn = 1; |
1325 | unsigned int newn = amd.side_effects.length (); |
1326 | new_pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (oldn + newn))gen_rtx_fmt_E_stat ((PARALLEL), ((((void) 0, E_VOIDmode))), ( (rtvec_alloc (oldn + newn))) ); |
1327 | if (GET_CODE (*pat)((enum rtx_code) (*pat)->code) == PARALLEL) |
1328 | for (i = 0; i < oldn; i++) |
1329 | XVECEXP (new_pat, 0, i)(((((new_pat)->u.fld[0]).rt_rtvec))->elem[i]) = XVECEXP (*pat, 0, i)(((((*pat)->u.fld[0]).rt_rtvec))->elem[i]); |
1330 | else |
1331 | XVECEXP (new_pat, 0, 0)(((((new_pat)->u.fld[0]).rt_rtvec))->elem[0]) = *pat; |
1332 | |
1333 | rtx effect; |
1334 | unsigned int j; |
1335 | FOR_EACH_VEC_ELT_REVERSE (amd.side_effects, j, effect)for (j = (amd.side_effects).length () - 1; (amd.side_effects) .iterate ((j), &(effect)); (j)--) |
1336 | XVECEXP (new_pat, 0, j + oldn)(((((new_pat)->u.fld[0]).rt_rtvec))->elem[j + oldn]) = effect; |
1337 | validate_change (NULL_RTX(rtx) 0, pat, new_pat, true); |
1338 | } |
1339 | } |
1340 | |
1341 | /* Return the DEBUG_EXPR of a DEBUG_EXPR_DECL or the VALUE in DV. */ |
1342 | static inline rtx |
1343 | dv_as_rtx (decl_or_value dv) |
1344 | { |
1345 | tree decl; |
1346 | |
1347 | if (dv_is_value_p (dv)) |
1348 | return dv_as_value (dv); |
1349 | |
1350 | decl = dv_as_decl (dv); |
1351 | |
1352 | gcc_checking_assert (TREE_CODE (decl) == DEBUG_EXPR_DECL)((void)(!(((enum tree_code) (decl)->base.code) == DEBUG_EXPR_DECL ) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1352, __FUNCTION__), 0 : 0)); |
1353 | return DECL_RTL_KNOWN_SET (decl)__extension__ ({ tree const __d = (decl); ((void)(!((((tree_contains_struct [(((enum tree_code) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1353, __FUNCTION__))->decl_with_rtl.rtl != nullptr)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1353, __FUNCTION__), 0 : 0)); &*((((tree_contains_struct [(((enum tree_code) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1353, __FUNCTION__))->decl_with_rtl.rtl != nullptr) ? (( contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1353, __FUNCTION__))->decl_with_rtl.rtl ? (__d)->decl_with_rtl .rtl : (make_decl_rtl (__d), (__d)->decl_with_rtl.rtl)) : nullptr ); }); |
1354 | } |
1355 | |
1356 | /* Return nonzero if a decl_or_value must not have more than one |
1357 | variable part. The returned value discriminates among various |
1358 | kinds of one-part DVs ccording to enum onepart_enum. */ |
1359 | static inline onepart_enum |
1360 | dv_onepart_p (decl_or_value dv) |
1361 | { |
1362 | tree decl; |
1363 | |
1364 | if (!MAY_HAVE_DEBUG_BIND_INSNSglobal_options.x_flag_var_tracking_assignments) |
1365 | return NOT_ONEPART; |
1366 | |
1367 | if (dv_is_value_p (dv)) |
1368 | return ONEPART_VALUE; |
1369 | |
1370 | decl = dv_as_decl (dv); |
1371 | |
1372 | if (TREE_CODE (decl)((enum tree_code) (decl)->base.code) == DEBUG_EXPR_DECL) |
1373 | return ONEPART_DEXPR; |
1374 | |
1375 | if (target_for_debug_bind (decl) != NULL_TREE(tree) nullptr) |
1376 | return ONEPART_VDECL; |
1377 | |
1378 | return NOT_ONEPART; |
1379 | } |
1380 | |
1381 | /* Return the variable pool to be used for a dv of type ONEPART. */ |
1382 | static inline pool_allocator & |
1383 | onepart_pool (onepart_enum onepart) |
1384 | { |
1385 | return onepart ? valvar_pool : var_pool; |
1386 | } |
1387 | |
1388 | /* Allocate a variable_def from the corresponding variable pool. */ |
1389 | static inline variable * |
1390 | onepart_pool_allocate (onepart_enum onepart) |
1391 | { |
1392 | return (variable*) onepart_pool (onepart).allocate (); |
1393 | } |
1394 | |
1395 | /* Build a decl_or_value out of a decl. */ |
1396 | static inline decl_or_value |
1397 | dv_from_decl (tree decl) |
1398 | { |
1399 | decl_or_value dv; |
1400 | dv = decl; |
1401 | gcc_checking_assert (dv_is_decl_p (dv))((void)(!(dv_is_decl_p (dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1401, __FUNCTION__), 0 : 0)); |
1402 | return dv; |
1403 | } |
1404 | |
1405 | /* Build a decl_or_value out of a value. */ |
1406 | static inline decl_or_value |
1407 | dv_from_value (rtx value) |
1408 | { |
1409 | decl_or_value dv; |
1410 | dv = value; |
1411 | gcc_checking_assert (dv_is_value_p (dv))((void)(!(dv_is_value_p (dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1411, __FUNCTION__), 0 : 0)); |
1412 | return dv; |
1413 | } |
1414 | |
1415 | /* Return a value or the decl of a debug_expr as a decl_or_value. */ |
1416 | static inline decl_or_value |
1417 | dv_from_rtx (rtx x) |
1418 | { |
1419 | decl_or_value dv; |
1420 | |
1421 | switch (GET_CODE (x)((enum rtx_code) (x)->code)) |
1422 | { |
1423 | case DEBUG_EXPR: |
1424 | dv = dv_from_decl (DEBUG_EXPR_TREE_DECL (x)(((x)->u.fld[0]).rt_tree)); |
1425 | gcc_checking_assert (DECL_RTL_KNOWN_SET (DEBUG_EXPR_TREE_DECL (x)) == x)((void)(!(__extension__ ({ tree const __d = ((((x)->u.fld[ 0]).rt_tree)); ((void)(!((((tree_contains_struct[(((enum tree_code ) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1425, __FUNCTION__))->decl_with_rtl.rtl != nullptr)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1425, __FUNCTION__), 0 : 0)); &*((((tree_contains_struct [(((enum tree_code) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1425, __FUNCTION__))->decl_with_rtl.rtl != nullptr) ? (( contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1425, __FUNCTION__))->decl_with_rtl.rtl ? (__d)->decl_with_rtl .rtl : (make_decl_rtl (__d), (__d)->decl_with_rtl.rtl)) : nullptr ); }) == x) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1425, __FUNCTION__), 0 : 0)); |
1426 | break; |
1427 | |
1428 | case VALUE: |
1429 | dv = dv_from_value (x); |
1430 | break; |
1431 | |
1432 | default: |
1433 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1433, __FUNCTION__)); |
1434 | } |
1435 | |
1436 | return dv; |
1437 | } |
1438 | |
1439 | extern void debug_dv (decl_or_value dv); |
1440 | |
1441 | DEBUG_FUNCTION__attribute__ ((__used__)) void |
1442 | debug_dv (decl_or_value dv) |
1443 | { |
1444 | if (dv_is_value_p (dv)) |
1445 | debug_rtx (dv_as_value (dv)); |
1446 | else |
1447 | debug_generic_stmt (dv_as_decl (dv)); |
1448 | } |
1449 | |
1450 | static void loc_exp_dep_clear (variable *var); |
1451 | |
1452 | /* Free the element of VARIABLE_HTAB (its type is struct variable_def). */ |
1453 | |
1454 | static void |
1455 | variable_htab_free (void *elem) |
1456 | { |
1457 | int i; |
1458 | variable *var = (variable *) elem; |
1459 | location_chain *node, *next; |
1460 | |
1461 | gcc_checking_assert (var->refcount > 0)((void)(!(var->refcount > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1461, __FUNCTION__), 0 : 0)); |
1462 | |
1463 | var->refcount--; |
1464 | if (var->refcount > 0) |
1465 | return; |
1466 | |
1467 | for (i = 0; i < var->n_var_parts; i++) |
1468 | { |
1469 | for (node = var->var_part[i].loc_chain; node; node = next) |
1470 | { |
1471 | next = node->next; |
1472 | delete node; |
1473 | } |
1474 | var->var_part[i].loc_chain = NULLnullptr; |
1475 | } |
1476 | if (var->onepart && VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1476, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))) |
1477 | { |
1478 | loc_exp_dep_clear (var); |
1479 | if (VAR_LOC_DEP_LST (var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1479, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) ? __extension__ (*({ variable *const __v = (var) ; ((void)(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1479, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))->backlinks : nullptr)) |
1480 | VAR_LOC_DEP_LST (var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1480, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) ? __extension__ (*({ variable *const __v = (var) ; ((void)(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1480, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))->backlinks : nullptr)->pprev = NULLnullptr; |
1481 | XDELETE (VAR_LOC_1PAUX (var))free ((void*) (__extension__ (*({ variable *const __v = (var) ; ((void)(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1481, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })))); |
1482 | /* These may be reused across functions, so reset |
1483 | e.g. NO_LOC_P. */ |
1484 | if (var->onepart == ONEPART_DEXPR) |
1485 | set_dv_changed (var->dv, true); |
1486 | } |
1487 | onepart_pool (var->onepart).remove (var); |
1488 | } |
1489 | |
1490 | /* Initialize the set (array) SET of attrs to empty lists. */ |
1491 | |
1492 | static void |
1493 | init_attrs_list_set (attrs **set) |
1494 | { |
1495 | int i; |
1496 | |
1497 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
1498 | set[i] = NULLnullptr; |
1499 | } |
1500 | |
1501 | /* Make the list *LISTP empty. */ |
1502 | |
1503 | static void |
1504 | attrs_list_clear (attrs **listp) |
1505 | { |
1506 | attrs *list, *next; |
1507 | |
1508 | for (list = *listp; list; list = next) |
1509 | { |
1510 | next = list->next; |
1511 | delete list; |
1512 | } |
1513 | *listp = NULLnullptr; |
1514 | } |
1515 | |
1516 | /* Return true if the pair of DECL and OFFSET is the member of the LIST. */ |
1517 | |
1518 | static attrs * |
1519 | attrs_list_member (attrs *list, decl_or_value dv, HOST_WIDE_INTlong offset) |
1520 | { |
1521 | for (; list; list = list->next) |
1522 | if (dv_as_opaque (list->dv) == dv_as_opaque (dv) && list->offset == offset) |
1523 | return list; |
1524 | return NULLnullptr; |
1525 | } |
1526 | |
1527 | /* Insert the triplet DECL, OFFSET, LOC to the list *LISTP. */ |
1528 | |
1529 | static void |
1530 | attrs_list_insert (attrs **listp, decl_or_value dv, |
1531 | HOST_WIDE_INTlong offset, rtx loc) |
1532 | { |
1533 | attrs *list = new attrs; |
1534 | list->loc = loc; |
1535 | list->dv = dv; |
1536 | list->offset = offset; |
1537 | list->next = *listp; |
1538 | *listp = list; |
1539 | } |
1540 | |
1541 | /* Copy all nodes from SRC and create a list *DSTP of the copies. */ |
1542 | |
1543 | static void |
1544 | attrs_list_copy (attrs **dstp, attrs *src) |
1545 | { |
1546 | attrs_list_clear (dstp); |
1547 | for (; src; src = src->next) |
1548 | { |
1549 | attrs *n = new attrs; |
1550 | n->loc = src->loc; |
1551 | n->dv = src->dv; |
1552 | n->offset = src->offset; |
1553 | n->next = *dstp; |
1554 | *dstp = n; |
1555 | } |
1556 | } |
1557 | |
1558 | /* Add all nodes from SRC which are not in *DSTP to *DSTP. */ |
1559 | |
1560 | static void |
1561 | attrs_list_union (attrs **dstp, attrs *src) |
1562 | { |
1563 | for (; src; src = src->next) |
1564 | { |
1565 | if (!attrs_list_member (*dstp, src->dv, src->offset)) |
1566 | attrs_list_insert (dstp, src->dv, src->offset, src->loc); |
1567 | } |
1568 | } |
1569 | |
1570 | /* Combine nodes that are not onepart nodes from SRC and SRC2 into |
1571 | *DSTP. */ |
1572 | |
1573 | static void |
1574 | attrs_list_mpdv_union (attrs **dstp, attrs *src, attrs *src2) |
1575 | { |
1576 | gcc_assert (!*dstp)((void)(!(!*dstp) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1576, __FUNCTION__), 0 : 0)); |
1577 | for (; src; src = src->next) |
1578 | { |
1579 | if (!dv_onepart_p (src->dv)) |
1580 | attrs_list_insert (dstp, src->dv, src->offset, src->loc); |
1581 | } |
1582 | for (src = src2; src; src = src->next) |
1583 | { |
1584 | if (!dv_onepart_p (src->dv) |
1585 | && !attrs_list_member (*dstp, src->dv, src->offset)) |
1586 | attrs_list_insert (dstp, src->dv, src->offset, src->loc); |
1587 | } |
1588 | } |
1589 | |
1590 | /* Shared hashtable support. */ |
1591 | |
1592 | /* Return true if VARS is shared. */ |
1593 | |
1594 | static inline bool |
1595 | shared_hash_shared (shared_hash *vars) |
1596 | { |
1597 | return vars->refcount > 1; |
1598 | } |
1599 | |
1600 | /* Return the hash table for VARS. */ |
1601 | |
1602 | static inline variable_table_type * |
1603 | shared_hash_htab (shared_hash *vars) |
1604 | { |
1605 | return vars->htab; |
1606 | } |
1607 | |
1608 | /* Return true if VAR is shared, or maybe because VARS is shared. */ |
1609 | |
1610 | static inline bool |
1611 | shared_var_p (variable *var, shared_hash *vars) |
1612 | { |
1613 | /* Don't count an entry in the changed_variables table as a duplicate. */ |
1614 | return ((var->refcount > 1 + (int) var->in_changed_variables) |
1615 | || shared_hash_shared (vars)); |
1616 | } |
1617 | |
1618 | /* Copy variables into a new hash table. */ |
1619 | |
1620 | static shared_hash * |
1621 | shared_hash_unshare (shared_hash *vars) |
1622 | { |
1623 | shared_hash *new_vars = new shared_hash; |
1624 | gcc_assert (vars->refcount > 1)((void)(!(vars->refcount > 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1624, __FUNCTION__), 0 : 0)); |
1625 | new_vars->refcount = 1; |
1626 | new_vars->htab = new variable_table_type (vars->htab->elements () + 3); |
1627 | vars_copy (new_vars->htab, vars->htab); |
1628 | vars->refcount--; |
1629 | return new_vars; |
1630 | } |
1631 | |
1632 | /* Increment reference counter on VARS and return it. */ |
1633 | |
1634 | static inline shared_hash * |
1635 | shared_hash_copy (shared_hash *vars) |
1636 | { |
1637 | vars->refcount++; |
1638 | return vars; |
1639 | } |
1640 | |
1641 | /* Decrement reference counter and destroy hash table if not shared |
1642 | anymore. */ |
1643 | |
1644 | static void |
1645 | shared_hash_destroy (shared_hash *vars) |
1646 | { |
1647 | gcc_checking_assert (vars->refcount > 0)((void)(!(vars->refcount > 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1647, __FUNCTION__), 0 : 0)); |
1648 | if (--vars->refcount == 0) |
1649 | { |
1650 | delete vars->htab; |
1651 | delete vars; |
1652 | } |
1653 | } |
1654 | |
1655 | /* Unshare *PVARS if shared and return slot for DV. If INS is |
1656 | INSERT, insert it if not already present. */ |
1657 | |
1658 | static inline variable ** |
1659 | shared_hash_find_slot_unshare_1 (shared_hash **pvars, decl_or_value dv, |
1660 | hashval_t dvhash, enum insert_option ins) |
1661 | { |
1662 | if (shared_hash_shared (*pvars)) |
1663 | *pvars = shared_hash_unshare (*pvars); |
1664 | return shared_hash_htab (*pvars)->find_slot_with_hash (dv, dvhash, ins); |
1665 | } |
1666 | |
1667 | static inline variable ** |
1668 | shared_hash_find_slot_unshare (shared_hash **pvars, decl_or_value dv, |
1669 | enum insert_option ins) |
1670 | { |
1671 | return shared_hash_find_slot_unshare_1 (pvars, dv, dv_htab_hash (dv), ins); |
1672 | } |
1673 | |
1674 | /* Return slot for DV, if it is already present in the hash table. |
1675 | If it is not present, insert it only VARS is not shared, otherwise |
1676 | return NULL. */ |
1677 | |
1678 | static inline variable ** |
1679 | shared_hash_find_slot_1 (shared_hash *vars, decl_or_value dv, hashval_t dvhash) |
1680 | { |
1681 | return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash, |
1682 | shared_hash_shared (vars) |
1683 | ? NO_INSERT : INSERT); |
1684 | } |
1685 | |
1686 | static inline variable ** |
1687 | shared_hash_find_slot (shared_hash *vars, decl_or_value dv) |
1688 | { |
1689 | return shared_hash_find_slot_1 (vars, dv, dv_htab_hash (dv)); |
1690 | } |
1691 | |
1692 | /* Return slot for DV only if it is already present in the hash table. */ |
1693 | |
1694 | static inline variable ** |
1695 | shared_hash_find_slot_noinsert_1 (shared_hash *vars, decl_or_value dv, |
1696 | hashval_t dvhash) |
1697 | { |
1698 | return shared_hash_htab (vars)->find_slot_with_hash (dv, dvhash, NO_INSERT); |
1699 | } |
1700 | |
1701 | static inline variable ** |
1702 | shared_hash_find_slot_noinsert (shared_hash *vars, decl_or_value dv) |
1703 | { |
1704 | return shared_hash_find_slot_noinsert_1 (vars, dv, dv_htab_hash (dv)); |
1705 | } |
1706 | |
1707 | /* Return variable for DV or NULL if not already present in the hash |
1708 | table. */ |
1709 | |
1710 | static inline variable * |
1711 | shared_hash_find_1 (shared_hash *vars, decl_or_value dv, hashval_t dvhash) |
1712 | { |
1713 | return shared_hash_htab (vars)->find_with_hash (dv, dvhash); |
1714 | } |
1715 | |
1716 | static inline variable * |
1717 | shared_hash_find (shared_hash *vars, decl_or_value dv) |
1718 | { |
1719 | return shared_hash_find_1 (vars, dv, dv_htab_hash (dv)); |
1720 | } |
1721 | |
1722 | /* Return true if TVAL is better than CVAL as a canonival value. We |
1723 | choose lowest-numbered VALUEs, using the RTX address as a |
1724 | tie-breaker. The idea is to arrange them into a star topology, |
1725 | such that all of them are at most one step away from the canonical |
1726 | value, and the canonical value has backlinks to all of them, in |
1727 | addition to all the actual locations. We don't enforce this |
1728 | topology throughout the entire dataflow analysis, though. |
1729 | */ |
1730 | |
1731 | static inline bool |
1732 | canon_value_cmp (rtx tval, rtx cval) |
1733 | { |
1734 | return !cval |
1735 | || CSELIB_VAL_PTR (tval)(((tval)->u.fld[0]).rt_cselib)->uid < CSELIB_VAL_PTR (cval)(((cval)->u.fld[0]).rt_cselib)->uid; |
1736 | } |
1737 | |
1738 | static bool dst_can_be_shared; |
1739 | |
1740 | /* Return a copy of a variable VAR and insert it to dataflow set SET. */ |
1741 | |
1742 | static variable ** |
1743 | unshare_variable (dataflow_set *set, variable **slot, variable *var, |
1744 | enum var_init_status initialized) |
1745 | { |
1746 | variable *new_var; |
1747 | int i; |
1748 | |
1749 | new_var = onepart_pool_allocate (var->onepart); |
1750 | new_var->dv = var->dv; |
1751 | new_var->refcount = 1; |
1752 | var->refcount--; |
1753 | new_var->n_var_parts = var->n_var_parts; |
1754 | new_var->onepart = var->onepart; |
1755 | new_var->in_changed_variables = false; |
1756 | |
1757 | if (! flag_var_tracking_uninitglobal_options.x_flag_var_tracking_uninit) |
1758 | initialized = VAR_INIT_STATUS_INITIALIZED; |
1759 | |
1760 | for (i = 0; i < var->n_var_parts; i++) |
1761 | { |
1762 | location_chain *node; |
1763 | location_chain **nextp; |
1764 | |
1765 | if (i == 0 && var->onepart) |
1766 | { |
1767 | /* One-part auxiliary data is only used while emitting |
1768 | notes, so propagate it to the new variable in the active |
1769 | dataflow set. If we're not emitting notes, this will be |
1770 | a no-op. */ |
1771 | gcc_checking_assert (!VAR_LOC_1PAUX (var) || emit_notes)((void)(!(!__extension__ (*({ variable *const __v = (var); (( void)(!(__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1771, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) || emit_notes) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1771, __FUNCTION__), 0 : 0)); |
1772 | VAR_LOC_1PAUX (new_var)__extension__ (*({ variable *const __v = (new_var); ((void)(! (__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1772, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) = VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1772, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })); |
1773 | VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1773, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) = NULLnullptr; |
1774 | } |
1775 | else |
1776 | VAR_PART_OFFSET (new_var, i)__extension__ (*({ variable *const __v = (new_var); ((void)(! (!__v->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1776, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) = VAR_PART_OFFSET (var, i)__extension__ (*({ variable *const __v = (var); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1776, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })); |
1777 | nextp = &new_var->var_part[i].loc_chain; |
1778 | for (node = var->var_part[i].loc_chain; node; node = node->next) |
1779 | { |
1780 | location_chain *new_lc; |
1781 | |
1782 | new_lc = new location_chain; |
1783 | new_lc->next = NULLnullptr; |
1784 | if (node->init > initialized) |
1785 | new_lc->init = node->init; |
1786 | else |
1787 | new_lc->init = initialized; |
1788 | if (node->set_src && !(MEM_P (node->set_src)(((enum rtx_code) (node->set_src)->code) == MEM))) |
1789 | new_lc->set_src = node->set_src; |
1790 | else |
1791 | new_lc->set_src = NULLnullptr; |
1792 | new_lc->loc = node->loc; |
1793 | |
1794 | *nextp = new_lc; |
1795 | nextp = &new_lc->next; |
1796 | } |
1797 | |
1798 | new_var->var_part[i].cur_loc = var->var_part[i].cur_loc; |
1799 | } |
1800 | |
1801 | dst_can_be_shared = false; |
1802 | if (shared_hash_shared (set->vars)) |
1803 | slot = shared_hash_find_slot_unshare (&set->vars, var->dv, NO_INSERT); |
1804 | else if (set->traversed_vars && set->vars != set->traversed_vars) |
1805 | slot = shared_hash_find_slot_noinsert (set->vars, var->dv); |
1806 | *slot = new_var; |
1807 | if (var->in_changed_variables) |
1808 | { |
1809 | variable **cslot |
1810 | = changed_variables->find_slot_with_hash (var->dv, |
1811 | dv_htab_hash (var->dv), |
1812 | NO_INSERT); |
1813 | gcc_assert (*cslot == (void *) var)((void)(!(*cslot == (void *) var) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1813, __FUNCTION__), 0 : 0)); |
1814 | var->in_changed_variables = false; |
1815 | variable_htab_free (var); |
1816 | *cslot = new_var; |
1817 | new_var->in_changed_variables = true; |
1818 | } |
1819 | return slot; |
1820 | } |
1821 | |
1822 | /* Copy all variables from hash table SRC to hash table DST. */ |
1823 | |
1824 | static void |
1825 | vars_copy (variable_table_type *dst, variable_table_type *src) |
1826 | { |
1827 | variable_iterator_type hi; |
1828 | variable *var; |
1829 | |
1830 | FOR_EACH_HASH_TABLE_ELEMENT (*src, var, variable, hi)for ((hi) = (*src).begin (); (hi) != (*src).end () ? (var = * (hi) , true) : false; ++(hi)) |
1831 | { |
1832 | variable **dstp; |
1833 | var->refcount++; |
1834 | dstp = dst->find_slot_with_hash (var->dv, dv_htab_hash (var->dv), |
1835 | INSERT); |
1836 | *dstp = var; |
1837 | } |
1838 | } |
1839 | |
1840 | /* Map a decl to its main debug decl. */ |
1841 | |
1842 | static inline tree |
1843 | var_debug_decl (tree decl) |
1844 | { |
1845 | if (decl && VAR_P (decl)(((enum tree_code) (decl)->base.code) == VAR_DECL) && DECL_HAS_DEBUG_EXPR_P (decl)((tree_check ((decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1845, __FUNCTION__, (VAR_DECL)))->decl_common.debug_expr_is_from )) |
1846 | { |
1847 | tree debugdecl = DECL_DEBUG_EXPR (decl)(decl_debug_expr_lookup ((tree_check ((decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1847, __FUNCTION__, (VAR_DECL))))); |
1848 | if (DECL_P (debugdecl)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (debugdecl)->base.code))] == tcc_declaration)) |
1849 | decl = debugdecl; |
1850 | } |
1851 | |
1852 | return decl; |
1853 | } |
1854 | |
1855 | /* Set the register LOC to contain DV, OFFSET. */ |
1856 | |
1857 | static void |
1858 | var_reg_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized, |
1859 | decl_or_value dv, HOST_WIDE_INTlong offset, rtx set_src, |
1860 | enum insert_option iopt) |
1861 | { |
1862 | attrs *node; |
1863 | bool decl_p = dv_is_decl_p (dv); |
1864 | |
1865 | if (decl_p) |
1866 | dv = dv_from_decl (var_debug_decl (dv_as_decl (dv))); |
1867 | |
1868 | for (node = set->regs[REGNO (loc)(rhs_regno(loc))]; node; node = node->next) |
1869 | if (dv_as_opaque (node->dv) == dv_as_opaque (dv) |
1870 | && node->offset == offset) |
1871 | break; |
1872 | if (!node) |
1873 | attrs_list_insert (&set->regs[REGNO (loc)(rhs_regno(loc))], dv, offset, loc); |
1874 | set_variable_part (set, loc, dv, offset, initialized, set_src, iopt); |
1875 | } |
1876 | |
1877 | /* Return true if we should track a location that is OFFSET bytes from |
1878 | a variable. Store the constant offset in *OFFSET_OUT if so. */ |
1879 | |
1880 | static bool |
1881 | track_offset_p (poly_int64 offset, HOST_WIDE_INTlong *offset_out) |
1882 | { |
1883 | HOST_WIDE_INTlong const_offset; |
1884 | if (!offset.is_constant (&const_offset) |
1885 | || !IN_RANGE (const_offset, 0, MAX_VAR_PARTS - 1)((unsigned long) (const_offset) - (unsigned long) (0) <= ( unsigned long) (16 - 1) - (unsigned long) (0))) |
1886 | return false; |
1887 | *offset_out = const_offset; |
1888 | return true; |
1889 | } |
1890 | |
1891 | /* Return the offset of a register that track_offset_p says we |
1892 | should track. */ |
1893 | |
1894 | static HOST_WIDE_INTlong |
1895 | get_tracked_reg_offset (rtx loc) |
1896 | { |
1897 | HOST_WIDE_INTlong offset; |
1898 | if (!track_offset_p (REG_OFFSET (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->offset), &offset)) |
1899 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 1899, __FUNCTION__)); |
1900 | return offset; |
1901 | } |
1902 | |
1903 | /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). */ |
1904 | |
1905 | static void |
1906 | var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized, |
1907 | rtx set_src) |
1908 | { |
1909 | tree decl = REG_EXPR (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->decl); |
1910 | HOST_WIDE_INTlong offset = get_tracked_reg_offset (loc); |
1911 | |
1912 | var_reg_decl_set (set, loc, initialized, |
1913 | dv_from_decl (decl), offset, set_src, INSERT); |
1914 | } |
1915 | |
1916 | static enum var_init_status |
1917 | get_init_value (dataflow_set *set, rtx loc, decl_or_value dv) |
1918 | { |
1919 | variable *var; |
1920 | int i; |
1921 | enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN; |
1922 | |
1923 | if (! flag_var_tracking_uninitglobal_options.x_flag_var_tracking_uninit) |
1924 | return VAR_INIT_STATUS_INITIALIZED; |
1925 | |
1926 | var = shared_hash_find (set->vars, dv); |
1927 | if (var) |
1928 | { |
1929 | for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++) |
1930 | { |
1931 | location_chain *nextp; |
1932 | for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next) |
1933 | if (rtx_equal_p (nextp->loc, loc)) |
1934 | { |
1935 | ret_val = nextp->init; |
1936 | break; |
1937 | } |
1938 | } |
1939 | } |
1940 | |
1941 | return ret_val; |
1942 | } |
1943 | |
1944 | /* Delete current content of register LOC in dataflow set SET and set |
1945 | the register to contain REG_EXPR (LOC), REG_OFFSET (LOC). If |
1946 | MODIFY is true, any other live copies of the same variable part are |
1947 | also deleted from the dataflow set, otherwise the variable part is |
1948 | assumed to be copied from another location holding the same |
1949 | part. */ |
1950 | |
1951 | static void |
1952 | var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify, |
1953 | enum var_init_status initialized, rtx set_src) |
1954 | { |
1955 | tree decl = REG_EXPR (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->decl); |
1956 | HOST_WIDE_INTlong offset = get_tracked_reg_offset (loc); |
1957 | attrs *node, *next; |
1958 | attrs **nextp; |
1959 | |
1960 | decl = var_debug_decl (decl); |
1961 | |
1962 | if (initialized == VAR_INIT_STATUS_UNKNOWN) |
1963 | initialized = get_init_value (set, loc, dv_from_decl (decl)); |
1964 | |
1965 | nextp = &set->regs[REGNO (loc)(rhs_regno(loc))]; |
1966 | for (node = *nextp; node; node = next) |
1967 | { |
1968 | next = node->next; |
1969 | if (dv_as_opaque (node->dv) != decl || node->offset != offset) |
1970 | { |
1971 | delete_variable_part (set, node->loc, node->dv, node->offset); |
1972 | delete node; |
1973 | *nextp = next; |
1974 | } |
1975 | else |
1976 | { |
1977 | node->loc = loc; |
1978 | nextp = &node->next; |
1979 | } |
1980 | } |
1981 | if (modify) |
1982 | clobber_variable_part (set, loc, dv_from_decl (decl), offset, set_src); |
1983 | var_reg_set (set, loc, initialized, set_src); |
1984 | } |
1985 | |
1986 | /* Delete the association of register LOC in dataflow set SET with any |
1987 | variables that aren't onepart. If CLOBBER is true, also delete any |
1988 | other live copies of the same variable part, and delete the |
1989 | association with onepart dvs too. */ |
1990 | |
1991 | static void |
1992 | var_reg_delete (dataflow_set *set, rtx loc, bool clobber) |
1993 | { |
1994 | attrs **nextp = &set->regs[REGNO (loc)(rhs_regno(loc))]; |
1995 | attrs *node, *next; |
1996 | |
1997 | HOST_WIDE_INTlong offset; |
1998 | if (clobber && track_offset_p (REG_OFFSET (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->offset), &offset)) |
1999 | { |
2000 | tree decl = REG_EXPR (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->decl); |
2001 | |
2002 | decl = var_debug_decl (decl); |
2003 | |
2004 | clobber_variable_part (set, NULLnullptr, dv_from_decl (decl), offset, NULLnullptr); |
2005 | } |
2006 | |
2007 | for (node = *nextp; node; node = next) |
2008 | { |
2009 | next = node->next; |
2010 | if (clobber || !dv_onepart_p (node->dv)) |
2011 | { |
2012 | delete_variable_part (set, node->loc, node->dv, node->offset); |
2013 | delete node; |
2014 | *nextp = next; |
2015 | } |
2016 | else |
2017 | nextp = &node->next; |
2018 | } |
2019 | } |
2020 | |
2021 | /* Delete content of register with number REGNO in dataflow set SET. */ |
2022 | |
2023 | static void |
2024 | var_regno_delete (dataflow_set *set, int regno) |
2025 | { |
2026 | attrs **reg = &set->regs[regno]; |
2027 | attrs *node, *next; |
2028 | |
2029 | for (node = *reg; node; node = next) |
2030 | { |
2031 | next = node->next; |
2032 | delete_variable_part (set, node->loc, node->dv, node->offset); |
2033 | delete node; |
2034 | } |
2035 | *reg = NULLnullptr; |
2036 | } |
2037 | |
2038 | /* Return true if I is the negated value of a power of two. */ |
2039 | static bool |
2040 | negative_power_of_two_p (HOST_WIDE_INTlong i) |
2041 | { |
2042 | unsigned HOST_WIDE_INTlong x = -(unsigned HOST_WIDE_INTlong)i; |
2043 | return pow2_or_zerop (x); |
2044 | } |
2045 | |
2046 | /* Strip constant offsets and alignments off of LOC. Return the base |
2047 | expression. */ |
2048 | |
2049 | static rtx |
2050 | vt_get_canonicalize_base (rtx loc) |
2051 | { |
2052 | while ((GET_CODE (loc)((enum rtx_code) (loc)->code) == PLUS |
2053 | || GET_CODE (loc)((enum rtx_code) (loc)->code) == AND) |
2054 | && GET_CODE (XEXP (loc, 1))((enum rtx_code) ((((loc)->u.fld[1]).rt_rtx))->code) == CONST_INT |
2055 | && (GET_CODE (loc)((enum rtx_code) (loc)->code) != AND |
2056 | || negative_power_of_two_p (INTVAL (XEXP (loc, 1))(((((loc)->u.fld[1]).rt_rtx))->u.hwint[0])))) |
2057 | loc = XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx); |
2058 | |
2059 | return loc; |
2060 | } |
2061 | |
2062 | /* This caches canonicalized addresses for VALUEs, computed using |
2063 | information in the global cselib table. */ |
2064 | static hash_map<rtx, rtx> *global_get_addr_cache; |
2065 | |
2066 | /* This caches canonicalized addresses for VALUEs, computed using |
2067 | information from the global cache and information pertaining to a |
2068 | basic block being analyzed. */ |
2069 | static hash_map<rtx, rtx> *local_get_addr_cache; |
2070 | |
2071 | static rtx vt_canonicalize_addr (dataflow_set *, rtx); |
2072 | |
2073 | /* Return the canonical address for LOC, that must be a VALUE, using a |
2074 | cached global equivalence or computing it and storing it in the |
2075 | global cache. */ |
2076 | |
2077 | static rtx |
2078 | get_addr_from_global_cache (rtx const loc) |
2079 | { |
2080 | rtx x; |
2081 | |
2082 | gcc_checking_assert (GET_CODE (loc) == VALUE)((void)(!(((enum rtx_code) (loc)->code) == VALUE) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2082, __FUNCTION__), 0 : 0)); |
2083 | |
2084 | bool existed; |
2085 | rtx *slot = &global_get_addr_cache->get_or_insert (loc, &existed); |
2086 | if (existed) |
2087 | return *slot; |
2088 | |
2089 | x = canon_rtx (get_addr (loc)); |
2090 | |
2091 | /* Tentative, avoiding infinite recursion. */ |
2092 | *slot = x; |
2093 | |
2094 | if (x != loc) |
2095 | { |
2096 | rtx nx = vt_canonicalize_addr (NULLnullptr, x); |
2097 | if (nx != x) |
2098 | { |
2099 | /* The table may have moved during recursion, recompute |
2100 | SLOT. */ |
2101 | *global_get_addr_cache->get (loc) = x = nx; |
2102 | } |
2103 | } |
2104 | |
2105 | return x; |
2106 | } |
2107 | |
2108 | /* Return the canonical address for LOC, that must be a VALUE, using a |
2109 | cached local equivalence or computing it and storing it in the |
2110 | local cache. */ |
2111 | |
2112 | static rtx |
2113 | get_addr_from_local_cache (dataflow_set *set, rtx const loc) |
2114 | { |
2115 | rtx x; |
2116 | decl_or_value dv; |
2117 | variable *var; |
2118 | location_chain *l; |
2119 | |
2120 | gcc_checking_assert (GET_CODE (loc) == VALUE)((void)(!(((enum rtx_code) (loc)->code) == VALUE) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2120, __FUNCTION__), 0 : 0)); |
2121 | |
2122 | bool existed; |
2123 | rtx *slot = &local_get_addr_cache->get_or_insert (loc, &existed); |
2124 | if (existed) |
2125 | return *slot; |
2126 | |
2127 | x = get_addr_from_global_cache (loc); |
2128 | |
2129 | /* Tentative, avoiding infinite recursion. */ |
2130 | *slot = x; |
2131 | |
2132 | /* Recurse to cache local expansion of X, or if we need to search |
2133 | for a VALUE in the expansion. */ |
2134 | if (x != loc) |
2135 | { |
2136 | rtx nx = vt_canonicalize_addr (set, x); |
2137 | if (nx != x) |
2138 | { |
2139 | slot = local_get_addr_cache->get (loc); |
2140 | *slot = x = nx; |
2141 | } |
2142 | return x; |
2143 | } |
2144 | |
2145 | dv = dv_from_rtx (x); |
2146 | var = shared_hash_find (set->vars, dv); |
2147 | if (!var) |
2148 | return x; |
2149 | |
2150 | /* Look for an improved equivalent expression. */ |
2151 | for (l = var->var_part[0].loc_chain; l; l = l->next) |
2152 | { |
2153 | rtx base = vt_get_canonicalize_base (l->loc); |
2154 | if (GET_CODE (base)((enum rtx_code) (base)->code) == VALUE |
2155 | && canon_value_cmp (base, loc)) |
2156 | { |
2157 | rtx nx = vt_canonicalize_addr (set, l->loc); |
2158 | if (x != nx) |
2159 | { |
2160 | slot = local_get_addr_cache->get (loc); |
2161 | *slot = x = nx; |
2162 | } |
2163 | break; |
2164 | } |
2165 | } |
2166 | |
2167 | return x; |
2168 | } |
2169 | |
2170 | /* Canonicalize LOC using equivalences from SET in addition to those |
2171 | in the cselib static table. It expects a VALUE-based expression, |
2172 | and it will only substitute VALUEs with other VALUEs or |
2173 | function-global equivalences, so that, if two addresses have base |
2174 | VALUEs that are locally or globally related in ways that |
2175 | memrefs_conflict_p cares about, they will both canonicalize to |
2176 | expressions that have the same base VALUE. |
2177 | |
2178 | The use of VALUEs as canonical base addresses enables the canonical |
2179 | RTXs to remain unchanged globally, if they resolve to a constant, |
2180 | or throughout a basic block otherwise, so that they can be cached |
2181 | and the cache needs not be invalidated when REGs, MEMs or such |
2182 | change. */ |
2183 | |
2184 | static rtx |
2185 | vt_canonicalize_addr (dataflow_set *set, rtx oloc) |
2186 | { |
2187 | poly_int64 ofst = 0, term; |
2188 | machine_mode mode = GET_MODE (oloc)((machine_mode) (oloc)->mode); |
2189 | rtx loc = oloc; |
2190 | rtx x; |
2191 | bool retry = true; |
2192 | |
2193 | while (retry) |
2194 | { |
2195 | while (GET_CODE (loc)((enum rtx_code) (loc)->code) == PLUS |
2196 | && poly_int_rtx_p (XEXP (loc, 1)(((loc)->u.fld[1]).rt_rtx), &term)) |
2197 | { |
2198 | ofst += term; |
2199 | loc = XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx); |
2200 | } |
2201 | |
2202 | /* Alignment operations can't normally be combined, so just |
2203 | canonicalize the base and we're done. We'll normally have |
2204 | only one stack alignment anyway. */ |
2205 | if (GET_CODE (loc)((enum rtx_code) (loc)->code) == AND |
2206 | && GET_CODE (XEXP (loc, 1))((enum rtx_code) ((((loc)->u.fld[1]).rt_rtx))->code) == CONST_INT |
2207 | && negative_power_of_two_p (INTVAL (XEXP (loc, 1))(((((loc)->u.fld[1]).rt_rtx))->u.hwint[0]))) |
2208 | { |
2209 | x = vt_canonicalize_addr (set, XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx)); |
2210 | if (x != XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx)) |
2211 | loc = gen_rtx_AND (mode, x, XEXP (loc, 1))gen_rtx_fmt_ee_stat ((AND), ((mode)), ((x)), (((((loc)->u. fld[1]).rt_rtx))) ); |
2212 | retry = false; |
2213 | } |
2214 | |
2215 | if (GET_CODE (loc)((enum rtx_code) (loc)->code) == VALUE) |
2216 | { |
2217 | if (set) |
2218 | loc = get_addr_from_local_cache (set, loc); |
2219 | else |
2220 | loc = get_addr_from_global_cache (loc); |
2221 | |
2222 | /* Consolidate plus_constants. */ |
2223 | while (maybe_ne (ofst, 0) |
2224 | && GET_CODE (loc)((enum rtx_code) (loc)->code) == PLUS |
2225 | && poly_int_rtx_p (XEXP (loc, 1)(((loc)->u.fld[1]).rt_rtx), &term)) |
2226 | { |
2227 | ofst += term; |
2228 | loc = XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx); |
2229 | } |
2230 | |
2231 | retry = false; |
2232 | } |
2233 | else |
2234 | { |
2235 | x = canon_rtx (loc); |
2236 | if (retry) |
2237 | retry = (x != loc); |
2238 | loc = x; |
2239 | } |
2240 | } |
2241 | |
2242 | /* Add OFST back in. */ |
2243 | if (maybe_ne (ofst, 0)) |
2244 | { |
2245 | /* Don't build new RTL if we can help it. */ |
2246 | if (strip_offset (oloc, &term) == loc && known_eq (term, ofst)(!maybe_ne (term, ofst))) |
2247 | return oloc; |
2248 | |
2249 | loc = plus_constant (mode, loc, ofst); |
2250 | } |
2251 | |
2252 | return loc; |
2253 | } |
2254 | |
2255 | /* Return true iff there's a true dependence between MLOC and LOC. |
2256 | MADDR must be a canonicalized version of MLOC's address. */ |
2257 | |
2258 | static inline bool |
2259 | vt_canon_true_dep (dataflow_set *set, rtx mloc, rtx maddr, rtx loc) |
2260 | { |
2261 | if (GET_CODE (loc)((enum rtx_code) (loc)->code) != MEM) |
2262 | return false; |
2263 | |
2264 | rtx addr = vt_canonicalize_addr (set, XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx)); |
2265 | if (!canon_true_dependence (mloc, GET_MODE (mloc)((machine_mode) (mloc)->mode), maddr, loc, addr)) |
2266 | return false; |
2267 | |
2268 | return true; |
2269 | } |
2270 | |
2271 | /* Hold parameters for the hashtab traversal function |
2272 | drop_overlapping_mem_locs, see below. */ |
2273 | |
2274 | struct overlapping_mems |
2275 | { |
2276 | dataflow_set *set; |
2277 | rtx loc, addr; |
2278 | }; |
2279 | |
2280 | /* Remove all MEMs that overlap with COMS->LOC from the location list |
2281 | of a hash table entry for a onepart variable. COMS->ADDR must be a |
2282 | canonicalized form of COMS->LOC's address, and COMS->LOC must be |
2283 | canonicalized itself. */ |
2284 | |
2285 | int |
2286 | drop_overlapping_mem_locs (variable **slot, overlapping_mems *coms) |
2287 | { |
2288 | dataflow_set *set = coms->set; |
2289 | rtx mloc = coms->loc, addr = coms->addr; |
2290 | variable *var = *slot; |
2291 | |
2292 | if (var->onepart != NOT_ONEPART) |
2293 | { |
2294 | location_chain *loc, **locp; |
2295 | bool changed = false; |
2296 | rtx cur_loc; |
2297 | |
2298 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2298, __FUNCTION__), 0 : 0)); |
2299 | |
2300 | if (shared_var_p (var, set->vars)) |
2301 | { |
2302 | for (loc = var->var_part[0].loc_chain; loc; loc = loc->next) |
2303 | if (vt_canon_true_dep (set, mloc, addr, loc->loc)) |
2304 | break; |
2305 | |
2306 | if (!loc) |
2307 | return 1; |
2308 | |
2309 | slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN); |
2310 | var = *slot; |
2311 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2311, __FUNCTION__), 0 : 0)); |
2312 | } |
2313 | |
2314 | if (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2314, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))) |
2315 | cur_loc = VAR_LOC_FROM (var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2315, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))->from); |
2316 | else |
2317 | cur_loc = var->var_part[0].cur_loc; |
2318 | |
2319 | for (locp = &var->var_part[0].loc_chain, loc = *locp; |
2320 | loc; loc = *locp) |
2321 | { |
2322 | if (!vt_canon_true_dep (set, mloc, addr, loc->loc)) |
2323 | { |
2324 | locp = &loc->next; |
2325 | continue; |
2326 | } |
2327 | |
2328 | *locp = loc->next; |
2329 | /* If we have deleted the location which was last emitted |
2330 | we have to emit new location so add the variable to set |
2331 | of changed variables. */ |
2332 | if (cur_loc == loc->loc) |
2333 | { |
2334 | changed = true; |
2335 | var->var_part[0].cur_loc = NULLnullptr; |
2336 | if (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2336, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))) |
2337 | VAR_LOC_FROM (var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2337, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))->from) = NULLnullptr; |
2338 | } |
2339 | delete loc; |
2340 | } |
2341 | |
2342 | if (!var->var_part[0].loc_chain) |
2343 | { |
2344 | var->n_var_parts--; |
2345 | changed = true; |
2346 | } |
2347 | if (changed) |
2348 | variable_was_changed (var, set); |
2349 | } |
2350 | |
2351 | return 1; |
2352 | } |
2353 | |
2354 | /* Remove from SET all VALUE bindings to MEMs that overlap with LOC. */ |
2355 | |
2356 | static void |
2357 | clobber_overlapping_mems (dataflow_set *set, rtx loc) |
2358 | { |
2359 | struct overlapping_mems coms; |
2360 | |
2361 | gcc_checking_assert (GET_CODE (loc) == MEM)((void)(!(((enum rtx_code) (loc)->code) == MEM) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2361, __FUNCTION__), 0 : 0)); |
2362 | |
2363 | coms.set = set; |
2364 | coms.loc = canon_rtx (loc); |
2365 | coms.addr = vt_canonicalize_addr (set, XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx)); |
2366 | |
2367 | set->traversed_vars = set->vars; |
2368 | shared_hash_htab (set->vars) |
2369 | ->traverse <overlapping_mems*, drop_overlapping_mem_locs> (&coms); |
2370 | set->traversed_vars = NULLnullptr; |
2371 | } |
2372 | |
2373 | /* Set the location of DV, OFFSET as the MEM LOC. */ |
2374 | |
2375 | static void |
2376 | var_mem_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized, |
2377 | decl_or_value dv, HOST_WIDE_INTlong offset, rtx set_src, |
2378 | enum insert_option iopt) |
2379 | { |
2380 | if (dv_is_decl_p (dv)) |
2381 | dv = dv_from_decl (var_debug_decl (dv_as_decl (dv))); |
2382 | |
2383 | set_variable_part (set, loc, dv, offset, initialized, set_src, iopt); |
2384 | } |
2385 | |
2386 | /* Set the location part of variable MEM_EXPR (LOC) in dataflow set |
2387 | SET to LOC. |
2388 | Adjust the address first if it is stack pointer based. */ |
2389 | |
2390 | static void |
2391 | var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized, |
2392 | rtx set_src) |
2393 | { |
2394 | tree decl = MEM_EXPR (loc)(get_mem_attrs (loc)->expr); |
2395 | HOST_WIDE_INTlong offset = int_mem_offset (loc); |
2396 | |
2397 | var_mem_decl_set (set, loc, initialized, |
2398 | dv_from_decl (decl), offset, set_src, INSERT); |
2399 | } |
2400 | |
2401 | /* Delete and set the location part of variable MEM_EXPR (LOC) in |
2402 | dataflow set SET to LOC. If MODIFY is true, any other live copies |
2403 | of the same variable part are also deleted from the dataflow set, |
2404 | otherwise the variable part is assumed to be copied from another |
2405 | location holding the same part. |
2406 | Adjust the address first if it is stack pointer based. */ |
2407 | |
2408 | static void |
2409 | var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify, |
2410 | enum var_init_status initialized, rtx set_src) |
2411 | { |
2412 | tree decl = MEM_EXPR (loc)(get_mem_attrs (loc)->expr); |
2413 | HOST_WIDE_INTlong offset = int_mem_offset (loc); |
2414 | |
2415 | clobber_overlapping_mems (set, loc); |
2416 | decl = var_debug_decl (decl); |
2417 | |
2418 | if (initialized == VAR_INIT_STATUS_UNKNOWN) |
2419 | initialized = get_init_value (set, loc, dv_from_decl (decl)); |
2420 | |
2421 | if (modify) |
2422 | clobber_variable_part (set, NULLnullptr, dv_from_decl (decl), offset, set_src); |
2423 | var_mem_set (set, loc, initialized, set_src); |
2424 | } |
2425 | |
2426 | /* Delete the location part LOC from dataflow set SET. If CLOBBER is |
2427 | true, also delete any other live copies of the same variable part. |
2428 | Adjust the address first if it is stack pointer based. */ |
2429 | |
2430 | static void |
2431 | var_mem_delete (dataflow_set *set, rtx loc, bool clobber) |
2432 | { |
2433 | tree decl = MEM_EXPR (loc)(get_mem_attrs (loc)->expr); |
2434 | HOST_WIDE_INTlong offset = int_mem_offset (loc); |
2435 | |
2436 | clobber_overlapping_mems (set, loc); |
2437 | decl = var_debug_decl (decl); |
2438 | if (clobber) |
2439 | clobber_variable_part (set, NULLnullptr, dv_from_decl (decl), offset, NULLnullptr); |
2440 | delete_variable_part (set, loc, dv_from_decl (decl), offset); |
2441 | } |
2442 | |
2443 | /* Return true if LOC should not be expanded for location expressions, |
2444 | or used in them. */ |
2445 | |
2446 | static inline bool |
2447 | unsuitable_loc (rtx loc) |
2448 | { |
2449 | switch (GET_CODE (loc)((enum rtx_code) (loc)->code)) |
2450 | { |
2451 | case PC: |
2452 | case SCRATCH: |
2453 | case ASM_INPUT: |
2454 | case ASM_OPERANDS: |
2455 | return true; |
2456 | |
2457 | default: |
2458 | return false; |
2459 | } |
2460 | } |
2461 | |
2462 | /* Bind VAL to LOC in SET. If MODIFIED, detach LOC from any values |
2463 | bound to it. */ |
2464 | |
2465 | static inline void |
2466 | val_bind (dataflow_set *set, rtx val, rtx loc, bool modified) |
2467 | { |
2468 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG)) |
2469 | { |
2470 | if (modified) |
2471 | var_regno_delete (set, REGNO (loc)(rhs_regno(loc))); |
2472 | var_reg_decl_set (set, loc, VAR_INIT_STATUS_INITIALIZED, |
2473 | dv_from_value (val), 0, NULL_RTX(rtx) 0, INSERT); |
2474 | } |
2475 | else if (MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
2476 | { |
2477 | struct elt_loc_list *l = CSELIB_VAL_PTR (val)(((val)->u.fld[0]).rt_cselib)->locs; |
2478 | |
2479 | if (modified) |
2480 | clobber_overlapping_mems (set, loc); |
2481 | |
2482 | if (l && GET_CODE (l->loc)((enum rtx_code) (l->loc)->code) == VALUE) |
2483 | l = canonical_cselib_val (CSELIB_VAL_PTR (l->loc)(((l->loc)->u.fld[0]).rt_cselib))->locs; |
2484 | |
2485 | /* If this MEM is a global constant, we don't need it in the |
2486 | dynamic tables. ??? We should test this before emitting the |
2487 | micro-op in the first place. */ |
2488 | while (l) |
2489 | if (GET_CODE (l->loc)((enum rtx_code) (l->loc)->code) == MEM && XEXP (l->loc, 0)(((l->loc)->u.fld[0]).rt_rtx) == XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx)) |
2490 | break; |
2491 | else |
2492 | l = l->next; |
2493 | |
2494 | if (!l) |
2495 | var_mem_decl_set (set, loc, VAR_INIT_STATUS_INITIALIZED, |
2496 | dv_from_value (val), 0, NULL_RTX(rtx) 0, INSERT); |
2497 | } |
2498 | else |
2499 | { |
2500 | /* Other kinds of equivalences are necessarily static, at least |
2501 | so long as we do not perform substitutions while merging |
2502 | expressions. */ |
2503 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2503, __FUNCTION__)); |
2504 | set_variable_part (set, loc, dv_from_value (val), 0, |
2505 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX(rtx) 0, INSERT); |
2506 | } |
2507 | } |
2508 | |
2509 | /* Bind a value to a location it was just stored in. If MODIFIED |
2510 | holds, assume the location was modified, detaching it from any |
2511 | values bound to it. */ |
2512 | |
2513 | static void |
2514 | val_store (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn, |
2515 | bool modified) |
2516 | { |
2517 | cselib_val *v = CSELIB_VAL_PTR (val)(((val)->u.fld[0]).rt_cselib); |
2518 | |
2519 | gcc_assert (cselib_preserved_value_p (v))((void)(!(cselib_preserved_value_p (v)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2519, __FUNCTION__), 0 : 0)); |
2520 | |
2521 | if (dump_file) |
2522 | { |
2523 | fprintf (dump_file, "%i: ", insn ? INSN_UID (insn) : 0); |
2524 | print_inline_rtx (dump_file, loc, 0); |
2525 | fprintf (dump_file, " evaluates to "); |
2526 | print_inline_rtx (dump_file, val, 0); |
2527 | if (v->locs) |
2528 | { |
2529 | struct elt_loc_list *l; |
2530 | for (l = v->locs; l; l = l->next) |
2531 | { |
2532 | fprintf (dump_file, "\n%i: ", INSN_UID (l->setting_insn)); |
2533 | print_inline_rtx (dump_file, l->loc, 0); |
2534 | } |
2535 | } |
2536 | fprintf (dump_file, "\n"); |
2537 | } |
2538 | |
2539 | gcc_checking_assert (!unsuitable_loc (loc))((void)(!(!unsuitable_loc (loc)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2539, __FUNCTION__), 0 : 0)); |
2540 | |
2541 | val_bind (set, val, loc, modified); |
2542 | } |
2543 | |
2544 | /* Clear (canonical address) slots that reference X. */ |
2545 | |
2546 | bool |
2547 | local_get_addr_clear_given_value (rtx const &, rtx *slot, rtx x) |
2548 | { |
2549 | if (vt_get_canonicalize_base (*slot) == x) |
2550 | *slot = NULLnullptr; |
2551 | return true; |
2552 | } |
2553 | |
2554 | /* Reset this node, detaching all its equivalences. Return the slot |
2555 | in the variable hash table that holds dv, if there is one. */ |
2556 | |
2557 | static void |
2558 | val_reset (dataflow_set *set, decl_or_value dv) |
2559 | { |
2560 | variable *var = shared_hash_find (set->vars, dv) ; |
2561 | location_chain *node; |
2562 | rtx cval; |
2563 | |
2564 | if (!var || !var->n_var_parts) |
2565 | return; |
2566 | |
2567 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2567, __FUNCTION__), 0 : 0)); |
2568 | |
2569 | if (var->onepart == ONEPART_VALUE) |
2570 | { |
2571 | rtx x = dv_as_value (dv); |
2572 | |
2573 | /* Relationships in the global cache don't change, so reset the |
2574 | local cache entry only. */ |
2575 | rtx *slot = local_get_addr_cache->get (x); |
2576 | if (slot) |
2577 | { |
2578 | /* If the value resolved back to itself, odds are that other |
2579 | values may have cached it too. These entries now refer |
2580 | to the old X, so detach them too. Entries that used the |
2581 | old X but resolved to something else remain ok as long as |
2582 | that something else isn't also reset. */ |
2583 | if (*slot == x) |
2584 | local_get_addr_cache |
2585 | ->traverse<rtx, local_get_addr_clear_given_value> (x); |
2586 | *slot = NULLnullptr; |
2587 | } |
2588 | } |
2589 | |
2590 | cval = NULLnullptr; |
2591 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
2592 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE |
2593 | && canon_value_cmp (node->loc, cval)) |
2594 | cval = node->loc; |
2595 | |
2596 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
2597 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE && cval != node->loc) |
2598 | { |
2599 | /* Redirect the equivalence link to the new canonical |
2600 | value, or simply remove it if it would point at |
2601 | itself. */ |
2602 | if (cval) |
2603 | set_variable_part (set, cval, dv_from_value (node->loc), |
2604 | 0, node->init, node->set_src, NO_INSERT); |
2605 | delete_variable_part (set, dv_as_value (dv), |
2606 | dv_from_value (node->loc), 0); |
2607 | } |
2608 | |
2609 | if (cval) |
2610 | { |
2611 | decl_or_value cdv = dv_from_value (cval); |
2612 | |
2613 | /* Keep the remaining values connected, accumulating links |
2614 | in the canonical value. */ |
2615 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
2616 | { |
2617 | if (node->loc == cval) |
2618 | continue; |
2619 | else if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == REG) |
2620 | var_reg_decl_set (set, node->loc, node->init, cdv, 0, |
2621 | node->set_src, NO_INSERT); |
2622 | else if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == MEM) |
2623 | var_mem_decl_set (set, node->loc, node->init, cdv, 0, |
2624 | node->set_src, NO_INSERT); |
2625 | else |
2626 | set_variable_part (set, node->loc, cdv, 0, |
2627 | node->init, node->set_src, NO_INSERT); |
2628 | } |
2629 | } |
2630 | |
2631 | /* We remove this last, to make sure that the canonical value is not |
2632 | removed to the point of requiring reinsertion. */ |
2633 | if (cval) |
2634 | delete_variable_part (set, dv_as_value (dv), dv_from_value (cval), 0); |
2635 | |
2636 | clobber_variable_part (set, NULLnullptr, dv, 0, NULLnullptr); |
2637 | } |
2638 | |
2639 | /* Find the values in a given location and map the val to another |
2640 | value, if it is unique, or add the location as one holding the |
2641 | value. */ |
2642 | |
2643 | static void |
2644 | val_resolve (dataflow_set *set, rtx val, rtx loc, rtx_insn *insn) |
2645 | { |
2646 | decl_or_value dv = dv_from_value (val); |
2647 | |
2648 | if (dump_file && (dump_flags & TDF_DETAILS)) |
2649 | { |
2650 | if (insn) |
2651 | fprintf (dump_file, "%i: ", INSN_UID (insn)); |
2652 | else |
2653 | fprintf (dump_file, "head: "); |
2654 | print_inline_rtx (dump_file, val, 0); |
2655 | fputs (" is at ", dump_file); |
2656 | print_inline_rtx (dump_file, loc, 0); |
2657 | fputc ('\n', dump_file); |
2658 | } |
2659 | |
2660 | val_reset (set, dv); |
2661 | |
2662 | gcc_checking_assert (!unsuitable_loc (loc))((void)(!(!unsuitable_loc (loc)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2662, __FUNCTION__), 0 : 0)); |
2663 | |
2664 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG)) |
2665 | { |
2666 | attrs *node, *found = NULLnullptr; |
2667 | |
2668 | for (node = set->regs[REGNO (loc)(rhs_regno(loc))]; node; node = node->next) |
2669 | if (dv_is_value_p (node->dv) |
2670 | && GET_MODE (dv_as_value (node->dv))((machine_mode) (dv_as_value (node->dv))->mode) == GET_MODE (loc)((machine_mode) (loc)->mode)) |
2671 | { |
2672 | found = node; |
2673 | |
2674 | /* Map incoming equivalences. ??? Wouldn't it be nice if |
2675 | we just started sharing the location lists? Maybe a |
2676 | circular list ending at the value itself or some |
2677 | such. */ |
2678 | set_variable_part (set, dv_as_value (node->dv), |
2679 | dv_from_value (val), node->offset, |
2680 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX(rtx) 0, INSERT); |
2681 | set_variable_part (set, val, node->dv, node->offset, |
2682 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX(rtx) 0, INSERT); |
2683 | } |
2684 | |
2685 | /* If we didn't find any equivalence, we need to remember that |
2686 | this value is held in the named register. */ |
2687 | if (found) |
2688 | return; |
2689 | } |
2690 | /* ??? Attempt to find and merge equivalent MEMs or other |
2691 | expressions too. */ |
2692 | |
2693 | val_bind (set, val, loc, false); |
2694 | } |
2695 | |
2696 | /* Initialize dataflow set SET to be empty. |
2697 | VARS_SIZE is the initial size of hash table VARS. */ |
2698 | |
2699 | static void |
2700 | dataflow_set_init (dataflow_set *set) |
2701 | { |
2702 | init_attrs_list_set (set->regs); |
2703 | set->vars = shared_hash_copy (empty_shared_hash); |
2704 | set->stack_adjust = 0; |
2705 | set->traversed_vars = NULLnullptr; |
2706 | } |
2707 | |
2708 | /* Delete the contents of dataflow set SET. */ |
2709 | |
2710 | static void |
2711 | dataflow_set_clear (dataflow_set *set) |
2712 | { |
2713 | int i; |
2714 | |
2715 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
2716 | attrs_list_clear (&set->regs[i]); |
2717 | |
2718 | shared_hash_destroy (set->vars); |
2719 | set->vars = shared_hash_copy (empty_shared_hash); |
2720 | } |
2721 | |
2722 | /* Copy the contents of dataflow set SRC to DST. */ |
2723 | |
2724 | static void |
2725 | dataflow_set_copy (dataflow_set *dst, dataflow_set *src) |
2726 | { |
2727 | int i; |
2728 | |
2729 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
2730 | attrs_list_copy (&dst->regs[i], src->regs[i]); |
2731 | |
2732 | shared_hash_destroy (dst->vars); |
2733 | dst->vars = shared_hash_copy (src->vars); |
2734 | dst->stack_adjust = src->stack_adjust; |
2735 | } |
2736 | |
2737 | /* Information for merging lists of locations for a given offset of variable. |
2738 | */ |
2739 | struct variable_union_info |
2740 | { |
2741 | /* Node of the location chain. */ |
2742 | location_chain *lc; |
2743 | |
2744 | /* The sum of positions in the input chains. */ |
2745 | int pos; |
2746 | |
2747 | /* The position in the chain of DST dataflow set. */ |
2748 | int pos_dst; |
2749 | }; |
2750 | |
2751 | /* Buffer for location list sorting and its allocated size. */ |
2752 | static struct variable_union_info *vui_vec; |
2753 | static int vui_allocated; |
2754 | |
2755 | /* Compare function for qsort, order the structures by POS element. */ |
2756 | |
2757 | static int |
2758 | variable_union_info_cmp_pos (const void *n1, const void *n2) |
2759 | { |
2760 | const struct variable_union_info *const i1 = |
2761 | (const struct variable_union_info *) n1; |
2762 | const struct variable_union_info *const i2 = |
2763 | ( const struct variable_union_info *) n2; |
2764 | |
2765 | if (i1->pos != i2->pos) |
2766 | return i1->pos - i2->pos; |
2767 | |
2768 | return (i1->pos_dst - i2->pos_dst); |
2769 | } |
2770 | |
2771 | /* Compute union of location parts of variable *SLOT and the same variable |
2772 | from hash table DATA. Compute "sorted" union of the location chains |
2773 | for common offsets, i.e. the locations of a variable part are sorted by |
2774 | a priority where the priority is the sum of the positions in the 2 chains |
2775 | (if a location is only in one list the position in the second list is |
2776 | defined to be larger than the length of the chains). |
2777 | When we are updating the location parts the newest location is in the |
2778 | beginning of the chain, so when we do the described "sorted" union |
2779 | we keep the newest locations in the beginning. */ |
2780 | |
2781 | static int |
2782 | variable_union (variable *src, dataflow_set *set) |
2783 | { |
2784 | variable *dst; |
2785 | variable **dstp; |
2786 | int i, j, k; |
2787 | |
2788 | dstp = shared_hash_find_slot (set->vars, src->dv); |
2789 | if (!dstp || !*dstp) |
2790 | { |
2791 | src->refcount++; |
2792 | |
2793 | dst_can_be_shared = false; |
2794 | if (!dstp) |
2795 | dstp = shared_hash_find_slot_unshare (&set->vars, src->dv, INSERT); |
2796 | |
2797 | *dstp = src; |
2798 | |
2799 | /* Continue traversing the hash table. */ |
2800 | return 1; |
2801 | } |
2802 | else |
2803 | dst = *dstp; |
2804 | |
2805 | gcc_assert (src->n_var_parts)((void)(!(src->n_var_parts) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2805, __FUNCTION__), 0 : 0)); |
2806 | gcc_checking_assert (src->onepart == dst->onepart)((void)(!(src->onepart == dst->onepart) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2806, __FUNCTION__), 0 : 0)); |
2807 | |
2808 | /* We can combine one-part variables very efficiently, because their |
2809 | entries are in canonical order. */ |
2810 | if (src->onepart) |
2811 | { |
2812 | location_chain **nodep, *dnode, *snode; |
2813 | |
2814 | gcc_assert (src->n_var_parts == 1((void)(!(src->n_var_parts == 1 && dst->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2815, __FUNCTION__), 0 : 0)) |
2815 | && dst->n_var_parts == 1)((void)(!(src->n_var_parts == 1 && dst->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2815, __FUNCTION__), 0 : 0)); |
2816 | |
2817 | snode = src->var_part[0].loc_chain; |
2818 | gcc_assert (snode)((void)(!(snode) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2818, __FUNCTION__), 0 : 0)); |
2819 | |
2820 | restart_onepart_unshared: |
2821 | nodep = &dst->var_part[0].loc_chain; |
2822 | dnode = *nodep; |
2823 | gcc_assert (dnode)((void)(!(dnode) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2823, __FUNCTION__), 0 : 0)); |
2824 | |
2825 | while (snode) |
2826 | { |
2827 | int r = dnode ? loc_cmp (dnode->loc, snode->loc) : 1; |
2828 | |
2829 | if (r > 0) |
2830 | { |
2831 | location_chain *nnode; |
2832 | |
2833 | if (shared_var_p (dst, set->vars)) |
2834 | { |
2835 | dstp = unshare_variable (set, dstp, dst, |
2836 | VAR_INIT_STATUS_INITIALIZED); |
2837 | dst = *dstp; |
2838 | goto restart_onepart_unshared; |
2839 | } |
2840 | |
2841 | *nodep = nnode = new location_chain; |
2842 | nnode->loc = snode->loc; |
2843 | nnode->init = snode->init; |
2844 | if (!snode->set_src || MEM_P (snode->set_src)(((enum rtx_code) (snode->set_src)->code) == MEM)) |
2845 | nnode->set_src = NULLnullptr; |
2846 | else |
2847 | nnode->set_src = snode->set_src; |
2848 | nnode->next = dnode; |
2849 | dnode = nnode; |
2850 | } |
2851 | else if (r == 0) |
2852 | gcc_checking_assert (rtx_equal_p (dnode->loc, snode->loc))((void)(!(rtx_equal_p (dnode->loc, snode->loc)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2852, __FUNCTION__), 0 : 0)); |
2853 | |
2854 | if (r >= 0) |
2855 | snode = snode->next; |
2856 | |
2857 | nodep = &dnode->next; |
2858 | dnode = *nodep; |
2859 | } |
2860 | |
2861 | return 1; |
2862 | } |
2863 | |
2864 | gcc_checking_assert (!src->onepart)((void)(!(!src->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2864, __FUNCTION__), 0 : 0)); |
2865 | |
2866 | /* Count the number of location parts, result is K. */ |
2867 | for (i = 0, j = 0, k = 0; |
2868 | i < src->n_var_parts && j < dst->n_var_parts; k++) |
2869 | { |
2870 | if (VAR_PART_OFFSET (src, i)__extension__ (*({ variable *const __v = (src); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2870, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) == VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2870, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; }))) |
2871 | { |
2872 | i++; |
2873 | j++; |
2874 | } |
2875 | else if (VAR_PART_OFFSET (src, i)__extension__ (*({ variable *const __v = (src); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2875, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) < VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2875, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; }))) |
2876 | i++; |
2877 | else |
2878 | j++; |
2879 | } |
2880 | k += src->n_var_parts - i; |
2881 | k += dst->n_var_parts - j; |
2882 | |
2883 | /* We track only variables whose size is <= MAX_VAR_PARTS bytes |
2884 | thus there are at most MAX_VAR_PARTS different offsets. */ |
2885 | gcc_checking_assert (dst->onepart ? k == 1 : k <= MAX_VAR_PARTS)((void)(!(dst->onepart ? k == 1 : k <= 16) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2885, __FUNCTION__), 0 : 0)); |
2886 | |
2887 | if (dst->n_var_parts != k && shared_var_p (dst, set->vars)) |
2888 | { |
2889 | dstp = unshare_variable (set, dstp, dst, VAR_INIT_STATUS_UNKNOWN); |
2890 | dst = *dstp; |
2891 | } |
2892 | |
2893 | i = src->n_var_parts - 1; |
2894 | j = dst->n_var_parts - 1; |
2895 | dst->n_var_parts = k; |
2896 | |
2897 | for (k--; k >= 0; k--) |
2898 | { |
2899 | location_chain *node, *node2; |
2900 | |
2901 | if (i >= 0 && j >= 0 |
2902 | && VAR_PART_OFFSET (src, i)__extension__ (*({ variable *const __v = (src); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2902, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) == VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2902, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; }))) |
2903 | { |
2904 | /* Compute the "sorted" union of the chains, i.e. the locations which |
2905 | are in both chains go first, they are sorted by the sum of |
2906 | positions in the chains. */ |
2907 | int dst_l, src_l; |
2908 | int ii, jj, n; |
2909 | struct variable_union_info *vui; |
2910 | |
2911 | /* If DST is shared compare the location chains. |
2912 | If they are different we will modify the chain in DST with |
2913 | high probability so make a copy of DST. */ |
2914 | if (shared_var_p (dst, set->vars)) |
2915 | { |
2916 | for (node = src->var_part[i].loc_chain, |
2917 | node2 = dst->var_part[j].loc_chain; node && node2; |
2918 | node = node->next, node2 = node2->next) |
2919 | { |
2920 | if (!((REG_P (node2->loc)(((enum rtx_code) (node2->loc)->code) == REG) |
2921 | && REG_P (node->loc)(((enum rtx_code) (node->loc)->code) == REG) |
2922 | && REGNO (node2->loc)(rhs_regno(node2->loc)) == REGNO (node->loc)(rhs_regno(node->loc))) |
2923 | || rtx_equal_p (node2->loc, node->loc))) |
2924 | { |
2925 | if (node2->init < node->init) |
2926 | node2->init = node->init; |
2927 | break; |
2928 | } |
2929 | } |
2930 | if (node || node2) |
2931 | { |
2932 | dstp = unshare_variable (set, dstp, dst, |
2933 | VAR_INIT_STATUS_UNKNOWN); |
2934 | dst = (variable *)*dstp; |
2935 | } |
2936 | } |
2937 | |
2938 | src_l = 0; |
2939 | for (node = src->var_part[i].loc_chain; node; node = node->next) |
2940 | src_l++; |
2941 | dst_l = 0; |
2942 | for (node = dst->var_part[j].loc_chain; node; node = node->next) |
2943 | dst_l++; |
2944 | |
2945 | if (dst_l == 1) |
2946 | { |
2947 | /* The most common case, much simpler, no qsort is needed. */ |
2948 | location_chain *dstnode = dst->var_part[j].loc_chain; |
2949 | dst->var_part[k].loc_chain = dstnode; |
2950 | VAR_PART_OFFSET (dst, k)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2950, __FUNCTION__), 0 : 0)); &__v->var_part[(k)].aux .offset; })) = VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 2950, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; })); |
2951 | node2 = dstnode; |
2952 | for (node = src->var_part[i].loc_chain; node; node = node->next) |
2953 | if (!((REG_P (dstnode->loc)(((enum rtx_code) (dstnode->loc)->code) == REG) |
2954 | && REG_P (node->loc)(((enum rtx_code) (node->loc)->code) == REG) |
2955 | && REGNO (dstnode->loc)(rhs_regno(dstnode->loc)) == REGNO (node->loc)(rhs_regno(node->loc))) |
2956 | || rtx_equal_p (dstnode->loc, node->loc))) |
2957 | { |
2958 | location_chain *new_node; |
2959 | |
2960 | /* Copy the location from SRC. */ |
2961 | new_node = new location_chain; |
2962 | new_node->loc = node->loc; |
2963 | new_node->init = node->init; |
2964 | if (!node->set_src || MEM_P (node->set_src)(((enum rtx_code) (node->set_src)->code) == MEM)) |
2965 | new_node->set_src = NULLnullptr; |
2966 | else |
2967 | new_node->set_src = node->set_src; |
2968 | node2->next = new_node; |
2969 | node2 = new_node; |
2970 | } |
2971 | node2->next = NULLnullptr; |
2972 | } |
2973 | else |
2974 | { |
2975 | if (src_l + dst_l > vui_allocated) |
2976 | { |
2977 | vui_allocated = MAX (vui_allocated * 2, src_l + dst_l)((vui_allocated * 2) > (src_l + dst_l) ? (vui_allocated * 2 ) : (src_l + dst_l)); |
2978 | vui_vec = XRESIZEVEC (struct variable_union_info, vui_vec,((struct variable_union_info *) xrealloc ((void *) (vui_vec), sizeof (struct variable_union_info) * (vui_allocated))) |
2979 | vui_allocated)((struct variable_union_info *) xrealloc ((void *) (vui_vec), sizeof (struct variable_union_info) * (vui_allocated))); |
2980 | } |
2981 | vui = vui_vec; |
2982 | |
2983 | /* Fill in the locations from DST. */ |
2984 | for (node = dst->var_part[j].loc_chain, jj = 0; node; |
2985 | node = node->next, jj++) |
2986 | { |
2987 | vui[jj].lc = node; |
2988 | vui[jj].pos_dst = jj; |
2989 | |
2990 | /* Pos plus value larger than a sum of 2 valid positions. */ |
2991 | vui[jj].pos = jj + src_l + dst_l; |
2992 | } |
2993 | |
2994 | /* Fill in the locations from SRC. */ |
2995 | n = dst_l; |
2996 | for (node = src->var_part[i].loc_chain, ii = 0; node; |
2997 | node = node->next, ii++) |
2998 | { |
2999 | /* Find location from NODE. */ |
3000 | for (jj = 0; jj < dst_l; jj++) |
3001 | { |
3002 | if ((REG_P (vui[jj].lc->loc)(((enum rtx_code) (vui[jj].lc->loc)->code) == REG) |
3003 | && REG_P (node->loc)(((enum rtx_code) (node->loc)->code) == REG) |
3004 | && REGNO (vui[jj].lc->loc)(rhs_regno(vui[jj].lc->loc)) == REGNO (node->loc)(rhs_regno(node->loc))) |
3005 | || rtx_equal_p (vui[jj].lc->loc, node->loc)) |
3006 | { |
3007 | vui[jj].pos = jj + ii; |
3008 | break; |
3009 | } |
3010 | } |
3011 | if (jj >= dst_l) /* The location has not been found. */ |
3012 | { |
3013 | location_chain *new_node; |
3014 | |
3015 | /* Copy the location from SRC. */ |
3016 | new_node = new location_chain; |
3017 | new_node->loc = node->loc; |
3018 | new_node->init = node->init; |
3019 | if (!node->set_src || MEM_P (node->set_src)(((enum rtx_code) (node->set_src)->code) == MEM)) |
3020 | new_node->set_src = NULLnullptr; |
3021 | else |
3022 | new_node->set_src = node->set_src; |
3023 | vui[n].lc = new_node; |
3024 | vui[n].pos_dst = src_l + dst_l; |
3025 | vui[n].pos = ii + src_l + dst_l; |
3026 | n++; |
3027 | } |
3028 | } |
3029 | |
3030 | if (dst_l == 2) |
3031 | { |
3032 | /* Special case still very common case. For dst_l == 2 |
3033 | all entries dst_l ... n-1 are sorted, with for i >= dst_l |
3034 | vui[i].pos == i + src_l + dst_l. */ |
3035 | if (vui[0].pos > vui[1].pos) |
3036 | { |
3037 | /* Order should be 1, 0, 2... */ |
3038 | dst->var_part[k].loc_chain = vui[1].lc; |
3039 | vui[1].lc->next = vui[0].lc; |
3040 | if (n >= 3) |
3041 | { |
3042 | vui[0].lc->next = vui[2].lc; |
3043 | vui[n - 1].lc->next = NULLnullptr; |
3044 | } |
3045 | else |
3046 | vui[0].lc->next = NULLnullptr; |
3047 | ii = 3; |
3048 | } |
3049 | else |
3050 | { |
3051 | dst->var_part[k].loc_chain = vui[0].lc; |
3052 | if (n >= 3 && vui[2].pos < vui[1].pos) |
3053 | { |
3054 | /* Order should be 0, 2, 1, 3... */ |
3055 | vui[0].lc->next = vui[2].lc; |
3056 | vui[2].lc->next = vui[1].lc; |
3057 | if (n >= 4) |
3058 | { |
3059 | vui[1].lc->next = vui[3].lc; |
3060 | vui[n - 1].lc->next = NULLnullptr; |
3061 | } |
3062 | else |
3063 | vui[1].lc->next = NULLnullptr; |
3064 | ii = 4; |
3065 | } |
3066 | else |
3067 | { |
3068 | /* Order should be 0, 1, 2... */ |
3069 | ii = 1; |
3070 | vui[n - 1].lc->next = NULLnullptr; |
3071 | } |
3072 | } |
3073 | for (; ii < n; ii++) |
3074 | vui[ii - 1].lc->next = vui[ii].lc; |
3075 | } |
3076 | else |
3077 | { |
3078 | qsort (vui, n, sizeof (struct variable_union_info),gcc_qsort (vui, n, sizeof (struct variable_union_info), variable_union_info_cmp_pos ) |
3079 | variable_union_info_cmp_pos)gcc_qsort (vui, n, sizeof (struct variable_union_info), variable_union_info_cmp_pos ); |
3080 | |
3081 | /* Reconnect the nodes in sorted order. */ |
3082 | for (ii = 1; ii < n; ii++) |
3083 | vui[ii - 1].lc->next = vui[ii].lc; |
3084 | vui[n - 1].lc->next = NULLnullptr; |
3085 | dst->var_part[k].loc_chain = vui[0].lc; |
3086 | } |
3087 | |
3088 | VAR_PART_OFFSET (dst, k)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3088, __FUNCTION__), 0 : 0)); &__v->var_part[(k)].aux .offset; })) = VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3088, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; })); |
3089 | } |
3090 | i--; |
3091 | j--; |
3092 | } |
3093 | else if ((i >= 0 && j >= 0 |
3094 | && VAR_PART_OFFSET (src, i)__extension__ (*({ variable *const __v = (src); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3094, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) < VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3094, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; }))) |
3095 | || i < 0) |
3096 | { |
3097 | dst->var_part[k] = dst->var_part[j]; |
3098 | j--; |
3099 | } |
3100 | else if ((i >= 0 && j >= 0 |
3101 | && VAR_PART_OFFSET (src, i)__extension__ (*({ variable *const __v = (src); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3101, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) > VAR_PART_OFFSET (dst, j)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3101, __FUNCTION__), 0 : 0)); &__v->var_part[(j)].aux .offset; }))) |
3102 | || j < 0) |
3103 | { |
3104 | location_chain **nextp; |
3105 | |
3106 | /* Copy the chain from SRC. */ |
3107 | nextp = &dst->var_part[k].loc_chain; |
3108 | for (node = src->var_part[i].loc_chain; node; node = node->next) |
3109 | { |
3110 | location_chain *new_lc; |
3111 | |
3112 | new_lc = new location_chain; |
3113 | new_lc->next = NULLnullptr; |
3114 | new_lc->init = node->init; |
3115 | if (!node->set_src || MEM_P (node->set_src)(((enum rtx_code) (node->set_src)->code) == MEM)) |
3116 | new_lc->set_src = NULLnullptr; |
3117 | else |
3118 | new_lc->set_src = node->set_src; |
3119 | new_lc->loc = node->loc; |
3120 | |
3121 | *nextp = new_lc; |
3122 | nextp = &new_lc->next; |
3123 | } |
3124 | |
3125 | VAR_PART_OFFSET (dst, k)__extension__ (*({ variable *const __v = (dst); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3125, __FUNCTION__), 0 : 0)); &__v->var_part[(k)].aux .offset; })) = VAR_PART_OFFSET (src, i)__extension__ (*({ variable *const __v = (src); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3125, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })); |
3126 | i--; |
3127 | } |
3128 | dst->var_part[k].cur_loc = NULLnullptr; |
3129 | } |
3130 | |
3131 | if (flag_var_tracking_uninitglobal_options.x_flag_var_tracking_uninit) |
3132 | for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++) |
3133 | { |
3134 | location_chain *node, *node2; |
3135 | for (node = src->var_part[i].loc_chain; node; node = node->next) |
3136 | for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next) |
3137 | if (rtx_equal_p (node->loc, node2->loc)) |
3138 | { |
3139 | if (node->init > node2->init) |
3140 | node2->init = node->init; |
3141 | } |
3142 | } |
3143 | |
3144 | /* Continue traversing the hash table. */ |
3145 | return 1; |
3146 | } |
3147 | |
3148 | /* Compute union of dataflow sets SRC and DST and store it to DST. */ |
3149 | |
3150 | static void |
3151 | dataflow_set_union (dataflow_set *dst, dataflow_set *src) |
3152 | { |
3153 | int i; |
3154 | |
3155 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
3156 | attrs_list_union (&dst->regs[i], src->regs[i]); |
3157 | |
3158 | if (dst->vars == empty_shared_hash) |
3159 | { |
3160 | shared_hash_destroy (dst->vars); |
3161 | dst->vars = shared_hash_copy (src->vars); |
3162 | } |
3163 | else |
3164 | { |
3165 | variable_iterator_type hi; |
3166 | variable *var; |
3167 | |
3168 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (src->vars),for ((hi) = (*shared_hash_htab (src->vars)).begin (); (hi) != (*shared_hash_htab (src->vars)).end () ? (var = *(hi) , true) : false; ++(hi)) |
3169 | var, variable, hi)for ((hi) = (*shared_hash_htab (src->vars)).begin (); (hi) != (*shared_hash_htab (src->vars)).end () ? (var = *(hi) , true) : false; ++(hi)) |
3170 | variable_union (var, dst); |
3171 | } |
3172 | } |
3173 | |
3174 | /* Whether the value is currently being expanded. */ |
3175 | #define VALUE_RECURSED_INTO(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3175, __FUNCTION__); _rtx; })->used) \ |
3176 | (RTL_FLAG_CHECK2 ("VALUE_RECURSED_INTO", (x), VALUE, DEBUG_EXPR)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3176, __FUNCTION__); _rtx; })->used) |
3177 | |
3178 | /* Whether no expansion was found, saving useless lookups. |
3179 | It must only be set when VALUE_CHANGED is clear. */ |
3180 | #define NO_LOC_P(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("NO_LOC_P" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3180, __FUNCTION__); _rtx; })->return_val) \ |
3181 | (RTL_FLAG_CHECK2 ("NO_LOC_P", (x), VALUE, DEBUG_EXPR)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("NO_LOC_P" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3181, __FUNCTION__); _rtx; })->return_val) |
3182 | |
3183 | /* Whether cur_loc in the value needs to be (re)computed. */ |
3184 | #define VALUE_CHANGED(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != VALUE) rtl_check_failed_flag ( "VALUE_CHANGED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3184, __FUNCTION__); _rtx; })->frame_related) \ |
3185 | (RTL_FLAG_CHECK1 ("VALUE_CHANGED", (x), VALUE)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != VALUE) rtl_check_failed_flag ( "VALUE_CHANGED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3185, __FUNCTION__); _rtx; })->frame_related) |
3186 | /* Whether cur_loc in the decl needs to be (re)computed. */ |
3187 | #define DECL_CHANGED(x)((x)->base.visited) TREE_VISITED (x)((x)->base.visited) |
3188 | |
3189 | /* Record (if NEWV) that DV needs to have its cur_loc recomputed. For |
3190 | user DECLs, this means they're in changed_variables. Values and |
3191 | debug exprs may be left with this flag set if no user variable |
3192 | requires them to be evaluated. */ |
3193 | |
3194 | static inline void |
3195 | set_dv_changed (decl_or_value dv, bool newv) |
3196 | { |
3197 | switch (dv_onepart_p (dv)) |
3198 | { |
3199 | case ONEPART_VALUE: |
3200 | if (newv) |
3201 | NO_LOC_P (dv_as_value (dv))(__extension__ ({ __typeof ((dv_as_value (dv))) const _rtx = ( (dv_as_value (dv))); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR ) rtl_check_failed_flag ("NO_LOC_P",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3201, __FUNCTION__); _rtx; })->return_val) = false; |
3202 | VALUE_CHANGED (dv_as_value (dv))(__extension__ ({ __typeof ((dv_as_value (dv))) const _rtx = ( (dv_as_value (dv))); if (((enum rtx_code) (_rtx)->code) != VALUE) rtl_check_failed_flag ("VALUE_CHANGED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3202, __FUNCTION__); _rtx; })->frame_related) = newv; |
3203 | break; |
3204 | |
3205 | case ONEPART_DEXPR: |
3206 | if (newv) |
3207 | NO_LOC_P (DECL_RTL_KNOWN_SET (dv_as_decl (dv)))(__extension__ ({ __typeof ((__extension__ ({ tree const __d = (dv_as_decl (dv)); ((void)(!((((tree_contains_struct[(((enum tree_code) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__))->decl_with_rtl.rtl != nullptr)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__), 0 : 0)); &*((((tree_contains_struct [(((enum tree_code) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__))->decl_with_rtl.rtl != nullptr) ? (( contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__))->decl_with_rtl.rtl ? (__d)->decl_with_rtl .rtl : (make_decl_rtl (__d), (__d)->decl_with_rtl.rtl)) : nullptr ); }))) const _rtx = ((__extension__ ({ tree const __d = (dv_as_decl (dv)); ((void)(!((((tree_contains_struct[(((enum tree_code) ( __d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__))->decl_with_rtl.rtl != nullptr)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__), 0 : 0)); &*((((tree_contains_struct [(((enum tree_code) (__d)->base.code))][(TS_DECL_WRTL)])) && (contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__))->decl_with_rtl.rtl != nullptr) ? (( contains_struct_check ((__d), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__))->decl_with_rtl.rtl ? (__d)->decl_with_rtl .rtl : (make_decl_rtl (__d), (__d)->decl_with_rtl.rtl)) : nullptr ); }))); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("NO_LOC_P",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3207, __FUNCTION__); _rtx; })->return_val) = false; |
3208 | /* Fall through. */ |
3209 | |
3210 | default: |
3211 | DECL_CHANGED (dv_as_decl (dv))((dv_as_decl (dv))->base.visited) = newv; |
3212 | break; |
3213 | } |
3214 | } |
3215 | |
3216 | /* Return true if DV needs to have its cur_loc recomputed. */ |
3217 | |
3218 | static inline bool |
3219 | dv_changed_p (decl_or_value dv) |
3220 | { |
3221 | return (dv_is_value_p (dv) |
3222 | ? VALUE_CHANGED (dv_as_value (dv))(__extension__ ({ __typeof ((dv_as_value (dv))) const _rtx = ( (dv_as_value (dv))); if (((enum rtx_code) (_rtx)->code) != VALUE) rtl_check_failed_flag ("VALUE_CHANGED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3222, __FUNCTION__); _rtx; })->frame_related) |
3223 | : DECL_CHANGED (dv_as_decl (dv))((dv_as_decl (dv))->base.visited)); |
3224 | } |
3225 | |
3226 | /* Return a location list node whose loc is rtx_equal to LOC, in the |
3227 | location list of a one-part variable or value VAR, or in that of |
3228 | any values recursively mentioned in the location lists. VARS must |
3229 | be in star-canonical form. */ |
3230 | |
3231 | static location_chain * |
3232 | find_loc_in_1pdv (rtx loc, variable *var, variable_table_type *vars) |
3233 | { |
3234 | location_chain *node; |
3235 | enum rtx_code loc_code; |
3236 | |
3237 | if (!var) |
3238 | return NULLnullptr; |
3239 | |
3240 | gcc_checking_assert (var->onepart)((void)(!(var->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3240, __FUNCTION__), 0 : 0)); |
3241 | |
3242 | if (!var->n_var_parts) |
3243 | return NULLnullptr; |
3244 | |
3245 | gcc_checking_assert (loc != dv_as_opaque (var->dv))((void)(!(loc != dv_as_opaque (var->dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3245, __FUNCTION__), 0 : 0)); |
3246 | |
3247 | loc_code = GET_CODE (loc)((enum rtx_code) (loc)->code); |
3248 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
3249 | { |
3250 | decl_or_value dv; |
3251 | variable *rvar; |
3252 | |
3253 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) != loc_code) |
3254 | { |
3255 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) != VALUE) |
3256 | continue; |
3257 | } |
3258 | else if (loc == node->loc) |
3259 | return node; |
3260 | else if (loc_code != VALUE) |
3261 | { |
3262 | if (rtx_equal_p (loc, node->loc)) |
3263 | return node; |
3264 | continue; |
3265 | } |
3266 | |
3267 | /* Since we're in star-canonical form, we don't need to visit |
3268 | non-canonical nodes: one-part variables and non-canonical |
3269 | values would only point back to the canonical node. */ |
3270 | if (dv_is_value_p (var->dv) |
3271 | && !canon_value_cmp (node->loc, dv_as_value (var->dv))) |
3272 | { |
3273 | /* Skip all subsequent VALUEs. */ |
3274 | while (node->next && GET_CODE (node->next->loc)((enum rtx_code) (node->next->loc)->code) == VALUE) |
3275 | { |
3276 | node = node->next; |
3277 | gcc_checking_assert (!canon_value_cmp (node->loc,((void)(!(!canon_value_cmp (node->loc, dv_as_value (var-> dv))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3278, __FUNCTION__), 0 : 0)) |
3278 | dv_as_value (var->dv)))((void)(!(!canon_value_cmp (node->loc, dv_as_value (var-> dv))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3278, __FUNCTION__), 0 : 0)); |
3279 | if (loc == node->loc) |
3280 | return node; |
3281 | } |
3282 | continue; |
3283 | } |
3284 | |
3285 | gcc_checking_assert (node == var->var_part[0].loc_chain)((void)(!(node == var->var_part[0].loc_chain) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3285, __FUNCTION__), 0 : 0)); |
3286 | gcc_checking_assert (!node->next)((void)(!(!node->next) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3286, __FUNCTION__), 0 : 0)); |
3287 | |
3288 | dv = dv_from_value (node->loc); |
3289 | rvar = vars->find_with_hash (dv, dv_htab_hash (dv)); |
3290 | return find_loc_in_1pdv (loc, rvar, vars); |
3291 | } |
3292 | |
3293 | /* ??? Gotta look in cselib_val locations too. */ |
3294 | |
3295 | return NULLnullptr; |
3296 | } |
3297 | |
3298 | /* Hash table iteration argument passed to variable_merge. */ |
3299 | struct dfset_merge |
3300 | { |
3301 | /* The set in which the merge is to be inserted. */ |
3302 | dataflow_set *dst; |
3303 | /* The set that we're iterating in. */ |
3304 | dataflow_set *cur; |
3305 | /* The set that may contain the other dv we are to merge with. */ |
3306 | dataflow_set *src; |
3307 | /* Number of onepart dvs in src. */ |
3308 | int src_onepart_cnt; |
3309 | }; |
3310 | |
3311 | /* Insert LOC in *DNODE, if it's not there yet. The list must be in |
3312 | loc_cmp order, and it is maintained as such. */ |
3313 | |
3314 | static void |
3315 | insert_into_intersection (location_chain **nodep, rtx loc, |
3316 | enum var_init_status status) |
3317 | { |
3318 | location_chain *node; |
3319 | int r; |
3320 | |
3321 | for (node = *nodep; node; nodep = &node->next, node = *nodep) |
3322 | if ((r = loc_cmp (node->loc, loc)) == 0) |
3323 | { |
3324 | node->init = MIN (node->init, status)((node->init) < (status) ? (node->init) : (status)); |
3325 | return; |
3326 | } |
3327 | else if (r > 0) |
3328 | break; |
3329 | |
3330 | node = new location_chain; |
3331 | |
3332 | node->loc = loc; |
3333 | node->set_src = NULLnullptr; |
3334 | node->init = status; |
3335 | node->next = *nodep; |
3336 | *nodep = node; |
3337 | } |
3338 | |
3339 | /* Insert in DEST the intersection of the locations present in both |
3340 | S1NODE and S2VAR, directly or indirectly. S1NODE is from a |
3341 | variable in DSM->cur, whereas S2VAR is from DSM->src. dvar is in |
3342 | DSM->dst. */ |
3343 | |
3344 | static void |
3345 | intersect_loc_chains (rtx val, location_chain **dest, struct dfset_merge *dsm, |
3346 | location_chain *s1node, variable *s2var) |
3347 | { |
3348 | dataflow_set *s1set = dsm->cur; |
3349 | dataflow_set *s2set = dsm->src; |
3350 | location_chain *found; |
3351 | |
3352 | if (s2var) |
3353 | { |
3354 | location_chain *s2node; |
3355 | |
3356 | gcc_checking_assert (s2var->onepart)((void)(!(s2var->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3356, __FUNCTION__), 0 : 0)); |
3357 | |
3358 | if (s2var->n_var_parts) |
3359 | { |
3360 | s2node = s2var->var_part[0].loc_chain; |
3361 | |
3362 | for (; s1node && s2node; |
3363 | s1node = s1node->next, s2node = s2node->next) |
3364 | if (s1node->loc != s2node->loc) |
3365 | break; |
3366 | else if (s1node->loc == val) |
3367 | continue; |
3368 | else |
3369 | insert_into_intersection (dest, s1node->loc, |
3370 | MIN (s1node->init, s2node->init)((s1node->init) < (s2node->init) ? (s1node->init) : (s2node->init))); |
3371 | } |
3372 | } |
3373 | |
3374 | for (; s1node; s1node = s1node->next) |
3375 | { |
3376 | if (s1node->loc == val) |
3377 | continue; |
3378 | |
3379 | if ((found = find_loc_in_1pdv (s1node->loc, s2var, |
3380 | shared_hash_htab (s2set->vars)))) |
3381 | { |
3382 | insert_into_intersection (dest, s1node->loc, |
3383 | MIN (s1node->init, found->init)((s1node->init) < (found->init) ? (s1node->init) : (found->init))); |
3384 | continue; |
3385 | } |
3386 | |
3387 | if (GET_CODE (s1node->loc)((enum rtx_code) (s1node->loc)->code) == VALUE |
3388 | && !VALUE_RECURSED_INTO (s1node->loc)(__extension__ ({ __typeof ((s1node->loc)) const _rtx = (( s1node->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3388, __FUNCTION__); _rtx; })->used)) |
3389 | { |
3390 | decl_or_value dv = dv_from_value (s1node->loc); |
3391 | variable *svar = shared_hash_find (s1set->vars, dv); |
3392 | if (svar) |
3393 | { |
3394 | if (svar->n_var_parts == 1) |
3395 | { |
3396 | VALUE_RECURSED_INTO (s1node->loc)(__extension__ ({ __typeof ((s1node->loc)) const _rtx = (( s1node->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3396, __FUNCTION__); _rtx; })->used) = true; |
3397 | intersect_loc_chains (val, dest, dsm, |
3398 | svar->var_part[0].loc_chain, |
3399 | s2var); |
3400 | VALUE_RECURSED_INTO (s1node->loc)(__extension__ ({ __typeof ((s1node->loc)) const _rtx = (( s1node->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3400, __FUNCTION__); _rtx; })->used) = false; |
3401 | } |
3402 | } |
3403 | } |
3404 | |
3405 | /* ??? gotta look in cselib_val locations too. */ |
3406 | |
3407 | /* ??? if the location is equivalent to any location in src, |
3408 | searched recursively |
3409 | |
3410 | add to dst the values needed to represent the equivalence |
3411 | |
3412 | telling whether locations S is equivalent to another dv's |
3413 | location list: |
3414 | |
3415 | for each location D in the list |
3416 | |
3417 | if S and D satisfy rtx_equal_p, then it is present |
3418 | |
3419 | else if D is a value, recurse without cycles |
3420 | |
3421 | else if S and D have the same CODE and MODE |
3422 | |
3423 | for each operand oS and the corresponding oD |
3424 | |
3425 | if oS and oD are not equivalent, then S an D are not equivalent |
3426 | |
3427 | else if they are RTX vectors |
3428 | |
3429 | if any vector oS element is not equivalent to its respective oD, |
3430 | then S and D are not equivalent |
3431 | |
3432 | */ |
3433 | |
3434 | |
3435 | } |
3436 | } |
3437 | |
3438 | /* Return -1 if X should be before Y in a location list for a 1-part |
3439 | variable, 1 if Y should be before X, and 0 if they're equivalent |
3440 | and should not appear in the list. */ |
3441 | |
3442 | static int |
3443 | loc_cmp (rtx x, rtx y) |
3444 | { |
3445 | int i, j, r; |
3446 | RTX_CODEenum rtx_code code = GET_CODE (x)((enum rtx_code) (x)->code); |
3447 | const char *fmt; |
3448 | |
3449 | if (x == y) |
3450 | return 0; |
3451 | |
3452 | if (REG_P (x)(((enum rtx_code) (x)->code) == REG)) |
3453 | { |
3454 | if (!REG_P (y)(((enum rtx_code) (y)->code) == REG)) |
3455 | return -1; |
3456 | gcc_assert (GET_MODE (x) == GET_MODE (y))((void)(!(((machine_mode) (x)->mode) == ((machine_mode) (y )->mode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3456, __FUNCTION__), 0 : 0)); |
3457 | if (REGNO (x)(rhs_regno(x)) == REGNO (y)(rhs_regno(y))) |
3458 | return 0; |
3459 | else if (REGNO (x)(rhs_regno(x)) < REGNO (y)(rhs_regno(y))) |
3460 | return -1; |
3461 | else |
3462 | return 1; |
3463 | } |
3464 | |
3465 | if (REG_P (y)(((enum rtx_code) (y)->code) == REG)) |
3466 | return 1; |
3467 | |
3468 | if (MEM_P (x)(((enum rtx_code) (x)->code) == MEM)) |
3469 | { |
3470 | if (!MEM_P (y)(((enum rtx_code) (y)->code) == MEM)) |
3471 | return -1; |
3472 | gcc_assert (GET_MODE (x) == GET_MODE (y))((void)(!(((machine_mode) (x)->mode) == ((machine_mode) (y )->mode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3472, __FUNCTION__), 0 : 0)); |
3473 | return loc_cmp (XEXP (x, 0)(((x)->u.fld[0]).rt_rtx), XEXP (y, 0)(((y)->u.fld[0]).rt_rtx)); |
3474 | } |
3475 | |
3476 | if (MEM_P (y)(((enum rtx_code) (y)->code) == MEM)) |
3477 | return 1; |
3478 | |
3479 | if (GET_CODE (x)((enum rtx_code) (x)->code) == VALUE) |
3480 | { |
3481 | if (GET_CODE (y)((enum rtx_code) (y)->code) != VALUE) |
3482 | return -1; |
3483 | /* Don't assert the modes are the same, that is true only |
3484 | when not recursing. (subreg:QI (value:SI 1:1) 0) |
3485 | and (subreg:QI (value:DI 2:2) 0) can be compared, |
3486 | even when the modes are different. */ |
3487 | if (canon_value_cmp (x, y)) |
3488 | return -1; |
3489 | else |
3490 | return 1; |
3491 | } |
3492 | |
3493 | if (GET_CODE (y)((enum rtx_code) (y)->code) == VALUE) |
3494 | return 1; |
3495 | |
3496 | /* Entry value is the least preferable kind of expression. */ |
3497 | if (GET_CODE (x)((enum rtx_code) (x)->code) == ENTRY_VALUE) |
3498 | { |
3499 | if (GET_CODE (y)((enum rtx_code) (y)->code) != ENTRY_VALUE) |
3500 | return 1; |
3501 | gcc_assert (GET_MODE (x) == GET_MODE (y))((void)(!(((machine_mode) (x)->mode) == ((machine_mode) (y )->mode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3501, __FUNCTION__), 0 : 0)); |
3502 | return loc_cmp (ENTRY_VALUE_EXP (x)(((x)->u.fld[0]).rt_rtx), ENTRY_VALUE_EXP (y)(((y)->u.fld[0]).rt_rtx)); |
3503 | } |
3504 | |
3505 | if (GET_CODE (y)((enum rtx_code) (y)->code) == ENTRY_VALUE) |
3506 | return -1; |
3507 | |
3508 | if (GET_CODE (x)((enum rtx_code) (x)->code) == GET_CODE (y)((enum rtx_code) (y)->code)) |
3509 | /* Compare operands below. */; |
3510 | else if (GET_CODE (x)((enum rtx_code) (x)->code) < GET_CODE (y)((enum rtx_code) (y)->code)) |
3511 | return -1; |
3512 | else |
3513 | return 1; |
3514 | |
3515 | gcc_assert (GET_MODE (x) == GET_MODE (y))((void)(!(((machine_mode) (x)->mode) == ((machine_mode) (y )->mode)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3515, __FUNCTION__), 0 : 0)); |
3516 | |
3517 | if (GET_CODE (x)((enum rtx_code) (x)->code) == DEBUG_EXPR) |
3518 | { |
3519 | if (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))(-((contains_struct_check (((tree_check ((((((x)->u.fld[0] ).rt_tree))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3519, __FUNCTION__, (DEBUG_EXPR_DECL)))), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3519, __FUNCTION__))->decl_minimal.uid)) |
3520 | < DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y))(-((contains_struct_check (((tree_check ((((((y)->u.fld[0] ).rt_tree))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3520, __FUNCTION__, (DEBUG_EXPR_DECL)))), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3520, __FUNCTION__))->decl_minimal.uid))) |
3521 | return -1; |
3522 | gcc_checking_assert (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))((void)(!((-((contains_struct_check (((tree_check ((((((x)-> u.fld[0]).rt_tree))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3522, __FUNCTION__, (DEBUG_EXPR_DECL)))), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3522, __FUNCTION__))->decl_minimal.uid)) > (-((contains_struct_check (((tree_check ((((((y)->u.fld[0]).rt_tree))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3523, __FUNCTION__, (DEBUG_EXPR_DECL)))), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3523, __FUNCTION__))->decl_minimal.uid))) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3523, __FUNCTION__), 0 : 0)) |
3523 | > DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)))((void)(!((-((contains_struct_check (((tree_check ((((((x)-> u.fld[0]).rt_tree))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3522, __FUNCTION__, (DEBUG_EXPR_DECL)))), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3522, __FUNCTION__))->decl_minimal.uid)) > (-((contains_struct_check (((tree_check ((((((y)->u.fld[0]).rt_tree))), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3523, __FUNCTION__, (DEBUG_EXPR_DECL)))), (TS_DECL_MINIMAL) , "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3523, __FUNCTION__))->decl_minimal.uid))) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3523, __FUNCTION__), 0 : 0)); |
3524 | return 1; |
3525 | } |
3526 | |
3527 | fmt = GET_RTX_FORMAT (code)(rtx_format[(int) (code)]); |
3528 | for (i = 0; i < GET_RTX_LENGTH (code)(rtx_length[(int) (code)]); i++) |
3529 | switch (fmt[i]) |
3530 | { |
3531 | case 'w': |
3532 | if (XWINT (x, i)((x)->u.hwint[i]) == XWINT (y, i)((y)->u.hwint[i])) |
3533 | break; |
3534 | else if (XWINT (x, i)((x)->u.hwint[i]) < XWINT (y, i)((y)->u.hwint[i])) |
3535 | return -1; |
3536 | else |
3537 | return 1; |
3538 | |
3539 | case 'n': |
3540 | case 'i': |
3541 | if (XINT (x, i)(((x)->u.fld[i]).rt_int) == XINT (y, i)(((y)->u.fld[i]).rt_int)) |
3542 | break; |
3543 | else if (XINT (x, i)(((x)->u.fld[i]).rt_int) < XINT (y, i)(((y)->u.fld[i]).rt_int)) |
3544 | return -1; |
3545 | else |
3546 | return 1; |
3547 | |
3548 | case 'p': |
3549 | r = compare_sizes_for_sort (SUBREG_BYTE (x)(((x)->u.fld[1]).rt_subreg), SUBREG_BYTE (y)(((y)->u.fld[1]).rt_subreg)); |
3550 | if (r != 0) |
3551 | return r; |
3552 | break; |
3553 | |
3554 | case 'V': |
3555 | case 'E': |
3556 | /* Compare the vector length first. */ |
3557 | if (XVECLEN (x, i)(((((x)->u.fld[i]).rt_rtvec))->num_elem) == XVECLEN (y, i)(((((y)->u.fld[i]).rt_rtvec))->num_elem)) |
3558 | /* Compare the vectors elements. */; |
3559 | else if (XVECLEN (x, i)(((((x)->u.fld[i]).rt_rtvec))->num_elem) < XVECLEN (y, i)(((((y)->u.fld[i]).rt_rtvec))->num_elem)) |
3560 | return -1; |
3561 | else |
3562 | return 1; |
3563 | |
3564 | for (j = 0; j < XVECLEN (x, i)(((((x)->u.fld[i]).rt_rtvec))->num_elem); j++) |
3565 | if ((r = loc_cmp (XVECEXP (x, i, j)(((((x)->u.fld[i]).rt_rtvec))->elem[j]), |
3566 | XVECEXP (y, i, j)(((((y)->u.fld[i]).rt_rtvec))->elem[j])))) |
3567 | return r; |
3568 | break; |
3569 | |
3570 | case 'e': |
3571 | if ((r = loc_cmp (XEXP (x, i)(((x)->u.fld[i]).rt_rtx), XEXP (y, i)(((y)->u.fld[i]).rt_rtx)))) |
3572 | return r; |
3573 | break; |
3574 | |
3575 | case 'S': |
3576 | case 's': |
3577 | if (XSTR (x, i)(((x)->u.fld[i]).rt_str) == XSTR (y, i)(((y)->u.fld[i]).rt_str)) |
3578 | break; |
3579 | if (!XSTR (x, i)(((x)->u.fld[i]).rt_str)) |
3580 | return -1; |
3581 | if (!XSTR (y, i)(((y)->u.fld[i]).rt_str)) |
3582 | return 1; |
3583 | if ((r = strcmp (XSTR (x, i)(((x)->u.fld[i]).rt_str), XSTR (y, i)(((y)->u.fld[i]).rt_str))) == 0) |
3584 | break; |
3585 | else if (r < 0) |
3586 | return -1; |
3587 | else |
3588 | return 1; |
3589 | |
3590 | case 'u': |
3591 | /* These are just backpointers, so they don't matter. */ |
3592 | break; |
3593 | |
3594 | case '0': |
3595 | case 't': |
3596 | break; |
3597 | |
3598 | /* It is believed that rtx's at this level will never |
3599 | contain anything but integers and other rtx's, |
3600 | except for within LABEL_REFs and SYMBOL_REFs. */ |
3601 | default: |
3602 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3602, __FUNCTION__)); |
3603 | } |
3604 | if (CONST_WIDE_INT_P (x)(((enum rtx_code) (x)->code) == CONST_WIDE_INT)) |
3605 | { |
3606 | /* Compare the vector length first. */ |
3607 | if (CONST_WIDE_INT_NUNITS (x)((int)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if ( ((enum rtx_code) (_rtx)->code) != CONST_WIDE_INT) rtl_check_failed_flag ("CWI_GET_NUM_ELEM", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3607, __FUNCTION__); _rtx; })->u2.num_elem) >= CONST_WIDE_INT_NUNITS (y)((int)__extension__ ({ __typeof ((y)) const _rtx = ((y)); if ( ((enum rtx_code) (_rtx)->code) != CONST_WIDE_INT) rtl_check_failed_flag ("CWI_GET_NUM_ELEM", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3607, __FUNCTION__); _rtx; })->u2.num_elem)) |
3608 | return 1; |
3609 | else if (CONST_WIDE_INT_NUNITS (x)((int)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if ( ((enum rtx_code) (_rtx)->code) != CONST_WIDE_INT) rtl_check_failed_flag ("CWI_GET_NUM_ELEM", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3609, __FUNCTION__); _rtx; })->u2.num_elem) < CONST_WIDE_INT_NUNITS (y)((int)__extension__ ({ __typeof ((y)) const _rtx = ((y)); if ( ((enum rtx_code) (_rtx)->code) != CONST_WIDE_INT) rtl_check_failed_flag ("CWI_GET_NUM_ELEM", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3609, __FUNCTION__); _rtx; })->u2.num_elem)) |
3610 | return -1; |
3611 | |
3612 | /* Compare the vectors elements. */; |
3613 | for (j = CONST_WIDE_INT_NUNITS (x)((int)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if ( ((enum rtx_code) (_rtx)->code) != CONST_WIDE_INT) rtl_check_failed_flag ("CWI_GET_NUM_ELEM", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3613, __FUNCTION__); _rtx; })->u2.num_elem) - 1; j >= 0 ; j--) |
3614 | { |
3615 | if (CONST_WIDE_INT_ELT (x, j)((x)->u.hwiv.elem[j]) < CONST_WIDE_INT_ELT (y, j)((y)->u.hwiv.elem[j])) |
3616 | return -1; |
3617 | if (CONST_WIDE_INT_ELT (x, j)((x)->u.hwiv.elem[j]) > CONST_WIDE_INT_ELT (y, j)((y)->u.hwiv.elem[j])) |
3618 | return 1; |
3619 | } |
3620 | } |
3621 | |
3622 | return 0; |
3623 | } |
3624 | |
3625 | /* Check the order of entries in one-part variables. */ |
3626 | |
3627 | int |
3628 | canonicalize_loc_order_check (variable **slot, |
3629 | dataflow_set *data ATTRIBUTE_UNUSED__attribute__ ((__unused__))) |
3630 | { |
3631 | variable *var = *slot; |
3632 | location_chain *node, *next; |
3633 | |
3634 | #ifdef ENABLE_RTL_CHECKING |
3635 | int i; |
3636 | for (i = 0; i < var->n_var_parts; i++) |
3637 | gcc_assert (var->var_part[0].cur_loc == NULL)((void)(!(var->var_part[0].cur_loc == nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3637, __FUNCTION__), 0 : 0)); |
3638 | gcc_assert (!var->in_changed_variables)((void)(!(!var->in_changed_variables) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3638, __FUNCTION__), 0 : 0)); |
3639 | #endif |
3640 | |
3641 | if (!var->onepart) |
3642 | return 1; |
3643 | |
3644 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3644, __FUNCTION__), 0 : 0)); |
3645 | node = var->var_part[0].loc_chain; |
3646 | gcc_assert (node)((void)(!(node) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3646, __FUNCTION__), 0 : 0)); |
3647 | |
3648 | while ((next = node->next)) |
3649 | { |
3650 | gcc_assert (loc_cmp (node->loc, next->loc) < 0)((void)(!(loc_cmp (node->loc, next->loc) < 0) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3650, __FUNCTION__), 0 : 0)); |
3651 | node = next; |
3652 | } |
3653 | |
3654 | return 1; |
3655 | } |
3656 | |
3657 | /* Mark with VALUE_RECURSED_INTO values that have neighbors that are |
3658 | more likely to be chosen as canonical for an equivalence set. |
3659 | Ensure less likely values can reach more likely neighbors, making |
3660 | the connections bidirectional. */ |
3661 | |
3662 | int |
3663 | canonicalize_values_mark (variable **slot, dataflow_set *set) |
3664 | { |
3665 | variable *var = *slot; |
3666 | decl_or_value dv = var->dv; |
3667 | rtx val; |
3668 | location_chain *node; |
3669 | |
3670 | if (!dv_is_value_p (dv)) |
3671 | return 1; |
3672 | |
3673 | gcc_checking_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3673, __FUNCTION__), 0 : 0)); |
3674 | |
3675 | val = dv_as_value (dv); |
3676 | |
3677 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
3678 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
3679 | { |
3680 | if (canon_value_cmp (node->loc, val)) |
3681 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3681, __FUNCTION__); _rtx; })->used) = true; |
3682 | else |
3683 | { |
3684 | decl_or_value odv = dv_from_value (node->loc); |
3685 | variable **oslot; |
3686 | oslot = shared_hash_find_slot_noinsert (set->vars, odv); |
3687 | |
3688 | set_slot_part (set, val, oslot, odv, 0, |
3689 | node->init, NULL_RTX(rtx) 0); |
3690 | |
3691 | VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3691, __FUNCTION__); _rtx; })->used) = true; |
3692 | } |
3693 | } |
3694 | |
3695 | return 1; |
3696 | } |
3697 | |
3698 | /* Remove redundant entries from equivalence lists in onepart |
3699 | variables, canonicalizing equivalence sets into star shapes. */ |
3700 | |
3701 | int |
3702 | canonicalize_values_star (variable **slot, dataflow_set *set) |
3703 | { |
3704 | variable *var = *slot; |
3705 | decl_or_value dv = var->dv; |
3706 | location_chain *node; |
3707 | decl_or_value cdv; |
3708 | rtx val, cval; |
3709 | variable **cslot; |
3710 | bool has_value; |
3711 | bool has_marks; |
3712 | |
3713 | if (!var->onepart) |
3714 | return 1; |
3715 | |
3716 | gcc_checking_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3716, __FUNCTION__), 0 : 0)); |
3717 | |
3718 | if (dv_is_value_p (dv)) |
3719 | { |
3720 | cval = dv_as_value (dv); |
3721 | if (!VALUE_RECURSED_INTO (cval)(__extension__ ({ __typeof ((cval)) const _rtx = ((cval)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3721, __FUNCTION__); _rtx; })->used)) |
3722 | return 1; |
3723 | VALUE_RECURSED_INTO (cval)(__extension__ ({ __typeof ((cval)) const _rtx = ((cval)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3723, __FUNCTION__); _rtx; })->used) = false; |
3724 | } |
3725 | else |
3726 | cval = NULL_RTX(rtx) 0; |
3727 | |
3728 | restart: |
3729 | val = cval; |
3730 | has_value = false; |
3731 | has_marks = false; |
3732 | |
3733 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3733, __FUNCTION__), 0 : 0)); |
3734 | |
3735 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
3736 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
3737 | { |
3738 | has_value = true; |
3739 | if (VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3739, __FUNCTION__); _rtx; })->used)) |
3740 | has_marks = true; |
3741 | if (canon_value_cmp (node->loc, cval)) |
3742 | cval = node->loc; |
3743 | } |
3744 | |
3745 | if (!has_value) |
3746 | return 1; |
3747 | |
3748 | if (cval == val) |
3749 | { |
3750 | if (!has_marks || dv_is_decl_p (dv)) |
3751 | return 1; |
3752 | |
3753 | /* Keep it marked so that we revisit it, either after visiting a |
3754 | child node, or after visiting a new parent that might be |
3755 | found out. */ |
3756 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3756, __FUNCTION__); _rtx; })->used) = true; |
3757 | |
3758 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
3759 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE |
3760 | && VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3760, __FUNCTION__); _rtx; })->used)) |
3761 | { |
3762 | cval = node->loc; |
3763 | restart_with_cval: |
3764 | VALUE_RECURSED_INTO (cval)(__extension__ ({ __typeof ((cval)) const _rtx = ((cval)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3764, __FUNCTION__); _rtx; })->used) = false; |
3765 | dv = dv_from_value (cval); |
3766 | slot = shared_hash_find_slot_noinsert (set->vars, dv); |
3767 | if (!slot) |
3768 | { |
3769 | gcc_assert (dv_is_decl_p (var->dv))((void)(!(dv_is_decl_p (var->dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3769, __FUNCTION__), 0 : 0)); |
3770 | /* The canonical value was reset and dropped. |
3771 | Remove it. */ |
3772 | clobber_variable_part (set, NULLnullptr, var->dv, 0, NULLnullptr); |
3773 | return 1; |
3774 | } |
3775 | var = *slot; |
3776 | gcc_assert (dv_is_value_p (var->dv))((void)(!(dv_is_value_p (var->dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3776, __FUNCTION__), 0 : 0)); |
3777 | if (var->n_var_parts == 0) |
3778 | return 1; |
3779 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3779, __FUNCTION__), 0 : 0)); |
3780 | goto restart; |
3781 | } |
3782 | |
3783 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3783, __FUNCTION__); _rtx; })->used) = false; |
3784 | |
3785 | return 1; |
3786 | } |
3787 | |
3788 | /* Push values to the canonical one. */ |
3789 | cdv = dv_from_value (cval); |
3790 | cslot = shared_hash_find_slot_noinsert (set->vars, cdv); |
3791 | |
3792 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
3793 | if (node->loc != cval) |
3794 | { |
3795 | cslot = set_slot_part (set, node->loc, cslot, cdv, 0, |
3796 | node->init, NULL_RTX(rtx) 0); |
3797 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
3798 | { |
3799 | decl_or_value ndv = dv_from_value (node->loc); |
3800 | |
3801 | set_variable_part (set, cval, ndv, 0, node->init, NULL_RTX(rtx) 0, |
3802 | NO_INSERT); |
3803 | |
3804 | if (canon_value_cmp (node->loc, val)) |
3805 | { |
3806 | /* If it could have been a local minimum, it's not any more, |
3807 | since it's now neighbor to cval, so it may have to push |
3808 | to it. Conversely, if it wouldn't have prevailed over |
3809 | val, then whatever mark it has is fine: if it was to |
3810 | push, it will now push to a more canonical node, but if |
3811 | it wasn't, then it has already pushed any values it might |
3812 | have to. */ |
3813 | VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3813, __FUNCTION__); _rtx; })->used) = true; |
3814 | /* Make sure we visit node->loc by ensuring we cval is |
3815 | visited too. */ |
3816 | VALUE_RECURSED_INTO (cval)(__extension__ ({ __typeof ((cval)) const _rtx = ((cval)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3816, __FUNCTION__); _rtx; })->used) = true; |
3817 | } |
3818 | else if (!VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3818, __FUNCTION__); _rtx; })->used)) |
3819 | /* If we have no need to "recurse" into this node, it's |
3820 | already "canonicalized", so drop the link to the old |
3821 | parent. */ |
3822 | clobber_variable_part (set, cval, ndv, 0, NULLnullptr); |
3823 | } |
3824 | else if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == REG) |
3825 | { |
3826 | attrs *list = set->regs[REGNO (node->loc)(rhs_regno(node->loc))], **listp; |
3827 | |
3828 | /* Change an existing attribute referring to dv so that it |
3829 | refers to cdv, removing any duplicate this might |
3830 | introduce, and checking that no previous duplicates |
3831 | existed, all in a single pass. */ |
3832 | |
3833 | while (list) |
3834 | { |
3835 | if (list->offset == 0 |
3836 | && (dv_as_opaque (list->dv) == dv_as_opaque (dv) |
3837 | || dv_as_opaque (list->dv) == dv_as_opaque (cdv))) |
3838 | break; |
3839 | |
3840 | list = list->next; |
3841 | } |
3842 | |
3843 | gcc_assert (list)((void)(!(list) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3843, __FUNCTION__), 0 : 0)); |
3844 | if (dv_as_opaque (list->dv) == dv_as_opaque (dv)) |
3845 | { |
3846 | list->dv = cdv; |
3847 | for (listp = &list->next; (list = *listp); listp = &list->next) |
3848 | { |
3849 | if (list->offset) |
3850 | continue; |
3851 | |
3852 | if (dv_as_opaque (list->dv) == dv_as_opaque (cdv)) |
3853 | { |
3854 | *listp = list->next; |
3855 | delete list; |
3856 | list = *listp; |
3857 | break; |
3858 | } |
3859 | |
3860 | gcc_assert (dv_as_opaque (list->dv) != dv_as_opaque (dv))((void)(!(dv_as_opaque (list->dv) != dv_as_opaque (dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3860, __FUNCTION__), 0 : 0)); |
3861 | } |
3862 | } |
3863 | else if (dv_as_opaque (list->dv) == dv_as_opaque (cdv)) |
3864 | { |
3865 | for (listp = &list->next; (list = *listp); listp = &list->next) |
3866 | { |
3867 | if (list->offset) |
3868 | continue; |
3869 | |
3870 | if (dv_as_opaque (list->dv) == dv_as_opaque (dv)) |
3871 | { |
3872 | *listp = list->next; |
3873 | delete list; |
3874 | list = *listp; |
3875 | break; |
3876 | } |
3877 | |
3878 | gcc_assert (dv_as_opaque (list->dv) != dv_as_opaque (cdv))((void)(!(dv_as_opaque (list->dv) != dv_as_opaque (cdv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3878, __FUNCTION__), 0 : 0)); |
3879 | } |
3880 | } |
3881 | else |
3882 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3882, __FUNCTION__)); |
3883 | |
3884 | if (flag_checkingglobal_options.x_flag_checking) |
3885 | while (list) |
3886 | { |
3887 | if (list->offset == 0 |
3888 | && (dv_as_opaque (list->dv) == dv_as_opaque (dv) |
3889 | || dv_as_opaque (list->dv) == dv_as_opaque (cdv))) |
3890 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3890, __FUNCTION__)); |
3891 | |
3892 | list = list->next; |
3893 | } |
3894 | } |
3895 | } |
3896 | |
3897 | if (val) |
3898 | set_slot_part (set, val, cslot, cdv, 0, |
3899 | VAR_INIT_STATUS_INITIALIZED, NULL_RTX(rtx) 0); |
3900 | |
3901 | slot = clobber_slot_part (set, cval, slot, 0, NULLnullptr); |
3902 | |
3903 | /* Variable may have been unshared. */ |
3904 | var = *slot; |
3905 | gcc_checking_assert (var->n_var_parts && var->var_part[0].loc_chain->loc == cval((void)(!(var->n_var_parts && var->var_part[0]. loc_chain->loc == cval && var->var_part[0].loc_chain ->next == nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3906, __FUNCTION__), 0 : 0)) |
3906 | && var->var_part[0].loc_chain->next == NULL)((void)(!(var->n_var_parts && var->var_part[0]. loc_chain->loc == cval && var->var_part[0].loc_chain ->next == nullptr) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3906, __FUNCTION__), 0 : 0)); |
3907 | |
3908 | if (VALUE_RECURSED_INTO (cval)(__extension__ ({ __typeof ((cval)) const _rtx = ((cval)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3908, __FUNCTION__); _rtx; })->used)) |
3909 | goto restart_with_cval; |
3910 | |
3911 | return 1; |
3912 | } |
3913 | |
3914 | /* Bind one-part variables to the canonical value in an equivalence |
3915 | set. Not doing this causes dataflow convergence failure in rare |
3916 | circumstances, see PR42873. Unfortunately we can't do this |
3917 | efficiently as part of canonicalize_values_star, since we may not |
3918 | have determined or even seen the canonical value of a set when we |
3919 | get to a variable that references another member of the set. */ |
3920 | |
3921 | int |
3922 | canonicalize_vars_star (variable **slot, dataflow_set *set) |
3923 | { |
3924 | variable *var = *slot; |
3925 | decl_or_value dv = var->dv; |
3926 | location_chain *node; |
3927 | rtx cval; |
3928 | decl_or_value cdv; |
3929 | variable **cslot; |
3930 | variable *cvar; |
3931 | location_chain *cnode; |
3932 | |
3933 | if (!var->onepart || var->onepart == ONEPART_VALUE) |
3934 | return 1; |
3935 | |
3936 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3936, __FUNCTION__), 0 : 0)); |
3937 | |
3938 | node = var->var_part[0].loc_chain; |
3939 | |
3940 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) != VALUE) |
3941 | return 1; |
3942 | |
3943 | gcc_assert (!node->next)((void)(!(!node->next) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3943, __FUNCTION__), 0 : 0)); |
3944 | cval = node->loc; |
3945 | |
3946 | /* Push values to the canonical one. */ |
3947 | cdv = dv_from_value (cval); |
3948 | cslot = shared_hash_find_slot_noinsert (set->vars, cdv); |
3949 | if (!cslot) |
3950 | return 1; |
3951 | cvar = *cslot; |
3952 | gcc_assert (cvar->n_var_parts == 1)((void)(!(cvar->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3952, __FUNCTION__), 0 : 0)); |
3953 | |
3954 | cnode = cvar->var_part[0].loc_chain; |
3955 | |
3956 | /* CVAL is canonical if its value list contains non-VALUEs or VALUEs |
3957 | that are not “more canonical” than it. */ |
3958 | if (GET_CODE (cnode->loc)((enum rtx_code) (cnode->loc)->code) != VALUE |
3959 | || !canon_value_cmp (cnode->loc, cval)) |
3960 | return 1; |
3961 | |
3962 | /* CVAL was found to be non-canonical. Change the variable to point |
3963 | to the canonical VALUE. */ |
3964 | gcc_assert (!cnode->next)((void)(!(!cnode->next) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3964, __FUNCTION__), 0 : 0)); |
3965 | cval = cnode->loc; |
3966 | |
3967 | slot = set_slot_part (set, cval, slot, dv, 0, |
3968 | node->init, node->set_src); |
3969 | clobber_slot_part (set, cval, slot, 0, node->set_src); |
3970 | |
3971 | return 1; |
3972 | } |
3973 | |
3974 | /* Combine variable or value in *S1SLOT (in DSM->cur) with the |
3975 | corresponding entry in DSM->src. Multi-part variables are combined |
3976 | with variable_union, whereas onepart dvs are combined with |
3977 | intersection. */ |
3978 | |
3979 | static int |
3980 | variable_merge_over_cur (variable *s1var, struct dfset_merge *dsm) |
3981 | { |
3982 | dataflow_set *dst = dsm->dst; |
3983 | variable **dstslot; |
3984 | variable *s2var, *dvar = NULLnullptr; |
3985 | decl_or_value dv = s1var->dv; |
3986 | onepart_enum onepart = s1var->onepart; |
3987 | rtx val; |
3988 | hashval_t dvhash; |
3989 | location_chain *node, **nodep; |
3990 | |
3991 | /* If the incoming onepart variable has an empty location list, then |
3992 | the intersection will be just as empty. For other variables, |
3993 | it's always union. */ |
3994 | gcc_checking_assert (s1var->n_var_parts((void)(!(s1var->n_var_parts && s1var->var_part [0].loc_chain) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3995, __FUNCTION__), 0 : 0)) |
3995 | && s1var->var_part[0].loc_chain)((void)(!(s1var->n_var_parts && s1var->var_part [0].loc_chain) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 3995, __FUNCTION__), 0 : 0)); |
3996 | |
3997 | if (!onepart) |
3998 | return variable_union (s1var, dst); |
3999 | |
4000 | gcc_checking_assert (s1var->n_var_parts == 1)((void)(!(s1var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4000, __FUNCTION__), 0 : 0)); |
4001 | |
4002 | dvhash = dv_htab_hash (dv); |
4003 | if (dv_is_value_p (dv)) |
4004 | val = dv_as_value (dv); |
4005 | else |
4006 | val = NULLnullptr; |
4007 | |
4008 | s2var = shared_hash_find_1 (dsm->src->vars, dv, dvhash); |
4009 | if (!s2var) |
4010 | { |
4011 | dst_can_be_shared = false; |
4012 | return 1; |
4013 | } |
4014 | |
4015 | dsm->src_onepart_cnt--; |
4016 | gcc_assert (s2var->var_part[0].loc_chain((void)(!(s2var->var_part[0].loc_chain && s2var-> onepart == onepart && s2var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4018, __FUNCTION__), 0 : 0)) |
4017 | && s2var->onepart == onepart((void)(!(s2var->var_part[0].loc_chain && s2var-> onepart == onepart && s2var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4018, __FUNCTION__), 0 : 0)) |
4018 | && s2var->n_var_parts == 1)((void)(!(s2var->var_part[0].loc_chain && s2var-> onepart == onepart && s2var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4018, __FUNCTION__), 0 : 0)); |
4019 | |
4020 | dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash); |
4021 | if (dstslot) |
4022 | { |
4023 | dvar = *dstslot; |
4024 | gcc_assert (dvar->refcount == 1((void)(!(dvar->refcount == 1 && dvar->onepart == onepart && dvar->n_var_parts == 1) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4026, __FUNCTION__), 0 : 0)) |
4025 | && dvar->onepart == onepart((void)(!(dvar->refcount == 1 && dvar->onepart == onepart && dvar->n_var_parts == 1) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4026, __FUNCTION__), 0 : 0)) |
4026 | && dvar->n_var_parts == 1)((void)(!(dvar->refcount == 1 && dvar->onepart == onepart && dvar->n_var_parts == 1) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4026, __FUNCTION__), 0 : 0)); |
4027 | nodep = &dvar->var_part[0].loc_chain; |
4028 | } |
4029 | else |
4030 | { |
4031 | nodep = &node; |
4032 | node = NULLnullptr; |
4033 | } |
4034 | |
4035 | if (!dstslot && !onepart_variable_different_p (s1var, s2var)) |
4036 | { |
4037 | dstslot = shared_hash_find_slot_unshare_1 (&dst->vars, dv, |
4038 | dvhash, INSERT); |
4039 | *dstslot = dvar = s2var; |
4040 | dvar->refcount++; |
4041 | } |
4042 | else |
4043 | { |
4044 | dst_can_be_shared = false; |
4045 | |
4046 | intersect_loc_chains (val, nodep, dsm, |
4047 | s1var->var_part[0].loc_chain, s2var); |
4048 | |
4049 | if (!dstslot) |
4050 | { |
4051 | if (node) |
4052 | { |
4053 | dvar = onepart_pool_allocate (onepart); |
4054 | dvar->dv = dv; |
4055 | dvar->refcount = 1; |
4056 | dvar->n_var_parts = 1; |
4057 | dvar->onepart = onepart; |
4058 | dvar->in_changed_variables = false; |
4059 | dvar->var_part[0].loc_chain = node; |
4060 | dvar->var_part[0].cur_loc = NULLnullptr; |
4061 | if (onepart) |
4062 | VAR_LOC_1PAUX (dvar)__extension__ (*({ variable *const __v = (dvar); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4062, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) = NULLnullptr; |
4063 | else |
4064 | VAR_PART_OFFSET (dvar, 0)__extension__ (*({ variable *const __v = (dvar); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4064, __FUNCTION__), 0 : 0)); &__v->var_part[(0)].aux .offset; })) = 0; |
4065 | |
4066 | dstslot |
4067 | = shared_hash_find_slot_unshare_1 (&dst->vars, dv, dvhash, |
4068 | INSERT); |
4069 | gcc_assert (!*dstslot)((void)(!(!*dstslot) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4069, __FUNCTION__), 0 : 0)); |
4070 | *dstslot = dvar; |
4071 | } |
4072 | else |
4073 | return 1; |
4074 | } |
4075 | } |
4076 | |
4077 | nodep = &dvar->var_part[0].loc_chain; |
4078 | while ((node = *nodep)) |
4079 | { |
4080 | location_chain **nextp = &node->next; |
4081 | |
4082 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == REG) |
4083 | { |
4084 | attrs *list; |
4085 | |
4086 | for (list = dst->regs[REGNO (node->loc)(rhs_regno(node->loc))]; list; list = list->next) |
4087 | if (GET_MODE (node->loc)((machine_mode) (node->loc)->mode) == GET_MODE (list->loc)((machine_mode) (list->loc)->mode) |
4088 | && dv_is_value_p (list->dv)) |
4089 | break; |
4090 | |
4091 | if (!list) |
4092 | attrs_list_insert (&dst->regs[REGNO (node->loc)(rhs_regno(node->loc))], |
4093 | dv, 0, node->loc); |
4094 | /* If this value became canonical for another value that had |
4095 | this register, we want to leave it alone. */ |
4096 | else if (dv_as_value (list->dv) != val) |
4097 | { |
4098 | dstslot = set_slot_part (dst, dv_as_value (list->dv), |
4099 | dstslot, dv, 0, |
4100 | node->init, NULL_RTX(rtx) 0); |
4101 | dstslot = delete_slot_part (dst, node->loc, dstslot, 0); |
4102 | |
4103 | /* Since nextp points into the removed node, we can't |
4104 | use it. The pointer to the next node moved to nodep. |
4105 | However, if the variable we're walking is unshared |
4106 | during our walk, we'll keep walking the location list |
4107 | of the previously-shared variable, in which case the |
4108 | node won't have been removed, and we'll want to skip |
4109 | it. That's why we test *nodep here. */ |
4110 | if (*nodep != node) |
4111 | nextp = nodep; |
4112 | } |
4113 | } |
4114 | else |
4115 | /* Canonicalization puts registers first, so we don't have to |
4116 | walk it all. */ |
4117 | break; |
4118 | nodep = nextp; |
4119 | } |
4120 | |
4121 | if (dvar != *dstslot) |
4122 | dvar = *dstslot; |
4123 | nodep = &dvar->var_part[0].loc_chain; |
4124 | |
4125 | if (val) |
4126 | { |
4127 | /* Mark all referenced nodes for canonicalization, and make sure |
4128 | we have mutual equivalence links. */ |
4129 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4129, __FUNCTION__); _rtx; })->used) = true; |
4130 | for (node = *nodep; node; node = node->next) |
4131 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
4132 | { |
4133 | VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4133, __FUNCTION__); _rtx; })->used) = true; |
4134 | set_variable_part (dst, val, dv_from_value (node->loc), 0, |
4135 | node->init, NULLnullptr, INSERT); |
4136 | } |
4137 | |
4138 | dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash); |
4139 | gcc_assert (*dstslot == dvar)((void)(!(*dstslot == dvar) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4139, __FUNCTION__), 0 : 0)); |
4140 | canonicalize_values_star (dstslot, dst); |
4141 | gcc_checking_assert (dstslot((void)(!(dstslot == shared_hash_find_slot_noinsert_1 (dst-> vars, dv, dvhash)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4143, __FUNCTION__), 0 : 0)) |
4142 | == shared_hash_find_slot_noinsert_1 (dst->vars,((void)(!(dstslot == shared_hash_find_slot_noinsert_1 (dst-> vars, dv, dvhash)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4143, __FUNCTION__), 0 : 0)) |
4143 | dv, dvhash))((void)(!(dstslot == shared_hash_find_slot_noinsert_1 (dst-> vars, dv, dvhash)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4143, __FUNCTION__), 0 : 0)); |
4144 | dvar = *dstslot; |
4145 | } |
4146 | else |
4147 | { |
4148 | bool has_value = false, has_other = false; |
4149 | |
4150 | /* If we have one value and anything else, we're going to |
4151 | canonicalize this, so make sure all values have an entry in |
4152 | the table and are marked for canonicalization. */ |
4153 | for (node = *nodep; node; node = node->next) |
4154 | { |
4155 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
4156 | { |
4157 | /* If this was marked during register canonicalization, |
4158 | we know we have to canonicalize values. */ |
4159 | if (has_value) |
4160 | has_other = true; |
4161 | has_value = true; |
4162 | if (has_other) |
4163 | break; |
4164 | } |
4165 | else |
4166 | { |
4167 | has_other = true; |
4168 | if (has_value) |
4169 | break; |
4170 | } |
4171 | } |
4172 | |
4173 | if (has_value && has_other) |
4174 | { |
4175 | for (node = *nodep; node; node = node->next) |
4176 | { |
4177 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
4178 | { |
4179 | decl_or_value dv = dv_from_value (node->loc); |
4180 | variable **slot = NULLnullptr; |
4181 | |
4182 | if (shared_hash_shared (dst->vars)) |
4183 | slot = shared_hash_find_slot_noinsert (dst->vars, dv); |
4184 | if (!slot) |
4185 | slot = shared_hash_find_slot_unshare (&dst->vars, dv, |
4186 | INSERT); |
4187 | if (!*slot) |
4188 | { |
4189 | variable *var = onepart_pool_allocate (ONEPART_VALUE); |
4190 | var->dv = dv; |
4191 | var->refcount = 1; |
4192 | var->n_var_parts = 1; |
4193 | var->onepart = ONEPART_VALUE; |
4194 | var->in_changed_variables = false; |
4195 | var->var_part[0].loc_chain = NULLnullptr; |
4196 | var->var_part[0].cur_loc = NULLnullptr; |
4197 | VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4197, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; })) = NULLnullptr; |
4198 | *slot = var; |
4199 | } |
4200 | |
4201 | VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4201, __FUNCTION__); _rtx; })->used) = true; |
4202 | } |
4203 | } |
4204 | |
4205 | dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash); |
4206 | gcc_assert (*dstslot == dvar)((void)(!(*dstslot == dvar) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4206, __FUNCTION__), 0 : 0)); |
4207 | canonicalize_values_star (dstslot, dst); |
4208 | gcc_checking_assert (dstslot((void)(!(dstslot == shared_hash_find_slot_noinsert_1 (dst-> vars, dv, dvhash)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4210, __FUNCTION__), 0 : 0)) |
4209 | == shared_hash_find_slot_noinsert_1 (dst->vars,((void)(!(dstslot == shared_hash_find_slot_noinsert_1 (dst-> vars, dv, dvhash)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4210, __FUNCTION__), 0 : 0)) |
4210 | dv, dvhash))((void)(!(dstslot == shared_hash_find_slot_noinsert_1 (dst-> vars, dv, dvhash)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4210, __FUNCTION__), 0 : 0)); |
4211 | dvar = *dstslot; |
4212 | } |
4213 | } |
4214 | |
4215 | if (!onepart_variable_different_p (dvar, s2var)) |
4216 | { |
4217 | variable_htab_free (dvar); |
4218 | *dstslot = dvar = s2var; |
4219 | dvar->refcount++; |
4220 | } |
4221 | else if (s2var != s1var && !onepart_variable_different_p (dvar, s1var)) |
4222 | { |
4223 | variable_htab_free (dvar); |
4224 | *dstslot = dvar = s1var; |
4225 | dvar->refcount++; |
4226 | dst_can_be_shared = false; |
4227 | } |
4228 | else |
4229 | dst_can_be_shared = false; |
4230 | |
4231 | return 1; |
4232 | } |
4233 | |
4234 | /* Copy s2slot (in DSM->src) to DSM->dst if the variable is a |
4235 | multi-part variable. Unions of multi-part variables and |
4236 | intersections of one-part ones will be handled in |
4237 | variable_merge_over_cur(). */ |
4238 | |
4239 | static int |
4240 | variable_merge_over_src (variable *s2var, struct dfset_merge *dsm) |
4241 | { |
4242 | dataflow_set *dst = dsm->dst; |
4243 | decl_or_value dv = s2var->dv; |
4244 | |
4245 | if (!s2var->onepart) |
4246 | { |
4247 | variable **dstp = shared_hash_find_slot (dst->vars, dv); |
4248 | *dstp = s2var; |
4249 | s2var->refcount++; |
4250 | return 1; |
4251 | } |
4252 | |
4253 | dsm->src_onepart_cnt++; |
4254 | return 1; |
4255 | } |
4256 | |
4257 | /* Combine dataflow set information from SRC2 into DST, using PDST |
4258 | to carry over information across passes. */ |
4259 | |
4260 | static void |
4261 | dataflow_set_merge (dataflow_set *dst, dataflow_set *src2) |
4262 | { |
4263 | dataflow_set cur = *dst; |
4264 | dataflow_set *src1 = &cur; |
4265 | struct dfset_merge dsm; |
4266 | int i; |
4267 | size_t src1_elems, src2_elems; |
4268 | variable_iterator_type hi; |
4269 | variable *var; |
4270 | |
4271 | src1_elems = shared_hash_htab (src1->vars)->elements (); |
4272 | src2_elems = shared_hash_htab (src2->vars)->elements (); |
4273 | dataflow_set_init (dst); |
4274 | dst->stack_adjust = cur.stack_adjust; |
4275 | shared_hash_destroy (dst->vars); |
4276 | dst->vars = new shared_hash; |
4277 | dst->vars->refcount = 1; |
4278 | dst->vars->htab = new variable_table_type (MAX (src1_elems, src2_elems)((src1_elems) > (src2_elems) ? (src1_elems) : (src2_elems) )); |
4279 | |
4280 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
4281 | attrs_list_mpdv_union (&dst->regs[i], src1->regs[i], src2->regs[i]); |
4282 | |
4283 | dsm.dst = dst; |
4284 | dsm.src = src2; |
4285 | dsm.cur = src1; |
4286 | dsm.src_onepart_cnt = 0; |
4287 | |
4288 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.src->vars),for ((hi) = (*shared_hash_htab (dsm.src->vars)).begin (); ( hi) != (*shared_hash_htab (dsm.src->vars)).end () ? (var = *(hi) , true) : false; ++(hi)) |
4289 | var, variable, hi)for ((hi) = (*shared_hash_htab (dsm.src->vars)).begin (); ( hi) != (*shared_hash_htab (dsm.src->vars)).end () ? (var = *(hi) , true) : false; ++(hi)) |
4290 | variable_merge_over_src (var, &dsm); |
4291 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (dsm.cur->vars),for ((hi) = (*shared_hash_htab (dsm.cur->vars)).begin (); ( hi) != (*shared_hash_htab (dsm.cur->vars)).end () ? (var = *(hi) , true) : false; ++(hi)) |
4292 | var, variable, hi)for ((hi) = (*shared_hash_htab (dsm.cur->vars)).begin (); ( hi) != (*shared_hash_htab (dsm.cur->vars)).end () ? (var = *(hi) , true) : false; ++(hi)) |
4293 | variable_merge_over_cur (var, &dsm); |
4294 | |
4295 | if (dsm.src_onepart_cnt) |
4296 | dst_can_be_shared = false; |
4297 | |
4298 | dataflow_set_destroy (src1); |
4299 | } |
4300 | |
4301 | /* Mark register equivalences. */ |
4302 | |
4303 | static void |
4304 | dataflow_set_equiv_regs (dataflow_set *set) |
4305 | { |
4306 | int i; |
4307 | attrs *list, **listp; |
4308 | |
4309 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
4310 | { |
4311 | rtx canon[NUM_MACHINE_MODES]; |
4312 | |
4313 | /* If the list is empty or one entry, no need to canonicalize |
4314 | anything. */ |
4315 | if (set->regs[i] == NULLnullptr || set->regs[i]->next == NULLnullptr) |
4316 | continue; |
4317 | |
4318 | memset (canon, 0, sizeof (canon)); |
4319 | |
4320 | for (list = set->regs[i]; list; list = list->next) |
4321 | if (list->offset == 0 && dv_is_value_p (list->dv)) |
4322 | { |
4323 | rtx val = dv_as_value (list->dv); |
4324 | rtx *cvalp = &canon[(int)GET_MODE (val)((machine_mode) (val)->mode)]; |
4325 | rtx cval = *cvalp; |
4326 | |
4327 | if (canon_value_cmp (val, cval)) |
4328 | *cvalp = val; |
4329 | } |
4330 | |
4331 | for (list = set->regs[i]; list; list = list->next) |
4332 | if (list->offset == 0 && dv_onepart_p (list->dv)) |
4333 | { |
4334 | rtx cval = canon[(int)GET_MODE (list->loc)((machine_mode) (list->loc)->mode)]; |
4335 | |
4336 | if (!cval) |
4337 | continue; |
4338 | |
4339 | if (dv_is_value_p (list->dv)) |
4340 | { |
4341 | rtx val = dv_as_value (list->dv); |
4342 | |
4343 | if (val == cval) |
4344 | continue; |
4345 | |
4346 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4346, __FUNCTION__); _rtx; })->used) = true; |
4347 | set_variable_part (set, val, dv_from_value (cval), 0, |
4348 | VAR_INIT_STATUS_INITIALIZED, |
4349 | NULLnullptr, NO_INSERT); |
4350 | } |
4351 | |
4352 | VALUE_RECURSED_INTO (cval)(__extension__ ({ __typeof ((cval)) const _rtx = ((cval)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4352, __FUNCTION__); _rtx; })->used) = true; |
4353 | set_variable_part (set, cval, list->dv, 0, |
4354 | VAR_INIT_STATUS_INITIALIZED, NULLnullptr, NO_INSERT); |
4355 | } |
4356 | |
4357 | for (listp = &set->regs[i]; (list = *listp); |
4358 | listp = list ? &list->next : listp) |
4359 | if (list->offset == 0 && dv_onepart_p (list->dv)) |
4360 | { |
4361 | rtx cval = canon[(int)GET_MODE (list->loc)((machine_mode) (list->loc)->mode)]; |
4362 | variable **slot; |
4363 | |
4364 | if (!cval) |
4365 | continue; |
4366 | |
4367 | if (dv_is_value_p (list->dv)) |
4368 | { |
4369 | rtx val = dv_as_value (list->dv); |
4370 | if (!VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4370, __FUNCTION__); _rtx; })->used)) |
4371 | continue; |
4372 | } |
4373 | |
4374 | slot = shared_hash_find_slot_noinsert (set->vars, list->dv); |
4375 | canonicalize_values_star (slot, set); |
4376 | if (*listp != list) |
4377 | list = NULLnullptr; |
4378 | } |
4379 | } |
4380 | } |
4381 | |
4382 | /* Remove any redundant values in the location list of VAR, which must |
4383 | be unshared and 1-part. */ |
4384 | |
4385 | static void |
4386 | remove_duplicate_values (variable *var) |
4387 | { |
4388 | location_chain *node, **nodep; |
4389 | |
4390 | gcc_assert (var->onepart)((void)(!(var->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4390, __FUNCTION__), 0 : 0)); |
4391 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4391, __FUNCTION__), 0 : 0)); |
4392 | gcc_assert (var->refcount == 1)((void)(!(var->refcount == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4392, __FUNCTION__), 0 : 0)); |
4393 | |
4394 | for (nodep = &var->var_part[0].loc_chain; (node = *nodep); ) |
4395 | { |
4396 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
4397 | { |
4398 | if (VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4398, __FUNCTION__); _rtx; })->used)) |
4399 | { |
4400 | /* Remove duplicate value node. */ |
4401 | *nodep = node->next; |
4402 | delete node; |
4403 | continue; |
4404 | } |
4405 | else |
4406 | VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4406, __FUNCTION__); _rtx; })->used) = true; |
4407 | } |
4408 | nodep = &node->next; |
4409 | } |
4410 | |
4411 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
4412 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
4413 | { |
4414 | gcc_assert (VALUE_RECURSED_INTO (node->loc))((void)(!((__extension__ ({ __typeof ((node->loc)) const _rtx = ((node->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR ) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4414, __FUNCTION__); _rtx; })->used)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4414, __FUNCTION__), 0 : 0)); |
4415 | VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4415, __FUNCTION__); _rtx; })->used) = false; |
4416 | } |
4417 | } |
4418 | |
4419 | |
4420 | /* Hash table iteration argument passed to variable_post_merge. */ |
4421 | struct dfset_post_merge |
4422 | { |
4423 | /* The new input set for the current block. */ |
4424 | dataflow_set *set; |
4425 | /* Pointer to the permanent input set for the current block, or |
4426 | NULL. */ |
4427 | dataflow_set **permp; |
4428 | }; |
4429 | |
4430 | /* Create values for incoming expressions associated with one-part |
4431 | variables that don't have value numbers for them. */ |
4432 | |
4433 | int |
4434 | variable_post_merge_new_vals (variable **slot, dfset_post_merge *dfpm) |
4435 | { |
4436 | dataflow_set *set = dfpm->set; |
4437 | variable *var = *slot; |
4438 | location_chain *node; |
4439 | |
4440 | if (!var->onepart || !var->n_var_parts) |
4441 | return 1; |
4442 | |
4443 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4443, __FUNCTION__), 0 : 0)); |
4444 | |
4445 | if (dv_is_decl_p (var->dv)) |
4446 | { |
4447 | bool check_dupes = false; |
4448 | |
4449 | restart: |
4450 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
4451 | { |
4452 | if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE) |
4453 | gcc_assert (!VALUE_RECURSED_INTO (node->loc))((void)(!(!(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR ) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4453, __FUNCTION__); _rtx; })->used)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4453, __FUNCTION__), 0 : 0)); |
4454 | else if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == REG) |
4455 | { |
4456 | attrs *att, **attp, **curp = NULLnullptr; |
4457 | |
4458 | if (var->refcount != 1) |
4459 | { |
4460 | slot = unshare_variable (set, slot, var, |
4461 | VAR_INIT_STATUS_INITIALIZED); |
4462 | var = *slot; |
4463 | goto restart; |
4464 | } |
4465 | |
4466 | for (attp = &set->regs[REGNO (node->loc)(rhs_regno(node->loc))]; (att = *attp); |
4467 | attp = &att->next) |
4468 | if (att->offset == 0 |
4469 | && GET_MODE (att->loc)((machine_mode) (att->loc)->mode) == GET_MODE (node->loc)((machine_mode) (node->loc)->mode)) |
4470 | { |
4471 | if (dv_is_value_p (att->dv)) |
4472 | { |
4473 | rtx cval = dv_as_value (att->dv); |
4474 | node->loc = cval; |
4475 | check_dupes = true; |
4476 | break; |
4477 | } |
4478 | else if (dv_as_opaque (att->dv) == dv_as_opaque (var->dv)) |
4479 | curp = attp; |
4480 | } |
4481 | |
4482 | if (!curp) |
4483 | { |
4484 | curp = attp; |
4485 | while (*curp) |
4486 | if ((*curp)->offset == 0 |
4487 | && GET_MODE ((*curp)->loc)((machine_mode) ((*curp)->loc)->mode) == GET_MODE (node->loc)((machine_mode) (node->loc)->mode) |
4488 | && dv_as_opaque ((*curp)->dv) == dv_as_opaque (var->dv)) |
4489 | break; |
4490 | else |
4491 | curp = &(*curp)->next; |
4492 | gcc_assert (*curp)((void)(!(*curp) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4492, __FUNCTION__), 0 : 0)); |
4493 | } |
4494 | |
4495 | if (!att) |
4496 | { |
4497 | decl_or_value cdv; |
4498 | rtx cval; |
4499 | |
4500 | if (!*dfpm->permp) |
4501 | { |
4502 | *dfpm->permp = XNEW (dataflow_set)((dataflow_set *) xmalloc (sizeof (dataflow_set))); |
4503 | dataflow_set_init (*dfpm->permp); |
4504 | } |
4505 | |
4506 | for (att = (*dfpm->permp)->regs[REGNO (node->loc)(rhs_regno(node->loc))]; |
4507 | att; att = att->next) |
4508 | if (GET_MODE (att->loc)((machine_mode) (att->loc)->mode) == GET_MODE (node->loc)((machine_mode) (node->loc)->mode)) |
4509 | { |
4510 | gcc_assert (att->offset == 0((void)(!(att->offset == 0 && dv_is_value_p (att-> dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4511, __FUNCTION__), 0 : 0)) |
4511 | && dv_is_value_p (att->dv))((void)(!(att->offset == 0 && dv_is_value_p (att-> dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4511, __FUNCTION__), 0 : 0)); |
4512 | val_reset (set, att->dv); |
4513 | break; |
4514 | } |
4515 | |
4516 | if (att) |
4517 | { |
4518 | cdv = att->dv; |
4519 | cval = dv_as_value (cdv); |
4520 | } |
4521 | else |
4522 | { |
4523 | /* Create a unique value to hold this register, |
4524 | that ought to be found and reused in |
4525 | subsequent rounds. */ |
4526 | cselib_val *v; |
4527 | gcc_assert (!cselib_lookup (node->loc,((void)(!(!cselib_lookup (node->loc, ((machine_mode) (node ->loc)->mode), 0, ((void) 0, E_VOIDmode))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4529, __FUNCTION__), 0 : 0)) |
4528 | GET_MODE (node->loc), 0,((void)(!(!cselib_lookup (node->loc, ((machine_mode) (node ->loc)->mode), 0, ((void) 0, E_VOIDmode))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4529, __FUNCTION__), 0 : 0)) |
4529 | VOIDmode))((void)(!(!cselib_lookup (node->loc, ((machine_mode) (node ->loc)->mode), 0, ((void) 0, E_VOIDmode))) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4529, __FUNCTION__), 0 : 0)); |
4530 | v = cselib_lookup (node->loc, GET_MODE (node->loc)((machine_mode) (node->loc)->mode), 1, |
4531 | VOIDmode((void) 0, E_VOIDmode)); |
4532 | cselib_preserve_value (v); |
4533 | cselib_invalidate_rtx (node->loc); |
4534 | cval = v->val_rtx; |
4535 | cdv = dv_from_value (cval); |
4536 | if (dump_file) |
4537 | fprintf (dump_file, |
4538 | "Created new value %u:%u for reg %i\n", |
4539 | v->uid, v->hash, REGNO (node->loc)(rhs_regno(node->loc))); |
4540 | } |
4541 | |
4542 | var_reg_decl_set (*dfpm->permp, node->loc, |
4543 | VAR_INIT_STATUS_INITIALIZED, |
4544 | cdv, 0, NULLnullptr, INSERT); |
4545 | |
4546 | node->loc = cval; |
4547 | check_dupes = true; |
4548 | } |
4549 | |
4550 | /* Remove attribute referring to the decl, which now |
4551 | uses the value for the register, already existing or |
4552 | to be added when we bring perm in. */ |
4553 | att = *curp; |
4554 | *curp = att->next; |
4555 | delete att; |
4556 | } |
4557 | } |
4558 | |
4559 | if (check_dupes) |
4560 | remove_duplicate_values (var); |
4561 | } |
4562 | |
4563 | return 1; |
4564 | } |
4565 | |
4566 | /* Reset values in the permanent set that are not associated with the |
4567 | chosen expression. */ |
4568 | |
4569 | int |
4570 | variable_post_merge_perm_vals (variable **pslot, dfset_post_merge *dfpm) |
4571 | { |
4572 | dataflow_set *set = dfpm->set; |
4573 | variable *pvar = *pslot, *var; |
4574 | location_chain *pnode; |
4575 | decl_or_value dv; |
4576 | attrs *att; |
4577 | |
4578 | gcc_assert (dv_is_value_p (pvar->dv)((void)(!(dv_is_value_p (pvar->dv) && pvar->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4579, __FUNCTION__), 0 : 0)) |
4579 | && pvar->n_var_parts == 1)((void)(!(dv_is_value_p (pvar->dv) && pvar->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4579, __FUNCTION__), 0 : 0)); |
4580 | pnode = pvar->var_part[0].loc_chain; |
4581 | gcc_assert (pnode((void)(!(pnode && !pnode->next && (((enum rtx_code) (pnode->loc)->code) == REG)) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4583, __FUNCTION__), 0 : 0)) |
4582 | && !pnode->next((void)(!(pnode && !pnode->next && (((enum rtx_code) (pnode->loc)->code) == REG)) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4583, __FUNCTION__), 0 : 0)) |
4583 | && REG_P (pnode->loc))((void)(!(pnode && !pnode->next && (((enum rtx_code) (pnode->loc)->code) == REG)) ? fancy_abort ( "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4583, __FUNCTION__), 0 : 0)); |
4584 | |
4585 | dv = pvar->dv; |
4586 | |
4587 | var = shared_hash_find (set->vars, dv); |
4588 | if (var) |
4589 | { |
4590 | /* Although variable_post_merge_new_vals may have made decls |
4591 | non-star-canonical, values that pre-existed in canonical form |
4592 | remain canonical, and newly-created values reference a single |
4593 | REG, so they are canonical as well. Since VAR has the |
4594 | location list for a VALUE, using find_loc_in_1pdv for it is |
4595 | fine, since VALUEs don't map back to DECLs. */ |
4596 | if (find_loc_in_1pdv (pnode->loc, var, shared_hash_htab (set->vars))) |
4597 | return 1; |
4598 | val_reset (set, dv); |
4599 | } |
4600 | |
4601 | for (att = set->regs[REGNO (pnode->loc)(rhs_regno(pnode->loc))]; att; att = att->next) |
4602 | if (att->offset == 0 |
4603 | && GET_MODE (att->loc)((machine_mode) (att->loc)->mode) == GET_MODE (pnode->loc)((machine_mode) (pnode->loc)->mode) |
4604 | && dv_is_value_p (att->dv)) |
4605 | break; |
4606 | |
4607 | /* If there is a value associated with this register already, create |
4608 | an equivalence. */ |
4609 | if (att && dv_as_value (att->dv) != dv_as_value (dv)) |
4610 | { |
4611 | rtx cval = dv_as_value (att->dv); |
4612 | set_variable_part (set, cval, dv, 0, pnode->init, NULLnullptr, INSERT); |
4613 | set_variable_part (set, dv_as_value (dv), att->dv, 0, pnode->init, |
4614 | NULLnullptr, INSERT); |
4615 | } |
4616 | else if (!att) |
4617 | { |
4618 | attrs_list_insert (&set->regs[REGNO (pnode->loc)(rhs_regno(pnode->loc))], |
4619 | dv, 0, pnode->loc); |
4620 | variable_union (pvar, set); |
4621 | } |
4622 | |
4623 | return 1; |
4624 | } |
4625 | |
4626 | /* Just checking stuff and registering register attributes for |
4627 | now. */ |
4628 | |
4629 | static void |
4630 | dataflow_post_merge_adjust (dataflow_set *set, dataflow_set **permp) |
4631 | { |
4632 | struct dfset_post_merge dfpm; |
4633 | |
4634 | dfpm.set = set; |
4635 | dfpm.permp = permp; |
4636 | |
4637 | shared_hash_htab (set->vars) |
4638 | ->traverse <dfset_post_merge*, variable_post_merge_new_vals> (&dfpm); |
4639 | if (*permp) |
4640 | shared_hash_htab ((*permp)->vars) |
4641 | ->traverse <dfset_post_merge*, variable_post_merge_perm_vals> (&dfpm); |
4642 | shared_hash_htab (set->vars) |
4643 | ->traverse <dataflow_set *, canonicalize_values_star> (set); |
4644 | shared_hash_htab (set->vars) |
4645 | ->traverse <dataflow_set *, canonicalize_vars_star> (set); |
4646 | } |
4647 | |
4648 | /* Return a node whose loc is a MEM that refers to EXPR in the |
4649 | location list of a one-part variable or value VAR, or in that of |
4650 | any values recursively mentioned in the location lists. */ |
4651 | |
4652 | static location_chain * |
4653 | find_mem_expr_in_1pdv (tree expr, rtx val, variable_table_type *vars) |
4654 | { |
4655 | location_chain *node; |
4656 | decl_or_value dv; |
4657 | variable *var; |
4658 | location_chain *where = NULLnullptr; |
4659 | |
4660 | if (!val) |
4661 | return NULLnullptr; |
4662 | |
4663 | gcc_assert (GET_CODE (val) == VALUE((void)(!(((enum rtx_code) (val)->code) == VALUE && !(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4664, __FUNCTION__); _rtx; })->used)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4664, __FUNCTION__), 0 : 0)) |
4664 | && !VALUE_RECURSED_INTO (val))((void)(!(((enum rtx_code) (val)->code) == VALUE && !(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4664, __FUNCTION__); _rtx; })->used)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4664, __FUNCTION__), 0 : 0)); |
4665 | |
4666 | dv = dv_from_value (val); |
4667 | var = vars->find_with_hash (dv, dv_htab_hash (dv)); |
4668 | |
4669 | if (!var) |
4670 | return NULLnullptr; |
4671 | |
4672 | gcc_assert (var->onepart)((void)(!(var->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4672, __FUNCTION__), 0 : 0)); |
4673 | |
4674 | if (!var->n_var_parts) |
4675 | return NULLnullptr; |
4676 | |
4677 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4677, __FUNCTION__); _rtx; })->used) = true; |
4678 | |
4679 | for (node = var->var_part[0].loc_chain; node; node = node->next) |
4680 | if (MEM_P (node->loc)(((enum rtx_code) (node->loc)->code) == MEM) |
4681 | && MEM_EXPR (node->loc)(get_mem_attrs (node->loc)->expr) == expr |
4682 | && int_mem_offset (node->loc) == 0) |
4683 | { |
4684 | where = node; |
4685 | break; |
4686 | } |
4687 | else if (GET_CODE (node->loc)((enum rtx_code) (node->loc)->code) == VALUE |
4688 | && !VALUE_RECURSED_INTO (node->loc)(__extension__ ({ __typeof ((node->loc)) const _rtx = ((node ->loc)); if (((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO",_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4688, __FUNCTION__); _rtx; })->used) |
4689 | && (where = find_mem_expr_in_1pdv (expr, node->loc, vars))) |
4690 | break; |
4691 | |
4692 | VALUE_RECURSED_INTO (val)(__extension__ ({ __typeof ((val)) const _rtx = ((val)); if ( ((enum rtx_code) (_rtx)->code) != VALUE && ((enum rtx_code ) (_rtx)->code) != DEBUG_EXPR) rtl_check_failed_flag ("VALUE_RECURSED_INTO" ,_rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4692, __FUNCTION__); _rtx; })->used) = false; |
4693 | |
4694 | return where; |
4695 | } |
4696 | |
4697 | /* Return TRUE if the value of MEM may vary across a call. */ |
4698 | |
4699 | static bool |
4700 | mem_dies_at_call (rtx mem) |
4701 | { |
4702 | tree expr = MEM_EXPR (mem)(get_mem_attrs (mem)->expr); |
4703 | tree decl; |
4704 | |
4705 | if (!expr) |
4706 | return true; |
4707 | |
4708 | decl = get_base_address (expr); |
4709 | |
4710 | if (!decl) |
4711 | return true; |
4712 | |
4713 | if (!DECL_P (decl)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (decl)->base.code))] == tcc_declaration)) |
4714 | return true; |
4715 | |
4716 | return (may_be_aliased (decl) |
4717 | || (!TREE_READONLY (decl)((non_type_check ((decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4717, __FUNCTION__))->base.readonly_flag) && is_global_var (decl))); |
4718 | } |
4719 | |
4720 | /* Remove all MEMs from the location list of a hash table entry for a |
4721 | one-part variable, except those whose MEM attributes map back to |
4722 | the variable itself, directly or within a VALUE. */ |
4723 | |
4724 | int |
4725 | dataflow_set_preserve_mem_locs (variable **slot, dataflow_set *set) |
4726 | { |
4727 | variable *var = *slot; |
4728 | |
4729 | if (var->onepart == ONEPART_VDECL || var->onepart == ONEPART_DEXPR) |
4730 | { |
4731 | tree decl = dv_as_decl (var->dv); |
4732 | location_chain *loc, **locp; |
4733 | bool changed = false; |
4734 | |
4735 | if (!var->n_var_parts) |
4736 | return 1; |
4737 | |
4738 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4738, __FUNCTION__), 0 : 0)); |
4739 | |
4740 | if (shared_var_p (var, set->vars)) |
4741 | { |
4742 | for (loc = var->var_part[0].loc_chain; loc; loc = loc->next) |
4743 | { |
4744 | /* We want to remove dying MEMs that don't refer to DECL. */ |
4745 | if (GET_CODE (loc->loc)((enum rtx_code) (loc->loc)->code) == MEM |
4746 | && (MEM_EXPR (loc->loc)(get_mem_attrs (loc->loc)->expr) != decl |
4747 | || int_mem_offset (loc->loc) != 0) |
4748 | && mem_dies_at_call (loc->loc)) |
4749 | break; |
4750 | /* We want to move here MEMs that do refer to DECL. */ |
4751 | else if (GET_CODE (loc->loc)((enum rtx_code) (loc->loc)->code) == VALUE |
4752 | && find_mem_expr_in_1pdv (decl, loc->loc, |
4753 | shared_hash_htab (set->vars))) |
4754 | break; |
4755 | } |
4756 | |
4757 | if (!loc) |
4758 | return 1; |
4759 | |
4760 | slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN); |
4761 | var = *slot; |
4762 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4762, __FUNCTION__), 0 : 0)); |
4763 | } |
4764 | |
4765 | for (locp = &var->var_part[0].loc_chain, loc = *locp; |
4766 | loc; loc = *locp) |
4767 | { |
4768 | rtx old_loc = loc->loc; |
4769 | if (GET_CODE (old_loc)((enum rtx_code) (old_loc)->code) == VALUE) |
4770 | { |
4771 | location_chain *mem_node |
4772 | = find_mem_expr_in_1pdv (decl, loc->loc, |
4773 | shared_hash_htab (set->vars)); |
4774 | |
4775 | /* ??? This picks up only one out of multiple MEMs that |
4776 | refer to the same variable. Do we ever need to be |
4777 | concerned about dealing with more than one, or, given |
4778 | that they should all map to the same variable |
4779 | location, their addresses will have been merged and |
4780 | they will be regarded as equivalent? */ |
4781 | if (mem_node) |
4782 | { |
4783 | loc->loc = mem_node->loc; |
4784 | loc->set_src = mem_node->set_src; |
4785 | loc->init = MIN (loc->init, mem_node->init)((loc->init) < (mem_node->init) ? (loc->init) : ( mem_node->init)); |
4786 | } |
4787 | } |
4788 | |
4789 | if (GET_CODE (loc->loc)((enum rtx_code) (loc->loc)->code) != MEM |
4790 | || (MEM_EXPR (loc->loc)(get_mem_attrs (loc->loc)->expr) == decl |
4791 | && int_mem_offset (loc->loc) == 0) |
4792 | || !mem_dies_at_call (loc->loc)) |
4793 | { |
4794 | if (old_loc != loc->loc && emit_notes) |
4795 | { |
4796 | if (old_loc == var->var_part[0].cur_loc) |
4797 | { |
4798 | changed = true; |
4799 | var->var_part[0].cur_loc = NULLnullptr; |
4800 | } |
4801 | } |
4802 | locp = &loc->next; |
4803 | continue; |
4804 | } |
4805 | |
4806 | if (emit_notes) |
4807 | { |
4808 | if (old_loc == var->var_part[0].cur_loc) |
4809 | { |
4810 | changed = true; |
4811 | var->var_part[0].cur_loc = NULLnullptr; |
4812 | } |
4813 | } |
4814 | *locp = loc->next; |
4815 | delete loc; |
4816 | } |
4817 | |
4818 | if (!var->var_part[0].loc_chain) |
4819 | { |
4820 | var->n_var_parts--; |
4821 | changed = true; |
4822 | } |
4823 | if (changed) |
4824 | variable_was_changed (var, set); |
4825 | } |
4826 | |
4827 | return 1; |
4828 | } |
4829 | |
4830 | /* Remove all MEMs from the location list of a hash table entry for a |
4831 | onepart variable. */ |
4832 | |
4833 | int |
4834 | dataflow_set_remove_mem_locs (variable **slot, dataflow_set *set) |
4835 | { |
4836 | variable *var = *slot; |
4837 | |
4838 | if (var->onepart != NOT_ONEPART) |
4839 | { |
4840 | location_chain *loc, **locp; |
4841 | bool changed = false; |
4842 | rtx cur_loc; |
4843 | |
4844 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4844, __FUNCTION__), 0 : 0)); |
4845 | |
4846 | if (shared_var_p (var, set->vars)) |
4847 | { |
4848 | for (loc = var->var_part[0].loc_chain; loc; loc = loc->next) |
4849 | if (GET_CODE (loc->loc)((enum rtx_code) (loc->loc)->code) == MEM |
4850 | && mem_dies_at_call (loc->loc)) |
4851 | break; |
4852 | |
4853 | if (!loc) |
4854 | return 1; |
4855 | |
4856 | slot = unshare_variable (set, slot, var, VAR_INIT_STATUS_UNKNOWN); |
4857 | var = *slot; |
4858 | gcc_assert (var->n_var_parts == 1)((void)(!(var->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4858, __FUNCTION__), 0 : 0)); |
4859 | } |
4860 | |
4861 | if (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4861, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))) |
4862 | cur_loc = VAR_LOC_FROM (var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4862, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))->from); |
4863 | else |
4864 | cur_loc = var->var_part[0].cur_loc; |
4865 | |
4866 | for (locp = &var->var_part[0].loc_chain, loc = *locp; |
4867 | loc; loc = *locp) |
4868 | { |
4869 | if (GET_CODE (loc->loc)((enum rtx_code) (loc->loc)->code) != MEM |
4870 | || !mem_dies_at_call (loc->loc)) |
4871 | { |
4872 | locp = &loc->next; |
4873 | continue; |
4874 | } |
4875 | |
4876 | *locp = loc->next; |
4877 | /* If we have deleted the location which was last emitted |
4878 | we have to emit new location so add the variable to set |
4879 | of changed variables. */ |
4880 | if (cur_loc == loc->loc) |
4881 | { |
4882 | changed = true; |
4883 | var->var_part[0].cur_loc = NULLnullptr; |
4884 | if (VAR_LOC_1PAUX (var)__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4884, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))) |
4885 | VAR_LOC_FROM (var)(__extension__ (*({ variable *const __v = (var); ((void)(!(__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4885, __FUNCTION__), 0 : 0)); &__v->var_part[0].aux. onepaux; }))->from) = NULLnullptr; |
4886 | } |
4887 | delete loc; |
4888 | } |
4889 | |
4890 | if (!var->var_part[0].loc_chain) |
4891 | { |
4892 | var->n_var_parts--; |
4893 | changed = true; |
4894 | } |
4895 | if (changed) |
4896 | variable_was_changed (var, set); |
4897 | } |
4898 | |
4899 | return 1; |
4900 | } |
4901 | |
4902 | /* Remove all variable-location information about call-clobbered |
4903 | registers, as well as associations between MEMs and VALUEs. */ |
4904 | |
4905 | static void |
4906 | dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn) |
4907 | { |
4908 | unsigned int r; |
4909 | hard_reg_set_iterator hrsi; |
4910 | |
4911 | HARD_REG_SET callee_clobbers |
4912 | = insn_callee_abi (call_insn).full_reg_clobbers (); |
4913 | |
4914 | EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, r, hrsi)for (hard_reg_set_iter_init (&(hrsi), (callee_clobbers), ( 0), &(r)); hard_reg_set_iter_set (&(hrsi), &(r)); hard_reg_set_iter_next (&(hrsi), &(r))) |
4915 | var_regno_delete (set, r); |
4916 | |
4917 | if (MAY_HAVE_DEBUG_BIND_INSNSglobal_options.x_flag_var_tracking_assignments) |
4918 | { |
4919 | set->traversed_vars = set->vars; |
4920 | shared_hash_htab (set->vars) |
4921 | ->traverse <dataflow_set *, dataflow_set_preserve_mem_locs> (set); |
4922 | set->traversed_vars = set->vars; |
4923 | shared_hash_htab (set->vars) |
4924 | ->traverse <dataflow_set *, dataflow_set_remove_mem_locs> (set); |
4925 | set->traversed_vars = NULLnullptr; |
4926 | } |
4927 | } |
4928 | |
4929 | static bool |
4930 | variable_part_different_p (variable_part *vp1, variable_part *vp2) |
4931 | { |
4932 | location_chain *lc1, *lc2; |
4933 | |
4934 | for (lc1 = vp1->loc_chain; lc1; lc1 = lc1->next) |
4935 | { |
4936 | for (lc2 = vp2->loc_chain; lc2; lc2 = lc2->next) |
4937 | { |
4938 | if (REG_P (lc1->loc)(((enum rtx_code) (lc1->loc)->code) == REG) && REG_P (lc2->loc)(((enum rtx_code) (lc2->loc)->code) == REG)) |
4939 | { |
4940 | if (REGNO (lc1->loc)(rhs_regno(lc1->loc)) == REGNO (lc2->loc)(rhs_regno(lc2->loc))) |
4941 | break; |
4942 | } |
4943 | if (rtx_equal_p (lc1->loc, lc2->loc)) |
4944 | break; |
4945 | } |
4946 | if (!lc2) |
4947 | return true; |
4948 | } |
4949 | return false; |
4950 | } |
4951 | |
4952 | /* Return true if one-part variables VAR1 and VAR2 are different. |
4953 | They must be in canonical order. */ |
4954 | |
4955 | static bool |
4956 | onepart_variable_different_p (variable *var1, variable *var2) |
4957 | { |
4958 | location_chain *lc1, *lc2; |
4959 | |
4960 | if (var1 == var2) |
4961 | return false; |
4962 | |
4963 | gcc_assert (var1->n_var_parts == 1((void)(!(var1->n_var_parts == 1 && var2->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4964, __FUNCTION__), 0 : 0)) |
4964 | && var2->n_var_parts == 1)((void)(!(var1->n_var_parts == 1 && var2->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4964, __FUNCTION__), 0 : 0)); |
4965 | |
4966 | lc1 = var1->var_part[0].loc_chain; |
4967 | lc2 = var2->var_part[0].loc_chain; |
4968 | |
4969 | gcc_assert (lc1 && lc2)((void)(!(lc1 && lc2) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4969, __FUNCTION__), 0 : 0)); |
4970 | |
4971 | while (lc1 && lc2) |
4972 | { |
4973 | if (loc_cmp (lc1->loc, lc2->loc)) |
4974 | return true; |
4975 | lc1 = lc1->next; |
4976 | lc2 = lc2->next; |
4977 | } |
4978 | |
4979 | return lc1 != lc2; |
4980 | } |
4981 | |
4982 | /* Return true if one-part variables VAR1 and VAR2 are different. |
4983 | They must be in canonical order. */ |
4984 | |
4985 | static void |
4986 | dump_onepart_variable_differences (variable *var1, variable *var2) |
4987 | { |
4988 | location_chain *lc1, *lc2; |
4989 | |
4990 | gcc_assert (var1 != var2)((void)(!(var1 != var2) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4990, __FUNCTION__), 0 : 0)); |
4991 | gcc_assert (dump_file)((void)(!(dump_file) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4991, __FUNCTION__), 0 : 0)); |
4992 | gcc_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv))((void)(!(dv_as_opaque (var1->dv) == dv_as_opaque (var2-> dv)) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4992, __FUNCTION__), 0 : 0)); |
4993 | gcc_assert (var1->n_var_parts == 1((void)(!(var1->n_var_parts == 1 && var2->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4994, __FUNCTION__), 0 : 0)) |
4994 | && var2->n_var_parts == 1)((void)(!(var1->n_var_parts == 1 && var2->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4994, __FUNCTION__), 0 : 0)); |
4995 | |
4996 | lc1 = var1->var_part[0].loc_chain; |
4997 | lc2 = var2->var_part[0].loc_chain; |
4998 | |
4999 | gcc_assert (lc1 && lc2)((void)(!(lc1 && lc2) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 4999, __FUNCTION__), 0 : 0)); |
5000 | |
5001 | while (lc1 && lc2) |
5002 | { |
5003 | switch (loc_cmp (lc1->loc, lc2->loc)) |
5004 | { |
5005 | case -1: |
5006 | fprintf (dump_file, "removed: "); |
5007 | print_rtl_single (dump_file, lc1->loc); |
5008 | lc1 = lc1->next; |
5009 | continue; |
5010 | case 0: |
5011 | break; |
5012 | case 1: |
5013 | fprintf (dump_file, "added: "); |
5014 | print_rtl_single (dump_file, lc2->loc); |
5015 | lc2 = lc2->next; |
5016 | continue; |
5017 | default: |
5018 | gcc_unreachable ()(fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5018, __FUNCTION__)); |
5019 | } |
5020 | lc1 = lc1->next; |
5021 | lc2 = lc2->next; |
5022 | } |
5023 | |
5024 | while (lc1) |
5025 | { |
5026 | fprintf (dump_file, "removed: "); |
5027 | print_rtl_single (dump_file, lc1->loc); |
5028 | lc1 = lc1->next; |
5029 | } |
5030 | |
5031 | while (lc2) |
5032 | { |
5033 | fprintf (dump_file, "added: "); |
5034 | print_rtl_single (dump_file, lc2->loc); |
5035 | lc2 = lc2->next; |
5036 | } |
5037 | } |
5038 | |
5039 | /* Return true if variables VAR1 and VAR2 are different. */ |
5040 | |
5041 | static bool |
5042 | variable_different_p (variable *var1, variable *var2) |
5043 | { |
5044 | int i; |
5045 | |
5046 | if (var1 == var2) |
5047 | return false; |
5048 | |
5049 | if (var1->onepart != var2->onepart) |
5050 | return true; |
5051 | |
5052 | if (var1->n_var_parts != var2->n_var_parts) |
5053 | return true; |
5054 | |
5055 | if (var1->onepart && var1->n_var_parts) |
5056 | { |
5057 | gcc_checking_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv)((void)(!(dv_as_opaque (var1->dv) == dv_as_opaque (var2-> dv) && var1->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5058, __FUNCTION__), 0 : 0)) |
5058 | && var1->n_var_parts == 1)((void)(!(dv_as_opaque (var1->dv) == dv_as_opaque (var2-> dv) && var1->n_var_parts == 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5058, __FUNCTION__), 0 : 0)); |
5059 | /* One-part values have locations in a canonical order. */ |
5060 | return onepart_variable_different_p (var1, var2); |
5061 | } |
5062 | |
5063 | for (i = 0; i < var1->n_var_parts; i++) |
5064 | { |
5065 | if (VAR_PART_OFFSET (var1, i)__extension__ (*({ variable *const __v = (var1); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5065, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; })) != VAR_PART_OFFSET (var2, i)__extension__ (*({ variable *const __v = (var2); ((void)(!(!__v ->onepart) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5065, __FUNCTION__), 0 : 0)); &__v->var_part[(i)].aux .offset; }))) |
5066 | return true; |
5067 | if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i])) |
5068 | return true; |
5069 | if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i])) |
5070 | return true; |
5071 | } |
5072 | return false; |
5073 | } |
5074 | |
5075 | /* Return true if dataflow sets OLD_SET and NEW_SET differ. */ |
5076 | |
5077 | static bool |
5078 | dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set) |
5079 | { |
5080 | variable_iterator_type hi; |
5081 | variable *var1; |
5082 | bool diffound = false; |
5083 | bool details = (dump_file && (dump_flags & TDF_DETAILS)); |
5084 | |
5085 | #define RETRUE \ |
5086 | do \ |
5087 | { \ |
5088 | if (!details) \ |
5089 | return true; \ |
5090 | else \ |
5091 | diffound = true; \ |
5092 | } \ |
5093 | while (0) |
5094 | |
5095 | if (old_set->vars == new_set->vars) |
5096 | return false; |
5097 | |
5098 | if (shared_hash_htab (old_set->vars)->elements () |
5099 | != shared_hash_htab (new_set->vars)->elements ()) |
5100 | RETRUE; |
5101 | |
5102 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (old_set->vars),for ((hi) = (*shared_hash_htab (old_set->vars)).begin (); ( hi) != (*shared_hash_htab (old_set->vars)).end () ? (var1 = *(hi) , true) : false; ++(hi)) |
5103 | var1, variable, hi)for ((hi) = (*shared_hash_htab (old_set->vars)).begin (); ( hi) != (*shared_hash_htab (old_set->vars)).end () ? (var1 = *(hi) , true) : false; ++(hi)) |
5104 | { |
5105 | variable_table_type *htab = shared_hash_htab (new_set->vars); |
5106 | variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv)); |
5107 | |
5108 | if (!var2) |
5109 | { |
5110 | if (dump_file && (dump_flags & TDF_DETAILS)) |
5111 | { |
5112 | fprintf (dump_file, "dataflow difference found: removal of:\n"); |
5113 | dump_var (var1); |
5114 | } |
5115 | RETRUE; |
5116 | } |
5117 | else if (variable_different_p (var1, var2)) |
5118 | { |
5119 | if (details) |
5120 | { |
5121 | fprintf (dump_file, "dataflow difference found: " |
5122 | "old and new follow:\n"); |
5123 | dump_var (var1); |
5124 | if (dv_onepart_p (var1->dv)) |
5125 | dump_onepart_variable_differences (var1, var2); |
5126 | dump_var (var2); |
5127 | } |
5128 | RETRUE; |
5129 | } |
5130 | } |
5131 | |
5132 | /* There's no need to traverse the second hashtab unless we want to |
5133 | print the details. If both have the same number of elements and |
5134 | the second one had all entries found in the first one, then the |
5135 | second can't have any extra entries. */ |
5136 | if (!details) |
5137 | return diffound; |
5138 | |
5139 | FOR_EACH_HASH_TABLE_ELEMENT (*shared_hash_htab (new_set->vars),for ((hi) = (*shared_hash_htab (new_set->vars)).begin (); ( hi) != (*shared_hash_htab (new_set->vars)).end () ? (var1 = *(hi) , true) : false; ++(hi)) |
5140 | var1, variable, hi)for ((hi) = (*shared_hash_htab (new_set->vars)).begin (); ( hi) != (*shared_hash_htab (new_set->vars)).end () ? (var1 = *(hi) , true) : false; ++(hi)) |
5141 | { |
5142 | variable_table_type *htab = shared_hash_htab (old_set->vars); |
5143 | variable *var2 = htab->find_with_hash (var1->dv, dv_htab_hash (var1->dv)); |
5144 | if (!var2) |
5145 | { |
5146 | if (details) |
5147 | { |
5148 | fprintf (dump_file, "dataflow difference found: addition of:\n"); |
5149 | dump_var (var1); |
5150 | } |
5151 | RETRUE; |
5152 | } |
5153 | } |
5154 | |
5155 | #undef RETRUE |
5156 | |
5157 | return diffound; |
5158 | } |
5159 | |
5160 | /* Free the contents of dataflow set SET. */ |
5161 | |
5162 | static void |
5163 | dataflow_set_destroy (dataflow_set *set) |
5164 | { |
5165 | int i; |
5166 | |
5167 | for (i = 0; i < FIRST_PSEUDO_REGISTER76; i++) |
5168 | attrs_list_clear (&set->regs[i]); |
5169 | |
5170 | shared_hash_destroy (set->vars); |
5171 | set->vars = NULLnullptr; |
5172 | } |
5173 | |
5174 | /* Return true if T is a tracked parameter with non-degenerate record type. */ |
5175 | |
5176 | static bool |
5177 | tracked_record_parameter_p (tree t) |
5178 | { |
5179 | if (TREE_CODE (t)((enum tree_code) (t)->base.code) != PARM_DECL) |
5180 | return false; |
5181 | |
5182 | if (DECL_MODE (t)((contains_struct_check ((t), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5182, __FUNCTION__))->decl_common.mode) == BLKmode((void) 0, E_BLKmode)) |
5183 | return false; |
5184 | |
5185 | tree type = TREE_TYPE (t)((contains_struct_check ((t), (TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5185, __FUNCTION__))->typed.type); |
5186 | if (TREE_CODE (type)((enum tree_code) (type)->base.code) != RECORD_TYPE) |
5187 | return false; |
5188 | |
5189 | if (TYPE_FIELDS (type)((tree_check3 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5189, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values) == NULL_TREE(tree) nullptr |
5190 | || DECL_CHAIN (TYPE_FIELDS (type))(((contains_struct_check (((contains_struct_check ((((tree_check3 ((type), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5190, __FUNCTION__, (RECORD_TYPE), (UNION_TYPE), (QUAL_UNION_TYPE )))->type_non_common.values)), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5190, __FUNCTION__))), (TS_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5190, __FUNCTION__))->common.chain)) == NULL_TREE(tree) nullptr) |
5191 | return false; |
5192 | |
5193 | return true; |
5194 | } |
5195 | |
5196 | /* Shall EXPR be tracked? */ |
5197 | |
5198 | static bool |
5199 | track_expr_p (tree expr, bool need_rtl) |
5200 | { |
5201 | rtx decl_rtl; |
5202 | tree realdecl; |
5203 | |
5204 | if (TREE_CODE (expr)((enum tree_code) (expr)->base.code) == DEBUG_EXPR_DECL) |
5205 | return DECL_RTL_SET_P (expr)(((tree_contains_struct[(((enum tree_code) (expr)->base.code ))][(TS_DECL_WRTL)])) && (contains_struct_check ((expr ), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5205, __FUNCTION__))->decl_with_rtl.rtl != nullptr); |
5206 | |
5207 | /* If EXPR is not a parameter or a variable do not track it. */ |
5208 | if (!VAR_P (expr)(((enum tree_code) (expr)->base.code) == VAR_DECL) && TREE_CODE (expr)((enum tree_code) (expr)->base.code) != PARM_DECL) |
5209 | return 0; |
5210 | |
5211 | /* It also must have a name... */ |
5212 | if (!DECL_NAME (expr)((contains_struct_check ((expr), (TS_DECL_MINIMAL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5212, __FUNCTION__))->decl_minimal.name) && need_rtl) |
5213 | return 0; |
5214 | |
5215 | /* ... and a RTL assigned to it. */ |
5216 | decl_rtl = DECL_RTL_IF_SET (expr)((((tree_contains_struct[(((enum tree_code) (expr)->base.code ))][(TS_DECL_WRTL)])) && (contains_struct_check ((expr ), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5216, __FUNCTION__))->decl_with_rtl.rtl != nullptr) ? (( contains_struct_check ((expr), (TS_DECL_WRTL), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5216, __FUNCTION__))->decl_with_rtl.rtl ? (expr)->decl_with_rtl .rtl : (make_decl_rtl (expr), (expr)->decl_with_rtl.rtl)) : nullptr); |
5217 | if (!decl_rtl && need_rtl) |
5218 | return 0; |
5219 | |
5220 | /* If this expression is really a debug alias of some other declaration, we |
5221 | don't need to track this expression if the ultimate declaration is |
5222 | ignored. */ |
5223 | realdecl = expr; |
5224 | if (VAR_P (realdecl)(((enum tree_code) (realdecl)->base.code) == VAR_DECL) && DECL_HAS_DEBUG_EXPR_P (realdecl)((tree_check ((realdecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5224, __FUNCTION__, (VAR_DECL)))->decl_common.debug_expr_is_from )) |
5225 | { |
5226 | realdecl = DECL_DEBUG_EXPR (realdecl)(decl_debug_expr_lookup ((tree_check ((realdecl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5226, __FUNCTION__, (VAR_DECL))))); |
5227 | if (!DECL_P (realdecl)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (realdecl)->base.code))] == tcc_declaration)) |
5228 | { |
5229 | if (handled_component_p (realdecl) |
5230 | || (TREE_CODE (realdecl)((enum tree_code) (realdecl)->base.code) == MEM_REF |
5231 | && TREE_CODE (TREE_OPERAND (realdecl, 0))((enum tree_code) ((*((const_cast<tree*> (tree_operand_check ((realdecl), (0), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5231, __FUNCTION__))))))->base.code) == ADDR_EXPR)) |
5232 | { |
5233 | HOST_WIDE_INTlong bitsize, bitpos; |
5234 | bool reverse; |
5235 | tree innerdecl |
5236 | = get_ref_base_and_extent_hwi (realdecl, &bitpos, |
5237 | &bitsize, &reverse); |
5238 | if (!innerdecl |
5239 | || !DECL_P (innerdecl)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (innerdecl)->base.code))] == tcc_declaration) |
5240 | || DECL_IGNORED_P (innerdecl)((contains_struct_check ((innerdecl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5240, __FUNCTION__))->decl_common.ignored_flag) |
5241 | /* Do not track declarations for parts of tracked record |
5242 | parameters since we want to track them as a whole. */ |
5243 | || tracked_record_parameter_p (innerdecl) |
5244 | || TREE_STATIC (innerdecl)((innerdecl)->base.static_flag) |
5245 | || bitsize == 0 |
5246 | || bitpos + bitsize > 256) |
5247 | return 0; |
5248 | else |
5249 | realdecl = expr; |
5250 | } |
5251 | else |
5252 | return 0; |
5253 | } |
5254 | } |
5255 | |
5256 | /* Do not track EXPR if REALDECL it should be ignored for debugging |
5257 | purposes. */ |
5258 | if (DECL_IGNORED_P (realdecl)((contains_struct_check ((realdecl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5258, __FUNCTION__))->decl_common.ignored_flag)) |
5259 | return 0; |
5260 | |
5261 | /* Do not track global variables until we are able to emit correct location |
5262 | list for them. */ |
5263 | if (TREE_STATIC (realdecl)((realdecl)->base.static_flag)) |
5264 | return 0; |
5265 | |
5266 | /* When the EXPR is a DECL for alias of some variable (see example) |
5267 | the TREE_STATIC flag is not used. Disable tracking all DECLs whose |
5268 | DECL_RTL contains SYMBOL_REF. |
5269 | |
5270 | Example: |
5271 | extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv"))); |
5272 | char **_dl_argv; |
5273 | */ |
5274 | if (decl_rtl && MEM_P (decl_rtl)(((enum rtx_code) (decl_rtl)->code) == MEM) |
5275 | && contains_symbol_ref_p (XEXP (decl_rtl, 0)(((decl_rtl)->u.fld[0]).rt_rtx))) |
5276 | return 0; |
5277 | |
5278 | /* If RTX is a memory it should not be very large (because it would be |
5279 | an array or struct). */ |
5280 | if (decl_rtl && MEM_P (decl_rtl)(((enum rtx_code) (decl_rtl)->code) == MEM)) |
5281 | { |
5282 | /* Do not track structures and arrays. */ |
5283 | if ((GET_MODE (decl_rtl)((machine_mode) (decl_rtl)->mode) == BLKmode((void) 0, E_BLKmode) |
5284 | || AGGREGATE_TYPE_P (TREE_TYPE (realdecl))(((enum tree_code) (((contains_struct_check ((realdecl), (TS_TYPED ), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5284, __FUNCTION__))->typed.type))->base.code) == ARRAY_TYPE || (((enum tree_code) (((contains_struct_check ((realdecl), ( TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5284, __FUNCTION__))->typed.type))->base.code) == RECORD_TYPE || ((enum tree_code) (((contains_struct_check ((realdecl), ( TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5284, __FUNCTION__))->typed.type))->base.code) == UNION_TYPE || ((enum tree_code) (((contains_struct_check ((realdecl), ( TS_TYPED), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5284, __FUNCTION__))->typed.type))->base.code) == QUAL_UNION_TYPE ))) |
5285 | && !tracked_record_parameter_p (realdecl)) |
5286 | return 0; |
5287 | if (MEM_SIZE_KNOWN_P (decl_rtl)(get_mem_attrs (decl_rtl)->size_known_p) |
5288 | && maybe_gt (MEM_SIZE (decl_rtl), MAX_VAR_PARTS)maybe_lt (16, (get_mem_attrs (decl_rtl)->size))) |
5289 | return 0; |
5290 | } |
5291 | |
5292 | DECL_CHANGED (expr)((expr)->base.visited) = 0; |
5293 | DECL_CHANGED (realdecl)((realdecl)->base.visited) = 0; |
5294 | return 1; |
5295 | } |
5296 | |
5297 | /* Determine whether a given LOC refers to the same variable part as |
5298 | EXPR+OFFSET. */ |
5299 | |
5300 | static bool |
5301 | same_variable_part_p (rtx loc, tree expr, poly_int64 offset) |
5302 | { |
5303 | tree expr2; |
5304 | poly_int64 offset2; |
5305 | |
5306 | if (! DECL_P (expr)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (expr)->base.code))] == tcc_declaration)) |
5307 | return false; |
5308 | |
5309 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG)) |
5310 | { |
5311 | expr2 = REG_EXPR (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->decl); |
5312 | offset2 = REG_OFFSET (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->offset); |
5313 | } |
5314 | else if (MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
5315 | { |
5316 | expr2 = MEM_EXPR (loc)(get_mem_attrs (loc)->expr); |
5317 | offset2 = int_mem_offset (loc); |
5318 | } |
5319 | else |
5320 | return false; |
5321 | |
5322 | if (! expr2 || ! DECL_P (expr2)(tree_code_type_tmpl <0>::tree_code_type[(int) (((enum tree_code ) (expr2)->base.code))] == tcc_declaration)) |
5323 | return false; |
5324 | |
5325 | expr = var_debug_decl (expr); |
5326 | expr2 = var_debug_decl (expr2); |
5327 | |
5328 | return (expr == expr2 && known_eq (offset, offset2)(!maybe_ne (offset, offset2))); |
5329 | } |
5330 | |
5331 | /* LOC is a REG or MEM that we would like to track if possible. |
5332 | If EXPR is null, we don't know what expression LOC refers to, |
5333 | otherwise it refers to EXPR + OFFSET. STORE_REG_P is true if |
5334 | LOC is an lvalue register. |
5335 | |
5336 | Return true if EXPR is nonnull and if LOC, or some lowpart of it, |
5337 | is something we can track. When returning true, store the mode of |
5338 | the lowpart we can track in *MODE_OUT (if nonnull) and its offset |
5339 | from EXPR in *OFFSET_OUT (if nonnull). */ |
5340 | |
5341 | static bool |
5342 | track_loc_p (rtx loc, tree expr, poly_int64 offset, bool store_reg_p, |
5343 | machine_mode *mode_out, HOST_WIDE_INTlong *offset_out) |
5344 | { |
5345 | machine_mode mode; |
5346 | |
5347 | if (expr == NULLnullptr || !track_expr_p (expr, true)) |
5348 | return false; |
5349 | |
5350 | /* If REG was a paradoxical subreg, its REG_ATTRS will describe the |
5351 | whole subreg, but only the old inner part is really relevant. */ |
5352 | mode = GET_MODE (loc)((machine_mode) (loc)->mode); |
5353 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc))(((__extension__ ({ __typeof ((loc)) const _rtx = ((loc)); if (((enum rtx_code) (_rtx)->code) != REG) rtl_check_failed_flag ("ORIGINAL_REGNO", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5353, __FUNCTION__); _rtx; })->u2.original_regno)) < 76 )) |
5354 | { |
5355 | machine_mode pseudo_mode; |
5356 | |
5357 | pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc))((machine_mode) (regno_reg_rtx[(__extension__ ({ __typeof ((loc )) const _rtx = ((loc)); if (((enum rtx_code) (_rtx)->code ) != REG) rtl_check_failed_flag ("ORIGINAL_REGNO", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5357, __FUNCTION__); _rtx; })->u2.original_regno)])-> mode); |
5358 | if (paradoxical_subreg_p (mode, pseudo_mode)) |
5359 | { |
5360 | offset += byte_lowpart_offset (pseudo_mode, mode); |
5361 | mode = pseudo_mode; |
5362 | } |
5363 | } |
5364 | |
5365 | /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself. |
5366 | Do the same if we are storing to a register and EXPR occupies |
5367 | the whole of register LOC; in that case, the whole of EXPR is |
5368 | being changed. We exclude complex modes from the second case |
5369 | because the real and imaginary parts are represented as separate |
5370 | pseudo registers, even if the whole complex value fits into one |
5371 | hard register. */ |
5372 | if ((paradoxical_subreg_p (mode, DECL_MODE (expr)((contains_struct_check ((expr), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5372, __FUNCTION__))->decl_common.mode)) |
5373 | || (store_reg_p |
5374 | && !COMPLEX_MODE_P (DECL_MODE (expr))(((enum mode_class) mode_class[((contains_struct_check ((expr ), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5374, __FUNCTION__))->decl_common.mode)]) == MODE_COMPLEX_INT || ((enum mode_class) mode_class[((contains_struct_check ((expr ), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5374, __FUNCTION__))->decl_common.mode)]) == MODE_COMPLEX_FLOAT ) |
5375 | && hard_regno_nregs (REGNO (loc)(rhs_regno(loc)), DECL_MODE (expr)((contains_struct_check ((expr), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5375, __FUNCTION__))->decl_common.mode)) == 1)) |
5376 | && known_eq (offset + byte_lowpart_offset (DECL_MODE (expr), mode), 0)(!maybe_ne (offset + byte_lowpart_offset (((contains_struct_check ((expr), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5376, __FUNCTION__))->decl_common.mode), mode), 0))) |
5377 | { |
5378 | mode = DECL_MODE (expr)((contains_struct_check ((expr), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5378, __FUNCTION__))->decl_common.mode); |
5379 | offset = 0; |
5380 | } |
5381 | |
5382 | HOST_WIDE_INTlong const_offset; |
5383 | if (!track_offset_p (offset, &const_offset)) |
5384 | return false; |
5385 | |
5386 | if (mode_out) |
5387 | *mode_out = mode; |
5388 | if (offset_out) |
5389 | *offset_out = const_offset; |
5390 | return true; |
5391 | } |
5392 | |
5393 | /* Return the MODE lowpart of LOC, or null if LOC is not something we |
5394 | want to track. When returning nonnull, make sure that the attributes |
5395 | on the returned value are updated. */ |
5396 | |
5397 | static rtx |
5398 | var_lowpart (machine_mode mode, rtx loc) |
5399 | { |
5400 | unsigned int regno; |
5401 | |
5402 | if (GET_MODE (loc)((machine_mode) (loc)->mode) == mode) |
5403 | return loc; |
5404 | |
5405 | if (!REG_P (loc)(((enum rtx_code) (loc)->code) == REG) && !MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
5406 | return NULLnullptr; |
5407 | |
5408 | poly_uint64 offset = byte_lowpart_offset (mode, GET_MODE (loc)((machine_mode) (loc)->mode)); |
5409 | |
5410 | if (MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
5411 | return adjust_address_nv (loc, mode, offset)adjust_address_1 (loc, mode, offset, 0, 1, 0, 0); |
5412 | |
5413 | poly_uint64 reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc)((machine_mode) (loc)->mode)); |
5414 | regno = REGNO (loc)(rhs_regno(loc)) + subreg_regno_offset (REGNO (loc)(rhs_regno(loc)), GET_MODE (loc)((machine_mode) (loc)->mode), |
5415 | reg_offset, mode); |
5416 | return gen_rtx_REG_offset (loc, mode, regno, offset); |
5417 | } |
5418 | |
5419 | /* Carry information about uses and stores while walking rtx. */ |
5420 | |
5421 | struct count_use_info |
5422 | { |
5423 | /* The insn where the RTX is. */ |
5424 | rtx_insn *insn; |
5425 | |
5426 | /* The basic block where insn is. */ |
5427 | basic_block bb; |
5428 | |
5429 | /* The array of n_sets sets in the insn, as determined by cselib. */ |
5430 | struct cselib_set *sets; |
5431 | int n_sets; |
5432 | |
5433 | /* True if we're counting stores, false otherwise. */ |
5434 | bool store_p; |
5435 | }; |
5436 | |
5437 | /* Find a VALUE corresponding to X. */ |
5438 | |
5439 | static inline cselib_val * |
5440 | find_use_val (rtx x, machine_mode mode, struct count_use_info *cui) |
5441 | { |
5442 | int i; |
5443 | |
5444 | if (cui->sets) |
5445 | { |
5446 | /* This is called after uses are set up and before stores are |
5447 | processed by cselib, so it's safe to look up srcs, but not |
5448 | dsts. So we look up expressions that appear in srcs or in |
5449 | dest expressions, but we search the sets array for dests of |
5450 | stores. */ |
5451 | if (cui->store_p) |
5452 | { |
5453 | /* Some targets represent memset and memcpy patterns |
5454 | by (set (mem:BLK ...) (reg:[QHSD]I ...)) or |
5455 | (set (mem:BLK ...) (const_int ...)) or |
5456 | (set (mem:BLK ...) (mem:BLK ...)). Don't return anything |
5457 | in that case, otherwise we end up with mode mismatches. */ |
5458 | if (mode == BLKmode((void) 0, E_BLKmode) && MEM_P (x)(((enum rtx_code) (x)->code) == MEM)) |
5459 | return NULLnullptr; |
5460 | for (i = 0; i < cui->n_sets; i++) |
5461 | if (cui->sets[i].dest == x) |
5462 | return cui->sets[i].src_elt; |
5463 | } |
5464 | else |
5465 | return cselib_lookup (x, mode, 0, VOIDmode((void) 0, E_VOIDmode)); |
5466 | } |
5467 | |
5468 | return NULLnullptr; |
5469 | } |
5470 | |
5471 | /* Replace all registers and addresses in an expression with VALUE |
5472 | expressions that map back to them, unless the expression is a |
5473 | register. If no mapping is or can be performed, returns NULL. */ |
5474 | |
5475 | static rtx |
5476 | replace_expr_with_values (rtx loc) |
5477 | { |
5478 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG) || GET_CODE (loc)((enum rtx_code) (loc)->code) == ENTRY_VALUE) |
5479 | return NULLnullptr; |
5480 | else if (MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
5481 | { |
5482 | cselib_val *addr = cselib_lookup (XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx), |
5483 | get_address_mode (loc), 0, |
5484 | GET_MODE (loc)((machine_mode) (loc)->mode)); |
5485 | if (addr) |
5486 | return replace_equiv_address_nv (loc, addr->val_rtx); |
5487 | else |
5488 | return NULLnullptr; |
5489 | } |
5490 | else |
5491 | return cselib_subst_to_values (loc, VOIDmode((void) 0, E_VOIDmode)); |
5492 | } |
5493 | |
5494 | /* Return true if X contains a DEBUG_EXPR. */ |
5495 | |
5496 | static bool |
5497 | rtx_debug_expr_p (const_rtx x) |
5498 | { |
5499 | subrtx_iterator::array_type array; |
5500 | FOR_EACH_SUBRTX (iter, array, x, ALL)for (subrtx_iterator iter (array, x, rtx_all_subrtx_bounds); ! iter.at_end (); iter.next ()) |
5501 | if (GET_CODE (*iter)((enum rtx_code) (*iter)->code) == DEBUG_EXPR) |
5502 | return true; |
5503 | return false; |
5504 | } |
5505 | |
5506 | /* Determine what kind of micro operation to choose for a USE. Return |
5507 | MO_CLOBBER if no micro operation is to be generated. */ |
5508 | |
5509 | static enum micro_operation_type |
5510 | use_type (rtx loc, struct count_use_info *cui, machine_mode *modep) |
5511 | { |
5512 | tree expr; |
5513 | |
5514 | if (cui && cui->sets) |
5515 | { |
5516 | if (GET_CODE (loc)((enum rtx_code) (loc)->code) == VAR_LOCATION) |
5517 | { |
5518 | if (track_expr_p (PAT_VAR_LOCATION_DECL (loc)(((((loc))->u.fld[0]).rt_tree)), false)) |
5519 | { |
5520 | rtx ploc = PAT_VAR_LOCATION_LOC (loc)(((((loc))->u.fld[1]).rt_rtx)); |
5521 | if (! VAR_LOC_UNKNOWN_P (ploc)(((enum rtx_code) (ploc)->code) == CLOBBER && (((( ploc))->u.fld[0]).rt_rtx) == (const_int_rtx[64]))) |
5522 | { |
5523 | cselib_val *val = cselib_lookup (ploc, GET_MODE (loc)((machine_mode) (loc)->mode), 1, |
5524 | VOIDmode((void) 0, E_VOIDmode)); |
5525 | |
5526 | /* ??? flag_float_store and volatile mems are never |
5527 | given values, but we could in theory use them for |
5528 | locations. */ |
5529 | gcc_assert (val || 1)((void)(!(val || 1) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5529, __FUNCTION__), 0 : 0)); |
5530 | } |
5531 | return MO_VAL_LOC; |
5532 | } |
5533 | else |
5534 | return MO_CLOBBER; |
5535 | } |
5536 | |
5537 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG) || MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
5538 | { |
5539 | if (modep) |
5540 | *modep = GET_MODE (loc)((machine_mode) (loc)->mode); |
5541 | if (cui->store_p) |
5542 | { |
5543 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG) |
5544 | || (find_use_val (loc, GET_MODE (loc)((machine_mode) (loc)->mode), cui) |
5545 | && cselib_lookup (XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx), |
5546 | get_address_mode (loc), 0, |
5547 | GET_MODE (loc)((machine_mode) (loc)->mode)))) |
5548 | return MO_VAL_SET; |
5549 | } |
5550 | else |
5551 | { |
5552 | cselib_val *val = find_use_val (loc, GET_MODE (loc)((machine_mode) (loc)->mode), cui); |
5553 | |
5554 | if (val && !cselib_preserved_value_p (val)) |
5555 | return MO_VAL_USE; |
5556 | } |
5557 | } |
5558 | } |
5559 | |
5560 | if (REG_P (loc)(((enum rtx_code) (loc)->code) == REG)) |
5561 | { |
5562 | gcc_assert (REGNO (loc) < FIRST_PSEUDO_REGISTER)((void)(!((rhs_regno(loc)) < 76) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5562, __FUNCTION__), 0 : 0)); |
5563 | |
5564 | if (loc == cfa_base_rtx) |
5565 | return MO_CLOBBER; |
5566 | expr = REG_EXPR (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->decl); |
5567 | |
5568 | if (!expr) |
5569 | return MO_USE_NO_VAR; |
5570 | else if (target_for_debug_bind (var_debug_decl (expr))) |
5571 | return MO_CLOBBER; |
5572 | else if (track_loc_p (loc, expr, REG_OFFSET (loc)(((&(loc)->u.reg)->attrs) == 0 ? 0 : ((&(loc)-> u.reg)->attrs)->offset), |
5573 | false, modep, NULLnullptr)) |
5574 | return MO_USE; |
5575 | else |
5576 | return MO_USE_NO_VAR; |
5577 | } |
5578 | else if (MEM_P (loc)(((enum rtx_code) (loc)->code) == MEM)) |
5579 | { |
5580 | expr = MEM_EXPR (loc)(get_mem_attrs (loc)->expr); |
5581 | |
5582 | if (!expr) |
5583 | return MO_CLOBBER; |
5584 | else if (target_for_debug_bind (var_debug_decl (expr))) |
5585 | return MO_CLOBBER; |
5586 | else if (track_loc_p (loc, expr, int_mem_offset (loc), |
5587 | false, modep, NULLnullptr) |
5588 | /* Multi-part variables shouldn't refer to one-part |
5589 | variable names such as VALUEs (never happens) or |
5590 | DEBUG_EXPRs (only happens in the presence of debug |
5591 | insns). */ |
5592 | && (!MAY_HAVE_DEBUG_BIND_INSNSglobal_options.x_flag_var_tracking_assignments |
5593 | || !rtx_debug_expr_p (XEXP (loc, 0)(((loc)->u.fld[0]).rt_rtx)))) |
5594 | return MO_USE; |
5595 | else |
5596 | return MO_CLOBBER; |
5597 | } |
5598 | |
5599 | return MO_CLOBBER; |
5600 | } |
5601 | |
5602 | /* Log to OUT information about micro-operation MOPT involving X in |
5603 | INSN of BB. */ |
5604 | |
5605 | static inline void |
5606 | log_op_type (rtx x, basic_block bb, rtx_insn *insn, |
5607 | enum micro_operation_type mopt, FILE *out) |
5608 | { |
5609 | fprintf (out, "bb %i op %i insn %i %s ", |
5610 | bb->index, VTI (bb)((variable_tracking_info *) (bb)->aux)->mos.length (), |
5611 | INSN_UID (insn), micro_operation_type_name[mopt]); |
5612 | print_inline_rtx (out, x, 2); |
5613 | fputc ('\n', out); |
5614 | } |
5615 | |
5616 | /* Tell whether the CONCAT used to holds a VALUE and its location |
5617 | needs value resolution, i.e., an attempt of mapping the location |
5618 | back to other incoming values. */ |
5619 | #define VAL_NEEDS_RESOLUTION(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_NEEDS_RESOLUTION", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5619, __FUNCTION__); _rtx; })->volatil) \ |
5620 | (RTL_FLAG_CHECK1 ("VAL_NEEDS_RESOLUTION", (x), CONCAT)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_NEEDS_RESOLUTION", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5620, __FUNCTION__); _rtx; })->volatil) |
5621 | /* Whether the location in the CONCAT is a tracked expression, that |
5622 | should also be handled like a MO_USE. */ |
5623 | #define VAL_HOLDS_TRACK_EXPR(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_HOLDS_TRACK_EXPR", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5623, __FUNCTION__); _rtx; })->used) \ |
5624 | (RTL_FLAG_CHECK1 ("VAL_HOLDS_TRACK_EXPR", (x), CONCAT)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_HOLDS_TRACK_EXPR", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5624, __FUNCTION__); _rtx; })->used) |
5625 | /* Whether the location in the CONCAT should be handled like a MO_COPY |
5626 | as well. */ |
5627 | #define VAL_EXPR_IS_COPIED(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_EXPR_IS_COPIED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5627, __FUNCTION__); _rtx; })->jump) \ |
5628 | (RTL_FLAG_CHECK1 ("VAL_EXPR_IS_COPIED", (x), CONCAT)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_EXPR_IS_COPIED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5628, __FUNCTION__); _rtx; })->jump) |
5629 | /* Whether the location in the CONCAT should be handled like a |
5630 | MO_CLOBBER as well. */ |
5631 | #define VAL_EXPR_IS_CLOBBERED(x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_EXPR_IS_CLOBBERED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5631, __FUNCTION__); _rtx; })->unchanging) \ |
5632 | (RTL_FLAG_CHECK1 ("VAL_EXPR_IS_CLOBBERED", (x), CONCAT)__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ( "VAL_EXPR_IS_CLOBBERED", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5632, __FUNCTION__); _rtx; })->unchanging) |
5633 | |
5634 | /* All preserved VALUEs. */ |
5635 | static vec<rtx> preserved_values; |
5636 | |
5637 | /* Ensure VAL is preserved and remember it in a vector for vt_emit_notes. */ |
5638 | |
5639 | static void |
5640 | preserve_value (cselib_val *val) |
5641 | { |
5642 | cselib_preserve_value (val); |
5643 | preserved_values.safe_push (val->val_rtx); |
5644 | } |
5645 | |
5646 | /* Helper function for MO_VAL_LOC handling. Return non-zero if |
5647 | any rtxes not suitable for CONST use not replaced by VALUEs |
5648 | are discovered. */ |
5649 | |
5650 | static bool |
5651 | non_suitable_const (const_rtx x) |
5652 | { |
5653 | subrtx_iterator::array_type array; |
5654 | FOR_EACH_SUBRTX (iter, array, x, ALL)for (subrtx_iterator iter (array, x, rtx_all_subrtx_bounds); ! iter.at_end (); iter.next ()) |
5655 | { |
5656 | const_rtx x = *iter; |
5657 | switch (GET_CODE (x)((enum rtx_code) (x)->code)) |
5658 | { |
5659 | case REG: |
5660 | case DEBUG_EXPR: |
5661 | case PC: |
5662 | case SCRATCH: |
5663 | case ASM_INPUT: |
5664 | case ASM_OPERANDS: |
5665 | return true; |
5666 | case MEM: |
5667 | if (!MEM_READONLY_P (x)(__extension__ ({ __typeof ((x)) const _rtx = ((x)); if (((enum rtx_code) (_rtx)->code) != MEM) rtl_check_failed_flag ("MEM_READONLY_P" , _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5667, __FUNCTION__); _rtx; })->unchanging)) |
5668 | return true; |
5669 | break; |
5670 | default: |
5671 | break; |
5672 | } |
5673 | } |
5674 | return false; |
5675 | } |
5676 | |
5677 | /* Add uses (register and memory references) LOC which will be tracked |
5678 | to VTI (bb)->mos. */ |
5679 | |
5680 | static void |
5681 | add_uses (rtx loc, struct count_use_info *cui) |
5682 | { |
5683 | machine_mode mode = VOIDmode((void) 0, E_VOIDmode); |
5684 | enum micro_operation_type type = use_type (loc, cui, &mode); |
5685 | |
5686 | if (type != MO_CLOBBER) |
5687 | { |
5688 | basic_block bb = cui->bb; |
5689 | micro_operation mo; |
5690 | |
5691 | mo.type = type; |
5692 | mo.u.loc = type == MO_USE ? var_lowpart (mode, loc) : loc; |
5693 | mo.insn = cui->insn; |
5694 | |
5695 | if (type == MO_VAL_LOC) |
5696 | { |
5697 | rtx oloc = loc; |
5698 | rtx vloc = PAT_VAR_LOCATION_LOC (oloc)(((((oloc))->u.fld[1]).rt_rtx)); |
5699 | cselib_val *val; |
5700 | |
5701 | gcc_assert (cui->sets)((void)(!(cui->sets) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5701, __FUNCTION__), 0 : 0)); |
5702 | |
5703 | if (MEM_P (vloc)(((enum rtx_code) (vloc)->code) == MEM) |
5704 | && !REG_P (XEXP (vloc, 0))(((enum rtx_code) ((((vloc)->u.fld[0]).rt_rtx))->code) == REG) |
5705 | && !MEM_P (XEXP (vloc, 0))(((enum rtx_code) ((((vloc)->u.fld[0]).rt_rtx))->code) == MEM)) |
5706 | { |
5707 | rtx mloc = vloc; |
5708 | machine_mode address_mode = get_address_mode (mloc); |
5709 | cselib_val *val |
5710 | = cselib_lookup (XEXP (mloc, 0)(((mloc)->u.fld[0]).rt_rtx), address_mode, 0, |
5711 | GET_MODE (mloc)((machine_mode) (mloc)->mode)); |
5712 | |
5713 | if (val && !cselib_preserved_value_p (val)) |
5714 | preserve_value (val); |
5715 | } |
5716 | |
5717 | if (CONSTANT_P (vloc)((rtx_class[(int) (((enum rtx_code) (vloc)->code))]) == RTX_CONST_OBJ ) |
5718 | && (GET_CODE (vloc)((enum rtx_code) (vloc)->code) != CONST || non_suitable_const (vloc))) |
5719 | /* For constants don't look up any value. */; |
5720 | else if (!VAR_LOC_UNKNOWN_P (vloc)(((enum rtx_code) (vloc)->code) == CLOBBER && (((( vloc))->u.fld[0]).rt_rtx) == (const_int_rtx[64])) && !unsuitable_loc (vloc) |
5721 | && (val = find_use_val (vloc, GET_MODE (oloc)((machine_mode) (oloc)->mode), cui))) |
5722 | { |
5723 | machine_mode mode2; |
5724 | enum micro_operation_type type2; |
5725 | rtx nloc = NULLnullptr; |
5726 | bool resolvable = REG_P (vloc)(((enum rtx_code) (vloc)->code) == REG) || MEM_P (vloc)(((enum rtx_code) (vloc)->code) == MEM); |
5727 | |
5728 | if (resolvable) |
5729 | nloc = replace_expr_with_values (vloc); |
5730 | |
5731 | if (nloc) |
5732 | { |
5733 | oloc = shallow_copy_rtx (oloc); |
5734 | PAT_VAR_LOCATION_LOC (oloc)(((((oloc))->u.fld[1]).rt_rtx)) = nloc; |
5735 | } |
5736 | |
5737 | oloc = gen_rtx_CONCAT (mode, val->val_rtx, oloc)gen_rtx_fmt_ee_stat ((CONCAT), ((mode)), ((val->val_rtx)), ((oloc)) ); |
5738 | |
5739 | type2 = use_type (vloc, 0, &mode2); |
5740 | |
5741 | gcc_assert (type2 == MO_USE || type2 == MO_USE_NO_VAR((void)(!(type2 == MO_USE || type2 == MO_USE_NO_VAR || type2 == MO_CLOBBER) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5742, __FUNCTION__), 0 : 0)) |
5742 | || type2 == MO_CLOBBER)((void)(!(type2 == MO_USE || type2 == MO_USE_NO_VAR || type2 == MO_CLOBBER) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5742, __FUNCTION__), 0 : 0)); |
5743 | |
5744 | if (type2 == MO_CLOBBER |
5745 | && !cselib_preserved_value_p (val)) |
5746 | { |
5747 | VAL_NEEDS_RESOLUTION (oloc)(__extension__ ({ __typeof ((oloc)) const _rtx = ((oloc)); if (((enum rtx_code) (_rtx)->code) != CONCAT) rtl_check_failed_flag ("VAL_NEEDS_RESOLUTION", _rtx, "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5747, __FUNCTION__); _rtx; })->volatil) = resolvable; |
5748 | preserve_value (val); |
5749 | } |
5750 | } |
5751 | else if (!VAR_LOC_UNKNOWN_P (vloc)(((enum rtx_code) (vloc)->code) == CLOBBER && (((( vloc))->u.fld[0]).rt_rtx) == (const_int_rtx[64]))) |
5752 | { |
5753 | oloc = shallow_copy_rtx (oloc); |
5754 | PAT_VAR_LOCATION_LOC (oloc)(((((oloc))->u.fld[1]).rt_rtx)) = gen_rtx_UNKNOWN_VAR_LOC ()(gen_rtx_fmt_e_stat ((CLOBBER), ((((void) 0, E_VOIDmode))), ( ((const_int_rtx[64]))) )); |
5755 | } |
5756 | |
5757 | mo.u.loc = oloc; |
5758 | } |
5759 | else if (type == MO_VAL_USE) |
5760 | { |
5761 | machine_mode mode2 = VOIDmode((void) 0, E_VOIDmode); |
5762 | enum micro_operation_type type2; |
5763 | cselib_val *val = find_use_val (loc, GET_MODE (loc)((machine_mode) (loc)->mode), cui); |
5764 | rtx vloc, oloc = loc, nloc; |
5765 | |
5766 | gcc_assert (cui->sets)((void)(!(cui->sets) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5766, __FUNCTION__), 0 : 0)); |
5767 | |
5768 | if (MEM_P (oloc)(((enum rtx_code) (oloc)->code) == MEM) |
5769 | && !REG_P (XEXP (oloc, 0))(((enum rtx_code) ((((oloc)->u.fld[0]).rt_rtx))->code) == REG) |
5770 | && !MEM_P (XEXP (oloc, 0))(((enum rtx_code) ((((oloc)->u.fld[0]).rt_rtx))->code) == MEM)) |
5771 | { |
5772 | rtx mloc = oloc; |
5773 | machine_mode address_mode = get_address_mode (mloc); |
5774 | cselib_val *val |
5775 | = cselib_lookup (XEXP (mloc, 0)(((mloc)->u.fld[0]).rt_rtx), address_mode, 0, |
5776 | GET_MODE (mloc)((machine_mode) (mloc)->mode)); |
5777 | |
5778 | if (val && !cselib_preserved_value_p (val)) |
5779 | preserve_value (val); |
5780 | } |
5781 | |
5782 | type2 = use_type (loc, 0, &mode2); |
5783 | |
5784 | gcc_assert (type2 == MO_USE || type2 == MO_USE_NO_VAR((void)(!(type2 == MO_USE || type2 == MO_USE_NO_VAR || type2 == MO_CLOBBER) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5785, __FUNCTION__), 0 : 0)) |
5785 | || type2 == MO_CLOBBER)((void)(!(type2 == MO_USE || type2 == MO_USE_NO_VAR || type2 == MO_CLOBBER) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/var-tracking.cc" , 5785, __FUNCTION__), 0 : 0)); |
5786 | |