[llvm] [LoopPeel] LCSSA form is destroyed by LoopPeel, preserve it (PR #78696)
Vedant Paranjape via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 1 01:24:45 PST 2024
vedantparanjape-amd wrote:
> @vedantparanjape-amd , going by the definition of LCSSA, I see that %0 is not used anywhere outside of the loop headed by bb1 except by the phi node in bb7, which I believe is permitted(going by this example in llvm-docs [Link](https://llvm.org/docs/LoopTerminology.html#loop-closed-ssa-lcssa)). Therefore in my opinion the code at the end of LoopPeel is already in LCSSA.
>
> If that is the case, I believe that this test case hit some corner condition which was not considered by `isRecursivelyInLCSSAForm` and thus the patch must modify that.
>
> @nikic @vedantparanjape-amd Please correct me if I am wrong, I am trying to refine my understanding of LCSSA
Yeah, this seems correct. The assumptions with which it has been implemented seem to be wrong in this case. Quoting the code in isBlockInLCSSAForm and LLVM documents.
```
// For practical purposes, we consider that the use in a PHI
// occurs in the respective predecessor block. For more info,
// see the `phi` doc in LangRef and the LCSSA doc.
if (const PHINode *P = dyn_cast<PHINode>(UI))
UserBB = P->getIncomingBlock(U);
Note that an exit block is outside of a loop, so how can such a phi "close"
the value inside the loop since it uses it outside of it ? First of all,
for phi nodes, as
`mentioned in the LangRef <https://llvm.org/docs/LangRef.html#id311>`_:
"the use of each incoming value is deemed to occur on the edge from the
corresponding predecessor block to the current block". Now, an
edge to an exit block is considered outside of the loop because
if we take that edge, it leads us clearly out of the loop.
However, an edge doesn't actually contain any IR, so in source code,
we have to choose a convention of whether the use happens in
the current block or in the respective predecessor. For LCSSA's purpose,
we consider the use happens in the latter (so as to consider the
use inside) [#point-of-use-phis]_.
```
So, the function starts with BB = bb1.peel.newph, UserBB = bb7 and UI = %phi8, now it checks if UI is a PhiNode, if it is, it assigns UserBB = IncomingBlock(UI) = bb7.loopexit, which is still fine. In the next if condition that returns false, it checks if BB != UserBB, which fails due to the wrong assumption that Phi occurs in the respective predecessor block only.
Actual call chain is `bb1.peel.newph -> bb4 -> bb7.loopexit -> bb7` or `bb1.peel.newph -> bb4 -> bb9-> bb7.loopexit -> bb7`
https://github.com/llvm/llvm-project/pull/78696
More information about the llvm-commits
mailing list