diff mbox

Fix 70199

Message ID 56E98F29.8090906@redhat.com
State New
Headers show

Commit Message

Richard Henderson March 16, 2016, 4:51 p.m. UTC
On 03/16/2016 02:40 AM, Richard Biener wrote:
> I like patch 2 more - btw, you need to add has_forced_label_in_static streaming
> to lto-streamer-{in,out}.c, just look for has_nonlocal_label streaming.  Also
> has_label_address_in_static_1 is now unused and should be removed.

I'd already found the latter with a full bootstrap, but thanks for the catch 
wrt the former.  I've now committed the following that addresses both.


r~
PR middle-end/70199
	* function.h (struct function): Add has_forced_label_in_static.
	* gimplify.c (force_labels_r): Set it.
	* lto-streamer-in.c (input_struct_function_base): Read it.
	* lto-streamer-out.c (output_struct_function_base): Write it.
	* tree-inline.c (has_label_address_in_static_1): Remove.
	(copy_forbidden): Remove fndecl parameter; test
	has_forced_label_in_static.
	(inline_forbidden_p): Update call to copy_forbidden.
	(tree_versionable_function_p): Likewise.
	* ipa-chkp.c (chkp_instrumentable_p): Likewise.
	(chkp_versioning): Likewise.
	* tree-inline.h (copy_forbidden): Update decl.

testsuite/
	* gcc.c-torture/compile/pr70199.c: New.
diff mbox

Patch

diff --git a/gcc/function.h b/gcc/function.h
index c4368cd..501ef68 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -328,6 +328,10 @@  struct GTY(()) function {
      from nested functions.  */
   unsigned int has_nonlocal_label : 1;
 
+  /* Nonzero if function being compiled has a forced label
+     placed into static storage.  */
+  unsigned int has_forced_label_in_static : 1;
+
   /* Nonzero if we've set cannot_be_copied_reason.  I.e. if
      (cannot_be_copied_set && !cannot_be_copied_reason), the function
      can in fact be copied.  */
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 692d168..84ce46e 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1414,7 +1414,10 @@  force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
   if (TYPE_P (*tp))
     *walk_subtrees = 0;
   if (TREE_CODE (*tp) == LABEL_DECL)
-    FORCED_LABEL (*tp) = 1;
+    {
+      FORCED_LABEL (*tp) = 1;
+      cfun->has_forced_label_in_static = 1;
+    }
 
   return NULL_TREE;
 }
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
index 4a6b43e..5f5df64 100644
--- a/gcc/ipa-chkp.c
+++ b/gcc/ipa-chkp.c
@@ -470,7 +470,7 @@  chkp_instrumentable_p (tree fndecl)
   return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
 	  && (!flag_chkp_instrument_marked_only
 	      || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
-	  && (!fn || !copy_forbidden (fn, fndecl)));
+	  && (!fn || !copy_forbidden (fn)));
 }
 
 /* Return clone created for instrumentation of NODE or NULL.  */
@@ -644,22 +644,22 @@  chkp_versioning (void)
 
   FOR_EACH_DEFINED_FUNCTION (node)
     {
+      tree decl = node->decl;
       if (!node->instrumentation_clone
 	  && !node->instrumented_version
 	  && !node->alias
 	  && !node->thunk.thunk_p
-	  && (!DECL_BUILT_IN (node->decl)
-	      || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
-		  && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
+	  && (!DECL_BUILT_IN (decl)
+	      || (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+		  && DECL_FUNCTION_CODE (decl) < BEGIN_CHKP_BUILTINS)))
 	{
-	  if (chkp_instrumentable_p (node->decl))
-	    chkp_maybe_create_clone (node->decl);
-	  else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
-					     node->decl)))
+	  if (chkp_instrumentable_p (decl))
+	    chkp_maybe_create_clone (decl);
+	  else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (decl))))
 	    {
-	      if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
+	      if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wchkp,
 			      "function cannot be instrumented"))
-		inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
+		inform (DECL_SOURCE_LOCATION (decl), reason, decl);
 	    }
 	}
     }
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 48a1c86..dd48777 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1008,6 +1008,7 @@  input_struct_function_base (struct function *fn, struct data_in *data_in,
   fn->after_inlining = bp_unpack_value (&bp, 1);
   fn->stdarg = bp_unpack_value (&bp, 1);
   fn->has_nonlocal_label = bp_unpack_value (&bp, 1);
+  fn->has_forced_label_in_static = bp_unpack_value (&bp, 1);
   fn->calls_alloca = bp_unpack_value (&bp, 1);
   fn->calls_setjmp = bp_unpack_value (&bp, 1);
   fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1);
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 997a28b..6703d41 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -2014,6 +2014,7 @@  output_struct_function_base (struct output_block *ob, struct function *fn)
   bp_pack_value (&bp, fn->after_inlining, 1);
   bp_pack_value (&bp, fn->stdarg, 1);
   bp_pack_value (&bp, fn->has_nonlocal_label, 1);
