Declare that a nofree function cannot arrange for memory to be freed
that was dereferenceable before the call -- whether by (transitive) call
or by communication with another thread.
This is a simplification from the perspective of using the information
provided by the function attribute when optimizing the caller, at the
cost of complicating the inference of nofree.
This change arguably increases the expressive power of the IR, since we
can now have functions that are (usefully) nofree without being nosync.
Before this change, nofree on a not-nosync function does not do
The attributor is updated so that a function containing a volatile
memory operation or a release (or stronger) atomic operations is not
nofree. The reasoning behind only checking for release ordering is
explained in a code comment.
@jdoerfert: I have zero knowledge of the attributor infrastructure, so if
this direction is taken I'd appreciate a review specifically of those parts.