[PATCH] D23214: [MDA] Treat invariant.start as non-dependence
Sanjoy Das via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 5 15:23:25 PDT 2016
Hi Daniel,
Daniel Berlin wrote:
> Okay, so you are saying you don't believe it will cause the same problem
> because you don't believe anything will legally try to hoist these.
Yes (unless we special case invariant_* intrinsics some other way).
> I'm willing to find out!
>
> Otherwise it will introduce undefined
> behavior:
>
> I'm not opposed to trying to mark these as readonly, but realize you are
> also assuming you know what the real invariant range is and what causes
> it :)
>
> Given the following:
>
> store(something that LLVM does not think aliases foo)
> bar = invariant.start(foo, 5)
> load foo
> invariant.end(bar)
>
> Transforming it into:
>
> bar = invariant.start(foo, 5)
> store(something that LLVM does not think aliases foo)
> load foo
> invariant.end(bar)
>
> Is equally as illegal by the langref, since you are now saying "during
> the operation of this store, the memory for foo is invariant", which is
> not what it said originally (though i can't think of cases this will
> break that don't involve threading).
(If!) I understand what you're saying, I was not able to come with a
concrete multi-threaded situation where re-ordering non-aliasing
stores will be a problem, as long as we respect
acquire/release/seq_cst re-ordering restrictions a readonly call would
have to obey. This is the closest example I could come up with:
// ptr0 and ptr1 are noalias, *ptr0 == 0, *thread_b_start = false
// initially, all accesses are relaxed.
ThreadA:
*ptr0 = 50
fence seq_cst
*thread_b_start = true
*ptr1 = 100
invariant_start(ptr1, sizeof(*ptr0))
**global = 90
int val = *ptr1
ThreadB:
while (!*thread_b_start) { fence seq_cst; }
fence seq_cst
if (*ptr0 != 50)
global = ptr1
The idea being we can certify *ptr1 to be invariant only once we've
published the *ptr0 = 50 store. If that gets re-ordered with the
invariant_start call then we're in trouble because the location would,
in fact, be changed by ThreadB while ThreadA was supposed to observe
an invariant *ptr1. However, I'd expect the "fence seq_cst" to
prevent that re-ordering.
> I also don't honestly know if getModRefInfo is going to say this is
> legal or not.
>
> That said, in theory:
>
> %a = add 5, 3
> bar = invariant.start(foo, 5)
> load foo
> invariant.end(bar)
>
> to
> bar = invariant.start(foo, 5)
> %a = add 5, 3
> load foo
> invariant.end(bar)
>
> is probably also illegal, and has the same issues :)
I don't understand why that ^ is a problem.
> With the memdep changes we will allow reordering loads across the
> invarinat_start call:
>
> int val = *ptr;
> invariant_start(ptr)
>
> <==>
>
> int val = *ptr;
> invariant_start(ptr)
>
>
> (you meant for the first one to have the load after invariant start, i
> presume)
I meant given what we're teaching MDA, the two are equivalent (hence
the "bidirectional arrow" :)).
> I'm willing to give it a shot if you want, i'm just in the "we'll
> probably break something unexpected" camp :)
I now think it is better to add one more special case to AliasAnalysis
around invariant_start s, like we do for assumes. It's a hack, but at
least a localized hack.
-- Sanjoy
More information about the llvm-commits
mailing list