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] Disallow inlining if static vars in that function contain addresses of that function's labels (PR tree-optimization/29484)


Hi!

The second testcase here fails to link, because GCC chooses to inline
a function with &&label in static var initializers.  As there is just one
static var instance for each inline fn (in C within TU, in C++ within whole
program), no matter how many times it has been inlined, we really need to
disallow inlining in this case, as the labels necessarily differ between the
various places it has been inlined into.  Specifically, without
-fkeep-inline-functions on 20071220-2.c the static var will contain a label
which isn't defined anywhere and with -fkeep-inline-functions it will
contain a label in the out of line body.
On 20071220-1.c testcase inlining was already disallowed because of the
use of computed goto, so this patch just extends the limitation also to
mere taking address of a label and storing it into static var's initializer.

Regtested on x86_64-linux, ok for trunk?

2007-12-20  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/29484
	* tree-inline.c (inline_forbidden_p_2): New function.
	(inline_forbidden_p): Disallow inlining if some static var
	has an address of a local LABEL_DECL in its initializer.

	* gcc.c-torture/execute/20071220-1.c: New test.
	* gcc.c-torture/execute/20071220-2.c: New test.

--- gcc/tree-inline.c.jj	2007-12-04 16:39:22.000000000 +0100
+++ gcc/tree-inline.c	2007-12-20 13:46:18.000000000 +0100
@@ -1951,6 +1951,27 @@ inline_forbidden_p_1 (tree *nodep, int *
   return NULL_TREE;
 }
 
+static tree
+inline_forbidden_p_2 (tree *nodep, int *walk_subtrees,
+		      void *fnp)
+{
+  tree node = *nodep;
+  tree fn = (tree) fnp;
+
+  if (TREE_CODE (node) == LABEL_DECL && DECL_CONTEXT (node) == fn)
+    {
+      inline_forbidden_reason
+	= G_("function %q+F can never be inlined "
+	     "because it saves address of local label in a static variable");
+      return node;
+    }
+
+  if (TYPE_P (node))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
 /* Return subexpression representing possible alloca call, if any.  */
 static tree
 inline_forbidden_p (tree fndecl)
@@ -1959,16 +1980,31 @@ inline_forbidden_p (tree fndecl)
   block_stmt_iterator bsi;
   basic_block bb;
   tree ret = NULL_TREE;
+  struct function *fun = DECL_STRUCT_FUNCTION (fndecl);
+  tree step;
 
-  FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl))
+  FOR_EACH_BB_FN (bb, fun)
     for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
       {
 	ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
-				    inline_forbidden_p_1, fndecl);
+					    inline_forbidden_p_1, fndecl);
 	if (ret)
 	  goto egress;
       }
 
+  for (step = fun->unexpanded_var_list; step; step = TREE_CHAIN (step))
+    {
+      tree decl = TREE_VALUE (step);
+      if (TREE_CODE (decl) == VAR_DECL
+	  && TREE_STATIC (decl)
+	  && !DECL_EXTERNAL (decl)
+	  && DECL_INITIAL (decl))
+	ret = walk_tree_without_duplicates (&DECL_INITIAL (decl),
+					    inline_forbidden_p_2, fndecl);
+	if (ret)
+	  goto egress;
+    }
+
 egress:
   input_location = saved_loc;
   return ret;
--- gcc/testsuite/gcc.c-torture/execute/20071220-1.c.jj	2007-12-20 14:29:04.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20071220-1.c	2007-12-20 14:28:12.000000000 +0100
@@ -0,0 +1,40 @@
+/* PR tree-optimization/29484 */
+
+extern void abort (void);
+
+void *__attribute__((noinline))
+baz (void **lab)
+{
+  asm volatile ("" : "+r" (lab));
+  return *lab;
+}
+
+static inline
+int bar (void)
+{
+  static void *b[] = { &&addr };
+  void *p = baz (b);
+  goto *p;
+addr:
+  return 17;
+}
+
+int __attribute__((noinline))
+f1 (void)
+{
+  return bar ();
+}
+
+int __attribute__((noinline))
+f2 (void)
+{
+  return bar ();
+}
+
+int
+main (void)
+{
+  if (f1 () != 17 || f1 () != 17 || f2 () != 17 || f2 () != 17)
+    abort ();
+  return 0;
+}
--- gcc/testsuite/gcc.c-torture/execute/20071220-2.c.jj	2007-12-20 14:29:13.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20071220-2.c	2007-12-20 14:28:30.000000000 +0100
@@ -0,0 +1,39 @@
+/* PR tree-optimization/29484 */
+
+extern void abort (void);
+
+void *__attribute__((noinline))
+baz (void **lab)
+{
+  asm volatile ("" : "+r" (lab));
+  return *lab;
+}
+
+static inline
+int bar (void)
+{
+  static void *b[] = { &&addr };
+  baz (b);
+addr:
+  return 17;
+}
+
+int __attribute__((noinline))
+f1 (void)
+{
+  return bar ();
+}
+
+int __attribute__((noinline))
+f2 (void)
+{
+  return bar ();
+}
+
+int
+main (void)
+{
+  if (f1 () != 17 || f1 () != 17 || f2 () != 17 || f2 () != 17)
+    abort ();
+  return 0;
+}

	Jakub


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