On Mon, Jan 13, 2020 at 05:10:24PM -0500, David Malcolm wrote:
> Unfortunately, I didn't resolve the hash_table/hash_map issue
> referred to here:
>   https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00734.html
> where r279139 on 2019-12-09 introduced the assumption that empty
> hash_table entries and empty hash_map keys are all zeroes.
> 
> The analyzer uses hash_map::empty in a single place with a hash_map
> where the "empty" key value is all-ones.
> 
> Unfortunately, without a fix for this issue, the analyzer can hang,
> leading to DejaGnu hanging, which I clearly don't want to push to
> master as-is.
> 
> The patch here fixes the issue:
>   https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00776.html
> but Jakub has expressed concern about the effect on code generated
> for the compiler.
> 
> As noted here:
>   https://gcc.gnu.org/ml/gcc-patches/2020-01/msg00651.html
> gcc successfully converts this back to a memset to 0 for hash_table
> at -O2, but not for hash_map, since it can't "know" that it's OK to
> clobber the values as well as the keys; it instead generates a loop
> that zeroes the keys without touching the values.

I guess in some cases the loop could be better (e.g. if the values are
large and/or keys too and mark_empty only sets something small), but I bet
in most cases the memset will be better.

> Some options:
> (a) the patch to fix hash_table::empty, and the analyzer kit
> (b) the analyzer kit with the following kludge
> (c) someone with better C++-fu than me figure out a way to get the
> memset optimization for hash_map with 0-valued empty (or to give me
> some suggestions)
> (d) not merge the analyzer for gcc 10

For (c), I see right now we have 37 mark_empty definitions:
find -type f | grep -v 'testsuite/\|ChangeLog' | xargs grep mark_empty | wc -l
37
From quick skimming of them, most of them are just zeroing one or more
fields, exceptions are profile.c, attribs.c (this one only in self-tests
and it is unclear why deleted is two NULLs and empty two ""s rather than
vice versa), and gcov.c.  Also, int_hash can be zero or non-zero, depending
on template argument, e.g.
typedef hash_map<int_hash <unsigned int, -1U>, unsigned int> live_vars_map;
struct uid_hash : int_hash <int, -1, -2> {};
are not either.
Can't we add next to the mark_empty and is_empty methods also a static const
bool data member empty_zero_p or similar and use it in in the two
hash-table.h spots where this would make a difference?
In alloc_entries the
  for (size_t i = 0; i < n; i++)
    mark_empty (nentries[i]);
loop could be conditionalized on !Descriptor::empty_zero_p because both
allocation paths actually allocate cleared memory, and in the spot
you are talking about.

Or isn't there (e), tweak whatever hash_table traits you use so that
empty case is all zeros?

        Jakub

Reply via email to