mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
LKMM pull request for v5.18
This series contains an improved explanation of syntactic and semantic dependencies from Alan Stern. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEbK7UrM+RBIrCoViJnr8S83LZ+4wFAmIurqQTHHBhdWxtY2tA a2VybmVsLm9yZwAKCRCevxLzctn7jGQnD/0eB7REmhm/nxzSttC6/l0aQMWoijRu uNFaeK7y+UmfjcVfS0VflUFwzmEOduLHUHeUOpXT7GoEEuoVi/4tN5YEgdarDCwn TPsMAizAvbrj3TymbXF1z+DC2QiWWeufVTcv4dSSKJviC839Zaauh4QZmoys7yGM BSuUX+dOHax6XGoXtolIqGwplH71RFkFM1dJy4BSSdmhVsTPuFLkxhoBVI9X4LgO tmRNAwV2J2mig8+HuMhtl+dYaugUTHAjZ+GqqFz7BhmH5isXuVPGK1iankEuiOhs rzvKNKrA0YW903a3bPj3g0DclbYYAFygOjBu49Jl6Y+BeHoID2eNbt9/+n+DWAtt D/uKJNFUfdVsDbBQ61P52rB0Bhz3dl3wTR4f6Nn7+MBNJAzLrhTVa73EZAzI1nuO GDReAzr6eb0xRB+WibFLK4iXVhRYw406YW9VPp/Ikl1DLl8vnPZlrQR3rEjTGhi7 lyLRRCXKBb8Aaja1rdHFG4CDb3j+BXW44YscC0wrAFzK9MQFOeHbLupruf4TxsXL X1KEFDqPVWPSCjTt9NbA1AofWNGIQFmjU3PNB7xLMLIlOBHRoI/ia4RUotA0cWz/ f5uFFKbFFeW+ZKDJtKyMBpNJpnnBrOqo1TrXBxIICM3DrYxFfiGDqrByebn7TupA GWRa5nAQjXIoBQ== =bGU7 -----END PGP SIGNATURE----- Merge tag 'lkmm.2022.03.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu Pull memory model doc update from Paul McKenney: "An improved explanation of syntactic and semantic dependencies from Alan Stern" * tag 'lkmm.2022.03.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: tools/memory-model: Explain syntactic and semantic dependencies
This commit is contained in:
commit
d2eb5500f1
@ -485,6 +485,57 @@ have R ->po X. It wouldn't make sense for a computation to depend
|
||||
somehow on a value that doesn't get loaded from shared memory until
|
||||
later in the code!
|
||||
|
||||
Here's a trick question: When is a dependency not a dependency? Answer:
|
||||
When it is purely syntactic rather than semantic. We say a dependency
|
||||
between two accesses is purely syntactic if the second access doesn't
|
||||
actually depend on the result of the first. Here is a trivial example:
|
||||
|
||||
r1 = READ_ONCE(x);
|
||||
WRITE_ONCE(y, r1 * 0);
|
||||
|
||||
There appears to be a data dependency from the load of x to the store
|
||||
of y, since the value to be stored is computed from the value that was
|
||||
loaded. But in fact, the value stored does not really depend on
|
||||
anything since it will always be 0. Thus the data dependency is only
|
||||
syntactic (it appears to exist in the code) but not semantic (the
|
||||
second access will always be the same, regardless of the value of the
|
||||
first access). Given code like this, a compiler could simply discard
|
||||
the value returned by the load from x, which would certainly destroy
|
||||
any dependency. (The compiler is not permitted to eliminate entirely
|
||||
the load generated for a READ_ONCE() -- that's one of the nice
|
||||
properties of READ_ONCE() -- but it is allowed to ignore the load's
|
||||
value.)
|
||||
|
||||
It's natural to object that no one in their right mind would write
|
||||
code like the above. However, macro expansions can easily give rise
|
||||
to this sort of thing, in ways that often are not apparent to the
|
||||
programmer.
|
||||
|
||||
Another mechanism that can lead to purely syntactic dependencies is
|
||||
related to the notion of "undefined behavior". Certain program
|
||||
behaviors are called "undefined" in the C language specification,
|
||||
which means that when they occur there are no guarantees at all about
|
||||
the outcome. Consider the following example:
|
||||
|
||||
int a[1];
|
||||
int i;
|
||||
|
||||
r1 = READ_ONCE(i);
|
||||
r2 = READ_ONCE(a[r1]);
|
||||
|
||||
Access beyond the end or before the beginning of an array is one kind
|
||||
of undefined behavior. Therefore the compiler doesn't have to worry
|
||||
about what will happen if r1 is nonzero, and it can assume that r1
|
||||
will always be zero regardless of the value actually loaded from i.
|
||||
(If the assumption turns out to be wrong the resulting behavior will
|
||||
be undefined anyway, so the compiler doesn't care!) Thus the value
|
||||
from the load can be discarded, breaking the address dependency.
|
||||
|
||||
The LKMM is unaware that purely syntactic dependencies are different
|
||||
from semantic dependencies and therefore mistakenly predicts that the
|
||||
accesses in the two examples above will be ordered. This is another
|
||||
example of how the compiler can undermine the memory model. Be warned.
|
||||
|
||||
|
||||
THE READS-FROM RELATION: rf, rfi, and rfe
|
||||
-----------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user