This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
RE: Optimization of conditional access to globals: thread-unsafe?
- From: "Dave Korn" <dave dot korn at artimi dot com>
- To: "'Darryl Miles'" <darryl-mailinglists at netbauds dot net>, "'Tomash Brechko'" <tomash dot brechko at gmail dot com>
- Cc: <gcc at gcc dot gnu dot org>
- Date: Sat, 27 Oct 2007 20:37:33 +0100
- Subject: RE: Optimization of conditional access to globals: thread-unsafe?
- References: <20071021145513.GB4925@moonlight.home> <472374FD.3080402@netbauds.net>
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....