[llvm] Branch folding: Avoid infinite loop with indirect target blocks (PR #96956)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 16 08:35:44 PDT 2024
v01dXYZ wrote:
I would like to replace the `PrevBB->isSuccessor(&*FallThrough)` with `(PrevTBB == &*FallThrough) || (PrevFBB == &*FallThrough)`. I think it's the cause of the infinite loop.
It seems to be related to the fact that `analyzeBranch(PrevBB, ...)` ignore the instructions for `INVOKE`/`INLINEASM_BR` while those constructs still affect the successors/predecessors of the blocks. That's because those instructions are not terminators.
Using `isSuccessor` to check if a Block is a target of the terminating branch is faulty.
If the return value is as if the branch is analyzable, given a successor of `PrevBB`, it does not mean the branch refers to this specific successor. BTW if the branch is analyzable, the branch exists (`PrevBB` could not be branchless because of previous checks ensuring `PrevBB` does not fallthough).
For example, in the case of `PrevBB` having a JMP to `MBB` at the end (EBB0, EBB1 are blocks only used by an `INLINEASM_BR`). When using `PrevBB->isSuccessor(&*FallThrough)`, the transform is applied and `MBB` is moved at the end. The next two iterations will do the same for EBB0, EBB1. After the third iteration, we are back at the initial placement. Thus, the infinite loop.
```
+----------+ +----------+
| PrevBB |--+ | PrevBB |--+
| JMP MBB | | | JMP MBB | |
+----------+ | +----------+ |
| | _______/ |
v | / |
+----------+ | | +----------+ |
| MBB | | | | EBB0 |<-+
+----------+ | ==> | +----------+ |
| | |
+----------+ | | +----------+ |
| EBB0 |<-+ | | EBB0 |<-+
+----------+ | | +----------+
| |
+----------+ | | +----------+
| EBB1 |<-+ +->| MBB |
+----------+ +----------+
```
`analyzeBranch` returns `false` and set only `PrevTBB` pointing to `MBB` while not setting `PrevFBB`. Since `PrevTBB != FallThrough`, the transform is not applied when using `PrevTBB`/`PrevFBB` instead of `PrevBB->isSuccessor(...)`.
Keeping the check about `FallThrough` not being a EHPad block is not absolutely necessary, but it prevents uselessly calling the expensive `analyzeBranch` since a catchpad could only be reached from an `INVOKE`.
As Indirect Targets could be reached from a branch, the check about not being an Indirect Target is conservative to prevent the infinite loop from reappearing.
https://github.com/llvm/llvm-project/pull/96956
More information about the llvm-commits
mailing list