diff mbox series

Fix devirtualization with LTO

Message ID 20181222200847.rj25xb4iflwtzau5@kam.mff.cuni.cz
State New
Headers show
Series Fix devirtualization with LTO | expand

Commit Message

Jan Hubicka Dec. 22, 2018, 8:08 p.m. UTC
Hi,
while fixing Firefox issues I also noticed that type simplification
completely disabled type based devirtualization on LTO path. Problem
is that method pointers now point to simplified type and 
obj_type_ref_class is not ready for that.

I also moved testcases where it makes sense to lto so this does not
happen again. This is not trivial task since one needs to work out why
testcases behaves differently when they do, so I will follow up on this
and convert more.

Bootstrapped/regtested x86_64-linux, comitted.

Honza

	* tree.c: (obj_type_ref_class): Move to...
	* ipa-devirt.c (obj_type_ref_class): Move to here; lookup main
	odr type.
	(get_odr_type): Compensate for type simplification.

	* g++.dg/ipa/devirt-30.C: Add dg-do.
	* g++.dg/lto/devirt-1_0.C: New testcase.
	* g++.dg/lto/devirt-2_0.C: New testcase.
	* g++.dg/lto/devirt-3_0.C: New testcase.
	* g++.dg/lto/devirt-4_0.C: New testcase.
	* g++.dg/lto/devirt-5_0.C: New testcase.
	* g++.dg/lto/devirt-6_0.C: New testcase.
	* g++.dg/lto/devirt-13_0.C: New testcase.
	* g++.dg/lto/devirt-14_0.C: New testcase.
	* g++.dg/lto/devirt-19_0.C: New testcase.
	* g++.dg/lto/devirt-22_0.C: New testcase.
	* g++.dg/lto/devirt-23_0.C: New testcase.
	* g++.dg/lto/devirt-30_0.C: New testcase.
	* g++.dg/lto/devirt-34_0.C: New testcase.

Comments

Sudakshina Das Dec. 24, 2018, 2:49 p.m. UTC | #1
Hi Jan

On 22/12/18 8:08 PM, Jan Hubicka wrote:
> Hi,
> while fixing Firefox issues I also noticed that type simplification
> completely disabled type based devirtualization on LTO path. Problem
> is that method pointers now point to simplified type and
> obj_type_ref_class is not ready for that.
>
> I also moved testcases where it makes sense to lto so this does not
> happen again. This is not trivial task since one needs to work out why
> testcases behaves differently when they do, so I will follow up on this
> and convert more.
>
> Bootstrapped/regtested x86_64-linux, comitted.
>
> Honza
>
> 	* tree.c: (obj_type_ref_class): Move to...
> 	* ipa-devirt.c (obj_type_ref_class): Move to here; lookup main
> 	odr type.
> 	(get_odr_type): Compensate for type simplification.
>
> 	* g++.dg/ipa/devirt-30.C: Add dg-do.
> 	* g++.dg/lto/devirt-1_0.C: New testcase.
> 	* g++.dg/lto/devirt-2_0.C: New testcase.
> 	* g++.dg/lto/devirt-3_0.C: New testcase.
> 	* g++.dg/lto/devirt-4_0.C: New testcase.
> 	* g++.dg/lto/devirt-5_0.C: New testcase.
> 	* g++.dg/lto/devirt-6_0.C: New testcase.
> 	* g++.dg/lto/devirt-13_0.C: New testcase.
> 	* g++.dg/lto/devirt-14_0.C: New testcase.
> 	* g++.dg/lto/devirt-19_0.C: New testcase.
> 	* g++.dg/lto/devirt-22_0.C: New testcase.
> 	* g++.dg/lto/devirt-23_0.C: New testcase.
> 	* g++.dg/lto/devirt-30_0.C: New testcase.
> 	* g++.dg/lto/devirt-34_0.C: New testcase.
> 	
I am seeing the following failures on aarch64-none-elf, 
aarch64-none-linux-gnu, aarch64_be-none-elf, arm-none-eabi, 
arm-none-linux-gnueabihf:

