xref: /dragonfly/contrib/gcc-8.0/gcc/ipa-icf.c (revision 58e805e6)
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