https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123226

Jan Hubicka <hubicka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hubicka at gcc dot gnu.org

--- Comment #5 from Jan Hubicka <hubicka at gcc dot gnu.org> ---
Resolving of this calles happens in:

0  cgraph_edge::resolve_speculation (edge=0x7ffff72c4618,
callee_decl=0x7ffff72af300) at ../../gcc/cgraph.cc:1539
#1  0x00000000010d269d in cgraph_update_edges_for_call_stmt_node
(node=0x7ffff72c6110, old_stmt=0x7ffff7303da8, old_call=0x0,
new_stmt=0x7ffff7303da8)
    at ../../gcc/cgraph.cc:2017
#2  0x00000000010d2965 in cgraph_update_edges_for_call_stmt
(old_stmt=0x7ffff7303da8, old_decl=0x0, new_stmt=0x7ffff7303da8) at
../../gcc/cgraph.cc:2091
#3  0x000000000193e7fd in fold_marked_statements (first=0,
statements=0x4911d60) at ../../gcc/tree-inline.cc:5575
#4  0x0000000001942133 in tree_function_versioning (old_decl=0x7ffff729f000,
new_decl=0x7ffff72b6c00, tree_map=0x7ffff72c3578,
param_adjustments=0x7ffff72c14e0, 
    update_clones=true, blocks_to_copy=0x0, new_entry=0x0) at
../../gcc/tree-inline.cc:6555
#5  0x00000000010ef6b1 in cgraph_node::materialize_clone (this=0x7ffff72c6110)
at ../../gcc/cgraphclones.cc:1249
#6  0x00000000016e2411 in execute_all_ipa_transforms (do_not_collect=false) at
../../gcc/passes.cc:2373
#7  0x00000000010e84f6 in cgraph_node::expand (this=0x7ffff72b9000) at
../../gcc/cgraphunit.cc:1864
#8  0x00000000010e8d6e in expand_all_functions () at
../../gcc/cgraphunit.cc:2054
#9  0x00000000010e98ae in symbol_table::compile (this=0x7ffff7406000) at
../../gcc/cgraphunit.cc:2432
#10 0x0000000000fa3b0d in lto_main () at ../../gcc/lto/lto.cc:694
#11 0x000000000186daa6 in compile_file () at ../../gcc/toplev.cc:455
#12 0x0000000001871027 in do_compile () at ../../gcc/toplev.cc:2225
#13 0x000000000187148e in toplev::main (this=0x7fffffffda5a, argc=29,
argv=0x4839c10) at ../../gcc/toplev.cc:2390
#14 0x00000000036f9a7e in main (argc=26, argv=0x7fffffffdb88) at
../../gcc/main.cc:39

stmt originally is

# .MEM = VDEF <.MEM>
D.5907 = OBJ_TYPE_REF(_2;(struct generic_parser_base)&MEM <struct n> [(void
*)&j + 16B]->3B) (&MEM <struct n> [(void *)&j + 16B]);

and folding turns it to

# .MEM = VDEF <.MEM>
D.5907 = _ZThn8_N4llvm14PassNameParserD0Ev (&MEM <struct n> [(void *)&j +
16B]);

We have

ZN4llvm2cl19generic_parser_base10findOptionENS_9StringRefE.constprop.0/69
(findOption.constprop)
  Type: function definition analyzed
  Visibility: artificial
  References:
_ZNK4llvm2cl19generic_parser_base14getOptionWidthERKNS0_6OptionE/2 (addr)
(speculative) _ZThn8_N4llvm14PassNameParserD0Ev/42 (addr) (speculative) j/14
(addr) 
  Referring: 
  Read from file: a-CommandLine.o
  Function findOption.constprop/69 is inline copy in _GLOBAL__sub_I_j/16
  Clone of _ZN4llvm2cl19generic_parser_base10findOptionENS_9StringRefE/1
  Availability: local
  Unit id: 1
  Function flags: count:6950038029 (estimated locally) body local
only_called_at_startup executed_once
  Called by: _ZN4llvm14PassNameParser1bEPKi.constprop.0/68 (inlined)
(6950038029 (estimated locally),6.47 per call) (can throw external) 
  Calls: _ZN4llvmeqENS_9StringRefES0_/4 (701953785967 (estimated
locally),653.75 per call) (can throw external)
_ZNK4llvm2cl19generic_parser_base14getOptionWidthERKNS0_6OptionE.constprop.0/70
(speculative) (inlined) (280781514649 (estimated locally),261.50 per call) (can
throw external) _ZThn8_N4llvm14PassNameParserD0Ev/74 (speculative) (inlined)
(168468908786 (estimated locally),156.90 per call) (can throw external) 
       indirect polymorphic callsite, vptr_changed, calling param -1, offset
64otr_token 3, otr_type struct generic_parser_base, context     Outer type
(dynamic):struct generic_parser_base (or a derived type) offset 0, flags 0, num
speculative call targets: 2

So the edge is speculate twice and the speculation to
_ZThn8_N4llvm14PassNameParserD0Ev is inlined

Now we do
         /* If call was devirtualized during cloning, mark edge
             as resolved.  */ 
          if (e->speculative)
            {       
              if (new_stmt && is_gimple_call (new_stmt))
                { 
                  tree decl = gimple_call_fndecl (new_stmt);
                  if (decl)
                    e = cgraph_edge::resolve_speculation (e, decl);
                }
              else
                e = cgraph_edge::resolve_speculation (e, NULL);
            }

this resolves one edge but is supposed to do all of them as documented in
resolve_speculation.

This fixes it
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 91ff2775de1..571b3cbf3ba 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -2014,10 +2014,10 @@ cgraph_update_edges_for_call_stmt_node (cgraph_node
*node,
                {
                  tree decl = gimple_call_fndecl (new_stmt);
                  if (decl)
-                   e = cgraph_edge::resolve_speculation (e, decl);
+                   e = cgraph_edge::make_direct (e, cgraph_node::get_create
(decl));
                }
              else
-               e = cgraph_edge::resolve_speculation (e, NULL);
+               gcc_unreachable ();
            }
          /* Keep calls marked as dead dead.  */
          if (new_stmt && is_gimple_call (new_stmt) && e->callee

The problem really traces back to the original multi-target speculation support
rf1ba88b1b20cb579b3b7ce6ce65470205742be7e 
I will test the patch above

However I think there is another problem.  In case we redirect edge to a clone
of original function, both make_direct and resolve_speculation will interpret
it as a failed speculation since callees won't match

cgraph_edge *
cgraph_edge::resolve_speculation (cgraph_edge *edge, tree callee_decl)
{         
  cgraph_edge *e2;
  ipa_ref *ref;

  gcc_assert (edge->speculative && (!callee_decl || edge->callee));
  if (!edge->callee)
    e2 = edge->first_speculative_call_target ();
  else      
    e2 = edge;
  ref = e2->speculative_call_target_ref ();
  edge = edge->speculative_call_indirect_edge ();
  symtab_node *callee;
  if (!callee_decl
      || !(callee = symtab_node::get (callee_decl))
      || !ref->referred->semantically_equivalent_p (callee))
    {   
      if (dump_file)
        { 
          if (callee_decl)
            {
              fprintf (dump_file, "Speculative indirect call %s => %s has "
                       "turned out to have contradicting known target ",
                       edge->caller->dump_name (),
                       e2->callee->dump_name ());
...

I will try to craft a testcase.

Reply via email to