public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-7809] analyzer: add region::tracked_p to optimize state objects [PR104954]
@ 2022-03-25 1:00 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2022-03-25 1:00 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:5f6197d7c197f9d2b7fb2e1a19dac39a023755e8
commit r12-7809-g5f6197d7c197f9d2b7fb2e1a19dac39a023755e8
Author: David Malcolm <dmalcolm@redhat.com>
Date: Thu Mar 24 20:58:10 2022 -0400
analyzer: add region::tracked_p to optimize state objects [PR104954]
PR analyzer/104954 tracks that -fanalyzer was taking a very long time
on a particular source file in the Linux kernel:
drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
One issue occurs with the repeated use of dynamic debug lines e.g. via
the DC_LOG_BANDWIDTH_CALCS macro, such as in print_bw_calcs_dceip in
drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h:
DC_LOG_BANDWIDTH_CALCS("#####################################################################");
DC_LOG_BANDWIDTH_CALCS("struct bw_calcs_dceip");
DC_LOG_BANDWIDTH_CALCS("#####################################################################");
[...snip dozens of lines...]
DC_LOG_BANDWIDTH_CALCS("[bw_fixed] dmif_request_buffer_size: %d",
bw_fixed_to_int(dceip->dmif_request_buffer_size));
When this is configured to use __dynamic_pr_debug, each of these becomes
code like:
do {
static struct _ddebug __attribute__((__aligned__(8)))
__attribute__((__section__("__dyndbg"))) __UNIQUE_ID_ddebug277 = {
[...snip...]
};
if (arch_static_branch(&__UNIQUE_ID_ddebug277.key, false))
__dynamic_pr_debug(&__UNIQUE_ID_ddebug277, [...the message...]);
} while (0);
The analyzer was naively seeing each call to __dynamic_pr_debug, noting
that the __UNIQUE_ID_nnnn object escapes. At each call, as successive
__UNIQUE_ID_nnnn object escapes, there are N escaped objects, and thus N
need clobbering, and so we have O(N^2) clobbering of escaped objects overall,
leading to huge amounts of pointless work: print_bw_calcs_data has 225
uses of DC_LOG_BANDWIDTH_CALCS, many of which are in loops.
This patch adds a way to identify declarations that aren't interesting
to the analyzer, so that we don't attempt to create binding_clusters
for them (i.e. we don't store any state for them in our state objects).
This is implemented by adding a new region::tracked_p, implemented for
declarations by walking the existing IPA data the first time the
analyzer sees a declaration, setting it to false for global vars that
have no loads/stores/aliases, and "sufficiently safe" address-of
ipa-refs.
The patch gives a large speedup of -fanalyzer on the above kernel
source file:
Before After
Total cc1 wallclock time: 180s 36s
analyzer wallclock time: 162s 17s
% spent in analyzer: 90% 47%
gcc/analyzer/ChangeLog:
PR analyzer/104954
* analyzer.opt (-fdump-analyzer-untracked): New option.
* engine.cc (impl_run_checkers): Handle it.
* region-model-asm.cc (region_model::on_asm_stmt): Don't attempt
to clobber regions with !tracked_p ().
* region-model-manager.cc (dump_untracked_region): New.
(region_model_manager::dump_untracked_regions): New.
(frame_region::dump_untracked_regions): New.
* region-model.h (region_model_manager::dump_untracked_regions):
New decl.
* region.cc (ipa_ref_requires_tracking): New.
(symnode_requires_tracking_p): New.
(decl_region::calc_tracked_p): New.
* region.h (region::tracked_p): New vfunc.
(frame_region::dump_untracked_regions): New decl.
(class decl_region): Note that this is also used fo SSA names.
(decl_region::decl_region): Initialize m_tracked.
(decl_region::tracked_p): New.
(decl_region::calc_tracked_p): New decl.
(decl_region::m_tracked): New.
* store.cc (store::get_or_create_cluster): Assert that we
don't try to create clusters for base regions that aren't
trackable.
(store::mark_as_escaped): Don't mark base regions that we're not
tracking.
gcc/ChangeLog:
PR analyzer/104954
* doc/invoke.texi (Static Analyzer Options): Add
-fdump-analyzer-untracked.
gcc/testsuite/ChangeLog:
PR analyzer/104954
* gcc.dg/analyzer/asm-x86-dyndbg-1.c: New test.
* gcc.dg/analyzer/asm-x86-dyndbg-2.c: New test.
* gcc.dg/analyzer/many-unused-locals.c: New test.
* gcc.dg/analyzer/untracked-1.c: New test.
* gcc.dg/analyzer/unused-local-1.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diff:
---
gcc/analyzer/analyzer.opt | 4 +
gcc/analyzer/engine.cc | 3 +
gcc/analyzer/region-model-asm.cc | 3 +-
gcc/analyzer/region-model-manager.cc | 41 +++++++
gcc/analyzer/region-model.h | 2 +
gcc/analyzer/region.cc | 88 ++++++++++++++
gcc/analyzer/region.h | 24 +++-
gcc/analyzer/store.cc | 6 +-
gcc/doc/invoke.texi | 5 +
gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-1.c | 126 +++++++++++++++++++++
gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c | 77 +++++++++++++
gcc/testsuite/gcc.dg/analyzer/many-unused-locals.c | 69 +++++++++++
gcc/testsuite/gcc.dg/analyzer/untracked-1.c | 99 ++++++++++++++++
gcc/testsuite/gcc.dg/analyzer/unused-local-1.c | 22 ++++
14 files changed, 565 insertions(+), 4 deletions(-)
diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt
index b9d2ece273c..a0ba2c94fb3 100644
--- a/gcc/analyzer/analyzer.opt
+++ b/gcc/analyzer/analyzer.opt
@@ -250,4 +250,8 @@ fdump-analyzer-supergraph
Common RejectNegative Var(flag_dump_analyzer_supergraph)
Dump the analyzer supergraph to a SRCFILE.supergraph.dot file.
+fdump-analyzer-untracked
+Common RejectNegative Var(flag_dump_analyzer_untracked)
+Emit custom warnings with internal details intended for analyzer developers.
+
; This comment is to ensure we retain the blank line above.
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 0f40e064a22..d8b61955aa6 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -5811,6 +5811,9 @@ impl_run_checkers (logger *logger)
if (flag_dump_analyzer_json)
dump_analyzer_json (sg, eg);
+ if (flag_dump_analyzer_untracked)
+ eng.get_model_manager ()->dump_untracked_regions ();
+
delete purge_map;
}
diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc
index 3bf2a02432c..c7389f0e38d 100644
--- a/gcc/analyzer/region-model-asm.cc
+++ b/gcc/analyzer/region-model-asm.cc
@@ -267,7 +267,8 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt)
iter != reachable_regs.end_mutable_base_regs (); ++iter)
{
const region *base_reg = *iter;
- if (base_reg->symbolic_for_unknown_ptr_p ())
+ if (base_reg->symbolic_for_unknown_ptr_p ()
+ || !base_reg->tracked_p ())
continue;
binding_cluster *cluster = m_store.get_or_create_cluster (base_reg);
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index bc8f554580b..61c7fb32628 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -1740,6 +1740,47 @@ store_manager::log_stats (logger *logger, bool show_objs) const
m_symbolic_binding_key_mgr);
}
+/* Emit a warning showing DECL_REG->tracked_p () for use in DejaGnu tests
+ (using -fdump-analyzer-untracked). */
+
+static void
+dump_untracked_region (const decl_region *decl_reg)
+{
+ tree decl = decl_reg->get_decl ();
+ if (TREE_CODE (decl) != VAR_DECL)
+ return;
+ warning_at (DECL_SOURCE_LOCATION (decl), 0,
+ "track %qD: %s",
+ decl, (decl_reg->tracked_p () ? "yes" : "no"));
+}
+
+/* Implementation of -fdump-analyzer-untracked. */
+
+void
+region_model_manager::dump_untracked_regions () const
+{
+ for (auto iter : m_globals_map)
+ {
+ const decl_region *decl_reg = iter.second;
+ dump_untracked_region (decl_reg);
+ }
+ for (auto frame_iter : m_frame_regions)
+ {
+ const frame_region *frame_reg = frame_iter.second;
+ frame_reg->dump_untracked_regions ();
+ }
+}
+
+void
+frame_region::dump_untracked_regions () const
+{
+ for (auto iter : m_locals)
+ {
+ const decl_region *decl_reg = iter.second;
+ dump_untracked_region (decl_reg);
+ }
+}
+
} // namespace ana
#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index d9e21432032..13a2ea94a3f 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -349,6 +349,8 @@ public:
logger *get_logger () const { return m_logger; }
+ void dump_untracked_regions () const;
+
private:
bool too_complex_p (const complexity &c) const;
bool reject_if_too_complex (svalue *sval);
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 2020ef4e4b5..9c9e043c658 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -1167,6 +1167,94 @@ decl_region::get_svalue_for_initializer (region_model_manager *mgr) const
return m.get_rvalue (path_var (init, 0), NULL);
}
+/* Subroutine of symnode_requires_tracking_p; return true if REF
+ within CONTEXT_FNDECL might imply that we should be tracking the
+ value of a decl. */
+
+static bool
+ipa_ref_requires_tracking (const ipa_ref *ref, tree context_fndecl)
+{
+ /* If we have a load/store/alias of the symbol, then we'll track
+ the decl's value. */
+ if (ref->use != IPA_REF_ADDR)
+ return true;
+
+ if (ref->stmt == NULL)
+ return true;
+
+ switch (ref->stmt->code)
+ {
+ default:
+ return true;
+ case GIMPLE_CALL:
+ {
+ cgraph_node *context_cnode = cgraph_node::get (context_fndecl);
+ cgraph_edge *edge = context_cnode->get_edge (ref->stmt);
+ if (!edge)
+ return true;
+ if (edge->callee == NULL)
+ return true; /* e.g. call through function ptr. */
+ if (edge->callee->definition)
+ return true;
+ /* If we get here, then this ref is a pointer passed to
+ a function we don't have the definition for. */
+ return false;
+ }
+ break;
+ case GIMPLE_ASM:
+ {
+ const gasm *asm_stmt = as_a <const gasm *> (ref->stmt);
+ if (gimple_asm_noutputs (asm_stmt) > 0)
+ return true;
+ if (gimple_asm_nclobbers (asm_stmt) > 0)
+ return true;
+ /* If we get here, then this ref is the decl being passed
+ by pointer to asm with no outputs. */
+ return false;
+ }
+ break;
+ }
+}
+
+/* Determine if the decl for SYMNODE should have binding_clusters
+ in our state objects; return false to optimize away tracking
+ certain decls in our state objects, as an optimization. */
+
+static bool
+symnode_requires_tracking_p (symtab_node *symnode)
+{
+ gcc_assert (symnode);
+ if (symnode->externally_visible)
+ return true;
+ tree context_fndecl = DECL_CONTEXT (symnode->decl);
+ if (context_fndecl == NULL)
+ return true;
+ if (TREE_CODE (context_fndecl) != FUNCTION_DECL)
+ return true;
+ for (auto ref : symnode->ref_list.referring)
+ if (ipa_ref_requires_tracking (ref, context_fndecl))
+ return true;
+
+ /* If we get here, then we don't have uses of this decl that require
+ tracking; we never read from it or write to it explicitly. */
+ return false;
+}
+
+/* Subroutine of decl_region ctor: determine whether this decl_region
+ can have binding_clusters; return false to optimize away tracking
+ of certain decls in our state objects, as an optimization. */
+
+bool
+decl_region::calc_tracked_p (tree decl)
+{
+ /* Precondition of symtab_node::get. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p))
+ if (symtab_node *symnode = symtab_node::get (decl))
+ return symnode_requires_tracking_p (symnode);
+ return true;
+}
+
/* class field_region : public region. */
/* Implementation of region::dump_to_pp vfunc for field_region. */
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index dbeb485e81f..5150be76d0b 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -197,6 +197,11 @@ public:
bool symbolic_for_unknown_ptr_p () const;
+ /* For most base regions it makes sense to track the bindings of the region
+ within the store. As an optimization, some are not tracked (to avoid
+ bloating the store object with redundant binding clusters). */
+ virtual bool tracked_p () const { return true; }
+
const complexity &get_complexity () const { return m_complexity; }
bool is_named_decl_p (const char *decl_name) const;
@@ -319,6 +324,9 @@ public:
unsigned get_num_locals () const { return m_locals.elements (); }
+ /* Implemented in region-model-manager.cc. */
+ void dump_untracked_regions () const;
+
private:
const frame_region *m_calling_frame;
function *m_fun;
@@ -633,13 +641,15 @@ template <> struct default_hash_traits<symbolic_region::key_t>
namespace ana {
/* Concrete region subclass representing the memory occupied by a
- variable (whether for a global or a local). */
+ variable (whether for a global or a local).
+ Also used for representing SSA names, as if they were locals. */
class decl_region : public region
{
public:
decl_region (unsigned id, const region *parent, tree decl)
- : region (complexity (parent), id, parent, TREE_TYPE (decl)), m_decl (decl)
+ : region (complexity (parent), id, parent, TREE_TYPE (decl)), m_decl (decl),
+ m_tracked (calc_tracked_p (decl))
{}
enum region_kind get_kind () const FINAL OVERRIDE { return RK_DECL; }
@@ -648,6 +658,8 @@ public:
void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+ bool tracked_p () const FINAL OVERRIDE { return m_tracked; }
+
tree get_decl () const { return m_decl; }
int get_stack_depth () const;
@@ -657,7 +669,15 @@ public:
const svalue *get_svalue_for_initializer (region_model_manager *mgr) const;
private:
+ static bool calc_tracked_p (tree decl);
+
tree m_decl;
+
+ /* Cached result of calc_tracked_p, so that we can quickly determine when
+ we don't to track a binding_cluster for this decl (to avoid bloating
+ store objects).
+ This can be debugged using -fdump-analyzer-untracked. */
+ bool m_tracked;
};
} // namespace ana
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index ec11433dffc..62733b9777f 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -2654,6 +2654,9 @@ store::get_or_create_cluster (const region *base_reg)
/* We shouldn't create clusters for dereferencing an UNKNOWN ptr. */
gcc_assert (!base_reg->symbolic_for_unknown_ptr_p ());
+ /* We shouldn't create clusters for base regions that aren't trackable. */
+ gcc_assert (base_reg->tracked_p ());
+
if (binding_cluster **slot = m_cluster_map.get (base_reg))
return *slot;
@@ -2742,7 +2745,8 @@ store::mark_as_escaped (const region *base_reg)
gcc_assert (base_reg);
gcc_assert (base_reg->get_base_region () == base_reg);
- if (base_reg->symbolic_for_unknown_ptr_p ())
+ if (base_reg->symbolic_for_unknown_ptr_p ()
+ || !base_reg->tracked_p ())
return;
binding_cluster *cluster = get_or_create_cluster (base_reg);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8b16b35ec12..afb21d9154c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -439,6 +439,7 @@ Objective-C and Objective-C++ Dialects}.
-fdump-analyzer-state-purge @gol
-fdump-analyzer-stderr @gol
-fdump-analyzer-supergraph @gol
+-fdump-analyzer-untracked @gol
-Wno-analyzer-double-fclose @gol
-Wno-analyzer-double-free @gol
-Wno-analyzer-exposure-through-output-file @gol
@@ -10212,6 +10213,10 @@ control flow graphs in the program, with interprocedural edges for
calls and returns. The second dump contains annotations showing nodes
in the ``exploded graph'' and diagnostics associated with them.
+@item -fdump-analyzer-untracked
+@opindex fdump-analyzer-untracked
+Emit custom warnings with internal details intended for analyzer developers.
+
@end table
@node Debugging Options
diff --git a/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-1.c b/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-1.c
new file mode 100644
index 00000000000..cce3f6b80bc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-1.c
@@ -0,0 +1,126 @@
+/* Test reduced from use of dynamic_pr_debug on Linux kernel, to verify that
+ we treat the static struct _ddebug as not needing to be tracked by the
+ analyzer, thus optimizing away bloat in the analyzer's state tracking. */
+
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-additional-options "-fdump-analyzer-untracked" } */
+
+/* Adapted from various files in the Linux kernel, all of which have: */
+/* SPDX-License-Identifier: GPL-2.0 */
+
+typedef _Bool bool;
+#define true 1
+#define false 0
+
+typedef struct {
+ int counter;
+} atomic_t;
+
+/* Adapted from include/linux/compiler_attributes.h */
+#define __always_inline inline __attribute__((__always_inline__))
+
+/* Adapted from include/linux/compiler-gcc.h */
+#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0)
+
+/* Adapted from include/linux/jump_label.h, which has: */
+
+struct static_key {
+ atomic_t enabled;
+ union {
+ /* [...snip...] */
+ struct jump_entry *entries;
+ /* [...snip...] */
+ };
+};
+
+struct static_key_true {
+ struct static_key key;
+};
+
+struct static_key_false {
+ struct static_key key;
+};
+
+extern bool ____wrong_branch_error(void);
+
+/* Adapted from arch/x86/include/asm/jump_label.h */
+
+#define JUMP_TABLE_ENTRY \
+ ".pushsection __jump_table, \"aw\" \n\t" \
+ /*_ASM_ALIGN*/ "\n\t" \
+ ".long 1b - . \n\t" \
+ ".long %l[l_yes] - . \n\t" \
+ /*_ASM_PTR*/ "%c0 + %c1 - .\n\t" \
+ ".popsection \n\t"
+
+static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
+{
+ asm_volatile_goto("1:"
+ /*".byte " __stringify(BYTES_NOP5) "\n\t" */
+ JUMP_TABLE_ENTRY
+ : : "i" (key), "i" (branch) : : l_yes);
+
+ return false;
+l_yes:
+ return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
+{
+ asm_volatile_goto("1:"
+ "jmp %l[l_yes]\n\t"
+ JUMP_TABLE_ENTRY
+ : : "i" (key), "i" (branch) : : l_yes);
+
+ return false;
+l_yes:
+ return true;
+}
+
+/* Adapted from include/linux/dynamic_debug.h */
+
+struct _ddebug {
+ /* [...snip...] */
+ const char *function;
+ const char *filename;
+ const char *format;
+ unsigned int lineno:18;
+ /* [...snip...] */
+ unsigned int flags:8;
+ union {
+ struct static_key_true dd_key_true;
+ struct static_key_false dd_key_false;
+ } key;
+} __attribute__((aligned(8)));
+
+extern void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
+
+static void expanded_dynamic_pr_debug(void) {
+ do {
+ static struct _ddebug __attribute__((__aligned__(8)))
+ __attribute__((__section__("__dyndbg"))) __UNIQUE_ID_ddebug277 = { /* { dg-warning "track '__UNIQUE_ID_ddebug277': no" } */
+ .function = __func__,
+ .filename = __FILE__,
+ .format = ("hello world"),
+ .lineno = __LINE__,
+ .flags = 0};
+ if (({
+ bool branch;
+ if (__builtin_types_compatible_p(
+ typeof(*&__UNIQUE_ID_ddebug277.key.dd_key_false),
+ struct static_key_true))
+ branch = arch_static_branch_jump(
+ &(&__UNIQUE_ID_ddebug277.key.dd_key_false)->key, false);
+ else if (__builtin_types_compatible_p(
+ typeof(*&__UNIQUE_ID_ddebug277.key.dd_key_false),
+ struct static_key_false))
+ branch = arch_static_branch(
+ &(&__UNIQUE_ID_ddebug277.key.dd_key_false)->key, false);
+ else
+ branch = ____wrong_branch_error();
+ __builtin_expect(!!(branch), 0);
+ }))
+ __dynamic_pr_debug(&__UNIQUE_ID_ddebug277,
+ "hello world");
+ } while (0);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c b/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c
new file mode 100644
index 00000000000..8111709206f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c
@@ -0,0 +1,77 @@
+/* Test reduced from use of dynamic_pr_debug on Linux kernel, to verify that
+ we treat the static struct _ddebug as not needing to be tracked by the
+ analyzer, thus optimizing away bloat in the analyzer's state tracking. */
+
+/* { dg-do compile { target x86_64-*-* } } */
+/* { dg-additional-options "-fdump-analyzer-untracked" } */
+
+/* Adapted from various files in the Linux kernel, all of which have: */
+/* SPDX-License-Identifier: GPL-2.0 */
+
+typedef _Bool bool;
+#define true 1
+#define false 0
+
+typedef struct {} atomic_t;
+
+/* Adapted from include/linux/compiler_attributes.h */
+#define __always_inline inline __attribute__((__always_inline__))
+
+/* Adapted from include/linux/compiler-gcc.h */
+#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0)
+
+/* Adapted from include/linux/jump_label.h, which has: */
+
+struct static_key {};
+
+/* Adapted from arch/x86/include/asm/jump_label.h */
+
+static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch)
+{
+ asm_volatile_goto("1:"
+ : : "i" (key), "i" (branch) : : l_yes);
+
+ return false;
+l_yes:
+ return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch)
+{
+ asm_volatile_goto("1:"
+ : : "i" (key), "i" (branch) : : l_yes);
+
+ return false;
+l_yes:
+ return true;
+}
+
+/* Adapted from include/linux/dynamic_debug.h */
+
+struct _ddebug {
+ /* [...snip...] */
+ const char *function;
+ const char *filename;
+ const char *format;
+ unsigned int lineno:18;
+ /* [...snip...] */
+ unsigned int flags:8;
+ struct static_key key;
+} __attribute__((aligned(8)));
+
+extern void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
+
+static void expanded_dynamic_pr_debug(void) {
+ do {
+ static struct _ddebug __attribute__((__aligned__(8)))
+ __attribute__((__section__("__dyndbg"))) __UNIQUE_ID_ddebug277 = { /* { dg-warning "track '__UNIQUE_ID_ddebug277': no" } */
+ .function = __func__,
+ .filename = __FILE__,
+ .format = ("hello world"),
+ .lineno = __LINE__,
+ .flags = 0};
+ if (arch_static_branch(&__UNIQUE_ID_ddebug277.key, false))
+ __dynamic_pr_debug(&__UNIQUE_ID_ddebug277,
+ "hello world");
+ } while (0);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/many-unused-locals.c b/gcc/testsuite/gcc.dg/analyzer/many-unused-locals.c
new file mode 100644
index 00000000000..6b5c85557c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/many-unused-locals.c
@@ -0,0 +1,69 @@
+struct st
+{
+ const char *m_filename;
+ int m_line;
+ const char *m_function;
+};
+
+extern void debug (struct st *);
+
+#define TEST_x_1(NAME) \
+ do \
+ { \
+ static struct st NAME = { __FILE__, __LINE__, __func__ }; \
+ debug (&NAME); \
+ } \
+ while (0)
+
+#define TEST_x_10(PREFIX) \
+ do \
+ { \
+ TEST_x_1(PREFIX ## _1); \
+ TEST_x_1(PREFIX ## _2); \
+ TEST_x_1(PREFIX ## _3); \
+ TEST_x_1(PREFIX ## _4); \
+ TEST_x_1(PREFIX ## _5); \
+ TEST_x_1(PREFIX ## _6); \
+ TEST_x_1(PREFIX ## _7); \
+ TEST_x_1(PREFIX ## _8); \
+ TEST_x_1(PREFIX ## _9); \
+ TEST_x_1(PREFIX ## _10); \
+ } \
+ while(0)
+
+#define TEST_x_100(PREFIX) \
+ do \
+ { \
+ TEST_x_10(PREFIX ## _1); \
+ TEST_x_10(PREFIX ## _2); \
+ TEST_x_10(PREFIX ## _3); \
+ TEST_x_10(PREFIX ## _4); \
+ TEST_x_10(PREFIX ## _5); \
+ TEST_x_10(PREFIX ## _6); \
+ TEST_x_10(PREFIX ## _7); \
+ TEST_x_10(PREFIX ## _8); \
+ TEST_x_10(PREFIX ## _9); \
+ TEST_x_10(PREFIX ## _10); \
+ } \
+ while(0)
+
+#define TEST_x_1000(PREFIX) \
+ do \
+ { \
+ TEST_x_100(PREFIX ## _1); \
+ TEST_x_100(PREFIX ## _2); \
+ TEST_x_100(PREFIX ## _3); \
+ TEST_x_100(PREFIX ## _4); \
+ TEST_x_100(PREFIX ## _5); \
+ TEST_x_100(PREFIX ## _6); \
+ TEST_x_100(PREFIX ## _7); \
+ TEST_x_100(PREFIX ## _8); \
+ TEST_x_100(PREFIX ## _9); \
+ TEST_x_100(PREFIX ## _10); \
+ } \
+ while(0)
+
+void test_many (void)
+{
+ TEST_x_1000(s);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/untracked-1.c b/gcc/testsuite/gcc.dg/analyzer/untracked-1.c
new file mode 100644
index 00000000000..b7536c399fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/untracked-1.c
@@ -0,0 +1,99 @@
+/* { dg-additional-options "-fdump-analyzer-untracked" } */
+
+struct st
+{
+ const char *m_filename;
+ int m_line;
+};
+
+typedef struct boxed_int { int value; } boxed_int;
+
+extern void extern_fn (struct st *);
+static void __attribute__((noinline)) internal_fn (struct st *) {}
+extern int extern_get_int (void);
+
+void test_0 (void)
+{
+ /* Not ever referenced; will get optimized away before
+ analyzer ever sees it, so no message. */
+ static struct st s1 = { __FILE__, __LINE__ };
+}
+
+void test_1 (void)
+{
+ static struct st s1 = { __FILE__, __LINE__ }; /* { dg-warning "track 's1': no" } */
+ extern_fn (&s1);
+}
+
+static struct st s2 = { __FILE__, __LINE__ }; /* { dg-warning "track 's2': yes" } */
+
+void test_2 (void)
+{
+ extern_fn (&s2);
+}
+
+void test_3 (void)
+{
+ struct st s3 = { __FILE__, __LINE__ }; /* { dg-warning "track 's3': yes" } */
+ extern_fn (&s3);
+}
+
+extern void called_by_test_4 (int *);
+
+int test_4 (void)
+{
+ int i; /* { dg-warning "track 'i': yes" } */
+ called_by_test_4 (&i);
+ return i;
+}
+
+void test_5 (int i)
+{
+ boxed_int bi5 = { i }; /* { dg-warning "track 'bi5': yes" } */
+}
+
+int test_6 (int i)
+{
+ static boxed_int bi6; /* { dg-warning "track 'bi6': yes" } */
+ bi6.value = i;
+ return bi6.value;
+}
+
+int test_7 (void)
+{
+ boxed_int bi7; /* { dg-warning "track 'bi7': yes" } */
+ return bi7.value; /* { dg-warning "use of uninitialized value 'bi7.value'" "uninit" } */
+}
+
+void test_8 (void)
+{
+ static struct st s8 = { __FILE__, __LINE__ }; /* { dg-warning "track 's8': no" } */
+ extern_fn (&s8);
+ extern_fn (&s8);
+}
+
+void test_9 (void)
+{
+ static struct st s9 = { __FILE__, __LINE__ }; /* { dg-warning "track 's9': yes" } */
+ internal_fn (&s9);
+}
+
+int test_10 (void)
+{
+ static struct st s10 = { __FILE__, __LINE__ }; /* { dg-warning "track 's10': yes" } */
+ extern_fn (&s10);
+ return s10.m_line;
+}
+
+int test_11 (void)
+{
+ static struct st s10 = { __FILE__, __LINE__ }; /* { dg-warning "track 's10': yes" } */
+ s10.m_line = extern_get_int ();
+ return 42;
+}
+
+int test_12 (void (*fnptr) (struct st *))
+{
+ static struct st s12 = { __FILE__, __LINE__ }; /* { dg-warning "track 's12': yes" } */
+ fnptr (&s12);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/unused-local-1.c b/gcc/testsuite/gcc.dg/analyzer/unused-local-1.c
new file mode 100644
index 00000000000..361cdced6e3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/unused-local-1.c
@@ -0,0 +1,22 @@
+/* { dg-additional-options "-fdump-analyzer-untracked" } */
+
+struct st
+{
+ const char *m_filename;
+ int m_line;
+ const char *m_function;
+};
+
+extern void debug (struct st *);
+
+void test (void)
+{
+ {
+ static struct st s1 = { __FILE__, __LINE__, __func__ }; /* { dg-warning "track 's1': no" } */
+ debug (&s1);
+ }
+ {
+ static struct st s2 = { __FILE__, __LINE__, __func__ }; /* { dg-warning "track 's2': no" } */
+ debug (&s2);
+ }
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-03-25 1:00 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-25 1:00 [gcc r12-7809] analyzer: add region::tracked_p to optimize state objects [PR104954] David Malcolm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).