analyzer: add region::tracked_p to optimize state objects [PR104954]
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 25 Mar 2022 00:58:10 +0000 (20:58 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Fri, 25 Mar 2022 00:58:10 +0000 (20:58 -0400)
commit5f6197d7c197f9d2b7fb2e1a19dac39a023755e8
tree55c78e08c0ae81516a4c8708283d76352ae64b52
parent319ba7e241e7e21f9eb481f075310796f13d2035
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>
14 files changed:
gcc/analyzer/analyzer.opt
gcc/analyzer/engine.cc
gcc/analyzer/region-model-asm.cc
gcc/analyzer/region-model-manager.cc
gcc/analyzer/region-model.h
gcc/analyzer/region.cc
gcc/analyzer/region.h
gcc/analyzer/store.cc
gcc/doc/invoke.texi
gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/asm-x86-dyndbg-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/many-unused-locals.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/untracked-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/unused-local-1.c [new file with mode: 0644]