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]

C++ PATCH: PR 16405


This patch fixes a C++ optimization problem.  In the case of the code
in the attached test case, the compiler was generating a temporary for
"a + b", as expected.  Then, for the call to the (implicitly declared)
assignment operator "T::operator=", we generated another temporary, to
bind to the const reference parameter to the assignment operator.
That's permitted, but silly.

The problem was that the front-end generates:

  memcpy (&a, *(const T*)&<target_expr operator+(b, c)>, sizeof (T))

The gimplifier could not see through the INDIRECT_REF/ADDR_EXPR
combination to find the underlying TARGET_EXPR, and so generate a
temporary for it.  One approach would be to change the front end not
to adjust things to elide those nodes, but the same kind of thing can
occur in user code.  So, I made the gimplifier smarter.

Tested on x86_64-unknown-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-12-23  Mark Mitchell  <mark@codesourcery.com>

	PR c++/16405
	* gimplify.c (gimplify_modify_expr_rhs): Handle
	INDIRECT_REF/ADDR_EXPR combinations.

2004-12-23  Mark Mitchell  <mark@codesourcery.com>

	PR c++/16405
	* g++.dg/opt/temp1.C: New test.

Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.95
diff -c -5 -p -r2.95 gimplify.c
*** gimplify.c	21 Dec 2004 19:27:07 -0000	2.95
--- gimplify.c	23 Dec 2004 07:58:26 -0000
*************** gimplify_modify_expr_rhs (tree *expr_p, 
*** 2794,2803 ****
--- 2794,2830 ----
    enum gimplify_status ret = GS_OK;
  
    while (ret != GS_UNHANDLED)
      switch (TREE_CODE (*from_p))
        {
+       case INDIRECT_REF:
+ 	{
+ 	  /* If we have code like 
+ 
+ 	        *(const A*)(A*)&x
+ 
+ 	     where the type of "x" is a (possibly cv-qualified variant
+ 	     of "A"), treat the entire expression as identical to "x".
+ 	     This kind of code arises in C++ when an object is bound
+ 	     to a const reference, and if "x" is a TARGET_EXPR we want
+ 	     to take advantage of the optimization below.  */
+ 	  tree pointer;
+ 
+ 	  pointer = TREE_OPERAND (*from_p, 0);
+ 	  STRIP_NOPS (pointer);
+ 	  if (TREE_CODE (pointer) == ADDR_EXPR
+ 	      && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))
+ 		  == TYPE_MAIN_VARIANT (TREE_TYPE (*from_p))))
+ 	    {
+ 	      *from_p = TREE_OPERAND (pointer, 0); 
+ 	      ret = GS_OK;
+ 	    }
+ 	  else
+ 	    ret = GS_UNHANDLED;
+ 	  break;
+ 	}
+ 
        case TARGET_EXPR:
  	{
  	  /* If we are initializing something from a TARGET_EXPR, strip the
  	     TARGET_EXPR and initialize it directly, if possible.  This can't
  	     be done if the initializer is void, since that implies that the
Index: testsuite/g++.dg/opt/temp1.C
===================================================================
RCS file: testsuite/g++.dg/opt/temp1.C
diff -N testsuite/g++.dg/opt/temp1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/opt/temp1.C	23 Dec 2004 07:58:26 -0000
***************
*** 0 ****
--- 1,39 ----
+ // PR c++/16405
+ // { dg-options "-O2" } 
+ 
+ // There should be exactly one temporary generated for the code in "f"
+ // below when optimizing -- for the result of "b + c".  We have no
+ // easy way of checking that directly, so we count the number of calls
+ // to "memcpy", which is used on (some?) targets to copy temporaries.
+ // If there is more than two calls (one for coping "*this" to "t", and
+ // one for copying the temporary to "a"), then there are too many
+ // temporaries. 
+ 
+ int i;
+ 
+ extern "C"
+ void *memcpy (void *dest, const void *src, __SIZE_TYPE__ n)
+ {
+   ++i;
+ }
+  
+ struct T {
+   int a[128];
+   T &operator+=(T const &v) __attribute__((noinline));
+   T operator+(T const &v) const { T t = *this; t += v; return t; }
+ };
+ 
+ T &T::operator+=(T const &v) {
+   return *this;
+ }
+ 
+ T a, b, c;
+ 
+ void f() { a = b + c; }
+ 
+ int main () {
+   i = 0;
+   f();
+   if (i > 2)
+     return 1;
+ }


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