summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/IPO/Attributor.cpp40
1 files changed, 31 insertions, 9 deletions
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index cea8cffa5c6..1ae8ac77de0 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/CaptureTracking.h"
+#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -1563,6 +1564,12 @@ struct AAIsDeadFunction : AAIsDead, BooleanState {
"Attempted to manifest an invalid state!");
ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
+ const Function &F = getAnchorScope();
+
+ // Flag to determine if we can change an invoke to a call assuming the callee
+ // is nounwind. This is not possible if the personality of the function allows
+ // to catch asynchronous exceptions.
+ bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(F);
for (const Instruction *NRC : NoReturnCalls) {
Instruction *I = const_cast<Instruction *>(NRC);
@@ -1573,14 +1580,17 @@ struct AAIsDeadFunction : AAIsDead, BooleanState {
/// Invoke is replaced with a call and unreachable is placed after it if
/// the callee is nounwind and noreturn. Otherwise, we keep the invoke
/// and only place an unreachable in the normal successor.
- if (Function *Callee = II->getCalledFunction()) {
- auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Callee);
- if (Callee->hasFnAttribute(Attribute::NoUnwind) ||
- (AANoUnw && AANoUnw->isAssumedNoUnwind())) {
- LLVM_DEBUG(dbgs() << "[AAIsDead] Replace invoke with call inst\n");
- changeToCall(II);
- changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false);
- continue;
+ if (Invoke2CallAllowed) {
+ if (Function *Callee = II->getCalledFunction()) {
+ auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Callee);
+ if (Callee->hasFnAttribute(Attribute::NoUnwind) ||
+ (AANoUnw && AANoUnw->isAssumedNoUnwind())) {
+ LLVM_DEBUG(dbgs()
+ << "[AAIsDead] Replace invoke with call inst\n");
+ changeToCall(II);
+ changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false);
+ continue;
+ }
}
}
@@ -1639,6 +1649,11 @@ struct AAIsDeadFunction : AAIsDead, BooleanState {
/// Check if instruction is after noreturn call, in other words, assumed dead.
bool isAfterNoReturn(const Instruction *I) const;
+ /// Determine if \p F might catch asynchronous exceptions.
+ static bool mayCatchAsynchronousExceptions(const Function &F) {
+ return F.hasPersonalityFn() && !canSimplifyInvokeNoUnwind(&F);
+ }
+
/// Collection of to be explored paths.
SmallSetVector<const Instruction *, 8> ToBeExploredPaths;
@@ -1662,6 +1677,12 @@ bool AAIsDeadFunction::isAfterNoReturn(const Instruction *I) const {
const Instruction *AAIsDeadFunction::findNextNoReturn(Attributor &A,
const Instruction *I) {
const BasicBlock *BB = I->getParent();
+ const Function &F = *BB->getParent();
+
+ // Flag to determine if we can change an invoke to a call assuming the callee
+ // is nounwind. This is not possible if the personality of the function allows
+ // to catch asynchronous exceptions.
+ bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(F);
// TODO: We should have a function that determines if an "edge" is dead.
// Edges could be from an instruction to the next or from a terminator
@@ -1678,7 +1699,8 @@ const Instruction *AAIsDeadFunction::findNextNoReturn(Attributor &A,
if (auto *Invoke = dyn_cast<InvokeInst>(I)) {
// Use nounwind to justify the unwind block is dead as well.
auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Invoke);
- if (!AANoUnw || !AANoUnw->isAssumedNoUnwind()) {
+ if (!Invoke2CallAllowed ||
+ (!AANoUnw || !AANoUnw->isAssumedNoUnwind())) {
AssumedLiveBlocks.insert(Invoke->getUnwindDest());
ToBeExploredPaths.insert(&Invoke->getUnwindDest()->front());
}
OpenPOWER on IntegriCloud