annotate gcc/ipa-icf.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Interprocedural Identical Code Folding pass
kono
parents:
diff changeset
2 Copyright (C) 2014-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 This file is part of GCC.
kono
parents:
diff changeset
7
kono
parents:
diff changeset
8 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
9 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
10 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
11 version.
kono
parents:
diff changeset
12
kono
parents:
diff changeset
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
16 for more details.
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
19 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
20 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
21
kono
parents:
diff changeset
22 /* Interprocedural Identical Code Folding for functions and
kono
parents:
diff changeset
23 read-only variables.
kono
parents:
diff changeset
24
kono
parents:
diff changeset
25 The goal of this transformation is to discover functions and read-only
kono
parents:
diff changeset
26 variables which do have exactly the same semantics.
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28 In case of functions,
kono
parents:
diff changeset
29 we could either create a virtual clone or do a simple function wrapper
kono
parents:
diff changeset
30 that will call equivalent function. If the function is just locally visible,
kono
parents:
diff changeset
31 all function calls can be redirected. For read-only variables, we create
kono
parents:
diff changeset
32 aliases if possible.
kono
parents:
diff changeset
33
kono
parents:
diff changeset
34 Optimization pass arranges as follows:
kono
parents:
diff changeset
35 1) All functions and read-only variables are visited and internal
kono
parents:
diff changeset
36 data structure, either sem_function or sem_variables is created.
kono
parents:
diff changeset
37 2) For every symbol from the previous step, VAR_DECL and FUNCTION_DECL are
kono
parents:
diff changeset
38 saved and matched to corresponding sem_items.
kono
parents:
diff changeset
39 3) These declaration are ignored for equality check and are solved
kono
parents:
diff changeset
40 by Value Numbering algorithm published by Alpert, Zadeck in 1992.
kono
parents:
diff changeset
41 4) We compute hash value for each symbol.
kono
parents:
diff changeset
42 5) Congruence classes are created based on hash value. If hash value are
kono
parents:
diff changeset
43 equal, equals function is called and symbols are deeply compared.
kono
parents:
diff changeset
44 We must prove that all SSA names, declarations and other items
kono
parents:
diff changeset
45 correspond.
kono
parents:
diff changeset
46 6) Value Numbering is executed for these classes. At the end of the process
kono
parents:
diff changeset
47 all symbol members in remaining classes can be merged.
kono
parents:
diff changeset
48 7) Merge operation creates alias in case of read-only variables. For
kono
parents:
diff changeset
49 callgraph node, we must decide if we can redirect local calls,
kono
parents:
diff changeset
50 create an alias or a thunk.
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 */
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 #include "config.h"
kono
parents:
diff changeset
55 #define INCLUDE_LIST
kono
parents:
diff changeset
56 #include "system.h"
kono
parents:
diff changeset
57 #include "coretypes.h"
kono
parents:
diff changeset
58 #include "backend.h"
kono
parents:
diff changeset
59 #include "target.h"
kono
parents:
diff changeset
60 #include "rtl.h"
kono
parents:
diff changeset
61 #include "tree.h"
kono
parents:
diff changeset
62 #include "gimple.h"
kono
parents:
diff changeset
63 #include "alloc-pool.h"
kono
parents:
diff changeset
64 #include "tree-pass.h"
kono
parents:
diff changeset
65 #include "ssa.h"
kono
parents:
diff changeset
66 #include "cgraph.h"
kono
parents:
diff changeset
67 #include "coverage.h"
kono
parents:
diff changeset
68 #include "gimple-pretty-print.h"
kono
parents:
diff changeset
69 #include "data-streamer.h"
kono
parents:
diff changeset
70 #include "fold-const.h"
kono
parents:
diff changeset
71 #include "calls.h"
kono
parents:
diff changeset
72 #include "varasm.h"
kono
parents:
diff changeset
73 #include "gimple-iterator.h"
kono
parents:
diff changeset
74 #include "tree-cfg.h"
kono
parents:
diff changeset
75 #include "symbol-summary.h"
kono
parents:
diff changeset
76 #include "ipa-prop.h"
kono
parents:
diff changeset
77 #include "ipa-fnsummary.h"
kono
parents:
diff changeset
78 #include "except.h"
kono
parents:
diff changeset
79 #include "attribs.h"
kono
parents:
diff changeset
80 #include "print-tree.h"
kono
parents:
diff changeset
81 #include "ipa-utils.h"
kono
parents:
diff changeset
82 #include "ipa-icf-gimple.h"
kono
parents:
diff changeset
83 #include "ipa-icf.h"
kono
parents:
diff changeset
84 #include "stor-layout.h"
kono
parents:
diff changeset
85 #include "dbgcnt.h"
kono
parents:
diff changeset
86
kono
parents:
diff changeset
87 using namespace ipa_icf_gimple;
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 namespace ipa_icf {
kono
parents:
diff changeset
90
kono
parents:
diff changeset
91 /* Initialization and computation of symtab node hash, there data
kono
parents:
diff changeset
92 are propagated later on. */
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 static sem_item_optimizer *optimizer = NULL;
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 /* Constructor. */
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 symbol_compare_collection::symbol_compare_collection (symtab_node *node)
kono
parents:
diff changeset
99 {
kono
parents:
diff changeset
100 m_references.create (0);
kono
parents:
diff changeset
101 m_interposables.create (0);
kono
parents:
diff changeset
102
kono
parents:
diff changeset
103 ipa_ref *ref;
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 if (is_a <varpool_node *> (node) && DECL_VIRTUAL_P (node->decl))
kono
parents:
diff changeset
106 return;
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 for (unsigned i = 0; node->iterate_reference (i, ref); i++)
kono
parents:
diff changeset
109 {
kono
parents:
diff changeset
110 if (ref->address_matters_p ())
kono
parents:
diff changeset
111 m_references.safe_push (ref->referred);
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 if (ref->referred->get_availability () <= AVAIL_INTERPOSABLE)
kono
parents:
diff changeset
114 {
kono
parents:
diff changeset
115 if (ref->address_matters_p ())
kono
parents:
diff changeset
116 m_references.safe_push (ref->referred);
kono
parents:
diff changeset
117 else
kono
parents:
diff changeset
118 m_interposables.safe_push (ref->referred);
kono
parents:
diff changeset
119 }
kono
parents:
diff changeset
120 }
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 if (is_a <cgraph_node *> (node))
kono
parents:
diff changeset
123 {
kono
parents:
diff changeset
124 cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
kono
parents:
diff changeset
127 if (e->callee->get_availability () <= AVAIL_INTERPOSABLE)
kono
parents:
diff changeset
128 m_interposables.safe_push (e->callee);
kono
parents:
diff changeset
129 }
kono
parents:
diff changeset
130 }
kono
parents:
diff changeset
131
kono
parents:
diff changeset
132 /* Constructor for key value pair, where _ITEM is key and _INDEX is a target. */
kono
parents:
diff changeset
133
kono
parents:
diff changeset
134 sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index)
kono
parents:
diff changeset
135 : item (_item), index (_index)
kono
parents:
diff changeset
136 {
kono
parents:
diff changeset
137 }
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 sem_item::sem_item (sem_item_type _type, bitmap_obstack *stack)
kono
parents:
diff changeset
140 : type (_type), m_hash (-1), m_hash_set (false)
kono
parents:
diff changeset
141 {
kono
parents:
diff changeset
142 setup (stack);
kono
parents:
diff changeset
143 }
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 sem_item::sem_item (sem_item_type _type, symtab_node *_node,
kono
parents:
diff changeset
146 bitmap_obstack *stack)
kono
parents:
diff changeset
147 : type (_type), node (_node), m_hash (-1), m_hash_set (false)
kono
parents:
diff changeset
148 {
kono
parents:
diff changeset
149 decl = node->decl;
kono
parents:
diff changeset
150 setup (stack);
kono
parents:
diff changeset
151 }
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 /* Add reference to a semantic TARGET. */
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 void
kono
parents:
diff changeset
156 sem_item::add_reference (sem_item *target)
kono
parents:
diff changeset
157 {
kono
parents:
diff changeset
158 refs.safe_push (target);
kono
parents:
diff changeset
159 unsigned index = refs.length ();
kono
parents:
diff changeset
160 target->usages.safe_push (new sem_usage_pair(this, index));
kono
parents:
diff changeset
161 bitmap_set_bit (target->usage_index_bitmap, index);
kono
parents:
diff changeset
162 refs_set.add (target->node);
kono
parents:
diff changeset
163 }
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 /* Initialize internal data structures. Bitmap STACK is used for
kono
parents:
diff changeset
166 bitmap memory allocation process. */
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 void
kono
parents:
diff changeset
169 sem_item::setup (bitmap_obstack *stack)
kono
parents:
diff changeset
170 {
kono
parents:
diff changeset
171 gcc_checking_assert (node);
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 refs.create (0);
kono
parents:
diff changeset
174 tree_refs.create (0);
kono
parents:
diff changeset
175 usages.create (0);
kono
parents:
diff changeset
176 usage_index_bitmap = BITMAP_ALLOC (stack);
kono
parents:
diff changeset
177 }
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 sem_item::~sem_item ()
kono
parents:
diff changeset
180 {
kono
parents:
diff changeset
181 for (unsigned i = 0; i < usages.length (); i++)
kono
parents:
diff changeset
182 delete usages[i];
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 refs.release ();
kono
parents:
diff changeset
185 tree_refs.release ();
kono
parents:
diff changeset
186 usages.release ();
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 BITMAP_FREE (usage_index_bitmap);
kono
parents:
diff changeset
189 }
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 /* Dump function for debugging purpose. */
kono
parents:
diff changeset
192
kono
parents:
diff changeset
193 DEBUG_FUNCTION void
kono
parents:
diff changeset
194 sem_item::dump (void)
kono
parents:
diff changeset
195 {
kono
parents:
diff changeset
196 if (dump_file)
kono
parents:
diff changeset
197 {
kono
parents:
diff changeset
198 fprintf (dump_file, "[%s] %s (tree:%p)\n", type == FUNC ? "func" : "var",
kono
parents:
diff changeset
199 node->dump_name (), (void *) node->decl);
kono
parents:
diff changeset
200 fprintf (dump_file, " hash: %u\n", get_hash ());
kono
parents:
diff changeset
201 fprintf (dump_file, " references: ");
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 for (unsigned i = 0; i < refs.length (); i++)
kono
parents:
diff changeset
204 fprintf (dump_file, "%s%s ", refs[i]->node->name (),
kono
parents:
diff changeset
205 i < refs.length() - 1 ? "," : "");
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 fprintf (dump_file, "\n");
kono
parents:
diff changeset
208 }
kono
parents:
diff changeset
209 }
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 /* Return true if target supports alias symbols. */
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 bool
kono
parents:
diff changeset
214 sem_item::target_supports_symbol_aliases_p (void)
kono
parents:
diff changeset
215 {
kono
parents:
diff changeset
216 #if !defined (ASM_OUTPUT_DEF) || (!defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL))
kono
parents:
diff changeset
217 return false;
kono
parents:
diff changeset
218 #else
kono
parents:
diff changeset
219 return true;
kono
parents:
diff changeset
220 #endif
kono
parents:
diff changeset
221 }
kono
parents:
diff changeset
222
kono
parents:
diff changeset
223 void sem_item::set_hash (hashval_t hash)
kono
parents:
diff changeset
224 {
kono
parents:
diff changeset
225 m_hash = hash;
kono
parents:
diff changeset
226 m_hash_set = true;
kono
parents:
diff changeset
227 }
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 /* Semantic function constructor that uses STACK as bitmap memory stack. */
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 sem_function::sem_function (bitmap_obstack *stack)
kono
parents:
diff changeset
232 : sem_item (FUNC, stack), m_checker (NULL), m_compared_func (NULL)
kono
parents:
diff changeset
233 {
kono
parents:
diff changeset
234 bb_sizes.create (0);
kono
parents:
diff changeset
235 bb_sorted.create (0);
kono
parents:
diff changeset
236 }
kono
parents:
diff changeset
237
kono
parents:
diff changeset
238 sem_function::sem_function (cgraph_node *node, bitmap_obstack *stack)
kono
parents:
diff changeset
239 : sem_item (FUNC, node, stack), m_checker (NULL), m_compared_func (NULL)
kono
parents:
diff changeset
240 {
kono
parents:
diff changeset
241 bb_sizes.create (0);
kono
parents:
diff changeset
242 bb_sorted.create (0);
kono
parents:
diff changeset
243 }
kono
parents:
diff changeset
244
kono
parents:
diff changeset
245 sem_function::~sem_function ()
kono
parents:
diff changeset
246 {
kono
parents:
diff changeset
247 for (unsigned i = 0; i < bb_sorted.length (); i++)
kono
parents:
diff changeset
248 delete (bb_sorted[i]);
kono
parents:
diff changeset
249
kono
parents:
diff changeset
250 bb_sizes.release ();
kono
parents:
diff changeset
251 bb_sorted.release ();
kono
parents:
diff changeset
252 }
kono
parents:
diff changeset
253
kono
parents:
diff changeset
254 /* Calculates hash value based on a BASIC_BLOCK. */
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 hashval_t
kono
parents:
diff changeset
257 sem_function::get_bb_hash (const sem_bb *basic_block)
kono
parents:
diff changeset
258 {
kono
parents:
diff changeset
259 inchash::hash hstate;
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 hstate.add_int (basic_block->nondbg_stmt_count);
kono
parents:
diff changeset
262 hstate.add_int (basic_block->edge_count);
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 return hstate.end ();
kono
parents:
diff changeset
265 }
kono
parents:
diff changeset
266
kono
parents:
diff changeset
267 /* References independent hash function. */
kono
parents:
diff changeset
268
kono
parents:
diff changeset
269 hashval_t
kono
parents:
diff changeset
270 sem_function::get_hash (void)
kono
parents:
diff changeset
271 {
kono
parents:
diff changeset
272 if (!m_hash_set)
kono
parents:
diff changeset
273 {
kono
parents:
diff changeset
274 inchash::hash hstate;
kono
parents:
diff changeset
275 hstate.add_int (177454); /* Random number for function type. */
kono
parents:
diff changeset
276
kono
parents:
diff changeset
277 hstate.add_int (arg_count);
kono
parents:
diff changeset
278 hstate.add_int (cfg_checksum);
kono
parents:
diff changeset
279 hstate.add_int (gcode_hash);
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 for (unsigned i = 0; i < bb_sorted.length (); i++)
kono
parents:
diff changeset
282 hstate.merge_hash (get_bb_hash (bb_sorted[i]));
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 for (unsigned i = 0; i < bb_sizes.length (); i++)
kono
parents:
diff changeset
285 hstate.add_int (bb_sizes[i]);
kono
parents:
diff changeset
286
kono
parents:
diff changeset
287 /* Add common features of declaration itself. */
kono
parents:
diff changeset
288 if (DECL_FUNCTION_SPECIFIC_TARGET (decl))
kono
parents:
diff changeset
289 hstate.add_hwi
kono
parents:
diff changeset
290 (cl_target_option_hash
kono
parents:
diff changeset
291 (TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (decl))));
kono
parents:
diff changeset
292 if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))
kono
parents:
diff changeset
293 hstate.add_hwi
kono
parents:
diff changeset
294 (cl_optimization_hash
kono
parents:
diff changeset
295 (TREE_OPTIMIZATION (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))));
kono
parents:
diff changeset
296 hstate.add_flag (DECL_CXX_CONSTRUCTOR_P (decl));
kono
parents:
diff changeset
297 hstate.add_flag (DECL_CXX_DESTRUCTOR_P (decl));
kono
parents:
diff changeset
298
kono
parents:
diff changeset
299 set_hash (hstate.end ());
kono
parents:
diff changeset
300 }
kono
parents:
diff changeset
301
kono
parents:
diff changeset
302 return m_hash;
kono
parents:
diff changeset
303 }
kono
parents:
diff changeset
304
kono
parents:
diff changeset
305 /* Return ture if A1 and A2 represent equivalent function attribute lists.
kono
parents:
diff changeset
306 Based on comp_type_attributes. */
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 bool
kono
parents:
diff changeset
309 sem_item::compare_attributes (const_tree a1, const_tree a2)
kono
parents:
diff changeset
310 {
kono
parents:
diff changeset
311 const_tree a;
kono
parents:
diff changeset
312 if (a1 == a2)
kono
parents:
diff changeset
313 return true;
kono
parents:
diff changeset
314 for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
kono
parents:
diff changeset
315 {
kono
parents:
diff changeset
316 const struct attribute_spec *as;
kono
parents:
diff changeset
317 const_tree attr;
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 as = lookup_attribute_spec (get_attribute_name (a));
kono
parents:
diff changeset
320 /* TODO: We can introduce as->affects_decl_identity
kono
parents:
diff changeset
321 and as->affects_decl_reference_identity if attribute mismatch
kono
parents:
diff changeset
322 gets a common reason to give up on merging. It may not be worth
kono
parents:
diff changeset
323 the effort.
kono
parents:
diff changeset
324 For example returns_nonnull affects only references, while
kono
parents:
diff changeset
325 optimize attribute can be ignored because it is already lowered
kono
parents:
diff changeset
326 into flags representation and compared separately. */
kono
parents:
diff changeset
327 if (!as)
kono
parents:
diff changeset
328 continue;
kono
parents:
diff changeset
329
kono
parents:
diff changeset
330 attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
kono
parents:
diff changeset
331 if (!attr || !attribute_value_equal (a, attr))
kono
parents:
diff changeset
332 break;
kono
parents:
diff changeset
333 }
kono
parents:
diff changeset
334 if (!a)
kono
parents:
diff changeset
335 {
kono
parents:
diff changeset
336 for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
kono
parents:
diff changeset
337 {
kono
parents:
diff changeset
338 const struct attribute_spec *as;
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 as = lookup_attribute_spec (get_attribute_name (a));
kono
parents:
diff changeset
341 if (!as)
kono
parents:
diff changeset
342 continue;
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
kono
parents:
diff changeset
345 break;
kono
parents:
diff changeset
346 /* We don't need to compare trees again, as we did this
kono
parents:
diff changeset
347 already in first loop. */
kono
parents:
diff changeset
348 }
kono
parents:
diff changeset
349 if (!a)
kono
parents:
diff changeset
350 return true;
kono
parents:
diff changeset
351 }
kono
parents:
diff changeset
352 /* TODO: As in comp_type_attributes we may want to introduce target hook. */
kono
parents:
diff changeset
353 return false;
kono
parents:
diff changeset
354 }
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 /* Compare properties of symbols N1 and N2 that does not affect semantics of
kono
parents:
diff changeset
357 symbol itself but affects semantics of its references from USED_BY (which
kono
parents:
diff changeset
358 may be NULL if it is unknown). If comparsion is false, symbols
kono
parents:
diff changeset
359 can still be merged but any symbols referring them can't.
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 If ADDRESS is true, do extra checking needed for IPA_REF_ADDR.
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363 TODO: We can also split attributes to those that determine codegen of
kono
parents:
diff changeset
364 a function body/variable constructor itself and those that are used when
kono
parents:
diff changeset
365 referring to it. */
kono
parents:
diff changeset
366
kono
parents:
diff changeset
367 bool
kono
parents:
diff changeset
368 sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
kono
parents:
diff changeset
369 symtab_node *n1,
kono
parents:
diff changeset
370 symtab_node *n2,
kono
parents:
diff changeset
371 bool address)
kono
parents:
diff changeset
372 {
kono
parents:
diff changeset
373 if (is_a <cgraph_node *> (n1))
kono
parents:
diff changeset
374 {
kono
parents:
diff changeset
375 /* Inline properties matters: we do now want to merge uses of inline
kono
parents:
diff changeset
376 function to uses of normal function because inline hint would be lost.
kono
parents:
diff changeset
377 We however can merge inline function to noinline because the alias
kono
parents:
diff changeset
378 will keep its DECL_DECLARED_INLINE flag.
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 Also ignore inline flag when optimizing for size or when function
kono
parents:
diff changeset
381 is known to not be inlinable.
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 TODO: the optimize_size checks can also be assumed to be true if
kono
parents:
diff changeset
384 unit has no !optimize_size functions. */
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 if ((!used_by || address || !is_a <cgraph_node *> (used_by)
kono
parents:
diff changeset
387 || !opt_for_fn (used_by->decl, optimize_size))
kono
parents:
diff changeset
388 && !opt_for_fn (n1->decl, optimize_size)
kono
parents:
diff changeset
389 && n1->get_availability () > AVAIL_INTERPOSABLE
kono
parents:
diff changeset
390 && (!DECL_UNINLINABLE (n1->decl) || !DECL_UNINLINABLE (n2->decl)))
kono
parents:
diff changeset
391 {
kono
parents:
diff changeset
392 if (DECL_DISREGARD_INLINE_LIMITS (n1->decl)
kono
parents:
diff changeset
393 != DECL_DISREGARD_INLINE_LIMITS (n2->decl))
kono
parents:
diff changeset
394 return return_false_with_msg
kono
parents:
diff changeset
395 ("DECL_DISREGARD_INLINE_LIMITS are different");
kono
parents:
diff changeset
396
kono
parents:
diff changeset
397 if (DECL_DECLARED_INLINE_P (n1->decl)
kono
parents:
diff changeset
398 != DECL_DECLARED_INLINE_P (n2->decl))
kono
parents:
diff changeset
399 return return_false_with_msg ("inline attributes are different");
kono
parents:
diff changeset
400 }
kono
parents:
diff changeset
401
kono
parents:
diff changeset
402 if (DECL_IS_OPERATOR_NEW (n1->decl)
kono
parents:
diff changeset
403 != DECL_IS_OPERATOR_NEW (n2->decl))
kono
parents:
diff changeset
404 return return_false_with_msg ("operator new flags are different");
kono
parents:
diff changeset
405 }
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 /* Merging two definitions with a reference to equivalent vtables, but
kono
parents:
diff changeset
408 belonging to a different type may result in ipa-polymorphic-call analysis
kono
parents:
diff changeset
409 giving a wrong answer about the dynamic type of instance. */
kono
parents:
diff changeset
410 if (is_a <varpool_node *> (n1))
kono
parents:
diff changeset
411 {
kono
parents:
diff changeset
412 if ((DECL_VIRTUAL_P (n1->decl) || DECL_VIRTUAL_P (n2->decl))
kono
parents:
diff changeset
413 && (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl)
kono
parents:
diff changeset
414 || !types_must_be_same_for_odr (DECL_CONTEXT (n1->decl),
kono
parents:
diff changeset
415 DECL_CONTEXT (n2->decl)))
kono
parents:
diff changeset
416 && (!used_by || !is_a <cgraph_node *> (used_by) || address
kono
parents:
diff changeset
417 || opt_for_fn (used_by->decl, flag_devirtualize)))
kono
parents:
diff changeset
418 return return_false_with_msg
kono
parents:
diff changeset
419 ("references to virtual tables can not be merged");
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 if (address && DECL_ALIGN (n1->decl) != DECL_ALIGN (n2->decl))
kono
parents:
diff changeset
422 return return_false_with_msg ("alignment mismatch");
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424 /* For functions we compare attributes in equals_wpa, because we do
kono
parents:
diff changeset
425 not know what attributes may cause codegen differences, but for
kono
parents:
diff changeset
426 variables just compare attributes for references - the codegen
kono
parents:
diff changeset
427 for constructors is affected only by those attributes that we lower
kono
parents:
diff changeset
428 to explicit representation (such as DECL_ALIGN or DECL_SECTION). */
kono
parents:
diff changeset
429 if (!compare_attributes (DECL_ATTRIBUTES (n1->decl),
kono
parents:
diff changeset
430 DECL_ATTRIBUTES (n2->decl)))
kono
parents:
diff changeset
431 return return_false_with_msg ("different var decl attributes");
kono
parents:
diff changeset
432 if (comp_type_attributes (TREE_TYPE (n1->decl),
kono
parents:
diff changeset
433 TREE_TYPE (n2->decl)) != 1)
kono
parents:
diff changeset
434 return return_false_with_msg ("different var type attributes");
kono
parents:
diff changeset
435 }
kono
parents:
diff changeset
436
kono
parents:
diff changeset
437 /* When matching virtual tables, be sure to also match information
kono
parents:
diff changeset
438 relevant for polymorphic call analysis. */
kono
parents:
diff changeset
439 if (used_by && is_a <varpool_node *> (used_by)
kono
parents:
diff changeset
440 && DECL_VIRTUAL_P (used_by->decl))
kono
parents:
diff changeset
441 {
kono
parents:
diff changeset
442 if (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl))
kono
parents:
diff changeset
443 return return_false_with_msg ("virtual flag mismatch");
kono
parents:
diff changeset
444 if (DECL_VIRTUAL_P (n1->decl) && is_a <cgraph_node *> (n1)
kono
parents:
diff changeset
445 && (DECL_FINAL_P (n1->decl) != DECL_FINAL_P (n2->decl)))
kono
parents:
diff changeset
446 return return_false_with_msg ("final flag mismatch");
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448 return true;
kono
parents:
diff changeset
449 }
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 /* Hash properties that are compared by compare_referenced_symbol_properties. */
kono
parents:
diff changeset
452
kono
parents:
diff changeset
453 void
kono
parents:
diff changeset
454 sem_item::hash_referenced_symbol_properties (symtab_node *ref,
kono
parents:
diff changeset
455 inchash::hash &hstate,
kono
parents:
diff changeset
456 bool address)
kono
parents:
diff changeset
457 {
kono
parents:
diff changeset
458 if (is_a <cgraph_node *> (ref))
kono
parents:
diff changeset
459 {
kono
parents:
diff changeset
460 if ((type != FUNC || address || !opt_for_fn (decl, optimize_size))
kono
parents:
diff changeset
461 && !opt_for_fn (ref->decl, optimize_size)
kono
parents:
diff changeset
462 && !DECL_UNINLINABLE (ref->decl))
kono
parents:
diff changeset
463 {
kono
parents:
diff changeset
464 hstate.add_flag (DECL_DISREGARD_INLINE_LIMITS (ref->decl));
kono
parents:
diff changeset
465 hstate.add_flag (DECL_DECLARED_INLINE_P (ref->decl));
kono
parents:
diff changeset
466 }
kono
parents:
diff changeset
467 hstate.add_flag (DECL_IS_OPERATOR_NEW (ref->decl));
kono
parents:
diff changeset
468 }
kono
parents:
diff changeset
469 else if (is_a <varpool_node *> (ref))
kono
parents:
diff changeset
470 {
kono
parents:
diff changeset
471 hstate.add_flag (DECL_VIRTUAL_P (ref->decl));
kono
parents:
diff changeset
472 if (address)
kono
parents:
diff changeset
473 hstate.add_int (DECL_ALIGN (ref->decl));
kono
parents:
diff changeset
474 }
kono
parents:
diff changeset
475 }
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477
kono
parents:
diff changeset
478 /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs
kono
parents:
diff changeset
479 point to a same function. Comparison can be skipped if IGNORED_NODES
kono
parents:
diff changeset
480 contains these nodes. ADDRESS indicate if address is taken. */
kono
parents:
diff changeset
481
kono
parents:
diff changeset
482 bool
kono
parents:
diff changeset
483 sem_item::compare_symbol_references (
kono
parents:
diff changeset
484 hash_map <symtab_node *, sem_item *> &ignored_nodes,
kono
parents:
diff changeset
485 symtab_node *n1, symtab_node *n2, bool address)
kono
parents:
diff changeset
486 {
kono
parents:
diff changeset
487 enum availability avail1, avail2;
kono
parents:
diff changeset
488
kono
parents:
diff changeset
489 if (n1 == n2)
kono
parents:
diff changeset
490 return true;
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 /* Never match variable and function. */
kono
parents:
diff changeset
493 if (is_a <varpool_node *> (n1) != is_a <varpool_node *> (n2))
kono
parents:
diff changeset
494 return false;
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 if (!compare_referenced_symbol_properties (node, n1, n2, address))
kono
parents:
diff changeset
497 return false;
kono
parents:
diff changeset
498 if (address && n1->equal_address_to (n2) == 1)
kono
parents:
diff changeset
499 return true;
kono
parents:
diff changeset
500 if (!address && n1->semantically_equivalent_p (n2))
kono
parents:
diff changeset
501 return true;
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 n1 = n1->ultimate_alias_target (&avail1);
kono
parents:
diff changeset
504 n2 = n2->ultimate_alias_target (&avail2);
kono
parents:
diff changeset
505
kono
parents:
diff changeset
506 if (avail1 > AVAIL_INTERPOSABLE && ignored_nodes.get (n1)
kono
parents:
diff changeset
507 && avail2 > AVAIL_INTERPOSABLE && ignored_nodes.get (n2))
kono
parents:
diff changeset
508 return true;
kono
parents:
diff changeset
509
kono
parents:
diff changeset
510 return return_false_with_msg ("different references");
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 /* If cgraph edges E1 and E2 are indirect calls, verify that
kono
parents:
diff changeset
514 ECF flags are the same. */
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 bool sem_function::compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2)
kono
parents:
diff changeset
517 {
kono
parents:
diff changeset
518 if (e1->indirect_info && e2->indirect_info)
kono
parents:
diff changeset
519 {
kono
parents:
diff changeset
520 int e1_flags = e1->indirect_info->ecf_flags;
kono
parents:
diff changeset
521 int e2_flags = e2->indirect_info->ecf_flags;
kono
parents:
diff changeset
522
kono
parents:
diff changeset
523 if (e1_flags != e2_flags)
kono
parents:
diff changeset
524 return return_false_with_msg ("ICF flags are different");
kono
parents:
diff changeset
525 }
kono
parents:
diff changeset
526 else if (e1->indirect_info || e2->indirect_info)
kono
parents:
diff changeset
527 return false;
kono
parents:
diff changeset
528
kono
parents:
diff changeset
529 return true;
kono
parents:
diff changeset
530 }
kono
parents:
diff changeset
531
kono
parents:
diff changeset
532 /* Return true if parameter I may be used. */
kono
parents:
diff changeset
533
kono
parents:
diff changeset
534 bool
kono
parents:
diff changeset
535 sem_function::param_used_p (unsigned int i)
kono
parents:
diff changeset
536 {
kono
parents:
diff changeset
537 if (ipa_node_params_sum == NULL)
kono
parents:
diff changeset
538 return true;
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 struct ipa_node_params *parms_info = IPA_NODE_REF (get_node ());
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 if (vec_safe_length (parms_info->descriptors) <= i)
kono
parents:
diff changeset
543 return true;
kono
parents:
diff changeset
544
kono
parents:
diff changeset
545 return ipa_is_param_used (IPA_NODE_REF (get_node ()), i);
kono
parents:
diff changeset
546 }
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 /* Perform additional check needed to match types function parameters that are
kono
parents:
diff changeset
549 used. Unlike for normal decls it matters if type is TYPE_RESTRICT and we
kono
parents:
diff changeset
550 make an assumption that REFERENCE_TYPE parameters are always non-NULL. */
kono
parents:
diff changeset
551
kono
parents:
diff changeset
552 bool
kono
parents:
diff changeset
553 sem_function::compatible_parm_types_p (tree parm1, tree parm2)
kono
parents:
diff changeset
554 {
kono
parents:
diff changeset
555 /* Be sure that parameters are TBAA compatible. */
kono
parents:
diff changeset
556 if (!func_checker::compatible_types_p (parm1, parm2))
kono
parents:
diff changeset
557 return return_false_with_msg ("parameter type is not compatible");
kono
parents:
diff changeset
558
kono
parents:
diff changeset
559 if (POINTER_TYPE_P (parm1)
kono
parents:
diff changeset
560 && (TYPE_RESTRICT (parm1) != TYPE_RESTRICT (parm2)))
kono
parents:
diff changeset
561 return return_false_with_msg ("argument restrict flag mismatch");
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 /* nonnull_arg_p implies non-zero range to REFERENCE types. */
kono
parents:
diff changeset
564 if (POINTER_TYPE_P (parm1)
kono
parents:
diff changeset
565 && TREE_CODE (parm1) != TREE_CODE (parm2)
kono
parents:
diff changeset
566 && opt_for_fn (decl, flag_delete_null_pointer_checks))
kono
parents:
diff changeset
567 return return_false_with_msg ("pointer wrt reference mismatch");
kono
parents:
diff changeset
568
kono
parents:
diff changeset
569 return true;
kono
parents:
diff changeset
570 }
kono
parents:
diff changeset
571
kono
parents:
diff changeset
572 /* Fast equality function based on knowledge known in WPA. */
kono
parents:
diff changeset
573
kono
parents:
diff changeset
574 bool
kono
parents:
diff changeset
575 sem_function::equals_wpa (sem_item *item,
kono
parents:
diff changeset
576 hash_map <symtab_node *, sem_item *> &ignored_nodes)
kono
parents:
diff changeset
577 {
kono
parents:
diff changeset
578 gcc_assert (item->type == FUNC);
kono
parents:
diff changeset
579 cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
kono
parents:
diff changeset
580 cgraph_node *cnode2 = dyn_cast <cgraph_node *> (item->node);
kono
parents:
diff changeset
581
kono
parents:
diff changeset
582 m_compared_func = static_cast<sem_function *> (item);
kono
parents:
diff changeset
583
kono
parents:
diff changeset
584 if (cnode->thunk.thunk_p != cnode2->thunk.thunk_p)
kono
parents:
diff changeset
585 return return_false_with_msg ("thunk_p mismatch");
kono
parents:
diff changeset
586
kono
parents:
diff changeset
587 if (cnode->thunk.thunk_p)
kono
parents:
diff changeset
588 {
kono
parents:
diff changeset
589 if (cnode->thunk.fixed_offset != cnode2->thunk.fixed_offset)
kono
parents:
diff changeset
590 return return_false_with_msg ("thunk fixed_offset mismatch");
kono
parents:
diff changeset
591 if (cnode->thunk.virtual_value != cnode2->thunk.virtual_value)
kono
parents:
diff changeset
592 return return_false_with_msg ("thunk virtual_value mismatch");
kono
parents:
diff changeset
593 if (cnode->thunk.this_adjusting != cnode2->thunk.this_adjusting)
kono
parents:
diff changeset
594 return return_false_with_msg ("thunk this_adjusting mismatch");
kono
parents:
diff changeset
595 if (cnode->thunk.virtual_offset_p != cnode2->thunk.virtual_offset_p)
kono
parents:
diff changeset
596 return return_false_with_msg ("thunk virtual_offset_p mismatch");
kono
parents:
diff changeset
597 if (cnode->thunk.add_pointer_bounds_args
kono
parents:
diff changeset
598 != cnode2->thunk.add_pointer_bounds_args)
kono
parents:
diff changeset
599 return return_false_with_msg ("thunk add_pointer_bounds_args mismatch");
kono
parents:
diff changeset
600 }
kono
parents:
diff changeset
601
kono
parents:
diff changeset
602 /* Compare special function DECL attributes. */
kono
parents:
diff changeset
603 if (DECL_FUNCTION_PERSONALITY (decl)
kono
parents:
diff changeset
604 != DECL_FUNCTION_PERSONALITY (item->decl))
kono
parents:
diff changeset
605 return return_false_with_msg ("function personalities are different");
kono
parents:
diff changeset
606
kono
parents:
diff changeset
607 if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl)
kono
parents:
diff changeset
608 != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl))
kono
parents:
diff changeset
609 return return_false_with_msg ("intrument function entry exit "
kono
parents:
diff changeset
610 "attributes are different");
kono
parents:
diff changeset
611
kono
parents:
diff changeset
612 if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
kono
parents:
diff changeset
613 return return_false_with_msg ("no stack limit attributes are different");
kono
parents:
diff changeset
614
kono
parents:
diff changeset
615 if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl))
kono
parents:
diff changeset
616 return return_false_with_msg ("DECL_CXX_CONSTRUCTOR mismatch");
kono
parents:
diff changeset
617
kono
parents:
diff changeset
618 if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl))
kono
parents:
diff changeset
619 return return_false_with_msg ("DECL_CXX_DESTRUCTOR mismatch");
kono
parents:
diff changeset
620
kono
parents:
diff changeset
621 /* TODO: pure/const flags mostly matters only for references, except for
kono
parents:
diff changeset
622 the fact that codegen takes LOOPING flag as a hint that loops are
kono
parents:
diff changeset
623 finite. We may arrange the code to always pick leader that has least
kono
parents:
diff changeset
624 specified flags and then this can go into comparing symbol properties. */
kono
parents:
diff changeset
625 if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl))
kono
parents:
diff changeset
626 return return_false_with_msg ("decl_or_type flags are different");
kono
parents:
diff changeset
627
kono
parents:
diff changeset
628 /* Do not match polymorphic constructors of different types. They calls
kono
parents:
diff changeset
629 type memory location for ipa-polymorphic-call and we do not want
kono
parents:
diff changeset
630 it to get confused by wrong type. */
kono
parents:
diff changeset
631 if (DECL_CXX_CONSTRUCTOR_P (decl)
kono
parents:
diff changeset
632 && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
kono
parents:
diff changeset
633 {
kono
parents:
diff changeset
634 if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
kono
parents:
diff changeset
635 return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch");
kono
parents:
diff changeset
636 else if (!func_checker::compatible_polymorphic_types_p
kono
parents:
diff changeset
637 (TYPE_METHOD_BASETYPE (TREE_TYPE (decl)),
kono
parents:
diff changeset
638 TYPE_METHOD_BASETYPE (TREE_TYPE (item->decl)), false))
kono
parents:
diff changeset
639 return return_false_with_msg ("ctor polymorphic type mismatch");
kono
parents:
diff changeset
640 }
kono
parents:
diff changeset
641
kono
parents:
diff changeset
642 /* Checking function TARGET and OPTIMIZATION flags. */
kono
parents:
diff changeset
643 cl_target_option *tar1 = target_opts_for_fn (decl);
kono
parents:
diff changeset
644 cl_target_option *tar2 = target_opts_for_fn (item->decl);
kono
parents:
diff changeset
645
kono
parents:
diff changeset
646 if (tar1 != tar2 && !cl_target_option_eq (tar1, tar2))
kono
parents:
diff changeset
647 {
kono
parents:
diff changeset
648 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
649 {
kono
parents:
diff changeset
650 fprintf (dump_file, "target flags difference");
kono
parents:
diff changeset
651 cl_target_option_print_diff (dump_file, 2, tar1, tar2);
kono
parents:
diff changeset
652 }
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 return return_false_with_msg ("Target flags are different");
kono
parents:
diff changeset
655 }
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 cl_optimization *opt1 = opts_for_fn (decl);
kono
parents:
diff changeset
658 cl_optimization *opt2 = opts_for_fn (item->decl);
kono
parents:
diff changeset
659
kono
parents:
diff changeset
660 if (opt1 != opt2 && memcmp (opt1, opt2, sizeof(cl_optimization)))
kono
parents:
diff changeset
661 {
kono
parents:
diff changeset
662 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
663 {
kono
parents:
diff changeset
664 fprintf (dump_file, "optimization flags difference");
kono
parents:
diff changeset
665 cl_optimization_print_diff (dump_file, 2, opt1, opt2);
kono
parents:
diff changeset
666 }
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 return return_false_with_msg ("optimization flags are different");
kono
parents:
diff changeset
669 }
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 /* Result type checking. */
kono
parents:
diff changeset
672 if (!func_checker::compatible_types_p
kono
parents:
diff changeset
673 (TREE_TYPE (TREE_TYPE (decl)),
kono
parents:
diff changeset
674 TREE_TYPE (TREE_TYPE (m_compared_func->decl))))
kono
parents:
diff changeset
675 return return_false_with_msg ("result types are different");
kono
parents:
diff changeset
676
kono
parents:
diff changeset
677 /* Checking types of arguments. */
kono
parents:
diff changeset
678 tree list1 = TYPE_ARG_TYPES (TREE_TYPE (decl)),
kono
parents:
diff changeset
679 list2 = TYPE_ARG_TYPES (TREE_TYPE (m_compared_func->decl));
kono
parents:
diff changeset
680 for (unsigned i = 0; list1 && list2;
kono
parents:
diff changeset
681 list1 = TREE_CHAIN (list1), list2 = TREE_CHAIN (list2), i++)
kono
parents:
diff changeset
682 {
kono
parents:
diff changeset
683 tree parm1 = TREE_VALUE (list1);
kono
parents:
diff changeset
684 tree parm2 = TREE_VALUE (list2);
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 /* This guard is here for function pointer with attributes (pr59927.c). */
kono
parents:
diff changeset
687 if (!parm1 || !parm2)
kono
parents:
diff changeset
688 return return_false_with_msg ("NULL argument type");
kono
parents:
diff changeset
689
kono
parents:
diff changeset
690 /* Verify that types are compatible to ensure that both functions
kono
parents:
diff changeset
691 have same calling conventions. */
kono
parents:
diff changeset
692 if (!types_compatible_p (parm1, parm2))
kono
parents:
diff changeset
693 return return_false_with_msg ("parameter types are not compatible");
kono
parents:
diff changeset
694
kono
parents:
diff changeset
695 if (!param_used_p (i))
kono
parents:
diff changeset
696 continue;
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 /* Perform additional checks for used parameters. */
kono
parents:
diff changeset
699 if (!compatible_parm_types_p (parm1, parm2))
kono
parents:
diff changeset
700 return false;
kono
parents:
diff changeset
701 }
kono
parents:
diff changeset
702
kono
parents:
diff changeset
703 if (list1 || list2)
kono
parents:
diff changeset
704 return return_false_with_msg ("Mismatched number of parameters");
kono
parents:
diff changeset
705
kono
parents:
diff changeset
706 if (node->num_references () != item->node->num_references ())
kono
parents:
diff changeset
707 return return_false_with_msg ("different number of references");
kono
parents:
diff changeset
708
kono
parents:
diff changeset
709 /* Checking function attributes.
kono
parents:
diff changeset
710 This is quadratic in number of attributes */
kono
parents:
diff changeset
711 if (comp_type_attributes (TREE_TYPE (decl),
kono
parents:
diff changeset
712 TREE_TYPE (item->decl)) != 1)
kono
parents:
diff changeset
713 return return_false_with_msg ("different type attributes");
kono
parents:
diff changeset
714 if (!compare_attributes (DECL_ATTRIBUTES (decl),
kono
parents:
diff changeset
715 DECL_ATTRIBUTES (item->decl)))
kono
parents:
diff changeset
716 return return_false_with_msg ("different decl attributes");
kono
parents:
diff changeset
717
kono
parents:
diff changeset
718 /* The type of THIS pointer type memory location for
kono
parents:
diff changeset
719 ipa-polymorphic-call-analysis. */
kono
parents:
diff changeset
720 if (opt_for_fn (decl, flag_devirtualize)
kono
parents:
diff changeset
721 && (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
kono
parents:
diff changeset
722 || TREE_CODE (TREE_TYPE (item->decl)) == METHOD_TYPE)
kono
parents:
diff changeset
723 && param_used_p (0)
kono
parents:
diff changeset
724 && compare_polymorphic_p ())
kono
parents:
diff changeset
725 {
kono
parents:
diff changeset
726 if (TREE_CODE (TREE_TYPE (decl)) != TREE_CODE (TREE_TYPE (item->decl)))
kono
parents:
diff changeset
727 return return_false_with_msg ("METHOD_TYPE and FUNCTION_TYPE mismatch");
kono
parents:
diff changeset
728 if (!func_checker::compatible_polymorphic_types_p
kono
parents:
diff changeset
729 (TYPE_METHOD_BASETYPE (TREE_TYPE (decl)),
kono
parents:
diff changeset
730 TYPE_METHOD_BASETYPE (TREE_TYPE (item->decl)), false))
kono
parents:
diff changeset
731 return return_false_with_msg ("THIS pointer ODR type mismatch");
kono
parents:
diff changeset
732 }
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 ipa_ref *ref = NULL, *ref2 = NULL;
kono
parents:
diff changeset
735 for (unsigned i = 0; node->iterate_reference (i, ref); i++)
kono
parents:
diff changeset
736 {
kono
parents:
diff changeset
737 item->node->iterate_reference (i, ref2);
kono
parents:
diff changeset
738
kono
parents:
diff changeset
739 if (ref->use != ref2->use)
kono
parents:
diff changeset
740 return return_false_with_msg ("reference use mismatch");
kono
parents:
diff changeset
741
kono
parents:
diff changeset
742 if (!compare_symbol_references (ignored_nodes, ref->referred,
kono
parents:
diff changeset
743 ref2->referred,
kono
parents:
diff changeset
744 ref->address_matters_p ()))
kono
parents:
diff changeset
745 return false;
kono
parents:
diff changeset
746 }
kono
parents:
diff changeset
747
kono
parents:
diff changeset
748 cgraph_edge *e1 = dyn_cast <cgraph_node *> (node)->callees;
kono
parents:
diff changeset
749 cgraph_edge *e2 = dyn_cast <cgraph_node *> (item->node)->callees;
kono
parents:
diff changeset
750
kono
parents:
diff changeset
751 while (e1 && e2)
kono
parents:
diff changeset
752 {
kono
parents:
diff changeset
753 if (!compare_symbol_references (ignored_nodes, e1->callee,
kono
parents:
diff changeset
754 e2->callee, false))
kono
parents:
diff changeset
755 return false;
kono
parents:
diff changeset
756 if (!compare_edge_flags (e1, e2))
kono
parents:
diff changeset
757 return false;
kono
parents:
diff changeset
758
kono
parents:
diff changeset
759 e1 = e1->next_callee;
kono
parents:
diff changeset
760 e2 = e2->next_callee;
kono
parents:
diff changeset
761 }
kono
parents:
diff changeset
762
kono
parents:
diff changeset
763 if (e1 || e2)
kono
parents:
diff changeset
764 return return_false_with_msg ("different number of calls");
kono
parents:
diff changeset
765
kono
parents:
diff changeset
766 e1 = dyn_cast <cgraph_node *> (node)->indirect_calls;
kono
parents:
diff changeset
767 e2 = dyn_cast <cgraph_node *> (item->node)->indirect_calls;
kono
parents:
diff changeset
768
kono
parents:
diff changeset
769 while (e1 && e2)
kono
parents:
diff changeset
770 {
kono
parents:
diff changeset
771 if (!compare_edge_flags (e1, e2))
kono
parents:
diff changeset
772 return false;
kono
parents:
diff changeset
773
kono
parents:
diff changeset
774 e1 = e1->next_callee;
kono
parents:
diff changeset
775 e2 = e2->next_callee;
kono
parents:
diff changeset
776 }
kono
parents:
diff changeset
777
kono
parents:
diff changeset
778 if (e1 || e2)
kono
parents:
diff changeset
779 return return_false_with_msg ("different number of indirect calls");
kono
parents:
diff changeset
780
kono
parents:
diff changeset
781 return true;
kono
parents:
diff changeset
782 }
kono
parents:
diff changeset
783
kono
parents:
diff changeset
784 /* Update hash by address sensitive references. We iterate over all
kono
parents:
diff changeset
785 sensitive references (address_matters_p) and we hash ultime alias
kono
parents:
diff changeset
786 target of these nodes, which can improve a semantic item hash.
kono
parents:
diff changeset
787
kono
parents:
diff changeset
788 Also hash in referenced symbols properties. This can be done at any time
kono
parents:
diff changeset
789 (as the properties should not change), but it is convenient to do it here
kono
parents:
diff changeset
790 while we walk the references anyway. */
kono
parents:
diff changeset
791
kono
parents:
diff changeset
792 void
kono
parents:
diff changeset
793 sem_item::update_hash_by_addr_refs (hash_map <symtab_node *,
kono
parents:
diff changeset
794 sem_item *> &m_symtab_node_map)
kono
parents:
diff changeset
795 {
kono
parents:
diff changeset
796 ipa_ref* ref;
kono
parents:
diff changeset
797 inchash::hash hstate (get_hash ());
kono
parents:
diff changeset
798
kono
parents:
diff changeset
799 for (unsigned i = 0; node->iterate_reference (i, ref); i++)
kono
parents:
diff changeset
800 {
kono
parents:
diff changeset
801 hstate.add_int (ref->use);
kono
parents:
diff changeset
802 hash_referenced_symbol_properties (ref->referred, hstate,
kono
parents:
diff changeset
803 ref->use == IPA_REF_ADDR);
kono
parents:
diff changeset
804 if (ref->address_matters_p () || !m_symtab_node_map.get (ref->referred))
kono
parents:
diff changeset
805 hstate.add_int (ref->referred->ultimate_alias_target ()->order);
kono
parents:
diff changeset
806 }
kono
parents:
diff changeset
807
kono
parents:
diff changeset
808 if (is_a <cgraph_node *> (node))
kono
parents:
diff changeset
809 {
kono
parents:
diff changeset
810 for (cgraph_edge *e = dyn_cast <cgraph_node *> (node)->callers; e;
kono
parents:
diff changeset
811 e = e->next_caller)
kono
parents:
diff changeset
812 {
kono
parents:
diff changeset
813 sem_item **result = m_symtab_node_map.get (e->callee);
kono
parents:
diff changeset
814 hash_referenced_symbol_properties (e->callee, hstate, false);
kono
parents:
diff changeset
815 if (!result)
kono
parents:
diff changeset
816 hstate.add_int (e->callee->ultimate_alias_target ()->order);
kono
parents:
diff changeset
817 }
kono
parents:
diff changeset
818 }
kono
parents:
diff changeset
819
kono
parents:
diff changeset
820 set_hash (hstate.end ());
kono
parents:
diff changeset
821 }
kono
parents:
diff changeset
822
kono
parents:
diff changeset
823 /* Update hash by computed local hash values taken from different
kono
parents:
diff changeset
824 semantic items.
kono
parents:
diff changeset
825 TODO: stronger SCC based hashing would be desirable here. */
kono
parents:
diff changeset
826
kono
parents:
diff changeset
827 void
kono
parents:
diff changeset
828 sem_item::update_hash_by_local_refs (hash_map <symtab_node *,
kono
parents:
diff changeset
829 sem_item *> &m_symtab_node_map)
kono
parents:
diff changeset
830 {
kono
parents:
diff changeset
831 ipa_ref* ref;
kono
parents:
diff changeset
832 inchash::hash state (get_hash ());
kono
parents:
diff changeset
833
kono
parents:
diff changeset
834 for (unsigned j = 0; node->iterate_reference (j, ref); j++)
kono
parents:
diff changeset
835 {
kono
parents:
diff changeset
836 sem_item **result = m_symtab_node_map.get (ref->referring);
kono
parents:
diff changeset
837 if (result)
kono
parents:
diff changeset
838 state.merge_hash ((*result)->get_hash ());
kono
parents:
diff changeset
839 }
kono
parents:
diff changeset
840
kono
parents:
diff changeset
841 if (type == FUNC)
kono
parents:
diff changeset
842 {
kono
parents:
diff changeset
843 for (cgraph_edge *e = dyn_cast <cgraph_node *> (node)->callees; e;
kono
parents:
diff changeset
844 e = e->next_callee)
kono
parents:
diff changeset
845 {
kono
parents:
diff changeset
846 sem_item **result = m_symtab_node_map.get (e->caller);
kono
parents:
diff changeset
847 if (result)
kono
parents:
diff changeset
848 state.merge_hash ((*result)->get_hash ());
kono
parents:
diff changeset
849 }
kono
parents:
diff changeset
850 }
kono
parents:
diff changeset
851
kono
parents:
diff changeset
852 global_hash = state.end ();
kono
parents:
diff changeset
853 }
kono
parents:
diff changeset
854
kono
parents:
diff changeset
855 /* Returns true if the item equals to ITEM given as argument. */
kono
parents:
diff changeset
856
kono
parents:
diff changeset
857 bool
kono
parents:
diff changeset
858 sem_function::equals (sem_item *item,
kono
parents:
diff changeset
859 hash_map <symtab_node *, sem_item *> &)
kono
parents:
diff changeset
860 {
kono
parents:
diff changeset
861 gcc_assert (item->type == FUNC);
kono
parents:
diff changeset
862 bool eq = equals_private (item);
kono
parents:
diff changeset
863
kono
parents:
diff changeset
864 if (m_checker != NULL)
kono
parents:
diff changeset
865 {
kono
parents:
diff changeset
866 delete m_checker;
kono
parents:
diff changeset
867 m_checker = NULL;
kono
parents:
diff changeset
868 }
kono
parents:
diff changeset
869
kono
parents:
diff changeset
870 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
871 fprintf (dump_file,
kono
parents:
diff changeset
872 "Equals called for: %s:%s with result: %s\n\n",
kono
parents:
diff changeset
873 node->dump_name (),
kono
parents:
diff changeset
874 item->node->dump_name (),
kono
parents:
diff changeset
875 eq ? "true" : "false");
kono
parents:
diff changeset
876
kono
parents:
diff changeset
877 return eq;
kono
parents:
diff changeset
878 }
kono
parents:
diff changeset
879
kono
parents:
diff changeset
880 /* Processes function equality comparison. */
kono
parents:
diff changeset
881
kono
parents:
diff changeset
882 bool
kono
parents:
diff changeset
883 sem_function::equals_private (sem_item *item)
kono
parents:
diff changeset
884 {
kono
parents:
diff changeset
885 if (item->type != FUNC)
kono
parents:
diff changeset
886 return false;
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 basic_block bb1, bb2;
kono
parents:
diff changeset
889 edge e1, e2;
kono
parents:
diff changeset
890 edge_iterator ei1, ei2;
kono
parents:
diff changeset
891 bool result = true;
kono
parents:
diff changeset
892 tree arg1, arg2;
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 m_compared_func = static_cast<sem_function *> (item);
kono
parents:
diff changeset
895
kono
parents:
diff changeset
896 gcc_assert (decl != item->decl);
kono
parents:
diff changeset
897
kono
parents:
diff changeset
898 if (bb_sorted.length () != m_compared_func->bb_sorted.length ()
kono
parents:
diff changeset
899 || edge_count != m_compared_func->edge_count
kono
parents:
diff changeset
900 || cfg_checksum != m_compared_func->cfg_checksum)
kono
parents:
diff changeset
901 return return_false ();
kono
parents:
diff changeset
902
kono
parents:
diff changeset
903 m_checker = new func_checker (decl, m_compared_func->decl,
kono
parents:
diff changeset
904 compare_polymorphic_p (),
kono
parents:
diff changeset
905 false,
kono
parents:
diff changeset
906 &refs_set,
kono
parents:
diff changeset
907 &m_compared_func->refs_set);
kono
parents:
diff changeset
908 arg1 = DECL_ARGUMENTS (decl);
kono
parents:
diff changeset
909 arg2 = DECL_ARGUMENTS (m_compared_func->decl);
kono
parents:
diff changeset
910 for (unsigned i = 0;
kono
parents:
diff changeset
911 arg1 && arg2; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2), i++)
kono
parents:
diff changeset
912 {
kono
parents:
diff changeset
913 if (!types_compatible_p (TREE_TYPE (arg1), TREE_TYPE (arg2)))
kono
parents:
diff changeset
914 return return_false_with_msg ("argument types are not compatible");
kono
parents:
diff changeset
915 if (!param_used_p (i))
kono
parents:
diff changeset
916 continue;
kono
parents:
diff changeset
917 /* Perform additional checks for used parameters. */
kono
parents:
diff changeset
918 if (!compatible_parm_types_p (TREE_TYPE (arg1), TREE_TYPE (arg2)))
kono
parents:
diff changeset
919 return false;
kono
parents:
diff changeset
920 if (!m_checker->compare_decl (arg1, arg2))
kono
parents:
diff changeset
921 return return_false ();
kono
parents:
diff changeset
922 }
kono
parents:
diff changeset
923 if (arg1 || arg2)
kono
parents:
diff changeset
924 return return_false_with_msg ("Mismatched number of arguments");
kono
parents:
diff changeset
925
kono
parents:
diff changeset
926 if (!dyn_cast <cgraph_node *> (node)->has_gimple_body_p ())
kono
parents:
diff changeset
927 return true;
kono
parents:
diff changeset
928
kono
parents:
diff changeset
929 /* Fill-up label dictionary. */
kono
parents:
diff changeset
930 for (unsigned i = 0; i < bb_sorted.length (); ++i)
kono
parents:
diff changeset
931 {
kono
parents:
diff changeset
932 m_checker->parse_labels (bb_sorted[i]);
kono
parents:
diff changeset
933 m_checker->parse_labels (m_compared_func->bb_sorted[i]);
kono
parents:
diff changeset
934 }
kono
parents:
diff changeset
935
kono
parents:
diff changeset
936 /* Checking all basic blocks. */
kono
parents:
diff changeset
937 for (unsigned i = 0; i < bb_sorted.length (); ++i)
kono
parents:
diff changeset
938 if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
kono
parents:
diff changeset
939 return return_false();
kono
parents:
diff changeset
940
kono
parents:
diff changeset
941 dump_message ("All BBs are equal\n");
kono
parents:
diff changeset
942
kono
parents:
diff changeset
943 auto_vec <int> bb_dict;
kono
parents:
diff changeset
944
kono
parents:
diff changeset
945 /* Basic block edges check. */
kono
parents:
diff changeset
946 for (unsigned i = 0; i < bb_sorted.length (); ++i)
kono
parents:
diff changeset
947 {
kono
parents:
diff changeset
948 bb1 = bb_sorted[i]->bb;
kono
parents:
diff changeset
949 bb2 = m_compared_func->bb_sorted[i]->bb;
kono
parents:
diff changeset
950
kono
parents:
diff changeset
951 ei2 = ei_start (bb2->preds);
kono
parents:
diff changeset
952
kono
parents:
diff changeset
953 for (ei1 = ei_start (bb1->preds); ei_cond (ei1, &e1); ei_next (&ei1))
kono
parents:
diff changeset
954 {
kono
parents:
diff changeset
955 ei_cond (ei2, &e2);
kono
parents:
diff changeset
956
kono
parents:
diff changeset
957 if (e1->flags != e2->flags)
kono
parents:
diff changeset
958 return return_false_with_msg ("flags comparison returns false");
kono
parents:
diff changeset
959
kono
parents:
diff changeset
960 if (!bb_dict_test (&bb_dict, e1->src->index, e2->src->index))
kono
parents:
diff changeset
961 return return_false_with_msg ("edge comparison returns false");
kono
parents:
diff changeset
962
kono
parents:
diff changeset
963 if (!bb_dict_test (&bb_dict, e1->dest->index, e2->dest->index))
kono
parents:
diff changeset
964 return return_false_with_msg ("BB comparison returns false");
kono
parents:
diff changeset
965
kono
parents:
diff changeset
966 if (!m_checker->compare_edge (e1, e2))
kono
parents:
diff changeset
967 return return_false_with_msg ("edge comparison returns false");
kono
parents:
diff changeset
968
kono
parents:
diff changeset
969 ei_next (&ei2);
kono
parents:
diff changeset
970 }
kono
parents:
diff changeset
971 }
kono
parents:
diff changeset
972
kono
parents:
diff changeset
973 /* Basic block PHI nodes comparison. */
kono
parents:
diff changeset
974 for (unsigned i = 0; i < bb_sorted.length (); i++)
kono
parents:
diff changeset
975 if (!compare_phi_node (bb_sorted[i]->bb, m_compared_func->bb_sorted[i]->bb))
kono
parents:
diff changeset
976 return return_false_with_msg ("PHI node comparison returns false");
kono
parents:
diff changeset
977
kono
parents:
diff changeset
978 return result;
kono
parents:
diff changeset
979 }
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 /* Set LOCAL_P of NODE to true if DATA is non-NULL.
kono
parents:
diff changeset
982 Helper for call_for_symbol_thunks_and_aliases. */
kono
parents:
diff changeset
983
kono
parents:
diff changeset
984 static bool
kono
parents:
diff changeset
985 set_local (cgraph_node *node, void *data)
kono
parents:
diff changeset
986 {
kono
parents:
diff changeset
987 node->local.local = data != NULL;
kono
parents:
diff changeset
988 return false;
kono
parents:
diff changeset
989 }
kono
parents:
diff changeset
990
kono
parents:
diff changeset
991 /* TREE_ADDRESSABLE of NODE to true.
kono
parents:
diff changeset
992 Helper for call_for_symbol_thunks_and_aliases. */
kono
parents:
diff changeset
993
kono
parents:
diff changeset
994 static bool
kono
parents:
diff changeset
995 set_addressable (varpool_node *node, void *)
kono
parents:
diff changeset
996 {
kono
parents:
diff changeset
997 TREE_ADDRESSABLE (node->decl) = 1;
kono
parents:
diff changeset
998 return false;
kono
parents:
diff changeset
999 }
kono
parents:
diff changeset
1000
kono
parents:
diff changeset
1001 /* Clear DECL_RTL of NODE.
kono
parents:
diff changeset
1002 Helper for call_for_symbol_thunks_and_aliases. */
kono
parents:
diff changeset
1003
kono
parents:
diff changeset
1004 static bool
kono
parents:
diff changeset
1005 clear_decl_rtl (symtab_node *node, void *)
kono
parents:
diff changeset
1006 {
kono
parents:
diff changeset
1007 SET_DECL_RTL (node->decl, NULL);
kono
parents:
diff changeset
1008 return false;
kono
parents:
diff changeset
1009 }
kono
parents:
diff changeset
1010
kono
parents:
diff changeset
1011 /* Redirect all callers of N and its aliases to TO. Remove aliases if
kono
parents:
diff changeset
1012 possible. Return number of redirections made. */
kono
parents:
diff changeset
1013
kono
parents:
diff changeset
1014 static int
kono
parents:
diff changeset
1015 redirect_all_callers (cgraph_node *n, cgraph_node *to)
kono
parents:
diff changeset
1016 {
kono
parents:
diff changeset
1017 int nredirected = 0;
kono
parents:
diff changeset
1018 ipa_ref *ref;
kono
parents:
diff changeset
1019 cgraph_edge *e = n->callers;
kono
parents:
diff changeset
1020
kono
parents:
diff changeset
1021 while (e)
kono
parents:
diff changeset
1022 {
kono
parents:
diff changeset
1023 /* Redirecting thunks to interposable symbols or symbols in other sections
kono
parents:
diff changeset
1024 may not be supported by target output code. Play safe for now and
kono
parents:
diff changeset
1025 punt on redirection. */
kono
parents:
diff changeset
1026 if (!e->caller->thunk.thunk_p)
kono
parents:
diff changeset
1027 {
kono
parents:
diff changeset
1028 struct cgraph_edge *nexte = e->next_caller;
kono
parents:
diff changeset
1029 e->redirect_callee (to);
kono
parents:
diff changeset
1030 e = nexte;
kono
parents:
diff changeset
1031 nredirected++;
kono
parents:
diff changeset
1032 }
kono
parents:
diff changeset
1033 else
kono
parents:
diff changeset
1034 e = e->next_callee;
kono
parents:
diff changeset
1035 }
kono
parents:
diff changeset
1036 for (unsigned i = 0; n->iterate_direct_aliases (i, ref);)
kono
parents:
diff changeset
1037 {
kono
parents:
diff changeset
1038 bool removed = false;
kono
parents:
diff changeset
1039 cgraph_node *n_alias = dyn_cast <cgraph_node *> (ref->referring);
kono
parents:
diff changeset
1040
kono
parents:
diff changeset
1041 if ((DECL_COMDAT_GROUP (n->decl)
kono
parents:
diff changeset
1042 && (DECL_COMDAT_GROUP (n->decl)
kono
parents:
diff changeset
1043 == DECL_COMDAT_GROUP (n_alias->decl)))
kono
parents:
diff changeset
1044 || (n_alias->get_availability () > AVAIL_INTERPOSABLE
kono
parents:
diff changeset
1045 && n->get_availability () > AVAIL_INTERPOSABLE))
kono
parents:
diff changeset
1046 {
kono
parents:
diff changeset
1047 nredirected += redirect_all_callers (n_alias, to);
kono
parents:
diff changeset
1048 if (n_alias->can_remove_if_no_direct_calls_p ()
kono
parents:
diff changeset
1049 && !n_alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p,
kono
parents:
diff changeset
1050 NULL, true)
kono
parents:
diff changeset
1051 && !n_alias->has_aliases_p ())
kono
parents:
diff changeset
1052 n_alias->remove ();
kono
parents:
diff changeset
1053 }
kono
parents:
diff changeset
1054 if (!removed)
kono
parents:
diff changeset
1055 i++;
kono
parents:
diff changeset
1056 }
kono
parents:
diff changeset
1057 return nredirected;
kono
parents:
diff changeset
1058 }
kono
parents:
diff changeset
1059
kono
parents:
diff changeset
1060 /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
kono
parents:
diff changeset
1061 be applied. */
kono
parents:
diff changeset
1062
kono
parents:
diff changeset
1063 bool
kono
parents:
diff changeset
1064 sem_function::merge (sem_item *alias_item)
kono
parents:
diff changeset
1065 {
kono
parents:
diff changeset
1066 gcc_assert (alias_item->type == FUNC);
kono
parents:
diff changeset
1067
kono
parents:
diff changeset
1068 sem_function *alias_func = static_cast<sem_function *> (alias_item);
kono
parents:
diff changeset
1069
kono
parents:
diff changeset
1070 cgraph_node *original = get_node ();
kono
parents:
diff changeset
1071 cgraph_node *local_original = NULL;
kono
parents:
diff changeset
1072 cgraph_node *alias = alias_func->get_node ();
kono
parents:
diff changeset
1073
kono
parents:
diff changeset
1074 bool create_wrapper = false;
kono
parents:
diff changeset
1075 bool create_alias = false;
kono
parents:
diff changeset
1076 bool redirect_callers = false;
kono
parents:
diff changeset
1077 bool remove = false;
kono
parents:
diff changeset
1078
kono
parents:
diff changeset
1079 bool original_discardable = false;
kono
parents:
diff changeset
1080 bool original_discarded = false;
kono
parents:
diff changeset
1081
kono
parents:
diff changeset
1082 bool original_address_matters = original->address_matters_p ();
kono
parents:
diff changeset
1083 bool alias_address_matters = alias->address_matters_p ();
kono
parents:
diff changeset
1084
kono
parents:
diff changeset
1085 if (DECL_EXTERNAL (alias->decl))
kono
parents:
diff changeset
1086 {
kono
parents:
diff changeset
1087 if (dump_file)
kono
parents:
diff changeset
1088 fprintf (dump_file, "Not unifying; alias is external.\n\n");
kono
parents:
diff changeset
1089 return false;
kono
parents:
diff changeset
1090 }
kono
parents:
diff changeset
1091
kono
parents:
diff changeset
1092 if (DECL_NO_INLINE_WARNING_P (original->decl)
kono
parents:
diff changeset
1093 != DECL_NO_INLINE_WARNING_P (alias->decl))
kono
parents:
diff changeset
1094 {
kono
parents:
diff changeset
1095 if (dump_file)
kono
parents:
diff changeset
1096 fprintf (dump_file,
kono
parents:
diff changeset
1097 "Not unifying; "
kono
parents:
diff changeset
1098 "DECL_NO_INLINE_WARNING mismatch.\n\n");
kono
parents:
diff changeset
1099 return false;
kono
parents:
diff changeset
1100 }
kono
parents:
diff changeset
1101
kono
parents:
diff changeset
1102 /* Do not attempt to mix functions from different user sections;
kono
parents:
diff changeset
1103 we do not know what user intends with those. */
kono
parents:
diff changeset
1104 if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
kono
parents:
diff changeset
1105 || (DECL_SECTION_NAME (alias->decl) && !alias->implicit_section))
kono
parents:
diff changeset
1106 && DECL_SECTION_NAME (original->decl) != DECL_SECTION_NAME (alias->decl))
kono
parents:
diff changeset
1107 {
kono
parents:
diff changeset
1108 if (dump_file)
kono
parents:
diff changeset
1109 fprintf (dump_file,
kono
parents:
diff changeset
1110 "Not unifying; "
kono
parents:
diff changeset
1111 "original and alias are in different sections.\n\n");
kono
parents:
diff changeset
1112 return false;
kono
parents:
diff changeset
1113 }
kono
parents:
diff changeset
1114
kono
parents:
diff changeset
1115 /* See if original is in a section that can be discarded if the main
kono
parents:
diff changeset
1116 symbol is not used. */
kono
parents:
diff changeset
1117
kono
parents:
diff changeset
1118 if (original->can_be_discarded_p ())
kono
parents:
diff changeset
1119 original_discardable = true;
kono
parents:
diff changeset
1120 /* Also consider case where we have resolution info and we know that
kono
parents:
diff changeset
1121 original's definition is not going to be used. In this case we can not
kono
parents:
diff changeset
1122 create alias to original. */
kono
parents:
diff changeset
1123 if (node->resolution != LDPR_UNKNOWN
kono
parents:
diff changeset
1124 && !decl_binds_to_current_def_p (node->decl))
kono
parents:
diff changeset
1125 original_discardable = original_discarded = true;
kono
parents:
diff changeset
1126
kono
parents:
diff changeset
1127 /* Creating a symtab alias is the optimal way to merge.
kono
parents:
diff changeset
1128 It however can not be used in the following cases:
kono
parents:
diff changeset
1129
kono
parents:
diff changeset
1130 1) if ORIGINAL and ALIAS may be possibly compared for address equality.
kono
parents:
diff changeset
1131 2) if ORIGINAL is in a section that may be discarded by linker or if
kono
parents:
diff changeset
1132 it is an external functions where we can not create an alias
kono
parents:
diff changeset
1133 (ORIGINAL_DISCARDABLE)
kono
parents:
diff changeset
1134 3) if target do not support symbol aliases.
kono
parents:
diff changeset
1135 4) original and alias lie in different comdat groups.
kono
parents:
diff changeset
1136
kono
parents:
diff changeset
1137 If we can not produce alias, we will turn ALIAS into WRAPPER of ORIGINAL
kono
parents:
diff changeset
1138 and/or redirect all callers from ALIAS to ORIGINAL. */
kono
parents:
diff changeset
1139 if ((original_address_matters && alias_address_matters)
kono
parents:
diff changeset
1140 || (original_discardable
kono
parents:
diff changeset
1141 && (!DECL_COMDAT_GROUP (alias->decl)
kono
parents:
diff changeset
1142 || (DECL_COMDAT_GROUP (alias->decl)
kono
parents:
diff changeset
1143 != DECL_COMDAT_GROUP (original->decl))))
kono
parents:
diff changeset
1144 || original_discarded
kono
parents:
diff changeset
1145 || !sem_item::target_supports_symbol_aliases_p ()
kono
parents:
diff changeset
1146 || DECL_COMDAT_GROUP (alias->decl) != DECL_COMDAT_GROUP (original->decl))
kono
parents:
diff changeset
1147 {
kono
parents:
diff changeset
1148 /* First see if we can produce wrapper. */
kono
parents:
diff changeset
1149
kono
parents:
diff changeset
1150 /* Symbol properties that matter for references must be preserved.
kono
parents:
diff changeset
1151 TODO: We can produce wrapper, but we need to produce alias of ORIGINAL
kono
parents:
diff changeset
1152 with proper properties. */
kono
parents:
diff changeset
1153 if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias,
kono
parents:
diff changeset
1154 alias->address_taken))
kono
parents:
diff changeset
1155 {
kono
parents:
diff changeset
1156 if (dump_file)
kono
parents:
diff changeset
1157 fprintf (dump_file,
kono
parents:
diff changeset
1158 "Wrapper cannot be created because referenced symbol "
kono
parents:
diff changeset
1159 "properties mismatch\n");
kono
parents:
diff changeset
1160 }
kono
parents:
diff changeset
1161 /* Do not turn function in one comdat group into wrapper to another
kono
parents:
diff changeset
1162 comdat group. Other compiler producing the body of the
kono
parents:
diff changeset
1163 another comdat group may make opossite decision and with unfortunate
kono
parents:
diff changeset
1164 linker choices this may close a loop. */
kono
parents:
diff changeset
1165 else if (DECL_COMDAT_GROUP (original->decl)
kono
parents:
diff changeset
1166 && DECL_COMDAT_GROUP (alias->decl)
kono
parents:
diff changeset
1167 && (DECL_COMDAT_GROUP (alias->decl)
kono
parents:
diff changeset
1168 != DECL_COMDAT_GROUP (original->decl)))
kono
parents:
diff changeset
1169 {
kono
parents:
diff changeset
1170 if (dump_file)
kono
parents:
diff changeset
1171 fprintf (dump_file,
kono
parents:
diff changeset
1172 "Wrapper cannot be created because of COMDAT\n");
kono
parents:
diff changeset
1173 }
kono
parents:
diff changeset
1174 else if (DECL_STATIC_CHAIN (alias->decl)
kono
parents:
diff changeset
1175 || DECL_STATIC_CHAIN (original->decl))
kono
parents:
diff changeset
1176 {
kono
parents:
diff changeset
1177 if (dump_file)
kono
parents:
diff changeset
1178 fprintf (dump_file,
kono
parents:
diff changeset
1179 "Cannot create wrapper of nested function.\n");
kono
parents:
diff changeset
1180 }
kono
parents:
diff changeset
1181 /* TODO: We can also deal with variadic functions never calling
kono
parents:
diff changeset
1182 VA_START. */
kono
parents:
diff changeset
1183 else if (stdarg_p (TREE_TYPE (alias->decl)))
kono
parents:
diff changeset
1184 {
kono
parents:
diff changeset
1185 if (dump_file)
kono
parents:
diff changeset
1186 fprintf (dump_file,
kono
parents:
diff changeset
1187 "can not create wrapper of stdarg function.\n");
kono
parents:
diff changeset
1188 }
kono
parents:
diff changeset
1189 else if (ipa_fn_summaries
kono
parents:
diff changeset
1190 && ipa_fn_summaries->get (alias)->self_size <= 2)
kono
parents:
diff changeset
1191 {
kono
parents:
diff changeset
1192 if (dump_file)
kono
parents:
diff changeset
1193 fprintf (dump_file, "Wrapper creation is not "
kono
parents:
diff changeset
1194 "profitable (function is too small).\n");
kono
parents:
diff changeset
1195 }
kono
parents:
diff changeset
1196 /* If user paid attention to mark function noinline, assume it is
kono
parents:
diff changeset
1197 somewhat special and do not try to turn it into a wrapper that can
kono
parents:
diff changeset
1198 not be undone by inliner. */
kono
parents:
diff changeset
1199 else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (alias->decl)))
kono
parents:
diff changeset
1200 {
kono
parents:
diff changeset
1201 if (dump_file)
kono
parents:
diff changeset
1202 fprintf (dump_file, "Wrappers are not created for noinline.\n");
kono
parents:
diff changeset
1203 }
kono
parents:
diff changeset
1204 else
kono
parents:
diff changeset
1205 create_wrapper = true;
kono
parents:
diff changeset
1206
kono
parents:
diff changeset
1207 /* We can redirect local calls in the case both alias and orignal
kono
parents:
diff changeset
1208 are not interposable. */
kono
parents:
diff changeset
1209 redirect_callers
kono
parents:
diff changeset
1210 = alias->get_availability () > AVAIL_INTERPOSABLE
kono
parents:
diff changeset
1211 && original->get_availability () > AVAIL_INTERPOSABLE
kono
parents:
diff changeset
1212 && !alias->instrumented_version;
kono
parents:
diff changeset
1213 /* TODO: We can redirect, but we need to produce alias of ORIGINAL
kono
parents:
diff changeset
1214 with proper properties. */
kono
parents:
diff changeset
1215 if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias,
kono
parents:
diff changeset
1216 alias->address_taken))
kono
parents:
diff changeset
1217 redirect_callers = false;
kono
parents:
diff changeset
1218
kono
parents:
diff changeset
1219 if (!redirect_callers && !create_wrapper)
kono
parents:
diff changeset
1220 {
kono
parents:
diff changeset
1221 if (dump_file)
kono
parents:
diff changeset
1222 fprintf (dump_file, "Not unifying; can not redirect callers nor "
kono
parents:
diff changeset
1223 "produce wrapper\n\n");
kono
parents:
diff changeset
1224 return false;
kono
parents:
diff changeset
1225 }
kono
parents:
diff changeset
1226
kono
parents:
diff changeset
1227 /* Work out the symbol the wrapper should call.
kono
parents:
diff changeset
1228 If ORIGINAL is interposable, we need to call a local alias.
kono
parents:
diff changeset
1229 Also produce local alias (if possible) as an optimization.
kono
parents:
diff changeset
1230
kono
parents:
diff changeset
1231 Local aliases can not be created inside comdat groups because that
kono
parents:
diff changeset
1232 prevents inlining. */
kono
parents:
diff changeset
1233 if (!original_discardable && !original->get_comdat_group ())
kono
parents:
diff changeset
1234 {
kono
parents:
diff changeset
1235 local_original
kono
parents:
diff changeset
1236 = dyn_cast <cgraph_node *> (original->noninterposable_alias ());
kono
parents:
diff changeset
1237 if (!local_original
kono
parents:
diff changeset
1238 && original->get_availability () > AVAIL_INTERPOSABLE)
kono
parents:
diff changeset
1239 local_original = original;
kono
parents:
diff changeset
1240 }
kono
parents:
diff changeset
1241 /* If we can not use local alias, fallback to the original
kono
parents:
diff changeset
1242 when possible. */
kono
parents:
diff changeset
1243 else if (original->get_availability () > AVAIL_INTERPOSABLE)
kono
parents:
diff changeset
1244 local_original = original;
kono
parents:
diff changeset
1245
kono
parents:
diff changeset
1246 /* If original is COMDAT local, we can not really redirect calls outside
kono
parents:
diff changeset
1247 of its comdat group to it. */
kono
parents:
diff changeset
1248 if (original->comdat_local_p ())
kono
parents:
diff changeset
1249 redirect_callers = false;
kono
parents:
diff changeset
1250 if (!local_original)
kono
parents:
diff changeset
1251 {
kono
parents:
diff changeset
1252 if (dump_file)
kono
parents:
diff changeset
1253 fprintf (dump_file, "Not unifying; "
kono
parents:
diff changeset
1254 "can not produce local alias.\n\n");
kono
parents:
diff changeset
1255 return false;
kono
parents:
diff changeset
1256 }
kono
parents:
diff changeset
1257
kono
parents:
diff changeset
1258 if (!redirect_callers && !create_wrapper)
kono
parents:
diff changeset
1259 {
kono
parents:
diff changeset
1260 if (dump_file)
kono
parents:
diff changeset
1261 fprintf (dump_file, "Not unifying; "
kono
parents:
diff changeset
1262 "can not redirect callers nor produce a wrapper\n\n");
kono
parents:
diff changeset
1263 return false;
kono
parents:
diff changeset
1264 }
kono
parents:
diff changeset
1265 if (!create_wrapper
kono
parents:
diff changeset
1266 && !alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p,
kono
parents:
diff changeset
1267 NULL, true)
kono
parents:
diff changeset
1268 && !alias->can_remove_if_no_direct_calls_p ())
kono
parents:
diff changeset
1269 {
kono
parents:
diff changeset
1270 if (dump_file)
kono
parents:
diff changeset
1271 fprintf (dump_file, "Not unifying; can not make wrapper and "
kono
parents:
diff changeset
1272 "function has other uses than direct calls\n\n");
kono
parents:
diff changeset
1273 return false;
kono
parents:
diff changeset
1274 }
kono
parents:
diff changeset
1275 }
kono
parents:
diff changeset
1276 else
kono
parents:
diff changeset
1277 create_alias = true;
kono
parents:
diff changeset
1278
kono
parents:
diff changeset
1279 if (redirect_callers)
kono
parents:
diff changeset
1280 {
kono
parents:
diff changeset
1281 int nredirected = redirect_all_callers (alias, local_original);
kono
parents:
diff changeset
1282
kono
parents:
diff changeset
1283 if (nredirected)
kono
parents:
diff changeset
1284 {
kono
parents:
diff changeset
1285 alias->icf_merged = true;
kono
parents:
diff changeset
1286 local_original->icf_merged = true;
kono
parents:
diff changeset
1287
kono
parents:
diff changeset
1288 if (dump_file && nredirected)
kono
parents:
diff changeset
1289 fprintf (dump_file, "%i local calls have been "
kono
parents:
diff changeset
1290 "redirected.\n", nredirected);
kono
parents:
diff changeset
1291 }
kono
parents:
diff changeset
1292
kono
parents:
diff changeset
1293 /* If all callers was redirected, do not produce wrapper. */
kono
parents:
diff changeset
1294 if (alias->can_remove_if_no_direct_calls_p ()
kono
parents:
diff changeset
1295 && !DECL_VIRTUAL_P (alias->decl)
kono
parents:
diff changeset
1296 && !alias->has_aliases_p ())
kono
parents:
diff changeset
1297 {
kono
parents:
diff changeset
1298 create_wrapper = false;
kono
parents:
diff changeset
1299 remove = true;
kono
parents:
diff changeset
1300 }
kono
parents:
diff changeset
1301 gcc_assert (!create_alias);
kono
parents:
diff changeset
1302 }
kono
parents:
diff changeset
1303 else if (create_alias)
kono
parents:
diff changeset
1304 {
kono
parents:
diff changeset
1305 alias->icf_merged = true;
kono
parents:
diff changeset
1306
kono
parents:
diff changeset
1307 /* Remove the function's body. */
kono
parents:
diff changeset
1308 ipa_merge_profiles (original, alias);
kono
parents:
diff changeset
1309 alias->release_body (true);
kono
parents:
diff changeset
1310 alias->reset ();
kono
parents:
diff changeset
1311 /* Notice global symbol possibly produced RTL. */
kono
parents:
diff changeset
1312 ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl,
kono
parents:
diff changeset
1313 NULL, true);
kono
parents:
diff changeset
1314
kono
parents:
diff changeset
1315 /* Create the alias. */
kono
parents:
diff changeset
1316 cgraph_node::create_alias (alias_func->decl, decl);
kono
parents:
diff changeset
1317 alias->resolve_alias (original);
kono
parents:
diff changeset
1318
kono
parents:
diff changeset
1319 original->call_for_symbol_thunks_and_aliases
kono
parents:
diff changeset
1320 (set_local, (void *)(size_t) original->local_p (), true);
kono
parents:
diff changeset
1321
kono
parents:
diff changeset
1322 if (dump_file)
kono
parents:
diff changeset
1323 fprintf (dump_file, "Unified; Function alias has been created.\n\n");
kono
parents:
diff changeset
1324 }
kono
parents:
diff changeset
1325 if (create_wrapper)
kono
parents:
diff changeset
1326 {
kono
parents:
diff changeset
1327 gcc_assert (!create_alias);
kono
parents:
diff changeset
1328 alias->icf_merged = true;
kono
parents:
diff changeset
1329 local_original->icf_merged = true;
kono
parents:
diff changeset
1330
kono
parents:
diff changeset
1331 /* FIXME update local_original counts. */
kono
parents:
diff changeset
1332 ipa_merge_profiles (original, alias, true);
kono
parents:
diff changeset
1333 alias->create_wrapper (local_original);
kono
parents:
diff changeset
1334
kono
parents:
diff changeset
1335 if (dump_file)
kono
parents:
diff changeset
1336 fprintf (dump_file, "Unified; Wrapper has been created.\n\n");
kono
parents:
diff changeset
1337 }
kono
parents:
diff changeset
1338
kono
parents:
diff changeset
1339 /* It's possible that redirection can hit thunks that block
kono
parents:
diff changeset
1340 redirection opportunities. */
kono
parents:
diff changeset
1341 gcc_assert (alias->icf_merged || remove || redirect_callers);
kono
parents:
diff changeset
1342 original->icf_merged = true;
kono
parents:
diff changeset
1343
kono
parents:
diff changeset
1344 /* We use merged flag to track cases where COMDAT function is known to be
kono
parents:
diff changeset
1345 compatible its callers. If we merged in non-COMDAT, we need to give up
kono
parents:
diff changeset
1346 on this optimization. */
kono
parents:
diff changeset
1347 if (original->merged_comdat && !alias->merged_comdat)
kono
parents:
diff changeset
1348 {
kono
parents:
diff changeset
1349 if (dump_file)
kono
parents:
diff changeset
1350 fprintf (dump_file, "Dropping merged_comdat flag.\n\n");
kono
parents:
diff changeset
1351 if (local_original)
kono
parents:
diff changeset
1352 local_original->merged_comdat = false;
kono
parents:
diff changeset
1353 original->merged_comdat = false;
kono
parents:
diff changeset
1354 }
kono
parents:
diff changeset
1355
kono
parents:
diff changeset
1356 if (remove)
kono
parents:
diff changeset
1357 {
kono
parents:
diff changeset
1358 ipa_merge_profiles (original, alias);
kono
parents:
diff changeset
1359 alias->release_body ();
kono
parents:
diff changeset
1360 alias->reset ();
kono
parents:
diff changeset
1361 alias->body_removed = true;
kono
parents:
diff changeset
1362 alias->icf_merged = true;
kono
parents:
diff changeset
1363 if (dump_file)
kono
parents:
diff changeset
1364 fprintf (dump_file, "Unified; Function body was removed.\n");
kono
parents:
diff changeset
1365 }
kono
parents:
diff changeset
1366
kono
parents:
diff changeset
1367 return true;
kono
parents:
diff changeset
1368 }
kono
parents:
diff changeset
1369
kono
parents:
diff changeset
1370 /* Semantic item initialization function. */
kono
parents:
diff changeset
1371
kono
parents:
diff changeset
1372 void
kono
parents:
diff changeset
1373 sem_function::init (void)
kono
parents:
diff changeset
1374 {
kono
parents:
diff changeset
1375 if (in_lto_p)
kono
parents:
diff changeset
1376 get_node ()->get_untransformed_body ();
kono
parents:
diff changeset
1377
kono
parents:
diff changeset
1378 tree fndecl = node->decl;
kono
parents:
diff changeset
1379 function *func = DECL_STRUCT_FUNCTION (fndecl);
kono
parents:
diff changeset
1380
kono
parents:
diff changeset
1381 gcc_assert (func);
kono
parents:
diff changeset
1382 gcc_assert (SSANAMES (func));
kono
parents:
diff changeset
1383
kono
parents:
diff changeset
1384 ssa_names_size = SSANAMES (func)->length ();
kono
parents:
diff changeset
1385 node = node;
kono
parents:
diff changeset
1386
kono
parents:
diff changeset
1387 decl = fndecl;
kono
parents:
diff changeset
1388 region_tree = func->eh->region_tree;
kono
parents:
diff changeset
1389
kono
parents:
diff changeset
1390 /* iterating all function arguments. */
kono
parents:
diff changeset
1391 arg_count = count_formal_params (fndecl);
kono
parents:
diff changeset
1392
kono
parents:
diff changeset
1393 edge_count = n_edges_for_fn (func);
kono
parents:
diff changeset
1394 cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
kono
parents:
diff changeset
1395 if (!cnode->thunk.thunk_p)
kono
parents:
diff changeset
1396 {
kono
parents:
diff changeset
1397 cfg_checksum = coverage_compute_cfg_checksum (func);
kono
parents:
diff changeset
1398
kono
parents:
diff changeset
1399 inchash::hash hstate;
kono
parents:
diff changeset
1400
kono
parents:
diff changeset
1401 basic_block bb;
kono
parents:
diff changeset
1402 FOR_EACH_BB_FN (bb, func)
kono
parents:
diff changeset
1403 {
kono
parents:
diff changeset
1404 unsigned nondbg_stmt_count = 0;
kono
parents:
diff changeset
1405
kono
parents:
diff changeset
1406 edge e;
kono
parents:
diff changeset
1407 for (edge_iterator ei = ei_start (bb->preds); ei_cond (ei, &e);
kono
parents:
diff changeset
1408 ei_next (&ei))
kono
parents:
diff changeset
1409 cfg_checksum = iterative_hash_host_wide_int (e->flags,
kono
parents:
diff changeset
1410 cfg_checksum);
kono
parents:
diff changeset
1411
kono
parents:
diff changeset
1412 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
kono
parents:
diff changeset
1413 gsi_next (&gsi))
kono
parents:
diff changeset
1414 {
kono
parents:
diff changeset
1415 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1416
kono
parents:
diff changeset
1417 if (gimple_code (stmt) != GIMPLE_DEBUG
kono
parents:
diff changeset
1418 && gimple_code (stmt) != GIMPLE_PREDICT)
kono
parents:
diff changeset
1419 {
kono
parents:
diff changeset
1420 hash_stmt (stmt, hstate);
kono
parents:
diff changeset
1421 nondbg_stmt_count++;
kono
parents:
diff changeset
1422 }
kono
parents:
diff changeset
1423 }
kono
parents:
diff changeset
1424
kono
parents:
diff changeset
1425 hstate.commit_flag ();
kono
parents:
diff changeset
1426 gcode_hash = hstate.end ();
kono
parents:
diff changeset
1427 bb_sizes.safe_push (nondbg_stmt_count);
kono
parents:
diff changeset
1428
kono
parents:
diff changeset
1429 /* Inserting basic block to hash table. */
kono
parents:
diff changeset
1430 sem_bb *semantic_bb = new sem_bb (bb, nondbg_stmt_count,
kono
parents:
diff changeset
1431 EDGE_COUNT (bb->preds)
kono
parents:
diff changeset
1432 + EDGE_COUNT (bb->succs));
kono
parents:
diff changeset
1433
kono
parents:
diff changeset
1434 bb_sorted.safe_push (semantic_bb);
kono
parents:
diff changeset
1435 }
kono
parents:
diff changeset
1436 }
kono
parents:
diff changeset
1437 else
kono
parents:
diff changeset
1438 {
kono
parents:
diff changeset
1439 cfg_checksum = 0;
kono
parents:
diff changeset
1440 inchash::hash hstate;
kono
parents:
diff changeset
1441 hstate.add_hwi (cnode->thunk.fixed_offset);
kono
parents:
diff changeset
1442 hstate.add_hwi (cnode->thunk.virtual_value);
kono
parents:
diff changeset
1443 hstate.add_flag (cnode->thunk.this_adjusting);
kono
parents:
diff changeset
1444 hstate.add_flag (cnode->thunk.virtual_offset_p);
kono
parents:
diff changeset
1445 hstate.add_flag (cnode->thunk.add_pointer_bounds_args);
kono
parents:
diff changeset
1446 gcode_hash = hstate.end ();
kono
parents:
diff changeset
1447 }
kono
parents:
diff changeset
1448 }
kono
parents:
diff changeset
1449
kono
parents:
diff changeset
1450 /* Accumulate to HSTATE a hash of expression EXP.
kono
parents:
diff changeset
1451 Identical to inchash::add_expr, but guaranteed to be stable across LTO
kono
parents:
diff changeset
1452 and DECL equality classes. */
kono
parents:
diff changeset
1453
kono
parents:
diff changeset
1454 void
kono
parents:
diff changeset
1455 sem_item::add_expr (const_tree exp, inchash::hash &hstate)
kono
parents:
diff changeset
1456 {
kono
parents:
diff changeset
1457 if (exp == NULL_TREE)
kono
parents:
diff changeset
1458 {
kono
parents:
diff changeset
1459 hstate.merge_hash (0);
kono
parents:
diff changeset
1460 return;
kono
parents:
diff changeset
1461 }
kono
parents:
diff changeset
1462
kono
parents:
diff changeset
1463 /* Handled component can be matched in a cureful way proving equivalence
kono
parents:
diff changeset
1464 even if they syntactically differ. Just skip them. */
kono
parents:
diff changeset
1465 STRIP_NOPS (exp);
kono
parents:
diff changeset
1466 while (handled_component_p (exp))
kono
parents:
diff changeset
1467 exp = TREE_OPERAND (exp, 0);
kono
parents:
diff changeset
1468
kono
parents:
diff changeset
1469 enum tree_code code = TREE_CODE (exp);
kono
parents:
diff changeset
1470 hstate.add_int (code);
kono
parents:
diff changeset
1471
kono
parents:
diff changeset
1472 switch (code)
kono
parents:
diff changeset
1473 {
kono
parents:
diff changeset
1474 /* Use inchash::add_expr for everything that is LTO stable. */
kono
parents:
diff changeset
1475 case VOID_CST:
kono
parents:
diff changeset
1476 case INTEGER_CST:
kono
parents:
diff changeset
1477 case REAL_CST:
kono
parents:
diff changeset
1478 case FIXED_CST:
kono
parents:
diff changeset
1479 case STRING_CST:
kono
parents:
diff changeset
1480 case COMPLEX_CST:
kono
parents:
diff changeset
1481 case VECTOR_CST:
kono
parents:
diff changeset
1482 inchash::add_expr (exp, hstate);
kono
parents:
diff changeset
1483 break;
kono
parents:
diff changeset
1484 case CONSTRUCTOR:
kono
parents:
diff changeset
1485 {
kono
parents:
diff changeset
1486 unsigned HOST_WIDE_INT idx;
kono
parents:
diff changeset
1487 tree value;
kono
parents:
diff changeset
1488
kono
parents:
diff changeset
1489 hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
kono
parents:
diff changeset
1490
kono
parents:
diff changeset
1491 FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
kono
parents:
diff changeset
1492 if (value)
kono
parents:
diff changeset
1493 add_expr (value, hstate);
kono
parents:
diff changeset
1494 break;
kono
parents:
diff changeset
1495 }
kono
parents:
diff changeset
1496 case ADDR_EXPR:
kono
parents:
diff changeset
1497 case FDESC_EXPR:
kono
parents:
diff changeset
1498 add_expr (get_base_address (TREE_OPERAND (exp, 0)), hstate);
kono
parents:
diff changeset
1499 break;
kono
parents:
diff changeset
1500 case SSA_NAME:
kono
parents:
diff changeset
1501 case VAR_DECL:
kono
parents:
diff changeset
1502 case CONST_DECL:
kono
parents:
diff changeset
1503 case PARM_DECL:
kono
parents:
diff changeset
1504 hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
kono
parents:
diff changeset
1505 break;
kono
parents:
diff changeset
1506 case MEM_REF:
kono
parents:
diff changeset
1507 case POINTER_PLUS_EXPR:
kono
parents:
diff changeset
1508 case MINUS_EXPR:
kono
parents:
diff changeset
1509 case RANGE_EXPR:
kono
parents:
diff changeset
1510 add_expr (TREE_OPERAND (exp, 0), hstate);
kono
parents:
diff changeset
1511 add_expr (TREE_OPERAND (exp, 1), hstate);
kono
parents:
diff changeset
1512 break;
kono
parents:
diff changeset
1513 case PLUS_EXPR:
kono
parents:
diff changeset
1514 {
kono
parents:
diff changeset
1515 inchash::hash one, two;
kono
parents:
diff changeset
1516 add_expr (TREE_OPERAND (exp, 0), one);
kono
parents:
diff changeset
1517 add_expr (TREE_OPERAND (exp, 1), two);
kono
parents:
diff changeset
1518 hstate.add_commutative (one, two);
kono
parents:
diff changeset
1519 }
kono
parents:
diff changeset
1520 break;
kono
parents:
diff changeset
1521 CASE_CONVERT:
kono
parents:
diff changeset
1522 hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
kono
parents:
diff changeset
1523 return add_expr (TREE_OPERAND (exp, 0), hstate);
kono
parents:
diff changeset
1524 default:
kono
parents:
diff changeset
1525 break;
kono
parents:
diff changeset
1526 }
kono
parents:
diff changeset
1527 }
kono
parents:
diff changeset
1528
kono
parents:
diff changeset
1529 /* Accumulate to HSTATE a hash of type t.
kono
parents:
diff changeset
1530 TYpes that may end up being compatible after LTO type merging needs to have
kono
parents:
diff changeset
1531 the same hash. */
kono
parents:
diff changeset
1532
kono
parents:
diff changeset
1533 void
kono
parents:
diff changeset
1534 sem_item::add_type (const_tree type, inchash::hash &hstate)
kono
parents:
diff changeset
1535 {
kono
parents:
diff changeset
1536 if (type == NULL_TREE)
kono
parents:
diff changeset
1537 {
kono
parents:
diff changeset
1538 hstate.merge_hash (0);
kono
parents:
diff changeset
1539 return;
kono
parents:
diff changeset
1540 }
kono
parents:
diff changeset
1541
kono
parents:
diff changeset
1542 type = TYPE_MAIN_VARIANT (type);
kono
parents:
diff changeset
1543
kono
parents:
diff changeset
1544 hstate.add_int (TYPE_MODE (type));
kono
parents:
diff changeset
1545
kono
parents:
diff changeset
1546 if (TREE_CODE (type) == COMPLEX_TYPE)
kono
parents:
diff changeset
1547 {
kono
parents:
diff changeset
1548 hstate.add_int (COMPLEX_TYPE);
kono
parents:
diff changeset
1549 sem_item::add_type (TREE_TYPE (type), hstate);
kono
parents:
diff changeset
1550 }
kono
parents:
diff changeset
1551 else if (INTEGRAL_TYPE_P (type))
kono
parents:
diff changeset
1552 {
kono
parents:
diff changeset
1553 hstate.add_int (INTEGER_TYPE);
kono
parents:
diff changeset
1554 hstate.add_flag (TYPE_UNSIGNED (type));
kono
parents:
diff changeset
1555 hstate.add_int (TYPE_PRECISION (type));
kono
parents:
diff changeset
1556 }
kono
parents:
diff changeset
1557 else if (VECTOR_TYPE_P (type))
kono
parents:
diff changeset
1558 {
kono
parents:
diff changeset
1559 hstate.add_int (VECTOR_TYPE);
kono
parents:
diff changeset
1560 hstate.add_int (TYPE_PRECISION (type));
kono
parents:
diff changeset
1561 sem_item::add_type (TREE_TYPE (type), hstate);
kono
parents:
diff changeset
1562 }
kono
parents:
diff changeset
1563 else if (TREE_CODE (type) == ARRAY_TYPE)
kono
parents:
diff changeset
1564 {
kono
parents:
diff changeset
1565 hstate.add_int (ARRAY_TYPE);
kono
parents:
diff changeset
1566 /* Do not hash size, so complete and incomplete types can match. */
kono
parents:
diff changeset
1567 sem_item::add_type (TREE_TYPE (type), hstate);
kono
parents:
diff changeset
1568 }
kono
parents:
diff changeset
1569 else if (RECORD_OR_UNION_TYPE_P (type))
kono
parents:
diff changeset
1570 {
kono
parents:
diff changeset
1571 gcc_checking_assert (COMPLETE_TYPE_P (type));
kono
parents:
diff changeset
1572 hashval_t *val = optimizer->m_type_hash_cache.get (type);
kono
parents:
diff changeset
1573
kono
parents:
diff changeset
1574 if (!val)
kono
parents:
diff changeset
1575 {
kono
parents:
diff changeset
1576 inchash::hash hstate2;
kono
parents:
diff changeset
1577 unsigned nf;
kono
parents:
diff changeset
1578 tree f;
kono
parents:
diff changeset
1579 hashval_t hash;
kono
parents:
diff changeset
1580
kono
parents:
diff changeset
1581 hstate2.add_int (RECORD_TYPE);
kono
parents:
diff changeset
1582 gcc_assert (COMPLETE_TYPE_P (type));
kono
parents:
diff changeset
1583
kono
parents:
diff changeset
1584 for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f))
kono
parents:
diff changeset
1585 if (TREE_CODE (f) == FIELD_DECL)
kono
parents:
diff changeset
1586 {
kono
parents:
diff changeset
1587 add_type (TREE_TYPE (f), hstate2);
kono
parents:
diff changeset
1588 nf++;
kono
parents:
diff changeset
1589 }
kono
parents:
diff changeset
1590
kono
parents:
diff changeset
1591 hstate2.add_int (nf);
kono
parents:
diff changeset
1592 hash = hstate2.end ();
kono
parents:
diff changeset
1593 hstate.add_hwi (hash);
kono
parents:
diff changeset
1594 optimizer->m_type_hash_cache.put (type, hash);
kono
parents:
diff changeset
1595 }
kono
parents:
diff changeset
1596 else
kono
parents:
diff changeset
1597 hstate.add_hwi (*val);
kono
parents:
diff changeset
1598 }
kono
parents:
diff changeset
1599 }
kono
parents:
diff changeset
1600
kono
parents:
diff changeset
1601 /* Improve accumulated hash for HSTATE based on a gimple statement STMT. */
kono
parents:
diff changeset
1602
kono
parents:
diff changeset
1603 void
kono
parents:
diff changeset
1604 sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
kono
parents:
diff changeset
1605 {
kono
parents:
diff changeset
1606 enum gimple_code code = gimple_code (stmt);
kono
parents:
diff changeset
1607
kono
parents:
diff changeset
1608 hstate.add_int (code);
kono
parents:
diff changeset
1609
kono
parents:
diff changeset
1610 switch (code)
kono
parents:
diff changeset
1611 {
kono
parents:
diff changeset
1612 case GIMPLE_SWITCH:
kono
parents:
diff changeset
1613 add_expr (gimple_switch_index (as_a <gswitch *> (stmt)), hstate);
kono
parents:
diff changeset
1614 break;
kono
parents:
diff changeset
1615 case GIMPLE_ASSIGN:
kono
parents:
diff changeset
1616 hstate.add_int (gimple_assign_rhs_code (stmt));
kono
parents:
diff changeset
1617 if (commutative_tree_code (gimple_assign_rhs_code (stmt))
kono
parents:
diff changeset
1618 || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
kono
parents:
diff changeset
1619 {
kono
parents:
diff changeset
1620 inchash::hash one, two;
kono
parents:
diff changeset
1621
kono
parents:
diff changeset
1622 add_expr (gimple_assign_rhs1 (stmt), one);
kono
parents:
diff changeset
1623 add_type (TREE_TYPE (gimple_assign_rhs1 (stmt)), one);
kono
parents:
diff changeset
1624 add_expr (gimple_assign_rhs2 (stmt), two);
kono
parents:
diff changeset
1625 hstate.add_commutative (one, two);
kono
parents:
diff changeset
1626 if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
kono
parents:
diff changeset
1627 {
kono
parents:
diff changeset
1628 add_expr (gimple_assign_rhs3 (stmt), hstate);
kono
parents:
diff changeset
1629 add_type (TREE_TYPE (gimple_assign_rhs3 (stmt)), hstate);
kono
parents:
diff changeset
1630 }
kono
parents:
diff changeset
1631 add_expr (gimple_assign_lhs (stmt), hstate);
kono
parents:
diff changeset
1632 add_type (TREE_TYPE (gimple_assign_lhs (stmt)), two);
kono
parents:
diff changeset
1633 break;
kono
parents:
diff changeset
1634 }
kono
parents:
diff changeset
1635 /* fall through */
kono
parents:
diff changeset
1636 case GIMPLE_CALL:
kono
parents:
diff changeset
1637 case GIMPLE_ASM:
kono
parents:
diff changeset
1638 case GIMPLE_COND:
kono
parents:
diff changeset
1639 case GIMPLE_GOTO:
kono
parents:
diff changeset
1640 case GIMPLE_RETURN:
kono
parents:
diff changeset
1641 /* All these statements are equivalent if their operands are. */
kono
parents:
diff changeset
1642 for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
kono
parents:
diff changeset
1643 {
kono
parents:
diff changeset
1644 add_expr (gimple_op (stmt, i), hstate);
kono
parents:
diff changeset
1645 if (gimple_op (stmt, i))
kono
parents:
diff changeset
1646 add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
kono
parents:
diff changeset
1647 }
kono
parents:
diff changeset
1648 /* Consider nocf_check attribute in hash as it affects code
kono
parents:
diff changeset
1649 generation. */
kono
parents:
diff changeset
1650 if (code == GIMPLE_CALL
kono
parents:
diff changeset
1651 && flag_cf_protection & CF_BRANCH)
kono
parents:
diff changeset
1652 hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
kono
parents:
diff changeset
1653 default:
kono
parents:
diff changeset
1654 break;
kono
parents:
diff changeset
1655 }
kono
parents:
diff changeset
1656 }
kono
parents:
diff changeset
1657
kono
parents:
diff changeset
1658
kono
parents:
diff changeset
1659 /* Return true if polymorphic comparison must be processed. */
kono
parents:
diff changeset
1660
kono
parents:
diff changeset
1661 bool
kono
parents:
diff changeset
1662 sem_function::compare_polymorphic_p (void)
kono
parents:
diff changeset
1663 {
kono
parents:
diff changeset
1664 struct cgraph_edge *e;
kono
parents:
diff changeset
1665
kono
parents:
diff changeset
1666 if (!opt_for_fn (get_node ()->decl, flag_devirtualize))
kono
parents:
diff changeset
1667 return false;
kono
parents:
diff changeset
1668 if (get_node ()->indirect_calls != NULL)
kono
parents:
diff changeset
1669 return true;
kono
parents:
diff changeset
1670 /* TODO: We can do simple propagation determining what calls may lead to
kono
parents:
diff changeset
1671 a polymorphic call. */
kono
parents:
diff changeset
1672 for (e = get_node ()->callees; e; e = e->next_callee)
kono
parents:
diff changeset
1673 if (e->callee->definition
kono
parents:
diff changeset
1674 && opt_for_fn (e->callee->decl, flag_devirtualize))
kono
parents:
diff changeset
1675 return true;
kono
parents:
diff changeset
1676 return false;
kono
parents:
diff changeset
1677 }
kono
parents:
diff changeset
1678
kono
parents:
diff changeset
1679 /* For a given call graph NODE, the function constructs new
kono
parents:
diff changeset
1680 semantic function item. */
kono
parents:
diff changeset
1681
kono
parents:
diff changeset
1682 sem_function *
kono
parents:
diff changeset
1683 sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
kono
parents:
diff changeset
1684 {
kono
parents:
diff changeset
1685 tree fndecl = node->decl;
kono
parents:
diff changeset
1686 function *func = DECL_STRUCT_FUNCTION (fndecl);
kono
parents:
diff changeset
1687
kono
parents:
diff changeset
1688 if (!func || (!node->has_gimple_body_p () && !node->thunk.thunk_p))
kono
parents:
diff changeset
1689 return NULL;
kono
parents:
diff changeset
1690
kono
parents:
diff changeset
1691 if (lookup_attribute_by_prefix ("omp ", DECL_ATTRIBUTES (node->decl)) != NULL)
kono
parents:
diff changeset
1692 return NULL;
kono
parents:
diff changeset
1693
kono
parents:
diff changeset
1694 if (lookup_attribute_by_prefix ("oacc ",
kono
parents:
diff changeset
1695 DECL_ATTRIBUTES (node->decl)) != NULL)
kono
parents:
diff changeset
1696 return NULL;
kono
parents:
diff changeset
1697
kono
parents:
diff changeset
1698 /* PR ipa/70306. */
kono
parents:
diff changeset
1699 if (DECL_STATIC_CONSTRUCTOR (node->decl)
kono
parents:
diff changeset
1700 || DECL_STATIC_DESTRUCTOR (node->decl))
kono
parents:
diff changeset
1701 return NULL;
kono
parents:
diff changeset
1702
kono
parents:
diff changeset
1703 sem_function *f = new sem_function (node, stack);
kono
parents:
diff changeset
1704
kono
parents:
diff changeset
1705 f->init ();
kono
parents:
diff changeset
1706
kono
parents:
diff changeset
1707 return f;
kono
parents:
diff changeset
1708 }
kono
parents:
diff changeset
1709
kono
parents:
diff changeset
1710 /* For given basic blocks BB1 and BB2 (from functions FUNC1 and FUNC),
kono
parents:
diff changeset
1711 return true if phi nodes are semantically equivalent in these blocks . */
kono
parents:
diff changeset
1712
kono
parents:
diff changeset
1713 bool
kono
parents:
diff changeset
1714 sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
kono
parents:
diff changeset
1715 {
kono
parents:
diff changeset
1716 gphi_iterator si1, si2;
kono
parents:
diff changeset
1717 gphi *phi1, *phi2;
kono
parents:
diff changeset
1718 unsigned size1, size2, i;
kono
parents:
diff changeset
1719 tree t1, t2;
kono
parents:
diff changeset
1720 edge e1, e2;
kono
parents:
diff changeset
1721
kono
parents:
diff changeset
1722 gcc_assert (bb1 != NULL);
kono
parents:
diff changeset
1723 gcc_assert (bb2 != NULL);
kono
parents:
diff changeset
1724
kono
parents:
diff changeset
1725 si2 = gsi_start_phis (bb2);
kono
parents:
diff changeset
1726 for (si1 = gsi_start_phis (bb1); !gsi_end_p (si1);
kono
parents:
diff changeset
1727 gsi_next (&si1))
kono
parents:
diff changeset
1728 {
kono
parents:
diff changeset
1729 gsi_next_nonvirtual_phi (&si1);
kono
parents:
diff changeset
1730 gsi_next_nonvirtual_phi (&si2);
kono
parents:
diff changeset
1731
kono
parents:
diff changeset
1732 if (gsi_end_p (si1) && gsi_end_p (si2))
kono
parents:
diff changeset
1733 break;
kono
parents:
diff changeset
1734
kono
parents:
diff changeset
1735 if (gsi_end_p (si1) || gsi_end_p (si2))
kono
parents:
diff changeset
1736 return return_false();
kono
parents:
diff changeset
1737
kono
parents:
diff changeset
1738 phi1 = si1.phi ();
kono
parents:
diff changeset
1739 phi2 = si2.phi ();
kono
parents:
diff changeset
1740
kono
parents:
diff changeset
1741 tree phi_result1 = gimple_phi_result (phi1);
kono
parents:
diff changeset
1742 tree phi_result2 = gimple_phi_result (phi2);
kono
parents:
diff changeset
1743
kono
parents:
diff changeset
1744 if (!m_checker->compare_operand (phi_result1, phi_result2))
kono
parents:
diff changeset
1745 return return_false_with_msg ("PHI results are different");
kono
parents:
diff changeset
1746
kono
parents:
diff changeset
1747 size1 = gimple_phi_num_args (phi1);
kono
parents:
diff changeset
1748 size2 = gimple_phi_num_args (phi2);
kono
parents:
diff changeset
1749
kono
parents:
diff changeset
1750 if (size1 != size2)
kono
parents:
diff changeset
1751 return return_false ();
kono
parents:
diff changeset
1752
kono
parents:
diff changeset
1753 for (i = 0; i < size1; ++i)
kono
parents:
diff changeset
1754 {
kono
parents:
diff changeset
1755 t1 = gimple_phi_arg (phi1, i)->def;
kono
parents:
diff changeset
1756 t2 = gimple_phi_arg (phi2, i)->def;
kono
parents:
diff changeset
1757
kono
parents:
diff changeset
1758 if (!m_checker->compare_operand (t1, t2))
kono
parents:
diff changeset
1759 return return_false ();
kono
parents:
diff changeset
1760
kono
parents:
diff changeset
1761 e1 = gimple_phi_arg_edge (phi1, i);
kono
parents:
diff changeset
1762 e2 = gimple_phi_arg_edge (phi2, i);
kono
parents:
diff changeset
1763
kono
parents:
diff changeset
1764 if (!m_checker->compare_edge (e1, e2))
kono
parents:
diff changeset
1765 return return_false ();
kono
parents:
diff changeset
1766 }
kono
parents:
diff changeset
1767
kono
parents:
diff changeset
1768 gsi_next (&si2);
kono
parents:
diff changeset
1769 }
kono
parents:
diff changeset
1770
kono
parents:
diff changeset
1771 return true;
kono
parents:
diff changeset
1772 }
kono
parents:
diff changeset
1773
kono
parents:
diff changeset
1774 /* Returns true if tree T can be compared as a handled component. */
kono
parents:
diff changeset
1775
kono
parents:
diff changeset
1776 bool
kono
parents:
diff changeset
1777 sem_function::icf_handled_component_p (tree t)
kono
parents:
diff changeset
1778 {
kono
parents:
diff changeset
1779 tree_code tc = TREE_CODE (t);
kono
parents:
diff changeset
1780
kono
parents:
diff changeset
1781 return (handled_component_p (t)
kono
parents:
diff changeset
1782 || tc == ADDR_EXPR || tc == MEM_REF || tc == OBJ_TYPE_REF);
kono
parents:
diff changeset
1783 }
kono
parents:
diff changeset
1784
kono
parents:
diff changeset
1785 /* Basic blocks dictionary BB_DICT returns true if SOURCE index BB
kono
parents:
diff changeset
1786 corresponds to TARGET. */
kono
parents:
diff changeset
1787
kono
parents:
diff changeset
1788 bool
kono
parents:
diff changeset
1789 sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
kono
parents:
diff changeset
1790 {
kono
parents:
diff changeset
1791 source++;
kono
parents:
diff changeset
1792 target++;
kono
parents:
diff changeset
1793
kono
parents:
diff changeset
1794 if (bb_dict->length () <= (unsigned)source)
kono
parents:
diff changeset
1795 bb_dict->safe_grow_cleared (source + 1);
kono
parents:
diff changeset
1796
kono
parents:
diff changeset
1797 if ((*bb_dict)[source] == 0)
kono
parents:
diff changeset
1798 {
kono
parents:
diff changeset
1799 (*bb_dict)[source] = target;
kono
parents:
diff changeset
1800 return true;
kono
parents:
diff changeset
1801 }
kono
parents:
diff changeset
1802 else
kono
parents:
diff changeset
1803 return (*bb_dict)[source] == target;
kono
parents:
diff changeset
1804 }
kono
parents:
diff changeset
1805
kono
parents:
diff changeset
1806 sem_variable::sem_variable (bitmap_obstack *stack): sem_item (VAR, stack)
kono
parents:
diff changeset
1807 {
kono
parents:
diff changeset
1808 }
kono
parents:
diff changeset
1809
kono
parents:
diff changeset
1810 sem_variable::sem_variable (varpool_node *node, bitmap_obstack *stack)
kono
parents:
diff changeset
1811 : sem_item (VAR, node, stack)
kono
parents:
diff changeset
1812 {
kono
parents:
diff changeset
1813 gcc_checking_assert (node);
kono
parents:
diff changeset
1814 gcc_checking_assert (get_node ());
kono
parents:
diff changeset
1815 }
kono
parents:
diff changeset
1816
kono
parents:
diff changeset
1817 /* Fast equality function based on knowledge known in WPA. */
kono
parents:
diff changeset
1818
kono
parents:
diff changeset
1819 bool
kono
parents:
diff changeset
1820 sem_variable::equals_wpa (sem_item *item,
kono
parents:
diff changeset
1821 hash_map <symtab_node *, sem_item *> &ignored_nodes)
kono
parents:
diff changeset
1822 {
kono
parents:
diff changeset
1823 gcc_assert (item->type == VAR);
kono
parents:
diff changeset
1824
kono
parents:
diff changeset
1825 if (node->num_references () != item->node->num_references ())
kono
parents:
diff changeset
1826 return return_false_with_msg ("different number of references");
kono
parents:
diff changeset
1827
kono
parents:
diff changeset
1828 if (DECL_TLS_MODEL (decl) || DECL_TLS_MODEL (item->decl))
kono
parents:
diff changeset
1829 return return_false_with_msg ("TLS model");
kono
parents:
diff changeset
1830
kono
parents:
diff changeset
1831 /* DECL_ALIGN is safe to merge, because we will always chose the largest
kono
parents:
diff changeset
1832 alignment out of all aliases. */
kono
parents:
diff changeset
1833
kono
parents:
diff changeset
1834 if (DECL_VIRTUAL_P (decl) != DECL_VIRTUAL_P (item->decl))
kono
parents:
diff changeset
1835 return return_false_with_msg ("Virtual flag mismatch");
kono
parents:
diff changeset
1836
kono
parents:
diff changeset
1837 if (DECL_SIZE (decl) != DECL_SIZE (item->decl)
kono
parents:
diff changeset
1838 && ((!DECL_SIZE (decl) || !DECL_SIZE (item->decl))
kono
parents:
diff changeset
1839 || !operand_equal_p (DECL_SIZE (decl),
kono
parents:
diff changeset
1840 DECL_SIZE (item->decl), OEP_ONLY_CONST)))
kono
parents:
diff changeset
1841 return return_false_with_msg ("size mismatch");
kono
parents:
diff changeset
1842
kono
parents:
diff changeset
1843 /* Do not attempt to mix data from different user sections;
kono
parents:
diff changeset
1844 we do not know what user intends with those. */
kono
parents:
diff changeset
1845 if (((DECL_SECTION_NAME (decl) && !node->implicit_section)
kono
parents:
diff changeset
1846 || (DECL_SECTION_NAME (item->decl) && !item->node->implicit_section))
kono
parents:
diff changeset
1847 && DECL_SECTION_NAME (decl) != DECL_SECTION_NAME (item->decl))
kono
parents:
diff changeset
1848 return return_false_with_msg ("user section mismatch");
kono
parents:
diff changeset
1849
kono
parents:
diff changeset
1850 if (DECL_IN_TEXT_SECTION (decl) != DECL_IN_TEXT_SECTION (item->decl))
kono
parents:
diff changeset
1851 return return_false_with_msg ("text section");
kono
parents:
diff changeset
1852
kono
parents:
diff changeset
1853 ipa_ref *ref = NULL, *ref2 = NULL;
kono
parents:
diff changeset
1854 for (unsigned i = 0; node->iterate_reference (i, ref); i++)
kono
parents:
diff changeset
1855 {
kono
parents:
diff changeset
1856 item->node->iterate_reference (i, ref2);
kono
parents:
diff changeset
1857
kono
parents:
diff changeset
1858 if (ref->use != ref2->use)
kono
parents:
diff changeset
1859 return return_false_with_msg ("reference use mismatch");
kono
parents:
diff changeset
1860
kono
parents:
diff changeset
1861 if (!compare_symbol_references (ignored_nodes,
kono
parents:
diff changeset
1862 ref->referred, ref2->referred,
kono
parents:
diff changeset
1863 ref->address_matters_p ()))
kono
parents:
diff changeset
1864 return false;
kono
parents:
diff changeset
1865 }
kono
parents:
diff changeset
1866
kono
parents:
diff changeset
1867 return true;
kono
parents:
diff changeset
1868 }
kono
parents:
diff changeset
1869
kono
parents:
diff changeset
1870 /* Returns true if the item equals to ITEM given as argument. */
kono
parents:
diff changeset
1871
kono
parents:
diff changeset
1872 bool
kono
parents:
diff changeset
1873 sem_variable::equals (sem_item *item,
kono
parents:
diff changeset
1874 hash_map <symtab_node *, sem_item *> &)
kono
parents:
diff changeset
1875 {
kono
parents:
diff changeset
1876 gcc_assert (item->type == VAR);
kono
parents:
diff changeset
1877 bool ret;
kono
parents:
diff changeset
1878
kono
parents:
diff changeset
1879 if (DECL_INITIAL (decl) == error_mark_node && in_lto_p)
kono
parents:
diff changeset
1880 dyn_cast <varpool_node *>(node)->get_constructor ();
kono
parents:
diff changeset
1881 if (DECL_INITIAL (item->decl) == error_mark_node && in_lto_p)
kono
parents:
diff changeset
1882 dyn_cast <varpool_node *>(item->node)->get_constructor ();
kono
parents:
diff changeset
1883
kono
parents:
diff changeset
1884 /* As seen in PR ipa/65303 we have to compare variables types. */
kono
parents:
diff changeset
1885 if (!func_checker::compatible_types_p (TREE_TYPE (decl),
kono
parents:
diff changeset
1886 TREE_TYPE (item->decl)))
kono
parents:
diff changeset
1887 return return_false_with_msg ("variables types are different");
kono
parents:
diff changeset
1888
kono
parents:
diff changeset
1889 ret = sem_variable::equals (DECL_INITIAL (decl),
kono
parents:
diff changeset
1890 DECL_INITIAL (item->node->decl));
kono
parents:
diff changeset
1891 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
1892 fprintf (dump_file,
kono
parents:
diff changeset
1893 "Equals called for vars: %s:%s with result: %s\n\n",
kono
parents:
diff changeset
1894 node->dump_name (), item->node->dump_name (),
kono
parents:
diff changeset
1895 ret ? "true" : "false");
kono
parents:
diff changeset
1896
kono
parents:
diff changeset
1897 return ret;
kono
parents:
diff changeset
1898 }
kono
parents:
diff changeset
1899
kono
parents:
diff changeset
1900 /* Compares trees T1 and T2 for semantic equality. */
kono
parents:
diff changeset
1901
kono
parents:
diff changeset
1902 bool
kono
parents:
diff changeset
1903 sem_variable::equals (tree t1, tree t2)
kono
parents:
diff changeset
1904 {
kono
parents:
diff changeset
1905 if (!t1 || !t2)
kono
parents:
diff changeset
1906 return return_with_debug (t1 == t2);
kono
parents:
diff changeset
1907 if (t1 == t2)
kono
parents:
diff changeset
1908 return true;
kono
parents:
diff changeset
1909 tree_code tc1 = TREE_CODE (t1);
kono
parents:
diff changeset
1910 tree_code tc2 = TREE_CODE (t2);
kono
parents:
diff changeset
1911
kono
parents:
diff changeset
1912 if (tc1 != tc2)
kono
parents:
diff changeset
1913 return return_false_with_msg ("TREE_CODE mismatch");
kono
parents:
diff changeset
1914
kono
parents:
diff changeset
1915 switch (tc1)
kono
parents:
diff changeset
1916 {
kono
parents:
diff changeset
1917 case CONSTRUCTOR:
kono
parents:
diff changeset
1918 {
kono
parents:
diff changeset
1919 vec<constructor_elt, va_gc> *v1, *v2;
kono
parents:
diff changeset
1920 unsigned HOST_WIDE_INT idx;
kono
parents:
diff changeset
1921
kono
parents:
diff changeset
1922 enum tree_code typecode = TREE_CODE (TREE_TYPE (t1));
kono
parents:
diff changeset
1923 if (typecode != TREE_CODE (TREE_TYPE (t2)))
kono
parents:
diff changeset
1924 return return_false_with_msg ("constructor type mismatch");
kono
parents:
diff changeset
1925
kono
parents:
diff changeset
1926 if (typecode == ARRAY_TYPE)
kono
parents:
diff changeset
1927 {
kono
parents:
diff changeset
1928 HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
kono
parents:
diff changeset
1929 /* For arrays, check that the sizes all match. */
kono
parents:
diff changeset
1930 if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
kono
parents:
diff changeset
1931 || size_1 == -1
kono
parents:
diff changeset
1932 || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
kono
parents:
diff changeset
1933 return return_false_with_msg ("constructor array size mismatch");
kono
parents:
diff changeset
1934 }
kono
parents:
diff changeset
1935 else if (!func_checker::compatible_types_p (TREE_TYPE (t1),
kono
parents:
diff changeset
1936 TREE_TYPE (t2)))
kono
parents:
diff changeset
1937 return return_false_with_msg ("constructor type incompatible");
kono
parents:
diff changeset
1938
kono
parents:
diff changeset
1939 v1 = CONSTRUCTOR_ELTS (t1);
kono
parents:
diff changeset
1940 v2 = CONSTRUCTOR_ELTS (t2);
kono
parents:
diff changeset
1941 if (vec_safe_length (v1) != vec_safe_length (v2))
kono
parents:
diff changeset
1942 return return_false_with_msg ("constructor number of elts mismatch");
kono
parents:
diff changeset
1943
kono
parents:
diff changeset
1944 for (idx = 0; idx < vec_safe_length (v1); ++idx)
kono
parents:
diff changeset
1945 {
kono
parents:
diff changeset
1946 constructor_elt *c1 = &(*v1)[idx];
kono
parents:
diff changeset
1947 constructor_elt *c2 = &(*v2)[idx];
kono
parents:
diff changeset
1948
kono
parents:
diff changeset
1949 /* Check that each value is the same... */
kono
parents:
diff changeset
1950 if (!sem_variable::equals (c1->value, c2->value))
kono
parents:
diff changeset
1951 return false;
kono
parents:
diff changeset
1952 /* ... and that they apply to the same fields! */
kono
parents:
diff changeset
1953 if (!sem_variable::equals (c1->index, c2->index))
kono
parents:
diff changeset
1954 return false;
kono
parents:
diff changeset
1955 }
kono
parents:
diff changeset
1956 return true;
kono
parents:
diff changeset
1957 }
kono
parents:
diff changeset
1958 case MEM_REF:
kono
parents:
diff changeset
1959 {
kono
parents:
diff changeset
1960 tree x1 = TREE_OPERAND (t1, 0);
kono
parents:
diff changeset
1961 tree x2 = TREE_OPERAND (t2, 0);
kono
parents:
diff changeset
1962 tree y1 = TREE_OPERAND (t1, 1);
kono
parents:
diff changeset
1963 tree y2 = TREE_OPERAND (t2, 1);
kono
parents:
diff changeset
1964
kono
parents:
diff changeset
1965 if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
kono
parents:
diff changeset
1966 return return_false ();
kono
parents:
diff changeset
1967
kono
parents:
diff changeset
1968 /* Type of the offset on MEM_REF does not matter. */
kono
parents:
diff changeset
1969 return return_with_debug (sem_variable::equals (x1, x2)
kono
parents:
diff changeset
1970 && wi::to_offset (y1)
kono
parents:
diff changeset
1971 == wi::to_offset (y2));
kono
parents:
diff changeset
1972 }
kono
parents:
diff changeset
1973 case ADDR_EXPR:
kono
parents:
diff changeset
1974 case FDESC_EXPR:
kono
parents:
diff changeset
1975 {
kono
parents:
diff changeset
1976 tree op1 = TREE_OPERAND (t1, 0);
kono
parents:
diff changeset
1977 tree op2 = TREE_OPERAND (t2, 0);
kono
parents:
diff changeset
1978 return sem_variable::equals (op1, op2);
kono
parents:
diff changeset
1979 }
kono
parents:
diff changeset
1980 /* References to other vars/decls are compared using ipa-ref. */
kono
parents:
diff changeset
1981 case FUNCTION_DECL:
kono
parents:
diff changeset
1982 case VAR_DECL:
kono
parents:
diff changeset
1983 if (decl_in_symtab_p (t1) && decl_in_symtab_p (t2))
kono
parents:
diff changeset
1984 return true;
kono
parents:
diff changeset
1985 return return_false_with_msg ("Declaration mismatch");
kono
parents:
diff changeset
1986 case CONST_DECL:
kono
parents:
diff changeset
1987 /* TODO: We can check CONST_DECL by its DECL_INITIAL, but for that we
kono
parents:
diff changeset
1988 need to process its VAR/FUNCTION references without relying on ipa-ref
kono
parents:
diff changeset
1989 compare. */
kono
parents:
diff changeset
1990 case FIELD_DECL:
kono
parents:
diff changeset
1991 case LABEL_DECL:
kono
parents:
diff changeset
1992 return return_false_with_msg ("Declaration mismatch");
kono
parents:
diff changeset
1993 case INTEGER_CST:
kono
parents:
diff changeset
1994 /* Integer constants are the same only if the same width of type. */
kono
parents:
diff changeset
1995 if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
kono
parents:
diff changeset
1996 return return_false_with_msg ("INTEGER_CST precision mismatch");
kono
parents:
diff changeset
1997 if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
kono
parents:
diff changeset
1998 return return_false_with_msg ("INTEGER_CST mode mismatch");
kono
parents:
diff changeset
1999 return return_with_debug (tree_int_cst_equal (t1, t2));
kono
parents:
diff changeset
2000 case STRING_CST:
kono
parents:
diff changeset
2001 if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
kono
parents:
diff changeset
2002 return return_false_with_msg ("STRING_CST mode mismatch");
kono
parents:
diff changeset
2003 if (TREE_STRING_LENGTH (t1) != TREE_STRING_LENGTH (t2))
kono
parents:
diff changeset
2004 return return_false_with_msg ("STRING_CST length mismatch");
kono
parents:
diff changeset
2005 if (memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
kono
parents:
diff changeset
2006 TREE_STRING_LENGTH (t1)))
kono
parents:
diff changeset
2007 return return_false_with_msg ("STRING_CST mismatch");
kono
parents:
diff changeset
2008 return true;
kono
parents:
diff changeset
2009 case FIXED_CST:
kono
parents:
diff changeset
2010 /* Fixed constants are the same only if the same width of type. */
kono
parents:
diff changeset
2011 if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
kono
parents:
diff changeset
2012 return return_false_with_msg ("FIXED_CST precision mismatch");
kono
parents:
diff changeset
2013
kono
parents:
diff changeset
2014 return return_with_debug (FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1),
kono
parents:
diff changeset
2015 TREE_FIXED_CST (t2)));
kono
parents:
diff changeset
2016 case COMPLEX_CST:
kono
parents:
diff changeset
2017 return (sem_variable::equals (TREE_REALPART (t1), TREE_REALPART (t2))
kono
parents:
diff changeset
2018 && sem_variable::equals (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
kono
parents:
diff changeset
2019 case REAL_CST:
kono
parents:
diff changeset
2020 /* Real constants are the same only if the same width of type. */
kono
parents:
diff changeset
2021 if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
kono
parents:
diff changeset
2022 return return_false_with_msg ("REAL_CST precision mismatch");
kono
parents:
diff changeset
2023 return return_with_debug (real_identical (&TREE_REAL_CST (t1),
kono
parents:
diff changeset
2024 &TREE_REAL_CST (t2)));
kono
parents:
diff changeset
2025 case VECTOR_CST:
kono
parents:
diff changeset
2026 {
kono
parents:
diff changeset
2027 unsigned i;
kono
parents:
diff changeset
2028
kono
parents:
diff changeset
2029 if (VECTOR_CST_NELTS (t1) != VECTOR_CST_NELTS (t2))
kono
parents:
diff changeset
2030 return return_false_with_msg ("VECTOR_CST nelts mismatch");
kono
parents:
diff changeset
2031
kono
parents:
diff changeset
2032 for (i = 0; i < VECTOR_CST_NELTS (t1); ++i)
kono
parents:
diff changeset
2033 if (!sem_variable::equals (VECTOR_CST_ELT (t1, i),
kono
parents:
diff changeset
2034 VECTOR_CST_ELT (t2, i)))
kono
parents:
diff changeset
2035 return 0;
kono
parents:
diff changeset
2036
kono
parents:
diff changeset
2037 return 1;
kono
parents:
diff changeset
2038 }
kono
parents:
diff changeset
2039 case ARRAY_REF:
kono
parents:
diff changeset
2040 case ARRAY_RANGE_REF:
kono
parents:
diff changeset
2041 {
kono
parents:
diff changeset
2042 tree x1 = TREE_OPERAND (t1, 0);
kono
parents:
diff changeset
2043 tree x2 = TREE_OPERAND (t2, 0);
kono
parents:
diff changeset
2044 tree y1 = TREE_OPERAND (t1, 1);
kono
parents:
diff changeset
2045 tree y2 = TREE_OPERAND (t2, 1);
kono
parents:
diff changeset
2046
kono
parents:
diff changeset
2047 if (!sem_variable::equals (x1, x2) || !sem_variable::equals (y1, y2))
kono
parents:
diff changeset
2048 return false;
kono
parents:
diff changeset
2049 if (!sem_variable::equals (array_ref_low_bound (t1),
kono
parents:
diff changeset
2050 array_ref_low_bound (t2)))
kono
parents:
diff changeset
2051 return false;
kono
parents:
diff changeset
2052 if (!sem_variable::equals (array_ref_element_size (t1),
kono
parents:
diff changeset
2053 array_ref_element_size (t2)))
kono
parents:
diff changeset
2054 return false;
kono
parents:
diff changeset
2055 return true;
kono
parents:
diff changeset
2056 }
kono
parents:
diff changeset
2057
kono
parents:
diff changeset
2058 case COMPONENT_REF:
kono
parents:
diff changeset
2059 case POINTER_PLUS_EXPR:
kono
parents:
diff changeset
2060 case PLUS_EXPR:
kono
parents:
diff changeset
2061 case MINUS_EXPR:
kono
parents:
diff changeset
2062 case RANGE_EXPR:
kono
parents:
diff changeset
2063 {
kono
parents:
diff changeset
2064 tree x1 = TREE_OPERAND (t1, 0);
kono
parents:
diff changeset
2065 tree x2 = TREE_OPERAND (t2, 0);
kono
parents:
diff changeset
2066 tree y1 = TREE_OPERAND (t1, 1);
kono
parents:
diff changeset
2067 tree y2 = TREE_OPERAND (t2, 1);
kono
parents:
diff changeset
2068
kono
parents:
diff changeset
2069 return sem_variable::equals (x1, x2) && sem_variable::equals (y1, y2);
kono
parents:
diff changeset
2070 }
kono
parents:
diff changeset
2071
kono
parents:
diff changeset
2072 CASE_CONVERT:
kono
parents:
diff changeset
2073 case VIEW_CONVERT_EXPR:
kono
parents:
diff changeset
2074 if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
kono
parents:
diff changeset
2075 return return_false ();
kono
parents:
diff changeset
2076 return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
kono
parents:
diff changeset
2077 case ERROR_MARK:
kono
parents:
diff changeset
2078 return return_false_with_msg ("ERROR_MARK");
kono
parents:
diff changeset
2079 default:
kono
parents:
diff changeset
2080 return return_false_with_msg ("Unknown TREE code reached");
kono
parents:
diff changeset
2081 }
kono
parents:
diff changeset
2082 }
kono
parents:
diff changeset
2083
kono
parents:
diff changeset
2084 /* Parser function that visits a varpool NODE. */
kono
parents:
diff changeset
2085
kono
parents:
diff changeset
2086 sem_variable *
kono
parents:
diff changeset
2087 sem_variable::parse (varpool_node *node, bitmap_obstack *stack)
kono
parents:
diff changeset
2088 {
kono
parents:
diff changeset
2089 if (TREE_THIS_VOLATILE (node->decl) || DECL_HARD_REGISTER (node->decl)
kono
parents:
diff changeset
2090 || node->alias)
kono
parents:
diff changeset
2091 return NULL;
kono
parents:
diff changeset
2092
kono
parents:
diff changeset
2093 sem_variable *v = new sem_variable (node, stack);
kono
parents:
diff changeset
2094
kono
parents:
diff changeset
2095 v->init ();
kono
parents:
diff changeset
2096
kono
parents:
diff changeset
2097 return v;
kono
parents:
diff changeset
2098 }
kono
parents:
diff changeset
2099
kono
parents:
diff changeset
2100 /* References independent hash function. */
kono
parents:
diff changeset
2101
kono
parents:
diff changeset
2102 hashval_t
kono
parents:
diff changeset
2103 sem_variable::get_hash (void)
kono
parents:
diff changeset
2104 {
kono
parents:
diff changeset
2105 if (m_hash_set)
kono
parents:
diff changeset
2106 return m_hash;
kono
parents:
diff changeset
2107
kono
parents:
diff changeset
2108 /* All WPA streamed in symbols should have their hashes computed at compile
kono
parents:
diff changeset
2109 time. At this point, the constructor may not be in memory at all.
kono
parents:
diff changeset
2110 DECL_INITIAL (decl) would be error_mark_node in that case. */
kono
parents:
diff changeset
2111 gcc_assert (!node->lto_file_data);
kono
parents:
diff changeset
2112 tree ctor = DECL_INITIAL (decl);
kono
parents:
diff changeset
2113 inchash::hash hstate;
kono
parents:
diff changeset
2114
kono
parents:
diff changeset
2115 hstate.add_int (456346417);
kono
parents:
diff changeset
2116 if (DECL_SIZE (decl) && tree_fits_shwi_p (DECL_SIZE (decl)))
kono
parents:
diff changeset
2117 hstate.add_hwi (tree_to_shwi (DECL_SIZE (decl)));
kono
parents:
diff changeset
2118 add_expr (ctor, hstate);
kono
parents:
diff changeset
2119 set_hash (hstate.end ());
kono
parents:
diff changeset
2120
kono
parents:
diff changeset
2121 return m_hash;
kono
parents:
diff changeset
2122 }
kono
parents:
diff changeset
2123
kono
parents:
diff changeset
2124 /* Set all points-to UIDs of aliases pointing to node N as UID. */
kono
parents:
diff changeset
2125
kono
parents:
diff changeset
2126 static void
kono
parents:
diff changeset
2127 set_alias_uids (symtab_node *n, int uid)
kono
parents:
diff changeset
2128 {
kono
parents:
diff changeset
2129 ipa_ref *ref;
kono
parents:
diff changeset
2130 FOR_EACH_ALIAS (n, ref)
kono
parents:
diff changeset
2131 {
kono
parents:
diff changeset
2132 if (dump_file)
kono
parents:
diff changeset
2133 fprintf (dump_file, " Setting points-to UID of [%s] as %d\n",
kono
parents:
diff changeset
2134 xstrdup_for_dump (ref->referring->asm_name ()), uid);
kono
parents:
diff changeset
2135
kono
parents:
diff changeset
2136 SET_DECL_PT_UID (ref->referring->decl, uid);
kono
parents:
diff changeset
2137 set_alias_uids (ref->referring, uid);
kono
parents:
diff changeset
2138 }
kono
parents:
diff changeset
2139 }
kono
parents:
diff changeset
2140
kono
parents:
diff changeset
2141 /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
kono
parents:
diff changeset
2142 be applied. */
kono
parents:
diff changeset
2143
kono
parents:
diff changeset
2144 bool
kono
parents:
diff changeset
2145 sem_variable::merge (sem_item *alias_item)
kono
parents:
diff changeset
2146 {
kono
parents:
diff changeset
2147 gcc_assert (alias_item->type == VAR);
kono
parents:
diff changeset
2148
kono
parents:
diff changeset
2149 if (!sem_item::target_supports_symbol_aliases_p ())
kono
parents:
diff changeset
2150 {
kono
parents:
diff changeset
2151 if (dump_file)
kono
parents:
diff changeset
2152 fprintf (dump_file, "Not unifying; "
kono
parents:
diff changeset
2153 "Symbol aliases are not supported by target\n\n");
kono
parents:
diff changeset
2154 return false;
kono
parents:
diff changeset
2155 }
kono
parents:
diff changeset
2156
kono
parents:
diff changeset
2157 if (DECL_EXTERNAL (alias_item->decl))
kono
parents:
diff changeset
2158 {
kono
parents:
diff changeset
2159 if (dump_file)
kono
parents:
diff changeset
2160 fprintf (dump_file, "Not unifying; alias is external.\n\n");
kono
parents:
diff changeset
2161 return false;
kono
parents:
diff changeset
2162 }
kono
parents:
diff changeset
2163
kono
parents:
diff changeset
2164 sem_variable *alias_var = static_cast<sem_variable *> (alias_item);
kono
parents:
diff changeset
2165
kono
parents:
diff changeset
2166 varpool_node *original = get_node ();
kono
parents:
diff changeset
2167 varpool_node *alias = alias_var->get_node ();
kono
parents:
diff changeset
2168 bool original_discardable = false;
kono
parents:
diff changeset
2169
kono
parents:
diff changeset
2170 bool alias_address_matters = alias->address_matters_p ();
kono
parents:
diff changeset
2171
kono
parents:
diff changeset
2172 /* See if original is in a section that can be discarded if the main
kono
parents:
diff changeset
2173 symbol is not used.
kono
parents:
diff changeset
2174 Also consider case where we have resolution info and we know that
kono
parents:
diff changeset
2175 original's definition is not going to be used. In this case we can not
kono
parents:
diff changeset
2176 create alias to original. */
kono
parents:
diff changeset
2177 if (original->can_be_discarded_p ()
kono
parents:
diff changeset
2178 || (node->resolution != LDPR_UNKNOWN
kono
parents:
diff changeset
2179 && !decl_binds_to_current_def_p (node->decl)))
kono
parents:
diff changeset
2180 original_discardable = true;
kono
parents:
diff changeset
2181
kono
parents:
diff changeset
2182 gcc_assert (!TREE_ASM_WRITTEN (alias->decl));
kono
parents:
diff changeset
2183
kono
parents:
diff changeset
2184 /* Constant pool machinery is not quite ready for aliases.
kono
parents:
diff changeset
2185 TODO: varasm code contains logic for merging DECL_IN_CONSTANT_POOL.
kono
parents:
diff changeset
2186 For LTO merging does not happen that is an important missing feature.
kono
parents:
diff changeset
2187 We can enable merging with LTO if the DECL_IN_CONSTANT_POOL
kono
parents:
diff changeset
2188 flag is dropped and non-local symbol name is assigned. */
kono
parents:
diff changeset
2189 if (DECL_IN_CONSTANT_POOL (alias->decl)
kono
parents:
diff changeset
2190 || DECL_IN_CONSTANT_POOL (original->decl))
kono
parents:
diff changeset
2191 {
kono
parents:
diff changeset
2192 if (dump_file)
kono
parents:
diff changeset
2193 fprintf (dump_file,
kono
parents:
diff changeset
2194 "Not unifying; constant pool variables.\n\n");
kono
parents:
diff changeset
2195 return false;
kono
parents:
diff changeset
2196 }
kono
parents:
diff changeset
2197
kono
parents:
diff changeset
2198 /* Do not attempt to mix functions from different user sections;
kono
parents:
diff changeset
2199 we do not know what user intends with those. */
kono
parents:
diff changeset
2200 if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
kono
parents:
diff changeset
2201 || (DECL_SECTION_NAME (alias->decl) && !alias->implicit_section))
kono
parents:
diff changeset
2202 && DECL_SECTION_NAME (original->decl) != DECL_SECTION_NAME (alias->decl))
kono
parents:
diff changeset
2203 {
kono
parents:
diff changeset
2204 if (dump_file)
kono
parents:
diff changeset
2205 fprintf (dump_file,
kono
parents:
diff changeset
2206 "Not unifying; "
kono
parents:
diff changeset
2207 "original and alias are in different sections.\n\n");
kono
parents:
diff changeset
2208 return false;
kono
parents:
diff changeset
2209 }
kono
parents:
diff changeset
2210
kono
parents:
diff changeset
2211 /* We can not merge if address comparsion metters. */
kono
parents:
diff changeset
2212 if (alias_address_matters && flag_merge_constants < 2)
kono
parents:
diff changeset
2213 {
kono
parents:
diff changeset
2214 if (dump_file)
kono
parents:
diff changeset
2215 fprintf (dump_file,
kono
parents:
diff changeset
2216 "Not unifying; address of original may be compared.\n\n");
kono
parents:
diff changeset
2217 return false;
kono
parents:
diff changeset
2218 }
kono
parents:
diff changeset
2219
kono
parents:
diff changeset
2220 if (DECL_ALIGN (original->decl) < DECL_ALIGN (alias->decl))
kono
parents:
diff changeset
2221 {
kono
parents:
diff changeset
2222 if (dump_file)
kono
parents:
diff changeset
2223 fprintf (dump_file, "Not unifying; "
kono
parents:
diff changeset
2224 "original and alias have incompatible alignments\n\n");
kono
parents:
diff changeset
2225
kono
parents:
diff changeset
2226 return false;
kono
parents:
diff changeset
2227 }
kono
parents:
diff changeset
2228
kono
parents:
diff changeset
2229 if (DECL_COMDAT_GROUP (original->decl) != DECL_COMDAT_GROUP (alias->decl))
kono
parents:
diff changeset
2230 {
kono
parents:
diff changeset
2231 if (dump_file)
kono
parents:
diff changeset
2232 fprintf (dump_file, "Not unifying; alias cannot be created; "
kono
parents:
diff changeset
2233 "across comdat group boundary\n\n");
kono
parents:
diff changeset
2234
kono
parents:
diff changeset
2235 return false;
kono
parents:
diff changeset
2236 }
kono
parents:
diff changeset
2237
kono
parents:
diff changeset
2238 if (original_discardable)
kono
parents:
diff changeset
2239 {
kono
parents:
diff changeset
2240 if (dump_file)
kono
parents:
diff changeset
2241 fprintf (dump_file, "Not unifying; alias cannot be created; "
kono
parents:
diff changeset
2242 "target is discardable\n\n");
kono
parents:
diff changeset
2243
kono
parents:
diff changeset
2244 return false;
kono
parents:
diff changeset
2245 }
kono
parents:
diff changeset
2246 else
kono
parents:
diff changeset
2247 {
kono
parents:
diff changeset
2248 gcc_assert (!original->alias);
kono
parents:
diff changeset
2249 gcc_assert (!alias->alias);
kono
parents:
diff changeset
2250
kono
parents:
diff changeset
2251 alias->analyzed = false;
kono
parents:
diff changeset
2252
kono
parents:
diff changeset
2253 DECL_INITIAL (alias->decl) = NULL;
kono
parents:
diff changeset
2254 ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl,
kono
parents:
diff changeset
2255 NULL, true);
kono
parents:
diff changeset
2256 alias->need_bounds_init = false;
kono
parents:
diff changeset
2257 alias->remove_all_references ();
kono
parents:
diff changeset
2258 if (TREE_ADDRESSABLE (alias->decl))
kono
parents:
diff changeset
2259 original->call_for_symbol_and_aliases (set_addressable, NULL, true);
kono
parents:
diff changeset
2260
kono
parents:
diff changeset
2261 varpool_node::create_alias (alias_var->decl, decl);
kono
parents:
diff changeset
2262 alias->resolve_alias (original);
kono
parents:
diff changeset
2263
kono
parents:
diff changeset
2264 if (dump_file)
kono
parents:
diff changeset
2265 fprintf (dump_file, "Unified; Variable alias has been created.\n");
kono
parents:
diff changeset
2266
kono
parents:
diff changeset
2267 set_alias_uids (original, DECL_UID (original->decl));
kono
parents:
diff changeset
2268 return true;
kono
parents:
diff changeset
2269 }
kono
parents:
diff changeset
2270 }
kono
parents:
diff changeset
2271
kono
parents:
diff changeset
2272 /* Dump symbol to FILE. */
kono
parents:
diff changeset
2273
kono
parents:
diff changeset
2274 void
kono
parents:
diff changeset
2275 sem_variable::dump_to_file (FILE *file)
kono
parents:
diff changeset
2276 {
kono
parents:
diff changeset
2277 gcc_assert (file);
kono
parents:
diff changeset
2278
kono
parents:
diff changeset
2279 print_node (file, "", decl, 0);
kono
parents:
diff changeset
2280 fprintf (file, "\n\n");
kono
parents:
diff changeset
2281 }
kono
parents:
diff changeset
2282
kono
parents:
diff changeset
2283 unsigned int sem_item_optimizer::class_id = 0;
kono
parents:
diff changeset
2284
kono
parents:
diff changeset
2285 sem_item_optimizer::sem_item_optimizer ()
kono
parents:
diff changeset
2286 : worklist (0), m_classes (0), m_classes_count (0), m_cgraph_node_hooks (NULL),
kono
parents:
diff changeset
2287 m_varpool_node_hooks (NULL)
kono
parents:
diff changeset
2288 {
kono
parents:
diff changeset
2289 m_items.create (0);
kono
parents:
diff changeset
2290 bitmap_obstack_initialize (&m_bmstack);
kono
parents:
diff changeset
2291 }
kono
parents:
diff changeset
2292
kono
parents:
diff changeset
2293 sem_item_optimizer::~sem_item_optimizer ()
kono
parents:
diff changeset
2294 {
kono
parents:
diff changeset
2295 for (unsigned int i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2296 delete m_items[i];
kono
parents:
diff changeset
2297
kono
parents:
diff changeset
2298
kono
parents:
diff changeset
2299 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
2300 it != m_classes.end (); ++it)
kono
parents:
diff changeset
2301 {
kono
parents:
diff changeset
2302 for (unsigned int i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
2303 delete (*it)->classes[i];
kono
parents:
diff changeset
2304
kono
parents:
diff changeset
2305 (*it)->classes.release ();
kono
parents:
diff changeset
2306 free (*it);
kono
parents:
diff changeset
2307 }
kono
parents:
diff changeset
2308
kono
parents:
diff changeset
2309 m_items.release ();
kono
parents:
diff changeset
2310
kono
parents:
diff changeset
2311 bitmap_obstack_release (&m_bmstack);
kono
parents:
diff changeset
2312 }
kono
parents:
diff changeset
2313
kono
parents:
diff changeset
2314 /* Write IPA ICF summary for symbols. */
kono
parents:
diff changeset
2315
kono
parents:
diff changeset
2316 void
kono
parents:
diff changeset
2317 sem_item_optimizer::write_summary (void)
kono
parents:
diff changeset
2318 {
kono
parents:
diff changeset
2319 unsigned int count = 0;
kono
parents:
diff changeset
2320
kono
parents:
diff changeset
2321 output_block *ob = create_output_block (LTO_section_ipa_icf);
kono
parents:
diff changeset
2322 lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
kono
parents:
diff changeset
2323 ob->symbol = NULL;
kono
parents:
diff changeset
2324
kono
parents:
diff changeset
2325 /* Calculate number of symbols to be serialized. */
kono
parents:
diff changeset
2326 for (lto_symtab_encoder_iterator lsei = lsei_start_in_partition (encoder);
kono
parents:
diff changeset
2327 !lsei_end_p (lsei);
kono
parents:
diff changeset
2328 lsei_next_in_partition (&lsei))
kono
parents:
diff changeset
2329 {
kono
parents:
diff changeset
2330 symtab_node *node = lsei_node (lsei);
kono
parents:
diff changeset
2331
kono
parents:
diff changeset
2332 if (m_symtab_node_map.get (node))
kono
parents:
diff changeset
2333 count++;
kono
parents:
diff changeset
2334 }
kono
parents:
diff changeset
2335
kono
parents:
diff changeset
2336 streamer_write_uhwi (ob, count);
kono
parents:
diff changeset
2337
kono
parents:
diff changeset
2338 /* Process all of the symbols. */
kono
parents:
diff changeset
2339 for (lto_symtab_encoder_iterator lsei = lsei_start_in_partition (encoder);
kono
parents:
diff changeset
2340 !lsei_end_p (lsei);
kono
parents:
diff changeset
2341 lsei_next_in_partition (&lsei))
kono
parents:
diff changeset
2342 {
kono
parents:
diff changeset
2343 symtab_node *node = lsei_node (lsei);
kono
parents:
diff changeset
2344
kono
parents:
diff changeset
2345 sem_item **item = m_symtab_node_map.get (node);
kono
parents:
diff changeset
2346
kono
parents:
diff changeset
2347 if (item && *item)
kono
parents:
diff changeset
2348 {
kono
parents:
diff changeset
2349 int node_ref = lto_symtab_encoder_encode (encoder, node);
kono
parents:
diff changeset
2350 streamer_write_uhwi_stream (ob->main_stream, node_ref);
kono
parents:
diff changeset
2351
kono
parents:
diff changeset
2352 streamer_write_uhwi (ob, (*item)->get_hash ());
kono
parents:
diff changeset
2353 }
kono
parents:
diff changeset
2354 }
kono
parents:
diff changeset
2355
kono
parents:
diff changeset
2356 streamer_write_char_stream (ob->main_stream, 0);
kono
parents:
diff changeset
2357 produce_asm (ob, NULL);
kono
parents:
diff changeset
2358 destroy_output_block (ob);
kono
parents:
diff changeset
2359 }
kono
parents:
diff changeset
2360
kono
parents:
diff changeset
2361 /* Reads a section from LTO stream file FILE_DATA. Input block for DATA
kono
parents:
diff changeset
2362 contains LEN bytes. */
kono
parents:
diff changeset
2363
kono
parents:
diff changeset
2364 void
kono
parents:
diff changeset
2365 sem_item_optimizer::read_section (lto_file_decl_data *file_data,
kono
parents:
diff changeset
2366 const char *data, size_t len)
kono
parents:
diff changeset
2367 {
kono
parents:
diff changeset
2368 const lto_function_header *header
kono
parents:
diff changeset
2369 = (const lto_function_header *) data;
kono
parents:
diff changeset
2370 const int cfg_offset = sizeof (lto_function_header);
kono
parents:
diff changeset
2371 const int main_offset = cfg_offset + header->cfg_size;
kono
parents:
diff changeset
2372 const int string_offset = main_offset + header->main_size;
kono
parents:
diff changeset
2373 data_in *data_in;
kono
parents:
diff changeset
2374 unsigned int i;
kono
parents:
diff changeset
2375 unsigned int count;
kono
parents:
diff changeset
2376
kono
parents:
diff changeset
2377 lto_input_block ib_main ((const char *) data + main_offset, 0,
kono
parents:
diff changeset
2378 header->main_size, file_data->mode_table);
kono
parents:
diff changeset
2379
kono
parents:
diff changeset
2380 data_in
kono
parents:
diff changeset
2381 = lto_data_in_create (file_data, (const char *) data + string_offset,
kono
parents:
diff changeset
2382 header->string_size, vNULL);
kono
parents:
diff changeset
2383
kono
parents:
diff changeset
2384 count = streamer_read_uhwi (&ib_main);
kono
parents:
diff changeset
2385
kono
parents:
diff changeset
2386 for (i = 0; i < count; i++)
kono
parents:
diff changeset
2387 {
kono
parents:
diff changeset
2388 unsigned int index;
kono
parents:
diff changeset
2389 symtab_node *node;
kono
parents:
diff changeset
2390 lto_symtab_encoder_t encoder;
kono
parents:
diff changeset
2391
kono
parents:
diff changeset
2392 index = streamer_read_uhwi (&ib_main);
kono
parents:
diff changeset
2393 encoder = file_data->symtab_node_encoder;
kono
parents:
diff changeset
2394 node = lto_symtab_encoder_deref (encoder, index);
kono
parents:
diff changeset
2395
kono
parents:
diff changeset
2396 hashval_t hash = streamer_read_uhwi (&ib_main);
kono
parents:
diff changeset
2397
kono
parents:
diff changeset
2398 gcc_assert (node->definition);
kono
parents:
diff changeset
2399
kono
parents:
diff changeset
2400 if (dump_file)
kono
parents:
diff changeset
2401 fprintf (dump_file, "Symbol added: %s (tree: %p)\n",
kono
parents:
diff changeset
2402 node->dump_asm_name (), (void *) node->decl);
kono
parents:
diff changeset
2403
kono
parents:
diff changeset
2404 if (is_a<cgraph_node *> (node))
kono
parents:
diff changeset
2405 {
kono
parents:
diff changeset
2406 cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
kono
parents:
diff changeset
2407
kono
parents:
diff changeset
2408 sem_function *fn = new sem_function (cnode, &m_bmstack);
kono
parents:
diff changeset
2409 fn->set_hash (hash);
kono
parents:
diff changeset
2410 m_items.safe_push (fn);
kono
parents:
diff changeset
2411 }
kono
parents:
diff changeset
2412 else
kono
parents:
diff changeset
2413 {
kono
parents:
diff changeset
2414 varpool_node *vnode = dyn_cast <varpool_node *> (node);
kono
parents:
diff changeset
2415
kono
parents:
diff changeset
2416 sem_variable *var = new sem_variable (vnode, &m_bmstack);
kono
parents:
diff changeset
2417 var->set_hash (hash);
kono
parents:
diff changeset
2418 m_items.safe_push (var);
kono
parents:
diff changeset
2419 }
kono
parents:
diff changeset
2420 }
kono
parents:
diff changeset
2421
kono
parents:
diff changeset
2422 lto_free_section_data (file_data, LTO_section_ipa_icf, NULL, data,
kono
parents:
diff changeset
2423 len);
kono
parents:
diff changeset
2424 lto_data_in_delete (data_in);
kono
parents:
diff changeset
2425 }
kono
parents:
diff changeset
2426
kono
parents:
diff changeset
2427 /* Read IPA ICF summary for symbols. */
kono
parents:
diff changeset
2428
kono
parents:
diff changeset
2429 void
kono
parents:
diff changeset
2430 sem_item_optimizer::read_summary (void)
kono
parents:
diff changeset
2431 {
kono
parents:
diff changeset
2432 lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
kono
parents:
diff changeset
2433 lto_file_decl_data *file_data;
kono
parents:
diff changeset
2434 unsigned int j = 0;
kono
parents:
diff changeset
2435
kono
parents:
diff changeset
2436 while ((file_data = file_data_vec[j++]))
kono
parents:
diff changeset
2437 {
kono
parents:
diff changeset
2438 size_t len;
kono
parents:
diff changeset
2439 const char *data = lto_get_section_data (file_data,
kono
parents:
diff changeset
2440 LTO_section_ipa_icf, NULL, &len);
kono
parents:
diff changeset
2441
kono
parents:
diff changeset
2442 if (data)
kono
parents:
diff changeset
2443 read_section (file_data, data, len);
kono
parents:
diff changeset
2444 }
kono
parents:
diff changeset
2445 }
kono
parents:
diff changeset
2446
kono
parents:
diff changeset
2447 /* Register callgraph and varpool hooks. */
kono
parents:
diff changeset
2448
kono
parents:
diff changeset
2449 void
kono
parents:
diff changeset
2450 sem_item_optimizer::register_hooks (void)
kono
parents:
diff changeset
2451 {
kono
parents:
diff changeset
2452 if (!m_cgraph_node_hooks)
kono
parents:
diff changeset
2453 m_cgraph_node_hooks = symtab->add_cgraph_removal_hook
kono
parents:
diff changeset
2454 (&sem_item_optimizer::cgraph_removal_hook, this);
kono
parents:
diff changeset
2455
kono
parents:
diff changeset
2456 if (!m_varpool_node_hooks)
kono
parents:
diff changeset
2457 m_varpool_node_hooks = symtab->add_varpool_removal_hook
kono
parents:
diff changeset
2458 (&sem_item_optimizer::varpool_removal_hook, this);
kono
parents:
diff changeset
2459 }
kono
parents:
diff changeset
2460
kono
parents:
diff changeset
2461 /* Unregister callgraph and varpool hooks. */
kono
parents:
diff changeset
2462
kono
parents:
diff changeset
2463 void
kono
parents:
diff changeset
2464 sem_item_optimizer::unregister_hooks (void)
kono
parents:
diff changeset
2465 {
kono
parents:
diff changeset
2466 if (m_cgraph_node_hooks)
kono
parents:
diff changeset
2467 symtab->remove_cgraph_removal_hook (m_cgraph_node_hooks);
kono
parents:
diff changeset
2468
kono
parents:
diff changeset
2469 if (m_varpool_node_hooks)
kono
parents:
diff changeset
2470 symtab->remove_varpool_removal_hook (m_varpool_node_hooks);
kono
parents:
diff changeset
2471 }
kono
parents:
diff changeset
2472
kono
parents:
diff changeset
2473 /* Adds a CLS to hashtable associated by hash value. */
kono
parents:
diff changeset
2474
kono
parents:
diff changeset
2475 void
kono
parents:
diff changeset
2476 sem_item_optimizer::add_class (congruence_class *cls)
kono
parents:
diff changeset
2477 {
kono
parents:
diff changeset
2478 gcc_assert (cls->members.length ());
kono
parents:
diff changeset
2479
kono
parents:
diff changeset
2480 congruence_class_group *group
kono
parents:
diff changeset
2481 = get_group_by_hash (cls->members[0]->get_hash (),
kono
parents:
diff changeset
2482 cls->members[0]->type);
kono
parents:
diff changeset
2483 group->classes.safe_push (cls);
kono
parents:
diff changeset
2484 }
kono
parents:
diff changeset
2485
kono
parents:
diff changeset
2486 /* Gets a congruence class group based on given HASH value and TYPE. */
kono
parents:
diff changeset
2487
kono
parents:
diff changeset
2488 congruence_class_group *
kono
parents:
diff changeset
2489 sem_item_optimizer::get_group_by_hash (hashval_t hash, sem_item_type type)
kono
parents:
diff changeset
2490 {
kono
parents:
diff changeset
2491 congruence_class_group *item = XNEW (congruence_class_group);
kono
parents:
diff changeset
2492 item->hash = hash;
kono
parents:
diff changeset
2493 item->type = type;
kono
parents:
diff changeset
2494
kono
parents:
diff changeset
2495 congruence_class_group **slot = m_classes.find_slot (item, INSERT);
kono
parents:
diff changeset
2496
kono
parents:
diff changeset
2497 if (*slot)
kono
parents:
diff changeset
2498 free (item);
kono
parents:
diff changeset
2499 else
kono
parents:
diff changeset
2500 {
kono
parents:
diff changeset
2501 item->classes.create (1);
kono
parents:
diff changeset
2502 *slot = item;
kono
parents:
diff changeset
2503 }
kono
parents:
diff changeset
2504
kono
parents:
diff changeset
2505 return *slot;
kono
parents:
diff changeset
2506 }
kono
parents:
diff changeset
2507
kono
parents:
diff changeset
2508 /* Callgraph removal hook called for a NODE with a custom DATA. */
kono
parents:
diff changeset
2509
kono
parents:
diff changeset
2510 void
kono
parents:
diff changeset
2511 sem_item_optimizer::cgraph_removal_hook (cgraph_node *node, void *data)
kono
parents:
diff changeset
2512 {
kono
parents:
diff changeset
2513 sem_item_optimizer *optimizer = (sem_item_optimizer *) data;
kono
parents:
diff changeset
2514 optimizer->remove_symtab_node (node);
kono
parents:
diff changeset
2515 }
kono
parents:
diff changeset
2516
kono
parents:
diff changeset
2517 /* Varpool removal hook called for a NODE with a custom DATA. */
kono
parents:
diff changeset
2518
kono
parents:
diff changeset
2519 void
kono
parents:
diff changeset
2520 sem_item_optimizer::varpool_removal_hook (varpool_node *node, void *data)
kono
parents:
diff changeset
2521 {
kono
parents:
diff changeset
2522 sem_item_optimizer *optimizer = (sem_item_optimizer *) data;
kono
parents:
diff changeset
2523 optimizer->remove_symtab_node (node);
kono
parents:
diff changeset
2524 }
kono
parents:
diff changeset
2525
kono
parents:
diff changeset
2526 /* Remove symtab NODE triggered by symtab removal hooks. */
kono
parents:
diff changeset
2527
kono
parents:
diff changeset
2528 void
kono
parents:
diff changeset
2529 sem_item_optimizer::remove_symtab_node (symtab_node *node)
kono
parents:
diff changeset
2530 {
kono
parents:
diff changeset
2531 gcc_assert (!m_classes.elements ());
kono
parents:
diff changeset
2532
kono
parents:
diff changeset
2533 m_removed_items_set.add (node);
kono
parents:
diff changeset
2534 }
kono
parents:
diff changeset
2535
kono
parents:
diff changeset
2536 void
kono
parents:
diff changeset
2537 sem_item_optimizer::remove_item (sem_item *item)
kono
parents:
diff changeset
2538 {
kono
parents:
diff changeset
2539 if (m_symtab_node_map.get (item->node))
kono
parents:
diff changeset
2540 m_symtab_node_map.remove (item->node);
kono
parents:
diff changeset
2541 delete item;
kono
parents:
diff changeset
2542 }
kono
parents:
diff changeset
2543
kono
parents:
diff changeset
2544 /* Removes all callgraph and varpool nodes that are marked by symtab
kono
parents:
diff changeset
2545 as deleted. */
kono
parents:
diff changeset
2546
kono
parents:
diff changeset
2547 void
kono
parents:
diff changeset
2548 sem_item_optimizer::filter_removed_items (void)
kono
parents:
diff changeset
2549 {
kono
parents:
diff changeset
2550 auto_vec <sem_item *> filtered;
kono
parents:
diff changeset
2551
kono
parents:
diff changeset
2552 for (unsigned int i = 0; i < m_items.length(); i++)
kono
parents:
diff changeset
2553 {
kono
parents:
diff changeset
2554 sem_item *item = m_items[i];
kono
parents:
diff changeset
2555
kono
parents:
diff changeset
2556 if (m_removed_items_set.contains (item->node))
kono
parents:
diff changeset
2557 {
kono
parents:
diff changeset
2558 remove_item (item);
kono
parents:
diff changeset
2559 continue;
kono
parents:
diff changeset
2560 }
kono
parents:
diff changeset
2561
kono
parents:
diff changeset
2562 if (item->type == FUNC)
kono
parents:
diff changeset
2563 {
kono
parents:
diff changeset
2564 cgraph_node *cnode = static_cast <sem_function *>(item)->get_node ();
kono
parents:
diff changeset
2565
kono
parents:
diff changeset
2566 if (in_lto_p && (cnode->alias || cnode->body_removed))
kono
parents:
diff changeset
2567 remove_item (item);
kono
parents:
diff changeset
2568 else
kono
parents:
diff changeset
2569 filtered.safe_push (item);
kono
parents:
diff changeset
2570 }
kono
parents:
diff changeset
2571 else /* VAR. */
kono
parents:
diff changeset
2572 {
kono
parents:
diff changeset
2573 if (!flag_ipa_icf_variables)
kono
parents:
diff changeset
2574 remove_item (item);
kono
parents:
diff changeset
2575 else
kono
parents:
diff changeset
2576 {
kono
parents:
diff changeset
2577 /* Filter out non-readonly variables. */
kono
parents:
diff changeset
2578 tree decl = item->decl;
kono
parents:
diff changeset
2579 if (TREE_READONLY (decl))
kono
parents:
diff changeset
2580 filtered.safe_push (item);
kono
parents:
diff changeset
2581 else
kono
parents:
diff changeset
2582 remove_item (item);
kono
parents:
diff changeset
2583 }
kono
parents:
diff changeset
2584 }
kono
parents:
diff changeset
2585 }
kono
parents:
diff changeset
2586
kono
parents:
diff changeset
2587 /* Clean-up of released semantic items. */
kono
parents:
diff changeset
2588
kono
parents:
diff changeset
2589 m_items.release ();
kono
parents:
diff changeset
2590 for (unsigned int i = 0; i < filtered.length(); i++)
kono
parents:
diff changeset
2591 m_items.safe_push (filtered[i]);
kono
parents:
diff changeset
2592 }
kono
parents:
diff changeset
2593
kono
parents:
diff changeset
2594 /* Optimizer entry point which returns true in case it processes
kono
parents:
diff changeset
2595 a merge operation. True is returned if there's a merge operation
kono
parents:
diff changeset
2596 processed. */
kono
parents:
diff changeset
2597
kono
parents:
diff changeset
2598 bool
kono
parents:
diff changeset
2599 sem_item_optimizer::execute (void)
kono
parents:
diff changeset
2600 {
kono
parents:
diff changeset
2601 filter_removed_items ();
kono
parents:
diff changeset
2602 unregister_hooks ();
kono
parents:
diff changeset
2603
kono
parents:
diff changeset
2604 build_graph ();
kono
parents:
diff changeset
2605 update_hash_by_addr_refs ();
kono
parents:
diff changeset
2606 build_hash_based_classes ();
kono
parents:
diff changeset
2607
kono
parents:
diff changeset
2608 if (dump_file)
kono
parents:
diff changeset
2609 fprintf (dump_file, "Dump after hash based groups\n");
kono
parents:
diff changeset
2610 dump_cong_classes ();
kono
parents:
diff changeset
2611
kono
parents:
diff changeset
2612 for (unsigned int i = 0; i < m_items.length(); i++)
kono
parents:
diff changeset
2613 m_items[i]->init_wpa ();
kono
parents:
diff changeset
2614
kono
parents:
diff changeset
2615 subdivide_classes_by_equality (true);
kono
parents:
diff changeset
2616
kono
parents:
diff changeset
2617 if (dump_file)
kono
parents:
diff changeset
2618 fprintf (dump_file, "Dump after WPA based types groups\n");
kono
parents:
diff changeset
2619
kono
parents:
diff changeset
2620 dump_cong_classes ();
kono
parents:
diff changeset
2621
kono
parents:
diff changeset
2622 process_cong_reduction ();
kono
parents:
diff changeset
2623 checking_verify_classes ();
kono
parents:
diff changeset
2624
kono
parents:
diff changeset
2625 if (dump_file)
kono
parents:
diff changeset
2626 fprintf (dump_file, "Dump after callgraph-based congruence reduction\n");
kono
parents:
diff changeset
2627
kono
parents:
diff changeset
2628 dump_cong_classes ();
kono
parents:
diff changeset
2629
kono
parents:
diff changeset
2630 parse_nonsingleton_classes ();
kono
parents:
diff changeset
2631 subdivide_classes_by_equality ();
kono
parents:
diff changeset
2632
kono
parents:
diff changeset
2633 if (dump_file)
kono
parents:
diff changeset
2634 fprintf (dump_file, "Dump after full equality comparison of groups\n");
kono
parents:
diff changeset
2635
kono
parents:
diff changeset
2636 dump_cong_classes ();
kono
parents:
diff changeset
2637
kono
parents:
diff changeset
2638 unsigned int prev_class_count = m_classes_count;
kono
parents:
diff changeset
2639
kono
parents:
diff changeset
2640 process_cong_reduction ();
kono
parents:
diff changeset
2641 dump_cong_classes ();
kono
parents:
diff changeset
2642 checking_verify_classes ();
kono
parents:
diff changeset
2643 bool merged_p = merge_classes (prev_class_count);
kono
parents:
diff changeset
2644
kono
parents:
diff changeset
2645 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2646 symtab->dump (dump_file);
kono
parents:
diff changeset
2647
kono
parents:
diff changeset
2648 return merged_p;
kono
parents:
diff changeset
2649 }
kono
parents:
diff changeset
2650
kono
parents:
diff changeset
2651 /* Function responsible for visiting all potential functions and
kono
parents:
diff changeset
2652 read-only variables that can be merged. */
kono
parents:
diff changeset
2653
kono
parents:
diff changeset
2654 void
kono
parents:
diff changeset
2655 sem_item_optimizer::parse_funcs_and_vars (void)
kono
parents:
diff changeset
2656 {
kono
parents:
diff changeset
2657 cgraph_node *cnode;
kono
parents:
diff changeset
2658
kono
parents:
diff changeset
2659 if (flag_ipa_icf_functions)
kono
parents:
diff changeset
2660 FOR_EACH_DEFINED_FUNCTION (cnode)
kono
parents:
diff changeset
2661 {
kono
parents:
diff changeset
2662 sem_function *f = sem_function::parse (cnode, &m_bmstack);
kono
parents:
diff changeset
2663 if (f)
kono
parents:
diff changeset
2664 {
kono
parents:
diff changeset
2665 m_items.safe_push (f);
kono
parents:
diff changeset
2666 m_symtab_node_map.put (cnode, f);
kono
parents:
diff changeset
2667
kono
parents:
diff changeset
2668 if (dump_file)
kono
parents:
diff changeset
2669 fprintf (dump_file, "Parsed function:%s\n", f->node->asm_name ());
kono
parents:
diff changeset
2670
kono
parents:
diff changeset
2671 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
2672 f->dump_to_file (dump_file);
kono
parents:
diff changeset
2673 }
kono
parents:
diff changeset
2674 else if (dump_file)
kono
parents:
diff changeset
2675 fprintf (dump_file, "Not parsed function:%s\n", cnode->asm_name ());
kono
parents:
diff changeset
2676 }
kono
parents:
diff changeset
2677
kono
parents:
diff changeset
2678 varpool_node *vnode;
kono
parents:
diff changeset
2679
kono
parents:
diff changeset
2680 if (flag_ipa_icf_variables)
kono
parents:
diff changeset
2681 FOR_EACH_DEFINED_VARIABLE (vnode)
kono
parents:
diff changeset
2682 {
kono
parents:
diff changeset
2683 sem_variable *v = sem_variable::parse (vnode, &m_bmstack);
kono
parents:
diff changeset
2684
kono
parents:
diff changeset
2685 if (v)
kono
parents:
diff changeset
2686 {
kono
parents:
diff changeset
2687 m_items.safe_push (v);
kono
parents:
diff changeset
2688 m_symtab_node_map.put (vnode, v);
kono
parents:
diff changeset
2689 }
kono
parents:
diff changeset
2690 }
kono
parents:
diff changeset
2691 }
kono
parents:
diff changeset
2692
kono
parents:
diff changeset
2693 /* Makes pairing between a congruence class CLS and semantic ITEM. */
kono
parents:
diff changeset
2694
kono
parents:
diff changeset
2695 void
kono
parents:
diff changeset
2696 sem_item_optimizer::add_item_to_class (congruence_class *cls, sem_item *item)
kono
parents:
diff changeset
2697 {
kono
parents:
diff changeset
2698 item->index_in_class = cls->members.length ();
kono
parents:
diff changeset
2699 cls->members.safe_push (item);
kono
parents:
diff changeset
2700 item->cls = cls;
kono
parents:
diff changeset
2701 }
kono
parents:
diff changeset
2702
kono
parents:
diff changeset
2703 /* For each semantic item, append hash values of references. */
kono
parents:
diff changeset
2704
kono
parents:
diff changeset
2705 void
kono
parents:
diff changeset
2706 sem_item_optimizer::update_hash_by_addr_refs ()
kono
parents:
diff changeset
2707 {
kono
parents:
diff changeset
2708 /* First, append to hash sensitive references and class type if it need to
kono
parents:
diff changeset
2709 be matched for ODR. */
kono
parents:
diff changeset
2710 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2711 {
kono
parents:
diff changeset
2712 m_items[i]->update_hash_by_addr_refs (m_symtab_node_map);
kono
parents:
diff changeset
2713 if (m_items[i]->type == FUNC)
kono
parents:
diff changeset
2714 {
kono
parents:
diff changeset
2715 if (TREE_CODE (TREE_TYPE (m_items[i]->decl)) == METHOD_TYPE
kono
parents:
diff changeset
2716 && contains_polymorphic_type_p
kono
parents:
diff changeset
2717 (TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl)))
kono
parents:
diff changeset
2718 && (DECL_CXX_CONSTRUCTOR_P (m_items[i]->decl)
kono
parents:
diff changeset
2719 || (static_cast<sem_function *> (m_items[i])->param_used_p (0)
kono
parents:
diff changeset
2720 && static_cast<sem_function *> (m_items[i])
kono
parents:
diff changeset
2721 ->compare_polymorphic_p ())))
kono
parents:
diff changeset
2722 {
kono
parents:
diff changeset
2723 tree class_type
kono
parents:
diff changeset
2724 = TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl));
kono
parents:
diff changeset
2725 inchash::hash hstate (m_items[i]->get_hash ());
kono
parents:
diff changeset
2726
kono
parents:
diff changeset
2727 if (TYPE_NAME (class_type)
kono
parents:
diff changeset
2728 && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
kono
parents:
diff changeset
2729 hstate.add_hwi
kono
parents:
diff changeset
2730 (IDENTIFIER_HASH_VALUE
kono
parents:
diff changeset
2731 (DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
kono
parents:
diff changeset
2732
kono
parents:
diff changeset
2733 m_items[i]->set_hash (hstate.end ());
kono
parents:
diff changeset
2734 }
kono
parents:
diff changeset
2735 }
kono
parents:
diff changeset
2736 }
kono
parents:
diff changeset
2737
kono
parents:
diff changeset
2738 /* Once all symbols have enhanced hash value, we can append
kono
parents:
diff changeset
2739 hash values of symbols that are seen by IPA ICF and are
kono
parents:
diff changeset
2740 references by a semantic item. Newly computed values
kono
parents:
diff changeset
2741 are saved to global_hash member variable. */
kono
parents:
diff changeset
2742 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2743 m_items[i]->update_hash_by_local_refs (m_symtab_node_map);
kono
parents:
diff changeset
2744
kono
parents:
diff changeset
2745 /* Global hash value replace current hash values. */
kono
parents:
diff changeset
2746 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2747 m_items[i]->set_hash (m_items[i]->global_hash);
kono
parents:
diff changeset
2748 }
kono
parents:
diff changeset
2749
kono
parents:
diff changeset
2750 /* Congruence classes are built by hash value. */
kono
parents:
diff changeset
2751
kono
parents:
diff changeset
2752 void
kono
parents:
diff changeset
2753 sem_item_optimizer::build_hash_based_classes (void)
kono
parents:
diff changeset
2754 {
kono
parents:
diff changeset
2755 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2756 {
kono
parents:
diff changeset
2757 sem_item *item = m_items[i];
kono
parents:
diff changeset
2758
kono
parents:
diff changeset
2759 congruence_class_group *group
kono
parents:
diff changeset
2760 = get_group_by_hash (item->get_hash (), item->type);
kono
parents:
diff changeset
2761
kono
parents:
diff changeset
2762 if (!group->classes.length ())
kono
parents:
diff changeset
2763 {
kono
parents:
diff changeset
2764 m_classes_count++;
kono
parents:
diff changeset
2765 group->classes.safe_push (new congruence_class (class_id++));
kono
parents:
diff changeset
2766 }
kono
parents:
diff changeset
2767
kono
parents:
diff changeset
2768 add_item_to_class (group->classes[0], item);
kono
parents:
diff changeset
2769 }
kono
parents:
diff changeset
2770 }
kono
parents:
diff changeset
2771
kono
parents:
diff changeset
2772 /* Build references according to call graph. */
kono
parents:
diff changeset
2773
kono
parents:
diff changeset
2774 void
kono
parents:
diff changeset
2775 sem_item_optimizer::build_graph (void)
kono
parents:
diff changeset
2776 {
kono
parents:
diff changeset
2777 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2778 {
kono
parents:
diff changeset
2779 sem_item *item = m_items[i];
kono
parents:
diff changeset
2780 m_symtab_node_map.put (item->node, item);
kono
parents:
diff changeset
2781
kono
parents:
diff changeset
2782 /* Initialize hash values if we are not in LTO mode. */
kono
parents:
diff changeset
2783 if (!in_lto_p)
kono
parents:
diff changeset
2784 item->get_hash ();
kono
parents:
diff changeset
2785 }
kono
parents:
diff changeset
2786
kono
parents:
diff changeset
2787 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2788 {
kono
parents:
diff changeset
2789 sem_item *item = m_items[i];
kono
parents:
diff changeset
2790
kono
parents:
diff changeset
2791 if (item->type == FUNC)
kono
parents:
diff changeset
2792 {
kono
parents:
diff changeset
2793 cgraph_node *cnode = dyn_cast <cgraph_node *> (item->node);
kono
parents:
diff changeset
2794
kono
parents:
diff changeset
2795 cgraph_edge *e = cnode->callees;
kono
parents:
diff changeset
2796 while (e)
kono
parents:
diff changeset
2797 {
kono
parents:
diff changeset
2798 sem_item **slot = m_symtab_node_map.get
kono
parents:
diff changeset
2799 (e->callee->ultimate_alias_target ());
kono
parents:
diff changeset
2800 if (slot)
kono
parents:
diff changeset
2801 item->add_reference (*slot);
kono
parents:
diff changeset
2802
kono
parents:
diff changeset
2803 e = e->next_callee;
kono
parents:
diff changeset
2804 }
kono
parents:
diff changeset
2805 }
kono
parents:
diff changeset
2806
kono
parents:
diff changeset
2807 ipa_ref *ref = NULL;
kono
parents:
diff changeset
2808 for (unsigned i = 0; item->node->iterate_reference (i, ref); i++)
kono
parents:
diff changeset
2809 {
kono
parents:
diff changeset
2810 sem_item **slot = m_symtab_node_map.get
kono
parents:
diff changeset
2811 (ref->referred->ultimate_alias_target ());
kono
parents:
diff changeset
2812 if (slot)
kono
parents:
diff changeset
2813 item->add_reference (*slot);
kono
parents:
diff changeset
2814 }
kono
parents:
diff changeset
2815 }
kono
parents:
diff changeset
2816 }
kono
parents:
diff changeset
2817
kono
parents:
diff changeset
2818 /* Semantic items in classes having more than one element and initialized.
kono
parents:
diff changeset
2819 In case of WPA, we load function body. */
kono
parents:
diff changeset
2820
kono
parents:
diff changeset
2821 void
kono
parents:
diff changeset
2822 sem_item_optimizer::parse_nonsingleton_classes (void)
kono
parents:
diff changeset
2823 {
kono
parents:
diff changeset
2824 unsigned int init_called_count = 0;
kono
parents:
diff changeset
2825
kono
parents:
diff changeset
2826 for (unsigned i = 0; i < m_items.length (); i++)
kono
parents:
diff changeset
2827 if (m_items[i]->cls->members.length () > 1)
kono
parents:
diff changeset
2828 {
kono
parents:
diff changeset
2829 m_items[i]->init ();
kono
parents:
diff changeset
2830 init_called_count++;
kono
parents:
diff changeset
2831 }
kono
parents:
diff changeset
2832
kono
parents:
diff changeset
2833 if (dump_file)
kono
parents:
diff changeset
2834 fprintf (dump_file, "Init called for %u items (%.2f%%).\n",
kono
parents:
diff changeset
2835 init_called_count,
kono
parents:
diff changeset
2836 m_items.length () ? 100.0f * init_called_count / m_items.length ()
kono
parents:
diff changeset
2837 : 0.0f);
kono
parents:
diff changeset
2838 }
kono
parents:
diff changeset
2839
kono
parents:
diff changeset
2840 /* Equality function for semantic items is used to subdivide existing
kono
parents:
diff changeset
2841 classes. If IN_WPA, fast equality function is invoked. */
kono
parents:
diff changeset
2842
kono
parents:
diff changeset
2843 void
kono
parents:
diff changeset
2844 sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
kono
parents:
diff changeset
2845 {
kono
parents:
diff changeset
2846 for (hash_table <congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
2847 it != m_classes.end (); ++it)
kono
parents:
diff changeset
2848 {
kono
parents:
diff changeset
2849 unsigned int class_count = (*it)->classes.length ();
kono
parents:
diff changeset
2850
kono
parents:
diff changeset
2851 for (unsigned i = 0; i < class_count; i++)
kono
parents:
diff changeset
2852 {
kono
parents:
diff changeset
2853 congruence_class *c = (*it)->classes[i];
kono
parents:
diff changeset
2854
kono
parents:
diff changeset
2855 if (c->members.length() > 1)
kono
parents:
diff changeset
2856 {
kono
parents:
diff changeset
2857 auto_vec <sem_item *> new_vector;
kono
parents:
diff changeset
2858
kono
parents:
diff changeset
2859 sem_item *first = c->members[0];
kono
parents:
diff changeset
2860 new_vector.safe_push (first);
kono
parents:
diff changeset
2861
kono
parents:
diff changeset
2862 unsigned class_split_first = (*it)->classes.length ();
kono
parents:
diff changeset
2863
kono
parents:
diff changeset
2864 for (unsigned j = 1; j < c->members.length (); j++)
kono
parents:
diff changeset
2865 {
kono
parents:
diff changeset
2866 sem_item *item = c->members[j];
kono
parents:
diff changeset
2867
kono
parents:
diff changeset
2868 bool equals
kono
parents:
diff changeset
2869 = in_wpa ? first->equals_wpa (item, m_symtab_node_map)
kono
parents:
diff changeset
2870 : first->equals (item, m_symtab_node_map);
kono
parents:
diff changeset
2871
kono
parents:
diff changeset
2872 if (equals)
kono
parents:
diff changeset
2873 new_vector.safe_push (item);
kono
parents:
diff changeset
2874 else
kono
parents:
diff changeset
2875 {
kono
parents:
diff changeset
2876 bool integrated = false;
kono
parents:
diff changeset
2877
kono
parents:
diff changeset
2878 for (unsigned k = class_split_first;
kono
parents:
diff changeset
2879 k < (*it)->classes.length (); k++)
kono
parents:
diff changeset
2880 {
kono
parents:
diff changeset
2881 sem_item *x = (*it)->classes[k]->members[0];
kono
parents:
diff changeset
2882 bool equals
kono
parents:
diff changeset
2883 = in_wpa ? x->equals_wpa (item, m_symtab_node_map)
kono
parents:
diff changeset
2884 : x->equals (item, m_symtab_node_map);
kono
parents:
diff changeset
2885
kono
parents:
diff changeset
2886 if (equals)
kono
parents:
diff changeset
2887 {
kono
parents:
diff changeset
2888 integrated = true;
kono
parents:
diff changeset
2889 add_item_to_class ((*it)->classes[k], item);
kono
parents:
diff changeset
2890
kono
parents:
diff changeset
2891 break;
kono
parents:
diff changeset
2892 }
kono
parents:
diff changeset
2893 }
kono
parents:
diff changeset
2894
kono
parents:
diff changeset
2895 if (!integrated)
kono
parents:
diff changeset
2896 {
kono
parents:
diff changeset
2897 congruence_class *c
kono
parents:
diff changeset
2898 = new congruence_class (class_id++);
kono
parents:
diff changeset
2899 m_classes_count++;
kono
parents:
diff changeset
2900 add_item_to_class (c, item);
kono
parents:
diff changeset
2901
kono
parents:
diff changeset
2902 (*it)->classes.safe_push (c);
kono
parents:
diff changeset
2903 }
kono
parents:
diff changeset
2904 }
kono
parents:
diff changeset
2905 }
kono
parents:
diff changeset
2906
kono
parents:
diff changeset
2907 // We replace newly created new_vector for the class we've just
kono
parents:
diff changeset
2908 // splitted.
kono
parents:
diff changeset
2909 c->members.release ();
kono
parents:
diff changeset
2910 c->members.create (new_vector.length ());
kono
parents:
diff changeset
2911
kono
parents:
diff changeset
2912 for (unsigned int j = 0; j < new_vector.length (); j++)
kono
parents:
diff changeset
2913 add_item_to_class (c, new_vector[j]);
kono
parents:
diff changeset
2914 }
kono
parents:
diff changeset
2915 }
kono
parents:
diff changeset
2916 }
kono
parents:
diff changeset
2917
kono
parents:
diff changeset
2918 checking_verify_classes ();
kono
parents:
diff changeset
2919 }
kono
parents:
diff changeset
2920
kono
parents:
diff changeset
2921 /* Subdivide classes by address references that members of the class
kono
parents:
diff changeset
2922 reference. Example can be a pair of functions that have an address
kono
parents:
diff changeset
2923 taken from a function. If these addresses are different the class
kono
parents:
diff changeset
2924 is split. */
kono
parents:
diff changeset
2925
kono
parents:
diff changeset
2926 unsigned
kono
parents:
diff changeset
2927 sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
kono
parents:
diff changeset
2928 {
kono
parents:
diff changeset
2929 typedef hash_map <symbol_compare_hash, vec <sem_item *> > subdivide_hash_map;
kono
parents:
diff changeset
2930
kono
parents:
diff changeset
2931 unsigned newly_created_classes = 0;
kono
parents:
diff changeset
2932
kono
parents:
diff changeset
2933 for (hash_table <congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
2934 it != m_classes.end (); ++it)
kono
parents:
diff changeset
2935 {
kono
parents:
diff changeset
2936 unsigned int class_count = (*it)->classes.length ();
kono
parents:
diff changeset
2937 auto_vec<congruence_class *> new_classes;
kono
parents:
diff changeset
2938
kono
parents:
diff changeset
2939 for (unsigned i = 0; i < class_count; i++)
kono
parents:
diff changeset
2940 {
kono
parents:
diff changeset
2941 congruence_class *c = (*it)->classes[i];
kono
parents:
diff changeset
2942
kono
parents:
diff changeset
2943 if (c->members.length() > 1)
kono
parents:
diff changeset
2944 {
kono
parents:
diff changeset
2945 subdivide_hash_map split_map;
kono
parents:
diff changeset
2946
kono
parents:
diff changeset
2947 for (unsigned j = 0; j < c->members.length (); j++)
kono
parents:
diff changeset
2948 {
kono
parents:
diff changeset
2949 sem_item *source_node = c->members[j];
kono
parents:
diff changeset
2950
kono
parents:
diff changeset
2951 symbol_compare_collection *collection
kono
parents:
diff changeset
2952 = new symbol_compare_collection (source_node->node);
kono
parents:
diff changeset
2953
kono
parents:
diff changeset
2954 bool existed;
kono
parents:
diff changeset
2955 vec <sem_item *> *slot
kono
parents:
diff changeset
2956 = &split_map.get_or_insert (collection, &existed);
kono
parents:
diff changeset
2957 gcc_checking_assert (slot);
kono
parents:
diff changeset
2958
kono
parents:
diff changeset
2959 slot->safe_push (source_node);
kono
parents:
diff changeset
2960
kono
parents:
diff changeset
2961 if (existed)
kono
parents:
diff changeset
2962 delete collection;
kono
parents:
diff changeset
2963 }
kono
parents:
diff changeset
2964
kono
parents:
diff changeset
2965 /* If the map contains more than one key, we have to split
kono
parents:
diff changeset
2966 the map appropriately. */
kono
parents:
diff changeset
2967 if (split_map.elements () != 1)
kono
parents:
diff changeset
2968 {
kono
parents:
diff changeset
2969 bool first_class = true;
kono
parents:
diff changeset
2970
kono
parents:
diff changeset
2971 for (subdivide_hash_map::iterator it2 = split_map.begin ();
kono
parents:
diff changeset
2972 it2 != split_map.end (); ++it2)
kono
parents:
diff changeset
2973 {
kono
parents:
diff changeset
2974 congruence_class *new_cls;
kono
parents:
diff changeset
2975 new_cls = new congruence_class (class_id++);
kono
parents:
diff changeset
2976
kono
parents:
diff changeset
2977 for (unsigned k = 0; k < (*it2).second.length (); k++)
kono
parents:
diff changeset
2978 add_item_to_class (new_cls, (*it2).second[k]);
kono
parents:
diff changeset
2979
kono
parents:
diff changeset
2980 worklist_push (new_cls);
kono
parents:
diff changeset
2981 newly_created_classes++;
kono
parents:
diff changeset
2982
kono
parents:
diff changeset
2983 if (first_class)
kono
parents:
diff changeset
2984 {
kono
parents:
diff changeset
2985 (*it)->classes[i] = new_cls;
kono
parents:
diff changeset
2986 first_class = false;
kono
parents:
diff changeset
2987 }
kono
parents:
diff changeset
2988 else
kono
parents:
diff changeset
2989 {
kono
parents:
diff changeset
2990 new_classes.safe_push (new_cls);
kono
parents:
diff changeset
2991 m_classes_count++;
kono
parents:
diff changeset
2992 }
kono
parents:
diff changeset
2993 }
kono
parents:
diff changeset
2994 }
kono
parents:
diff changeset
2995
kono
parents:
diff changeset
2996 /* Release memory. */
kono
parents:
diff changeset
2997 for (subdivide_hash_map::iterator it2 = split_map.begin ();
kono
parents:
diff changeset
2998 it2 != split_map.end (); ++it2)
kono
parents:
diff changeset
2999 {
kono
parents:
diff changeset
3000 delete (*it2).first;
kono
parents:
diff changeset
3001 (*it2).second.release ();
kono
parents:
diff changeset
3002 }
kono
parents:
diff changeset
3003 }
kono
parents:
diff changeset
3004 }
kono
parents:
diff changeset
3005
kono
parents:
diff changeset
3006 for (unsigned i = 0; i < new_classes.length (); i++)
kono
parents:
diff changeset
3007 (*it)->classes.safe_push (new_classes[i]);
kono
parents:
diff changeset
3008 }
kono
parents:
diff changeset
3009
kono
parents:
diff changeset
3010 return newly_created_classes;
kono
parents:
diff changeset
3011 }
kono
parents:
diff changeset
3012
kono
parents:
diff changeset
3013 /* Verify congruence classes, if checking is enabled. */
kono
parents:
diff changeset
3014
kono
parents:
diff changeset
3015 void
kono
parents:
diff changeset
3016 sem_item_optimizer::checking_verify_classes (void)
kono
parents:
diff changeset
3017 {
kono
parents:
diff changeset
3018 if (flag_checking)
kono
parents:
diff changeset
3019 verify_classes ();
kono
parents:
diff changeset
3020 }
kono
parents:
diff changeset
3021
kono
parents:
diff changeset
3022 /* Verify congruence classes. */
kono
parents:
diff changeset
3023
kono
parents:
diff changeset
3024 void
kono
parents:
diff changeset
3025 sem_item_optimizer::verify_classes (void)
kono
parents:
diff changeset
3026 {
kono
parents:
diff changeset
3027 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3028 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3029 {
kono
parents:
diff changeset
3030 for (unsigned int i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
3031 {
kono
parents:
diff changeset
3032 congruence_class *cls = (*it)->classes[i];
kono
parents:
diff changeset
3033
kono
parents:
diff changeset
3034 gcc_assert (cls);
kono
parents:
diff changeset
3035 gcc_assert (cls->members.length () > 0);
kono
parents:
diff changeset
3036
kono
parents:
diff changeset
3037 for (unsigned int j = 0; j < cls->members.length (); j++)
kono
parents:
diff changeset
3038 {
kono
parents:
diff changeset
3039 sem_item *item = cls->members[j];
kono
parents:
diff changeset
3040
kono
parents:
diff changeset
3041 gcc_assert (item);
kono
parents:
diff changeset
3042 gcc_assert (item->cls == cls);
kono
parents:
diff changeset
3043
kono
parents:
diff changeset
3044 for (unsigned k = 0; k < item->usages.length (); k++)
kono
parents:
diff changeset
3045 {
kono
parents:
diff changeset
3046 sem_usage_pair *usage = item->usages[k];
kono
parents:
diff changeset
3047 gcc_assert (usage->item->index_in_class
kono
parents:
diff changeset
3048 < usage->item->cls->members.length ());
kono
parents:
diff changeset
3049 }
kono
parents:
diff changeset
3050 }
kono
parents:
diff changeset
3051 }
kono
parents:
diff changeset
3052 }
kono
parents:
diff changeset
3053 }
kono
parents:
diff changeset
3054
kono
parents:
diff changeset
3055 /* Disposes split map traverse function. CLS_PTR is pointer to congruence
kono
parents:
diff changeset
3056 class, BSLOT is bitmap slot we want to release. DATA is mandatory,
kono
parents:
diff changeset
3057 but unused argument. */
kono
parents:
diff changeset
3058
kono
parents:
diff changeset
3059 bool
kono
parents:
diff changeset
3060 sem_item_optimizer::release_split_map (congruence_class * const &,
kono
parents:
diff changeset
3061 bitmap const &b, traverse_split_pair *)
kono
parents:
diff changeset
3062 {
kono
parents:
diff changeset
3063 bitmap bmp = b;
kono
parents:
diff changeset
3064
kono
parents:
diff changeset
3065 BITMAP_FREE (bmp);
kono
parents:
diff changeset
3066
kono
parents:
diff changeset
3067 return true;
kono
parents:
diff changeset
3068 }
kono
parents:
diff changeset
3069
kono
parents:
diff changeset
3070 /* Process split operation for a class given as pointer CLS_PTR,
kono
parents:
diff changeset
3071 where bitmap B splits congruence class members. DATA is used
kono
parents:
diff changeset
3072 as argument of split pair. */
kono
parents:
diff changeset
3073
kono
parents:
diff changeset
3074 bool
kono
parents:
diff changeset
3075 sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
kono
parents:
diff changeset
3076 bitmap const &b,
kono
parents:
diff changeset
3077 traverse_split_pair *pair)
kono
parents:
diff changeset
3078 {
kono
parents:
diff changeset
3079 sem_item_optimizer *optimizer = pair->optimizer;
kono
parents:
diff changeset
3080 const congruence_class *splitter_cls = pair->cls;
kono
parents:
diff changeset
3081
kono
parents:
diff changeset
3082 /* If counted bits are greater than zero and less than the number of members
kono
parents:
diff changeset
3083 a group will be splitted. */
kono
parents:
diff changeset
3084 unsigned popcount = bitmap_count_bits (b);
kono
parents:
diff changeset
3085
kono
parents:
diff changeset
3086 if (popcount > 0 && popcount < cls->members.length ())
kono
parents:
diff changeset
3087 {
kono
parents:
diff changeset
3088 auto_vec <congruence_class *, 2> newclasses;
kono
parents:
diff changeset
3089 newclasses.quick_push (new congruence_class (class_id++));
kono
parents:
diff changeset
3090 newclasses.quick_push (new congruence_class (class_id++));
kono
parents:
diff changeset
3091
kono
parents:
diff changeset
3092 for (unsigned int i = 0; i < cls->members.length (); i++)
kono
parents:
diff changeset
3093 {
kono
parents:
diff changeset
3094 int target = bitmap_bit_p (b, i);
kono
parents:
diff changeset
3095 congruence_class *tc = newclasses[target];
kono
parents:
diff changeset
3096
kono
parents:
diff changeset
3097 add_item_to_class (tc, cls->members[i]);
kono
parents:
diff changeset
3098 }
kono
parents:
diff changeset
3099
kono
parents:
diff changeset
3100 if (flag_checking)
kono
parents:
diff changeset
3101 {
kono
parents:
diff changeset
3102 for (unsigned int i = 0; i < 2; i++)
kono
parents:
diff changeset
3103 gcc_assert (newclasses[i]->members.length ());
kono
parents:
diff changeset
3104 }
kono
parents:
diff changeset
3105
kono
parents:
diff changeset
3106 if (splitter_cls == cls)
kono
parents:
diff changeset
3107 optimizer->splitter_class_removed = true;
kono
parents:
diff changeset
3108
kono
parents:
diff changeset
3109 /* Remove old class from worklist if presented. */
kono
parents:
diff changeset
3110 bool in_worklist = cls->in_worklist;
kono
parents:
diff changeset
3111
kono
parents:
diff changeset
3112 if (in_worklist)
kono
parents:
diff changeset
3113 cls->in_worklist = false;
kono
parents:
diff changeset
3114
kono
parents:
diff changeset
3115 congruence_class_group g;
kono
parents:
diff changeset
3116 g.hash = cls->members[0]->get_hash ();
kono
parents:
diff changeset
3117 g.type = cls->members[0]->type;
kono
parents:
diff changeset
3118
kono
parents:
diff changeset
3119 congruence_class_group *slot = optimizer->m_classes.find (&g);
kono
parents:
diff changeset
3120
kono
parents:
diff changeset
3121 for (unsigned int i = 0; i < slot->classes.length (); i++)
kono
parents:
diff changeset
3122 if (slot->classes[i] == cls)
kono
parents:
diff changeset
3123 {
kono
parents:
diff changeset
3124 slot->classes.ordered_remove (i);
kono
parents:
diff changeset
3125 break;
kono
parents:
diff changeset
3126 }
kono
parents:
diff changeset
3127
kono
parents:
diff changeset
3128 /* New class will be inserted and integrated to work list. */
kono
parents:
diff changeset
3129 for (unsigned int i = 0; i < 2; i++)
kono
parents:
diff changeset
3130 optimizer->add_class (newclasses[i]);
kono
parents:
diff changeset
3131
kono
parents:
diff changeset
3132 /* Two classes replace one, so that increment just by one. */
kono
parents:
diff changeset
3133 optimizer->m_classes_count++;
kono
parents:
diff changeset
3134
kono
parents:
diff changeset
3135 /* If OLD class was presented in the worklist, we remove the class
kono
parents:
diff changeset
3136 and replace it will both newly created classes. */
kono
parents:
diff changeset
3137 if (in_worklist)
kono
parents:
diff changeset
3138 for (unsigned int i = 0; i < 2; i++)
kono
parents:
diff changeset
3139 optimizer->worklist_push (newclasses[i]);
kono
parents:
diff changeset
3140 else /* Just smaller class is inserted. */
kono
parents:
diff changeset
3141 {
kono
parents:
diff changeset
3142 unsigned int smaller_index
kono
parents:
diff changeset
3143 = (newclasses[0]->members.length ()
kono
parents:
diff changeset
3144 < newclasses[1]->members.length ()
kono
parents:
diff changeset
3145 ? 0 : 1);
kono
parents:
diff changeset
3146 optimizer->worklist_push (newclasses[smaller_index]);
kono
parents:
diff changeset
3147 }
kono
parents:
diff changeset
3148
kono
parents:
diff changeset
3149 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
3150 {
kono
parents:
diff changeset
3151 fprintf (dump_file, " congruence class splitted:\n");
kono
parents:
diff changeset
3152 cls->dump (dump_file, 4);
kono
parents:
diff changeset
3153
kono
parents:
diff changeset
3154 fprintf (dump_file, " newly created groups:\n");
kono
parents:
diff changeset
3155 for (unsigned int i = 0; i < 2; i++)
kono
parents:
diff changeset
3156 newclasses[i]->dump (dump_file, 4);
kono
parents:
diff changeset
3157 }
kono
parents:
diff changeset
3158
kono
parents:
diff changeset
3159 /* Release class if not presented in work list. */
kono
parents:
diff changeset
3160 if (!in_worklist)
kono
parents:
diff changeset
3161 delete cls;
kono
parents:
diff changeset
3162 }
kono
parents:
diff changeset
3163
kono
parents:
diff changeset
3164
kono
parents:
diff changeset
3165 return true;
kono
parents:
diff changeset
3166 }
kono
parents:
diff changeset
3167
kono
parents:
diff changeset
3168 /* Tests if a class CLS used as INDEXth splits any congruence classes.
kono
parents:
diff changeset
3169 Bitmap stack BMSTACK is used for bitmap allocation. */
kono
parents:
diff changeset
3170
kono
parents:
diff changeset
3171 void
kono
parents:
diff changeset
3172 sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
kono
parents:
diff changeset
3173 unsigned int index)
kono
parents:
diff changeset
3174 {
kono
parents:
diff changeset
3175 hash_map <congruence_class *, bitmap> split_map;
kono
parents:
diff changeset
3176
kono
parents:
diff changeset
3177 for (unsigned int i = 0; i < cls->members.length (); i++)
kono
parents:
diff changeset
3178 {
kono
parents:
diff changeset
3179 sem_item *item = cls->members[i];
kono
parents:
diff changeset
3180
kono
parents:
diff changeset
3181 /* Iterate all usages that have INDEX as usage of the item. */
kono
parents:
diff changeset
3182 for (unsigned int j = 0; j < item->usages.length (); j++)
kono
parents:
diff changeset
3183 {
kono
parents:
diff changeset
3184 sem_usage_pair *usage = item->usages[j];
kono
parents:
diff changeset
3185
kono
parents:
diff changeset
3186 if (usage->index != index)
kono
parents:
diff changeset
3187 continue;
kono
parents:
diff changeset
3188
kono
parents:
diff changeset
3189 bitmap *slot = split_map.get (usage->item->cls);
kono
parents:
diff changeset
3190 bitmap b;
kono
parents:
diff changeset
3191
kono
parents:
diff changeset
3192 if(!slot)
kono
parents:
diff changeset
3193 {
kono
parents:
diff changeset
3194 b = BITMAP_ALLOC (&m_bmstack);
kono
parents:
diff changeset
3195 split_map.put (usage->item->cls, b);
kono
parents:
diff changeset
3196 }
kono
parents:
diff changeset
3197 else
kono
parents:
diff changeset
3198 b = *slot;
kono
parents:
diff changeset
3199
kono
parents:
diff changeset
3200 gcc_checking_assert (usage->item->cls);
kono
parents:
diff changeset
3201 gcc_checking_assert (usage->item->index_in_class
kono
parents:
diff changeset
3202 < usage->item->cls->members.length ());
kono
parents:
diff changeset
3203
kono
parents:
diff changeset
3204 bitmap_set_bit (b, usage->item->index_in_class);
kono
parents:
diff changeset
3205 }
kono
parents:
diff changeset
3206 }
kono
parents:
diff changeset
3207
kono
parents:
diff changeset
3208 traverse_split_pair pair;
kono
parents:
diff changeset
3209 pair.optimizer = this;
kono
parents:
diff changeset
3210 pair.cls = cls;
kono
parents:
diff changeset
3211
kono
parents:
diff changeset
3212 splitter_class_removed = false;
kono
parents:
diff changeset
3213 split_map.traverse <traverse_split_pair *,
kono
parents:
diff changeset
3214 sem_item_optimizer::traverse_congruence_split> (&pair);
kono
parents:
diff changeset
3215
kono
parents:
diff changeset
3216 /* Bitmap clean-up. */
kono
parents:
diff changeset
3217 split_map.traverse <traverse_split_pair *,
kono
parents:
diff changeset
3218 sem_item_optimizer::release_split_map> (NULL);
kono
parents:
diff changeset
3219 }
kono
parents:
diff changeset
3220
kono
parents:
diff changeset
3221 /* Every usage of a congruence class CLS is a candidate that can split the
kono
parents:
diff changeset
3222 collection of classes. Bitmap stack BMSTACK is used for bitmap
kono
parents:
diff changeset
3223 allocation. */
kono
parents:
diff changeset
3224
kono
parents:
diff changeset
3225 void
kono
parents:
diff changeset
3226 sem_item_optimizer::do_congruence_step (congruence_class *cls)
kono
parents:
diff changeset
3227 {
kono
parents:
diff changeset
3228 bitmap_iterator bi;
kono
parents:
diff changeset
3229 unsigned int i;
kono
parents:
diff changeset
3230
kono
parents:
diff changeset
3231 bitmap usage = BITMAP_ALLOC (&m_bmstack);
kono
parents:
diff changeset
3232
kono
parents:
diff changeset
3233 for (unsigned int i = 0; i < cls->members.length (); i++)
kono
parents:
diff changeset
3234 bitmap_ior_into (usage, cls->members[i]->usage_index_bitmap);
kono
parents:
diff changeset
3235
kono
parents:
diff changeset
3236 EXECUTE_IF_SET_IN_BITMAP (usage, 0, i, bi)
kono
parents:
diff changeset
3237 {
kono
parents:
diff changeset
3238 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
3239 fprintf (dump_file, " processing congruence step for class: %u, "
kono
parents:
diff changeset
3240 "index: %u\n", cls->id, i);
kono
parents:
diff changeset
3241
kono
parents:
diff changeset
3242 do_congruence_step_for_index (cls, i);
kono
parents:
diff changeset
3243
kono
parents:
diff changeset
3244 if (splitter_class_removed)
kono
parents:
diff changeset
3245 break;
kono
parents:
diff changeset
3246 }
kono
parents:
diff changeset
3247
kono
parents:
diff changeset
3248 BITMAP_FREE (usage);
kono
parents:
diff changeset
3249 }
kono
parents:
diff changeset
3250
kono
parents:
diff changeset
3251 /* Adds a newly created congruence class CLS to worklist. */
kono
parents:
diff changeset
3252
kono
parents:
diff changeset
3253 void
kono
parents:
diff changeset
3254 sem_item_optimizer::worklist_push (congruence_class *cls)
kono
parents:
diff changeset
3255 {
kono
parents:
diff changeset
3256 /* Return if the class CLS is already presented in work list. */
kono
parents:
diff changeset
3257 if (cls->in_worklist)
kono
parents:
diff changeset
3258 return;
kono
parents:
diff changeset
3259
kono
parents:
diff changeset
3260 cls->in_worklist = true;
kono
parents:
diff changeset
3261 worklist.push_back (cls);
kono
parents:
diff changeset
3262 }
kono
parents:
diff changeset
3263
kono
parents:
diff changeset
3264 /* Pops a class from worklist. */
kono
parents:
diff changeset
3265
kono
parents:
diff changeset
3266 congruence_class *
kono
parents:
diff changeset
3267 sem_item_optimizer::worklist_pop (void)
kono
parents:
diff changeset
3268 {
kono
parents:
diff changeset
3269 congruence_class *cls;
kono
parents:
diff changeset
3270
kono
parents:
diff changeset
3271 while (!worklist.empty ())
kono
parents:
diff changeset
3272 {
kono
parents:
diff changeset
3273 cls = worklist.front ();
kono
parents:
diff changeset
3274 worklist.pop_front ();
kono
parents:
diff changeset
3275 if (cls->in_worklist)
kono
parents:
diff changeset
3276 {
kono
parents:
diff changeset
3277 cls->in_worklist = false;
kono
parents:
diff changeset
3278
kono
parents:
diff changeset
3279 return cls;
kono
parents:
diff changeset
3280 }
kono
parents:
diff changeset
3281 else
kono
parents:
diff changeset
3282 {
kono
parents:
diff changeset
3283 /* Work list item was already intended to be removed.
kono
parents:
diff changeset
3284 The only reason for doing it is to split a class.
kono
parents:
diff changeset
3285 Thus, the class CLS is deleted. */
kono
parents:
diff changeset
3286 delete cls;
kono
parents:
diff changeset
3287 }
kono
parents:
diff changeset
3288 }
kono
parents:
diff changeset
3289
kono
parents:
diff changeset
3290 return NULL;
kono
parents:
diff changeset
3291 }
kono
parents:
diff changeset
3292
kono
parents:
diff changeset
3293 /* Iterative congruence reduction function. */
kono
parents:
diff changeset
3294
kono
parents:
diff changeset
3295 void
kono
parents:
diff changeset
3296 sem_item_optimizer::process_cong_reduction (void)
kono
parents:
diff changeset
3297 {
kono
parents:
diff changeset
3298 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3299 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3300 for (unsigned i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
3301 if ((*it)->classes[i]->is_class_used ())
kono
parents:
diff changeset
3302 worklist_push ((*it)->classes[i]);
kono
parents:
diff changeset
3303
kono
parents:
diff changeset
3304 if (dump_file)
kono
parents:
diff changeset
3305 fprintf (dump_file, "Worklist has been filled with: %lu\n",
kono
parents:
diff changeset
3306 (unsigned long) worklist.size ());
kono
parents:
diff changeset
3307
kono
parents:
diff changeset
3308 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
3309 fprintf (dump_file, "Congruence class reduction\n");
kono
parents:
diff changeset
3310
kono
parents:
diff changeset
3311 congruence_class *cls;
kono
parents:
diff changeset
3312
kono
parents:
diff changeset
3313 /* Process complete congruence reduction. */
kono
parents:
diff changeset
3314 while ((cls = worklist_pop ()) != NULL)
kono
parents:
diff changeset
3315 do_congruence_step (cls);
kono
parents:
diff changeset
3316
kono
parents:
diff changeset
3317 /* Subdivide newly created classes according to references. */
kono
parents:
diff changeset
3318 unsigned new_classes = subdivide_classes_by_sensitive_refs ();
kono
parents:
diff changeset
3319
kono
parents:
diff changeset
3320 if (dump_file)
kono
parents:
diff changeset
3321 fprintf (dump_file, "Address reference subdivision created: %u "
kono
parents:
diff changeset
3322 "new classes.\n", new_classes);
kono
parents:
diff changeset
3323 }
kono
parents:
diff changeset
3324
kono
parents:
diff changeset
3325 /* Debug function prints all informations about congruence classes. */
kono
parents:
diff changeset
3326
kono
parents:
diff changeset
3327 void
kono
parents:
diff changeset
3328 sem_item_optimizer::dump_cong_classes (void)
kono
parents:
diff changeset
3329 {
kono
parents:
diff changeset
3330 if (!dump_file)
kono
parents:
diff changeset
3331 return;
kono
parents:
diff changeset
3332
kono
parents:
diff changeset
3333 fprintf (dump_file,
kono
parents:
diff changeset
3334 "Congruence classes: %u (unique hash values: %lu), with total: "
kono
parents:
diff changeset
3335 "%u items\n", m_classes_count,
kono
parents:
diff changeset
3336 (unsigned long) m_classes.elements (), m_items.length ());
kono
parents:
diff changeset
3337
kono
parents:
diff changeset
3338 /* Histogram calculation. */
kono
parents:
diff changeset
3339 unsigned int max_index = 0;
kono
parents:
diff changeset
3340 unsigned int* histogram = XCNEWVEC (unsigned int, m_items.length () + 1);
kono
parents:
diff changeset
3341
kono
parents:
diff changeset
3342 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3343 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3344 for (unsigned i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
3345 {
kono
parents:
diff changeset
3346 unsigned int c = (*it)->classes[i]->members.length ();
kono
parents:
diff changeset
3347 histogram[c]++;
kono
parents:
diff changeset
3348
kono
parents:
diff changeset
3349 if (c > max_index)
kono
parents:
diff changeset
3350 max_index = c;
kono
parents:
diff changeset
3351 }
kono
parents:
diff changeset
3352
kono
parents:
diff changeset
3353 fprintf (dump_file,
kono
parents:
diff changeset
3354 "Class size histogram [num of members]: number of classe number "
kono
parents:
diff changeset
3355 "of classess\n");
kono
parents:
diff changeset
3356
kono
parents:
diff changeset
3357 for (unsigned int i = 0; i <= max_index; i++)
kono
parents:
diff changeset
3358 if (histogram[i])
kono
parents:
diff changeset
3359 fprintf (dump_file, "[%u]: %u classes\n", i, histogram[i]);
kono
parents:
diff changeset
3360
kono
parents:
diff changeset
3361 fprintf (dump_file, "\n\n");
kono
parents:
diff changeset
3362
kono
parents:
diff changeset
3363 if (dump_flags & TDF_DETAILS)
kono
parents:
diff changeset
3364 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3365 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3366 {
kono
parents:
diff changeset
3367 fprintf (dump_file, " group: with %u classes:\n",
kono
parents:
diff changeset
3368 (*it)->classes.length ());
kono
parents:
diff changeset
3369
kono
parents:
diff changeset
3370 for (unsigned i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
3371 {
kono
parents:
diff changeset
3372 (*it)->classes[i]->dump (dump_file, 4);
kono
parents:
diff changeset
3373
kono
parents:
diff changeset
3374 if (i < (*it)->classes.length () - 1)
kono
parents:
diff changeset
3375 fprintf (dump_file, " ");
kono
parents:
diff changeset
3376 }
kono
parents:
diff changeset
3377 }
kono
parents:
diff changeset
3378
kono
parents:
diff changeset
3379 free (histogram);
kono
parents:
diff changeset
3380 }
kono
parents:
diff changeset
3381
kono
parents:
diff changeset
3382 /* Sort pair of sem_items A and B by DECL_UID. */
kono
parents:
diff changeset
3383
kono
parents:
diff changeset
3384 static int
kono
parents:
diff changeset
3385 sort_sem_items_by_decl_uid (const void *a, const void *b)
kono
parents:
diff changeset
3386 {
kono
parents:
diff changeset
3387 const sem_item *i1 = *(const sem_item * const *)a;
kono
parents:
diff changeset
3388 const sem_item *i2 = *(const sem_item * const *)b;
kono
parents:
diff changeset
3389
kono
parents:
diff changeset
3390 int uid1 = DECL_UID (i1->decl);
kono
parents:
diff changeset
3391 int uid2 = DECL_UID (i2->decl);
kono
parents:
diff changeset
3392
kono
parents:
diff changeset
3393 if (uid1 < uid2)
kono
parents:
diff changeset
3394 return -1;
kono
parents:
diff changeset
3395 else if (uid1 > uid2)
kono
parents:
diff changeset
3396 return 1;
kono
parents:
diff changeset
3397 else
kono
parents:
diff changeset
3398 return 0;
kono
parents:
diff changeset
3399 }
kono
parents:
diff changeset
3400
kono
parents:
diff changeset
3401 /* Sort pair of congruence_classes A and B by DECL_UID of the first member. */
kono
parents:
diff changeset
3402
kono
parents:
diff changeset
3403 static int
kono
parents:
diff changeset
3404 sort_congruence_classes_by_decl_uid (const void *a, const void *b)
kono
parents:
diff changeset
3405 {
kono
parents:
diff changeset
3406 const congruence_class *c1 = *(const congruence_class * const *)a;
kono
parents:
diff changeset
3407 const congruence_class *c2 = *(const congruence_class * const *)b;
kono
parents:
diff changeset
3408
kono
parents:
diff changeset
3409 int uid1 = DECL_UID (c1->members[0]->decl);
kono
parents:
diff changeset
3410 int uid2 = DECL_UID (c2->members[0]->decl);
kono
parents:
diff changeset
3411
kono
parents:
diff changeset
3412 if (uid1 < uid2)
kono
parents:
diff changeset
3413 return -1;
kono
parents:
diff changeset
3414 else if (uid1 > uid2)
kono
parents:
diff changeset
3415 return 1;
kono
parents:
diff changeset
3416 else
kono
parents:
diff changeset
3417 return 0;
kono
parents:
diff changeset
3418 }
kono
parents:
diff changeset
3419
kono
parents:
diff changeset
3420 /* Sort pair of congruence_class_groups A and B by
kono
parents:
diff changeset
3421 DECL_UID of the first member of a first group. */
kono
parents:
diff changeset
3422
kono
parents:
diff changeset
3423 static int
kono
parents:
diff changeset
3424 sort_congruence_class_groups_by_decl_uid (const void *a, const void *b)
kono
parents:
diff changeset
3425 {
kono
parents:
diff changeset
3426 const congruence_class_group *g1
kono
parents:
diff changeset
3427 = *(const congruence_class_group * const *)a;
kono
parents:
diff changeset
3428 const congruence_class_group *g2
kono
parents:
diff changeset
3429 = *(const congruence_class_group * const *)b;
kono
parents:
diff changeset
3430
kono
parents:
diff changeset
3431 int uid1 = DECL_UID (g1->classes[0]->members[0]->decl);
kono
parents:
diff changeset
3432 int uid2 = DECL_UID (g2->classes[0]->members[0]->decl);
kono
parents:
diff changeset
3433
kono
parents:
diff changeset
3434 if (uid1 < uid2)
kono
parents:
diff changeset
3435 return -1;
kono
parents:
diff changeset
3436 else if (uid1 > uid2)
kono
parents:
diff changeset
3437 return 1;
kono
parents:
diff changeset
3438 else
kono
parents:
diff changeset
3439 return 0;
kono
parents:
diff changeset
3440 }
kono
parents:
diff changeset
3441
kono
parents:
diff changeset
3442 /* After reduction is done, we can declare all items in a group
kono
parents:
diff changeset
3443 to be equal. PREV_CLASS_COUNT is start number of classes
kono
parents:
diff changeset
3444 before reduction. True is returned if there's a merge operation
kono
parents:
diff changeset
3445 processed. */
kono
parents:
diff changeset
3446
kono
parents:
diff changeset
3447 bool
kono
parents:
diff changeset
3448 sem_item_optimizer::merge_classes (unsigned int prev_class_count)
kono
parents:
diff changeset
3449 {
kono
parents:
diff changeset
3450 unsigned int item_count = m_items.length ();
kono
parents:
diff changeset
3451 unsigned int class_count = m_classes_count;
kono
parents:
diff changeset
3452 unsigned int equal_items = item_count - class_count;
kono
parents:
diff changeset
3453
kono
parents:
diff changeset
3454 unsigned int non_singular_classes_count = 0;
kono
parents:
diff changeset
3455 unsigned int non_singular_classes_sum = 0;
kono
parents:
diff changeset
3456
kono
parents:
diff changeset
3457 bool merged_p = false;
kono
parents:
diff changeset
3458
kono
parents:
diff changeset
3459 /* PR lto/78211
kono
parents:
diff changeset
3460 Sort functions in congruence classes by DECL_UID and do the same
kono
parents:
diff changeset
3461 for the classes to not to break -fcompare-debug. */
kono
parents:
diff changeset
3462
kono
parents:
diff changeset
3463 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3464 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3465 {
kono
parents:
diff changeset
3466 for (unsigned int i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
3467 {
kono
parents:
diff changeset
3468 congruence_class *c = (*it)->classes[i];
kono
parents:
diff changeset
3469 c->members.qsort (sort_sem_items_by_decl_uid);
kono
parents:
diff changeset
3470 }
kono
parents:
diff changeset
3471
kono
parents:
diff changeset
3472 (*it)->classes.qsort (sort_congruence_classes_by_decl_uid);
kono
parents:
diff changeset
3473 }
kono
parents:
diff changeset
3474
kono
parents:
diff changeset
3475 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3476 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3477 for (unsigned int i = 0; i < (*it)->classes.length (); i++)
kono
parents:
diff changeset
3478 {
kono
parents:
diff changeset
3479 congruence_class *c = (*it)->classes[i];
kono
parents:
diff changeset
3480 if (c->members.length () > 1)
kono
parents:
diff changeset
3481 {
kono
parents:
diff changeset
3482 non_singular_classes_count++;
kono
parents:
diff changeset
3483 non_singular_classes_sum += c->members.length ();
kono
parents:
diff changeset
3484 }
kono
parents:
diff changeset
3485 }
kono
parents:
diff changeset
3486
kono
parents:
diff changeset
3487 auto_vec <congruence_class_group *> classes (m_classes.elements ());
kono
parents:
diff changeset
3488 for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
kono
parents:
diff changeset
3489 it != m_classes.end (); ++it)
kono
parents:
diff changeset
3490 classes.quick_push (*it);
kono
parents:
diff changeset
3491
kono
parents:
diff changeset
3492 classes.qsort (sort_congruence_class_groups_by_decl_uid);
kono
parents:
diff changeset
3493
kono
parents:
diff changeset
3494 if (dump_file)
kono
parents:
diff changeset
3495 {
kono
parents:
diff changeset
3496 fprintf (dump_file, "\nItem count: %u\n", item_count);
kono
parents:
diff changeset
3497 fprintf (dump_file, "Congruent classes before: %u, after: %u\n",
kono
parents:
diff changeset
3498 prev_class_count, class_count);
kono
parents:
diff changeset
3499 fprintf (dump_file, "Average class size before: %.2f, after: %.2f\n",
kono
parents:
diff changeset
3500 prev_class_count ? 1.0f * item_count / prev_class_count : 0.0f,
kono
parents:
diff changeset
3501 class_count ? 1.0f * item_count / class_count : 0.0f);
kono
parents:
diff changeset
3502 fprintf (dump_file, "Average non-singular class size: %.2f, count: %u\n",
kono
parents:
diff changeset
3503 non_singular_classes_count ? 1.0f * non_singular_classes_sum /
kono
parents:
diff changeset
3504 non_singular_classes_count : 0.0f,
kono
parents:
diff changeset
3505 non_singular_classes_count);
kono
parents:
diff changeset
3506 fprintf (dump_file, "Equal symbols: %u\n", equal_items);
kono
parents:
diff changeset
3507 fprintf (dump_file, "Fraction of visited symbols: %.2f%%\n\n",
kono
parents:
diff changeset
3508 item_count ? 100.0f * equal_items / item_count : 0.0f);
kono
parents:
diff changeset
3509 }
kono
parents:
diff changeset
3510
kono
parents:
diff changeset
3511 unsigned int l;
kono
parents:
diff changeset
3512 congruence_class_group *it;
kono
parents:
diff changeset
3513 FOR_EACH_VEC_ELT (classes, l, it)
kono
parents:
diff changeset
3514 for (unsigned int i = 0; i < it->classes.length (); i++)
kono
parents:
diff changeset
3515 {
kono
parents:
diff changeset
3516 congruence_class *c = it->classes[i];
kono
parents:
diff changeset
3517
kono
parents:
diff changeset
3518 if (c->members.length () == 1)
kono
parents:
diff changeset
3519 continue;
kono
parents:
diff changeset
3520
kono
parents:
diff changeset
3521 sem_item *source = c->members[0];
kono
parents:
diff changeset
3522
kono
parents:
diff changeset
3523 if (DECL_NAME (source->decl)
kono
parents:
diff changeset
3524 && MAIN_NAME_P (DECL_NAME (source->decl)))
kono
parents:
diff changeset
3525 /* If merge via wrappers, picking main as the target can be
kono
parents:
diff changeset
3526 problematic. */
kono
parents:
diff changeset
3527 source = c->members[1];
kono
parents:
diff changeset
3528
kono
parents:
diff changeset
3529 for (unsigned int j = 0; j < c->members.length (); j++)
kono
parents:
diff changeset
3530 {
kono
parents:
diff changeset
3531 sem_item *alias = c->members[j];
kono
parents:
diff changeset
3532
kono
parents:
diff changeset
3533 if (alias == source)
kono
parents:
diff changeset
3534 continue;
kono
parents:
diff changeset
3535
kono
parents:
diff changeset
3536 if (dump_file)
kono
parents:
diff changeset
3537 {
kono
parents:
diff changeset
3538 fprintf (dump_file, "Semantic equality hit:%s->%s\n",
kono
parents:
diff changeset
3539 xstrdup_for_dump (source->node->name ()),
kono
parents:
diff changeset
3540 xstrdup_for_dump (alias->node->name ()));
kono
parents:
diff changeset
3541 fprintf (dump_file, "Assembler symbol names:%s->%s\n",
kono
parents:
diff changeset
3542 xstrdup_for_dump (source->node->asm_name ()),
kono
parents:
diff changeset
3543 xstrdup_for_dump (alias->node->asm_name ()));
kono
parents:
diff changeset
3544 }
kono
parents:
diff changeset
3545
kono
parents:
diff changeset
3546 if (lookup_attribute ("no_icf", DECL_ATTRIBUTES (alias->decl)))
kono
parents:
diff changeset
3547 {
kono
parents:
diff changeset
3548 if (dump_file)
kono
parents:
diff changeset
3549 fprintf (dump_file,
kono
parents:
diff changeset
3550 "Merge operation is skipped due to no_icf "
kono
parents:
diff changeset
3551 "attribute.\n\n");
kono
parents:
diff changeset
3552
kono
parents:
diff changeset
3553 continue;
kono
parents:
diff changeset
3554 }
kono
parents:
diff changeset
3555
kono
parents:
diff changeset
3556 if (dump_file && (dump_flags & TDF_DETAILS))
kono
parents:
diff changeset
3557 {
kono
parents:
diff changeset
3558 source->dump_to_file (dump_file);
kono
parents:
diff changeset
3559 alias->dump_to_file (dump_file);
kono
parents:
diff changeset
3560 }
kono
parents:
diff changeset
3561
kono
parents:
diff changeset
3562 if (dbg_cnt (merged_ipa_icf))
kono
parents:
diff changeset
3563 merged_p |= source->merge (alias);
kono
parents:
diff changeset
3564 }
kono
parents:
diff changeset
3565 }
kono
parents:
diff changeset
3566
kono
parents:
diff changeset
3567 return merged_p;
kono
parents:
diff changeset
3568 }
kono
parents:
diff changeset
3569
kono
parents:
diff changeset
3570 /* Dump function prints all class members to a FILE with an INDENT. */
kono
parents:
diff changeset
3571
kono
parents:
diff changeset
3572 void
kono
parents:
diff changeset
3573 congruence_class::dump (FILE *file, unsigned int indent) const
kono
parents:
diff changeset
3574 {
kono
parents:
diff changeset
3575 FPRINTF_SPACES (file, indent, "class with id: %u, hash: %u, items: %u\n",
kono
parents:
diff changeset
3576 id, members[0]->get_hash (), members.length ());
kono
parents:
diff changeset
3577
kono
parents:
diff changeset
3578 FPUTS_SPACES (file, indent + 2, "");
kono
parents:
diff changeset
3579 for (unsigned i = 0; i < members.length (); i++)
kono
parents:
diff changeset
3580 fprintf (file, "%s ", members[i]->node->dump_asm_name ());
kono
parents:
diff changeset
3581
kono
parents:
diff changeset
3582 fprintf (file, "\n");
kono
parents:
diff changeset
3583 }
kono
parents:
diff changeset
3584
kono
parents:
diff changeset
3585 /* Returns true if there's a member that is used from another group. */
kono
parents:
diff changeset
3586
kono
parents:
diff changeset
3587 bool
kono
parents:
diff changeset
3588 congruence_class::is_class_used (void)
kono
parents:
diff changeset
3589 {
kono
parents:
diff changeset
3590 for (unsigned int i = 0; i < members.length (); i++)
kono
parents:
diff changeset
3591 if (members[i]->usages.length ())
kono
parents:
diff changeset
3592 return true;
kono
parents:
diff changeset
3593
kono
parents:
diff changeset
3594 return false;
kono
parents:
diff changeset
3595 }
kono
parents:
diff changeset
3596
kono
parents:
diff changeset
3597 /* Generate pass summary for IPA ICF pass. */
kono
parents:
diff changeset
3598
kono
parents:
diff changeset
3599 static void
kono
parents:
diff changeset
3600 ipa_icf_generate_summary (void)
kono
parents:
diff changeset
3601 {
kono
parents:
diff changeset
3602 if (!optimizer)
kono
parents:
diff changeset
3603 optimizer = new sem_item_optimizer ();
kono
parents:
diff changeset
3604
kono
parents:
diff changeset
3605 optimizer->register_hooks ();
kono
parents:
diff changeset
3606 optimizer->parse_funcs_and_vars ();
kono
parents:
diff changeset
3607 }
kono
parents:
diff changeset
3608
kono
parents:
diff changeset
3609 /* Write pass summary for IPA ICF pass. */
kono
parents:
diff changeset
3610
kono
parents:
diff changeset
3611 static void
kono
parents:
diff changeset
3612 ipa_icf_write_summary (void)
kono
parents:
diff changeset
3613 {
kono
parents:
diff changeset
3614 gcc_assert (optimizer);
kono
parents:
diff changeset
3615
kono
parents:
diff changeset
3616 optimizer->write_summary ();
kono
parents:
diff changeset
3617 }
kono
parents:
diff changeset
3618
kono
parents:
diff changeset
3619 /* Read pass summary for IPA ICF pass. */
kono
parents:
diff changeset
3620
kono
parents:
diff changeset
3621 static void
kono
parents:
diff changeset
3622 ipa_icf_read_summary (void)
kono
parents:
diff changeset
3623 {
kono
parents:
diff changeset
3624 if (!optimizer)
kono
parents:
diff changeset
3625 optimizer = new sem_item_optimizer ();
kono
parents:
diff changeset
3626
kono
parents:
diff changeset
3627 optimizer->read_summary ();
kono
parents:
diff changeset
3628 optimizer->register_hooks ();
kono
parents:
diff changeset
3629 }
kono
parents:
diff changeset
3630
kono
parents:
diff changeset
3631 /* Semantic equality exection function. */
kono
parents:
diff changeset
3632
kono
parents:
diff changeset
3633 static unsigned int
kono
parents:
diff changeset
3634 ipa_icf_driver (void)
kono
parents:
diff changeset
3635 {
kono
parents:
diff changeset
3636 gcc_assert (optimizer);
kono
parents:
diff changeset
3637
kono
parents:
diff changeset
3638 bool merged_p = optimizer->execute ();
kono
parents:
diff changeset
3639
kono
parents:
diff changeset
3640 delete optimizer;
kono
parents:
diff changeset
3641 optimizer = NULL;
kono
parents:
diff changeset
3642
kono
parents:
diff changeset
3643 return merged_p ? TODO_remove_functions : 0;
kono
parents:
diff changeset
3644 }
kono
parents:
diff changeset
3645
kono
parents:
diff changeset
3646 const pass_data pass_data_ipa_icf =
kono
parents:
diff changeset
3647 {
kono
parents:
diff changeset
3648 IPA_PASS, /* type */
kono
parents:
diff changeset
3649 "icf", /* name */
kono
parents:
diff changeset
3650 OPTGROUP_IPA, /* optinfo_flags */
kono
parents:
diff changeset
3651 TV_IPA_ICF, /* tv_id */
kono
parents:
diff changeset
3652 0, /* properties_required */
kono
parents:
diff changeset
3653 0, /* properties_provided */
kono
parents:
diff changeset
3654 0, /* properties_destroyed */
kono
parents:
diff changeset
3655 0, /* todo_flags_start */
kono
parents:
diff changeset
3656 0, /* todo_flags_finish */
kono
parents:
diff changeset
3657 };
kono
parents:
diff changeset
3658
kono
parents:
diff changeset
3659 class pass_ipa_icf : public ipa_opt_pass_d
kono
parents:
diff changeset
3660 {
kono
parents:
diff changeset
3661 public:
kono
parents:
diff changeset
3662 pass_ipa_icf (gcc::context *ctxt)
kono
parents:
diff changeset
3663 : ipa_opt_pass_d (pass_data_ipa_icf, ctxt,
kono
parents:
diff changeset
3664 ipa_icf_generate_summary, /* generate_summary */
kono
parents:
diff changeset
3665 ipa_icf_write_summary, /* write_summary */
kono
parents:
diff changeset
3666 ipa_icf_read_summary, /* read_summary */
kono
parents:
diff changeset
3667 NULL, /*
kono
parents:
diff changeset
3668 write_optimization_summary */
kono
parents:
diff changeset
3669 NULL, /*
kono
parents:
diff changeset
3670 read_optimization_summary */
kono
parents:
diff changeset
3671 NULL, /* stmt_fixup */
kono
parents:
diff changeset
3672 0, /* function_transform_todo_flags_start */
kono
parents:
diff changeset
3673 NULL, /* function_transform */
kono
parents:
diff changeset
3674 NULL) /* variable_transform */
kono
parents:
diff changeset
3675 {}
kono
parents:
diff changeset
3676
kono
parents:
diff changeset
3677 /* opt_pass methods: */
kono
parents:
diff changeset
3678 virtual bool gate (function *)
kono
parents:
diff changeset
3679 {
kono
parents:
diff changeset
3680 return in_lto_p || flag_ipa_icf_variables || flag_ipa_icf_functions;
kono
parents:
diff changeset
3681 }
kono
parents:
diff changeset
3682
kono
parents:
diff changeset
3683 virtual unsigned int execute (function *)
kono
parents:
diff changeset
3684 {
kono
parents:
diff changeset
3685 return ipa_icf_driver();
kono
parents:
diff changeset
3686 }
kono
parents:
diff changeset
3687 }; // class pass_ipa_icf
kono
parents:
diff changeset
3688
kono
parents:
diff changeset
3689 } // ipa_icf namespace
kono
parents:
diff changeset
3690
kono
parents:
diff changeset
3691 ipa_opt_pass_d *
kono
parents:
diff changeset
3692 make_pass_ipa_icf (gcc::context *ctxt)
kono
parents:
diff changeset
3693 {
kono
parents:
diff changeset
3694 return new ipa_icf::pass_ipa_icf (ctxt);
kono
parents:
diff changeset
3695 }