On Wed, 16 Jan 2019, Andrea Parri wrote:

> Can the compiler (maybe, it does?) transform, at the C or at the "asm"
> level, LB1's P0 in LB2's P0 (LB1 and LB2 are reported below)?
> 
> C LB1
> 
> {
>       int *x = &a;
> }
> 
> P0(int **x, int *y)
> {
>       int *r0;
> 
>       r0 = rcu_dereference(*x);
>       *r0 = 0;
>       smp_wmb();
>       WRITE_ONCE(*y, 1);
> }
> 
> P1(int **x, int *y, int *b)
> {
>       int r0;
> 
>       r0 = READ_ONCE(*y);
>       rcu_assign_pointer(*x, b);
> }
> 
> exists (0:r0=b /\ 1:r0=1)
> 
> 
> C LB2
> 
> {
>       int *x = &a;
> }
> 
> P0(int **x, int *y)
> {
>       int *r0;
> 
>       r0 = rcu_dereference(*x);
>       if (*r0)
>               *r0 = 0;
>       smp_wmb();
>       WRITE_ONCE(*y, 1);
> }
> 
> P1(int **x, int *y, int *b)
> {
>       int r0;
> 
>       r0 = READ_ONCE(*y);
>       rcu_assign_pointer(*x, b);
> }
> 
> exists (0:r0=b /\ 1:r0=1)
> 
> LB1 and LB2 are data-race free, according to the patch; LB1's "exists"
> clause is not satisfiable, while LB2's "exists" clause is satisfiable.

Umm.  Transforming

        *r0 = 0;

to

        if (*r0 != 0)
                *r0 = 0;

wouldn't work on Alpha if r0 was assigned from a plain read with no
memory barrier between.  But when r0 is assigned from an
rcu_dereference call, or if there's no indirection (as in "if (a != 0)
a = 0;"), the compiler is indeed allowed to perform this
transformation.

This means my definition of preserved writes was wrong; a write we 
thought had to be preserved could instead be transformed into a read.

This objection throws a serious monkey wrench into my approach.  For
one thing, it implies that (as in the example) we can't expect
smp_wmb() always to order plain writes.  For another, it means we have
to assume a lot more writes need not be preserved.

I don't know.  This may doom the effort to formalize dependencies to
plain accesses.  Or at least, those other than address dependencies
from marked reads.

Alan

Reply via email to