问题
Consider this code, where x
and y
are integers:
if (x)
y = 42;
Is the following compiler transformation allowed ?
int tmp = y;
y = 42;
if (!x)
y = tmp;
context:
This is from Bjarne Stroustrup's FAQ:
// start with x==0 and y==0
if (x) y = 1; // Thread 1
if (y) x = 1; // Thread 2
The FAQ states this is data race free; with x
and y
both 0, none of the vars should be written to.
But what if the transformation is allowed ?
回答1:
Unlike I wrote in my incorrect comment, this transformation is actually not allowed if y
is potentially shared between threads and the compiler cannot prove any existing UB in the original code.
The standard explicitly says:
Compiler transformations that introduce assignments to a potentially shared memory location that would not be modified by the abstract machine are generally precluded by this standard, since such an assignment might overwrite another assignment by a different thread in cases in which an abstract machine execution would not have encountered a data race.
[intro.multithread] (1.10/22) in N3337, (1.10/25) in N4141.
So if x
is always 0, the original code would be race-free, while the transformed one wouldn't. Thus the transformation is not legal.
回答2:
If it was, then you just wouldn't be able to exclude access to any object that's reachable from global variables or other variables. The compiler could even tentatively call functions that are never called, whenever an indirect call is made, and "cancel" their effect afterward by restoring the original value.
Going down this opti-pessimisation path, it could do division by zero in advance then "ignore" the result if the divisor was zero, even if that's a trap and program is stopped.
This is patently absurd and must be rejected whether or not the standard says it should be.
来源:https://stackoverflow.com/questions/45885048/is-this-compiler-transformation-allowed