138fd1498Szrj /* Interprocedural Identical Code Folding pass
238fd1498Szrj Copyright (C) 2014-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj Contributed by Jan Hubicka <hubicka@ucw.cz> and Martin Liska <mliska@suse.cz>
538fd1498Szrj
638fd1498Szrj This file is part of GCC.
738fd1498Szrj
838fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
938fd1498Szrj the terms of the GNU General Public License as published by the Free
1038fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1138fd1498Szrj version.
1238fd1498Szrj
1338fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1438fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1538fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1638fd1498Szrj for more details.
1738fd1498Szrj
1838fd1498Szrj You should have received a copy of the GNU General Public License
1938fd1498Szrj along with GCC; see the file COPYING3. If not see
2038fd1498Szrj <http://www.gnu.org/licenses/>. */
2138fd1498Szrj
2238fd1498Szrj /* Interprocedural Identical Code Folding for functions and
2338fd1498Szrj read-only variables.
2438fd1498Szrj
2538fd1498Szrj The goal of this transformation is to discover functions and read-only
2638fd1498Szrj variables which do have exactly the same semantics.
2738fd1498Szrj
2838fd1498Szrj In case of functions,
2938fd1498Szrj we could either create a virtual clone or do a simple function wrapper
3038fd1498Szrj that will call equivalent function. If the function is just locally visible,
3138fd1498Szrj all function calls can be redirected. For read-only variables, we create
3238fd1498Szrj aliases if possible.
3338fd1498Szrj
3438fd1498Szrj Optimization pass arranges as follows:
3538fd1498Szrj 1) All functions and read-only variables are visited and internal
3638fd1498Szrj data structure, either sem_function or sem_variables is created.
3738fd1498Szrj 2) For every symbol from the previous step, VAR_DECL and FUNCTION_DECL are
3838fd1498Szrj saved and matched to corresponding sem_items.
3938fd1498Szrj 3) These declaration are ignored for equality check and are solved
4038fd1498Szrj by Value Numbering algorithm published by Alpert, Zadeck in 1992.
4138fd1498Szrj 4) We compute hash value for each symbol.
4238fd1498Szrj 5) Congruence classes are created based on hash value. If hash value are
4338fd1498Szrj equal, equals function is called and symbols are deeply compared.
4438fd1498Szrj We must prove that all SSA names, declarations and other items
4538fd1498Szrj correspond.
4638fd1498Szrj 6) Value Numbering is executed for these classes. At the end of the process
4738fd1498Szrj all symbol members in remaining classes can be merged.
4838fd1498Szrj 7) Merge operation creates alias in case of read-only variables. For
4938fd1498Szrj callgraph node, we must decide if we can redirect local calls,
5038fd1498Szrj create an alias or a thunk.
5138fd1498Szrj
5238fd1498Szrj */
5338fd1498Szrj
5438fd1498Szrj #include "config.h"
5538fd1498Szrj #define INCLUDE_LIST
5638fd1498Szrj #include "system.h"
5738fd1498Szrj #include "coretypes.h"
5838fd1498Szrj #include "backend.h"
5938fd1498Szrj #include "target.h"
6038fd1498Szrj #include "rtl.h"
6138fd1498Szrj #include "tree.h"
6238fd1498Szrj #include "gimple.h"
6338fd1498Szrj #include "alloc-pool.h"
6438fd1498Szrj #include "tree-pass.h"
6538fd1498Szrj #include "ssa.h"
6638fd1498Szrj #include "cgraph.h"
6738fd1498Szrj #include "coverage.h"
6838fd1498Szrj #include "gimple-pretty-print.h"
6938fd1498Szrj #include "data-streamer.h"
7038fd1498Szrj #include "fold-const.h"
7138fd1498Szrj #include "calls.h"
7238fd1498Szrj #include "varasm.h"
7338fd1498Szrj #include "gimple-iterator.h"
7438fd1498Szrj #include "tree-cfg.h"
7538fd1498Szrj #include "symbol-summary.h"
7638fd1498Szrj #include "ipa-prop.h"
7738fd1498Szrj #include "ipa-fnsummary.h"
7838fd1498Szrj #include "except.h"
7938fd1498Szrj #include "attribs.h"
8038fd1498Szrj #include "print-tree.h"
8138fd1498Szrj #include "ipa-utils.h"
8238fd1498Szrj #include "ipa-icf-gimple.h"
8338fd1498Szrj #include "ipa-icf.h"
8438fd1498Szrj #include "stor-layout.h"
8538fd1498Szrj #include "dbgcnt.h"
8638fd1498Szrj #include "tree-vector-builder.h"
8738fd1498Szrj
8838fd1498Szrj using namespace ipa_icf_gimple;
8938fd1498Szrj
9038fd1498Szrj namespace ipa_icf {
9138fd1498Szrj
9238fd1498Szrj /* Initialization and computation of symtab node hash, there data
9338fd1498Szrj are propagated later on. */
9438fd1498Szrj
9538fd1498Szrj static sem_item_optimizer *optimizer = NULL;
9638fd1498Szrj
9738fd1498Szrj /* Constructor. */
9838fd1498Szrj
symbol_compare_collection(symtab_node * node)9938fd1498Szrj symbol_compare_collection::symbol_compare_collection (symtab_node *node)
10038fd1498Szrj {
10138fd1498Szrj m_references.create (0);
10238fd1498Szrj m_interposables.create (0);
10338fd1498Szrj
10438fd1498Szrj ipa_ref *ref;
10538fd1498Szrj
10638fd1498Szrj if (is_a <varpool_node *> (node) && DECL_VIRTUAL_P (node->decl))
10738fd1498Szrj return;
10838fd1498Szrj
10938fd1498Szrj for (unsigned i = 0; node->iterate_reference (i, ref); i++)
11038fd1498Szrj {
11138fd1498Szrj if (ref->address_matters_p ())
11238fd1498Szrj m_references.safe_push (ref->referred);
11338fd1498Szrj
11438fd1498Szrj if (ref->referred->get_availability () <= AVAIL_INTERPOSABLE)
11538fd1498Szrj {
11638fd1498Szrj if (ref->address_matters_p ())
11738fd1498Szrj m_references.safe_push (ref->referred);
11838fd1498Szrj else
11938fd1498Szrj m_interposables.safe_push (ref->referred);
12038fd1498Szrj }
12138fd1498Szrj }
12238fd1498Szrj
12338fd1498Szrj if (is_a <cgraph_node *> (node))
12438fd1498Szrj {
12538fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
12638fd1498Szrj
12738fd1498Szrj for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
12838fd1498Szrj if (e->callee->get_availability () <= AVAIL_INTERPOSABLE)
12938fd1498Szrj m_interposables.safe_push (e->callee);
13038fd1498Szrj }
13138fd1498Szrj }
13238fd1498Szrj
13338fd1498Szrj /* Constructor for key value pair, where _ITEM is key and _INDEX is a target. */
13438fd1498Szrj
sem_usage_pair(sem_item * _item,unsigned int _index)13538fd1498Szrj sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index)
13638fd1498Szrj : item (_item), index (_index)
13738fd1498Szrj {
13838fd1498Szrj }
13938fd1498Szrj
sem_item(sem_item_type _type,bitmap_obstack * stack)14038fd1498Szrj sem_item::sem_item (sem_item_type _type, bitmap_obstack *stack)
14138fd1498Szrj : type (_type), m_hash (-1), m_hash_set (false)
14238fd1498Szrj {
14338fd1498Szrj setup (stack);
14438fd1498Szrj }
14538fd1498Szrj
sem_item(sem_item_type _type,symtab_node * _node,bitmap_obstack * stack)14638fd1498Szrj sem_item::sem_item (sem_item_type _type, symtab_node *_node,
14738fd1498Szrj bitmap_obstack *stack)
14838fd1498Szrj : type (_type), node (_node), m_hash (-1), m_hash_set (false)
14938fd1498Szrj {
15038fd1498Szrj decl = node->decl;
15138fd1498Szrj setup (stack);
15238fd1498Szrj }
15338fd1498Szrj
15438fd1498Szrj /* Add reference to a semantic TARGET. */
15538fd1498Szrj
15638fd1498Szrj void
add_reference(sem_item * target)15738fd1498Szrj sem_item::add_reference (sem_item *target)
15838fd1498Szrj {
15938fd1498Szrj refs.safe_push (target);
16038fd1498Szrj unsigned index = refs.length ();
16138fd1498Szrj target->usages.safe_push (new sem_usage_pair(this, index));
16238fd1498Szrj bitmap_set_bit (target->usage_index_bitmap, index);
16338fd1498Szrj refs_set.add (target->node);
16438fd1498Szrj }
16538fd1498Szrj
16638fd1498Szrj /* Initialize internal data structures. Bitmap STACK is used for
16738fd1498Szrj bitmap memory allocation process. */
16838fd1498Szrj
16938fd1498Szrj void
setup(bitmap_obstack * stack)17038fd1498Szrj sem_item::setup (bitmap_obstack *stack)
17138fd1498Szrj {
17238fd1498Szrj gcc_checking_assert (node);
17338fd1498Szrj
17438fd1498Szrj refs.create (0);
17538fd1498Szrj tree_refs.create (0);
17638fd1498Szrj usages.create (0);
17738fd1498Szrj usage_index_bitmap = BITMAP_ALLOC (stack);
17838fd1498Szrj }
17938fd1498Szrj
~sem_item()18038fd1498Szrj sem_item::~sem_item ()
18138fd1498Szrj {
18238fd1498Szrj for (unsigned i = 0; i < usages.length (); i++)
18338fd1498Szrj delete usages[i];
18438fd1498Szrj
18538fd1498Szrj refs.release ();
18638fd1498Szrj tree_refs.release ();
18738fd1498Szrj usages.release ();
18838fd1498Szrj
18938fd1498Szrj BITMAP_FREE (usage_index_bitmap);
19038fd1498Szrj }
19138fd1498Szrj
19238fd1498Szrj /* Dump function for debugging purpose. */
19338fd1498Szrj
19438fd1498Szrj DEBUG_FUNCTION void
dump(void)19538fd1498Szrj sem_item::dump (void)
19638fd1498Szrj {
19738fd1498Szrj if (dump_file)
19838fd1498Szrj {
19938fd1498Szrj fprintf (dump_file, "[%s] %s (tree:%p)\n", type == FUNC ? "func" : "var",
20038fd1498Szrj node->dump_name (), (void *) node->decl);
20138fd1498Szrj fprintf (dump_file, " hash: %u\n", get_hash ());
20238fd1498Szrj fprintf (dump_file, " references: ");
20338fd1498Szrj
20438fd1498Szrj for (unsigned i = 0; i < refs.length (); i++)
20538fd1498Szrj fprintf (dump_file, "%s%s ", refs[i]->node->name (),
20638fd1498Szrj i < refs.length() - 1 ? "," : "");
20738fd1498Szrj
20838fd1498Szrj fprintf (dump_file, "\n");
20938fd1498Szrj }
21038fd1498Szrj }
21138fd1498Szrj
21238fd1498Szrj /* Return true if target supports alias symbols. */
21338fd1498Szrj
21438fd1498Szrj bool
target_supports_symbol_aliases_p(void)21538fd1498Szrj sem_item::target_supports_symbol_aliases_p (void)
21638fd1498Szrj {
21738fd1498Szrj #if !defined (ASM_OUTPUT_DEF) || (!defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL))
21838fd1498Szrj return false;
21938fd1498Szrj #else
22038fd1498Szrj return true;
22138fd1498Szrj #endif
22238fd1498Szrj }
22338fd1498Szrj
set_hash(hashval_t hash)22438fd1498Szrj void sem_item::set_hash (hashval_t hash)
22538fd1498Szrj {
22638fd1498Szrj m_hash = hash;
22738fd1498Szrj m_hash_set = true;
22838fd1498Szrj }
22938fd1498Szrj
23038fd1498Szrj /* Semantic function constructor that uses STACK as bitmap memory stack. */
23138fd1498Szrj
sem_function(bitmap_obstack * stack)23238fd1498Szrj sem_function::sem_function (bitmap_obstack *stack)
23338fd1498Szrj : sem_item (FUNC, stack), m_checker (NULL), m_compared_func (NULL)
23438fd1498Szrj {
23538fd1498Szrj bb_sizes.create (0);
23638fd1498Szrj bb_sorted.create (0);
23738fd1498Szrj }
23838fd1498Szrj
sem_function(cgraph_node * node,bitmap_obstack * stack)23938fd1498Szrj sem_function::sem_function (cgraph_node *node, bitmap_obstack *stack)
24038fd1498Szrj : sem_item (FUNC, node, stack), m_checker (NULL), m_compared_func (NULL)
24138fd1498Szrj {
24238fd1498Szrj bb_sizes.create (0);
24338fd1498Szrj bb_sorted.create (0);
24438fd1498Szrj }
24538fd1498Szrj
~sem_function()24638fd1498Szrj sem_function::~sem_function ()
24738fd1498Szrj {
24838fd1498Szrj for (unsigned i = 0; i < bb_sorted.length (); i++)
24938fd1498Szrj delete (bb_sorted[i]);
25038fd1498Szrj
25138fd1498Szrj bb_sizes.release ();
25238fd1498Szrj bb_sorted.release ();
25338fd1498Szrj }
25438fd1498Szrj
25538fd1498Szrj /* Calculates hash value based on a BASIC_BLOCK. */
25638fd1498Szrj
25738fd1498Szrj hashval_t
get_bb_hash(const sem_bb * basic_block)25838fd1498Szrj sem_function::get_bb_hash (const sem_bb *basic_block)
25938fd1498Szrj {
26038fd1498Szrj inchash::hash hstate;
26138fd1498Szrj
26238fd1498Szrj hstate.add_int (basic_block->nondbg_stmt_count);
26338fd1498Szrj hstate.add_int (basic_block->edge_count);
26438fd1498Szrj
26538fd1498Szrj return hstate.end ();
26638fd1498Szrj }
26738fd1498Szrj
26838fd1498Szrj /* References independent hash function. */
26938fd1498Szrj
27038fd1498Szrj hashval_t
get_hash(void)27138fd1498Szrj sem_function::get_hash (void)
27238fd1498Szrj {
27338fd1498Szrj if (!m_hash_set)
27438fd1498Szrj {
27538fd1498Szrj inchash::hash hstate;
27638fd1498Szrj hstate.add_int (177454); /* Random number for function type. */
27738fd1498Szrj
27838fd1498Szrj hstate.add_int (arg_count);
27938fd1498Szrj hstate.add_int (cfg_checksum);
28038fd1498Szrj hstate.add_int (gcode_hash);
28138fd1498Szrj
28238fd1498Szrj for (unsigned i = 0; i < bb_sorted.length (); i++)
28338fd1498Szrj hstate.merge_hash (get_bb_hash (bb_sorted[i]));
28438fd1498Szrj
28538fd1498Szrj for (unsigned i = 0; i < bb_sizes.length (); i++)
28638fd1498Szrj hstate.add_int (bb_sizes[i]);
28738fd1498Szrj
28838fd1498Szrj /* Add common features of declaration itself. */
28938fd1498Szrj if (DECL_FUNCTION_SPECIFIC_TARGET (decl))
29038fd1498Szrj hstate.add_hwi
29138fd1498Szrj (cl_target_option_hash
29238fd1498Szrj (TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (decl))));
29338fd1498Szrj if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))
29438fd1498Szrj hstate.add_hwi
29538fd1498Szrj (cl_optimization_hash
29638fd1498Szrj (TREE_OPTIMIZATION (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))));
29738fd1498Szrj hstate.add_flag (DECL_CXX_CONSTRUCTOR_P (decl));
29838fd1498Szrj hstate.add_flag (DECL_CXX_DESTRUCTOR_P (decl));
29938fd1498Szrj
30038fd1498Szrj set_hash (hstate.end ());
30138fd1498Szrj }
30238fd1498Szrj
30338fd1498Szrj return m_hash;
30438fd1498Szrj }
30538fd1498Szrj
30638fd1498Szrj /* Return ture if A1 and A2 represent equivalent function attribute lists.
30738fd1498Szrj Based on comp_type_attributes. */
30838fd1498Szrj
30938fd1498Szrj bool
compare_attributes(const_tree a1,const_tree a2)31038fd1498Szrj sem_item::compare_attributes (const_tree a1, const_tree a2)
31138fd1498Szrj {
31238fd1498Szrj const_tree a;
31338fd1498Szrj if (a1 == a2)
31438fd1498Szrj return true;
31538fd1498Szrj for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
31638fd1498Szrj {
31738fd1498Szrj const struct attribute_spec *as;
31838fd1498Szrj const_tree attr;
31938fd1498Szrj
32038fd1498Szrj as = lookup_attribute_spec (get_attribute_name (a));
32138fd1498Szrj /* TODO: We can introduce as->affects_decl_identity
32238fd1498Szrj and as->affects_decl_reference_identity if attribute mismatch
32338fd1498Szrj gets a common reason to give up on merging. It may not be worth
32438fd1498Szrj the effort.
32538fd1498Szrj For example returns_nonnull affects only references, while
32638fd1498Szrj optimize attribute can be ignored because it is already lowered
32738fd1498Szrj into flags representation and compared separately. */
32838fd1498Szrj if (!as)
32938fd1498Szrj continue;
33038fd1498Szrj
33138fd1498Szrj attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
33238fd1498Szrj if (!attr || !attribute_value_equal (a, attr))
33338fd1498Szrj break;
33438fd1498Szrj }
33538fd1498Szrj if (!a)
33638fd1498Szrj {
33738fd1498Szrj for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
33838fd1498Szrj {
33938fd1498Szrj const struct attribute_spec *as;
34038fd1498Szrj
34138fd1498Szrj as = lookup_attribute_spec (get_attribute_name (a));
34238fd1498Szrj if (!as)
34338fd1498Szrj continue;
34438fd1498Szrj
34538fd1498Szrj if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
34638fd1498Szrj break;
34738fd1498Szrj /* We don't need to compare trees again, as we did this
34838fd1498Szrj already in first loop. */
34938fd1498Szrj }
35038fd1498Szrj if (!a)
35138fd1498Szrj return true;
35238fd1498Szrj }
35338fd1498Szrj /* TODO: As in comp_type_attributes we may want to introduce target hook. */
35438fd1498Szrj return false;
35538fd1498Szrj }
35638fd1498Szrj
35738fd1498Szrj /* Compare properties of symbols N1 and N2 that does not affect semantics of
35838fd1498Szrj symbol itself but affects semantics of its references from USED_BY (which
35938fd1498Szrj may be NULL if it is unknown). If comparsion is false, symbols
36038fd1498Szrj can still be merged but any symbols referring them can't.
36138fd1498Szrj
36238fd1498Szrj If ADDRESS is true, do extra checking needed for IPA_REF_ADDR.
36338fd1498Szrj
36438fd1498Szrj TODO: We can also split attributes to those that determine codegen of
36538fd1498Szrj a function body/variable constructor itself and those that are used when
36638fd1498Szrj referring to it. */
36738fd1498Szrj
36838fd1498Szrj bool
compare_referenced_symbol_properties(symtab_node * used_by,symtab_node * n1,symtab_node * n2,bool address)36938fd1498Szrj sem_item::compare_referenced_symbol_properties (symtab_node *used_by,
37038fd1498Szrj symtab_node *n1,
37138fd1498Szrj symtab_node *n2,
37238fd1498Szrj bool address)
37338fd1498Szrj {
37438fd1498Szrj if (is_a <cgraph_node *> (n1))
37538fd1498Szrj {
37638fd1498Szrj /* Inline properties matters: we do now want to merge uses of inline
37738fd1498Szrj function to uses of normal function because inline hint would be lost.
37838fd1498Szrj We however can merge inline function to noinline because the alias
37938fd1498Szrj will keep its DECL_DECLARED_INLINE flag.
38038fd1498Szrj
38138fd1498Szrj Also ignore inline flag when optimizing for size or when function
38238fd1498Szrj is known to not be inlinable.
38338fd1498Szrj
38438fd1498Szrj TODO: the optimize_size checks can also be assumed to be true if
38538fd1498Szrj unit has no !optimize_size functions. */
38638fd1498Szrj
38738fd1498Szrj if ((!used_by || address || !is_a <cgraph_node *> (used_by)
38838fd1498Szrj || !opt_for_fn (used_by->decl, optimize_size))
38938fd1498Szrj && !opt_for_fn (n1->decl, optimize_size)
39038fd1498Szrj && n1->get_availability () > AVAIL_INTERPOSABLE
39138fd1498Szrj && (!DECL_UNINLINABLE (n1->decl) || !DECL_UNINLINABLE (n2->decl)))
39238fd1498Szrj {
39338fd1498Szrj if (DECL_DISREGARD_INLINE_LIMITS (n1->decl)
39438fd1498Szrj != DECL_DISREGARD_INLINE_LIMITS (n2->decl))
39538fd1498Szrj return return_false_with_msg
39638fd1498Szrj ("DECL_DISREGARD_INLINE_LIMITS are different");
39738fd1498Szrj
39838fd1498Szrj if (DECL_DECLARED_INLINE_P (n1->decl)
39938fd1498Szrj != DECL_DECLARED_INLINE_P (n2->decl))
40038fd1498Szrj return return_false_with_msg ("inline attributes are different");
40138fd1498Szrj }
40238fd1498Szrj
40338fd1498Szrj if (DECL_IS_OPERATOR_NEW (n1->decl)
40438fd1498Szrj != DECL_IS_OPERATOR_NEW (n2->decl))
40538fd1498Szrj return return_false_with_msg ("operator new flags are different");
40638fd1498Szrj }
40738fd1498Szrj
40838fd1498Szrj /* Merging two definitions with a reference to equivalent vtables, but
40938fd1498Szrj belonging to a different type may result in ipa-polymorphic-call analysis
41038fd1498Szrj giving a wrong answer about the dynamic type of instance. */
41138fd1498Szrj if (is_a <varpool_node *> (n1))
41238fd1498Szrj {
41338fd1498Szrj if ((DECL_VIRTUAL_P (n1->decl) || DECL_VIRTUAL_P (n2->decl))
41438fd1498Szrj && (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl)
41538fd1498Szrj || !types_must_be_same_for_odr (DECL_CONTEXT (n1->decl),
41638fd1498Szrj DECL_CONTEXT (n2->decl)))
41738fd1498Szrj && (!used_by || !is_a <cgraph_node *> (used_by) || address
41838fd1498Szrj || opt_for_fn (used_by->decl, flag_devirtualize)))
41938fd1498Szrj return return_false_with_msg
42038fd1498Szrj ("references to virtual tables can not be merged");
42138fd1498Szrj
42238fd1498Szrj if (address && DECL_ALIGN (n1->decl) != DECL_ALIGN (n2->decl))
42338fd1498Szrj return return_false_with_msg ("alignment mismatch");
42438fd1498Szrj
42538fd1498Szrj /* For functions we compare attributes in equals_wpa, because we do
42638fd1498Szrj not know what attributes may cause codegen differences, but for
42738fd1498Szrj variables just compare attributes for references - the codegen
42838fd1498Szrj for constructors is affected only by those attributes that we lower
42938fd1498Szrj to explicit representation (such as DECL_ALIGN or DECL_SECTION). */
43038fd1498Szrj if (!compare_attributes (DECL_ATTRIBUTES (n1->decl),
43138fd1498Szrj DECL_ATTRIBUTES (n2->decl)))
43238fd1498Szrj return return_false_with_msg ("different var decl attributes");
43338fd1498Szrj if (comp_type_attributes (TREE_TYPE (n1->decl),
43438fd1498Szrj TREE_TYPE (n2->decl)) != 1)
43538fd1498Szrj return return_false_with_msg ("different var type attributes");
43638fd1498Szrj }
43738fd1498Szrj
43838fd1498Szrj /* When matching virtual tables, be sure to also match information
43938fd1498Szrj relevant for polymorphic call analysis. */
44038fd1498Szrj if (used_by && is_a <varpool_node *> (used_by)
44138fd1498Szrj && DECL_VIRTUAL_P (used_by->decl))
44238fd1498Szrj {
44338fd1498Szrj if (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl))
44438fd1498Szrj return return_false_with_msg ("virtual flag mismatch");
44538fd1498Szrj if (DECL_VIRTUAL_P (n1->decl) && is_a <cgraph_node *> (n1)
44638fd1498Szrj && (DECL_FINAL_P (n1->decl) != DECL_FINAL_P (n2->decl)))
44738fd1498Szrj return return_false_with_msg ("final flag mismatch");
44838fd1498Szrj }
44938fd1498Szrj return true;
45038fd1498Szrj }
45138fd1498Szrj
45238fd1498Szrj /* Hash properties that are compared by compare_referenced_symbol_properties. */
45338fd1498Szrj
45438fd1498Szrj void
hash_referenced_symbol_properties(symtab_node * ref,inchash::hash & hstate,bool address)45538fd1498Szrj sem_item::hash_referenced_symbol_properties (symtab_node *ref,
45638fd1498Szrj inchash::hash &hstate,
45738fd1498Szrj bool address)
45838fd1498Szrj {
45938fd1498Szrj if (is_a <cgraph_node *> (ref))
46038fd1498Szrj {
46138fd1498Szrj if ((type != FUNC || address || !opt_for_fn (decl, optimize_size))
46238fd1498Szrj && !opt_for_fn (ref->decl, optimize_size)
46338fd1498Szrj && !DECL_UNINLINABLE (ref->decl))
46438fd1498Szrj {
46538fd1498Szrj hstate.add_flag (DECL_DISREGARD_INLINE_LIMITS (ref->decl));
46638fd1498Szrj hstate.add_flag (DECL_DECLARED_INLINE_P (ref->decl));
46738fd1498Szrj }
46838fd1498Szrj hstate.add_flag (DECL_IS_OPERATOR_NEW (ref->decl));
46938fd1498Szrj }
47038fd1498Szrj else if (is_a <varpool_node *> (ref))
47138fd1498Szrj {
47238fd1498Szrj hstate.add_flag (DECL_VIRTUAL_P (ref->decl));
47338fd1498Szrj if (address)
47438fd1498Szrj hstate.add_int (DECL_ALIGN (ref->decl));
47538fd1498Szrj }
47638fd1498Szrj }
47738fd1498Szrj
47838fd1498Szrj
47938fd1498Szrj /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs
48038fd1498Szrj point to a same function. Comparison can be skipped if IGNORED_NODES
48138fd1498Szrj contains these nodes. ADDRESS indicate if address is taken. */
48238fd1498Szrj
48338fd1498Szrj bool
compare_symbol_references(hash_map<symtab_node *,sem_item * > & ignored_nodes,symtab_node * n1,symtab_node * n2,bool address)48438fd1498Szrj sem_item::compare_symbol_references (
48538fd1498Szrj hash_map <symtab_node *, sem_item *> &ignored_nodes,
48638fd1498Szrj symtab_node *n1, symtab_node *n2, bool address)
48738fd1498Szrj {
48838fd1498Szrj enum availability avail1, avail2;
48938fd1498Szrj
49038fd1498Szrj if (n1 == n2)
49138fd1498Szrj return true;
49238fd1498Szrj
49338fd1498Szrj /* Never match variable and function. */
49438fd1498Szrj if (is_a <varpool_node *> (n1) != is_a <varpool_node *> (n2))
49538fd1498Szrj return false;
49638fd1498Szrj
49738fd1498Szrj if (!compare_referenced_symbol_properties (node, n1, n2, address))
49838fd1498Szrj return false;
49938fd1498Szrj if (address && n1->equal_address_to (n2) == 1)
50038fd1498Szrj return true;
50138fd1498Szrj if (!address && n1->semantically_equivalent_p (n2))
50238fd1498Szrj return true;
50338fd1498Szrj
50438fd1498Szrj n1 = n1->ultimate_alias_target (&avail1);
50538fd1498Szrj n2 = n2->ultimate_alias_target (&avail2);
50638fd1498Szrj
50738fd1498Szrj if (avail1 > AVAIL_INTERPOSABLE && ignored_nodes.get (n1)
50838fd1498Szrj && avail2 > AVAIL_INTERPOSABLE && ignored_nodes.get (n2))
50938fd1498Szrj return true;
51038fd1498Szrj
51138fd1498Szrj return return_false_with_msg ("different references");
51238fd1498Szrj }
51338fd1498Szrj
51438fd1498Szrj /* If cgraph edges E1 and E2 are indirect calls, verify that
51538fd1498Szrj ECF flags are the same. */
51638fd1498Szrj
compare_edge_flags(cgraph_edge * e1,cgraph_edge * e2)51738fd1498Szrj bool sem_function::compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2)
51838fd1498Szrj {
51938fd1498Szrj if (e1->indirect_info && e2->indirect_info)
52038fd1498Szrj {
52138fd1498Szrj int e1_flags = e1->indirect_info->ecf_flags;
52238fd1498Szrj int e2_flags = e2->indirect_info->ecf_flags;
52338fd1498Szrj
52438fd1498Szrj if (e1_flags != e2_flags)
52538fd1498Szrj return return_false_with_msg ("ICF flags are different");
52638fd1498Szrj }
52738fd1498Szrj else if (e1->indirect_info || e2->indirect_info)
52838fd1498Szrj return false;
52938fd1498Szrj
53038fd1498Szrj return true;
53138fd1498Szrj }
53238fd1498Szrj
53338fd1498Szrj /* Return true if parameter I may be used. */
53438fd1498Szrj
53538fd1498Szrj bool
param_used_p(unsigned int i)53638fd1498Szrj sem_function::param_used_p (unsigned int i)
53738fd1498Szrj {
53838fd1498Szrj if (ipa_node_params_sum == NULL)
53938fd1498Szrj return true;
54038fd1498Szrj
54138fd1498Szrj struct ipa_node_params *parms_info = IPA_NODE_REF (get_node ());
54238fd1498Szrj
54338fd1498Szrj if (vec_safe_length (parms_info->descriptors) <= i)
54438fd1498Szrj return true;
54538fd1498Szrj
54638fd1498Szrj return ipa_is_param_used (IPA_NODE_REF (get_node ()), i);
54738fd1498Szrj }
54838fd1498Szrj
54938fd1498Szrj /* Perform additional check needed to match types function parameters that are
55038fd1498Szrj used. Unlike for normal decls it matters if type is TYPE_RESTRICT and we
55138fd1498Szrj make an assumption that REFERENCE_TYPE parameters are always non-NULL. */
55238fd1498Szrj
55338fd1498Szrj bool
compatible_parm_types_p(tree parm1,tree parm2)55438fd1498Szrj sem_function::compatible_parm_types_p (tree parm1, tree parm2)
55538fd1498Szrj {
55638fd1498Szrj /* Be sure that parameters are TBAA compatible. */
55738fd1498Szrj if (!func_checker::compatible_types_p (parm1, parm2))
55838fd1498Szrj return return_false_with_msg ("parameter type is not compatible");
55938fd1498Szrj
56038fd1498Szrj if (POINTER_TYPE_P (parm1)
56138fd1498Szrj && (TYPE_RESTRICT (parm1) != TYPE_RESTRICT (parm2)))
56238fd1498Szrj return return_false_with_msg ("argument restrict flag mismatch");
56338fd1498Szrj
56438fd1498Szrj /* nonnull_arg_p implies non-zero range to REFERENCE types. */
56538fd1498Szrj if (POINTER_TYPE_P (parm1)
56638fd1498Szrj && TREE_CODE (parm1) != TREE_CODE (parm2)
56738fd1498Szrj && opt_for_fn (decl, flag_delete_null_pointer_checks))
56838fd1498Szrj return return_false_with_msg ("pointer wrt reference mismatch");
56938fd1498Szrj
57038fd1498Szrj return true;
57138fd1498Szrj }
57238fd1498Szrj
57338fd1498Szrj /* Fast equality function based on knowledge known in WPA. */
57438fd1498Szrj
57538fd1498Szrj bool
equals_wpa(sem_item * item,hash_map<symtab_node *,sem_item * > & ignored_nodes)57638fd1498Szrj sem_function::equals_wpa (sem_item *item,
57738fd1498Szrj hash_map <symtab_node *, sem_item *> &ignored_nodes)
57838fd1498Szrj {
57938fd1498Szrj gcc_assert (item->type == FUNC);
58038fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
58138fd1498Szrj cgraph_node *cnode2 = dyn_cast <cgraph_node *> (item->node);
58238fd1498Szrj
58338fd1498Szrj m_compared_func = static_cast<sem_function *> (item);
58438fd1498Szrj
58538fd1498Szrj if (cnode->thunk.thunk_p != cnode2->thunk.thunk_p)
58638fd1498Szrj return return_false_with_msg ("thunk_p mismatch");
58738fd1498Szrj
58838fd1498Szrj if (cnode->thunk.thunk_p)
58938fd1498Szrj {
59038fd1498Szrj if (cnode->thunk.fixed_offset != cnode2->thunk.fixed_offset)
59138fd1498Szrj return return_false_with_msg ("thunk fixed_offset mismatch");
59238fd1498Szrj if (cnode->thunk.virtual_value != cnode2->thunk.virtual_value)
59338fd1498Szrj return return_false_with_msg ("thunk virtual_value mismatch");
59438fd1498Szrj if (cnode->thunk.this_adjusting != cnode2->thunk.this_adjusting)
59538fd1498Szrj return return_false_with_msg ("thunk this_adjusting mismatch");
59638fd1498Szrj if (cnode->thunk.virtual_offset_p != cnode2->thunk.virtual_offset_p)
59738fd1498Szrj return return_false_with_msg ("thunk virtual_offset_p mismatch");
59838fd1498Szrj if (cnode->thunk.add_pointer_bounds_args
59938fd1498Szrj != cnode2->thunk.add_pointer_bounds_args)
60038fd1498Szrj return return_false_with_msg ("thunk add_pointer_bounds_args mismatch");
60138fd1498Szrj }
60238fd1498Szrj
60338fd1498Szrj /* Compare special function DECL attributes. */
60438fd1498Szrj if (DECL_FUNCTION_PERSONALITY (decl)
60538fd1498Szrj != DECL_FUNCTION_PERSONALITY (item->decl))
60638fd1498Szrj return return_false_with_msg ("function personalities are different");
60738fd1498Szrj
60838fd1498Szrj if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl)
60938fd1498Szrj != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl))
61038fd1498Szrj return return_false_with_msg ("intrument function entry exit "
61138fd1498Szrj "attributes are different");
61238fd1498Szrj
61338fd1498Szrj if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl))
61438fd1498Szrj return return_false_with_msg ("no stack limit attributes are different");
61538fd1498Szrj
61638fd1498Szrj if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl))
61738fd1498Szrj return return_false_with_msg ("DECL_CXX_CONSTRUCTOR mismatch");
61838fd1498Szrj
61938fd1498Szrj if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl))
62038fd1498Szrj return return_false_with_msg ("DECL_CXX_DESTRUCTOR mismatch");
62138fd1498Szrj
62238fd1498Szrj /* TODO: pure/const flags mostly matters only for references, except for
62338fd1498Szrj the fact that codegen takes LOOPING flag as a hint that loops are
62438fd1498Szrj finite. We may arrange the code to always pick leader that has least
62538fd1498Szrj specified flags and then this can go into comparing symbol properties. */
62638fd1498Szrj if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl))
62738fd1498Szrj return return_false_with_msg ("decl_or_type flags are different");
62838fd1498Szrj
62938fd1498Szrj /* Do not match polymorphic constructors of different types. They calls
63038fd1498Szrj type memory location for ipa-polymorphic-call and we do not want
63138fd1498Szrj it to get confused by wrong type. */
63238fd1498Szrj if (DECL_CXX_CONSTRUCTOR_P (decl)
63338fd1498Szrj && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
63438fd1498Szrj {
63538fd1498Szrj if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE)
63638fd1498Szrj return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch");
63738fd1498Szrj else if (!func_checker::compatible_polymorphic_types_p
63838fd1498Szrj (TYPE_METHOD_BASETYPE (TREE_TYPE (decl)),
63938fd1498Szrj TYPE_METHOD_BASETYPE (TREE_TYPE (item->decl)), false))
64038fd1498Szrj return return_false_with_msg ("ctor polymorphic type mismatch");
64138fd1498Szrj }
64238fd1498Szrj
64338fd1498Szrj /* Checking function TARGET and OPTIMIZATION flags. */
64438fd1498Szrj cl_target_option *tar1 = target_opts_for_fn (decl);
64538fd1498Szrj cl_target_option *tar2 = target_opts_for_fn (item->decl);
64638fd1498Szrj
64738fd1498Szrj if (tar1 != tar2 && !cl_target_option_eq (tar1, tar2))
64838fd1498Szrj {
64938fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
65038fd1498Szrj {
65138fd1498Szrj fprintf (dump_file, "target flags difference");
65238fd1498Szrj cl_target_option_print_diff (dump_file, 2, tar1, tar2);
65338fd1498Szrj }
65438fd1498Szrj
65538fd1498Szrj return return_false_with_msg ("Target flags are different");
65638fd1498Szrj }
65738fd1498Szrj
65838fd1498Szrj cl_optimization *opt1 = opts_for_fn (decl);
65938fd1498Szrj cl_optimization *opt2 = opts_for_fn (item->decl);
66038fd1498Szrj
66138fd1498Szrj if (opt1 != opt2 && memcmp (opt1, opt2, sizeof(cl_optimization)))
66238fd1498Szrj {
66338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
66438fd1498Szrj {
66538fd1498Szrj fprintf (dump_file, "optimization flags difference");
66638fd1498Szrj cl_optimization_print_diff (dump_file, 2, opt1, opt2);
66738fd1498Szrj }
66838fd1498Szrj
66938fd1498Szrj return return_false_with_msg ("optimization flags are different");
67038fd1498Szrj }
67138fd1498Szrj
67238fd1498Szrj /* Result type checking. */
67338fd1498Szrj if (!func_checker::compatible_types_p
67438fd1498Szrj (TREE_TYPE (TREE_TYPE (decl)),
67538fd1498Szrj TREE_TYPE (TREE_TYPE (m_compared_func->decl))))
67638fd1498Szrj return return_false_with_msg ("result types are different");
67738fd1498Szrj
67838fd1498Szrj /* Checking types of arguments. */
67938fd1498Szrj tree list1 = TYPE_ARG_TYPES (TREE_TYPE (decl)),
68038fd1498Szrj list2 = TYPE_ARG_TYPES (TREE_TYPE (m_compared_func->decl));
68138fd1498Szrj for (unsigned i = 0; list1 && list2;
68238fd1498Szrj list1 = TREE_CHAIN (list1), list2 = TREE_CHAIN (list2), i++)
68338fd1498Szrj {
68438fd1498Szrj tree parm1 = TREE_VALUE (list1);
68538fd1498Szrj tree parm2 = TREE_VALUE (list2);
68638fd1498Szrj
68738fd1498Szrj /* This guard is here for function pointer with attributes (pr59927.c). */
68838fd1498Szrj if (!parm1 || !parm2)
68938fd1498Szrj return return_false_with_msg ("NULL argument type");
69038fd1498Szrj
69138fd1498Szrj /* Verify that types are compatible to ensure that both functions
69238fd1498Szrj have same calling conventions. */
69338fd1498Szrj if (!types_compatible_p (parm1, parm2))
69438fd1498Szrj return return_false_with_msg ("parameter types are not compatible");
69538fd1498Szrj
69638fd1498Szrj if (!param_used_p (i))
69738fd1498Szrj continue;
69838fd1498Szrj
69938fd1498Szrj /* Perform additional checks for used parameters. */
70038fd1498Szrj if (!compatible_parm_types_p (parm1, parm2))
70138fd1498Szrj return false;
70238fd1498Szrj }
70338fd1498Szrj
70438fd1498Szrj if (list1 || list2)
70538fd1498Szrj return return_false_with_msg ("Mismatched number of parameters");
70638fd1498Szrj
70738fd1498Szrj if (node->num_references () != item->node->num_references ())
70838fd1498Szrj return return_false_with_msg ("different number of references");
70938fd1498Szrj
71038fd1498Szrj /* Checking function attributes.
71138fd1498Szrj This is quadratic in number of attributes */
71238fd1498Szrj if (comp_type_attributes (TREE_TYPE (decl),
71338fd1498Szrj TREE_TYPE (item->decl)) != 1)
71438fd1498Szrj return return_false_with_msg ("different type attributes");
71538fd1498Szrj if (!compare_attributes (DECL_ATTRIBUTES (decl),
71638fd1498Szrj DECL_ATTRIBUTES (item->decl)))
71738fd1498Szrj return return_false_with_msg ("different decl attributes");
71838fd1498Szrj
71938fd1498Szrj /* The type of THIS pointer type memory location for
72038fd1498Szrj ipa-polymorphic-call-analysis. */
72138fd1498Szrj if (opt_for_fn (decl, flag_devirtualize)
72238fd1498Szrj && (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
72338fd1498Szrj || TREE_CODE (TREE_TYPE (item->decl)) == METHOD_TYPE)
72438fd1498Szrj && param_used_p (0)
72538fd1498Szrj && compare_polymorphic_p ())
72638fd1498Szrj {
72738fd1498Szrj if (TREE_CODE (TREE_TYPE (decl)) != TREE_CODE (TREE_TYPE (item->decl)))
72838fd1498Szrj return return_false_with_msg ("METHOD_TYPE and FUNCTION_TYPE mismatch");
72938fd1498Szrj if (!func_checker::compatible_polymorphic_types_p
73038fd1498Szrj (TYPE_METHOD_BASETYPE (TREE_TYPE (decl)),
73138fd1498Szrj TYPE_METHOD_BASETYPE (TREE_TYPE (item->decl)), false))
73238fd1498Szrj return return_false_with_msg ("THIS pointer ODR type mismatch");
73338fd1498Szrj }
73438fd1498Szrj
73538fd1498Szrj ipa_ref *ref = NULL, *ref2 = NULL;
73638fd1498Szrj for (unsigned i = 0; node->iterate_reference (i, ref); i++)
73738fd1498Szrj {
73838fd1498Szrj item->node->iterate_reference (i, ref2);
73938fd1498Szrj
74038fd1498Szrj if (ref->use != ref2->use)
74138fd1498Szrj return return_false_with_msg ("reference use mismatch");
74238fd1498Szrj
74338fd1498Szrj if (!compare_symbol_references (ignored_nodes, ref->referred,
74438fd1498Szrj ref2->referred,
74538fd1498Szrj ref->address_matters_p ()))
74638fd1498Szrj return false;
74738fd1498Szrj }
74838fd1498Szrj
74938fd1498Szrj cgraph_edge *e1 = dyn_cast <cgraph_node *> (node)->callees;
75038fd1498Szrj cgraph_edge *e2 = dyn_cast <cgraph_node *> (item->node)->callees;
75138fd1498Szrj
75238fd1498Szrj while (e1 && e2)
75338fd1498Szrj {
75438fd1498Szrj if (!compare_symbol_references (ignored_nodes, e1->callee,
75538fd1498Szrj e2->callee, false))
75638fd1498Szrj return false;
75738fd1498Szrj if (!compare_edge_flags (e1, e2))
75838fd1498Szrj return false;
75938fd1498Szrj
76038fd1498Szrj e1 = e1->next_callee;
76138fd1498Szrj e2 = e2->next_callee;
76238fd1498Szrj }
76338fd1498Szrj
76438fd1498Szrj if (e1 || e2)
76538fd1498Szrj return return_false_with_msg ("different number of calls");
76638fd1498Szrj
76738fd1498Szrj e1 = dyn_cast <cgraph_node *> (node)->indirect_calls;
76838fd1498Szrj e2 = dyn_cast <cgraph_node *> (item->node)->indirect_calls;
76938fd1498Szrj
77038fd1498Szrj while (e1 && e2)
77138fd1498Szrj {
77238fd1498Szrj if (!compare_edge_flags (e1, e2))
77338fd1498Szrj return false;
77438fd1498Szrj
77538fd1498Szrj e1 = e1->next_callee;
77638fd1498Szrj e2 = e2->next_callee;
77738fd1498Szrj }
77838fd1498Szrj
77938fd1498Szrj if (e1 || e2)
78038fd1498Szrj return return_false_with_msg ("different number of indirect calls");
78138fd1498Szrj
78238fd1498Szrj return true;
78338fd1498Szrj }
78438fd1498Szrj
78538fd1498Szrj /* Update hash by address sensitive references. We iterate over all
78638fd1498Szrj sensitive references (address_matters_p) and we hash ultime alias
78738fd1498Szrj target of these nodes, which can improve a semantic item hash.
78838fd1498Szrj
78938fd1498Szrj Also hash in referenced symbols properties. This can be done at any time
79038fd1498Szrj (as the properties should not change), but it is convenient to do it here
79138fd1498Szrj while we walk the references anyway. */
79238fd1498Szrj
79338fd1498Szrj void
update_hash_by_addr_refs(hash_map<symtab_node *,sem_item * > & m_symtab_node_map)79438fd1498Szrj sem_item::update_hash_by_addr_refs (hash_map <symtab_node *,
79538fd1498Szrj sem_item *> &m_symtab_node_map)
79638fd1498Szrj {
79738fd1498Szrj ipa_ref* ref;
79838fd1498Szrj inchash::hash hstate (get_hash ());
79938fd1498Szrj
80038fd1498Szrj for (unsigned i = 0; node->iterate_reference (i, ref); i++)
80138fd1498Szrj {
80238fd1498Szrj hstate.add_int (ref->use);
80338fd1498Szrj hash_referenced_symbol_properties (ref->referred, hstate,
80438fd1498Szrj ref->use == IPA_REF_ADDR);
80538fd1498Szrj if (ref->address_matters_p () || !m_symtab_node_map.get (ref->referred))
80638fd1498Szrj hstate.add_int (ref->referred->ultimate_alias_target ()->order);
80738fd1498Szrj }
80838fd1498Szrj
80938fd1498Szrj if (is_a <cgraph_node *> (node))
81038fd1498Szrj {
81138fd1498Szrj for (cgraph_edge *e = dyn_cast <cgraph_node *> (node)->callers; e;
81238fd1498Szrj e = e->next_caller)
81338fd1498Szrj {
81438fd1498Szrj sem_item **result = m_symtab_node_map.get (e->callee);
81538fd1498Szrj hash_referenced_symbol_properties (e->callee, hstate, false);
81638fd1498Szrj if (!result)
81738fd1498Szrj hstate.add_int (e->callee->ultimate_alias_target ()->order);
81838fd1498Szrj }
81938fd1498Szrj }
82038fd1498Szrj
82138fd1498Szrj set_hash (hstate.end ());
82238fd1498Szrj }
82338fd1498Szrj
82438fd1498Szrj /* Update hash by computed local hash values taken from different
82538fd1498Szrj semantic items.
82638fd1498Szrj TODO: stronger SCC based hashing would be desirable here. */
82738fd1498Szrj
82838fd1498Szrj void
update_hash_by_local_refs(hash_map<symtab_node *,sem_item * > & m_symtab_node_map)82938fd1498Szrj sem_item::update_hash_by_local_refs (hash_map <symtab_node *,
83038fd1498Szrj sem_item *> &m_symtab_node_map)
83138fd1498Szrj {
83238fd1498Szrj ipa_ref* ref;
83338fd1498Szrj inchash::hash state (get_hash ());
83438fd1498Szrj
83538fd1498Szrj for (unsigned j = 0; node->iterate_reference (j, ref); j++)
83638fd1498Szrj {
83738fd1498Szrj sem_item **result = m_symtab_node_map.get (ref->referring);
83838fd1498Szrj if (result)
83938fd1498Szrj state.merge_hash ((*result)->get_hash ());
84038fd1498Szrj }
84138fd1498Szrj
84238fd1498Szrj if (type == FUNC)
84338fd1498Szrj {
84438fd1498Szrj for (cgraph_edge *e = dyn_cast <cgraph_node *> (node)->callees; e;
84538fd1498Szrj e = e->next_callee)
84638fd1498Szrj {
84738fd1498Szrj sem_item **result = m_symtab_node_map.get (e->caller);
84838fd1498Szrj if (result)
84938fd1498Szrj state.merge_hash ((*result)->get_hash ());
85038fd1498Szrj }
85138fd1498Szrj }
85238fd1498Szrj
85338fd1498Szrj global_hash = state.end ();
85438fd1498Szrj }
85538fd1498Szrj
85638fd1498Szrj /* Returns true if the item equals to ITEM given as argument. */
85738fd1498Szrj
85838fd1498Szrj bool
equals(sem_item * item,hash_map<symtab_node *,sem_item * > &)85938fd1498Szrj sem_function::equals (sem_item *item,
86038fd1498Szrj hash_map <symtab_node *, sem_item *> &)
86138fd1498Szrj {
86238fd1498Szrj gcc_assert (item->type == FUNC);
86338fd1498Szrj bool eq = equals_private (item);
86438fd1498Szrj
86538fd1498Szrj if (m_checker != NULL)
86638fd1498Szrj {
86738fd1498Szrj delete m_checker;
86838fd1498Szrj m_checker = NULL;
86938fd1498Szrj }
87038fd1498Szrj
87138fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
87238fd1498Szrj fprintf (dump_file,
87338fd1498Szrj "Equals called for: %s:%s with result: %s\n\n",
87438fd1498Szrj node->dump_name (),
87538fd1498Szrj item->node->dump_name (),
87638fd1498Szrj eq ? "true" : "false");
87738fd1498Szrj
87838fd1498Szrj return eq;
87938fd1498Szrj }
88038fd1498Szrj
88138fd1498Szrj /* Processes function equality comparison. */
88238fd1498Szrj
88338fd1498Szrj bool
equals_private(sem_item * item)88438fd1498Szrj sem_function::equals_private (sem_item *item)
88538fd1498Szrj {
88638fd1498Szrj if (item->type != FUNC)
88738fd1498Szrj return false;
88838fd1498Szrj
88938fd1498Szrj basic_block bb1, bb2;
89038fd1498Szrj edge e1, e2;
89138fd1498Szrj edge_iterator ei1, ei2;
89238fd1498Szrj bool result = true;
89338fd1498Szrj tree arg1, arg2;
89438fd1498Szrj
89538fd1498Szrj m_compared_func = static_cast<sem_function *> (item);
89638fd1498Szrj
89738fd1498Szrj gcc_assert (decl != item->decl);
89838fd1498Szrj
89938fd1498Szrj if (bb_sorted.length () != m_compared_func->bb_sorted.length ()
90038fd1498Szrj || edge_count != m_compared_func->edge_count
90138fd1498Szrj || cfg_checksum != m_compared_func->cfg_checksum)
90238fd1498Szrj return return_false ();
90338fd1498Szrj
90438fd1498Szrj m_checker = new func_checker (decl, m_compared_func->decl,
90538fd1498Szrj compare_polymorphic_p (),
90638fd1498Szrj false,
90738fd1498Szrj &refs_set,
90838fd1498Szrj &m_compared_func->refs_set);
90938fd1498Szrj arg1 = DECL_ARGUMENTS (decl);
91038fd1498Szrj arg2 = DECL_ARGUMENTS (m_compared_func->decl);
91138fd1498Szrj for (unsigned i = 0;
91238fd1498Szrj arg1 && arg2; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2), i++)
91338fd1498Szrj {
91438fd1498Szrj if (!types_compatible_p (TREE_TYPE (arg1), TREE_TYPE (arg2)))
91538fd1498Szrj return return_false_with_msg ("argument types are not compatible");
91638fd1498Szrj if (!param_used_p (i))
91738fd1498Szrj continue;
91838fd1498Szrj /* Perform additional checks for used parameters. */
91938fd1498Szrj if (!compatible_parm_types_p (TREE_TYPE (arg1), TREE_TYPE (arg2)))
92038fd1498Szrj return false;
92138fd1498Szrj if (!m_checker->compare_decl (arg1, arg2))
92238fd1498Szrj return return_false ();
92338fd1498Szrj }
92438fd1498Szrj if (arg1 || arg2)
92538fd1498Szrj return return_false_with_msg ("Mismatched number of arguments");
92638fd1498Szrj
92738fd1498Szrj if (!dyn_cast <cgraph_node *> (node)->has_gimple_body_p ())
92838fd1498Szrj return true;
92938fd1498Szrj
93038fd1498Szrj /* Fill-up label dictionary. */
93138fd1498Szrj for (unsigned i = 0; i < bb_sorted.length (); ++i)
93238fd1498Szrj {
93338fd1498Szrj m_checker->parse_labels (bb_sorted[i]);
93438fd1498Szrj m_checker->parse_labels (m_compared_func->bb_sorted[i]);
93538fd1498Szrj }
93638fd1498Szrj
93738fd1498Szrj /* Checking all basic blocks. */
93838fd1498Szrj for (unsigned i = 0; i < bb_sorted.length (); ++i)
93938fd1498Szrj if(!m_checker->compare_bb (bb_sorted[i], m_compared_func->bb_sorted[i]))
94038fd1498Szrj return return_false();
94138fd1498Szrj
94238fd1498Szrj dump_message ("All BBs are equal\n");
94338fd1498Szrj
94438fd1498Szrj auto_vec <int> bb_dict;
94538fd1498Szrj
94638fd1498Szrj /* Basic block edges check. */
94738fd1498Szrj for (unsigned i = 0; i < bb_sorted.length (); ++i)
94838fd1498Szrj {
94938fd1498Szrj bb1 = bb_sorted[i]->bb;
95038fd1498Szrj bb2 = m_compared_func->bb_sorted[i]->bb;
95138fd1498Szrj
95238fd1498Szrj ei2 = ei_start (bb2->preds);
95338fd1498Szrj
95438fd1498Szrj for (ei1 = ei_start (bb1->preds); ei_cond (ei1, &e1); ei_next (&ei1))
95538fd1498Szrj {
95638fd1498Szrj ei_cond (ei2, &e2);
95738fd1498Szrj
95838fd1498Szrj if (e1->flags != e2->flags)
95938fd1498Szrj return return_false_with_msg ("flags comparison returns false");
96038fd1498Szrj
96138fd1498Szrj if (!bb_dict_test (&bb_dict, e1->src->index, e2->src->index))
96238fd1498Szrj return return_false_with_msg ("edge comparison returns false");
96338fd1498Szrj
96438fd1498Szrj if (!bb_dict_test (&bb_dict, e1->dest->index, e2->dest->index))
96538fd1498Szrj return return_false_with_msg ("BB comparison returns false");
96638fd1498Szrj
96738fd1498Szrj if (!m_checker->compare_edge (e1, e2))
96838fd1498Szrj return return_false_with_msg ("edge comparison returns false");
96938fd1498Szrj
97038fd1498Szrj ei_next (&ei2);
97138fd1498Szrj }
97238fd1498Szrj }
97338fd1498Szrj
97438fd1498Szrj /* Basic block PHI nodes comparison. */
97538fd1498Szrj for (unsigned i = 0; i < bb_sorted.length (); i++)
97638fd1498Szrj if (!compare_phi_node (bb_sorted[i]->bb, m_compared_func->bb_sorted[i]->bb))
97738fd1498Szrj return return_false_with_msg ("PHI node comparison returns false");
97838fd1498Szrj
97938fd1498Szrj return result;
98038fd1498Szrj }
98138fd1498Szrj
98238fd1498Szrj /* Set LOCAL_P of NODE to true if DATA is non-NULL.
98338fd1498Szrj Helper for call_for_symbol_thunks_and_aliases. */
98438fd1498Szrj
98538fd1498Szrj static bool
set_local(cgraph_node * node,void * data)98638fd1498Szrj set_local (cgraph_node *node, void *data)
98738fd1498Szrj {
98838fd1498Szrj node->local.local = data != NULL;
98938fd1498Szrj return false;
99038fd1498Szrj }
99138fd1498Szrj
99238fd1498Szrj /* TREE_ADDRESSABLE of NODE to true.
99338fd1498Szrj Helper for call_for_symbol_thunks_and_aliases. */
99438fd1498Szrj
99538fd1498Szrj static bool
set_addressable(varpool_node * node,void *)99638fd1498Szrj set_addressable (varpool_node *node, void *)
99738fd1498Szrj {
99838fd1498Szrj TREE_ADDRESSABLE (node->decl) = 1;
99938fd1498Szrj return false;
100038fd1498Szrj }
100138fd1498Szrj
100238fd1498Szrj /* Clear DECL_RTL of NODE.
100338fd1498Szrj Helper for call_for_symbol_thunks_and_aliases. */
100438fd1498Szrj
100538fd1498Szrj static bool
clear_decl_rtl(symtab_node * node,void *)100638fd1498Szrj clear_decl_rtl (symtab_node *node, void *)
100738fd1498Szrj {
100838fd1498Szrj SET_DECL_RTL (node->decl, NULL);
100938fd1498Szrj return false;
101038fd1498Szrj }
101138fd1498Szrj
101238fd1498Szrj /* Redirect all callers of N and its aliases to TO. Remove aliases if
101338fd1498Szrj possible. Return number of redirections made. */
101438fd1498Szrj
101538fd1498Szrj static int
redirect_all_callers(cgraph_node * n,cgraph_node * to)101638fd1498Szrj redirect_all_callers (cgraph_node *n, cgraph_node *to)
101738fd1498Szrj {
101838fd1498Szrj int nredirected = 0;
101938fd1498Szrj ipa_ref *ref;
102038fd1498Szrj cgraph_edge *e = n->callers;
102138fd1498Szrj
102238fd1498Szrj while (e)
102338fd1498Szrj {
102438fd1498Szrj /* Redirecting thunks to interposable symbols or symbols in other sections
102538fd1498Szrj may not be supported by target output code. Play safe for now and
102638fd1498Szrj punt on redirection. */
102738fd1498Szrj if (!e->caller->thunk.thunk_p)
102838fd1498Szrj {
102938fd1498Szrj struct cgraph_edge *nexte = e->next_caller;
103038fd1498Szrj e->redirect_callee (to);
103138fd1498Szrj e = nexte;
103238fd1498Szrj nredirected++;
103338fd1498Szrj }
103438fd1498Szrj else
103538fd1498Szrj e = e->next_callee;
103638fd1498Szrj }
103738fd1498Szrj for (unsigned i = 0; n->iterate_direct_aliases (i, ref);)
103838fd1498Szrj {
103938fd1498Szrj bool removed = false;
104038fd1498Szrj cgraph_node *n_alias = dyn_cast <cgraph_node *> (ref->referring);
104138fd1498Szrj
104238fd1498Szrj if ((DECL_COMDAT_GROUP (n->decl)
104338fd1498Szrj && (DECL_COMDAT_GROUP (n->decl)
104438fd1498Szrj == DECL_COMDAT_GROUP (n_alias->decl)))
104538fd1498Szrj || (n_alias->get_availability () > AVAIL_INTERPOSABLE
104638fd1498Szrj && n->get_availability () > AVAIL_INTERPOSABLE))
104738fd1498Szrj {
104838fd1498Szrj nredirected += redirect_all_callers (n_alias, to);
104938fd1498Szrj if (n_alias->can_remove_if_no_direct_calls_p ()
105038fd1498Szrj && !n_alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p,
105138fd1498Szrj NULL, true)
105238fd1498Szrj && !n_alias->has_aliases_p ())
105338fd1498Szrj n_alias->remove ();
105438fd1498Szrj }
105538fd1498Szrj if (!removed)
105638fd1498Szrj i++;
105738fd1498Szrj }
105838fd1498Szrj return nredirected;
105938fd1498Szrj }
106038fd1498Szrj
106138fd1498Szrj /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
106238fd1498Szrj be applied. */
106338fd1498Szrj
106438fd1498Szrj bool
merge(sem_item * alias_item)106538fd1498Szrj sem_function::merge (sem_item *alias_item)
106638fd1498Szrj {
106738fd1498Szrj gcc_assert (alias_item->type == FUNC);
106838fd1498Szrj
106938fd1498Szrj sem_function *alias_func = static_cast<sem_function *> (alias_item);
107038fd1498Szrj
107138fd1498Szrj cgraph_node *original = get_node ();
107238fd1498Szrj cgraph_node *local_original = NULL;
107338fd1498Szrj cgraph_node *alias = alias_func->get_node ();
107438fd1498Szrj
107538fd1498Szrj bool create_wrapper = false;
107638fd1498Szrj bool create_alias = false;
107738fd1498Szrj bool redirect_callers = false;
107838fd1498Szrj bool remove = false;
107938fd1498Szrj
108038fd1498Szrj bool original_discardable = false;
108138fd1498Szrj bool original_discarded = false;
108238fd1498Szrj
108338fd1498Szrj bool original_address_matters = original->address_matters_p ();
108438fd1498Szrj bool alias_address_matters = alias->address_matters_p ();
108538fd1498Szrj
108638fd1498Szrj if (DECL_EXTERNAL (alias->decl))
108738fd1498Szrj {
108838fd1498Szrj if (dump_file)
108938fd1498Szrj fprintf (dump_file, "Not unifying; alias is external.\n\n");
109038fd1498Szrj return false;
109138fd1498Szrj }
109238fd1498Szrj
109338fd1498Szrj if (DECL_NO_INLINE_WARNING_P (original->decl)
109438fd1498Szrj != DECL_NO_INLINE_WARNING_P (alias->decl))
109538fd1498Szrj {
109638fd1498Szrj if (dump_file)
109738fd1498Szrj fprintf (dump_file,
109838fd1498Szrj "Not unifying; "
109938fd1498Szrj "DECL_NO_INLINE_WARNING mismatch.\n\n");
110038fd1498Szrj return false;
110138fd1498Szrj }
110238fd1498Szrj
110338fd1498Szrj /* Do not attempt to mix functions from different user sections;
110438fd1498Szrj we do not know what user intends with those. */
110538fd1498Szrj if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
110638fd1498Szrj || (DECL_SECTION_NAME (alias->decl) && !alias->implicit_section))
110738fd1498Szrj && DECL_SECTION_NAME (original->decl) != DECL_SECTION_NAME (alias->decl))
110838fd1498Szrj {
110938fd1498Szrj if (dump_file)
111038fd1498Szrj fprintf (dump_file,
111138fd1498Szrj "Not unifying; "
111238fd1498Szrj "original and alias are in different sections.\n\n");
111338fd1498Szrj return false;
111438fd1498Szrj }
111538fd1498Szrj
111638fd1498Szrj if (!original->in_same_comdat_group_p (alias)
111738fd1498Szrj || original->comdat_local_p ())
111838fd1498Szrj {
111938fd1498Szrj if (dump_file)
112038fd1498Szrj fprintf (dump_file,
112138fd1498Szrj "Not unifying; alias nor wrapper cannot be created; "
112238fd1498Szrj "across comdat group boundary\n\n");
112338fd1498Szrj
112438fd1498Szrj return false;
112538fd1498Szrj }
112638fd1498Szrj
112738fd1498Szrj /* See if original is in a section that can be discarded if the main
112838fd1498Szrj symbol is not used. */
112938fd1498Szrj
113038fd1498Szrj if (original->can_be_discarded_p ())
113138fd1498Szrj original_discardable = true;
113238fd1498Szrj /* Also consider case where we have resolution info and we know that
113338fd1498Szrj original's definition is not going to be used. In this case we can not
113438fd1498Szrj create alias to original. */
113538fd1498Szrj if (node->resolution != LDPR_UNKNOWN
113638fd1498Szrj && !decl_binds_to_current_def_p (node->decl))
113738fd1498Szrj original_discardable = original_discarded = true;
113838fd1498Szrj
113938fd1498Szrj /* Creating a symtab alias is the optimal way to merge.
114038fd1498Szrj It however can not be used in the following cases:
114138fd1498Szrj
114238fd1498Szrj 1) if ORIGINAL and ALIAS may be possibly compared for address equality.
114338fd1498Szrj 2) if ORIGINAL is in a section that may be discarded by linker or if
114438fd1498Szrj it is an external functions where we can not create an alias
114538fd1498Szrj (ORIGINAL_DISCARDABLE)
114638fd1498Szrj 3) if target do not support symbol aliases.
114738fd1498Szrj 4) original and alias lie in different comdat groups.
114838fd1498Szrj
114938fd1498Szrj If we can not produce alias, we will turn ALIAS into WRAPPER of ORIGINAL
115038fd1498Szrj and/or redirect all callers from ALIAS to ORIGINAL. */
115138fd1498Szrj if ((original_address_matters && alias_address_matters)
115238fd1498Szrj || (original_discardable
115338fd1498Szrj && (!DECL_COMDAT_GROUP (alias->decl)
115438fd1498Szrj || (DECL_COMDAT_GROUP (alias->decl)
115538fd1498Szrj != DECL_COMDAT_GROUP (original->decl))))
115638fd1498Szrj || original_discarded
115738fd1498Szrj || !sem_item::target_supports_symbol_aliases_p ()
115838fd1498Szrj || DECL_COMDAT_GROUP (alias->decl) != DECL_COMDAT_GROUP (original->decl))
115938fd1498Szrj {
116038fd1498Szrj /* First see if we can produce wrapper. */
116138fd1498Szrj
116238fd1498Szrj /* Symbol properties that matter for references must be preserved.
116338fd1498Szrj TODO: We can produce wrapper, but we need to produce alias of ORIGINAL
116438fd1498Szrj with proper properties. */
116538fd1498Szrj if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias,
116638fd1498Szrj alias->address_taken))
116738fd1498Szrj {
116838fd1498Szrj if (dump_file)
116938fd1498Szrj fprintf (dump_file,
117038fd1498Szrj "Wrapper cannot be created because referenced symbol "
117138fd1498Szrj "properties mismatch\n");
117238fd1498Szrj }
117338fd1498Szrj /* Do not turn function in one comdat group into wrapper to another
117438fd1498Szrj comdat group. Other compiler producing the body of the
117538fd1498Szrj another comdat group may make opossite decision and with unfortunate
117638fd1498Szrj linker choices this may close a loop. */
117738fd1498Szrj else if (DECL_COMDAT_GROUP (original->decl)
117838fd1498Szrj && DECL_COMDAT_GROUP (alias->decl)
117938fd1498Szrj && (DECL_COMDAT_GROUP (alias->decl)
118038fd1498Szrj != DECL_COMDAT_GROUP (original->decl)))
118138fd1498Szrj {
118238fd1498Szrj if (dump_file)
118338fd1498Szrj fprintf (dump_file,
118438fd1498Szrj "Wrapper cannot be created because of COMDAT\n");
118538fd1498Szrj }
118638fd1498Szrj else if (DECL_STATIC_CHAIN (alias->decl)
118738fd1498Szrj || DECL_STATIC_CHAIN (original->decl))
118838fd1498Szrj {
118938fd1498Szrj if (dump_file)
119038fd1498Szrj fprintf (dump_file,
119138fd1498Szrj "Cannot create wrapper of nested function.\n");
119238fd1498Szrj }
119338fd1498Szrj /* TODO: We can also deal with variadic functions never calling
119438fd1498Szrj VA_START. */
119538fd1498Szrj else if (stdarg_p (TREE_TYPE (alias->decl)))
119638fd1498Szrj {
119738fd1498Szrj if (dump_file)
119838fd1498Szrj fprintf (dump_file,
119938fd1498Szrj "can not create wrapper of stdarg function.\n");
120038fd1498Szrj }
120138fd1498Szrj else if (ipa_fn_summaries
120238fd1498Szrj && ipa_fn_summaries->get (alias)->self_size <= 2)
120338fd1498Szrj {
120438fd1498Szrj if (dump_file)
120538fd1498Szrj fprintf (dump_file, "Wrapper creation is not "
120638fd1498Szrj "profitable (function is too small).\n");
120738fd1498Szrj }
120838fd1498Szrj /* If user paid attention to mark function noinline, assume it is
120938fd1498Szrj somewhat special and do not try to turn it into a wrapper that can
121038fd1498Szrj not be undone by inliner. */
121138fd1498Szrj else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (alias->decl)))
121238fd1498Szrj {
121338fd1498Szrj if (dump_file)
121438fd1498Szrj fprintf (dump_file, "Wrappers are not created for noinline.\n");
121538fd1498Szrj }
121638fd1498Szrj else
121738fd1498Szrj create_wrapper = true;
121838fd1498Szrj
121938fd1498Szrj /* We can redirect local calls in the case both alias and orignal
122038fd1498Szrj are not interposable. */
122138fd1498Szrj redirect_callers
122238fd1498Szrj = alias->get_availability () > AVAIL_INTERPOSABLE
122338fd1498Szrj && original->get_availability () > AVAIL_INTERPOSABLE
122438fd1498Szrj && !alias->instrumented_version;
122538fd1498Szrj /* TODO: We can redirect, but we need to produce alias of ORIGINAL
122638fd1498Szrj with proper properties. */
122738fd1498Szrj if (!sem_item::compare_referenced_symbol_properties (NULL, original, alias,
122838fd1498Szrj alias->address_taken))
122938fd1498Szrj redirect_callers = false;
123038fd1498Szrj
123138fd1498Szrj if (!redirect_callers && !create_wrapper)
123238fd1498Szrj {
123338fd1498Szrj if (dump_file)
123438fd1498Szrj fprintf (dump_file, "Not unifying; can not redirect callers nor "
123538fd1498Szrj "produce wrapper\n\n");
123638fd1498Szrj return false;
123738fd1498Szrj }
123838fd1498Szrj
123938fd1498Szrj /* Work out the symbol the wrapper should call.
124038fd1498Szrj If ORIGINAL is interposable, we need to call a local alias.
124138fd1498Szrj Also produce local alias (if possible) as an optimization.
124238fd1498Szrj
124338fd1498Szrj Local aliases can not be created inside comdat groups because that
124438fd1498Szrj prevents inlining. */
124538fd1498Szrj if (!original_discardable && !original->get_comdat_group ())
124638fd1498Szrj {
124738fd1498Szrj local_original
124838fd1498Szrj = dyn_cast <cgraph_node *> (original->noninterposable_alias ());
124938fd1498Szrj if (!local_original
125038fd1498Szrj && original->get_availability () > AVAIL_INTERPOSABLE)
125138fd1498Szrj local_original = original;
125238fd1498Szrj }
125338fd1498Szrj /* If we can not use local alias, fallback to the original
125438fd1498Szrj when possible. */
125538fd1498Szrj else if (original->get_availability () > AVAIL_INTERPOSABLE)
125638fd1498Szrj local_original = original;
125738fd1498Szrj
125838fd1498Szrj /* If original is COMDAT local, we can not really redirect calls outside
125938fd1498Szrj of its comdat group to it. */
126038fd1498Szrj if (original->comdat_local_p ())
126138fd1498Szrj redirect_callers = false;
126238fd1498Szrj if (!local_original)
126338fd1498Szrj {
126438fd1498Szrj if (dump_file)
126538fd1498Szrj fprintf (dump_file, "Not unifying; "
126638fd1498Szrj "can not produce local alias.\n\n");
126738fd1498Szrj return false;
126838fd1498Szrj }
126938fd1498Szrj
127038fd1498Szrj if (!redirect_callers && !create_wrapper)
127138fd1498Szrj {
127238fd1498Szrj if (dump_file)
127338fd1498Szrj fprintf (dump_file, "Not unifying; "
127438fd1498Szrj "can not redirect callers nor produce a wrapper\n\n");
127538fd1498Szrj return false;
127638fd1498Szrj }
127738fd1498Szrj if (!create_wrapper
127838fd1498Szrj && !alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p,
127938fd1498Szrj NULL, true)
128038fd1498Szrj && !alias->can_remove_if_no_direct_calls_p ())
128138fd1498Szrj {
128238fd1498Szrj if (dump_file)
128338fd1498Szrj fprintf (dump_file, "Not unifying; can not make wrapper and "
128438fd1498Szrj "function has other uses than direct calls\n\n");
128538fd1498Szrj return false;
128638fd1498Szrj }
128738fd1498Szrj }
128838fd1498Szrj else
128938fd1498Szrj create_alias = true;
129038fd1498Szrj
129138fd1498Szrj if (redirect_callers)
129238fd1498Szrj {
129338fd1498Szrj int nredirected = redirect_all_callers (alias, local_original);
129438fd1498Szrj
129538fd1498Szrj if (nredirected)
129638fd1498Szrj {
129738fd1498Szrj alias->icf_merged = true;
129838fd1498Szrj local_original->icf_merged = true;
129938fd1498Szrj
130038fd1498Szrj if (dump_file && nredirected)
130138fd1498Szrj fprintf (dump_file, "%i local calls have been "
130238fd1498Szrj "redirected.\n", nredirected);
130338fd1498Szrj }
130438fd1498Szrj
130538fd1498Szrj /* If all callers was redirected, do not produce wrapper. */
130638fd1498Szrj if (alias->can_remove_if_no_direct_calls_p ()
130738fd1498Szrj && !DECL_VIRTUAL_P (alias->decl)
130838fd1498Szrj && !alias->has_aliases_p ())
130938fd1498Szrj {
131038fd1498Szrj create_wrapper = false;
131138fd1498Szrj remove = true;
131238fd1498Szrj }
131338fd1498Szrj gcc_assert (!create_alias);
131438fd1498Szrj }
131538fd1498Szrj else if (create_alias)
131638fd1498Szrj {
131738fd1498Szrj alias->icf_merged = true;
131838fd1498Szrj
131938fd1498Szrj /* Remove the function's body. */
132038fd1498Szrj ipa_merge_profiles (original, alias);
132138fd1498Szrj alias->release_body (true);
132238fd1498Szrj alias->reset ();
132338fd1498Szrj /* Notice global symbol possibly produced RTL. */
132438fd1498Szrj ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl,
132538fd1498Szrj NULL, true);
132638fd1498Szrj
132738fd1498Szrj /* Create the alias. */
132838fd1498Szrj cgraph_node::create_alias (alias_func->decl, decl);
132938fd1498Szrj alias->resolve_alias (original);
133038fd1498Szrj
133138fd1498Szrj original->call_for_symbol_thunks_and_aliases
133238fd1498Szrj (set_local, (void *)(size_t) original->local_p (), true);
133338fd1498Szrj
133438fd1498Szrj if (dump_file)
133538fd1498Szrj fprintf (dump_file, "Unified; Function alias has been created.\n\n");
133638fd1498Szrj }
133738fd1498Szrj if (create_wrapper)
133838fd1498Szrj {
133938fd1498Szrj gcc_assert (!create_alias);
134038fd1498Szrj alias->icf_merged = true;
134138fd1498Szrj local_original->icf_merged = true;
134238fd1498Szrj
134338fd1498Szrj /* FIXME update local_original counts. */
134438fd1498Szrj ipa_merge_profiles (original, alias, true);
134538fd1498Szrj alias->create_wrapper (local_original);
134638fd1498Szrj
134738fd1498Szrj if (dump_file)
134838fd1498Szrj fprintf (dump_file, "Unified; Wrapper has been created.\n\n");
134938fd1498Szrj }
135038fd1498Szrj
135138fd1498Szrj /* It's possible that redirection can hit thunks that block
135238fd1498Szrj redirection opportunities. */
135338fd1498Szrj gcc_assert (alias->icf_merged || remove || redirect_callers);
135438fd1498Szrj original->icf_merged = true;
135538fd1498Szrj
135638fd1498Szrj /* We use merged flag to track cases where COMDAT function is known to be
135738fd1498Szrj compatible its callers. If we merged in non-COMDAT, we need to give up
135838fd1498Szrj on this optimization. */
135938fd1498Szrj if (original->merged_comdat && !alias->merged_comdat)
136038fd1498Szrj {
136138fd1498Szrj if (dump_file)
136238fd1498Szrj fprintf (dump_file, "Dropping merged_comdat flag.\n\n");
136338fd1498Szrj if (local_original)
136438fd1498Szrj local_original->merged_comdat = false;
136538fd1498Szrj original->merged_comdat = false;
136638fd1498Szrj }
136738fd1498Szrj
136838fd1498Szrj if (remove)
136938fd1498Szrj {
137038fd1498Szrj ipa_merge_profiles (original, alias);
137138fd1498Szrj alias->release_body ();
137238fd1498Szrj alias->reset ();
137338fd1498Szrj alias->body_removed = true;
137438fd1498Szrj alias->icf_merged = true;
137538fd1498Szrj if (dump_file)
137638fd1498Szrj fprintf (dump_file, "Unified; Function body was removed.\n");
137738fd1498Szrj }
137838fd1498Szrj
137938fd1498Szrj return true;
138038fd1498Szrj }
138138fd1498Szrj
138238fd1498Szrj /* Semantic item initialization function. */
138338fd1498Szrj
138438fd1498Szrj void
init(void)138538fd1498Szrj sem_function::init (void)
138638fd1498Szrj {
138738fd1498Szrj if (in_lto_p)
138838fd1498Szrj get_node ()->get_untransformed_body ();
138938fd1498Szrj
139038fd1498Szrj tree fndecl = node->decl;
139138fd1498Szrj function *func = DECL_STRUCT_FUNCTION (fndecl);
139238fd1498Szrj
139338fd1498Szrj gcc_assert (func);
139438fd1498Szrj gcc_assert (SSANAMES (func));
139538fd1498Szrj
139638fd1498Szrj ssa_names_size = SSANAMES (func)->length ();
139738fd1498Szrj node = node;
139838fd1498Szrj
139938fd1498Szrj decl = fndecl;
140038fd1498Szrj region_tree = func->eh->region_tree;
140138fd1498Szrj
140238fd1498Szrj /* iterating all function arguments. */
140338fd1498Szrj arg_count = count_formal_params (fndecl);
140438fd1498Szrj
140538fd1498Szrj edge_count = n_edges_for_fn (func);
140638fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
140738fd1498Szrj if (!cnode->thunk.thunk_p)
140838fd1498Szrj {
140938fd1498Szrj cfg_checksum = coverage_compute_cfg_checksum (func);
141038fd1498Szrj
141138fd1498Szrj inchash::hash hstate;
141238fd1498Szrj
141338fd1498Szrj basic_block bb;
141438fd1498Szrj FOR_EACH_BB_FN (bb, func)
141538fd1498Szrj {
141638fd1498Szrj unsigned nondbg_stmt_count = 0;
141738fd1498Szrj
141838fd1498Szrj edge e;
141938fd1498Szrj for (edge_iterator ei = ei_start (bb->preds); ei_cond (ei, &e);
142038fd1498Szrj ei_next (&ei))
142138fd1498Szrj cfg_checksum = iterative_hash_host_wide_int (e->flags,
142238fd1498Szrj cfg_checksum);
142338fd1498Szrj
142438fd1498Szrj for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
142538fd1498Szrj gsi_next (&gsi))
142638fd1498Szrj {
142738fd1498Szrj gimple *stmt = gsi_stmt (gsi);
142838fd1498Szrj
142938fd1498Szrj if (gimple_code (stmt) != GIMPLE_DEBUG
143038fd1498Szrj && gimple_code (stmt) != GIMPLE_PREDICT)
143138fd1498Szrj {
143238fd1498Szrj hash_stmt (stmt, hstate);
143338fd1498Szrj nondbg_stmt_count++;
143438fd1498Szrj }
143538fd1498Szrj }
143638fd1498Szrj
143738fd1498Szrj hstate.commit_flag ();
143838fd1498Szrj gcode_hash = hstate.end ();
143938fd1498Szrj bb_sizes.safe_push (nondbg_stmt_count);
144038fd1498Szrj
144138fd1498Szrj /* Inserting basic block to hash table. */
144238fd1498Szrj sem_bb *semantic_bb = new sem_bb (bb, nondbg_stmt_count,
144338fd1498Szrj EDGE_COUNT (bb->preds)
144438fd1498Szrj + EDGE_COUNT (bb->succs));
144538fd1498Szrj
144638fd1498Szrj bb_sorted.safe_push (semantic_bb);
144738fd1498Szrj }
144838fd1498Szrj }
144938fd1498Szrj else
145038fd1498Szrj {
145138fd1498Szrj cfg_checksum = 0;
145238fd1498Szrj inchash::hash hstate;
145338fd1498Szrj hstate.add_hwi (cnode->thunk.fixed_offset);
145438fd1498Szrj hstate.add_hwi (cnode->thunk.virtual_value);
145538fd1498Szrj hstate.add_flag (cnode->thunk.this_adjusting);
145638fd1498Szrj hstate.add_flag (cnode->thunk.virtual_offset_p);
145738fd1498Szrj hstate.add_flag (cnode->thunk.add_pointer_bounds_args);
145838fd1498Szrj gcode_hash = hstate.end ();
145938fd1498Szrj }
146038fd1498Szrj }
146138fd1498Szrj
146238fd1498Szrj /* Accumulate to HSTATE a hash of expression EXP.
146338fd1498Szrj Identical to inchash::add_expr, but guaranteed to be stable across LTO
146438fd1498Szrj and DECL equality classes. */
146538fd1498Szrj
146638fd1498Szrj void
add_expr(const_tree exp,inchash::hash & hstate)146738fd1498Szrj sem_item::add_expr (const_tree exp, inchash::hash &hstate)
146838fd1498Szrj {
146938fd1498Szrj if (exp == NULL_TREE)
147038fd1498Szrj {
147138fd1498Szrj hstate.merge_hash (0);
147238fd1498Szrj return;
147338fd1498Szrj }
147438fd1498Szrj
147538fd1498Szrj /* Handled component can be matched in a cureful way proving equivalence
147638fd1498Szrj even if they syntactically differ. Just skip them. */
147738fd1498Szrj STRIP_NOPS (exp);
147838fd1498Szrj while (handled_component_p (exp))
147938fd1498Szrj exp = TREE_OPERAND (exp, 0);
148038fd1498Szrj
148138fd1498Szrj enum tree_code code = TREE_CODE (exp);
148238fd1498Szrj hstate.add_int (code);
148338fd1498Szrj
148438fd1498Szrj switch (code)
148538fd1498Szrj {
148638fd1498Szrj /* Use inchash::add_expr for everything that is LTO stable. */
148738fd1498Szrj case VOID_CST:
148838fd1498Szrj case INTEGER_CST:
148938fd1498Szrj case REAL_CST:
149038fd1498Szrj case FIXED_CST:
149138fd1498Szrj case STRING_CST:
149238fd1498Szrj case COMPLEX_CST:
149338fd1498Szrj case VECTOR_CST:
149438fd1498Szrj inchash::add_expr (exp, hstate);
149538fd1498Szrj break;
149638fd1498Szrj case CONSTRUCTOR:
149738fd1498Szrj {
149838fd1498Szrj unsigned HOST_WIDE_INT idx;
149938fd1498Szrj tree value;
150038fd1498Szrj
150138fd1498Szrj hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
150238fd1498Szrj
150338fd1498Szrj FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
150438fd1498Szrj if (value)
150538fd1498Szrj add_expr (value, hstate);
150638fd1498Szrj break;
150738fd1498Szrj }
150838fd1498Szrj case ADDR_EXPR:
150938fd1498Szrj case FDESC_EXPR:
151038fd1498Szrj add_expr (get_base_address (TREE_OPERAND (exp, 0)), hstate);
151138fd1498Szrj break;
151238fd1498Szrj case SSA_NAME:
151338fd1498Szrj case VAR_DECL:
151438fd1498Szrj case CONST_DECL:
151538fd1498Szrj case PARM_DECL:
151638fd1498Szrj hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
151738fd1498Szrj break;
151838fd1498Szrj case MEM_REF:
151938fd1498Szrj case POINTER_PLUS_EXPR:
152038fd1498Szrj case MINUS_EXPR:
152138fd1498Szrj case RANGE_EXPR:
152238fd1498Szrj add_expr (TREE_OPERAND (exp, 0), hstate);
152338fd1498Szrj add_expr (TREE_OPERAND (exp, 1), hstate);
152438fd1498Szrj break;
152538fd1498Szrj case PLUS_EXPR:
152638fd1498Szrj {
152738fd1498Szrj inchash::hash one, two;
152838fd1498Szrj add_expr (TREE_OPERAND (exp, 0), one);
152938fd1498Szrj add_expr (TREE_OPERAND (exp, 1), two);
153038fd1498Szrj hstate.add_commutative (one, two);
153138fd1498Szrj }
153238fd1498Szrj break;
153338fd1498Szrj CASE_CONVERT:
153438fd1498Szrj hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
153538fd1498Szrj return add_expr (TREE_OPERAND (exp, 0), hstate);
153638fd1498Szrj default:
153738fd1498Szrj break;
153838fd1498Szrj }
153938fd1498Szrj }
154038fd1498Szrj
154138fd1498Szrj /* Accumulate to HSTATE a hash of type t.
154238fd1498Szrj TYpes that may end up being compatible after LTO type merging needs to have
154338fd1498Szrj the same hash. */
154438fd1498Szrj
154538fd1498Szrj void
add_type(const_tree type,inchash::hash & hstate)154638fd1498Szrj sem_item::add_type (const_tree type, inchash::hash &hstate)
154738fd1498Szrj {
154838fd1498Szrj if (type == NULL_TREE)
154938fd1498Szrj {
155038fd1498Szrj hstate.merge_hash (0);
155138fd1498Szrj return;
155238fd1498Szrj }
155338fd1498Szrj
155438fd1498Szrj type = TYPE_MAIN_VARIANT (type);
155538fd1498Szrj
155638fd1498Szrj hstate.add_int (TYPE_MODE (type));
155738fd1498Szrj
155838fd1498Szrj if (TREE_CODE (type) == COMPLEX_TYPE)
155938fd1498Szrj {
156038fd1498Szrj hstate.add_int (COMPLEX_TYPE);
156138fd1498Szrj sem_item::add_type (TREE_TYPE (type), hstate);
156238fd1498Szrj }
156338fd1498Szrj else if (INTEGRAL_TYPE_P (type))
156438fd1498Szrj {
156538fd1498Szrj hstate.add_int (INTEGER_TYPE);
156638fd1498Szrj hstate.add_flag (TYPE_UNSIGNED (type));
156738fd1498Szrj hstate.add_int (TYPE_PRECISION (type));
156838fd1498Szrj }
156938fd1498Szrj else if (VECTOR_TYPE_P (type))
157038fd1498Szrj {
157138fd1498Szrj hstate.add_int (VECTOR_TYPE);
157238fd1498Szrj hstate.add_int (TYPE_PRECISION (type));
157338fd1498Szrj sem_item::add_type (TREE_TYPE (type), hstate);
157438fd1498Szrj }
157538fd1498Szrj else if (TREE_CODE (type) == ARRAY_TYPE)
157638fd1498Szrj {
157738fd1498Szrj hstate.add_int (ARRAY_TYPE);
157838fd1498Szrj /* Do not hash size, so complete and incomplete types can match. */
157938fd1498Szrj sem_item::add_type (TREE_TYPE (type), hstate);
158038fd1498Szrj }
158138fd1498Szrj else if (RECORD_OR_UNION_TYPE_P (type))
158238fd1498Szrj {
158338fd1498Szrj gcc_checking_assert (COMPLETE_TYPE_P (type));
158438fd1498Szrj hashval_t *val = optimizer->m_type_hash_cache.get (type);
158538fd1498Szrj
158638fd1498Szrj if (!val)
158738fd1498Szrj {
158838fd1498Szrj inchash::hash hstate2;
158938fd1498Szrj unsigned nf;
159038fd1498Szrj tree f;
159138fd1498Szrj hashval_t hash;
159238fd1498Szrj
159338fd1498Szrj hstate2.add_int (RECORD_TYPE);
159438fd1498Szrj gcc_assert (COMPLETE_TYPE_P (type));
159538fd1498Szrj
159638fd1498Szrj for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f))
159738fd1498Szrj if (TREE_CODE (f) == FIELD_DECL)
159838fd1498Szrj {
159938fd1498Szrj add_type (TREE_TYPE (f), hstate2);
160038fd1498Szrj nf++;
160138fd1498Szrj }
160238fd1498Szrj
160338fd1498Szrj hstate2.add_int (nf);
160438fd1498Szrj hash = hstate2.end ();
160538fd1498Szrj hstate.add_hwi (hash);
160638fd1498Szrj optimizer->m_type_hash_cache.put (type, hash);
160738fd1498Szrj }
160838fd1498Szrj else
160938fd1498Szrj hstate.add_hwi (*val);
161038fd1498Szrj }
161138fd1498Szrj }
161238fd1498Szrj
161338fd1498Szrj /* Improve accumulated hash for HSTATE based on a gimple statement STMT. */
161438fd1498Szrj
161538fd1498Szrj void
hash_stmt(gimple * stmt,inchash::hash & hstate)161638fd1498Szrj sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
161738fd1498Szrj {
161838fd1498Szrj enum gimple_code code = gimple_code (stmt);
161938fd1498Szrj
162038fd1498Szrj hstate.add_int (code);
162138fd1498Szrj
162238fd1498Szrj switch (code)
162338fd1498Szrj {
162438fd1498Szrj case GIMPLE_SWITCH:
162538fd1498Szrj add_expr (gimple_switch_index (as_a <gswitch *> (stmt)), hstate);
162638fd1498Szrj break;
162738fd1498Szrj case GIMPLE_ASSIGN:
162838fd1498Szrj hstate.add_int (gimple_assign_rhs_code (stmt));
162938fd1498Szrj if (commutative_tree_code (gimple_assign_rhs_code (stmt))
163038fd1498Szrj || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
163138fd1498Szrj {
163238fd1498Szrj inchash::hash one, two;
163338fd1498Szrj
163438fd1498Szrj add_expr (gimple_assign_rhs1 (stmt), one);
163538fd1498Szrj add_type (TREE_TYPE (gimple_assign_rhs1 (stmt)), one);
163638fd1498Szrj add_expr (gimple_assign_rhs2 (stmt), two);
163738fd1498Szrj hstate.add_commutative (one, two);
163838fd1498Szrj if (commutative_ternary_tree_code (gimple_assign_rhs_code (stmt)))
163938fd1498Szrj {
164038fd1498Szrj add_expr (gimple_assign_rhs3 (stmt), hstate);
164138fd1498Szrj add_type (TREE_TYPE (gimple_assign_rhs3 (stmt)), hstate);
164238fd1498Szrj }
164338fd1498Szrj add_expr (gimple_assign_lhs (stmt), hstate);
164438fd1498Szrj add_type (TREE_TYPE (gimple_assign_lhs (stmt)), two);
164538fd1498Szrj break;
164638fd1498Szrj }
164738fd1498Szrj /* fall through */
164838fd1498Szrj case GIMPLE_CALL:
164938fd1498Szrj case GIMPLE_ASM:
165038fd1498Szrj case GIMPLE_COND:
165138fd1498Szrj case GIMPLE_GOTO:
165238fd1498Szrj case GIMPLE_RETURN:
165338fd1498Szrj /* All these statements are equivalent if their operands are. */
165438fd1498Szrj for (unsigned i = 0; i < gimple_num_ops (stmt); ++i)
165538fd1498Szrj {
165638fd1498Szrj add_expr (gimple_op (stmt, i), hstate);
165738fd1498Szrj if (gimple_op (stmt, i))
165838fd1498Szrj add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
165938fd1498Szrj }
166038fd1498Szrj /* Consider nocf_check attribute in hash as it affects code
166138fd1498Szrj generation. */
166238fd1498Szrj if (code == GIMPLE_CALL
166338fd1498Szrj && flag_cf_protection & CF_BRANCH)
166438fd1498Szrj hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
166538fd1498Szrj default:
166638fd1498Szrj break;
166738fd1498Szrj }
166838fd1498Szrj }
166938fd1498Szrj
167038fd1498Szrj
167138fd1498Szrj /* Return true if polymorphic comparison must be processed. */
167238fd1498Szrj
167338fd1498Szrj bool
compare_polymorphic_p(void)167438fd1498Szrj sem_function::compare_polymorphic_p (void)
167538fd1498Szrj {
167638fd1498Szrj struct cgraph_edge *e;
167738fd1498Szrj
167838fd1498Szrj if (!opt_for_fn (get_node ()->decl, flag_devirtualize))
167938fd1498Szrj return false;
168038fd1498Szrj if (get_node ()->indirect_calls != NULL)
168138fd1498Szrj return true;
168238fd1498Szrj /* TODO: We can do simple propagation determining what calls may lead to
168338fd1498Szrj a polymorphic call. */
168438fd1498Szrj for (e = get_node ()->callees; e; e = e->next_callee)
168538fd1498Szrj if (e->callee->definition
168638fd1498Szrj && opt_for_fn (e->callee->decl, flag_devirtualize))
168738fd1498Szrj return true;
168838fd1498Szrj return false;
168938fd1498Szrj }
169038fd1498Szrj
169138fd1498Szrj /* For a given call graph NODE, the function constructs new
169238fd1498Szrj semantic function item. */
169338fd1498Szrj
169438fd1498Szrj sem_function *
parse(cgraph_node * node,bitmap_obstack * stack)169538fd1498Szrj sem_function::parse (cgraph_node *node, bitmap_obstack *stack)
169638fd1498Szrj {
169738fd1498Szrj tree fndecl = node->decl;
169838fd1498Szrj function *func = DECL_STRUCT_FUNCTION (fndecl);
169938fd1498Szrj
170038fd1498Szrj if (!func || (!node->has_gimple_body_p () && !node->thunk.thunk_p))
170138fd1498Szrj return NULL;
170238fd1498Szrj
170338fd1498Szrj if (lookup_attribute_by_prefix ("omp ", DECL_ATTRIBUTES (node->decl)) != NULL)
170438fd1498Szrj return NULL;
170538fd1498Szrj
170638fd1498Szrj if (lookup_attribute_by_prefix ("oacc ",
170738fd1498Szrj DECL_ATTRIBUTES (node->decl)) != NULL)
170838fd1498Szrj return NULL;
170938fd1498Szrj
171038fd1498Szrj /* PR ipa/70306. */
171138fd1498Szrj if (DECL_STATIC_CONSTRUCTOR (node->decl)
171238fd1498Szrj || DECL_STATIC_DESTRUCTOR (node->decl))
171338fd1498Szrj return NULL;
171438fd1498Szrj
171538fd1498Szrj sem_function *f = new sem_function (node, stack);
171638fd1498Szrj
171738fd1498Szrj f->init ();
171838fd1498Szrj
171938fd1498Szrj return f;
172038fd1498Szrj }
172138fd1498Szrj
172238fd1498Szrj /* For given basic blocks BB1 and BB2 (from functions FUNC1 and FUNC),
172338fd1498Szrj return true if phi nodes are semantically equivalent in these blocks . */
172438fd1498Szrj
172538fd1498Szrj bool
compare_phi_node(basic_block bb1,basic_block bb2)172638fd1498Szrj sem_function::compare_phi_node (basic_block bb1, basic_block bb2)
172738fd1498Szrj {
172838fd1498Szrj gphi_iterator si1, si2;
172938fd1498Szrj gphi *phi1, *phi2;
173038fd1498Szrj unsigned size1, size2, i;
173138fd1498Szrj tree t1, t2;
173238fd1498Szrj edge e1, e2;
173338fd1498Szrj
173438fd1498Szrj gcc_assert (bb1 != NULL);
173538fd1498Szrj gcc_assert (bb2 != NULL);
173638fd1498Szrj
173738fd1498Szrj si2 = gsi_start_phis (bb2);
173838fd1498Szrj for (si1 = gsi_start_phis (bb1); !gsi_end_p (si1);
173938fd1498Szrj gsi_next (&si1))
174038fd1498Szrj {
174138fd1498Szrj gsi_next_nonvirtual_phi (&si1);
174238fd1498Szrj gsi_next_nonvirtual_phi (&si2);
174338fd1498Szrj
174438fd1498Szrj if (gsi_end_p (si1) && gsi_end_p (si2))
174538fd1498Szrj break;
174638fd1498Szrj
174738fd1498Szrj if (gsi_end_p (si1) || gsi_end_p (si2))
174838fd1498Szrj return return_false();
174938fd1498Szrj
175038fd1498Szrj phi1 = si1.phi ();
175138fd1498Szrj phi2 = si2.phi ();
175238fd1498Szrj
175338fd1498Szrj tree phi_result1 = gimple_phi_result (phi1);
175438fd1498Szrj tree phi_result2 = gimple_phi_result (phi2);
175538fd1498Szrj
175638fd1498Szrj if (!m_checker->compare_operand (phi_result1, phi_result2))
175738fd1498Szrj return return_false_with_msg ("PHI results are different");
175838fd1498Szrj
175938fd1498Szrj size1 = gimple_phi_num_args (phi1);
176038fd1498Szrj size2 = gimple_phi_num_args (phi2);
176138fd1498Szrj
176238fd1498Szrj if (size1 != size2)
176338fd1498Szrj return return_false ();
176438fd1498Szrj
176538fd1498Szrj for (i = 0; i < size1; ++i)
176638fd1498Szrj {
176738fd1498Szrj t1 = gimple_phi_arg (phi1, i)->def;
176838fd1498Szrj t2 = gimple_phi_arg (phi2, i)->def;
176938fd1498Szrj
177038fd1498Szrj if (!m_checker->compare_operand (t1, t2))
177138fd1498Szrj return return_false ();
177238fd1498Szrj
177338fd1498Szrj e1 = gimple_phi_arg_edge (phi1, i);
177438fd1498Szrj e2 = gimple_phi_arg_edge (phi2, i);
177538fd1498Szrj
177638fd1498Szrj if (!m_checker->compare_edge (e1, e2))
177738fd1498Szrj return return_false ();
177838fd1498Szrj }
177938fd1498Szrj
178038fd1498Szrj gsi_next (&si2);
178138fd1498Szrj }
178238fd1498Szrj
178338fd1498Szrj return true;
178438fd1498Szrj }
178538fd1498Szrj
178638fd1498Szrj /* Returns true if tree T can be compared as a handled component. */
178738fd1498Szrj
178838fd1498Szrj bool
icf_handled_component_p(tree t)178938fd1498Szrj sem_function::icf_handled_component_p (tree t)
179038fd1498Szrj {
179138fd1498Szrj tree_code tc = TREE_CODE (t);
179238fd1498Szrj
179338fd1498Szrj return (handled_component_p (t)
179438fd1498Szrj || tc == ADDR_EXPR || tc == MEM_REF || tc == OBJ_TYPE_REF);
179538fd1498Szrj }
179638fd1498Szrj
179738fd1498Szrj /* Basic blocks dictionary BB_DICT returns true if SOURCE index BB
179838fd1498Szrj corresponds to TARGET. */
179938fd1498Szrj
180038fd1498Szrj bool
bb_dict_test(vec<int> * bb_dict,int source,int target)180138fd1498Szrj sem_function::bb_dict_test (vec<int> *bb_dict, int source, int target)
180238fd1498Szrj {
180338fd1498Szrj source++;
180438fd1498Szrj target++;
180538fd1498Szrj
180638fd1498Szrj if (bb_dict->length () <= (unsigned)source)
180738fd1498Szrj bb_dict->safe_grow_cleared (source + 1);
180838fd1498Szrj
180938fd1498Szrj if ((*bb_dict)[source] == 0)
181038fd1498Szrj {
181138fd1498Szrj (*bb_dict)[source] = target;
181238fd1498Szrj return true;
181338fd1498Szrj }
181438fd1498Szrj else
181538fd1498Szrj return (*bb_dict)[source] == target;
181638fd1498Szrj }
181738fd1498Szrj
sem_variable(bitmap_obstack * stack)181838fd1498Szrj sem_variable::sem_variable (bitmap_obstack *stack): sem_item (VAR, stack)
181938fd1498Szrj {
182038fd1498Szrj }
182138fd1498Szrj
sem_variable(varpool_node * node,bitmap_obstack * stack)182238fd1498Szrj sem_variable::sem_variable (varpool_node *node, bitmap_obstack *stack)
182338fd1498Szrj : sem_item (VAR, node, stack)
182438fd1498Szrj {
182538fd1498Szrj gcc_checking_assert (node);
182638fd1498Szrj gcc_checking_assert (get_node ());
182738fd1498Szrj }
182838fd1498Szrj
182938fd1498Szrj /* Fast equality function based on knowledge known in WPA. */
183038fd1498Szrj
183138fd1498Szrj bool
equals_wpa(sem_item * item,hash_map<symtab_node *,sem_item * > & ignored_nodes)183238fd1498Szrj sem_variable::equals_wpa (sem_item *item,
183338fd1498Szrj hash_map <symtab_node *, sem_item *> &ignored_nodes)
183438fd1498Szrj {
183538fd1498Szrj gcc_assert (item->type == VAR);
183638fd1498Szrj
183738fd1498Szrj if (node->num_references () != item->node->num_references ())
183838fd1498Szrj return return_false_with_msg ("different number of references");
183938fd1498Szrj
184038fd1498Szrj if (DECL_TLS_MODEL (decl) || DECL_TLS_MODEL (item->decl))
184138fd1498Szrj return return_false_with_msg ("TLS model");
184238fd1498Szrj
184338fd1498Szrj /* DECL_ALIGN is safe to merge, because we will always chose the largest
184438fd1498Szrj alignment out of all aliases. */
184538fd1498Szrj
184638fd1498Szrj if (DECL_VIRTUAL_P (decl) != DECL_VIRTUAL_P (item->decl))
184738fd1498Szrj return return_false_with_msg ("Virtual flag mismatch");
184838fd1498Szrj
184938fd1498Szrj if (DECL_SIZE (decl) != DECL_SIZE (item->decl)
185038fd1498Szrj && ((!DECL_SIZE (decl) || !DECL_SIZE (item->decl))
185138fd1498Szrj || !operand_equal_p (DECL_SIZE (decl),
185238fd1498Szrj DECL_SIZE (item->decl), OEP_ONLY_CONST)))
185338fd1498Szrj return return_false_with_msg ("size mismatch");
185438fd1498Szrj
185538fd1498Szrj /* Do not attempt to mix data from different user sections;
185638fd1498Szrj we do not know what user intends with those. */
185738fd1498Szrj if (((DECL_SECTION_NAME (decl) && !node->implicit_section)
185838fd1498Szrj || (DECL_SECTION_NAME (item->decl) && !item->node->implicit_section))
185938fd1498Szrj && DECL_SECTION_NAME (decl) != DECL_SECTION_NAME (item->decl))
186038fd1498Szrj return return_false_with_msg ("user section mismatch");
186138fd1498Szrj
186238fd1498Szrj if (DECL_IN_TEXT_SECTION (decl) != DECL_IN_TEXT_SECTION (item->decl))
186338fd1498Szrj return return_false_with_msg ("text section");
186438fd1498Szrj
186538fd1498Szrj ipa_ref *ref = NULL, *ref2 = NULL;
186638fd1498Szrj for (unsigned i = 0; node->iterate_reference (i, ref); i++)
186738fd1498Szrj {
186838fd1498Szrj item->node->iterate_reference (i, ref2);
186938fd1498Szrj
187038fd1498Szrj if (ref->use != ref2->use)
187138fd1498Szrj return return_false_with_msg ("reference use mismatch");
187238fd1498Szrj
187338fd1498Szrj if (!compare_symbol_references (ignored_nodes,
187438fd1498Szrj ref->referred, ref2->referred,
187538fd1498Szrj ref->address_matters_p ()))
187638fd1498Szrj return false;
187738fd1498Szrj }
187838fd1498Szrj
187938fd1498Szrj return true;
188038fd1498Szrj }
188138fd1498Szrj
188238fd1498Szrj /* Returns true if the item equals to ITEM given as argument. */
188338fd1498Szrj
188438fd1498Szrj bool
equals(sem_item * item,hash_map<symtab_node *,sem_item * > &)188538fd1498Szrj sem_variable::equals (sem_item *item,
188638fd1498Szrj hash_map <symtab_node *, sem_item *> &)
188738fd1498Szrj {
188838fd1498Szrj gcc_assert (item->type == VAR);
188938fd1498Szrj bool ret;
189038fd1498Szrj
189138fd1498Szrj if (DECL_INITIAL (decl) == error_mark_node && in_lto_p)
189238fd1498Szrj dyn_cast <varpool_node *>(node)->get_constructor ();
189338fd1498Szrj if (DECL_INITIAL (item->decl) == error_mark_node && in_lto_p)
189438fd1498Szrj dyn_cast <varpool_node *>(item->node)->get_constructor ();
189538fd1498Szrj
189638fd1498Szrj /* As seen in PR ipa/65303 we have to compare variables types. */
189738fd1498Szrj if (!func_checker::compatible_types_p (TREE_TYPE (decl),
189838fd1498Szrj TREE_TYPE (item->decl)))
189938fd1498Szrj return return_false_with_msg ("variables types are different");
190038fd1498Szrj
190138fd1498Szrj ret = sem_variable::equals (DECL_INITIAL (decl),
190238fd1498Szrj DECL_INITIAL (item->node->decl));
190338fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
190438fd1498Szrj fprintf (dump_file,
190538fd1498Szrj "Equals called for vars: %s:%s with result: %s\n\n",
190638fd1498Szrj node->dump_name (), item->node->dump_name (),
190738fd1498Szrj ret ? "true" : "false");
190838fd1498Szrj
190938fd1498Szrj return ret;
191038fd1498Szrj }
191138fd1498Szrj
191238fd1498Szrj /* Compares trees T1 and T2 for semantic equality. */
191338fd1498Szrj
191438fd1498Szrj bool
equals(tree t1,tree t2)191538fd1498Szrj sem_variable::equals (tree t1, tree t2)
191638fd1498Szrj {
191738fd1498Szrj if (!t1 || !t2)
191838fd1498Szrj return return_with_debug (t1 == t2);
191938fd1498Szrj if (t1 == t2)
192038fd1498Szrj return true;
192138fd1498Szrj tree_code tc1 = TREE_CODE (t1);
192238fd1498Szrj tree_code tc2 = TREE_CODE (t2);
192338fd1498Szrj
192438fd1498Szrj if (tc1 != tc2)
192538fd1498Szrj return return_false_with_msg ("TREE_CODE mismatch");
192638fd1498Szrj
192738fd1498Szrj switch (tc1)
192838fd1498Szrj {
192938fd1498Szrj case CONSTRUCTOR:
193038fd1498Szrj {
193138fd1498Szrj vec<constructor_elt, va_gc> *v1, *v2;
193238fd1498Szrj unsigned HOST_WIDE_INT idx;
193338fd1498Szrj
193438fd1498Szrj enum tree_code typecode = TREE_CODE (TREE_TYPE (t1));
193538fd1498Szrj if (typecode != TREE_CODE (TREE_TYPE (t2)))
193638fd1498Szrj return return_false_with_msg ("constructor type mismatch");
193738fd1498Szrj
193838fd1498Szrj if (typecode == ARRAY_TYPE)
193938fd1498Szrj {
194038fd1498Szrj HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1));
194138fd1498Szrj /* For arrays, check that the sizes all match. */
194238fd1498Szrj if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))
194338fd1498Szrj || size_1 == -1
194438fd1498Szrj || size_1 != int_size_in_bytes (TREE_TYPE (t2)))
194538fd1498Szrj return return_false_with_msg ("constructor array size mismatch");
194638fd1498Szrj }
194738fd1498Szrj else if (!func_checker::compatible_types_p (TREE_TYPE (t1),
194838fd1498Szrj TREE_TYPE (t2)))
194938fd1498Szrj return return_false_with_msg ("constructor type incompatible");
195038fd1498Szrj
195138fd1498Szrj v1 = CONSTRUCTOR_ELTS (t1);
195238fd1498Szrj v2 = CONSTRUCTOR_ELTS (t2);
195338fd1498Szrj if (vec_safe_length (v1) != vec_safe_length (v2))
195438fd1498Szrj return return_false_with_msg ("constructor number of elts mismatch");
195538fd1498Szrj
195638fd1498Szrj for (idx = 0; idx < vec_safe_length (v1); ++idx)
195738fd1498Szrj {
195838fd1498Szrj constructor_elt *c1 = &(*v1)[idx];
195938fd1498Szrj constructor_elt *c2 = &(*v2)[idx];
196038fd1498Szrj
196138fd1498Szrj /* Check that each value is the same... */
196238fd1498Szrj if (!sem_variable::equals (c1->value, c2->value))
196338fd1498Szrj return false;
196438fd1498Szrj /* ... and that they apply to the same fields! */
196538fd1498Szrj if (!sem_variable::equals (c1->index, c2->index))
196638fd1498Szrj return false;
196738fd1498Szrj }
196838fd1498Szrj return true;
196938fd1498Szrj }
197038fd1498Szrj case MEM_REF:
197138fd1498Szrj {
197238fd1498Szrj tree x1 = TREE_OPERAND (t1, 0);
197338fd1498Szrj tree x2 = TREE_OPERAND (t2, 0);
197438fd1498Szrj tree y1 = TREE_OPERAND (t1, 1);
197538fd1498Szrj tree y2 = TREE_OPERAND (t2, 1);
197638fd1498Szrj
197738fd1498Szrj if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2)))
197838fd1498Szrj return return_false ();
197938fd1498Szrj
198038fd1498Szrj /* Type of the offset on MEM_REF does not matter. */
198138fd1498Szrj return return_with_debug (sem_variable::equals (x1, x2)
198238fd1498Szrj && wi::to_offset (y1)
198338fd1498Szrj == wi::to_offset (y2));
198438fd1498Szrj }
198538fd1498Szrj case ADDR_EXPR:
198638fd1498Szrj case FDESC_EXPR:
198738fd1498Szrj {
198838fd1498Szrj tree op1 = TREE_OPERAND (t1, 0);
198938fd1498Szrj tree op2 = TREE_OPERAND (t2, 0);
199038fd1498Szrj return sem_variable::equals (op1, op2);
199138fd1498Szrj }
199238fd1498Szrj /* References to other vars/decls are compared using ipa-ref. */
199338fd1498Szrj case FUNCTION_DECL:
199438fd1498Szrj case VAR_DECL:
199538fd1498Szrj if (decl_in_symtab_p (t1) && decl_in_symtab_p (t2))
199638fd1498Szrj return true;
199738fd1498Szrj return return_false_with_msg ("Declaration mismatch");
199838fd1498Szrj case CONST_DECL:
199938fd1498Szrj /* TODO: We can check CONST_DECL by its DECL_INITIAL, but for that we
200038fd1498Szrj need to process its VAR/FUNCTION references without relying on ipa-ref
200138fd1498Szrj compare. */
200238fd1498Szrj case FIELD_DECL:
200338fd1498Szrj case LABEL_DECL:
200438fd1498Szrj return return_false_with_msg ("Declaration mismatch");
200538fd1498Szrj case INTEGER_CST:
200638fd1498Szrj /* Integer constants are the same only if the same width of type. */
200738fd1498Szrj if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
200838fd1498Szrj return return_false_with_msg ("INTEGER_CST precision mismatch");
200938fd1498Szrj if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
201038fd1498Szrj return return_false_with_msg ("INTEGER_CST mode mismatch");
201138fd1498Szrj return return_with_debug (tree_int_cst_equal (t1, t2));
201238fd1498Szrj case STRING_CST:
201338fd1498Szrj if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)))
201438fd1498Szrj return return_false_with_msg ("STRING_CST mode mismatch");
201538fd1498Szrj if (TREE_STRING_LENGTH (t1) != TREE_STRING_LENGTH (t2))
201638fd1498Szrj return return_false_with_msg ("STRING_CST length mismatch");
201738fd1498Szrj if (memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
201838fd1498Szrj TREE_STRING_LENGTH (t1)))
201938fd1498Szrj return return_false_with_msg ("STRING_CST mismatch");
202038fd1498Szrj return true;
202138fd1498Szrj case FIXED_CST:
202238fd1498Szrj /* Fixed constants are the same only if the same width of type. */
202338fd1498Szrj if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
202438fd1498Szrj return return_false_with_msg ("FIXED_CST precision mismatch");
202538fd1498Szrj
202638fd1498Szrj return return_with_debug (FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1),
202738fd1498Szrj TREE_FIXED_CST (t2)));
202838fd1498Szrj case COMPLEX_CST:
202938fd1498Szrj return (sem_variable::equals (TREE_REALPART (t1), TREE_REALPART (t2))
203038fd1498Szrj && sem_variable::equals (TREE_IMAGPART (t1), TREE_IMAGPART (t2)));
203138fd1498Szrj case REAL_CST:
203238fd1498Szrj /* Real constants are the same only if the same width of type. */
203338fd1498Szrj if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2)))
203438fd1498Szrj return return_false_with_msg ("REAL_CST precision mismatch");
203538fd1498Szrj return return_with_debug (real_identical (&TREE_REAL_CST (t1),
203638fd1498Szrj &TREE_REAL_CST (t2)));
203738fd1498Szrj case VECTOR_CST:
203838fd1498Szrj {
203938fd1498Szrj if (maybe_ne (VECTOR_CST_NELTS (t1), VECTOR_CST_NELTS (t2)))
204038fd1498Szrj return return_false_with_msg ("VECTOR_CST nelts mismatch");
204138fd1498Szrj
204238fd1498Szrj unsigned int count
204338fd1498Szrj = tree_vector_builder::binary_encoded_nelts (t1, t2);
204438fd1498Szrj for (unsigned int i = 0; i < count; ++i)
204538fd1498Szrj if (!sem_variable::equals (VECTOR_CST_ENCODED_ELT (t1, i),
204638fd1498Szrj VECTOR_CST_ENCODED_ELT (t2, i)))
204738fd1498Szrj return false;
204838fd1498Szrj
204938fd1498Szrj return true;
205038fd1498Szrj }
205138fd1498Szrj case ARRAY_REF:
205238fd1498Szrj case ARRAY_RANGE_REF:
205338fd1498Szrj {
205438fd1498Szrj tree x1 = TREE_OPERAND (t1, 0);
205538fd1498Szrj tree x2 = TREE_OPERAND (t2, 0);
205638fd1498Szrj tree y1 = TREE_OPERAND (t1, 1);
205738fd1498Szrj tree y2 = TREE_OPERAND (t2, 1);
205838fd1498Szrj
205938fd1498Szrj if (!sem_variable::equals (x1, x2) || !sem_variable::equals (y1, y2))
206038fd1498Szrj return false;
206138fd1498Szrj if (!sem_variable::equals (array_ref_low_bound (t1),
206238fd1498Szrj array_ref_low_bound (t2)))
206338fd1498Szrj return false;
206438fd1498Szrj if (!sem_variable::equals (array_ref_element_size (t1),
206538fd1498Szrj array_ref_element_size (t2)))
206638fd1498Szrj return false;
206738fd1498Szrj return true;
206838fd1498Szrj }
206938fd1498Szrj
207038fd1498Szrj case COMPONENT_REF:
207138fd1498Szrj case POINTER_PLUS_EXPR:
207238fd1498Szrj case PLUS_EXPR:
207338fd1498Szrj case MINUS_EXPR:
207438fd1498Szrj case RANGE_EXPR:
207538fd1498Szrj {
207638fd1498Szrj tree x1 = TREE_OPERAND (t1, 0);
207738fd1498Szrj tree x2 = TREE_OPERAND (t2, 0);
207838fd1498Szrj tree y1 = TREE_OPERAND (t1, 1);
207938fd1498Szrj tree y2 = TREE_OPERAND (t2, 1);
208038fd1498Szrj
208138fd1498Szrj return sem_variable::equals (x1, x2) && sem_variable::equals (y1, y2);
208238fd1498Szrj }
208338fd1498Szrj
208438fd1498Szrj CASE_CONVERT:
208538fd1498Szrj case VIEW_CONVERT_EXPR:
208638fd1498Szrj if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2)))
208738fd1498Szrj return return_false ();
208838fd1498Szrj return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
208938fd1498Szrj case ERROR_MARK:
209038fd1498Szrj return return_false_with_msg ("ERROR_MARK");
209138fd1498Szrj default:
209238fd1498Szrj return return_false_with_msg ("Unknown TREE code reached");
209338fd1498Szrj }
209438fd1498Szrj }
209538fd1498Szrj
209638fd1498Szrj /* Parser function that visits a varpool NODE. */
209738fd1498Szrj
209838fd1498Szrj sem_variable *
parse(varpool_node * node,bitmap_obstack * stack)209938fd1498Szrj sem_variable::parse (varpool_node *node, bitmap_obstack *stack)
210038fd1498Szrj {
210138fd1498Szrj if (TREE_THIS_VOLATILE (node->decl) || DECL_HARD_REGISTER (node->decl)
210238fd1498Szrj || node->alias)
210338fd1498Szrj return NULL;
210438fd1498Szrj
210538fd1498Szrj sem_variable *v = new sem_variable (node, stack);
210638fd1498Szrj
210738fd1498Szrj v->init ();
210838fd1498Szrj
210938fd1498Szrj return v;
211038fd1498Szrj }
211138fd1498Szrj
211238fd1498Szrj /* References independent hash function. */
211338fd1498Szrj
211438fd1498Szrj hashval_t
get_hash(void)211538fd1498Szrj sem_variable::get_hash (void)
211638fd1498Szrj {
211738fd1498Szrj if (m_hash_set)
211838fd1498Szrj return m_hash;
211938fd1498Szrj
212038fd1498Szrj /* All WPA streamed in symbols should have their hashes computed at compile
212138fd1498Szrj time. At this point, the constructor may not be in memory at all.
212238fd1498Szrj DECL_INITIAL (decl) would be error_mark_node in that case. */
212338fd1498Szrj gcc_assert (!node->lto_file_data);
212438fd1498Szrj tree ctor = DECL_INITIAL (decl);
212538fd1498Szrj inchash::hash hstate;
212638fd1498Szrj
212738fd1498Szrj hstate.add_int (456346417);
212838fd1498Szrj if (DECL_SIZE (decl) && tree_fits_shwi_p (DECL_SIZE (decl)))
212938fd1498Szrj hstate.add_hwi (tree_to_shwi (DECL_SIZE (decl)));
213038fd1498Szrj add_expr (ctor, hstate);
213138fd1498Szrj set_hash (hstate.end ());
213238fd1498Szrj
213338fd1498Szrj return m_hash;
213438fd1498Szrj }
213538fd1498Szrj
213638fd1498Szrj /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
213738fd1498Szrj be applied. */
213838fd1498Szrj
213938fd1498Szrj bool
merge(sem_item * alias_item)214038fd1498Szrj sem_variable::merge (sem_item *alias_item)
214138fd1498Szrj {
214238fd1498Szrj gcc_assert (alias_item->type == VAR);
214338fd1498Szrj
214438fd1498Szrj if (!sem_item::target_supports_symbol_aliases_p ())
214538fd1498Szrj {
214638fd1498Szrj if (dump_file)
214738fd1498Szrj fprintf (dump_file, "Not unifying; "
214838fd1498Szrj "Symbol aliases are not supported by target\n\n");
214938fd1498Szrj return false;
215038fd1498Szrj }
215138fd1498Szrj
215238fd1498Szrj if (DECL_EXTERNAL (alias_item->decl))
215338fd1498Szrj {
215438fd1498Szrj if (dump_file)
215538fd1498Szrj fprintf (dump_file, "Not unifying; alias is external.\n\n");
215638fd1498Szrj return false;
215738fd1498Szrj }
215838fd1498Szrj
215938fd1498Szrj sem_variable *alias_var = static_cast<sem_variable *> (alias_item);
216038fd1498Szrj
216138fd1498Szrj varpool_node *original = get_node ();
216238fd1498Szrj varpool_node *alias = alias_var->get_node ();
216338fd1498Szrj bool original_discardable = false;
216438fd1498Szrj
216538fd1498Szrj bool alias_address_matters = alias->address_matters_p ();
216638fd1498Szrj
216738fd1498Szrj /* See if original is in a section that can be discarded if the main
216838fd1498Szrj symbol is not used.
216938fd1498Szrj Also consider case where we have resolution info and we know that
217038fd1498Szrj original's definition is not going to be used. In this case we can not
217138fd1498Szrj create alias to original. */
217238fd1498Szrj if (original->can_be_discarded_p ()
217338fd1498Szrj || (node->resolution != LDPR_UNKNOWN
217438fd1498Szrj && !decl_binds_to_current_def_p (node->decl)))
217538fd1498Szrj original_discardable = true;
217638fd1498Szrj
217738fd1498Szrj gcc_assert (!TREE_ASM_WRITTEN (alias->decl));
217838fd1498Szrj
217938fd1498Szrj /* Constant pool machinery is not quite ready for aliases.
218038fd1498Szrj TODO: varasm code contains logic for merging DECL_IN_CONSTANT_POOL.
218138fd1498Szrj For LTO merging does not happen that is an important missing feature.
218238fd1498Szrj We can enable merging with LTO if the DECL_IN_CONSTANT_POOL
218338fd1498Szrj flag is dropped and non-local symbol name is assigned. */
218438fd1498Szrj if (DECL_IN_CONSTANT_POOL (alias->decl)
218538fd1498Szrj || DECL_IN_CONSTANT_POOL (original->decl))
218638fd1498Szrj {
218738fd1498Szrj if (dump_file)
218838fd1498Szrj fprintf (dump_file,
218938fd1498Szrj "Not unifying; constant pool variables.\n\n");
219038fd1498Szrj return false;
219138fd1498Szrj }
219238fd1498Szrj
219338fd1498Szrj /* Do not attempt to mix functions from different user sections;
219438fd1498Szrj we do not know what user intends with those. */
219538fd1498Szrj if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
219638fd1498Szrj || (DECL_SECTION_NAME (alias->decl) && !alias->implicit_section))
219738fd1498Szrj && DECL_SECTION_NAME (original->decl) != DECL_SECTION_NAME (alias->decl))
219838fd1498Szrj {
219938fd1498Szrj if (dump_file)
220038fd1498Szrj fprintf (dump_file,
220138fd1498Szrj "Not unifying; "
220238fd1498Szrj "original and alias are in different sections.\n\n");
220338fd1498Szrj return false;
220438fd1498Szrj }
220538fd1498Szrj
220638fd1498Szrj /* We can not merge if address comparsion metters. */
220738fd1498Szrj if (alias_address_matters && flag_merge_constants < 2)
220838fd1498Szrj {
220938fd1498Szrj if (dump_file)
221038fd1498Szrj fprintf (dump_file,
221138fd1498Szrj "Not unifying; address of original may be compared.\n\n");
221238fd1498Szrj return false;
221338fd1498Szrj }
221438fd1498Szrj
221538fd1498Szrj if (DECL_ALIGN (original->decl) < DECL_ALIGN (alias->decl))
221638fd1498Szrj {
221738fd1498Szrj if (dump_file)
221838fd1498Szrj fprintf (dump_file, "Not unifying; "
221938fd1498Szrj "original and alias have incompatible alignments\n\n");
222038fd1498Szrj
222138fd1498Szrj return false;
222238fd1498Szrj }
222338fd1498Szrj
222438fd1498Szrj if (DECL_COMDAT_GROUP (original->decl) != DECL_COMDAT_GROUP (alias->decl))
222538fd1498Szrj {
222638fd1498Szrj if (dump_file)
222738fd1498Szrj fprintf (dump_file, "Not unifying; alias cannot be created; "
222838fd1498Szrj "across comdat group boundary\n\n");
222938fd1498Szrj
223038fd1498Szrj return false;
223138fd1498Szrj }
223238fd1498Szrj
223338fd1498Szrj if (original_discardable)
223438fd1498Szrj {
223538fd1498Szrj if (dump_file)
223638fd1498Szrj fprintf (dump_file, "Not unifying; alias cannot be created; "
223738fd1498Szrj "target is discardable\n\n");
223838fd1498Szrj
223938fd1498Szrj return false;
224038fd1498Szrj }
224138fd1498Szrj else
224238fd1498Szrj {
224338fd1498Szrj gcc_assert (!original->alias);
224438fd1498Szrj gcc_assert (!alias->alias);
224538fd1498Szrj
224638fd1498Szrj alias->analyzed = false;
224738fd1498Szrj
224838fd1498Szrj DECL_INITIAL (alias->decl) = NULL;
224938fd1498Szrj ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl,
225038fd1498Szrj NULL, true);
225138fd1498Szrj alias->need_bounds_init = false;
225238fd1498Szrj alias->remove_all_references ();
225338fd1498Szrj if (TREE_ADDRESSABLE (alias->decl))
225438fd1498Szrj original->call_for_symbol_and_aliases (set_addressable, NULL, true);
225538fd1498Szrj
225638fd1498Szrj varpool_node::create_alias (alias_var->decl, decl);
225738fd1498Szrj alias->resolve_alias (original);
225838fd1498Szrj
225938fd1498Szrj if (dump_file)
226038fd1498Szrj fprintf (dump_file, "Unified; Variable alias has been created.\n");
226138fd1498Szrj
226238fd1498Szrj return true;
226338fd1498Szrj }
226438fd1498Szrj }
226538fd1498Szrj
226638fd1498Szrj /* Dump symbol to FILE. */
226738fd1498Szrj
226838fd1498Szrj void
dump_to_file(FILE * file)226938fd1498Szrj sem_variable::dump_to_file (FILE *file)
227038fd1498Szrj {
227138fd1498Szrj gcc_assert (file);
227238fd1498Szrj
227338fd1498Szrj print_node (file, "", decl, 0);
227438fd1498Szrj fprintf (file, "\n\n");
227538fd1498Szrj }
227638fd1498Szrj
227738fd1498Szrj unsigned int sem_item_optimizer::class_id = 0;
227838fd1498Szrj
sem_item_optimizer()227938fd1498Szrj sem_item_optimizer::sem_item_optimizer ()
228038fd1498Szrj : worklist (0), m_classes (0), m_classes_count (0), m_cgraph_node_hooks (NULL),
228138fd1498Szrj m_varpool_node_hooks (NULL), m_merged_variables ()
228238fd1498Szrj {
228338fd1498Szrj m_items.create (0);
228438fd1498Szrj bitmap_obstack_initialize (&m_bmstack);
228538fd1498Szrj }
228638fd1498Szrj
~sem_item_optimizer()228738fd1498Szrj sem_item_optimizer::~sem_item_optimizer ()
228838fd1498Szrj {
228938fd1498Szrj for (unsigned int i = 0; i < m_items.length (); i++)
229038fd1498Szrj delete m_items[i];
229138fd1498Szrj
229238fd1498Szrj
229338fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
229438fd1498Szrj it != m_classes.end (); ++it)
229538fd1498Szrj {
229638fd1498Szrj for (unsigned int i = 0; i < (*it)->classes.length (); i++)
229738fd1498Szrj delete (*it)->classes[i];
229838fd1498Szrj
229938fd1498Szrj (*it)->classes.release ();
230038fd1498Szrj free (*it);
230138fd1498Szrj }
230238fd1498Szrj
230338fd1498Szrj m_items.release ();
230438fd1498Szrj
230538fd1498Szrj bitmap_obstack_release (&m_bmstack);
230638fd1498Szrj m_merged_variables.release ();
230738fd1498Szrj }
230838fd1498Szrj
230938fd1498Szrj /* Write IPA ICF summary for symbols. */
231038fd1498Szrj
231138fd1498Szrj void
write_summary(void)231238fd1498Szrj sem_item_optimizer::write_summary (void)
231338fd1498Szrj {
231438fd1498Szrj unsigned int count = 0;
231538fd1498Szrj
231638fd1498Szrj output_block *ob = create_output_block (LTO_section_ipa_icf);
231738fd1498Szrj lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
231838fd1498Szrj ob->symbol = NULL;
231938fd1498Szrj
232038fd1498Szrj /* Calculate number of symbols to be serialized. */
232138fd1498Szrj for (lto_symtab_encoder_iterator lsei = lsei_start_in_partition (encoder);
232238fd1498Szrj !lsei_end_p (lsei);
232338fd1498Szrj lsei_next_in_partition (&lsei))
232438fd1498Szrj {
232538fd1498Szrj symtab_node *node = lsei_node (lsei);
232638fd1498Szrj
232738fd1498Szrj if (m_symtab_node_map.get (node))
232838fd1498Szrj count++;
232938fd1498Szrj }
233038fd1498Szrj
233138fd1498Szrj streamer_write_uhwi (ob, count);
233238fd1498Szrj
233338fd1498Szrj /* Process all of the symbols. */
233438fd1498Szrj for (lto_symtab_encoder_iterator lsei = lsei_start_in_partition (encoder);
233538fd1498Szrj !lsei_end_p (lsei);
233638fd1498Szrj lsei_next_in_partition (&lsei))
233738fd1498Szrj {
233838fd1498Szrj symtab_node *node = lsei_node (lsei);
233938fd1498Szrj
234038fd1498Szrj sem_item **item = m_symtab_node_map.get (node);
234138fd1498Szrj
234238fd1498Szrj if (item && *item)
234338fd1498Szrj {
234438fd1498Szrj int node_ref = lto_symtab_encoder_encode (encoder, node);
234538fd1498Szrj streamer_write_uhwi_stream (ob->main_stream, node_ref);
234638fd1498Szrj
234738fd1498Szrj streamer_write_uhwi (ob, (*item)->get_hash ());
234838fd1498Szrj }
234938fd1498Szrj }
235038fd1498Szrj
235138fd1498Szrj streamer_write_char_stream (ob->main_stream, 0);
235238fd1498Szrj produce_asm (ob, NULL);
235338fd1498Szrj destroy_output_block (ob);
235438fd1498Szrj }
235538fd1498Szrj
235638fd1498Szrj /* Reads a section from LTO stream file FILE_DATA. Input block for DATA
235738fd1498Szrj contains LEN bytes. */
235838fd1498Szrj
235938fd1498Szrj void
read_section(lto_file_decl_data * file_data,const char * data,size_t len)236038fd1498Szrj sem_item_optimizer::read_section (lto_file_decl_data *file_data,
236138fd1498Szrj const char *data, size_t len)
236238fd1498Szrj {
236338fd1498Szrj const lto_function_header *header
236438fd1498Szrj = (const lto_function_header *) data;
236538fd1498Szrj const int cfg_offset = sizeof (lto_function_header);
236638fd1498Szrj const int main_offset = cfg_offset + header->cfg_size;
236738fd1498Szrj const int string_offset = main_offset + header->main_size;
236838fd1498Szrj data_in *data_in;
236938fd1498Szrj unsigned int i;
237038fd1498Szrj unsigned int count;
237138fd1498Szrj
237238fd1498Szrj lto_input_block ib_main ((const char *) data + main_offset, 0,
237338fd1498Szrj header->main_size, file_data->mode_table);
237438fd1498Szrj
237538fd1498Szrj data_in
237638fd1498Szrj = lto_data_in_create (file_data, (const char *) data + string_offset,
237738fd1498Szrj header->string_size, vNULL);
237838fd1498Szrj
237938fd1498Szrj count = streamer_read_uhwi (&ib_main);
238038fd1498Szrj
238138fd1498Szrj for (i = 0; i < count; i++)
238238fd1498Szrj {
238338fd1498Szrj unsigned int index;
238438fd1498Szrj symtab_node *node;
238538fd1498Szrj lto_symtab_encoder_t encoder;
238638fd1498Szrj
238738fd1498Szrj index = streamer_read_uhwi (&ib_main);
238838fd1498Szrj encoder = file_data->symtab_node_encoder;
238938fd1498Szrj node = lto_symtab_encoder_deref (encoder, index);
239038fd1498Szrj
239138fd1498Szrj hashval_t hash = streamer_read_uhwi (&ib_main);
239238fd1498Szrj
239338fd1498Szrj gcc_assert (node->definition);
239438fd1498Szrj
239538fd1498Szrj if (dump_file)
239638fd1498Szrj fprintf (dump_file, "Symbol added: %s (tree: %p)\n",
239738fd1498Szrj node->dump_asm_name (), (void *) node->decl);
239838fd1498Szrj
239938fd1498Szrj if (is_a<cgraph_node *> (node))
240038fd1498Szrj {
240138fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
240238fd1498Szrj
240338fd1498Szrj sem_function *fn = new sem_function (cnode, &m_bmstack);
240438fd1498Szrj fn->set_hash (hash);
240538fd1498Szrj m_items.safe_push (fn);
240638fd1498Szrj }
240738fd1498Szrj else
240838fd1498Szrj {
240938fd1498Szrj varpool_node *vnode = dyn_cast <varpool_node *> (node);
241038fd1498Szrj
241138fd1498Szrj sem_variable *var = new sem_variable (vnode, &m_bmstack);
241238fd1498Szrj var->set_hash (hash);
241338fd1498Szrj m_items.safe_push (var);
241438fd1498Szrj }
241538fd1498Szrj }
241638fd1498Szrj
241738fd1498Szrj lto_free_section_data (file_data, LTO_section_ipa_icf, NULL, data,
241838fd1498Szrj len);
241938fd1498Szrj lto_data_in_delete (data_in);
242038fd1498Szrj }
242138fd1498Szrj
242238fd1498Szrj /* Read IPA ICF summary for symbols. */
242338fd1498Szrj
242438fd1498Szrj void
read_summary(void)242538fd1498Szrj sem_item_optimizer::read_summary (void)
242638fd1498Szrj {
242738fd1498Szrj lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
242838fd1498Szrj lto_file_decl_data *file_data;
242938fd1498Szrj unsigned int j = 0;
243038fd1498Szrj
243138fd1498Szrj while ((file_data = file_data_vec[j++]))
243238fd1498Szrj {
243338fd1498Szrj size_t len;
243438fd1498Szrj const char *data = lto_get_section_data (file_data,
243538fd1498Szrj LTO_section_ipa_icf, NULL, &len);
243638fd1498Szrj
243738fd1498Szrj if (data)
243838fd1498Szrj read_section (file_data, data, len);
243938fd1498Szrj }
244038fd1498Szrj }
244138fd1498Szrj
244238fd1498Szrj /* Register callgraph and varpool hooks. */
244338fd1498Szrj
244438fd1498Szrj void
register_hooks(void)244538fd1498Szrj sem_item_optimizer::register_hooks (void)
244638fd1498Szrj {
244738fd1498Szrj if (!m_cgraph_node_hooks)
244838fd1498Szrj m_cgraph_node_hooks = symtab->add_cgraph_removal_hook
244938fd1498Szrj (&sem_item_optimizer::cgraph_removal_hook, this);
245038fd1498Szrj
245138fd1498Szrj if (!m_varpool_node_hooks)
245238fd1498Szrj m_varpool_node_hooks = symtab->add_varpool_removal_hook
245338fd1498Szrj (&sem_item_optimizer::varpool_removal_hook, this);
245438fd1498Szrj }
245538fd1498Szrj
245638fd1498Szrj /* Unregister callgraph and varpool hooks. */
245738fd1498Szrj
245838fd1498Szrj void
unregister_hooks(void)245938fd1498Szrj sem_item_optimizer::unregister_hooks (void)
246038fd1498Szrj {
246138fd1498Szrj if (m_cgraph_node_hooks)
246238fd1498Szrj symtab->remove_cgraph_removal_hook (m_cgraph_node_hooks);
246338fd1498Szrj
246438fd1498Szrj if (m_varpool_node_hooks)
246538fd1498Szrj symtab->remove_varpool_removal_hook (m_varpool_node_hooks);
246638fd1498Szrj }
246738fd1498Szrj
246838fd1498Szrj /* Adds a CLS to hashtable associated by hash value. */
246938fd1498Szrj
247038fd1498Szrj void
add_class(congruence_class * cls)247138fd1498Szrj sem_item_optimizer::add_class (congruence_class *cls)
247238fd1498Szrj {
247338fd1498Szrj gcc_assert (cls->members.length ());
247438fd1498Szrj
247538fd1498Szrj congruence_class_group *group
247638fd1498Szrj = get_group_by_hash (cls->members[0]->get_hash (),
247738fd1498Szrj cls->members[0]->type);
247838fd1498Szrj group->classes.safe_push (cls);
247938fd1498Szrj }
248038fd1498Szrj
248138fd1498Szrj /* Gets a congruence class group based on given HASH value and TYPE. */
248238fd1498Szrj
248338fd1498Szrj congruence_class_group *
get_group_by_hash(hashval_t hash,sem_item_type type)248438fd1498Szrj sem_item_optimizer::get_group_by_hash (hashval_t hash, sem_item_type type)
248538fd1498Szrj {
248638fd1498Szrj congruence_class_group *item = XNEW (congruence_class_group);
248738fd1498Szrj item->hash = hash;
248838fd1498Szrj item->type = type;
248938fd1498Szrj
249038fd1498Szrj congruence_class_group **slot = m_classes.find_slot (item, INSERT);
249138fd1498Szrj
249238fd1498Szrj if (*slot)
249338fd1498Szrj free (item);
249438fd1498Szrj else
249538fd1498Szrj {
249638fd1498Szrj item->classes.create (1);
249738fd1498Szrj *slot = item;
249838fd1498Szrj }
249938fd1498Szrj
250038fd1498Szrj return *slot;
250138fd1498Szrj }
250238fd1498Szrj
250338fd1498Szrj /* Callgraph removal hook called for a NODE with a custom DATA. */
250438fd1498Szrj
250538fd1498Szrj void
cgraph_removal_hook(cgraph_node * node,void * data)250638fd1498Szrj sem_item_optimizer::cgraph_removal_hook (cgraph_node *node, void *data)
250738fd1498Szrj {
250838fd1498Szrj sem_item_optimizer *optimizer = (sem_item_optimizer *) data;
250938fd1498Szrj optimizer->remove_symtab_node (node);
251038fd1498Szrj }
251138fd1498Szrj
251238fd1498Szrj /* Varpool removal hook called for a NODE with a custom DATA. */
251338fd1498Szrj
251438fd1498Szrj void
varpool_removal_hook(varpool_node * node,void * data)251538fd1498Szrj sem_item_optimizer::varpool_removal_hook (varpool_node *node, void *data)
251638fd1498Szrj {
251738fd1498Szrj sem_item_optimizer *optimizer = (sem_item_optimizer *) data;
251838fd1498Szrj optimizer->remove_symtab_node (node);
251938fd1498Szrj }
252038fd1498Szrj
252138fd1498Szrj /* Remove symtab NODE triggered by symtab removal hooks. */
252238fd1498Szrj
252338fd1498Szrj void
remove_symtab_node(symtab_node * node)252438fd1498Szrj sem_item_optimizer::remove_symtab_node (symtab_node *node)
252538fd1498Szrj {
252638fd1498Szrj gcc_assert (!m_classes.elements ());
252738fd1498Szrj
252838fd1498Szrj m_removed_items_set.add (node);
252938fd1498Szrj }
253038fd1498Szrj
253138fd1498Szrj void
remove_item(sem_item * item)253238fd1498Szrj sem_item_optimizer::remove_item (sem_item *item)
253338fd1498Szrj {
253438fd1498Szrj if (m_symtab_node_map.get (item->node))
253538fd1498Szrj m_symtab_node_map.remove (item->node);
253638fd1498Szrj delete item;
253738fd1498Szrj }
253838fd1498Szrj
253938fd1498Szrj /* Removes all callgraph and varpool nodes that are marked by symtab
254038fd1498Szrj as deleted. */
254138fd1498Szrj
254238fd1498Szrj void
filter_removed_items(void)254338fd1498Szrj sem_item_optimizer::filter_removed_items (void)
254438fd1498Szrj {
254538fd1498Szrj auto_vec <sem_item *> filtered;
254638fd1498Szrj
254738fd1498Szrj for (unsigned int i = 0; i < m_items.length(); i++)
254838fd1498Szrj {
254938fd1498Szrj sem_item *item = m_items[i];
255038fd1498Szrj
255138fd1498Szrj if (m_removed_items_set.contains (item->node))
255238fd1498Szrj {
255338fd1498Szrj remove_item (item);
255438fd1498Szrj continue;
255538fd1498Szrj }
255638fd1498Szrj
255738fd1498Szrj if (item->type == FUNC)
255838fd1498Szrj {
255938fd1498Szrj cgraph_node *cnode = static_cast <sem_function *>(item)->get_node ();
256038fd1498Szrj
256138fd1498Szrj if (in_lto_p && (cnode->alias || cnode->body_removed))
256238fd1498Szrj remove_item (item);
256338fd1498Szrj else
256438fd1498Szrj filtered.safe_push (item);
256538fd1498Szrj }
256638fd1498Szrj else /* VAR. */
256738fd1498Szrj {
256838fd1498Szrj if (!flag_ipa_icf_variables)
256938fd1498Szrj remove_item (item);
257038fd1498Szrj else
257138fd1498Szrj {
257238fd1498Szrj /* Filter out non-readonly variables. */
257338fd1498Szrj tree decl = item->decl;
257438fd1498Szrj if (TREE_READONLY (decl))
257538fd1498Szrj filtered.safe_push (item);
257638fd1498Szrj else
257738fd1498Szrj remove_item (item);
257838fd1498Szrj }
257938fd1498Szrj }
258038fd1498Szrj }
258138fd1498Szrj
258238fd1498Szrj /* Clean-up of released semantic items. */
258338fd1498Szrj
258438fd1498Szrj m_items.release ();
258538fd1498Szrj for (unsigned int i = 0; i < filtered.length(); i++)
258638fd1498Szrj m_items.safe_push (filtered[i]);
258738fd1498Szrj }
258838fd1498Szrj
258938fd1498Szrj /* Optimizer entry point which returns true in case it processes
259038fd1498Szrj a merge operation. True is returned if there's a merge operation
259138fd1498Szrj processed. */
259238fd1498Szrj
259338fd1498Szrj bool
execute(void)259438fd1498Szrj sem_item_optimizer::execute (void)
259538fd1498Szrj {
259638fd1498Szrj filter_removed_items ();
259738fd1498Szrj unregister_hooks ();
259838fd1498Szrj
259938fd1498Szrj build_graph ();
260038fd1498Szrj update_hash_by_addr_refs ();
260138fd1498Szrj build_hash_based_classes ();
260238fd1498Szrj
260338fd1498Szrj if (dump_file)
260438fd1498Szrj fprintf (dump_file, "Dump after hash based groups\n");
260538fd1498Szrj dump_cong_classes ();
260638fd1498Szrj
260738fd1498Szrj for (unsigned int i = 0; i < m_items.length(); i++)
260838fd1498Szrj m_items[i]->init_wpa ();
260938fd1498Szrj
261038fd1498Szrj subdivide_classes_by_equality (true);
261138fd1498Szrj
261238fd1498Szrj if (dump_file)
261338fd1498Szrj fprintf (dump_file, "Dump after WPA based types groups\n");
261438fd1498Szrj
261538fd1498Szrj dump_cong_classes ();
261638fd1498Szrj
261738fd1498Szrj process_cong_reduction ();
261838fd1498Szrj checking_verify_classes ();
261938fd1498Szrj
262038fd1498Szrj if (dump_file)
262138fd1498Szrj fprintf (dump_file, "Dump after callgraph-based congruence reduction\n");
262238fd1498Szrj
262338fd1498Szrj dump_cong_classes ();
262438fd1498Szrj
262538fd1498Szrj parse_nonsingleton_classes ();
262638fd1498Szrj subdivide_classes_by_equality ();
262738fd1498Szrj
262838fd1498Szrj if (dump_file)
262938fd1498Szrj fprintf (dump_file, "Dump after full equality comparison of groups\n");
263038fd1498Szrj
263138fd1498Szrj dump_cong_classes ();
263238fd1498Szrj
263338fd1498Szrj unsigned int prev_class_count = m_classes_count;
263438fd1498Szrj
263538fd1498Szrj process_cong_reduction ();
263638fd1498Szrj dump_cong_classes ();
263738fd1498Szrj checking_verify_classes ();
263838fd1498Szrj bool merged_p = merge_classes (prev_class_count);
263938fd1498Szrj
264038fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
264138fd1498Szrj symtab->dump (dump_file);
264238fd1498Szrj
264338fd1498Szrj return merged_p;
264438fd1498Szrj }
264538fd1498Szrj
264638fd1498Szrj /* Function responsible for visiting all potential functions and
264738fd1498Szrj read-only variables that can be merged. */
264838fd1498Szrj
264938fd1498Szrj void
parse_funcs_and_vars(void)265038fd1498Szrj sem_item_optimizer::parse_funcs_and_vars (void)
265138fd1498Szrj {
265238fd1498Szrj cgraph_node *cnode;
265338fd1498Szrj
265438fd1498Szrj if (flag_ipa_icf_functions)
265538fd1498Szrj FOR_EACH_DEFINED_FUNCTION (cnode)
265638fd1498Szrj {
265738fd1498Szrj sem_function *f = sem_function::parse (cnode, &m_bmstack);
265838fd1498Szrj if (f)
265938fd1498Szrj {
266038fd1498Szrj m_items.safe_push (f);
266138fd1498Szrj m_symtab_node_map.put (cnode, f);
266238fd1498Szrj
266338fd1498Szrj if (dump_file)
266438fd1498Szrj fprintf (dump_file, "Parsed function:%s\n", f->node->asm_name ());
266538fd1498Szrj
266638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
266738fd1498Szrj f->dump_to_file (dump_file);
266838fd1498Szrj }
266938fd1498Szrj else if (dump_file)
267038fd1498Szrj fprintf (dump_file, "Not parsed function:%s\n", cnode->asm_name ());
267138fd1498Szrj }
267238fd1498Szrj
267338fd1498Szrj varpool_node *vnode;
267438fd1498Szrj
267538fd1498Szrj if (flag_ipa_icf_variables)
267638fd1498Szrj FOR_EACH_DEFINED_VARIABLE (vnode)
267738fd1498Szrj {
267838fd1498Szrj sem_variable *v = sem_variable::parse (vnode, &m_bmstack);
267938fd1498Szrj
268038fd1498Szrj if (v)
268138fd1498Szrj {
268238fd1498Szrj m_items.safe_push (v);
268338fd1498Szrj m_symtab_node_map.put (vnode, v);
268438fd1498Szrj }
268538fd1498Szrj }
268638fd1498Szrj }
268738fd1498Szrj
268838fd1498Szrj /* Makes pairing between a congruence class CLS and semantic ITEM. */
268938fd1498Szrj
269038fd1498Szrj void
add_item_to_class(congruence_class * cls,sem_item * item)269138fd1498Szrj sem_item_optimizer::add_item_to_class (congruence_class *cls, sem_item *item)
269238fd1498Szrj {
269338fd1498Szrj item->index_in_class = cls->members.length ();
269438fd1498Szrj cls->members.safe_push (item);
269538fd1498Szrj item->cls = cls;
269638fd1498Szrj }
269738fd1498Szrj
269838fd1498Szrj /* For each semantic item, append hash values of references. */
269938fd1498Szrj
270038fd1498Szrj void
update_hash_by_addr_refs()270138fd1498Szrj sem_item_optimizer::update_hash_by_addr_refs ()
270238fd1498Szrj {
270338fd1498Szrj /* First, append to hash sensitive references and class type if it need to
270438fd1498Szrj be matched for ODR. */
270538fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
270638fd1498Szrj {
270738fd1498Szrj m_items[i]->update_hash_by_addr_refs (m_symtab_node_map);
270838fd1498Szrj if (m_items[i]->type == FUNC)
270938fd1498Szrj {
271038fd1498Szrj if (TREE_CODE (TREE_TYPE (m_items[i]->decl)) == METHOD_TYPE
271138fd1498Szrj && contains_polymorphic_type_p
271238fd1498Szrj (TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl)))
271338fd1498Szrj && (DECL_CXX_CONSTRUCTOR_P (m_items[i]->decl)
271438fd1498Szrj || (static_cast<sem_function *> (m_items[i])->param_used_p (0)
271538fd1498Szrj && static_cast<sem_function *> (m_items[i])
271638fd1498Szrj ->compare_polymorphic_p ())))
271738fd1498Szrj {
271838fd1498Szrj tree class_type
271938fd1498Szrj = TYPE_METHOD_BASETYPE (TREE_TYPE (m_items[i]->decl));
272038fd1498Szrj inchash::hash hstate (m_items[i]->get_hash ());
272138fd1498Szrj
272238fd1498Szrj if (TYPE_NAME (class_type)
272338fd1498Szrj && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
272438fd1498Szrj hstate.add_hwi
272538fd1498Szrj (IDENTIFIER_HASH_VALUE
272638fd1498Szrj (DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
272738fd1498Szrj
272838fd1498Szrj m_items[i]->set_hash (hstate.end ());
272938fd1498Szrj }
273038fd1498Szrj }
273138fd1498Szrj }
273238fd1498Szrj
273338fd1498Szrj /* Once all symbols have enhanced hash value, we can append
273438fd1498Szrj hash values of symbols that are seen by IPA ICF and are
273538fd1498Szrj references by a semantic item. Newly computed values
273638fd1498Szrj are saved to global_hash member variable. */
273738fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
273838fd1498Szrj m_items[i]->update_hash_by_local_refs (m_symtab_node_map);
273938fd1498Szrj
274038fd1498Szrj /* Global hash value replace current hash values. */
274138fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
274238fd1498Szrj m_items[i]->set_hash (m_items[i]->global_hash);
274338fd1498Szrj }
274438fd1498Szrj
274538fd1498Szrj /* Congruence classes are built by hash value. */
274638fd1498Szrj
274738fd1498Szrj void
build_hash_based_classes(void)274838fd1498Szrj sem_item_optimizer::build_hash_based_classes (void)
274938fd1498Szrj {
275038fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
275138fd1498Szrj {
275238fd1498Szrj sem_item *item = m_items[i];
275338fd1498Szrj
275438fd1498Szrj congruence_class_group *group
275538fd1498Szrj = get_group_by_hash (item->get_hash (), item->type);
275638fd1498Szrj
275738fd1498Szrj if (!group->classes.length ())
275838fd1498Szrj {
275938fd1498Szrj m_classes_count++;
276038fd1498Szrj group->classes.safe_push (new congruence_class (class_id++));
276138fd1498Szrj }
276238fd1498Szrj
276338fd1498Szrj add_item_to_class (group->classes[0], item);
276438fd1498Szrj }
276538fd1498Szrj }
276638fd1498Szrj
276738fd1498Szrj /* Build references according to call graph. */
276838fd1498Szrj
276938fd1498Szrj void
build_graph(void)277038fd1498Szrj sem_item_optimizer::build_graph (void)
277138fd1498Szrj {
277238fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
277338fd1498Szrj {
277438fd1498Szrj sem_item *item = m_items[i];
277538fd1498Szrj m_symtab_node_map.put (item->node, item);
277638fd1498Szrj
277738fd1498Szrj /* Initialize hash values if we are not in LTO mode. */
277838fd1498Szrj if (!in_lto_p)
277938fd1498Szrj item->get_hash ();
278038fd1498Szrj }
278138fd1498Szrj
278238fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
278338fd1498Szrj {
278438fd1498Szrj sem_item *item = m_items[i];
278538fd1498Szrj
278638fd1498Szrj if (item->type == FUNC)
278738fd1498Szrj {
278838fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (item->node);
278938fd1498Szrj
279038fd1498Szrj cgraph_edge *e = cnode->callees;
279138fd1498Szrj while (e)
279238fd1498Szrj {
279338fd1498Szrj sem_item **slot = m_symtab_node_map.get
279438fd1498Szrj (e->callee->ultimate_alias_target ());
279538fd1498Szrj if (slot)
279638fd1498Szrj item->add_reference (*slot);
279738fd1498Szrj
279838fd1498Szrj e = e->next_callee;
279938fd1498Szrj }
280038fd1498Szrj }
280138fd1498Szrj
280238fd1498Szrj ipa_ref *ref = NULL;
280338fd1498Szrj for (unsigned i = 0; item->node->iterate_reference (i, ref); i++)
280438fd1498Szrj {
280538fd1498Szrj sem_item **slot = m_symtab_node_map.get
280638fd1498Szrj (ref->referred->ultimate_alias_target ());
280738fd1498Szrj if (slot)
280838fd1498Szrj item->add_reference (*slot);
280938fd1498Szrj }
281038fd1498Szrj }
281138fd1498Szrj }
281238fd1498Szrj
281338fd1498Szrj /* Semantic items in classes having more than one element and initialized.
281438fd1498Szrj In case of WPA, we load function body. */
281538fd1498Szrj
281638fd1498Szrj void
parse_nonsingleton_classes(void)281738fd1498Szrj sem_item_optimizer::parse_nonsingleton_classes (void)
281838fd1498Szrj {
281938fd1498Szrj unsigned int init_called_count = 0;
282038fd1498Szrj
282138fd1498Szrj for (unsigned i = 0; i < m_items.length (); i++)
282238fd1498Szrj if (m_items[i]->cls->members.length () > 1)
282338fd1498Szrj {
282438fd1498Szrj m_items[i]->init ();
282538fd1498Szrj init_called_count++;
282638fd1498Szrj }
282738fd1498Szrj
282838fd1498Szrj if (dump_file)
282938fd1498Szrj fprintf (dump_file, "Init called for %u items (%.2f%%).\n",
283038fd1498Szrj init_called_count,
283138fd1498Szrj m_items.length () ? 100.0f * init_called_count / m_items.length ()
283238fd1498Szrj : 0.0f);
283338fd1498Szrj }
283438fd1498Szrj
283538fd1498Szrj /* Equality function for semantic items is used to subdivide existing
283638fd1498Szrj classes. If IN_WPA, fast equality function is invoked. */
283738fd1498Szrj
283838fd1498Szrj void
subdivide_classes_by_equality(bool in_wpa)283938fd1498Szrj sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
284038fd1498Szrj {
284138fd1498Szrj for (hash_table <congruence_class_hash>::iterator it = m_classes.begin ();
284238fd1498Szrj it != m_classes.end (); ++it)
284338fd1498Szrj {
284438fd1498Szrj unsigned int class_count = (*it)->classes.length ();
284538fd1498Szrj
284638fd1498Szrj for (unsigned i = 0; i < class_count; i++)
284738fd1498Szrj {
284838fd1498Szrj congruence_class *c = (*it)->classes[i];
284938fd1498Szrj
285038fd1498Szrj if (c->members.length() > 1)
285138fd1498Szrj {
285238fd1498Szrj auto_vec <sem_item *> new_vector;
285338fd1498Szrj
285438fd1498Szrj sem_item *first = c->members[0];
285538fd1498Szrj new_vector.safe_push (first);
285638fd1498Szrj
285738fd1498Szrj unsigned class_split_first = (*it)->classes.length ();
285838fd1498Szrj
285938fd1498Szrj for (unsigned j = 1; j < c->members.length (); j++)
286038fd1498Szrj {
286138fd1498Szrj sem_item *item = c->members[j];
286238fd1498Szrj
286338fd1498Szrj bool equals
286438fd1498Szrj = in_wpa ? first->equals_wpa (item, m_symtab_node_map)
286538fd1498Szrj : first->equals (item, m_symtab_node_map);
286638fd1498Szrj
286738fd1498Szrj if (equals)
286838fd1498Szrj new_vector.safe_push (item);
286938fd1498Szrj else
287038fd1498Szrj {
287138fd1498Szrj bool integrated = false;
287238fd1498Szrj
287338fd1498Szrj for (unsigned k = class_split_first;
287438fd1498Szrj k < (*it)->classes.length (); k++)
287538fd1498Szrj {
287638fd1498Szrj sem_item *x = (*it)->classes[k]->members[0];
287738fd1498Szrj bool equals
287838fd1498Szrj = in_wpa ? x->equals_wpa (item, m_symtab_node_map)
287938fd1498Szrj : x->equals (item, m_symtab_node_map);
288038fd1498Szrj
288138fd1498Szrj if (equals)
288238fd1498Szrj {
288338fd1498Szrj integrated = true;
288438fd1498Szrj add_item_to_class ((*it)->classes[k], item);
288538fd1498Szrj
288638fd1498Szrj break;
288738fd1498Szrj }
288838fd1498Szrj }
288938fd1498Szrj
289038fd1498Szrj if (!integrated)
289138fd1498Szrj {
289238fd1498Szrj congruence_class *c
289338fd1498Szrj = new congruence_class (class_id++);
289438fd1498Szrj m_classes_count++;
289538fd1498Szrj add_item_to_class (c, item);
289638fd1498Szrj
289738fd1498Szrj (*it)->classes.safe_push (c);
289838fd1498Szrj }
289938fd1498Szrj }
290038fd1498Szrj }
290138fd1498Szrj
290238fd1498Szrj // We replace newly created new_vector for the class we've just
290338fd1498Szrj // splitted.
290438fd1498Szrj c->members.release ();
290538fd1498Szrj c->members.create (new_vector.length ());
290638fd1498Szrj
290738fd1498Szrj for (unsigned int j = 0; j < new_vector.length (); j++)
290838fd1498Szrj add_item_to_class (c, new_vector[j]);
290938fd1498Szrj }
291038fd1498Szrj }
291138fd1498Szrj }
291238fd1498Szrj
291338fd1498Szrj checking_verify_classes ();
291438fd1498Szrj }
291538fd1498Szrj
291638fd1498Szrj /* Subdivide classes by address references that members of the class
291738fd1498Szrj reference. Example can be a pair of functions that have an address
291838fd1498Szrj taken from a function. If these addresses are different the class
291938fd1498Szrj is split. */
292038fd1498Szrj
292138fd1498Szrj unsigned
subdivide_classes_by_sensitive_refs()292238fd1498Szrj sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
292338fd1498Szrj {
292438fd1498Szrj typedef hash_map <symbol_compare_hash, vec <sem_item *> > subdivide_hash_map;
292538fd1498Szrj
292638fd1498Szrj unsigned newly_created_classes = 0;
292738fd1498Szrj
292838fd1498Szrj for (hash_table <congruence_class_hash>::iterator it = m_classes.begin ();
292938fd1498Szrj it != m_classes.end (); ++it)
293038fd1498Szrj {
293138fd1498Szrj unsigned int class_count = (*it)->classes.length ();
293238fd1498Szrj auto_vec<congruence_class *> new_classes;
293338fd1498Szrj
293438fd1498Szrj for (unsigned i = 0; i < class_count; i++)
293538fd1498Szrj {
293638fd1498Szrj congruence_class *c = (*it)->classes[i];
293738fd1498Szrj
293838fd1498Szrj if (c->members.length() > 1)
293938fd1498Szrj {
294038fd1498Szrj subdivide_hash_map split_map;
294138fd1498Szrj
294238fd1498Szrj for (unsigned j = 0; j < c->members.length (); j++)
294338fd1498Szrj {
294438fd1498Szrj sem_item *source_node = c->members[j];
294538fd1498Szrj
294638fd1498Szrj symbol_compare_collection *collection
294738fd1498Szrj = new symbol_compare_collection (source_node->node);
294838fd1498Szrj
294938fd1498Szrj bool existed;
295038fd1498Szrj vec <sem_item *> *slot
295138fd1498Szrj = &split_map.get_or_insert (collection, &existed);
295238fd1498Szrj gcc_checking_assert (slot);
295338fd1498Szrj
295438fd1498Szrj slot->safe_push (source_node);
295538fd1498Szrj
295638fd1498Szrj if (existed)
295738fd1498Szrj delete collection;
295838fd1498Szrj }
295938fd1498Szrj
296038fd1498Szrj /* If the map contains more than one key, we have to split
296138fd1498Szrj the map appropriately. */
296238fd1498Szrj if (split_map.elements () != 1)
296338fd1498Szrj {
296438fd1498Szrj bool first_class = true;
296538fd1498Szrj
296638fd1498Szrj for (subdivide_hash_map::iterator it2 = split_map.begin ();
296738fd1498Szrj it2 != split_map.end (); ++it2)
296838fd1498Szrj {
296938fd1498Szrj congruence_class *new_cls;
297038fd1498Szrj new_cls = new congruence_class (class_id++);
297138fd1498Szrj
297238fd1498Szrj for (unsigned k = 0; k < (*it2).second.length (); k++)
297338fd1498Szrj add_item_to_class (new_cls, (*it2).second[k]);
297438fd1498Szrj
297538fd1498Szrj worklist_push (new_cls);
297638fd1498Szrj newly_created_classes++;
297738fd1498Szrj
297838fd1498Szrj if (first_class)
297938fd1498Szrj {
298038fd1498Szrj (*it)->classes[i] = new_cls;
298138fd1498Szrj first_class = false;
298238fd1498Szrj }
298338fd1498Szrj else
298438fd1498Szrj {
298538fd1498Szrj new_classes.safe_push (new_cls);
298638fd1498Szrj m_classes_count++;
298738fd1498Szrj }
298838fd1498Szrj }
298938fd1498Szrj }
299038fd1498Szrj
299138fd1498Szrj /* Release memory. */
299238fd1498Szrj for (subdivide_hash_map::iterator it2 = split_map.begin ();
299338fd1498Szrj it2 != split_map.end (); ++it2)
299438fd1498Szrj {
299538fd1498Szrj delete (*it2).first;
299638fd1498Szrj (*it2).second.release ();
299738fd1498Szrj }
299838fd1498Szrj }
299938fd1498Szrj }
300038fd1498Szrj
300138fd1498Szrj for (unsigned i = 0; i < new_classes.length (); i++)
300238fd1498Szrj (*it)->classes.safe_push (new_classes[i]);
300338fd1498Szrj }
300438fd1498Szrj
300538fd1498Szrj return newly_created_classes;
300638fd1498Szrj }
300738fd1498Szrj
300838fd1498Szrj /* Verify congruence classes, if checking is enabled. */
300938fd1498Szrj
301038fd1498Szrj void
checking_verify_classes(void)301138fd1498Szrj sem_item_optimizer::checking_verify_classes (void)
301238fd1498Szrj {
301338fd1498Szrj if (flag_checking)
301438fd1498Szrj verify_classes ();
301538fd1498Szrj }
301638fd1498Szrj
301738fd1498Szrj /* Verify congruence classes. */
301838fd1498Szrj
301938fd1498Szrj void
verify_classes(void)302038fd1498Szrj sem_item_optimizer::verify_classes (void)
302138fd1498Szrj {
302238fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
302338fd1498Szrj it != m_classes.end (); ++it)
302438fd1498Szrj {
302538fd1498Szrj for (unsigned int i = 0; i < (*it)->classes.length (); i++)
302638fd1498Szrj {
302738fd1498Szrj congruence_class *cls = (*it)->classes[i];
302838fd1498Szrj
302938fd1498Szrj gcc_assert (cls);
303038fd1498Szrj gcc_assert (cls->members.length () > 0);
303138fd1498Szrj
303238fd1498Szrj for (unsigned int j = 0; j < cls->members.length (); j++)
303338fd1498Szrj {
303438fd1498Szrj sem_item *item = cls->members[j];
303538fd1498Szrj
303638fd1498Szrj gcc_assert (item);
303738fd1498Szrj gcc_assert (item->cls == cls);
303838fd1498Szrj
303938fd1498Szrj for (unsigned k = 0; k < item->usages.length (); k++)
304038fd1498Szrj {
304138fd1498Szrj sem_usage_pair *usage = item->usages[k];
304238fd1498Szrj gcc_assert (usage->item->index_in_class
304338fd1498Szrj < usage->item->cls->members.length ());
304438fd1498Szrj }
304538fd1498Szrj }
304638fd1498Szrj }
304738fd1498Szrj }
304838fd1498Szrj }
304938fd1498Szrj
305038fd1498Szrj /* Disposes split map traverse function. CLS_PTR is pointer to congruence
305138fd1498Szrj class, BSLOT is bitmap slot we want to release. DATA is mandatory,
305238fd1498Szrj but unused argument. */
305338fd1498Szrj
305438fd1498Szrj bool
release_split_map(congruence_class * const &,bitmap const & b,traverse_split_pair *)305538fd1498Szrj sem_item_optimizer::release_split_map (congruence_class * const &,
305638fd1498Szrj bitmap const &b, traverse_split_pair *)
305738fd1498Szrj {
305838fd1498Szrj bitmap bmp = b;
305938fd1498Szrj
306038fd1498Szrj BITMAP_FREE (bmp);
306138fd1498Szrj
306238fd1498Szrj return true;
306338fd1498Szrj }
306438fd1498Szrj
306538fd1498Szrj /* Process split operation for a class given as pointer CLS_PTR,
306638fd1498Szrj where bitmap B splits congruence class members. DATA is used
306738fd1498Szrj as argument of split pair. */
306838fd1498Szrj
306938fd1498Szrj bool
traverse_congruence_split(congruence_class * const & cls,bitmap const & b,traverse_split_pair * pair)307038fd1498Szrj sem_item_optimizer::traverse_congruence_split (congruence_class * const &cls,
307138fd1498Szrj bitmap const &b,
307238fd1498Szrj traverse_split_pair *pair)
307338fd1498Szrj {
307438fd1498Szrj sem_item_optimizer *optimizer = pair->optimizer;
307538fd1498Szrj const congruence_class *splitter_cls = pair->cls;
307638fd1498Szrj
307738fd1498Szrj /* If counted bits are greater than zero and less than the number of members
307838fd1498Szrj a group will be splitted. */
307938fd1498Szrj unsigned popcount = bitmap_count_bits (b);
308038fd1498Szrj
308138fd1498Szrj if (popcount > 0 && popcount < cls->members.length ())
308238fd1498Szrj {
308338fd1498Szrj auto_vec <congruence_class *, 2> newclasses;
308438fd1498Szrj newclasses.quick_push (new congruence_class (class_id++));
308538fd1498Szrj newclasses.quick_push (new congruence_class (class_id++));
308638fd1498Szrj
308738fd1498Szrj for (unsigned int i = 0; i < cls->members.length (); i++)
308838fd1498Szrj {
308938fd1498Szrj int target = bitmap_bit_p (b, i);
309038fd1498Szrj congruence_class *tc = newclasses[target];
309138fd1498Szrj
309238fd1498Szrj add_item_to_class (tc, cls->members[i]);
309338fd1498Szrj }
309438fd1498Szrj
309538fd1498Szrj if (flag_checking)
309638fd1498Szrj {
309738fd1498Szrj for (unsigned int i = 0; i < 2; i++)
309838fd1498Szrj gcc_assert (newclasses[i]->members.length ());
309938fd1498Szrj }
310038fd1498Szrj
310138fd1498Szrj if (splitter_cls == cls)
310238fd1498Szrj optimizer->splitter_class_removed = true;
310338fd1498Szrj
310438fd1498Szrj /* Remove old class from worklist if presented. */
310538fd1498Szrj bool in_worklist = cls->in_worklist;
310638fd1498Szrj
310738fd1498Szrj if (in_worklist)
310838fd1498Szrj cls->in_worklist = false;
310938fd1498Szrj
311038fd1498Szrj congruence_class_group g;
311138fd1498Szrj g.hash = cls->members[0]->get_hash ();
311238fd1498Szrj g.type = cls->members[0]->type;
311338fd1498Szrj
311438fd1498Szrj congruence_class_group *slot = optimizer->m_classes.find (&g);
311538fd1498Szrj
311638fd1498Szrj for (unsigned int i = 0; i < slot->classes.length (); i++)
311738fd1498Szrj if (slot->classes[i] == cls)
311838fd1498Szrj {
311938fd1498Szrj slot->classes.ordered_remove (i);
312038fd1498Szrj break;
312138fd1498Szrj }
312238fd1498Szrj
312338fd1498Szrj /* New class will be inserted and integrated to work list. */
312438fd1498Szrj for (unsigned int i = 0; i < 2; i++)
312538fd1498Szrj optimizer->add_class (newclasses[i]);
312638fd1498Szrj
312738fd1498Szrj /* Two classes replace one, so that increment just by one. */
312838fd1498Szrj optimizer->m_classes_count++;
312938fd1498Szrj
313038fd1498Szrj /* If OLD class was presented in the worklist, we remove the class
313138fd1498Szrj and replace it will both newly created classes. */
313238fd1498Szrj if (in_worklist)
313338fd1498Szrj for (unsigned int i = 0; i < 2; i++)
313438fd1498Szrj optimizer->worklist_push (newclasses[i]);
313538fd1498Szrj else /* Just smaller class is inserted. */
313638fd1498Szrj {
313738fd1498Szrj unsigned int smaller_index
313838fd1498Szrj = (newclasses[0]->members.length ()
313938fd1498Szrj < newclasses[1]->members.length ()
314038fd1498Szrj ? 0 : 1);
314138fd1498Szrj optimizer->worklist_push (newclasses[smaller_index]);
314238fd1498Szrj }
314338fd1498Szrj
314438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
314538fd1498Szrj {
314638fd1498Szrj fprintf (dump_file, " congruence class splitted:\n");
314738fd1498Szrj cls->dump (dump_file, 4);
314838fd1498Szrj
314938fd1498Szrj fprintf (dump_file, " newly created groups:\n");
315038fd1498Szrj for (unsigned int i = 0; i < 2; i++)
315138fd1498Szrj newclasses[i]->dump (dump_file, 4);
315238fd1498Szrj }
315338fd1498Szrj
315438fd1498Szrj /* Release class if not presented in work list. */
315538fd1498Szrj if (!in_worklist)
315638fd1498Szrj delete cls;
315738fd1498Szrj }
315838fd1498Szrj
315938fd1498Szrj
316038fd1498Szrj return true;
316138fd1498Szrj }
316238fd1498Szrj
3163*58e805e6Szrj /* Compare function for sorting pairs in do_congruence_step_f. */
3164*58e805e6Szrj
3165*58e805e6Szrj int
sort_congruence_split(const void * a_,const void * b_)3166*58e805e6Szrj sem_item_optimizer::sort_congruence_split (const void *a_, const void *b_)
3167*58e805e6Szrj {
3168*58e805e6Szrj const std::pair<congruence_class *, bitmap> *a
3169*58e805e6Szrj = (const std::pair<congruence_class *, bitmap> *)a_;
3170*58e805e6Szrj const std::pair<congruence_class *, bitmap> *b
3171*58e805e6Szrj = (const std::pair<congruence_class *, bitmap> *)b_;
3172*58e805e6Szrj if (a->first->id < b->first->id)
3173*58e805e6Szrj return -1;
3174*58e805e6Szrj else if (a->first->id > b->first->id)
3175*58e805e6Szrj return 1;
3176*58e805e6Szrj return 0;
3177*58e805e6Szrj }
3178*58e805e6Szrj
317938fd1498Szrj /* Tests if a class CLS used as INDEXth splits any congruence classes.
318038fd1498Szrj Bitmap stack BMSTACK is used for bitmap allocation. */
318138fd1498Szrj
318238fd1498Szrj void
do_congruence_step_for_index(congruence_class * cls,unsigned int index)318338fd1498Szrj sem_item_optimizer::do_congruence_step_for_index (congruence_class *cls,
318438fd1498Szrj unsigned int index)
318538fd1498Szrj {
318638fd1498Szrj hash_map <congruence_class *, bitmap> split_map;
318738fd1498Szrj
318838fd1498Szrj for (unsigned int i = 0; i < cls->members.length (); i++)
318938fd1498Szrj {
319038fd1498Szrj sem_item *item = cls->members[i];
319138fd1498Szrj
319238fd1498Szrj /* Iterate all usages that have INDEX as usage of the item. */
319338fd1498Szrj for (unsigned int j = 0; j < item->usages.length (); j++)
319438fd1498Szrj {
319538fd1498Szrj sem_usage_pair *usage = item->usages[j];
319638fd1498Szrj
319738fd1498Szrj if (usage->index != index)
319838fd1498Szrj continue;
319938fd1498Szrj
320038fd1498Szrj bitmap *slot = split_map.get (usage->item->cls);
320138fd1498Szrj bitmap b;
320238fd1498Szrj
320338fd1498Szrj if(!slot)
320438fd1498Szrj {
320538fd1498Szrj b = BITMAP_ALLOC (&m_bmstack);
320638fd1498Szrj split_map.put (usage->item->cls, b);
320738fd1498Szrj }
320838fd1498Szrj else
320938fd1498Szrj b = *slot;
321038fd1498Szrj
321138fd1498Szrj gcc_checking_assert (usage->item->cls);
321238fd1498Szrj gcc_checking_assert (usage->item->index_in_class
321338fd1498Szrj < usage->item->cls->members.length ());
321438fd1498Szrj
321538fd1498Szrj bitmap_set_bit (b, usage->item->index_in_class);
321638fd1498Szrj }
321738fd1498Szrj }
321838fd1498Szrj
3219*58e805e6Szrj auto_vec<std::pair<congruence_class *, bitmap> > to_split;
3220*58e805e6Szrj to_split.reserve_exact (split_map.elements ());
3221*58e805e6Szrj for (hash_map <congruence_class *, bitmap>::iterator i = split_map.begin ();
3222*58e805e6Szrj i != split_map.end (); ++i)
3223*58e805e6Szrj to_split.safe_push (*i);
3224*58e805e6Szrj to_split.qsort (sort_congruence_split);
3225*58e805e6Szrj
322638fd1498Szrj traverse_split_pair pair;
322738fd1498Szrj pair.optimizer = this;
322838fd1498Szrj pair.cls = cls;
322938fd1498Szrj
323038fd1498Szrj splitter_class_removed = false;
3231*58e805e6Szrj for (unsigned i = 0; i < to_split.length (); ++i)
3232*58e805e6Szrj traverse_congruence_split (to_split[i].first, to_split[i].second, &pair);
323338fd1498Szrj
323438fd1498Szrj /* Bitmap clean-up. */
323538fd1498Szrj split_map.traverse <traverse_split_pair *,
323638fd1498Szrj sem_item_optimizer::release_split_map> (NULL);
323738fd1498Szrj }
323838fd1498Szrj
323938fd1498Szrj /* Every usage of a congruence class CLS is a candidate that can split the
324038fd1498Szrj collection of classes. Bitmap stack BMSTACK is used for bitmap
324138fd1498Szrj allocation. */
324238fd1498Szrj
324338fd1498Szrj void
do_congruence_step(congruence_class * cls)324438fd1498Szrj sem_item_optimizer::do_congruence_step (congruence_class *cls)
324538fd1498Szrj {
324638fd1498Szrj bitmap_iterator bi;
324738fd1498Szrj unsigned int i;
324838fd1498Szrj
324938fd1498Szrj bitmap usage = BITMAP_ALLOC (&m_bmstack);
325038fd1498Szrj
325138fd1498Szrj for (unsigned int i = 0; i < cls->members.length (); i++)
325238fd1498Szrj bitmap_ior_into (usage, cls->members[i]->usage_index_bitmap);
325338fd1498Szrj
325438fd1498Szrj EXECUTE_IF_SET_IN_BITMAP (usage, 0, i, bi)
325538fd1498Szrj {
325638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
325738fd1498Szrj fprintf (dump_file, " processing congruence step for class: %u, "
325838fd1498Szrj "index: %u\n", cls->id, i);
325938fd1498Szrj
326038fd1498Szrj do_congruence_step_for_index (cls, i);
326138fd1498Szrj
326238fd1498Szrj if (splitter_class_removed)
326338fd1498Szrj break;
326438fd1498Szrj }
326538fd1498Szrj
326638fd1498Szrj BITMAP_FREE (usage);
326738fd1498Szrj }
326838fd1498Szrj
326938fd1498Szrj /* Adds a newly created congruence class CLS to worklist. */
327038fd1498Szrj
327138fd1498Szrj void
worklist_push(congruence_class * cls)327238fd1498Szrj sem_item_optimizer::worklist_push (congruence_class *cls)
327338fd1498Szrj {
327438fd1498Szrj /* Return if the class CLS is already presented in work list. */
327538fd1498Szrj if (cls->in_worklist)
327638fd1498Szrj return;
327738fd1498Szrj
327838fd1498Szrj cls->in_worklist = true;
327938fd1498Szrj worklist.push_back (cls);
328038fd1498Szrj }
328138fd1498Szrj
328238fd1498Szrj /* Pops a class from worklist. */
328338fd1498Szrj
328438fd1498Szrj congruence_class *
worklist_pop(void)328538fd1498Szrj sem_item_optimizer::worklist_pop (void)
328638fd1498Szrj {
328738fd1498Szrj congruence_class *cls;
328838fd1498Szrj
328938fd1498Szrj while (!worklist.empty ())
329038fd1498Szrj {
329138fd1498Szrj cls = worklist.front ();
329238fd1498Szrj worklist.pop_front ();
329338fd1498Szrj if (cls->in_worklist)
329438fd1498Szrj {
329538fd1498Szrj cls->in_worklist = false;
329638fd1498Szrj
329738fd1498Szrj return cls;
329838fd1498Szrj }
329938fd1498Szrj else
330038fd1498Szrj {
330138fd1498Szrj /* Work list item was already intended to be removed.
330238fd1498Szrj The only reason for doing it is to split a class.
330338fd1498Szrj Thus, the class CLS is deleted. */
330438fd1498Szrj delete cls;
330538fd1498Szrj }
330638fd1498Szrj }
330738fd1498Szrj
330838fd1498Szrj return NULL;
330938fd1498Szrj }
331038fd1498Szrj
331138fd1498Szrj /* Iterative congruence reduction function. */
331238fd1498Szrj
331338fd1498Szrj void
process_cong_reduction(void)331438fd1498Szrj sem_item_optimizer::process_cong_reduction (void)
331538fd1498Szrj {
331638fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
331738fd1498Szrj it != m_classes.end (); ++it)
331838fd1498Szrj for (unsigned i = 0; i < (*it)->classes.length (); i++)
331938fd1498Szrj if ((*it)->classes[i]->is_class_used ())
332038fd1498Szrj worklist_push ((*it)->classes[i]);
332138fd1498Szrj
332238fd1498Szrj if (dump_file)
332338fd1498Szrj fprintf (dump_file, "Worklist has been filled with: %lu\n",
332438fd1498Szrj (unsigned long) worklist.size ());
332538fd1498Szrj
332638fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
332738fd1498Szrj fprintf (dump_file, "Congruence class reduction\n");
332838fd1498Szrj
332938fd1498Szrj congruence_class *cls;
333038fd1498Szrj
333138fd1498Szrj /* Process complete congruence reduction. */
333238fd1498Szrj while ((cls = worklist_pop ()) != NULL)
333338fd1498Szrj do_congruence_step (cls);
333438fd1498Szrj
333538fd1498Szrj /* Subdivide newly created classes according to references. */
333638fd1498Szrj unsigned new_classes = subdivide_classes_by_sensitive_refs ();
333738fd1498Szrj
333838fd1498Szrj if (dump_file)
333938fd1498Szrj fprintf (dump_file, "Address reference subdivision created: %u "
334038fd1498Szrj "new classes.\n", new_classes);
334138fd1498Szrj }
334238fd1498Szrj
334338fd1498Szrj /* Debug function prints all informations about congruence classes. */
334438fd1498Szrj
334538fd1498Szrj void
dump_cong_classes(void)334638fd1498Szrj sem_item_optimizer::dump_cong_classes (void)
334738fd1498Szrj {
334838fd1498Szrj if (!dump_file)
334938fd1498Szrj return;
335038fd1498Szrj
335138fd1498Szrj fprintf (dump_file,
335238fd1498Szrj "Congruence classes: %u (unique hash values: %lu), with total: "
335338fd1498Szrj "%u items\n", m_classes_count,
335438fd1498Szrj (unsigned long) m_classes.elements (), m_items.length ());
335538fd1498Szrj
335638fd1498Szrj /* Histogram calculation. */
335738fd1498Szrj unsigned int max_index = 0;
335838fd1498Szrj unsigned int* histogram = XCNEWVEC (unsigned int, m_items.length () + 1);
335938fd1498Szrj
336038fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
336138fd1498Szrj it != m_classes.end (); ++it)
336238fd1498Szrj for (unsigned i = 0; i < (*it)->classes.length (); i++)
336338fd1498Szrj {
336438fd1498Szrj unsigned int c = (*it)->classes[i]->members.length ();
336538fd1498Szrj histogram[c]++;
336638fd1498Szrj
336738fd1498Szrj if (c > max_index)
336838fd1498Szrj max_index = c;
336938fd1498Szrj }
337038fd1498Szrj
337138fd1498Szrj fprintf (dump_file,
337238fd1498Szrj "Class size histogram [num of members]: number of classe number "
337338fd1498Szrj "of classess\n");
337438fd1498Szrj
337538fd1498Szrj for (unsigned int i = 0; i <= max_index; i++)
337638fd1498Szrj if (histogram[i])
337738fd1498Szrj fprintf (dump_file, "[%u]: %u classes\n", i, histogram[i]);
337838fd1498Szrj
337938fd1498Szrj fprintf (dump_file, "\n\n");
338038fd1498Szrj
338138fd1498Szrj if (dump_flags & TDF_DETAILS)
338238fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
338338fd1498Szrj it != m_classes.end (); ++it)
338438fd1498Szrj {
338538fd1498Szrj fprintf (dump_file, " group: with %u classes:\n",
338638fd1498Szrj (*it)->classes.length ());
338738fd1498Szrj
338838fd1498Szrj for (unsigned i = 0; i < (*it)->classes.length (); i++)
338938fd1498Szrj {
339038fd1498Szrj (*it)->classes[i]->dump (dump_file, 4);
339138fd1498Szrj
339238fd1498Szrj if (i < (*it)->classes.length () - 1)
339338fd1498Szrj fprintf (dump_file, " ");
339438fd1498Szrj }
339538fd1498Szrj }
339638fd1498Szrj
339738fd1498Szrj free (histogram);
339838fd1498Szrj }
339938fd1498Szrj
340038fd1498Szrj /* Sort pair of sem_items A and B by DECL_UID. */
340138fd1498Szrj
340238fd1498Szrj static int
sort_sem_items_by_decl_uid(const void * a,const void * b)340338fd1498Szrj sort_sem_items_by_decl_uid (const void *a, const void *b)
340438fd1498Szrj {
340538fd1498Szrj const sem_item *i1 = *(const sem_item * const *)a;
340638fd1498Szrj const sem_item *i2 = *(const sem_item * const *)b;
340738fd1498Szrj
340838fd1498Szrj int uid1 = DECL_UID (i1->decl);
340938fd1498Szrj int uid2 = DECL_UID (i2->decl);
341038fd1498Szrj
341138fd1498Szrj if (uid1 < uid2)
341238fd1498Szrj return -1;
341338fd1498Szrj else if (uid1 > uid2)
341438fd1498Szrj return 1;
341538fd1498Szrj else
341638fd1498Szrj return 0;
341738fd1498Szrj }
341838fd1498Szrj
341938fd1498Szrj /* Sort pair of congruence_classes A and B by DECL_UID of the first member. */
342038fd1498Szrj
342138fd1498Szrj static int
sort_congruence_classes_by_decl_uid(const void * a,const void * b)342238fd1498Szrj sort_congruence_classes_by_decl_uid (const void *a, const void *b)
342338fd1498Szrj {
342438fd1498Szrj const congruence_class *c1 = *(const congruence_class * const *)a;
342538fd1498Szrj const congruence_class *c2 = *(const congruence_class * const *)b;
342638fd1498Szrj
342738fd1498Szrj int uid1 = DECL_UID (c1->members[0]->decl);
342838fd1498Szrj int uid2 = DECL_UID (c2->members[0]->decl);
342938fd1498Szrj
343038fd1498Szrj if (uid1 < uid2)
343138fd1498Szrj return -1;
343238fd1498Szrj else if (uid1 > uid2)
343338fd1498Szrj return 1;
343438fd1498Szrj else
343538fd1498Szrj return 0;
343638fd1498Szrj }
343738fd1498Szrj
343838fd1498Szrj /* Sort pair of congruence_class_groups A and B by
343938fd1498Szrj DECL_UID of the first member of a first group. */
344038fd1498Szrj
344138fd1498Szrj static int
sort_congruence_class_groups_by_decl_uid(const void * a,const void * b)344238fd1498Szrj sort_congruence_class_groups_by_decl_uid (const void *a, const void *b)
344338fd1498Szrj {
344438fd1498Szrj const congruence_class_group *g1
344538fd1498Szrj = *(const congruence_class_group * const *)a;
344638fd1498Szrj const congruence_class_group *g2
344738fd1498Szrj = *(const congruence_class_group * const *)b;
344838fd1498Szrj
344938fd1498Szrj int uid1 = DECL_UID (g1->classes[0]->members[0]->decl);
345038fd1498Szrj int uid2 = DECL_UID (g2->classes[0]->members[0]->decl);
345138fd1498Szrj
345238fd1498Szrj if (uid1 < uid2)
345338fd1498Szrj return -1;
345438fd1498Szrj else if (uid1 > uid2)
345538fd1498Szrj return 1;
345638fd1498Szrj else
345738fd1498Szrj return 0;
345838fd1498Szrj }
345938fd1498Szrj
346038fd1498Szrj /* After reduction is done, we can declare all items in a group
346138fd1498Szrj to be equal. PREV_CLASS_COUNT is start number of classes
346238fd1498Szrj before reduction. True is returned if there's a merge operation
346338fd1498Szrj processed. */
346438fd1498Szrj
346538fd1498Szrj bool
merge_classes(unsigned int prev_class_count)346638fd1498Szrj sem_item_optimizer::merge_classes (unsigned int prev_class_count)
346738fd1498Szrj {
346838fd1498Szrj unsigned int item_count = m_items.length ();
346938fd1498Szrj unsigned int class_count = m_classes_count;
347038fd1498Szrj unsigned int equal_items = item_count - class_count;
347138fd1498Szrj
347238fd1498Szrj unsigned int non_singular_classes_count = 0;
347338fd1498Szrj unsigned int non_singular_classes_sum = 0;
347438fd1498Szrj
347538fd1498Szrj bool merged_p = false;
347638fd1498Szrj
347738fd1498Szrj /* PR lto/78211
347838fd1498Szrj Sort functions in congruence classes by DECL_UID and do the same
347938fd1498Szrj for the classes to not to break -fcompare-debug. */
348038fd1498Szrj
348138fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
348238fd1498Szrj it != m_classes.end (); ++it)
348338fd1498Szrj {
348438fd1498Szrj for (unsigned int i = 0; i < (*it)->classes.length (); i++)
348538fd1498Szrj {
348638fd1498Szrj congruence_class *c = (*it)->classes[i];
348738fd1498Szrj c->members.qsort (sort_sem_items_by_decl_uid);
348838fd1498Szrj }
348938fd1498Szrj
349038fd1498Szrj (*it)->classes.qsort (sort_congruence_classes_by_decl_uid);
349138fd1498Szrj }
349238fd1498Szrj
349338fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
349438fd1498Szrj it != m_classes.end (); ++it)
349538fd1498Szrj for (unsigned int i = 0; i < (*it)->classes.length (); i++)
349638fd1498Szrj {
349738fd1498Szrj congruence_class *c = (*it)->classes[i];
349838fd1498Szrj if (c->members.length () > 1)
349938fd1498Szrj {
350038fd1498Szrj non_singular_classes_count++;
350138fd1498Szrj non_singular_classes_sum += c->members.length ();
350238fd1498Szrj }
350338fd1498Szrj }
350438fd1498Szrj
350538fd1498Szrj auto_vec <congruence_class_group *> classes (m_classes.elements ());
350638fd1498Szrj for (hash_table<congruence_class_hash>::iterator it = m_classes.begin ();
350738fd1498Szrj it != m_classes.end (); ++it)
350838fd1498Szrj classes.quick_push (*it);
350938fd1498Szrj
351038fd1498Szrj classes.qsort (sort_congruence_class_groups_by_decl_uid);
351138fd1498Szrj
351238fd1498Szrj if (dump_file)
351338fd1498Szrj {
351438fd1498Szrj fprintf (dump_file, "\nItem count: %u\n", item_count);
351538fd1498Szrj fprintf (dump_file, "Congruent classes before: %u, after: %u\n",
351638fd1498Szrj prev_class_count, class_count);
351738fd1498Szrj fprintf (dump_file, "Average class size before: %.2f, after: %.2f\n",
351838fd1498Szrj prev_class_count ? 1.0f * item_count / prev_class_count : 0.0f,
351938fd1498Szrj class_count ? 1.0f * item_count / class_count : 0.0f);
352038fd1498Szrj fprintf (dump_file, "Average non-singular class size: %.2f, count: %u\n",
352138fd1498Szrj non_singular_classes_count ? 1.0f * non_singular_classes_sum /
352238fd1498Szrj non_singular_classes_count : 0.0f,
352338fd1498Szrj non_singular_classes_count);
352438fd1498Szrj fprintf (dump_file, "Equal symbols: %u\n", equal_items);
352538fd1498Szrj fprintf (dump_file, "Fraction of visited symbols: %.2f%%\n\n",
352638fd1498Szrj item_count ? 100.0f * equal_items / item_count : 0.0f);
352738fd1498Szrj }
352838fd1498Szrj
352938fd1498Szrj unsigned int l;
353038fd1498Szrj congruence_class_group *it;
353138fd1498Szrj FOR_EACH_VEC_ELT (classes, l, it)
353238fd1498Szrj for (unsigned int i = 0; i < it->classes.length (); i++)
353338fd1498Szrj {
353438fd1498Szrj congruence_class *c = it->classes[i];
353538fd1498Szrj
353638fd1498Szrj if (c->members.length () == 1)
353738fd1498Szrj continue;
353838fd1498Szrj
353938fd1498Szrj sem_item *source = c->members[0];
354038fd1498Szrj
354138fd1498Szrj if (DECL_NAME (source->decl)
354238fd1498Szrj && MAIN_NAME_P (DECL_NAME (source->decl)))
354338fd1498Szrj /* If merge via wrappers, picking main as the target can be
354438fd1498Szrj problematic. */
354538fd1498Szrj source = c->members[1];
354638fd1498Szrj
354738fd1498Szrj for (unsigned int j = 0; j < c->members.length (); j++)
354838fd1498Szrj {
354938fd1498Szrj sem_item *alias = c->members[j];
355038fd1498Szrj
355138fd1498Szrj if (alias == source)
355238fd1498Szrj continue;
355338fd1498Szrj
355438fd1498Szrj if (dump_file)
355538fd1498Szrj {
355638fd1498Szrj fprintf (dump_file, "Semantic equality hit:%s->%s\n",
355738fd1498Szrj xstrdup_for_dump (source->node->name ()),
355838fd1498Szrj xstrdup_for_dump (alias->node->name ()));
355938fd1498Szrj fprintf (dump_file, "Assembler symbol names:%s->%s\n",
356038fd1498Szrj xstrdup_for_dump (source->node->asm_name ()),
356138fd1498Szrj xstrdup_for_dump (alias->node->asm_name ()));
356238fd1498Szrj }
356338fd1498Szrj
356438fd1498Szrj if (lookup_attribute ("no_icf", DECL_ATTRIBUTES (alias->decl)))
356538fd1498Szrj {
356638fd1498Szrj if (dump_file)
356738fd1498Szrj fprintf (dump_file,
356838fd1498Szrj "Merge operation is skipped due to no_icf "
356938fd1498Szrj "attribute.\n\n");
357038fd1498Szrj
357138fd1498Szrj continue;
357238fd1498Szrj }
357338fd1498Szrj
357438fd1498Szrj if (dump_file && (dump_flags & TDF_DETAILS))
357538fd1498Szrj {
357638fd1498Szrj source->dump_to_file (dump_file);
357738fd1498Szrj alias->dump_to_file (dump_file);
357838fd1498Szrj }
357938fd1498Szrj
358038fd1498Szrj if (dbg_cnt (merged_ipa_icf))
358138fd1498Szrj {
358238fd1498Szrj bool merged = source->merge (alias);
358338fd1498Szrj merged_p |= merged;
358438fd1498Szrj
358538fd1498Szrj if (merged && alias->type == VAR)
358638fd1498Szrj {
358738fd1498Szrj symtab_pair p = symtab_pair (source->node, alias->node);
358838fd1498Szrj m_merged_variables.safe_push (p);
358938fd1498Szrj }
359038fd1498Szrj }
359138fd1498Szrj }
359238fd1498Szrj }
359338fd1498Szrj
359438fd1498Szrj if (!m_merged_variables.is_empty ())
359538fd1498Szrj fixup_points_to_sets ();
359638fd1498Szrj
359738fd1498Szrj return merged_p;
359838fd1498Szrj }
359938fd1498Szrj
360038fd1498Szrj /* Fixup points to set PT. */
360138fd1498Szrj
360238fd1498Szrj void
fixup_pt_set(struct pt_solution * pt)360338fd1498Szrj sem_item_optimizer::fixup_pt_set (struct pt_solution *pt)
360438fd1498Szrj {
360538fd1498Szrj if (pt->vars == NULL)
360638fd1498Szrj return;
360738fd1498Szrj
360838fd1498Szrj unsigned i;
360938fd1498Szrj symtab_pair *item;
361038fd1498Szrj FOR_EACH_VEC_ELT (m_merged_variables, i, item)
361138fd1498Szrj if (bitmap_bit_p (pt->vars, DECL_UID (item->second->decl)))
361238fd1498Szrj bitmap_set_bit (pt->vars, DECL_UID (item->first->decl));
361338fd1498Szrj }
361438fd1498Szrj
361538fd1498Szrj /* Set all points-to UIDs of aliases pointing to node N as UID. */
361638fd1498Szrj
361738fd1498Szrj static void
set_alias_uids(symtab_node * n,int uid)361838fd1498Szrj set_alias_uids (symtab_node *n, int uid)
361938fd1498Szrj {
362038fd1498Szrj ipa_ref *ref;
362138fd1498Szrj FOR_EACH_ALIAS (n, ref)
362238fd1498Szrj {
362338fd1498Szrj if (dump_file)
362438fd1498Szrj fprintf (dump_file, " Setting points-to UID of [%s] as %d\n",
362538fd1498Szrj xstrdup_for_dump (ref->referring->asm_name ()), uid);
362638fd1498Szrj
362738fd1498Szrj SET_DECL_PT_UID (ref->referring->decl, uid);
362838fd1498Szrj set_alias_uids (ref->referring, uid);
362938fd1498Szrj }
363038fd1498Szrj }
363138fd1498Szrj
363238fd1498Szrj /* Fixup points to analysis info. */
363338fd1498Szrj
363438fd1498Szrj void
fixup_points_to_sets(void)363538fd1498Szrj sem_item_optimizer::fixup_points_to_sets (void)
363638fd1498Szrj {
363738fd1498Szrj /* TODO: remove in GCC 9 and trigger PTA re-creation after IPA passes. */
363838fd1498Szrj cgraph_node *cnode;
363938fd1498Szrj
364038fd1498Szrj FOR_EACH_DEFINED_FUNCTION (cnode)
364138fd1498Szrj {
364238fd1498Szrj tree name;
364338fd1498Szrj unsigned i;
364438fd1498Szrj function *fn = DECL_STRUCT_FUNCTION (cnode->decl);
364538fd1498Szrj if (!gimple_in_ssa_p (fn))
364638fd1498Szrj continue;
364738fd1498Szrj
364838fd1498Szrj FOR_EACH_SSA_NAME (i, name, fn)
364938fd1498Szrj if (POINTER_TYPE_P (TREE_TYPE (name))
365038fd1498Szrj && SSA_NAME_PTR_INFO (name))
365138fd1498Szrj fixup_pt_set (&SSA_NAME_PTR_INFO (name)->pt);
365238fd1498Szrj fixup_pt_set (&fn->gimple_df->escaped);
365338fd1498Szrj
365438fd1498Szrj /* The above get's us to 99% I guess, at least catching the
365538fd1498Szrj address compares. Below also gets us aliasing correct
365638fd1498Szrj but as said we're giving leeway to the situation with
365738fd1498Szrj readonly vars anyway, so ... */
365838fd1498Szrj basic_block bb;
365938fd1498Szrj FOR_EACH_BB_FN (bb, fn)
366038fd1498Szrj for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
366138fd1498Szrj gsi_next (&gsi))
366238fd1498Szrj {
366338fd1498Szrj gcall *call = dyn_cast<gcall *> (gsi_stmt (gsi));
366438fd1498Szrj if (call)
366538fd1498Szrj {
366638fd1498Szrj fixup_pt_set (gimple_call_use_set (call));
366738fd1498Szrj fixup_pt_set (gimple_call_clobber_set (call));
366838fd1498Szrj }
366938fd1498Szrj }
367038fd1498Szrj }
367138fd1498Szrj
367238fd1498Szrj unsigned i;
367338fd1498Szrj symtab_pair *item;
367438fd1498Szrj FOR_EACH_VEC_ELT (m_merged_variables, i, item)
367538fd1498Szrj set_alias_uids (item->first, DECL_UID (item->first->decl));
367638fd1498Szrj }
367738fd1498Szrj
367838fd1498Szrj /* Dump function prints all class members to a FILE with an INDENT. */
367938fd1498Szrj
368038fd1498Szrj void
dump(FILE * file,unsigned int indent)368138fd1498Szrj congruence_class::dump (FILE *file, unsigned int indent) const
368238fd1498Szrj {
368338fd1498Szrj FPRINTF_SPACES (file, indent, "class with id: %u, hash: %u, items: %u\n",
368438fd1498Szrj id, members[0]->get_hash (), members.length ());
368538fd1498Szrj
368638fd1498Szrj FPUTS_SPACES (file, indent + 2, "");
368738fd1498Szrj for (unsigned i = 0; i < members.length (); i++)
368838fd1498Szrj fprintf (file, "%s ", members[i]->node->dump_asm_name ());
368938fd1498Szrj
369038fd1498Szrj fprintf (file, "\n");
369138fd1498Szrj }
369238fd1498Szrj
369338fd1498Szrj /* Returns true if there's a member that is used from another group. */
369438fd1498Szrj
369538fd1498Szrj bool
is_class_used(void)369638fd1498Szrj congruence_class::is_class_used (void)
369738fd1498Szrj {
369838fd1498Szrj for (unsigned int i = 0; i < members.length (); i++)
369938fd1498Szrj if (members[i]->usages.length ())
370038fd1498Szrj return true;
370138fd1498Szrj
370238fd1498Szrj return false;
370338fd1498Szrj }
370438fd1498Szrj
370538fd1498Szrj /* Generate pass summary for IPA ICF pass. */
370638fd1498Szrj
370738fd1498Szrj static void
ipa_icf_generate_summary(void)370838fd1498Szrj ipa_icf_generate_summary (void)
370938fd1498Szrj {
371038fd1498Szrj if (!optimizer)
371138fd1498Szrj optimizer = new sem_item_optimizer ();
371238fd1498Szrj
371338fd1498Szrj optimizer->register_hooks ();
371438fd1498Szrj optimizer->parse_funcs_and_vars ();
371538fd1498Szrj }
371638fd1498Szrj
371738fd1498Szrj /* Write pass summary for IPA ICF pass. */
371838fd1498Szrj
371938fd1498Szrj static void
ipa_icf_write_summary(void)372038fd1498Szrj ipa_icf_write_summary (void)
372138fd1498Szrj {
372238fd1498Szrj gcc_assert (optimizer);
372338fd1498Szrj
372438fd1498Szrj optimizer->write_summary ();
372538fd1498Szrj }
372638fd1498Szrj
372738fd1498Szrj /* Read pass summary for IPA ICF pass. */
372838fd1498Szrj
372938fd1498Szrj static void
ipa_icf_read_summary(void)373038fd1498Szrj ipa_icf_read_summary (void)
373138fd1498Szrj {
373238fd1498Szrj if (!optimizer)
373338fd1498Szrj optimizer = new sem_item_optimizer ();
373438fd1498Szrj
373538fd1498Szrj optimizer->read_summary ();
373638fd1498Szrj optimizer->register_hooks ();
373738fd1498Szrj }
373838fd1498Szrj
373938fd1498Szrj /* Semantic equality exection function. */
374038fd1498Szrj
374138fd1498Szrj static unsigned int
ipa_icf_driver(void)374238fd1498Szrj ipa_icf_driver (void)
374338fd1498Szrj {
374438fd1498Szrj gcc_assert (optimizer);
374538fd1498Szrj
374638fd1498Szrj bool merged_p = optimizer->execute ();
374738fd1498Szrj
374838fd1498Szrj delete optimizer;
374938fd1498Szrj optimizer = NULL;
375038fd1498Szrj
375138fd1498Szrj return merged_p ? TODO_remove_functions : 0;
375238fd1498Szrj }
375338fd1498Szrj
375438fd1498Szrj const pass_data pass_data_ipa_icf =
375538fd1498Szrj {
375638fd1498Szrj IPA_PASS, /* type */
375738fd1498Szrj "icf", /* name */
375838fd1498Szrj OPTGROUP_IPA, /* optinfo_flags */
375938fd1498Szrj TV_IPA_ICF, /* tv_id */
376038fd1498Szrj 0, /* properties_required */
376138fd1498Szrj 0, /* properties_provided */
376238fd1498Szrj 0, /* properties_destroyed */
376338fd1498Szrj 0, /* todo_flags_start */
376438fd1498Szrj 0, /* todo_flags_finish */
376538fd1498Szrj };
376638fd1498Szrj
376738fd1498Szrj class pass_ipa_icf : public ipa_opt_pass_d
376838fd1498Szrj {
376938fd1498Szrj public:
pass_ipa_icf(gcc::context * ctxt)377038fd1498Szrj pass_ipa_icf (gcc::context *ctxt)
377138fd1498Szrj : ipa_opt_pass_d (pass_data_ipa_icf, ctxt,
377238fd1498Szrj ipa_icf_generate_summary, /* generate_summary */
377338fd1498Szrj ipa_icf_write_summary, /* write_summary */
377438fd1498Szrj ipa_icf_read_summary, /* read_summary */
377538fd1498Szrj NULL, /*
377638fd1498Szrj write_optimization_summary */
377738fd1498Szrj NULL, /*
377838fd1498Szrj read_optimization_summary */
377938fd1498Szrj NULL, /* stmt_fixup */
378038fd1498Szrj 0, /* function_transform_todo_flags_start */
378138fd1498Szrj NULL, /* function_transform */
378238fd1498Szrj NULL) /* variable_transform */
378338fd1498Szrj {}
378438fd1498Szrj
378538fd1498Szrj /* opt_pass methods: */
gate(function *)378638fd1498Szrj virtual bool gate (function *)
378738fd1498Szrj {
378838fd1498Szrj return in_lto_p || flag_ipa_icf_variables || flag_ipa_icf_functions;
378938fd1498Szrj }
379038fd1498Szrj
execute(function *)379138fd1498Szrj virtual unsigned int execute (function *)
379238fd1498Szrj {
379338fd1498Szrj return ipa_icf_driver();
379438fd1498Szrj }
379538fd1498Szrj }; // class pass_ipa_icf
379638fd1498Szrj
379738fd1498Szrj } // ipa_icf namespace
379838fd1498Szrj
379938fd1498Szrj ipa_opt_pass_d *
make_pass_ipa_icf(gcc::context * ctxt)380038fd1498Szrj make_pass_ipa_icf (gcc::context *ctxt)
380138fd1498Szrj {
380238fd1498Szrj return new ipa_icf::pass_ipa_icf (ctxt);
380338fd1498Szrj }
3804