[LLVMdev] Can simplifycfg kill llvm.lifetime intrinsics?
Nick Lewycky
nicholas at mxc.ca
Thu Dec 27 23:11:04 PST 2012
On 12/27/2012 12:35 PM, Rafael EspĂndola wrote:
>>> Oh, I was reading "precedes/following" as having static (dominance)
>>> meaning. That is, in the above example you could not delete the store
>>> since it is not true that
>>> llvm.lifetime.end dominates it.
>>>
>>> Nick, is this what you had in mind? If not, then we must delete a
>>> matching llvm.lifetime.end, but it is not clear how we define
>>> "matching". In the following code some executions will hit the first
>>> llvm.lifetime.end and others will hit the second one.
>>
>>
>> Yes, I meant at runtime.
>>
>
> OK, thanks. What is the meaning in the case of aliases? Should this work:
>
> llvm.lifetime.start(%x)
>
> ...
>
> llvm.lifetime.end(%y which alias %x sometimes)
That's only a matching pair iff %x == %y at run time.
(If I wanted to require statically analyzable pairings, I would've made
start return type {} and have the end intrinsic take that as an
argument, like I did for the invariant intrinsics.)
You can almost entirely model lifetime.start and lifetime.end as being a
store of undef to the address. However, they're the tiniest bit
stronger. With a store of undef, you can delete stores that precede
(with no intervening load) and loads that follow (with no intervening
store). On top of that, a start lets you delete loads that precede, and
an end lets you delete stores that follow.
> If so, I guess that in order to delete a llvm.lifetime.start we have
> to delete all llvm.lifetime.end that are "directly" reachable from it
> and take an argument that may alias the one passed to
> llvm.lifetime.start. Is that it? What about calling
> llvm.lifetime.start in one function and llvm.lifetime.end in another?
>
> It seems that deleting llvm.lifetime.start is impossible in general,
> but it is safe to add one if at least one already exists, is that the
> case?
>
> On the other hand, removing llvm.lifetime.end should always be safe, right?
I really only invented them for a specific case, so I haven't thought
through all the cases where it may or may not be legal to add or delete
them. Here goes!
Suppose you have four lifetime operations on the same address in memory,
with loads and stores all around them:
start1--end1 .. start2--end2
If you remove start1 then you have a bare pointer, the memory came from
somewhere and you lose the optimization that loads before start1 become
undef, but you don't miscompile.
If you remove end1 then the code between start1 and start2 is in
trouble. We would miscompile start1+store+load+start2 by folding the
load to undef.
If you remove start2, we miscompile again. Accesses between start2 and
end2 could be transformed into loads of undef and dead stores, and deleted.
Removing end2 only means that you get to assume the memory is still live
since you haven't been told otherwise.
So ultimately the problem is with removing either part of the end->start
transition. We need to make sure we don't remove one of those.
This means that the optimizer can't consider lifetime intrinsics to be
no-ops unless it can prove it's looking at the first start or last end
of that memory address. That's much worse than I thought it was when I
first added these intrinsics. Sorry.
Nick
More information about the llvm-dev
mailing list