Notes:
    This patch optimizes out calls to __dynamic_cast when the type being cast 
to is final (or its destructor), replacing them with a simple comparison of the 
types' vtable addresses. This is already implemented and done by default in 
clang (https://review
    s.llvm.org/D154658), but can be turned off with -fno-assume-unique-vtables, 
due to the problems it can cause with unmerged vtables when using shared 
libraries. With the optimization not really fitting well under any existing 
flag (that I know of), I believe an -fassume-unique-vtables flag (or something 
similar) would be appropriate to add to gcc, which besides enabling this 
optimization, should probably also define __GXX_MERGED_TYPEINFO_NAMES as 1. I 
believe instead of adding this flag and the vtable addr comparison logic, just 
replacing __dynamic_cast with type_info::operator== (whose behaviour depends on 
__GXX_MERGED_TYPEINFO_NAMES) is insufficient as it performs additional 
dereferences compared to a simple vtable addr comparison, still leaving room 
for further optimization.

 gcc/c-family/c.opt                    |  4 ++
 gcc/cp/rtti.cc                        | 55 +++++++++++++++++++++++++
 gcc/testsuite/g++.dg/rtti/dyncast10.C | 58 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/rtti/dyncast9.C  | 58 +++++++++++++++++++++++++++
 4 files changed, 175 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/rtti/dyncast10.C
 create mode 100644 gcc/testsuite/g++.dg/rtti/dyncast9.C

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 12877eb0e17..b597df70bfe 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1719,6 +1719,10 @@ fassume-sane-operators-new-delete
 C++ ObjC++ Optimization Var(flag_assume_sane_operators_new_delete) Init(1)
 Assume C++ replaceable global operators new, new[], delete, delete[] don't 
read or write visible global state.

+fassume-unique-vtables
+C++ ObjC++ Optimization Var(flag_assume_unique_vtables) Init(0)
+Assume that, throughout the program's lifetime, each pair of class types 
representing the same class shares a common vtable.
+
 ; Define extra predefined macros for use in libgcc.
 fbuilding-libgcc
 C ObjC C++ ObjC++ Undocumented Var(flag_building_libgcc)
diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc
index c06a18b3ff1..7227386ddbf 100644
--- a/gcc/cp/rtti.cc
+++ b/gcc/cp/rtti.cc
@@ -761,6 +761,61 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
       if (tc == REFERENCE_TYPE)
         expr1 = cp_build_addr_expr (expr1, complain);

+
+
+    /* If type is final, don't call dynamic_cast.
+     * Instead just check vtable equivalence at runtime.
+     * TYPE_FINAL_P does not return true for non-final class with
+     * final destructor overriding virtual though,
+     * so look through virtual functions for final destructor */
+
+    bool can_inherit = true;
+    if(flag_assume_unique_vtables)
+      {
+        can_inherit = !TYPE_FINAL_P (target_type);
+        tree vchain;
+        for (vchain = BINFO_VIRTUALS (TYPE_BINFO (target_type));
+          vchain && can_inherit;
+          vchain = TREE_CHAIN (vchain))
+    {
+      if (!DECL_DESTRUCTOR_P (BV_FN (vchain)))
+        continue;
+      if (!DECL_FINAL_P (BV_FN (vchain)))
+        continue;
+      can_inherit = false;
+    }
+      }
+
+    if (!can_inherit)
+      {
+        tree binfo = lookup_base (target_type, static_type, ba_check, NULL, 
complain);
+
+          if (!binfo || binfo == error_mark_node)
+              return error_mark_node;
+
+        /* Retrieve vtable declaration and address.
+         * The offset-to-top field is adjusted for here. */
+        tree trgt_vptr = build_vtbl_address (
+                BINFO_VTABLE (binfo) ? binfo : TYPE_BINFO (target_type));
+
+        tree src_obj = cp_build_fold_indirect_ref (expr);
+        tree src_vptr = build_vfield_ref (src_obj, static_type);
+
+        tree fail_result = tc == REFERENCE_TYPE ? throw_bad_cast () : 
nullptr_node;
+        tree succ_result = build_base_path (MINUS_EXPR, expr1, binfo, true, 
complain);
+
+        /* Check vtable equivalence by vptr address */
+        tree cond = build2 (NE_EXPR, boolean_type_node, trgt_vptr, src_vptr);
+        tree result = build3 (COND_EXPR, type, cond, fail_result, succ_result);
+
+        SET_EXPR_LOCATION (result, loc);
+
+        if (tc == REFERENCE_TYPE)
+          return result;
+
+        return build_if_nonnull (expr, result, complain);
+      }
+
       elems[0] = expr1;
       elems[1] = td3;
       elems[2] = td2;
