[llvm] [IR] Don't skip `catchswitch` instructions when calling `getFirstNonPHIOrDbgOrAlloca()` (PR #136056)

Tyler Lanphear via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 16 16:44:09 PDT 2025


https://github.com/tylanphear created https://github.com/llvm/llvm-project/pull/136056

`BasicBlock::getFirstNonPHIOrDbgOrAlloca()` is supposed to yield the first instruction in the block which is not a PHI or dbg or alloca instruction. To that effect, it also skips an EHPad instruction which might be present after any PHIs. Normally, the latter is fine, but it has an unexpected interaction with `catchswitch` blocks:

```
bb:
    ; optional PHIs
    %0 = catchswitch within none [label %catch] unwind to caller
```

If we skip over the `catchswitch` instruction in the previous block, we'll return the end iterator, despite `catchswitch` not being a PHI or dbg or alloca instruction.

This patch amends the logic to not skip an EHPad instruction which is also a terminator. This means that calling
`getFirstNonPHIOrDbgOrAlloca()` on a non-empty block with a terminator (such as the above) will always yield a valid instruction iterator. This appears to be the expected behavior anyways, as most usages of this method do not check that the returned iterator is `end()`.

Closes #136048.

>From e13882623dbd647c20ad2361b295bcebef28211f Mon Sep 17 00:00:00 2001
From: Tyler Lanphear <tyler.lanphear at intel.com>
Date: Wed, 16 Apr 2025 16:30:55 -0700
Subject: [PATCH] [IR] Don't skip `catchswitch` instructions when calling
 `getFirstNonPHIOrDbgOrAlloca()`

`BasicBlock::getFirstNonPHIOrDbgOrAlloca()` is supposed to yield the
first instruction in the block which is not a PHI or dbg or alloca
instruction. To that effect, it also skips an EHPad instruction which
might be present after any PHIs. Normally, the latter is fine, but it
has an unexpected interaction with `catchswitch` blocks:

```
bb:
    ; optional PHIs
    %0 = catchswitch within none [label %catch] unwind to caller
```

If we skip over the `catchswitch` instruction in the previous block,
we'll return the end iterator, despite `catchswitch` not being a PHI or
dbg or alloca instruction.

This patch amends the logic to not skip an EHPad instruction which is
also a terminator. This means that calling
`getFirstNonPHIOrDbgOrAlloca()` on a non-empty block with a terminator
(such as the above) will always yield a valid instruction iterator. This
appears to be the expected behavior anyways, as most usages of this
method do not check that the returned iterator is `end()`.

Closes #136048.
---
 llvm/lib/IR/BasicBlock.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index c632b1b2dc2ab..f870fb53307ea 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -455,7 +455,7 @@ BasicBlock::const_iterator BasicBlock::getFirstNonPHIOrDbgOrAlloca() const {
   if (InsertPt == end())
     return end();
 
-  if (InsertPt->isEHPad())
+  if (InsertPt->isEHPad() && !InsertPt->isTerminator())
     ++InsertPt;
 
   if (isEntryBlock()) {



More information about the llvm-commits mailing list