UNRESOLVED: g++-dg-lto-devirt-13-01.exe scan-tree-dump-times ssa 
"OBJ_TYPE_REF" 0
UNRESOLVED: g++-dg-lto-devirt-13-11.exe scan-tree-dump-times ssa 
"OBJ_TYPE_REF" 0
UNRESOLVED: g++-dg-lto-devirt-13-21.exe scan-tree-dump-times ssa 
"OBJ_TYPE_REF" 0
UNRESOLVED: g++-dg-lto-devirt-14-01.exe scan-tree-dump-not ssa "A.*foo"
UNRESOLVED: g++-dg-lto-devirt-14-11.exe scan-tree-dump-not ssa "A.*foo"
UNRESOLVED: g++-dg-lto-devirt-23-01.exe scan-wpa-ipa-dump cp "Discovered 
a virtual call to"

With an error like:

g++-dg-lto-devirt-14-11.exe: dump file does not exist

In my brief attempt, I can see that the scan-dump* routines are 
computing the wrong base name. I get the following if I edit

diff --git a/gcc/testsuite/lib/scandump.exp 
b/gcc/testsuite/lib/scandump.exp
index 3d42692..5961623 100644
--- a/gcc/testsuite/lib/scandump.exp
+++ b/gcc/testsuite/lib/scandump.exp
@@ -160,7 +160,7 @@ proc scan-dump-not { args } {
      set dumpbase [dump-base $src [lindex $args 3]]
      set output_file "[glob -nocomplain $dumpbase.[lindex $args 2]]"
      if { $output_file == "" } {
-       verbose -log "$testcase: dump file does not exist"
+       verbose -log "$testcase: dump file does not exist $dumpbase"
         unresolved "$testname"
         return
      }

g++-dg-lto-devirt-14-11.exe: dump file does not exist 
g++-dg-lto-devirt-14-11.exe

UNRESOLVED: g++-dg-lto-devirt-14-11.exe scan-tree-dump-not ssa "A.*foo

Thanks

Sudi

> Index: ipa-devirt.c
> ===================================================================
> --- ipa-devirt.c	(revision 267337)
> +++ ipa-devirt.c	(working copy)
> @@ -1985,6 +1985,30 @@ add_type_duplicate (odr_type val, tree t
>     return build_bases;
>   }
>   
> +/* REF is OBJ_TYPE_REF, return the class the ref corresponds to.  */
> +
> +tree
> +obj_type_ref_class (const_tree ref)
> +{
> +  gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF);
> +  ref = TREE_TYPE (ref);
> +  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
> +  ref = TREE_TYPE (ref);
> +  /* We look for type THIS points to.  ObjC also builds
> +     OBJ_TYPE_REF with non-method calls, Their first parameter
> +     ID however also corresponds to class type. */
> +  gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE
> +		       || TREE_CODE (ref) == FUNCTION_TYPE);
> +  ref = TREE_VALUE (TYPE_ARG_TYPES (ref));
> +  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
> +  tree ret = TREE_TYPE (ref);
> +  if (!in_lto_p)
> +    ret = TYPE_CANONICAL (ret);
> +  else
> +    ret = get_odr_type (ret)->type;
> +  return ret;
> +}
> +
>   /* Get ODR type hash entry for TYPE.  If INSERT is true, create
>      possibly new entry.  */
>   
> @@ -2000,6 +2024,8 @@ get_odr_type (tree type, bool insert)
>     int base_id = -1;
>   
>     type = TYPE_MAIN_VARIANT (type);
> +  if (!in_lto_p)
> +    type = TYPE_CANONICAL (type);
>   
>     gcc_checking_assert (can_be_name_hashed_p (type)
>   		       || can_be_vtable_hashed_p (type));
> Index: testsuite/g++.dg/ipa/devirt-30.C
> ===================================================================
> --- testsuite/g++.dg/ipa/devirt-30.C	(revision 267337)
> +++ testsuite/g++.dg/ipa/devirt-30.C	(working copy)
> @@ -1,4 +1,5 @@
>   // PR c++/58678
> +// { dg-do compile }
>   // { dg-options "-O3 -fdump-ipa-devirt" }
>   
>   // We shouldn't speculatively devirtualize to ~B because B is an abstract
> Index: testsuite/g++.dg/lto/devirt-13_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-13_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-13_0.C	(working copy)
> @@ -0,0 +1,5 @@
> +/* { dg-lto-do run } */
> +/* Call to foo should be devirtualized because there are no derived types of A.  */
> +/* { dg-lto-options "-O2 -flto -fdump-tree-ssa"  } */
> +#include "../ipa/devirt-13.C"
> +/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "ssa"} } */
> Index: testsuite/g++.dg/lto/devirt-14_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-14_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-14_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options "-O2 -fdump-tree-ssa"  } */
> +#include "../ipa/devirt-14.C"
> +/* { dg-final { scan-tree-dump-not "A.*foo" "ssa"} } */
> Index: testsuite/g++.dg/lto/devirt-19_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-19_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-19_0.C	(working copy)
> @@ -0,0 +1,5 @@
> +/* { dg-lto-do link } */
> +/* { dg-lto-options { "-O2 -fdump-ipa-cp -Wno-return-type -flto -r -nostdlib" } } */
> +/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
> +#include "../ipa/devirt-19.C"
> +/* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-1_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-1_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-1_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
> +#include "../ipa/devirt-1.C"
> +/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-22_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-22_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-22_0.C	(working copy)
> @@ -0,0 +1,5 @@
> +/* { dg-lto-do link } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp -flto -r -nostdlib" } } */
> +/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
> +#include "../ipa/devirt-22.C"
> +/* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 2 "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-23_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-23_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-23_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-ipa-sra -flto -fno-devirtualize-speculatively" } } */
> +#include "../ipa/devirt-23.C"
> +/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to" "cp" { xfail *-*-* } } } */
> Index: testsuite/g++.dg/lto/devirt-2_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-2_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-2_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
> +#include "../ipa/devirt-2.C"
> +/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-30_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-30_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-30_0.C	(working copy)
> @@ -0,0 +1,5 @@
> +/* { dg-lto-do link } */
> +/* { dg-lto-options { "-O3 -fdump-ipa-devirt -flto -r -nostdlib" } } */
> +/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
> +#include "../ipa/devirt-30.C"
> +// { dg-final { scan-wpa-ipa-dump-not "Speculatively devirtualizing" "devirt" } }
> Index: testsuite/g++.dg/lto/devirt-34_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-34_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-34_0.C	(working copy)
> @@ -0,0 +1,6 @@
> +/* { dg-lto-do link } */
> +/* { dg-lto-options { "-O2 -fdump-ipa-devirt -flto -r -nostdlib" } } */
> +/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
> +#include "../ipa/devirt-34.C"
> +/* { dg-final { scan-wpa-ipa-dump "Speculative targets"  "devirt"  } } */
> +/* { dg-final { scan-wpa-ipa-dump "1 speculatively devirtualized"  "devirt"  } } */
> Index: testsuite/g++.dg/lto/devirt-3_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-3_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-3_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
> +#include "../ipa/devirt-3.C"
> +/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-4_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-4_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-4_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
> +#include "../ipa/devirt-4.C"
> +/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-5_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-5_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-5_0.C	(working copy)
> @@ -0,0 +1,4 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
> +#include "../ipa/devirt-5.C"
> +/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
> Index: testsuite/g++.dg/lto/devirt-6_0.C
> ===================================================================
> --- testsuite/g++.dg/lto/devirt-6_0.C	(nonexistent)
> +++ testsuite/g++.dg/lto/devirt-6_0.C	(working copy)
> @@ -0,0 +1,3 @@
> +/* { dg-lto-do run } */
> +/* { dg-lto-options { "-O3 -flto" } } */
> +#include "../ipa/devirt-6.C"
> Index: tree.c
> ===================================================================
> --- tree.c	(revision 267337)
> +++ tree.c	(working copy)
> @@ -12838,25 +12838,6 @@ virtual_method_call_p (const_tree target
>     return true;
>   }
>   
> -/* REF is OBJ_TYPE_REF, return the class the ref corresponds to.  */
> -
> -tree
> -obj_type_ref_class (const_tree ref)
> -{
> -  gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF);
> -  ref = TREE_TYPE (ref);
> -  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
> -  ref = TREE_TYPE (ref);
> -  /* We look for type THIS points to.  ObjC also builds
> -     OBJ_TYPE_REF with non-method calls, Their first parameter
> -     ID however also corresponds to class type. */
> -  gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE
> -		       || TREE_CODE (ref) == FUNCTION_TYPE);
> -  ref = TREE_VALUE (TYPE_ARG_TYPES (ref));
> -  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
> -  return TREE_TYPE (ref);
> -}
> -
>   /* Lookup sub-BINFO of BINFO of TYPE at offset POS.  */
>   
>   static tree
Jan Hubicka Dec. 24, 2018, 3:15 p.m. UTC | #2
> UNRESOLVED: g++-dg-lto-devirt-13-01.exe scan-tree-dump-times ssa 
> "OBJ_TYPE_REF" 0
> UNRESOLVED: g++-dg-lto-devirt-13-11.exe scan-tree-dump-times ssa 
> "OBJ_TYPE_REF" 0
> UNRESOLVED: g++-dg-lto-devirt-13-21.exe scan-tree-dump-times ssa 
> "OBJ_TYPE_REF" 0
> UNRESOLVED: g++-dg-lto-devirt-14-01.exe scan-tree-dump-not ssa "A.*foo"
> UNRESOLVED: g++-dg-lto-devirt-14-11.exe scan-tree-dump-not ssa "A.*foo"
> UNRESOLVED: g++-dg-lto-devirt-23-01.exe scan-wpa-ipa-dump cp "Discovered 
> a virtual call to"

