This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[lto] Fix gimple_types_compatible_p
- From: Diego Novillo <dnovillo at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 23 Feb 2009 08:33:44 -0500
- Subject: [lto] Fix gimple_types_compatible_p
I've been meaning to revise this for a while. The quirky version
we had before was causing SRA to get confused because CCP was
folding a structure reference the wrong way (thinking that struct
Bar and struct Baz were compatible in this test case).
The change to free_lang_data_in_type is needed to remove
TYPE_DECLs from unions. Otherwise, gimple_types_compatible_p was
getting into infinite recursion cycles.
Tested on x86_64 and i686.
Diego.
* gimple.c (gimple_types_compatible_p): Call itself
recursively when comparing fields of aggregates.
Handle unions.
Honor TYPE_CANONICAL and pointer equality.
* tree.c (free_lang_data_in_type): Remove non-FIELD_DECLs
from UNION_TYPE and QUAL_UNION_TYPE.
testsuite/ChangeLog.lto
* gcc.dg/lto/20090219_0.c: Add -fPIC.
* g++.dg/lto/20090221_0.C: New.
Index: tree.c
===================================================================
--- tree.c (revision 144372)
+++ tree.c (working copy)
@@ -3825,9 +3825,11 @@ free_lang_data_in_type (tree type)
}
}
- /* Remove members that are not actually FIELD_DECLs
- from the field list of a record. These occur in C++. */
- if (TREE_CODE (type) == RECORD_TYPE)
+ /* Remove members that are not actually FIELD_DECLs from the field
+ list of an aggregate. These occur in C++. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE)
{
tree prev, member;
Index: gimple.c
===================================================================
--- gimple.c (revision 144329)
+++ gimple.c (working copy)
@@ -3193,30 +3193,47 @@ gimple_call_copy_skip_args (gimple stmt,
}
-/* Return 1 if TYPE1 and TYPE2 are structurally compatible and/or they
- have the same main variant. */
+/* Return 1 if TYPE1 and TYPE2 are structurally compatible. */
int
gimple_types_compatible_p (tree type1, tree type2)
{
+ /* Types are trivially compatible with themselves. */
+ if (type1 == type2)
+ return 1;
+
+ /* Only types with the same code can be compatible. */
+ if (TREE_CODE (type1) != TREE_CODE (type2))
+ return 0;
+
+ /* If the main variants or their canonical type are the same, then
+ they are compatible. */
+ if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
+ || TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2))
+ return 1;
+
+ /* In the case of aggregates, check structural equality. Note that
+ at this point, TYPE1 and TYPE2 are guaranteed to have the same
+ code already. */
if (TREE_CODE (type1) == RECORD_TYPE
- && TREE_CODE (type2) == RECORD_TYPE)
+ || TREE_CODE (type1) == UNION_TYPE
+ || TREE_CODE (type1) == QUAL_UNION_TYPE)
{
- /* Check structural equality. */
tree f1, f2;
for (f1 = TYPE_FIELDS (type1), f2 = TYPE_FIELDS (type2);
f1 && f2;
f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
- {
- if (TREE_CODE (f1) != TREE_CODE (f2)
- || DECL_NAME (f1) != DECL_NAME (f2))
- break;
- }
+ if (!gimple_types_compatible_p (TREE_TYPE (f1), TREE_TYPE (f2)))
+ return 0;
- return f1 && f2 ? 0 : 1;
+ /* If one aggregate is bigger than the other, then they are not
+ compatible. */
+ return f1 || f2 ? 0 : 1;
}
- return TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2);
+ /* In any other case, the two types are not compatible. */
+ return 0;
}
+
#include "gt-gimple.h"
Index: testsuite/gcc.dg/lto/20090219_0.c
===================================================================
--- testsuite/gcc.dg/lto/20090219_0.c (revision 144329)
+++ testsuite/gcc.dg/lto/20090219_0.c (working copy)
@@ -1,5 +1,5 @@
/* { dg-do link } */
-/* { dg-options "{-O3 -fwhopr -shared}" } */
+/* { dg-options "{-O3 -fwhopr -fPIC -shared}" } */
struct Foo { int f1, f2, f3, f4, f5; };
Index: testsuite/g++.dg/lto/20090221_0.C
===================================================================
--- testsuite/g++.dg/lto/20090221_0.C (revision 0)
+++ testsuite/g++.dg/lto/20090221_0.C (revision 0)
@@ -0,0 +1,53 @@
+// { dg-do compile }
+extern void some_function (const char *);
+extern bool some_other_function ();
+
+struct Foo
+{
+ long long a;
+ int b;
+};
+
+bool Foo_eq(Foo x, Foo y)
+{
+ return x.a == y.a && x.b == y.b;
+}
+
+struct Bar
+{
+ Foo a;
+ int b;
+};
+
+struct Baz
+{
+ Bar a;
+ Baz(Bar &a):a(a) { }
+};
+
+struct Zonk
+{
+ Baz baz;
+
+ Bar func_1(const Bar & bar) {
+ if (Foo_eq(bar.a, baz.a.a) && bar.b == baz.a.b || some_other_function ())
+ return bar;
+ }
+
+ void func_2(const Baz & baz) {
+ func_1(baz.a);
+ some_function(__PRETTY_FUNCTION__);
+ }
+};
+
+void func() {
+ Bar bar;
+ Zonk *rep;
+ rep->func_1(bar);
+ rep->func_2(Baz(bar));
+}
+
+void foo ()
+{
+ func();
+}