[llvm] r367931 - [Attributor][Fix] Keep invokes if handlers catch asynchronous exceptions

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 5 14:34:45 PDT 2019


Author: jdoerfert
Date: Mon Aug  5 14:34:45 2019
New Revision: 367931

URL: http://llvm.org/viewvc/llvm-project?rev=367931&view=rev
Log:
[Attributor][Fix] Keep invokes if handlers catch asynchronous exceptions

Similar to other places where we transform invokes to calls we need to
be careful if the handler (=personality) can catch asynchronous
exceptions as they are not modeled as part of nounwind.

This is tested with D59978.

Modified:
    llvm/trunk/lib/Transforms/IPO/Attributor.cpp

Modified: llvm/trunk/lib/Transforms/IPO/Attributor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Attributor.cpp?rev=367931&r1=367930&r2=367931&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/Attributor.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/Attributor.cpp Mon Aug  5 14:34:45 2019
@@ -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, Bool
            "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, Bool
         /// 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, Bool
   /// 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(c
 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::fin
       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());
         }




More information about the llvm-commits mailing list