Hmm, it looks like tree dumps may not work in lto testsuite.  I guess I
can either disable those tests or move them to ipa directory. I will
take a look.

Honza
Richard Biener Dec. 24, 2018, 7:09 p.m. UTC | #3
On December 24, 2018 4:15:09 PM GMT+01:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>> UNRESOLVED: g++-dg-lto-devirt-13-01.exe scan-tree-dump-times ssa 
>> "OBJ_TYPE_REF" 0
>> UNRESOLVED: g++-dg-lto-devirt-13-11.exe scan-tree-dump-times ssa 
>> "OBJ_TYPE_REF" 0
>> UNRESOLVED: g++-dg-lto-devirt-13-21.exe scan-tree-dump-times ssa 
>> "OBJ_TYPE_REF" 0
>> UNRESOLVED: g++-dg-lto-devirt-14-01.exe scan-tree-dump-not ssa
>"A.*foo"
>> UNRESOLVED: g++-dg-lto-devirt-14-11.exe scan-tree-dump-not ssa
>"A.*foo"
>> UNRESOLVED: g++-dg-lto-devirt-23-01.exe scan-wpa-ipa-dump cp
>"Discovered 
>> a virtual call to"
>
>Hmm, it looks like tree dumps may not work in lto testsuite.  I guess I
>can either disable those tests or move them to ipa directory. I will
>take a look.

