@@ -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. */
@@ -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;
}
@@ -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);
}
}
}
@@ -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);
@@ -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);
new file mode 100644
@@ -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);
+}
@@ -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.
@@ -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. */