Patchwork [PR,46120] Fix get_binfo_at_offset

login
register
mail settings
Submitter Martin Jambor
Date Nov. 1, 2010, 3:53 p.m.
Message ID <20101101155316.GD16393@virgil.arch.suse.de>
Download mbox | patch
Permalink /patch/69796/
State New
Headers show

Comments

Martin Jambor - Nov. 1, 2010, 3:53 p.m.
Hi,

just like in the previous email, the correct way of detecting and
ignoring the primary base classes is to test that their field offset
is zero.  This patch does that in get_binfo_at_offset, which fixes PR
46120.

Bootstrapped and tested on x86_64-linux and also passes check-c++ on
i686.  OK for trunk?

Thanks,

Martin


2010-10-27  Martin Jambor  <mjambor@suse.cz>

	PR middle-end/46120
	* tree.c (get_binfo_at_offset): Bail out on artificial
	fields. Identify primary bases according to their offsets.

	* testsuite/g++.dg/ipa/ivinline-9.C: New test.
Jason Merrill - Nov. 1, 2010, 7:36 p.m.
OK, but please add comments here and in gimple_get_relevant_ref_binfo to 
indicate why you're checking for offset 0: because that indicates the 
primary base, whose vtable contents are represented in the binfo for the 
derived class.

Jason

Patch

Index: icln/gcc/tree.c
===================================================================
--- icln.orig/gcc/tree.c
+++ icln/gcc/tree.c
@@ -10906,16 +10906,17 @@  lhd_gcc_personality (void)
 tree
 get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type)
 {
-  tree type;
+  tree type = TREE_TYPE (binfo);
 
-  type = TREE_TYPE (binfo);
-  while (offset > 0)
+  while (true)
     {
-      tree base_binfo, found_binfo;
       HOST_WIDE_INT pos, size;
       tree fld;
       int i;
 
+      gcc_checking_assert (offset >= 0);
+      if (type == expected_type)
+	  return binfo;
       if (TREE_CODE (type) != RECORD_TYPE)
 	return NULL_TREE;
 
@@ -10929,27 +10930,26 @@  get_binfo_at_offset (tree binfo, HOST_WI
 	  if (pos <= offset && (pos + size) > offset)
 	    break;
 	}
-      if (!fld)
+      if (!fld || !DECL_ARTIFICIAL (fld))
 	return NULL_TREE;
 
-      found_binfo = NULL_TREE;
-      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
-	if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
-	  {
-	    found_binfo = base_binfo;
-	    break;
-	  }
-
-      if (!found_binfo)
-	return NULL_TREE;
+      if (offset != 0)
+	{
+	  tree base_binfo, found_binfo = NULL_TREE;
+	  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+	    if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
+	      {
+		found_binfo = base_binfo;
+		break;
+	      }
+	  if (!found_binfo)
+	    return NULL_TREE;
+	  binfo = found_binfo;
+	}
 
       type = TREE_TYPE (fld);
-      binfo = found_binfo;
       offset -= pos;
     }
-  if (type != expected_type)
-    return NULL_TREE;
-  return binfo;
 }
 
 /* Returns true if X is a typedef decl.  */
Index: icln/gcc/testsuite/g++.dg/ipa/ivinline-9.C
===================================================================
--- /dev/null
+++ icln/gcc/testsuite/g++.dg/ipa/ivinline-9.C
@@ -0,0 +1,93 @@ 
+/* Verify that simple virtual calls are inlined even without early
+   inlining, even when a typecast to an ancestor is involved along the
+   way and that ancestor itself has an ancestor wich is not the
+   primary base class.  */
+/* { dg-do run } */
+/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp"  } */
+
+extern "C" void abort (void);
+
+class Distraction
+{
+public:
+  float f;
+  double d;
+  Distraction ()
+  {
+    f = 8.3;
+    d = 10.2;
+  }
+  virtual float bar (float z);
+};
+
+class A
+{
+public:
+  int data;
+  virtual int foo (int i);
+};
+/*
+class D2
+{
+public:
+  virtual float baz (float z)
+  {
+    abort();
+  }
+};
+*/
+class A2 : public Distraction, public A
+{
+  int i2;
+};
+
+class B : public A2
+{
+public:
+  virtual int foo (int i);
+};
+
+float Distraction::bar (float z)
+{
+  f += z;
+  return f/2;
+}
+
+int A::foo (int i)
+{
+  return i + 1;
+}
+
+int B::foo (int i)
+{
+  return i + 2;
+}
+
+int __attribute__ ((noinline,noclone)) get_input(void)
+{
+  return 1;
+}
+
+static int middleman_1 (class A *obj, int i)
+{
+  return obj->foo (i);
+}
+
+static int middleman_2 (class B *obj, int i)
+{
+  return middleman_1 (obj, i);
+}
+
+int main (int argc, char *argv[])
+{
+  class B b;
+  int i;
+
+  for (i = 0; i < get_input (); i++)
+    if (middleman_2 (&b, get_input ()) != 3)
+      abort ();
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main"  "inline"  } } */
+/* { dg-final { cleanup-ipa-dump "inline" } } */