IIRC there's ltrans dump variant now? 

>Honza
Jan Hubicka Dec. 24, 2018, 7:17 p.m. UTC | #4
> On December 24, 2018 4:15:09 PM GMT+01:00, Jan Hubicka <hubicka@ucw.cz> wrote:
> >> UNRESOLVED: g++-dg-lto-devirt-13-01.exe scan-tree-dump-times ssa 
> >> "OBJ_TYPE_REF" 0
> >> UNRESOLVED: g++-dg-lto-devirt-13-11.exe scan-tree-dump-times ssa 
> >> "OBJ_TYPE_REF" 0
> >> UNRESOLVED: g++-dg-lto-devirt-13-21.exe scan-tree-dump-times ssa 
> >> "OBJ_TYPE_REF" 0
> >> UNRESOLVED: g++-dg-lto-devirt-14-01.exe scan-tree-dump-not ssa
> >"A.*foo"
> >> UNRESOLVED: g++-dg-lto-devirt-14-11.exe scan-tree-dump-not ssa
> >"A.*foo"
> >> UNRESOLVED: g++-dg-lto-devirt-23-01.exe scan-wpa-ipa-dump cp
> >"Discovered 
> >> a virtual call to"
> >
> >Hmm, it looks like tree dumps may not work in lto testsuite.  I guess I
> >can either disable those tests or move them to ipa directory. I will
> >take a look.
> 
> IIRC there's ltrans dump variant now? 

Those are early opts. I was intending to test whether free lang data
disables the transform.   I will look into that and add also some ltrans
checks.

