Hi, I was trying to address first TODO from ipa-comdats.c (attached patch) TODO: When symbol is used only by comdat symbols, but from different groups, it would make sense to produce a new comdat group for it with anonymous name.
The patch introduces new lattice value ANON "between" COMDAT and BOTTOM values. The meet operation is rewritten in merge_comdat_group(). Does the approach look reasonable ? For comdat-1.C (attached) q is referenced from both i1 and i2 and hence is put in it's own comdat-section. I suppose that's the expected result ? However it fails for comdat-2.C with the error below. error: comdat-local function called by int i1() outside its comdat However in case of comdat-1.C, i1() calls q() which is also placed in another comdat group but doesn't give error for that case. It also works if r() is referenced from another comdat group and not just from q (comdat-3.C). I am not able to understand why the error occurs for comdat-2.C. Could someone please have a look at it ? Thanks! Assembling functions: comdat-2.C: At global scope: comdat-2.C:33:15: error: comdat-local function called by int i2() outside its comdat int (*f2)()=i2; ^ comdat-2.C:33:15: error: comdat-local function called by int i1() outside its comdat _ZL1qv/1 (int q()) @0x7fe19ccde170 Type: function definition analyzed Visibility: prevailing_def_ironly comdat_group:q Same comdat group as: _ZL1rv/0 References: Referring: Availability: local First run: 0 Function flags: body local Called by: _Z2i2v/3 (1.00 per call) (can throw external) _Z2i1v/2 (1.00 per call) (can throw external) Calls: _ZL1rv/0 (1.00 per call) (can throw external) _Z6printfPKcz/6 (1.00 per call) (can throw external) comdat-2.C:33:15: internal compiler error: verify_cgraph_node failed 0x936083 cgraph_node::verify_node() ../../gcc/gcc/cgraph.c:3233 0x92b6df symtab_node::verify() ../../gcc/gcc/symtab.c:1177 0x92b7cf symtab_node::verify_symtab_nodes() ../../gcc/gcc/symtab.c:1197 0x93e736 symtab_node::checking_verify_symtab_nodes() ../../gcc/gcc/cgraph.h:602 0x93e736 symbol_table::compile() ../../gcc/gcc/cgraphunit.c:2431 0x940a57 symbol_table::compile() ../../gcc/gcc/cgraphunit.c:2538 0x940a57 symbol_table::finalize_compilation_unit() ../../gcc/gcc/cgraphunit.c:2564 Thanks, Prathamesh
diff --git a/gcc/ipa-comdats.c b/gcc/ipa-comdats.c index 6e0f762..999bed2 100644 --- a/gcc/ipa-comdats.c +++ b/gcc/ipa-comdats.c @@ -56,6 +56,68 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "cgraph.h" + +static void +set_anon (tree& newgroup, symtab_node *symbol, + hash_set<tree>& anon_set, + hash_map<tree, symtab_node *>& comdat_head_map) +{ + newgroup = DECL_NAME (symbol->decl); + anon_set.add (newgroup); + comdat_head_map.put (newgroup, symbol); + symbol->set_comdat_group (newgroup); + fprintf (stderr, "newgroup goes to anon: %s\n", IDENTIFIER_POINTER (newgroup)); +} + +static void +merge_comdat_group (tree& newgroup, tree *val2, symtab_node *symbol, + hash_set<tree>& anon_set, + hash_map<tree, symtab_node *>& comdat_head_map) +{ + /* *val2 is TOP. */ + if (val2 == NULL || *val2 == NULL) + return; + + /* *val2 is BOTTOM. */ + if (*val2 == error_mark_node) + { + newgroup = error_mark_node; + return; + } + + /* *val2 is ANON. */ + else if (anon_set.contains (*val2)) + { + /* ANON meet TOP == ANON. */ + if (newgroup == NULL) + newgroup = *val2; + /* ANON1 meet ANON2 == ANON2. */ + else if (anon_set.contains (newgroup)) + ; + /* ANON meet COMDAT == ANON2. */ + else + set_anon (newgroup, symbol, anon_set, comdat_head_map); + } + + /* *val2 is COMDAT. */ + else + { + /* COMDAT meet TOP == COMDAT. */ + if (newgroup == NULL) + { + newgroup = *val2; + return; + } + /* COMDAT1 meet COMDAT2 == ANON. */ + else if (*val2 != newgroup) + set_anon (newgroup, symbol, anon_set, comdat_head_map); + /* ensure this case is COMDAT meet COMDAT. */ + else + gcc_assert (*val2 == newgroup); + } +} + + /* Main dataflow loop propagating comdat groups across the symbol table. All references to SYMBOL are examined and NEWGROUP is updated accordingly. MAP holds current lattice @@ -63,7 +125,9 @@ along with GCC; see the file COPYING3. If not see tree propagate_comdat_group (struct symtab_node *symbol, - tree newgroup, hash_map<symtab_node *, tree> &map) + tree newgroup, hash_map<symtab_node *, tree> &map, + hash_set<tree>& anon_set, + hash_map<tree, symtab_node *>& comdat_head_map) { int i; struct ipa_ref *ref; @@ -78,7 +142,7 @@ propagate_comdat_group (struct symtab_node *symbol, if (ref->use == IPA_REF_ALIAS) { - newgroup = propagate_comdat_group (symbol2, newgroup, map); + newgroup = propagate_comdat_group (symbol2, newgroup, map, anon_set, comdat_head_map); continue; } @@ -102,17 +166,7 @@ propagate_comdat_group (struct symtab_node *symbol, symbol2 = cn->global.inlined_to; } - /* The actual merge operation. */ - - tree *val2 = map.get (symbol2); - - if (val2 && *val2 != newgroup) - { - if (!newgroup) - newgroup = *val2; - else - newgroup = error_mark_node; - } + merge_comdat_group (newgroup, map.get (symbol2), symbol, anon_set, comdat_head_map); } /* If we analyze function, walk also callers. */ @@ -129,7 +183,7 @@ propagate_comdat_group (struct symtab_node *symbol, { /* Thunks can not call across section boundary. */ if (cn->thunk.thunk_p) - newgroup = propagate_comdat_group (symbol2, newgroup, map); + newgroup = propagate_comdat_group (symbol2, newgroup, map, anon_set, comdat_head_map); /* If we see inline clone, its comdat group actually corresponds to the comdat group of the function it is inlined to. */ @@ -137,17 +191,7 @@ propagate_comdat_group (struct symtab_node *symbol, symbol2 = cn->global.inlined_to; } - /* The actual merge operation. */ - - tree *val2 = map.get (symbol2); - - if (val2 && *val2 != newgroup) - { - if (!newgroup) - newgroup = *val2; - else - newgroup = error_mark_node; - } + merge_comdat_group (newgroup, map.get (symbol2), symbol, anon_set, comdat_head_map); } return newgroup; } @@ -237,6 +280,7 @@ ipa_comdats (void) bool comdat_group_seen = false; symtab_node *first = (symtab_node *) (void *) 1; tree group; + hash_set<tree> anon_set; /* Start the dataflow by assigning comdat group to symbols that are in comdat groups already. All other externally visible symbols must stay, we use @@ -310,7 +354,7 @@ ipa_comdats (void) if (group == error_mark_node) continue; - newgroup = propagate_comdat_group (symbol, group, map); + newgroup = propagate_comdat_group (symbol, group, map, anon_set, comdat_head_map); /* If nothing changed, proceed to next symbol. */ if (newgroup == group)
/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ /* { dg-options "-O2 -fdump-ipa-comdats" } */ int printf (const char *, ...); /* q should be placed in anon comdat group. */ __attribute__ ((noinline)) static int q(void) { printf ("test"); } inline int i1(void) { return q(); } inline int i2(void) { return q(); } int (*f)()=i1; int (*f2)()=i2; /* { dg-final { scan-ipa-dump-times "Localizing symbol" 1 "comdats" } } */
/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ /* { dg-options "-O2 -fdump-ipa-comdats" } */ /* q should be put in anonymous comdat group since it's referenced from i1 and i2. r should be put in same comdat group as q. */ int printf (const char *, ...); __attribute__ ((noinline)) static int r(void) { return printf ("world"); } __attribute__ ((noinline)) static int q(void) { printf ("test"); return r(); } inline int i1(void) { return q(); } inline int i2(void) { return q(); } int (*f)()=i1; int (*f2)()=i2; /* { dg-final { scan-ipa-dump-times "Localizing symbol" 1 "comdats" } } */
/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ /* { dg-options "-O2 -fdump-ipa-comdats" } */ int printf (const char *, ...); /* q and r should be placed in anonymous groups. */ __attribute__ ((noinline)) static int r(void) { return printf ("world"); } __attribute__ ((noinline)) static int q(void) { printf ("test"); return r(); } inline int i1(void) { return q(); } inline int i2(void) { return q(); } inline int i3(void) { return r(); } int (*f)()=i1; int (*f2)()=i2; int (*f3)()=i3; /* { dg-final { scan-ipa-dump-times "Localizing symbol" 1 "comdats" } } */