[llvm] [coro][CoroSplit] Use `llvm.lifetime.end` to compute putting objects on the frame vs the stack (PR #90265)

Alan Zhao via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 29 22:01:01 PDT 2024


================
@@ -1614,6 +1621,24 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
       // suspend point between lifetime markers. This should also cover the
       // case of a single lifetime.start intrinsic in a loop with suspend point.
       if (PI.isEscaped()) {
+        // If there is no explicit lifetime.end, then assume the address can
+        // cross suspension points.
+        if (LifetimeEndBBs.empty())
+          return true;
+
+        // If there is a path from a lifetime.start to a suspend without a
+        // corresponding lifetime.end, then the alloca's lifetime persists
+        // beyond that suspension point and the alloca must go on the frame.
+        for (AnyCoroSuspendInst *SuspendInst : CoroShape.CoroSuspends) {
+          SmallVector<BasicBlock *> LifetimeStartsBB;
+          for (IntrinsicInst *II : LifetimeStarts)
+            LifetimeStartsBB.push_back(II->getParent());
+          if (isPotentiallyReachableFromMany(LifetimeStartsBB,
----------------
alanzhao1 wrote:

The problem is that we have to detect whether there are other `llvm.coro.end`s between `llvm.lifetime.start` and `llvm.lifetime.end` - see for example:

[Block A: `lifetime.start`] -> [Block B: `lifetime.end`] -> [Block C: `coro.suspend`] -> [Block D: `lifetime.end`].

In this case, if we were analyzing A -> D, then we would see that there is a path from A's `lifetime.start` to D's `lifetime.start`, suggesting that we need to put the object on the frame. However, this analysis is incorrect because B ends the lifetime before `coro.suspend`. A correct analysis would need some way to filter out all intermediate `lifetime.end` blocks

This is even more problematic for the case in the original bug where `lifetime.end` was missing. Therefore, we would need to check paths from `lifetime.start` to `return` and `unreachable`. So for example:

[Block A: `lifetime.start`] -> [Block B: `lifetime.end`] -> [Block C: `coro.suspend`] -> [Block D: `unreachable`].

we would run into the same problem because we see that `lifetime.start` -> `unreachable` requires a pass through `coro.suspend`, suggesting that we need to put the object on the frame when we actually don't due to the `lifetime.end`.

https://github.com/llvm/llvm-project/pull/90265


More information about the llvm-commits mailing list