Honza
> 
> >Honza
>
Richard Biener Dec. 25, 2018, 1:03 p.m. UTC | #5
On December 24, 2018 8:17:51 PM GMT+01:00, Jan Hubicka <hubicka@ucw.cz> wrote:
>> On December 24, 2018 4:15:09 PM GMT+01:00, Jan Hubicka
><hubicka@ucw.cz> wrote:
>> >> UNRESOLVED: g++-dg-lto-devirt-13-01.exe scan-tree-dump-times ssa 
>> >> "OBJ_TYPE_REF" 0
>> >> UNRESOLVED: g++-dg-lto-devirt-13-11.exe scan-tree-dump-times ssa 
>> >> "OBJ_TYPE_REF" 0
>> >> UNRESOLVED: g++-dg-lto-devirt-13-21.exe scan-tree-dump-times ssa 
>> >> "OBJ_TYPE_REF" 0
>> >> UNRESOLVED: g++-dg-lto-devirt-14-01.exe scan-tree-dump-not ssa
>> >"A.*foo"
>> >> UNRESOLVED: g++-dg-lto-devirt-14-11.exe scan-tree-dump-not ssa
>> >"A.*foo"
>> >> UNRESOLVED: g++-dg-lto-devirt-23-01.exe scan-wpa-ipa-dump cp
>> >"Discovered 
>> >> a virtual call to"
>> >
>> >Hmm, it looks like tree dumps may not work in lto testsuite.  I
>guess I
>> >can either disable those tests or move them to ipa directory. I will
>> >take a look.
>> 
>> IIRC there's ltrans dump variant now? 
>
>Those are early opts. I was intending to test whether free lang data
>disables the transform.   I will look into that and add also some
>ltrans
>checks.

Ah, I suppose a - - param free-lang-data might be a good idea for this. 

Richard. 

>
>Honza
>> 
>> >Honza
>>
diff mbox series

Patch

Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 267337)
+++ ipa-devirt.c	(working copy)
@@ -1985,6 +1985,30 @@  add_type_duplicate (odr_type val, tree t
   return build_bases;
 }
 
+/* REF is OBJ_TYPE_REF, return the class the ref corresponds to.  */
+
+tree
+obj_type_ref_class (const_tree ref)
+{
+  gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF);
+  ref = TREE_TYPE (ref);
+  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
+  ref = TREE_TYPE (ref);
+  /* We look for type THIS points to.  ObjC also builds
+     OBJ_TYPE_REF with non-method calls, Their first parameter
+     ID however also corresponds to class type. */
+  gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE
+		       || TREE_CODE (ref) == FUNCTION_TYPE);
+  ref = TREE_VALUE (TYPE_ARG_TYPES (ref));
+  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
+  tree ret = TREE_TYPE (ref);
+  if (!in_lto_p)
+    ret = TYPE_CANONICAL (ret);
+  else
+    ret = get_odr_type (ret)->type;
+  return ret;
+}
+
 /* Get ODR type hash entry for TYPE.  If INSERT is true, create
    possibly new entry.  */
 
@@ -2000,6 +2024,8 @@  get_odr_type (tree type, bool insert)
   int base_id = -1;
 
   type = TYPE_MAIN_VARIANT (type);
+  if (!in_lto_p)
+    type = TYPE_CANONICAL (type);
 
   gcc_checking_assert (can_be_name_hashed_p (type)
 		       || can_be_vtable_hashed_p (type));
Index: testsuite/g++.dg/ipa/devirt-30.C
===================================================================
--- testsuite/g++.dg/ipa/devirt-30.C	(revision 267337)
+++ testsuite/g++.dg/ipa/devirt-30.C	(working copy)
@@ -1,4 +1,5 @@ 
 // PR c++/58678
+// { dg-do compile }
 // { dg-options "-O3 -fdump-ipa-devirt" }
 
 // We shouldn't speculatively devirtualize to ~B because B is an abstract
