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: improve expansion of C++ pointer to member function constants


When expanding a pointer to member function constant, the C++ front
end fails to extract the delta field, generating instead a
COMPONENT_REF of unknown value.  This interferes with folding, and can
result in failed optimizations.

For example, consider the following code fragment:

  struct S {
    void f () {};
  };

  template<void (S::*pf) ()> void g(S &s)
  {
    (s.*pf) ();    // s.f ()
  }

  void h ()
  {
    S s;

    g<&S::f> (s);
  }

Replacing (s.*pf) () with s.f (), should generate identical code.
However, with -O0 on x86, the code as is generates a block like:

        movl    $_ZN1S1fEv, %eax
        movl    $0, %edx
        movl    %edx, %eax
        addl    8(%ebp), %eax
        movl    %eax, (%esp)
        call    _ZN1S1fEv

The assembly with s.f () is the much simpler:

        movl    8(%ebp), %eax
        movl    %eax, (%esp)
        call    _ZN1S1fEv

Things get even worse when optimization is enabled.  With -O2, the
calls are all inlined.  However, in the first case, the definition of
_ZN1S1fEv is not removed, resulting in excess code generation.

This patch resolves the problem by adding a delta_from_ptrmemfunc
function which mirrors the behavior of the existing
pfn_from_ptrmemfunc function.  With this improvement, the code
generated by the two examples is identical.

Tested with a C/C++/Java bootstrap and testsuite on i686-pc-linux-gnu.

Ollie

:ADDPATCH c++:

2007-11-14  Ollie Wild  <aaw@google.com>

        * typeck.c (delta_from_ptrmemfunc): New function.
        (get_member_function_from_ptrfunc): Call delta_from_ptrmemfunc.
        (build_binary_op): Call delta_from_ptrmemfunc.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index d167de2..da46bb3 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "params.h"
 
 static tree pfn_from_ptrmemfunc (tree);
+static tree delta_from_ptrmemfunc (tree);
 static tree convert_for_assignment (tree, tree, const char *, tree, int);
 static tree cp_pointer_int_sum (enum tree_code, tree, tree);
 static tree rationalize_conditional_expr (enum tree_code, tree);
@@ -2586,7 +2587,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
 
       /* Start by extracting all the information from the PMF itself.  */
       e3 = pfn_from_ptrmemfunc (function);
-      delta = build_ptrmemfunc_access_expr (function, delta_identifier);
+      delta = delta_from_ptrmemfunc (function);
       idx = build1 (NOP_EXPR, vtable_index_type, e3);
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
 	{
@@ -3370,8 +3371,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 	      == ptrmemfunc_vbit_in_delta)
 	    {
 	      tree pfn0 = pfn_from_ptrmemfunc (op0);
-	      tree delta0 = build_ptrmemfunc_access_expr (op0,
-			 	 			  delta_identifier);
+	      tree delta0 = delta_from_ptrmemfunc (op0);
 	      tree e1 = cp_build_binary_op (EQ_EXPR,
 	  			            pfn0,	
 				      	    fold_convert (TREE_TYPE (pfn0),
@@ -3412,10 +3412,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
 	  pfn0 = pfn_from_ptrmemfunc (op0);
 	  pfn1 = pfn_from_ptrmemfunc (op1);
-	  delta0 = build_ptrmemfunc_access_expr (op0,
-						 delta_identifier);
-	  delta1 = build_ptrmemfunc_access_expr (op1,
-						 delta_identifier);
+	  delta0 = delta_from_ptrmemfunc (op0);
+	  delta1 = delta_from_ptrmemfunc (op1);
 	  if (TARGET_PTRMEMFUNC_VBIT_LOCATION
 	      == ptrmemfunc_vbit_in_delta)
 	    {
@@ -6290,6 +6288,25 @@ pfn_from_ptrmemfunc (tree t)
   return build_ptrmemfunc_access_expr (t, pfn_identifier);
 }
 
+/* Return an expression for DELTA from the pointer-to-member function
+   given by T.  */
+
+static tree
+delta_from_ptrmemfunc (tree t)
+{
+  if (TREE_CODE (t) == PTRMEM_CST)
+    {
+      tree delta;
+      tree pfn;
+
+      expand_ptrmemfunc_cst (t, &delta, &pfn);
+      if (delta)
+	return delta;
+    }
+
+  return build_ptrmemfunc_access_expr (t, delta_identifier);
+}
+
 /* Convert value RHS to type TYPE as preparation for an assignment to
    an lvalue of type TYPE.  ERRTYPE is a string to use in error
    messages: "assignment", "return", etc.  If FNDECL is non-NULL, we

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