(For reviewers who get duplicates, sorry! Forgot to add llvm-commits to the first review and had to close it and open another.)
According to my reading of the LangRef, volatiles are only ordered with respect to other volatiles. It is entirely legal and profitable to forward unrelated loads over the volatile load. This patch implements this for GVN by refining the transition rules MemoryDependenceAnalysis uses when encountering a volatile.
The added test cases show where the extra flexibility is profitable for local dependence optimizations. I have a related patch (http://reviews.llvm.org/D6895) which will extend this to non-local dependence (i.e. PRE), but that's essentially orthogonal to the semantic change in this patch. I have tested the two together and can confirm that PRE works over a volatile load with both changes.
One question for reviewers: should a load being volatile change the default handling for a *may* alias load? For a non-volatile load, we'll keep scanning past looking for an actual mustalias dependency. Is this the behaviour we want for volatiles? While I think this matches the letter of the LangRef, I'm not entirely sure it matches the expectations of mapping C volatile to LLVM volatile. In particular, should the following code always return 0? With my current patch, we can and will forward the first load to third without changing the second.
int example(int* p, int *q) { // q == p at runtime
int x = *p; *(volatile int*)q int y = *p; return x-y;
}