Index: testsuite/g++.dg/lto/devirt-13_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-13_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-13_0.C	(working copy)
@@ -0,0 +1,5 @@ 
+/* { dg-lto-do run } */
+/* Call to foo should be devirtualized because there are no derived types of A.  */
+/* { dg-lto-options "-O2 -flto -fdump-tree-ssa"  } */
+#include "../ipa/devirt-13.C"
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "ssa"} } */
Index: testsuite/g++.dg/lto/devirt-14_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-14_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-14_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options "-O2 -fdump-tree-ssa"  } */
+#include "../ipa/devirt-14.C"
+/* { dg-final { scan-tree-dump-not "A.*foo" "ssa"} } */
Index: testsuite/g++.dg/lto/devirt-19_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-19_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-19_0.C	(working copy)
@@ -0,0 +1,5 @@ 
+/* { dg-lto-do link } */
+/* { dg-lto-options { "-O2 -fdump-ipa-cp -Wno-return-type -flto -r -nostdlib" } } */
+/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
+#include "../ipa/devirt-19.C"
+/* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-1_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-1_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-1_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
+#include "../ipa/devirt-1.C"
+/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-22_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-22_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-22_0.C	(working copy)
@@ -0,0 +1,5 @@ 
+/* { dg-lto-do link } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp -flto -r -nostdlib" } } */
+/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
+#include "../ipa/devirt-22.C"
+/* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 2 "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-23_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-23_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-23_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-ipa-sra -flto -fno-devirtualize-speculatively" } } */
+#include "../ipa/devirt-23.C"
+/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to" "cp" { xfail *-*-* } } } */
Index: testsuite/g++.dg/lto/devirt-2_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-2_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-2_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
+#include "../ipa/devirt-2.C"
+/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-30_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-30_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-30_0.C	(working copy)
@@ -0,0 +1,5 @@ 
+/* { dg-lto-do link } */
+/* { dg-lto-options { "-O3 -fdump-ipa-devirt -flto -r -nostdlib" } } */
+/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
+#include "../ipa/devirt-30.C"
+// { dg-final { scan-wpa-ipa-dump-not "Speculatively devirtualizing" "devirt" } }
Index: testsuite/g++.dg/lto/devirt-34_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-34_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-34_0.C	(working copy)
@@ -0,0 +1,6 @@ 
+/* { dg-lto-do link } */
+/* { dg-lto-options { "-O2 -fdump-ipa-devirt -flto -r -nostdlib" } } */
+/* { dg-extra-ld-options "-flinker-output=nolto-rel" } */
+#include "../ipa/devirt-34.C"
+/* { dg-final { scan-wpa-ipa-dump "Speculative targets"  "devirt"  } } */
+/* { dg-final { scan-wpa-ipa-dump "1 speculatively devirtualized"  "devirt"  } } */
Index: testsuite/g++.dg/lto/devirt-3_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-3_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-3_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
+#include "../ipa/devirt-3.C"
+/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-4_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-4_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-4_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
+#include "../ipa/devirt-4.C"
+/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-5_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-5_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-5_0.C	(working copy)
@@ -0,0 +1,4 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized -flto" } } */
+#include "../ipa/devirt-5.C"
+/* { dg-final { scan-wpa-ipa-dump "Discovered a virtual call to a known target.*foo"  "cp"  } } */
Index: testsuite/g++.dg/lto/devirt-6_0.C
===================================================================
--- testsuite/g++.dg/lto/devirt-6_0.C	(nonexistent)
+++ testsuite/g++.dg/lto/devirt-6_0.C	(working copy)
@@ -0,0 +1,3 @@ 
+/* { dg-lto-do run } */
+/* { dg-lto-options { "-O3 -flto" } } */
+#include "../ipa/devirt-6.C"
Index: tree.c
===================================================================
--- tree.c	(revision 267337)
+++ tree.c	(working copy)
@@ -12838,25 +12838,6 @@  virtual_method_call_p (const_tree target
   return true;
 }
 
-/* REF is OBJ_TYPE_REF, return the class the ref corresponds to.  */
-
-tree
-obj_type_ref_class (const_tree ref)
-{
-  gcc_checking_assert (TREE_CODE (ref) == OBJ_TYPE_REF);
-  ref = TREE_TYPE (ref);
-  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
-  ref = TREE_TYPE (ref);
-  /* We look for type THIS points to.  ObjC also builds
-     OBJ_TYPE_REF with non-method calls, Their first parameter
-     ID however also corresponds to class type. */
-  gcc_checking_assert (TREE_CODE (ref) == METHOD_TYPE
-		       || TREE_CODE (ref) == FUNCTION_TYPE);
-  ref = TREE_VALUE (TYPE_ARG_TYPES (ref));
-  gcc_checking_assert (TREE_CODE (ref) == POINTER_TYPE);
-  return TREE_TYPE (ref);
-}
-
 /* Lookup sub-BINFO of BINFO of TYPE at offset POS.  */
 
 static tree