Message ID | 20140619114955.GA24436@virgil.suse |
---|---|
State | New |
Headers | show |
> 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" } } */
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 --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" } } */