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 <ja...@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 <ja...@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; }
typebound_call_21.f03
Description: Binary data