[llvm-commits] patch: CXAGuardElimination pass.

Luke Dalessandro luked at cs.rochester.edu
Tue May 26 07:06:08 PDT 2009


Nick Lewycky wrote:
> Eli Friedman wrote:
>> On Mon, May 25, 2009 at 5:17 PM, Nick Lewycky <nicholas at mxc.ca> wrote:
>>> Eli Friedman wrote:
>>>> On Mon, May 25, 2009 at 3:59 PM, Nick Lewycky <nicholas at mxc.ca> wrote:

[cut]

>>>> Ooh, that's right.  Actually, it gets nastier than that: suppose
>>>> something like the following:
>>>>
>>>> static int gval1 = 1;
>>>> int gval2 = 1;
>>>> struct A { A() { if (gval1) { printf("%d\n", gval2); } };
>>>> void a() { static A x(); gval2 = 0;}
>>>> void b() { a(); }
>>>> void c() { gval1 = 0; a(); }
>>>>
>>>> Then suppose b() and c() are called at the same time on separate
>>>> threads, and we've inlined/optimized everything; if the guard is
>>>> removed from c(), we can end up printing out "0", which shouldn't be
>>>> possible because setting gval2 to zero only happens after the
>>>> constructor for A finishes. 
>>>>
>>> Right. deadGuardElim checks for memory *reads* as well as writes and
>>> unwinds in order to prevent this sort of thing from happening. 
>>>
>> If a() gets inlined into c(), the load inside A() of gval1 can be
>> eliminated; I'm not sure if we do that particular optimization at the
>> moment, though.

This example has data races on gval1 and gval2. The LLVM VM doesn't have 
a memory model as far as I know, which basically means that all sorts of 
crazy things are allowed to happen to this code. Printing out 0 is 
probably fine. Even in something like the Java Memory Model printing out 
0 is fine, given the raciness of the code.

The main concern is if the __cxa_guard_acquire and release pair are 
supposed to have locking semantics. The Intel ABI says that they are 
"probably" implemented with locks, but doesn't really pin down any 
ordering semantics for them. It seems mandatory that any real 
implementation has to enforce some sort of synchronization to be correct 
-- even if it's nonblocking. This probably requires that you insert a 
memory fence if you remove the guards, or know the actual implementation 
of the library calls.

I don't have an example off-hand that triggers this behavior, but it's 
one of those traditional problems. The Java literature probably has some 
examples that are applicable.

> 
> Boo. We'll continue to have problems so long as we try to eliminate one 
> pair at a time, we need to either prove them all dead for a given guard 
> variable or not.
> 

You may be ok. You just need to make sure that you don't introduce a 
data race into an otherwise data-race-free program.

Luke

> Excellent review, by the way!
> 
> Nick
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list