diff mbox

[PR,61540] Do not ICE on impossible devirtualization

Message ID 20140619114955.GA24436@virgil.suse
State New
Headers show

Commit Message

Martin Jambor June 19, 2014, 11:49 a.m. UTC
Hi,

On Wed, Jun 18, 2014 at 06:12:34PM +0200, Bernhard Reutner-Fischer wrote:
> On 18 June 2014 10:24:16 Martin Jambor <mjambor@suse.cz> wrote:
> 
> >@@ -3002,10 +3014,8 @@ try_make_edge_direct_virtual_call (struct
> >cgraph_edge *ie,
> >
> >   if (target)
> >     {
> >-#ifdef ENABLE_CHECKING
> >-      gcc_assert (possible_polymorphic_call_target_p
> >-	 (ie, cgraph_get_node (target)));
> >-#endif
> >+      if (!possible_polymorphic_call_target_p (ie, cgraph_get_node (target)))
> >+	return ipa_make_edge_direct_to_target (ie, target);
> >       return ipa_make_edge_direct_to_target (ie, target);
> >     }
> 
> The above looks odd. You return the same thing both conditionally
> and unconditionally?
> 

You are obviously right, apparently I was too tired to attempt to work
that night.  Thanks, for spotting it.  The following patch has this
corrected and it also passes bootstrap and testing on x86_64-linux on
both the trunk and the 4.9 branch. OK for both?

Thanks,

Martin


2014-06-19  Martin Jambor  <mjambor@suse.cz>

	PR ipa/61540
	* ipa-prop.c (impossible_devirt_target): New function.
	(try_make_edge_direct_virtual_call): Use it, also instead of
	asserting.

testsuite/
        * g++.dg/ipa/pr61540.C: New test.

Comments

Jan Hubicka June 19, 2014, 4:51 p.m. UTC | #1
> Hi,
> 
> On Wed, Jun 18, 2014 at 06:12:34PM +0200, Bernhard Reutner-Fischer wrote:
> > On 18 June 2014 10:24:16 Martin Jambor <mjambor@suse.cz> wrote:
> > 
> > >@@ -3002,10 +3014,8 @@ try_make_edge_direct_virtual_call (struct
> > >cgraph_edge *ie,
> > >
> > >   if (target)
> > >     {
> > >-#ifdef ENABLE_CHECKING
> > >-      gcc_assert (possible_polymorphic_call_target_p
> > >-	 (ie, cgraph_get_node (target)));
> > >-#endif
> > >+      if (!possible_polymorphic_call_target_p (ie, cgraph_get_node (target)))
> > >+	return ipa_make_edge_direct_to_target (ie, target);
> > >       return ipa_make_edge_direct_to_target (ie, target);
> > >     }
> > 
> > The above looks odd. You return the same thing both conditionally
> > and unconditionally?
> > 
> 
> You are obviously right, apparently I was too tired to attempt to work
> that night.  Thanks, for spotting it.  The following patch has this
> corrected and it also passes bootstrap and testing on x86_64-linux on
> both the trunk and the 4.9 branch. OK for both?

OK,
Honza
> 
> Thanks,
> 
> Martin
> 
> 
> 2014-06-19  Martin Jambor  <mjambor@suse.cz>
> 
> 	PR ipa/61540
> 	* ipa-prop.c (impossible_devirt_target): New function.
> 	(try_make_edge_direct_virtual_call): Use it, also instead of
> 	asserting.
> 
> testsuite/
>         * g++.dg/ipa/pr61540.C: New test.
> 
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index b67deed..d9dca52 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -2912,6 +2912,29 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
>    return cs;
>  }
>  
> +/* Return the target to be used in cases of impossible devirtualization.  IE
> +   and target (the latter can be NULL) are dumped when dumping is enabled.  */
> +
> +static tree
> +impossible_devirt_target (struct cgraph_edge *ie, tree target)
> +{
> +  if (dump_file)
> +    {
> +      if (target)
> +	fprintf (dump_file,
> +		 "Type inconsident devirtualization: %s/%i->%s\n",
> +		 ie->caller->name (), ie->caller->order,
> +		 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
> +      else
> +	fprintf (dump_file,
> +		 "No devirtualization target in %s/%i\n",
> +		 ie->caller->name (), ie->caller->order);
> +    }
> +  tree new_target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
> +  cgraph_get_create_node (new_target);
> +  return new_target;
> +}
> +
>  /* Try to find a destination for indirect edge IE that corresponds to a virtual
>     call based on a formal parameter which is described by jump function JFUNC
>     and if it can be determined, make it direct and return the direct edge.
> @@ -2946,15 +2969,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
>  		   && DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
>  		  || !possible_polymorphic_call_target_p
>  		       (ie, cgraph_get_node (target)))
> -		{
> -		  if (dump_file)
> -		    fprintf (dump_file,
> -			     "Type inconsident devirtualization: %s/%i->%s\n",
> -			     ie->caller->name (), ie->caller->order,
> -			     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
> -		  target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
> -		  cgraph_get_create_node (target);
> -		}
> +		target = impossible_devirt_target (ie, target);
>  	      return ipa_make_edge_direct_to_target (ie, target);
>  	    }
>  	}
> @@ -2984,10 +2999,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
>        if (targets.length () == 1)
>  	target = targets[0]->decl;
>        else
> -	{
> -          target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
> -	  cgraph_get_create_node (target);
> -	}
> +	target = impossible_devirt_target (ie, NULL_TREE);
>      }
>    else
>      {
> @@ -3002,10 +3014,8 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
>  
>    if (target)
>      {
> -#ifdef ENABLE_CHECKING
> -      gcc_assert (possible_polymorphic_call_target_p
> -	 (ie, cgraph_get_node (target)));
> -#endif
> +      if (!possible_polymorphic_call_target_p (ie, cgraph_get_node (target)))
> +	target = impossible_devirt_target (ie, target);
>        return ipa_make_edge_direct_to_target (ie, target);
>      }
>    else
> diff --git a/gcc/testsuite/g++.dg/ipa/pr61540.C b/gcc/testsuite/g++.dg/ipa/pr61540.C
> new file mode 100644
> index 0000000..d298964
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ipa/pr61540.C
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp" } */
> +
> +struct data {
> +  data(int) {}
> +};
> +
> +struct top {
> +  virtual int topf() {}
> +};
> +
> +struct intermediate: top {
> +    int topf() /* override */ { return 0; }
> +};
> +
> +struct child1: top {
> +    void childf()
> +    {
> +        data d(topf());
> +    }
> +};
> +
> +struct child2: intermediate {};
> +
> +void test(top& t)
> +{
> +    child1& c = static_cast<child1&>(t);
> +    c.childf();
> +    child2 d;
> +    test(d);
> +}
> +
> +int main (int argc, char **argv)
> +{
> +  child1 c;
> +  test (c);
> +  return 0;
> +}
> +
> +/* { dg-final { scan-ipa-dump "Type inconsident devirtualization" "cp" } } */
> +/* { dg-final { cleanup-ipa-dump "cp" } } */
James Greenhalgh June 23, 2014, 12:38 p.m. UTC | #2
On Thu, Jun 19, 2014 at 12:49:55PM +0100, Martin Jambor wrote:
> Hi,
> 
> On Wed, Jun 18, 2014 at 06:12:34PM +0200, Bernhard Reutner-Fischer wrote:
> > On 18 June 2014 10:24:16 Martin Jambor <mjambor@suse.cz> wrote:
> > 
> > >@@ -3002,10 +3014,8 @@ try_make_edge_direct_virtual_call (struct
> > >cgraph_edge *ie,
> > >
> > >   if (target)
> > >     {
> > >-#ifdef ENABLE_CHECKING
> > >-      gcc_assert (possible_polymorphic_call_target_p
> > >-	 (ie, cgraph_get_node (target)));
> > >-#endif
> > >+      if (!possible_polymorphic_call_target_p (ie, cgraph_get_node (target)))
> > >+	return ipa_make_edge_direct_to_target (ie, target);
> > >       return ipa_make_edge_direct_to_target (ie, target);
> > >     }
> > 
> > The above looks odd. You return the same thing both conditionally
> > and unconditionally?
> > 
> 
> You are obviously right, apparently I was too tired to attempt to work
> that night.  Thanks, for spotting it.  The following patch has this
> corrected and it also passes bootstrap and testing on x86_64-linux on
> both the trunk and the 4.9 branch. OK for both?
> 
> Thanks,
> 
> Martin

Hi Martin,

This new test fails for test variants with -fPIC. ( trunk and gcc-4_9-branch )
I've confirmed this on ARM, AArch64 and x86_64.

  FAIL: g++.dg/ipa/pr61540.C -std=gnu++11  scan-ipa-dump cp "Type inconsident devirtualization"
  FAIL: g++.dg/ipa/pr61540.C -std=gnu++1y  scan-ipa-dump cp "Type inconsident devirtualization"
  FAIL: g++.dg/ipa/pr61540.C -std=gnu++98  scan-ipa-dump cp "Type inconsident devirtualization"

I don't understand enough of this area to be more helpful, but I've
attached the relevant dump and the generated assembly for x86_64 for this
command:

./cc1plus ../../src/gcc/gcc/testsuite/g++.dg/ipa/pr61540.C -fmessage-length=0 -std=gnu++98 -O3 -fno-early-inlining -fdump-ipa-cp -o foo.s -fPIC

Let me know if you need any patches testing, or if there is anything else
I can help with.

Thanks,
James
.file	"pr61540.C"
	.section	.text.unlikely._ZN3top4topfEv,"axG",@progbits,_ZN3top4topfEv,comdat
	.align 2
.LCOLDB0:
	.section	.text._ZN3top4topfEv,"axG",@progbits,_ZN3top4topfEv,comdat
.LHOTB0:
	.align 2
	.p2align 4,,15
	.weak	_ZN3top4topfEv
	.type	_ZN3top4topfEv, @function
_ZN3top4topfEv:
.LFB3:
	.cfi_startproc
	rep; ret
	.cfi_endproc
.LFE3:
	.size	_ZN3top4topfEv, .-_ZN3top4topfEv
	.section	.text.unlikely._ZN3top4topfEv,"axG",@progbits,_ZN3top4topfEv,comdat
.LCOLDE0:
	.section	.text._ZN3top4topfEv,"axG",@progbits,_ZN3top4topfEv,comdat
.LHOTE0:
	.section	.text.unlikely._ZN12intermediate4topfEv,"axG",@progbits,_ZN12intermediate4topfEv,comdat
	.align 2
.LCOLDB1:
	.section	.text._ZN12intermediate4topfEv,"axG",@progbits,_ZN12intermediate4topfEv,comdat
.LHOTB1:
	.align 2
	.p2align 4,,15
	.weak	_ZN12intermediate4topfEv
	.type	_ZN12intermediate4topfEv, @function
_ZN12intermediate4topfEv:
.LFB4:
	.cfi_startproc
	xorl	%eax, %eax
	ret
	.cfi_endproc
.LFE4:
	.size	_ZN12intermediate4topfEv, .-_ZN12intermediate4topfEv
	.section	.text.unlikely._ZN12intermediate4topfEv,"axG",@progbits,_ZN12intermediate4topfEv,comdat
.LCOLDE1:
	.section	.text._ZN12intermediate4topfEv,"axG",@progbits,_ZN12intermediate4topfEv,comdat
.LHOTE1:
	.section	.text.unlikely,"ax",@progbits
.LCOLDB2:
	.text
.LHOTB2:
	.p2align 4,,15
	.globl	_Z4testR3top
	.type	_Z4testR3top, @function
_Z4testR3top:
.LFB6:
	.cfi_startproc
	subq	$24, %rsp
	.cfi_def_cfa_offset 32
	movq	(%rdi), %rax
	movq	(%rax), %rax
	cmpq	_ZN3top4topfEv@GOTPCREL(%rip), %rax
	jne	.L7
.L4:
	movq	_ZTV6child2@GOTPCREL(%rip), %rax
	movq	%rsp, %rdi
	addq	$16, %rax
	movq	%rax, (%rsp)
	call	_Z4testR3top@PLT
	addq	$24, %rsp
	.cfi_remember_state
	.cfi_def_cfa_offset 8
	ret
	.p2align 4,,10
	.p2align 3
.L7:
	.cfi_restore_state
	call	*%rax
	jmp	.L4
	.cfi_endproc
.LFE6:
	.size	_Z4testR3top, .-_Z4testR3top
	.section	.text.unlikely
.LCOLDE2:
	.text
.LHOTE2:
	.section	.text.unlikely
.LCOLDB3:
	.section	.text.startup,"ax",@progbits
.LHOTB3:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB16:
	.cfi_startproc
	subq	$24, %rsp
	.cfi_def_cfa_offset 32
	movq	_ZTV6child1@GOTPCREL(%rip), %rax
	movq	%rsp, %rdi
	addq	$16, %rax
	movq	%rax, (%rsp)
	call	_Z4testR3top@PLT
	xorl	%eax, %eax
	addq	$24, %rsp
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE16:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE3:
	.section	.text.startup
.LHOTE3:
	.weak	_ZTS3top
	.section	.rodata._ZTS3top,"aG",@progbits,_ZTS3top,comdat
	.type	_ZTS3top, @object
	.size	_ZTS3top, 5
_ZTS3top:
	.string	"3top"
	.weak	_ZTI3top
	.section	.data.rel.ro._ZTI3top,"awG",@progbits,_ZTI3top,comdat
	.align 8
	.type	_ZTI3top, @object
	.size	_ZTI3top, 16
_ZTI3top:
	.quad	_ZTVN10__cxxabiv117__class_type_infoE+16
	.quad	_ZTS3top
	.weak	_ZTS12intermediate
	.section	.rodata._ZTS12intermediate,"aG",@progbits,_ZTS12intermediate,comdat
	.type	_ZTS12intermediate, @object
	.size	_ZTS12intermediate, 15
_ZTS12intermediate:
	.string	"12intermediate"
	.weak	_ZTI12intermediate
	.section	.data.rel.ro._ZTI12intermediate,"awG",@progbits,_ZTI12intermediate,comdat
	.align 8
	.type	_ZTI12intermediate, @object
	.size	_ZTI12intermediate, 24
_ZTI12intermediate:
	.quad	_ZTVN10__cxxabiv120__si_class_type_infoE+16
	.quad	_ZTS12intermediate
	.quad	_ZTI3top
	.weak	_ZTS6child1
	.section	.rodata._ZTS6child1,"aG",@progbits,_ZTS6child1,comdat
	.type	_ZTS6child1, @object
	.size	_ZTS6child1, 8
_ZTS6child1:
	.string	"6child1"
	.weak	_ZTI6child1
	.section	.data.rel.ro._ZTI6child1,"awG",@progbits,_ZTI6child1,comdat
	.align 8
	.type	_ZTI6child1, @object
	.size	_ZTI6child1, 24
_ZTI6child1:
	.quad	_ZTVN10__cxxabiv120__si_class_type_infoE+16
	.quad	_ZTS6child1
	.quad	_ZTI3top
	.weak	_ZTS6child2
	.section	.rodata._ZTS6child2,"aG",@progbits,_ZTS6child2,comdat
	.type	_ZTS6child2, @object
	.size	_ZTS6child2, 8
_ZTS6child2:
	.string	"6child2"
	.weak	_ZTI6child2
	.section	.data.rel.ro._ZTI6child2,"awG",@progbits,_ZTI6child2,comdat
	.align 8
	.type	_ZTI6child2, @object
	.size	_ZTI6child2, 24
_ZTI6child2:
	.quad	_ZTVN10__cxxabiv120__si_class_type_infoE+16
	.quad	_ZTS6child2
	.quad	_ZTI12intermediate
	.weak	_ZTV3top
	.section	.data.rel.ro._ZTV3top,"awG",@progbits,_ZTV3top,comdat
	.align 8
	.type	_ZTV3top, @object
	.size	_ZTV3top, 24
_ZTV3top:
	.quad	0
	.quad	_ZTI3top
	.quad	_ZN3top4topfEv
	.weak	_ZTV12intermediate
	.section	.data.rel.ro._ZTV12intermediate,"awG",@progbits,_ZTV12intermediate,comdat
	.align 8
	.type	_ZTV12intermediate, @object
	.size	_ZTV12intermediate, 24
_ZTV12intermediate:
	.quad	0
	.quad	_ZTI12intermediate
	.quad	_ZN12intermediate4topfEv
	.weak	_ZTV6child1
	.section	.data.rel.ro._ZTV6child1,"awG",@progbits,_ZTV6child1,comdat
	.align 8
	.type	_ZTV6child1, @object
	.size	_ZTV6child1, 24
_ZTV6child1:
	.quad	0
	.quad	_ZTI6child1
	.quad	_ZN3top4topfEv
	.weak	_ZTV6child2
	.section	.data.rel.ro._ZTV6child2,"awG",@progbits,_ZTV6child2,comdat
	.align 8
	.type	_ZTV6child2, @object
	.size	_ZTV6child2, 24
_ZTV6child2:
	.quad	0
	.quad	_ZTI6child2
	.quad	_ZN12intermediate4topfEv
	.ident	"GCC: (GNU) 4.10.0 20140622 (experimental)"
	.section	.note.GNU-stack,"",@progbits
IPA constant propagation start:

IPA structures before propagation:

Jump functions:
  Jump functions of caller  child1::child1()/39:
  Jump functions of caller  top::top()/38:
  Jump functions of caller  intermediate::intermediate()/37:
  Jump functions of caller  child2::child2()/36:
  Jump functions of caller  int main(int, char**)/19:
    callsite  int main(int, char**)/19 -> void test(top&)/15 : 
       param 0: KNOWN TYPE: base  struct child1, offset 0, component struct top
    callsite  int main(int, char**)/19 -> child1::child1()/18 : 
       param 0: KNOWN TYPE: base  struct child1, offset 0, component struct child1
  Jump functions of caller  child1::child1()/18:
  Jump functions of caller  child1::child1()/17:
    callsite  child1::child1()/17 -> top::top()/7 : 
       param 0: ANCESTOR: 0, offset 0, struct top, agg_preserved, type_preserved
  Jump functions of caller  void test(top&)/15:
    callsite  void test(top&)/15 -> void test(top&)/15 : 
       param 0: KNOWN TYPE: base  struct child2, offset 0, component struct top
    callsite  void test(top&)/15 -> child2::child2()/14 : 
       param 0: KNOWN TYPE: base  struct child2, offset 0, component struct child2
    callsite  void test(top&)/15 -> void child1::childf()/5 : 
       param 0: PASS THROUGH: 0, op nop_expr, agg_preserved, type_preserved
  Jump functions of caller  child2::child2()/14:
  Jump functions of caller  child2::child2()/13:
    callsite  child2::child2()/13 -> intermediate::intermediate()/10 : 
       param 0: ANCESTOR: 0, offset 0, struct intermediate, agg_preserved, type_preserved
  Jump functions of caller  intermediate::intermediate()/11:
  Jump functions of caller  intermediate::intermediate()/10:
    callsite  intermediate::intermediate()/10 -> top::top()/7 : 
       param 0: ANCESTOR: 0, offset 0, struct top, agg_preserved, type_preserved
  Jump functions of caller  top::top()/8:
  Jump functions of caller  top::top()/7:
  Jump functions of caller  void child1::childf()/5:
    callsite  void child1::childf()/5 -> virtual int top::topf()/3 : 
       param 0: ANCESTOR: 0, offset 0, struct top, agg_preserved, type_preserved
    indirect polymorphic callsite, calling param 0, offset 0, for stmt OBJ_TYPE_REF(_4;_5->0) (_5);
       param 0: ANCESTOR: 0, offset 0, struct top, agg_preserved, type_preserved
  Jump functions of caller  virtual int intermediate::topf()/4:
  Jump functions of caller  virtual int top::topf()/3:

 Propagating constants:

Function int main(int, char**)/19 is not versionable, reason: insufficient body availability.
Not considering child1::child1() for cloning; no hot calls.
Function void test(top&)/15 is not versionable, reason: insufficient body availability.
Considering child2::child2() for cloning.
Considering intermediate::intermediate() for cloning.
Considering top::top() for cloning.
Considering void child1::childf() for cloning.
Not considering virtual int intermediate::topf() for cloning; no hot calls.
Considering virtual int top::topf() for cloning.

overall_size: 53, max_new_size: 11001

IPA lattices after all propagation:

Lattices:
  Node: int main(int, char**)/19:
    param [0]: BOTTOM
        AGGS BOTTOM
    param [1]: BOTTOM
        AGGS BOTTOM
  Node: child1::child1()/17:
    param [0]: BOTTOM
        AGGS BOTTOM
  Node: void test(top&)/15:
    param [0]: BOTTOM
        AGGS BOTTOM
  Node: child2::child2()/13:
    param [0]: VARIABLE
               BINFO struct child2 [loc_time: 0, loc_size: 0, prop_time: 0, prop_size: 0]
        AGGS VARIABLE
  Node: intermediate::intermediate()/10:
    param [0]: VARIABLE
               BINFO struct child2 [loc_time: 0, loc_size: 0, prop_time: 0, prop_size: 0]
        AGGS BOTTOM
  Node: top::top()/7:
    param [0]: VARIABLE
               BINFO struct child2 [loc_time: 0, loc_size: 0, prop_time: 0, prop_size: 0]
        AGGS BOTTOM
  Node: void child1::childf()/5:
    param [0]: VARIABLE
        virt_call flag set
        AGGS VARIABLE
  Node: virtual int intermediate::topf()/4:
    param [0]: BOTTOM
        AGGS BOTTOM
  Node: virtual int top::topf()/3:
    param [0]: VARIABLE
        AGGS BOTTOM

IPA decision stage:


IPA constant propagation end

Reclaiming functions:
Reclaiming variables:
Clearing address taken flags:
Symbol table:

_ZN6child1C4Ev/39 (child1::child1()) @0x7fe5e6f4ee60
  Type: function
  Visibility: asm_written external public weak comdat artificial
  References: 
  Referring: 
  Availability: not_available
  First run: 0
  Function flags:
  Called by: 
  Calls: 
_ZN3topC4Ev/38 (top::top()) @0x7fe5e6f4e8a0
  Type: function
  Visibility: asm_written external public weak comdat artificial
  References: 
  Referring: 
  Availability: not_available
  First run: 0
  Function flags:
  Called by: 
  Calls: 
_ZN12intermediateC4Ev/37 (intermediate::intermediate()) @0x7fe5e6f4e450
  Type: function
  Visibility: asm_written external public weak comdat artificial
  References: 
  Referring: 
  Availability: not_available
  First run: 0
  Function flags:
  Called by: 
  Calls: 
_ZN6child2C4Ev/36 (child2::child2()) @0x7fe5e6f4e000
  Type: function
  Visibility: asm_written external public weak comdat artificial
  References: 
  Referring: 
  Availability: not_available
  First run: 0
  Function flags:
  Called by: 
  Calls: 
_ZTVN10__cxxabiv117__class_type_infoE/34 (int (* const __cxxabiv1::__class_type_info::_ZTVN10__cxxabiv117__class_type_infoE [])(...)) @0x7fe5e6f3ff78
  Type: variable
  Body removed by symtab_remove_unreachable_nodes
  Visibility: external public visibility_specified virtual artificial
  References: 
  Referring: _ZTI3top/30 (addr)
  Availability: not_available
  Varpool flags: read-only
_ZTVN10__cxxabiv120__si_class_type_infoE/33 (int (* const __cxxabiv1::__si_class_type_info::_ZTVN10__cxxabiv120__si_class_type_infoE [])(...)) @0x7fe5e6f3ff00
  Type: variable
  Body removed by symtab_remove_unreachable_nodes
  Visibility: external public visibility_specified virtual artificial
  References: 
  Referring: _ZTI6child2/24 (addr)_ZTI12intermediate/28 (addr)_ZTI6child1/26 (addr)
  Availability: not_available
  Varpool flags: read-only
_ZTS3top/31 (const char _ZTS3top [5]) @0x7fe5e6f3fe88
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTS3top one_only artificial
  References: 
  Referring: _ZTI3top/30 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTI3top/30 (const __class_type_info_pseudo _ZTI3top) @0x7fe5e6f3fe10
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTI3top one_only artificial
  References: _ZTVN10__cxxabiv117__class_type_infoE/34 (addr)_ZTS3top/31 (addr)
  Referring: _ZTI12intermediate/28 (addr)_ZTV3top/23 (addr)_ZTI6child1/26 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTS12intermediate/29 (const char _ZTS12intermediate [15]) @0x7fe5e6f3fd98
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTS12intermediate one_only artificial
  References: 
  Referring: _ZTI12intermediate/28 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTI12intermediate/28 (const __si_class_type_info_pseudo _ZTI12intermediate) @0x7fe5e6f3fd20
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTI12intermediate one_only artificial
  References: _ZTVN10__cxxabiv120__si_class_type_infoE/33 (addr)_ZTS12intermediate/29 (addr)_ZTI3top/30 (addr)
  Referring: _ZTI6child2/24 (addr)_ZTV12intermediate/22 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTS6child1/27 (const char _ZTS6child1 [8]) @0x7fe5e6f3fca8
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTS6child1 one_only artificial
  References: 
  Referring: _ZTI6child1/26 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTI6child1/26 (const __si_class_type_info_pseudo _ZTI6child1) @0x7fe5e6f3fc30
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTI6child1 one_only artificial
  References: _ZTVN10__cxxabiv120__si_class_type_infoE/33 (addr)_ZTS6child1/27 (addr)_ZTI3top/30 (addr)
  Referring: _ZTV6child1/21 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTS6child2/25 (const char _ZTS6child2 [8]) @0x7fe5e6f3fbb8
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTS6child2 one_only artificial
  References: 
  Referring: _ZTI6child2/24 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTI6child2/24 (const __si_class_type_info_pseudo _ZTI6child2) @0x7fe5e6f3fb40
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTI6child2 one_only artificial
  References: _ZTVN10__cxxabiv120__si_class_type_infoE/33 (addr)_ZTS6child2/25 (addr)_ZTI12intermediate/28 (addr)
  Referring: _ZTV6child2/20 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTV3top/23 (int (* top::_ZTV3top [3])(...)) @0x7fe5e6f3fac8
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTV3top one_only virtual artificial
  References: _ZTI3top/30 (addr)_ZN3top4topfEv/3 (addr)
  Referring: _ZN3topC2Ev/7 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTV12intermediate/22 (int (* intermediate::_ZTV12intermediate [3])(...)) @0x7fe5e6f3fa50
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTV12intermediate one_only virtual artificial
  References: _ZTI12intermediate/28 (addr)_ZN12intermediate4topfEv/4 (addr)
  Referring: _ZN12intermediateC2Ev/10 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTV6child1/21 (int (* child1::_ZTV6child1 [3])(...)) @0x7fe5e6f3f9d8
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTV6child1 one_only virtual artificial
  References: _ZTI6child1/26 (addr)_ZN3top4topfEv/3 (addr)
  Referring: _ZN6child1C2Ev/17 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
_ZTV6child2/20 (int (* child2::_ZTV6child2 [3])(...)) @0x7fe5e6f3f960
  Type: variable definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZTV6child2 one_only virtual artificial
  References: _ZTI6child2/24 (addr)_ZN12intermediate4topfEv/4 (addr)
  Referring: _ZN6child2C2Ev/13 (addr)
  Availability: available
  Varpool flags: initialized read-only const-value-known
main/19 (int main(int, char**)) @0x7fe5e6f572e0
  Type: function definition analyzed
  Visibility: externally_visible public
  References: 
  Referring: 
  Availability: overwritable
  First run: 0
  Function flags: body only_called_at_startup
  Called by: 
  Calls: _Z4testR3top/15 (1.00 per call) (can throw external) _ZN6child1C1Ev/18 (1.00 per call) 
_ZN6child1C1Ev/18 (child1::child1()) @0x7fe5e6f57170
  Type: function definition analyzed alias cpp_implicit_alias
  Visibility: externally_visible public weak comdat comdat_group:_ZN6child1C5Ev one_only artificial
  Same comdat group as: _ZN6child1C2Ev/17
  References: _ZN6child1C2Ev/17 (alias)
  Referring: 
  Availability: available
  First run: 0
  Function flags:
  Called by: main/19 (1.00 per call) 
  Calls: 
_ZN6child1C2Ev/17 (child1::child1()) @0x7fe5e6f57000
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN6child1C5Ev one_only artificial
  Same comdat group as: _ZN6child1C1Ev/18
  References: _ZTV6child1/21 (addr)
  Referring: _ZN6child1C1Ev/18 (alias)
  Availability: available
  First run: 0
  Function flags: body
  Called by: 
  Calls: _ZN3topC2Ev/7 (1.00 per call) 
_Z4testR3top/15 (void test(top&)) @0x7fe5e6f4ecf0
  Type: function definition analyzed
  Visibility: externally_visible public
  References: 
  Referring: 
  Availability: overwritable
  First run: 0
  Function flags: body
  Called by: main/19 (1.00 per call) (can throw external) _Z4testR3top/15 (1.00 per call) (can throw external) 
  Calls: _Z4testR3top/15 (1.00 per call) (can throw external) _ZN6child2C1Ev/14 (1.00 per call) _ZN6child16childfEv/5 (1.00 per call) (can throw external) 
_ZN6child2C1Ev/14 (child2::child2()) @0x7fe5e6f4eb80
  Type: function definition analyzed alias cpp_implicit_alias
  Visibility: externally_visible public weak comdat comdat_group:_ZN6child2C5Ev one_only artificial
  Same comdat group as: _ZN6child2C2Ev/13
  References: _ZN6child2C2Ev/13 (alias)
  Referring: 
  Availability: available
  First run: 0
  Function flags:
  Called by: _Z4testR3top/15 (1.00 per call) 
  Calls: 
_ZN6child2C2Ev/13 (child2::child2()) @0x7fe5e6f4ea10
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN6child2C5Ev one_only artificial
  Same comdat group as: _ZN6child2C1Ev/14
  References: _ZTV6child2/20 (addr)
  Referring: _ZN6child2C1Ev/14 (alias)
  Availability: available
  First run: 0
  Function flags: body
  Called by: 
  Calls: _ZN12intermediateC2Ev/10 (1.00 per call) 
_ZN12intermediateC1Ev/11 (intermediate::intermediate()) @0x7fe5e6f4e730
  Type: function definition analyzed alias cpp_implicit_alias
  Visibility: externally_visible public weak comdat comdat_group:_ZN12intermediateC5Ev one_only artificial
  Same comdat group as: _ZN12intermediateC2Ev/10
  References: _ZN12intermediateC2Ev/10 (alias)
  Referring: 
  Availability: available
  First run: 0
  Function flags:
  Called by: 
  Calls: 
_ZN12intermediateC2Ev/10 (intermediate::intermediate()) @0x7fe5e6f4e5c0
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN12intermediateC5Ev one_only artificial
  Same comdat group as: _ZN12intermediateC1Ev/11
  References: _ZTV12intermediate/22 (addr)
  Referring: _ZN12intermediateC1Ev/11 (alias)
  Availability: available
  First run: 0
  Function flags: body
  Called by: _ZN6child2C2Ev/13 (1.00 per call) 
  Calls: _ZN3topC2Ev/7 (1.00 per call) 
_ZN3topC1Ev/8 (top::top()) @0x7fe5e6f4e2e0
  Type: function definition analyzed alias cpp_implicit_alias
  Visibility: externally_visible public weak comdat comdat_group:_ZN3topC5Ev one_only artificial
  Same comdat group as: _ZN3topC2Ev/7
  References: _ZN3topC2Ev/7 (alias)
  Referring: 
  Availability: available
  First run: 0
  Function flags:
  Called by: 
  Calls: 
_ZN3topC2Ev/7 (top::top()) @0x7fe5e6f4e170
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN3topC5Ev one_only artificial
  Same comdat group as: _ZN3topC1Ev/8
  References: _ZTV3top/23 (addr)
  Referring: _ZN3topC1Ev/8 (alias)
  Availability: available
  First run: 0
  Function flags: body
  Called by: _ZN6child1C2Ev/17 (1.00 per call) _ZN12intermediateC2Ev/10 (1.00 per call) 
  Calls: 
_ZN6child16childfEv/5 (void child1::childf()) @0x7fe5e6f40cf0
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN6child16childfEv one_only
  References: _ZN3top4topfEv/3 (addr) (speculative)
  Referring: 
  Availability: available
  First run: 0
  Function flags: body
  Called by: _Z4testR3top/15 (1.00 per call) (can throw external) 
  Calls: _ZN3top4topfEv/3 (speculative) (0.80 per call) 
  Has 1 outgoing edges for indirect calls.
_ZN12intermediate4topfEv/4 (virtual int intermediate::topf()) @0x7fe5e6f408a0
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN12intermediate4topfEv one_only virtual
  Address is taken.
  References: 
  Referring: _ZTV6child2/20 (addr)_ZTV12intermediate/22 (addr)
  Availability: available
  First run: 0
  Function flags: body
  Called by: 
  Calls: 
_ZN3top4topfEv/3 (virtual int top::topf()) @0x7fe5e6f405c0
  Type: function definition analyzed
  Visibility: externally_visible public weak comdat comdat_group:_ZN3top4topfEv one_only virtual
  Address is taken.
  References: 
  Referring: _ZTV3top/23 (addr)_ZTV6child1/21 (addr)_ZN6child16childfEv/5 (addr) (speculative)
  Availability: available
  First run: 0
  Function flags: body
  Called by: _ZN6child16childfEv/5 (0.80 per call) (speculative) 
  Calls: 
int main(int, char**) (int argc, char * * argv)
{
  struct child1 c;

  <bb 2>:
  child1::child1 (&c);
  test (&c.D.2263);
  c ={v} {CLOBBER};
  return 0;

}


child1::child1() (struct child1 * const this)
{
  struct top * _2;

  <bb 2>:
  _2 = &this_1(D)->D.2263;
  top::top (_2);
  this_1(D)->D.2263._vptr.top = &MEM[(void *)&_ZTV6child1 + 16B];
  return;

}


void test(top&) (struct top & t)
{
  struct child2 d;

  <bb 2>:
  child1::childf (t_1(D));
  child2::child2 (&d);
  test (&d.D.2280.D.2254);
  d ={v} {CLOBBER};
  return;

}


child2::child2() (struct child2 * const this)
{
  struct intermediate * _2;

  <bb 2>:
  _2 = &this_1(D)->D.2280;
  intermediate::intermediate (_2);
  this_1(D)->D.2280.D.2254._vptr.top = &MEM[(void *)&_ZTV6child2 + 16B];
  return;

}


intermediate::intermediate() (struct intermediate * const this)
{
  struct top * _2;

  <bb 2>:
  _2 = &this_1(D)->D.2254;
  top::top (_2);
  this_1(D)->D.2254._vptr.top = &MEM[(void *)&_ZTV12intermediate + 16B];
  return;

}


top::top() (struct top * const this)
{
  <bb 2>:
  this_2(D)->_vptr.top = &MEM[(void *)&_ZTV3top + 16B];
  return;

}


void child1::childf() (struct child1 * const this)
{
  int (*__vtbl_ptr_type) () * _3;
  int (*__vtbl_ptr_type) () _4;
  struct top * _5;

  <bb 2>:
  _3 = this_1(D)->D.2263._vptr.top;
  _4 = *_3;
  _5 = &this_1(D)->D.2263;
  OBJ_TYPE_REF(_4;(struct top)_5->0) (_5);
  return;

}


virtual int intermediate::topf() (struct intermediate * const this)
{
  <bb 2>:
  return 0;

}


virtual int top::topf() (struct top * const this)
{
  <bb 2>:
  return;

}



;; Function virtual int top::topf() (_ZN3top4topfEv, funcdef_no=3, decl_uid=2243, cgraph_uid=3, symbol_order=3)

Modification phase of node virtual int top::topf()/3
virtual int top::topf() (struct top * const this)
{
  <bb 2>:
  return;

}



;; Function virtual int intermediate::topf() (_ZN12intermediate4topfEv, funcdef_no=4, decl_uid=2252, cgraph_uid=4, symbol_order=4)

Modification phase of node virtual int intermediate::topf()/4
virtual int intermediate::topf() (struct intermediate * const this)
{
  <bb 2>:
  return 0;

}



;; Function void test(top&) (_Z4testR3top, funcdef_no=6, decl_uid=2285, cgraph_uid=15, symbol_order=15)

Modification phase of node void test(top&)/15
void test(top&) (struct top & t)
{
  struct child2 d;

  <bb 2>:
  child1::childf (t_1(D));
  child2::child2 (&d);
  test (&d.D.2280.D.2254);
  d ={v} {CLOBBER};
  return;

}



;; Function int main(int, char**) (main, funcdef_no=16, decl_uid=2363, cgraph_uid=19, symbol_order=19) (executed once)

Modification phase of node int main(int, char**)/19
int main(int, char**) (int argc, char * * argv)
{
  struct child1 c;

  <bb 2>:
  child1::child1 (&c);
  test (&c.D.2263);
  c ={v} {CLOBBER};
  return 0;

}
diff mbox

Patch

diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index b67deed..d9dca52 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -2912,6 +2912,29 @@  try_make_edge_direct_simple_call (struct cgraph_edge *ie,
   return cs;
 }
 
+/* Return the target to be used in cases of impossible devirtualization.  IE
+   and target (the latter can be NULL) are dumped when dumping is enabled.  */
+
+static tree
+impossible_devirt_target (struct cgraph_edge *ie, tree target)
+{
+  if (dump_file)
+    {
+      if (target)
+	fprintf (dump_file,
+		 "Type inconsident devirtualization: %s/%i->%s\n",
+		 ie->caller->name (), ie->caller->order,
+		 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
+      else
+	fprintf (dump_file,
+		 "No devirtualization target in %s/%i\n",
+		 ie->caller->name (), ie->caller->order);
+    }
+  tree new_target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+  cgraph_get_create_node (new_target);
+  return new_target;
+}
+
 /* Try to find a destination for indirect edge IE that corresponds to a virtual
    call based on a formal parameter which is described by jump function JFUNC
    and if it can be determined, make it direct and return the direct edge.
@@ -2946,15 +2969,7 @@  try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 		   && DECL_FUNCTION_CODE (target) == BUILT_IN_UNREACHABLE)
 		  || !possible_polymorphic_call_target_p
 		       (ie, cgraph_get_node (target)))
-		{
-		  if (dump_file)
-		    fprintf (dump_file,
-			     "Type inconsident devirtualization: %s/%i->%s\n",
-			     ie->caller->name (), ie->caller->order,
-			     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
-		  target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
-		  cgraph_get_create_node (target);
-		}
+		target = impossible_devirt_target (ie, target);
 	      return ipa_make_edge_direct_to_target (ie, target);
 	    }
 	}
@@ -2984,10 +2999,7 @@  try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
       if (targets.length () == 1)
 	target = targets[0]->decl;
       else
-	{
-          target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
-	  cgraph_get_create_node (target);
-	}
+	target = impossible_devirt_target (ie, NULL_TREE);
     }
   else
     {
@@ -3002,10 +3014,8 @@  try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 
   if (target)
     {
-#ifdef ENABLE_CHECKING
-      gcc_assert (possible_polymorphic_call_target_p
-	 (ie, cgraph_get_node (target)));
-#endif
+      if (!possible_polymorphic_call_target_p (ie, cgraph_get_node (target)))
+	target = impossible_devirt_target (ie, target);
       return ipa_make_edge_direct_to_target (ie, target);
     }
   else
diff --git a/gcc/testsuite/g++.dg/ipa/pr61540.C b/gcc/testsuite/g++.dg/ipa/pr61540.C
new file mode 100644
index 0000000..d298964
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr61540.C
@@ -0,0 +1,41 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp" } */
+
+struct data {
+  data(int) {}
+};
+
+struct top {
+  virtual int topf() {}
+};
+
+struct intermediate: top {
+    int topf() /* override */ { return 0; }
+};
+
+struct child1: top {
+    void childf()
+    {
+        data d(topf());
+    }
+};
+
+struct child2: intermediate {};
+
+void test(top& t)
+{
+    child1& c = static_cast<child1&>(t);
+    c.childf();
+    child2 d;
+    test(d);
+}
+
+int main (int argc, char **argv)
+{
+  child1 c;
+  test (c);
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Type inconsident devirtualization" "cp" } } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */