[PATCH] Disallow inlining if static vars in that function contain addresses of that function's labels (PR tree-optimization/29484)

Jakub Jelinek jakub@redhat.com
Wed Jan 2 09:11:00 GMT 2008


On Sun, Dec 30, 2007 at 11:22:19AM -0800, Mark Mitchell wrote:
> Joseph S. Myers wrote:
> > On Wed, 26 Dec 2007, Mark Mitchell wrote:
> > 
> >> would succeed.  Function pointers are guaranteed unique, and labels seem
> >> quite similar at first blush, though I understand that they can only be
> >> used from within the function itself.
> >>
> >> Joseph, as a C maintainer, what do you think about this?
> > 
> > Existing practice for this extension has the labels only valid for 
> > computed goto, with the actual values unspecified and no requirements for 
> > comparability.
> 
> OK, it sounds like everyone agrees that the intended semantics are as
> Jakub suggests.  Jakub, would you mind updating the documentation to
> reflect that?

Like this?

2008-01-02  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.
	* doc/extend.texi (Labels as Values): Document &&foo behaviour
	vs. inlining.

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

--- gcc/doc/extend.texi.jj	2007-11-20 11:31:09.000000000 +0100
+++ gcc/doc/extend.texi	2008-01-02 09:59:40.000000000 +0100
@@ -370,6 +370,12 @@ This is more friendly to code living in 
 the number of dynamic relocations that are needed, and by consequence,
 allows the data to be read-only.
 
+The @code{&&foo} expressions for the same label might have different values
+if the containing function is inlined or cloned.  If a program relies on
+them being always the same, @code{__attribute__((__noinline__))} should
+be used to prevent inlining.  If @code{&&foo} is used
+in a static variable initializer, inlining is forbidden.
+
 @node Nested Functions
 @section Nested Functions
 @cindex nested functions
--- gcc/tree-inline.c.jj	2007-12-27 09:09:40.000000000 +0100
+++ gcc/tree-inline.c	2008-01-02 09:59:50.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	2008-01-02 09:59:50.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20071220-1.c	2008-01-02 09:59:50.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	2008-01-02 09:59:50.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20071220-2.c	2008-01-02 09:59:50.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



More information about the Gcc-patches mailing list