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] Fix PR c++/17972


Hi,

The reporter of this PR found a slight different case where the C++ compiler 
again generates wrong code because of tree inlining with 3.4.x:

struct thread_info
{
  short preempt_count;
} x;

static inline struct thread_info *cti (void) __attribute__ ((const));
static inline struct thread_info *cti (void)
{
  return &x;
}

void fn (void) __attribute__ ((noinline));
void fn (void)
{
  cti()->preempt_count -= 1;
}

int main (void)
{
  fn ();
  return 0;
}

When the C++ FE converts the decrement expression to the 3-operand form, it 
first stabilizes the lhs; however, since the function is marked as 'const', 
the stabilization is a no-op so the CALL_EXPR ends up being referenced twice 
in the expression.  Later, when the tree inliner kicks in, it inlines the 
unique CALL_EXPR.  When the enclosing expression is expanded to RTL, the 
inlined body is expanded twice and all hell breaks loose since the RETURN of 
the second block points to the return label of the first block.

Mark proposed to fix the problem in stabilize_reference, by always stabilizing 
CALL_EXPR (if tree inlining is enabled).  I've attached a version for 4.0/4.1 
and a version for 3.4, both bootstrapped/regtested on AMD64.


4.0/4.1
2005-03-09  Eric Botcazou  <ebotcazou@libertysurf.fr>

	PR c++/17972
	* tree.c: Include tree-inline.h.
	(save_expr): Stabilize CALL_EXPRs if tree inlining is enabled.
	(stabilize_reference_1): Likewise.

3.4
2005-03-09  Eric Botcazou  <ebotcazou@libertysurf.fr>

	PR c++/17972
	* tree-inline.h (flag_inline_trees): Move from here to...
	* flags.h (flag_inline_trees): ...here.
	* tree-inline.c (flag_inline_trees): Move from here to...
	* toplev.c (flag_inline_trees): ...here.	
	* tree.c (save_expr): Stabilize CALL_EXPRs if tree inlining is enabled.
	(stabilize_reference_1): Likewise.

cp/
	* optimize.c: Include flags.h.


2005-03-09  Eric Botcazou  <ebotcazou@libertysurf.fr>


	* g++.dg/opt/inline10.C: New test.


-- 
Eric Botcazou
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.466
diff -u -p -r1.466 tree.c
--- tree.c	12 Feb 2005 00:26:56 -0000	1.466
+++ tree.c	8 Mar 2005 08:41:54 -0000
@@ -35,6 +35,7 @@ Software Foundation, 59 Temple Place - S
 #include "tm.h"
 #include "flags.h"
 #include "tree.h"
+#include "tree-inline.h"
 #include "real.h"
 #include "tm_p.h"
 #include "function.h"