diff --git a/gcc/testsuite/g++.dg/rtti/dyncast10.C 
b/gcc/testsuite/g++.dg/rtti/dyncast10.C
new file mode 100644
index 00000000000..e4c9b303cef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/rtti/dyncast10.C
@@ -0,0 +1,58 @@
+// { dg-options "-fassume-unique-vtables" }
+// { dg-final { scan-tree-dump-not "__dynamic_cast" "original" } }
+
+extern "C" void abort ();
+
+struct A
+{
+  virtual ~A () {}
+};
+
+struct B final : public A
+{
+  ~B() {}
+  void p () { c++; }
+  int c;
+};
+struct C final : public A
+{
+  ~C() {}
+  void f () { c++; }
+  int c;
+};
+
+
+bool f (A* a) {
+  return dynamic_cast<B*>(a) != nullptr;
+}
+bool g (A& a) {
+  try
+    {
+      dynamic_cast<B&>(a).p();
+      return true;
+    }
+  catch (...)
+    {
+      return false;
+    }
+}
+
+int
+main (void)
+{
+  A a;
+  B b;
+  C c;
+  if (f (&a))
+    abort ();
+  if (g (a))
+    abort ();
+  if (!f (&b))
+    abort ();
+  if (!g (b))
+    abort ();
+  if (f (&c))
+    abort ();
+  if (g (c))
+    abort ();
+}
diff --git a/gcc/testsuite/g++.dg/rtti/dyncast9.C 
b/gcc/testsuite/g++.dg/rtti/dyncast9.C
new file mode 100644
index 00000000000..4f3b2348d13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/rtti/dyncast9.C
@@ -0,0 +1,58 @@
+// { dg-options "-fassume-unique-vtables" }
+// { dg-final { scan-tree-dump-not "__dynamic_cast" "original" } }
+
+extern "C" void abort ();
+
+struct A
+{
+  virtual ~A () {}
+};
+
+struct B : public A
+{
+  ~B() final {}
+  void p () { c++; }
+  int c;
+};
+struct C : public A
+{
+  ~C() final {}
+  void f () { c++; }
+  int c;
+};
+
+
+bool f (A* a) {
+  return dynamic_cast<B*>(a) != nullptr;
+}
+bool g (A& a) {
+  try
+    {
+      dynamic_cast<B&>(a).p();
+      return true;
+    }
+  catch (...)
+    {
+      return false;
+    }
+}
+
+int
+main (void)
+{
+  A a;
+  B b;
+  C c;
+  if (f (&a))
+    abort ();
+  if (g (a))
+    abort ();
+  if (!f (&b))
+    abort ();
+  if (!g (b))
+    abort ();
+  if (f (&c))
+    abort ();
+  if (g (c))
+    abort ();
+}
--
2.34.1




This e-mail and any attachments may contain information that is confidential 
and proprietary and otherwise protected from disclosure. If you are not the 
intended recipient of this e-mail, do not read, duplicate or redistribute it by 
any means. Please immediately delete it and any attachments and notify the 
sender that you have received it by mistake. Unintended recipients are 
prohibited from taking action on the basis of information in this e-mail or any 
attachments. The DRW Companies make no representations that this e-mail or any 
attachments are free of computer viruses or other defects.

Reply via email to