[PATCH] D23214: [MDA] Treat invariant.start as non-dependence
Sanjoy Das via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 8 13:51:08 PDT 2016
Hi Daniel,
Daniel Berlin wrote:
> Well, no.
> If invariant end was readonly, it would value forward past invariant
> ends, and extend the range in the case it was like this:
>
> %a =invariant.start
> ...
> invariant.end(%a)
>
> <non-memory affecting instructions>
>
> %b=invariant.start
> ...
> invariant.end(%b)
>
> As long as there are no memory writing instructions in the middle,
> things will believe the two invariant starts produce the same value, and
> forward it :)
I have to think about it a bit more before I can commit to this, but
at least intuitively the above seems fine -- if there are no memory
clobbering instructions between the two ranges then they should be
merged. This can even be a valuable optimization in cases where the
"<non-memory affecting instruction>" bits were hidden behind a call
that was later inlined.
The way I see it is that invariant_start and invariant_end denote the
boundaries of a region that can be assumed to not have stores to a
specific location[1]. To preserve this property we only need to avoid
stores floating into the region, and for that readonly semantics is
sufficient for non-atomic accesses (and potentially some kinds of
atomic accesses too). Readonly semantics may even be stronger than we
need, since I think we can allow stores floating *out* of the region.
I'm not yet fully confident that the above semantics will hold under
pressure, since it fails the test of "can I write an implementation of
invariant_start and invariant_end that will give me the guarantees I
need?". The best I can do with invariant_start and invariant_end as
specified is:
void* invariant_start(iN* ptr) {
cell = malloc(sizeof(iN));
*(iN*)cell = ptr;
return cell;
}
void invariant_end(void* cell, iN* ptr) {
assert(*(iN*)cell == *ptr);
}
which still allows the transform:
x = invariant_start(ptr)
int val = *ptr;
print(val);
invariant_end(x, ptr)
==>
x = invariant_start(ptr)
int val_backup = *ptr;
*ptr = 400;
*ptr = val_backup;
int val = *ptr;
print(val);
invariant_end(x, ptr)
That's not a clear problem (after all, intrinsics are allowed to have
special semantics that may not be "implementable" in IR), but it is a
"slightly red" flag.
[1]: An alternate framing would be: no stores to that specific
location change the contained value.
-- Sanjoy
>
> GVN is not quite smart enough yet, but it's about to be.
>
> GCC even has testcases that we both eliminate and PRE pure/const
> (readonly/readnone) calls.
More information about the llvm-commits
mailing list