Two comments inline,
Am 9/27/2024 um 6:38 AM schrieb Boqun Feng:
compilers can replace 'ptr' with 'head' because of the equality, and
even putting barrier() here cannot prevent compiler to rewrite the else
branch into:
else {
barrier();
return head;
}
because that's just using a different register, unrelated to memory
accesses.
Yeah, that was the solution I had in mind. My reasoning was that from
the C abstract machine, head is still a memory access, and the barrier()
should make the compiler forget everything it knew about the value of
head from before the barrier().
So I had a gap in my understanding of the strength of barrier(). Can I
understand it to mean that the compiler can do escape analysis to reason
that a volatile asm code with ::memory can't possibly be manipulating
some variables (like head in this case)?
That idea seems to be confirmed by this (atrocious, not to be copied!)
example:
int fct_escape_address_of_b(void)
{
int *a, *b;
do {
a = READ_ONCE(p);
asm volatile ("" : : : "memory");
b = READ_ONCE(p);
} while (a != b);
// really really hide b
int **p = &b;
OPTIMIZER_HIDE_VAR(p);
asm volatile ("" : : : "memory");
return *b;
}
This also does not generate any additional instructions, unlike just
using OPTIMIZER_HIDE_VAR(b).
What is the advantage of defining OPTIMIZE_HIDE_VAR the way it currently
works instead of like above?
> On Fri, Sep 27, 2024 at 03:20:40AM +0200, Mathieu Desnoyers wrote:
I have a set of examples below that show gcc use the result of the
first load, and clang use the result of the second load (on
both x86-64 and aarch64). Likewise when a load-acquire is used as
second load, which I find odd.
Note that if you use acquire on the second load, the code is correct
even if the compiler uses the result of the first load.
That is because the acquire load will still synchronize sufficiently
with the second publishing store after the ABA, and then we can get the
right data even from the old address.
Best wishes,
jonas