+  bp_pack_value (&bp, fn->has_forced_label_in_static, 1);
   bp_pack_value (&bp, fn->calls_alloca, 1);
   bp_pack_value (&bp, fn->calls_setjmp, 1);
   bp_pack_value (&bp, fn->has_force_vectorize_loops, 1);
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr70199.c b/gcc/testsuite/gcc.c-torture/compile/pr70199.c
new file mode 100644
index 0000000..a4323f0
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr70199.c
@@ -0,0 +1,20 @@ 
+static volatile int v = 0;
+static
+void benchmark(long runs) {
+  void* labels[] = {
+    &&l0, &&l1, &&l2
+  };
+  for(unsigned int mask = 0x1F; mask > 0; mask >>= 1) {
+    unsigned lfsr = 0xACE1u;
+    long n = 10000000;
+    while(n > 0) {
+      l2: v;
+      l1: v;
+      goto *labels[lfsr & mask];
+      l0: n--;
+    }
+  }
+}
+int f(void) {
+  benchmark(10000000);
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index d52e0c6..9d4f8f7 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -3504,33 +3504,13 @@  declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
   return use;
 }
 
-/* Callback through walk_tree.  Determine if a DECL_INITIAL makes reference
-   to a local label.  */
-
-static tree
-has_label_address_in_static_1 (tree *nodep, int *walk_subtrees, void *fnp)
-{
-  tree node = *nodep;
-  tree fn = (tree) fnp;
-
-  if (TREE_CODE (node) == LABEL_DECL && DECL_CONTEXT (node) == fn)
-    return node;
-
-  if (TYPE_P (node))
-    *walk_subtrees = 0;
-
-  return NULL_TREE;
-}
-
 /* Determine if the function can be copied.  If so return NULL.  If
    not return a string describng the reason for failure.  */
 
 const char *
-copy_forbidden (struct function *fun, tree fndecl)
+copy_forbidden (struct function *fun)
 {
   const char *reason = fun->cannot_be_copied_reason;
-  tree decl;
-  unsigned ix;
 
   /* Only examine the function once.  */
   if (fun->cannot_be_copied_set)
@@ -3549,19 +3529,12 @@  copy_forbidden (struct function *fun, tree fndecl)
       goto fail;
     }
 
-  FOR_EACH_LOCAL_DECL (fun, ix, decl)
-    if (TREE_CODE (decl) == VAR_DECL
-	&& TREE_STATIC (decl)
-	&& !DECL_EXTERNAL (decl)
-	&& DECL_INITIAL (decl)
-	&& walk_tree_without_duplicates (&DECL_INITIAL (decl),
-					 has_label_address_in_static_1,
-					 fndecl))
-      {
-	reason = G_("function %q+F can never be copied because it saves "
-		    "address of local label in a static variable");
-	goto fail;
-      }
+  if (fun->has_forced_label_in_static)
+    {
+      reason = G_("function %q+F can never be copied because it saves "
+		  "address of local label in a static variable");
+      goto fail;
+    }
 
  fail:
   fun->cannot_be_copied_reason = reason;
@@ -3705,7 +3678,7 @@  inline_forbidden_p (tree fndecl)
   bool forbidden_p = false;
 
   /* First check for shared reasons not to copy the code.  */
-  inline_forbidden_reason = copy_forbidden (fun, fndecl);
+  inline_forbidden_reason = copy_forbidden (fun);
   if (inline_forbidden_reason != NULL)
     return true;
 
@@ -5552,7 +5525,7 @@  bool
 tree_versionable_function_p (tree fndecl)
 {
   return (!lookup_attribute ("noclone", DECL_ATTRIBUTES (fndecl))
-	  && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl), fndecl) == NULL);
+	  && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl)) == NULL);
 }
 
 /* Delete all unreachable basic blocks and update callgraph.
diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h
index 4cc1f19..9ca2a91 100644
--- a/gcc/tree-inline.h
+++ b/gcc/tree-inline.h
@@ -217,7 +217,7 @@  extern tree remap_type (tree type, copy_body_data *id);
 extern gimple_seq copy_gimple_seq_and_replace_locals (gimple_seq seq);
 extern bool debug_find_tree (tree, tree);
 extern tree copy_fn (tree, tree&, tree&);
-extern const char *copy_forbidden (struct function *fun, tree fndecl);
+extern const char *copy_forbidden (struct function *fun);
 
 /* This is in tree-inline.c since the routine uses
    data structures from the inliner.  */