From 361c9aad59cd53541245e876f3b78953e87cff57 Mon Sep 17 00:00:00 2001 From: jakub Date: Thu, 3 Jan 2008 08:33:57 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@131300 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 9 ++++++ gcc/doc/extend.texi | 6 ++++ gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/gcc.c-torture/execute/20071220-1.c | 40 ++++++++++++++++++++++++ gcc/testsuite/gcc.c-torture/execute/20071220-2.c | 39 +++++++++++++++++++++++ gcc/tree-inline.c | 40 ++++++++++++++++++++++-- 6 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/20071220-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20071220-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f5516e7..e7098d0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2008-01-03 Jakub Jelinek + + 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. + 2007-12-19 Sebastian Pop PR tree-optimization/34635 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index c86052e..34a5a46 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -370,6 +370,12 @@ This is more friendly to code living in shared libraries, as it reduces 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ff42813..abf7969 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2008-01-03 Jakub Jelinek + + PR tree-optimization/29484 + * gcc.c-torture/execute/20071220-1.c: New test. + * gcc.c-torture/execute/20071220-2.c: New test. + 2007-12-19 Sebastian Pop PR tree-optimization/34635 diff --git a/gcc/testsuite/gcc.c-torture/execute/20071220-1.c b/gcc/testsuite/gcc.c-torture/execute/20071220-1.c new file mode 100644 index 0000000..00c2fa5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20071220-1.c @@ -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; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20071220-2.c b/gcc/testsuite/gcc.c-torture/execute/20071220-2.c new file mode 100644 index 0000000..93fa9de --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20071220-2.c @@ -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; +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 1efc0ed..ebb413a 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1951,6 +1951,27 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, 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; -- 2.7.4