This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: Optimization of conditional access to globals: thread-unsafe?


On 27 October 2007 18:27, Darryl Miles wrote:

> The "unintended write-access" optimization is a massive headache for
> developers of multi-threaded code.

  But it's a boon for the autovectoriser, because it means it can transform
code with a branch into straight-line code.

> The problem here is the mandatory write access to a memory location for
> which the as-written code path does not indicate a write memory access
> should occur.

  That's the difference between as-if and actual.
 
> This is a tricky one, optimizations which have the effect of causing an
> "unintended write access to some resource" when the code path does not
> intend this to happen crosses a line IMHO.

  Well, volatile was invented to address this exact issue.  If you use it, you
get exactly what you're asking for.
 
> I think that GCC should understand where that line is and have a compile
> time parameter to configure if that line maybe crossed.  Its a matter
> for debate as to what the default should be and/or -O6 should allow that
> line to be crossed, but having no mechanism to control it is the real
> bummer.

  Well, that's kind of like what -fvolatile used to do; but it's a bit
indiscriminate to apply it to the entire program when shared state of this
sort may be infrequent or even entirely absent.
 
> Even if the interpretation offered of the C language standards
> specification says the line maybe be crossed, from a practical point of
> view this is one aspect of optimization that a developer would want to
> have complete control over.

  That's what volatile gives you.
 
> So much control that I would also like to see a pair of
> __attribute__((optimization_hint_keywords)) attached to the variable
> declaration to provide fine grain control.  Such a solution to the
> problem would keep everybody happy.

  How about attaching the 'volatile' keyword to the variable?

>> Here are some pieces from C99:
>> 
> ...SNIP...
>> Sec 3.1 par 4: NOTE 3 Expressions that are not evaluated do not access
>>                objects.

  I only have a draft copy, but isn't this language specific to the definition
of 'restrict' semantics?  I'm not sure it's relevant here in that case.
 
> Hmm... on this point there can be a problem.  There are 2 major types of
> access read from memory (load) and write to memory (store).  It is very
> possible to end up performing an optimistic read; only to throw away the
> value contained due to a compare/jump.  This is usually considered a
> safe optimization.

  As embedded programmers who have to deal with registers containing
auto-resetting status bits have known for many years, this is not a safe
optimisation at all.  We use 'volatile' to suppress it.

> But reading the statement above as-is and in the context of this problem
> might make some believe this  "optimistic read" optimization is breaking
> the rules.


> NB Marking the variable 'volatile' does not mean anything useful in the
> situation you are in.  The exact meaning of what 'volatile' is can be a
> problem between compilers, but in the case of GCC it can stop the
> re-ordering and the caching of value in register aspect of your entire
> problem.  But it will never enforce the method used to perform the
> load/store, not will it (at this time) stop the unintended write-access.

  Huh?  When I tried compiling the test case, it did exactly that.  Hang on,
I'll check:

[dk@tuxtlas serial_booting]$ gcc -S -O1 -x c - -o a.s

     extern int v;

     void
     f(int set_v)
     {
       if (set_v)
         v = 1;
     }


[dk@tuxtlas serial_booting]$ cat a.s
        .file   ""
        .text
.globl f
        .type   f, @function
f:
.LFB2:
        testl   %edi, %edi
        movl    $1, %eax
        cmove   v(%rip), %eax
        movl    %eax, v(%rip)
        ret
.LFE2:
        .size   f, .-f
        .section        .eh_frame,"a",@progbits

        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-8)"
[dk@tuxtlas serial_booting]$ gcc -S -O1 -x c - -o a.s

     extern volatile int v ;


     void
     f(int set_v)
     {
       if (set_v)
         v = 1;
     }

[dk@tuxtlas serial_booting]$ cat a.s
        .file   ""
        .text
.globl f
        .type   f, @function
f:
.LFB2:
        testl   %edi, %edi
        je      .L1
        movl    $1, v(%rip)
.L1:
        rep ; ret
.LFE2:
        .size   f, .-f
        .section        .eh_frame,"a",@progbits

        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-8)"
[dk@tuxtlas serial_booting]$


  Looks good to me.  Isn't that what everyone wants the compiler to be doing
with this code?

    cheers,
      DaveK
-- 
Can't think of a witty .sigline today....


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]