This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, Fortran, OOP] PR 50919: Don't use vtable for NON_OVERRIDABLE TBP


Hi all,

up to now we call all type-bound procedures in a dynamic way, i.e.
through their entry in the vtable. However, for non-overridable
procedures this is not necessary. Since they can not be overridden, a
call to those can be resolved at compile time to an ordinary function
call, without the need of a 'detour' through the vtable. This is what
the attached patch does, thereby removing unneeded overhead and
improving the possibility of optimization (inlining, etc).

The patch actually consists of two parts:
1) The resolve.c part prevents the conversion to a PPC call via the
_vptr (for functions and subroutines).
2) The class.c parts prevents adding the non-overridable TBP to the vtable.

As noted by Tobias, the second part breaks the ABI, so we might
consider deferring it until other ABI-breaking features will be
implemented (cf. http://gcc.gnu.org/wiki/LibgfortranAbiCleanup). On
the other hand, one could argue that the OOP ABI is still quite young
and hasn't really stabilized yet (it was broken already from 4.5 to
4.6), so we might as well break it again. I know that there are a
couple of real-world codes out there, which make use of gfortran's OOP
features already, but I have a hard time estimating how many such
projects exists, or how problematic an ABI breaking would be for them
(user input welcome).

So, the question is: Should I commit both parts, or only the resolve.c
one for now? The patch was regtested on x86_64-unknown-linux-gnu.

Cheers,
Janus


2011-11-06  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/50919
	* class.c (add_proc_comp): Don't add non-overridable procedures to the
	vtable.
	* resolve.c (resolve_typebound_function,resolve_typebound_subroutine):
	Don't generate a dynamic _vptr call for non-overridable procedures.

2011-11-06  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/50919
	* gfortran.dg/typebound_call_21.f03: New.
Index: gcc/fortran/class.c
===================================================================
--- gcc/fortran/class.c	(revision 181043)
+++ gcc/fortran/class.c	(working copy)
@@ -288,6 +288,10 @@ static void
 add_proc_comp (gfc_symbol *vtype, const char *name, gfc_typebound_proc *tb)
 {
   gfc_component *c;
+
+  if (tb->non_overridable)
+    return;
+  
   c = gfc_find_component (vtype, name, true, true);
 
   if (c == NULL)
Index: gcc/fortran/resolve.c
===================================================================
--- gcc/fortran/resolve.c	(revision 181044)
+++ gcc/fortran/resolve.c	(working copy)
@@ -5868,11 +5868,13 @@ resolve_typebound_function (gfc_expr* e)
   const char *name;
   gfc_typespec ts;
   gfc_expr *expr;
+  bool overridable;
 
   st = e->symtree;
 
   /* Deal with typebound operators for CLASS objects.  */
   expr = e->value.compcall.base_object;
+  overridable = !e->value.compcall.tbp->non_overridable;
   if (expr && expr->ts.type == BT_CLASS && e->value.compcall.name)
     {
       /* Since the typebound operators are generic, we have to ensure
@@ -5923,22 +5925,26 @@ resolve_typebound_function (gfc_expr* e)
     return FAILURE;
   ts = e->ts;
 
-  /* Then convert the expression to a procedure pointer component call.  */
-  e->value.function.esym = NULL;
-  e->symtree = st;
+  if (overridable)
+    {
+      /* Convert the expression to a procedure pointer component call.  */
+      e->value.function.esym = NULL;
+      e->symtree = st;
 
-  if (new_ref)  
-    e->ref = new_ref;
+      if (new_ref)  
+	e->ref = new_ref;
 
-  /* '_vptr' points to the vtab, which contains the procedure pointers.  */
-  gfc_add_vptr_component (e);
-  gfc_add_component_ref (e, name);
+      /* '_vptr' points to the vtab, which contains the procedure pointers.  */
+      gfc_add_vptr_component (e);
+      gfc_add_component_ref (e, name);
 
-  /* Recover the typespec for the expression.  This is really only
-     necessary for generic procedures, where the additional call
-     to gfc_add_component_ref seems to throw the collection of the
-     correct typespec.  */
-  e->ts = ts;
+      /* Recover the typespec for the expression.  This is really only
+	necessary for generic procedures, where the additional call
+	to gfc_add_component_ref seems to throw the collection of the
+	correct typespec.  */
+      e->ts = ts;
+    }
+
   return SUCCESS;
 }
 
@@ -5957,11 +5963,13 @@ resolve_typebound_subroutine (gfc_code *code)
   const char *name;
   gfc_typespec ts;
   gfc_expr *expr;
+  bool overridable;
 
   st = code->expr1->symtree;
 
   /* Deal with typebound operators for CLASS objects.  */
   expr = code->expr1->value.compcall.base_object;
+  overridable = !code->expr1->value.compcall.tbp->non_overridable;
   if (expr && expr->ts.type == BT_CLASS && code->expr1->value.compcall.name)
     {
       /* Since the typebound operators are generic, we have to ensure
@@ -6006,22 +6014,26 @@ resolve_typebound_subroutine (gfc_code *code)
     return FAILURE;
   ts = code->expr1->ts;
 
-  /* Then convert the expression to a procedure pointer component call.  */
-  code->expr1->value.function.esym = NULL;
-  code->expr1->symtree = st;
+  if (overridable)
+    {
+      /* Convert the expression to a procedure pointer component call.  */
+      code->expr1->value.function.esym = NULL;
+      code->expr1->symtree = st;
 
-  if (new_ref)
-    code->expr1->ref = new_ref;
+      if (new_ref)
+	code->expr1->ref = new_ref;
 
-  /* '_vptr' points to the vtab, which contains the procedure pointers.  */
-  gfc_add_vptr_component (code->expr1);
-  gfc_add_component_ref (code->expr1, name);
+      /* '_vptr' points to the vtab, which contains the procedure pointers.  */
+      gfc_add_vptr_component (code->expr1);
+      gfc_add_component_ref (code->expr1, name);
 
-  /* Recover the typespec for the expression.  This is really only
-     necessary for generic procedures, where the additional call
-     to gfc_add_component_ref seems to throw the collection of the
-     correct typespec.  */
-  code->expr1->ts = ts;
+      /* Recover the typespec for the expression.  This is really only
+	necessary for generic procedures, where the additional call
+	to gfc_add_component_ref seems to throw the collection of the
+	correct typespec.  */
+      code->expr1->ts = ts;
+    }
+
   return SUCCESS;
 }
 

Attachment: typebound_call_21.f03
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]