[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