diff options
author | Roman Lebedev <lebedev.ri@gmail.com> | 2022-02-05 01:28:24 +0300 |
---|---|---|
committer | Roman Lebedev <lebedev.ri@gmail.com> | 2022-02-05 02:15:07 +0300 |
commit | 598833c987593ce192fa827f162cae8c867c9d43 (patch) | |
tree | 26c07f684542d733551053df615e650be8ab39a7 /llvm/lib/Transforms/Utils/Local.cpp | |
parent | 75c1d1dab41709a9e0780ad2fbad23e46bfba4dd (diff) | |
download | llvm-598833c987593ce192fa827f162cae8c867c9d43.zip llvm-598833c987593ce192fa827f162cae8c867c9d43.tar.gz llvm-598833c987593ce192fa827f162cae8c867c9d43.tar.bz2 |
[SimplifyCFG] `markAliveBlocks()`: recognize that normal dest of `invoke`d `noreturn` function is `unreachable`
As per LangRef's definition of `noreturn` attribute:
```
noreturn
This function attribute indicates that the function never returns
normally, hence through a return instruction.
This produces undefined behavior at runtime if the function
ever does dynamically return. nnotated functions may still
raise an exception, i.a., nounwind is not implied.
```
Diffstat (limited to 'llvm/lib/Transforms/Utils/Local.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/Local.cpp | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 9a10535..58eb7d4 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -2349,19 +2349,32 @@ static bool markAliveBlocks(Function &F, isa<UndefValue>(Callee)) { changeToUnreachable(II, false, DTU); Changed = true; - } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) { - if (II->use_empty() && II->onlyReadsMemory()) { - // jump to the normal destination branch. - BasicBlock *NormalDestBB = II->getNormalDest(); - BasicBlock *UnwindDestBB = II->getUnwindDest(); - BranchInst::Create(NormalDestBB, II); - UnwindDestBB->removePredecessor(II->getParent()); - II->eraseFromParent(); - if (DTU) - DTU->applyUpdates({{DominatorTree::Delete, BB, UnwindDestBB}}); - } else - changeToCall(II, DTU); - Changed = true; + } else { + if (II->doesNotReturn()) { + // If we found an invoke of a no-return function, + // insert an unreachable instruction after it (on the normal dest). + // Make sure there isn't *already* one there though. + Instruction *FirstNormalInst = &II->getNormalDest()->front(); + if (!isa<UnreachableInst>(FirstNormalInst)) { + // Don't insert a call to llvm.trap right before the unreachable. + changeToUnreachable(FirstNormalInst, false, DTU); + Changed = true; + } + } + if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) { + if (II->use_empty() && II->onlyReadsMemory()) { + // jump to the normal destination branch. + BasicBlock *NormalDestBB = II->getNormalDest(); + BasicBlock *UnwindDestBB = II->getUnwindDest(); + BranchInst::Create(NormalDestBB, II); + UnwindDestBB->removePredecessor(II->getParent()); + II->eraseFromParent(); + if (DTU) + DTU->applyUpdates({{DominatorTree::Delete, BB, UnwindDestBB}}); + } else + changeToCall(II, DTU); + Changed = true; + } } } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Terminator)) { // Remove catchpads which cannot be reached. |