@@ -1692,7 +1693,10 @@ save_expr (tree expr)
   inner = skip_simple_arithmetic (t);
 
   if (TREE_INVARIANT (inner)
-      || (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
+      || (TREE_READONLY (inner)
+	  && ! (TREE_SIDE_EFFECTS (inner)
+	        /* See comment in stabilize_reference.  */
+		|| (TREE_CODE (inner) == CALL_EXPR && flag_inline_trees)))
       || TREE_CODE (inner) == SAVE_EXPR
       || TREE_CODE (inner) == ERROR_MARK)
     return t;
@@ -2323,7 +2327,13 @@ stabilize_reference_1 (tree e)
 	 so that it will only be evaluated once.  */
       /* The reference (r) and comparison (<) classes could be handled as
 	 below, but it is generally faster to only evaluate them once.  */
-      if (TREE_SIDE_EFFECTS (e))
+      if (TREE_SIDE_EFFECTS (e)
+	  /* If tree inlining is enabled, we must stabilize CALL_EXPRs
+	     without side-effects; otherwise they may end up referenced
+	     multiple times in the same expression so, if subsequently
+	     inlined, the body of the called function may be expanded
+	     to RTL multiples times.  */
+	  || (code == CALL_EXPR && flag_inline_trees))
 	return save_expr (e);
       return e;
 
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.127.4.1
diff -u -p -r1.127.4.1 flags.h
--- flags.h	18 Feb 2004 00:09:04 -0000	1.127.4.1
+++ flags.h	7 Mar 2005 10:21:31 -0000
@@ -383,6 +383,13 @@ extern int flag_rerun_loop_opt;
 
 extern int flag_inline_functions;
 
+/* 0 if we should not perform inlining.
+   1 if we should expand functions calls inline at the tree level.
+   2 if we should consider *all* functions to be inline
+   candidates.  */
+
+extern int flag_inline_trees;
+
 /* Nonzero for -fkeep-inline-functions: even if we make a function
    go inline everywhere, keep its definition around for debugging
    purposes.  */
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.863.4.14
diff -u -p -r1.863.4.14 toplev.c
--- toplev.c	16 Jan 2005 16:01:19 -0000	1.863.4.14
+++ toplev.c	7 Mar 2005 10:21:33 -0000
@@ -724,6 +724,13 @@ int flag_rerun_loop_opt;
 
 int flag_inline_functions;
 
+/* 0 if we should not perform inlining.
+   1 if we should expand functions calls inline at the tree level.
+   2 if we should consider *all* functions to be inline
+   candidates.  */
+
+int flag_inline_trees = 0;
+
 /* Nonzero for -fkeep-inline-functions: even if we make a function
    go inline everywhere, keep its definition around for debugging
    purposes.  */
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.342.2.5
diff -u -p -r1.342.2.5 tree.c
--- tree.c	23 Aug 2004 18:02:41 -0000	1.342.2.5
+++ tree.c	7 Mar 2005 10:21:35 -0000
@@ -1350,7 +1350,10 @@ save_expr (tree expr)
      literal node.  */
   inner = skip_simple_arithmetic (t);
   if (TREE_CONSTANT (inner)
-      || (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
+      || (TREE_READONLY (inner)
+	  && ! (TREE_SIDE_EFFECTS (inner)
+	        /* See comment in stabilize_reference.  */
+		|| (TREE_CODE (inner) == CALL_EXPR && flag_inline_trees)))
       || TREE_CODE (inner) == SAVE_EXPR
       || TREE_CODE (inner) == ERROR_MARK)
     return t;
@@ -2245,7 +2248,13 @@ stabilize_reference_1 (tree e)
 	 so that it will only be evaluated once.  */
       /* The reference (r) and comparison (<) classes could be handled as
 	 below, but it is generally faster to only evaluate them once.  */
-      if (TREE_SIDE_EFFECTS (e))
+      if (TREE_SIDE_EFFECTS (e)
+	  /* If tree inlining is enabled, we must stabilize CALL_EXPRs
+	     without side-effects; otherwise they may end up referenced
+	     multiple times in the same expression so, if subsequently
+	     inlined, the body of the called function may be expanded
+	     to RTL multiples times.  */
+	  || (code == CALL_EXPR && flag_inline_trees))
 	return save_expr (e);
       return e;
 
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.90.4.6
diff -u -p -r1.90.4.6 tree-inline.c
--- tree-inline.c	15 Dec 2004 19:17:46 -0000	1.90.4.6
+++ tree-inline.c	7 Mar 2005 10:21:36 -0000
@@ -50,13 +50,6 @@ Boston, MA 02111-1307, USA.  */
 #include "java-tree.h"
 #endif /* INLINER_FOR_JAVA */
 
-/* 0 if we should not perform inlining.
-   1 if we should expand functions calls inline at the tree level.
-   2 if we should consider *all* functions to be inline
-   candidates.  */
-
-int flag_inline_trees = 0;
-
 /* To Do:
 
    o In order to make inlining-on-trees work, we pessimized
Index: tree-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.h,v
retrieving revision 1.8
diff -u -p -r1.8 tree-inline.h
--- tree-inline.h	5 Aug 2003 14:11:43 -0000	1.8
+++ tree-inline.h	7 Mar 2005 10:21:36 -0000
@@ -32,11 +32,4 @@ tree copy_tree_r (tree*, int*, void*);
 void clone_body (tree, tree, void*);
 void remap_save_expr (tree*, void*, tree, int*);
 
-/* 0 if we should not perform inlining.
-   1 if we should expand functions calls inline at the tree level.
-   2 if we should consider *all* functions to be inline
-   candidates.  */
-
-extern int flag_inline_trees;
-
 #endif /* GCC_TREE_INLINE_H */
Index: cp/optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/optimize.c,v
retrieving revision 1.103.4.2
diff -u -p -r1.103.4.2 optimize.c
--- cp/optimize.c	8 Feb 2004 01:52:50 -0000	1.103.4.2
+++ cp/optimize.c	7 Mar 2005 10:21:36 -0000
@@ -24,6 +24,7 @@ Software Foundation, 59 Temple Place - S
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "flags.h"
 #include "tree.h"
 #include "cp-tree.h"
 #include "rtl.h"
// PR c++/17972
// Origin: Michal Ostrowski <mostrows@watson.ibm.com>
// Testcase by Alan Modra <amodra@bigpond.net.au>
// { dg-do run }
// { dg-options "-O" }

struct thread_info
{
  short preempt_count;
} x;

static inline struct thread_info *cti (void) __attribute__ ((const));
static inline struct thread_info *cti (void)
{
  return &x;
}

void fn (void) __attribute__ ((noinline));
void fn (void)
{
  cti()->preempt_count -= 1;
}

int main (void)
{
  fn ();
  return 0;
}

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