[llvm] r228782 - Don't promote asynch EH invokes of nounwind functions to calls

Reid Kleckner reid at kleckner.net
Tue Feb 10 17:23:17 PST 2015


Author: rnk
Date: Tue Feb 10 19:23:16 2015
New Revision: 228782

URL: http://llvm.org/viewvc/llvm-project?rev=228782&view=rev
Log:
Don't promote asynch EH invokes of nounwind functions to calls

If the landingpad of the invoke is using a personality function that
catches asynch exceptions, then it can catch a trap.

Also add some landingpads to invalid LLVM IR test cases that lack them.

Over-the-shoulder reviewed by David Majnemer.

Added:
    llvm/trunk/test/Feature/seh-nounwind.ll
    llvm/trunk/test/Transforms/PruneEH/seh-nounwind.ll
    llvm/trunk/test/Transforms/SimplifyCFG/seh-nounwind.ll
Removed:
    llvm/trunk/test/Transforms/PruneEH/2003-11-21-PHIUpdate.ll
Modified:
    llvm/trunk/docs/LangRef.rst
    llvm/trunk/include/llvm/Analysis/LibCallSemantics.h
    llvm/trunk/lib/Analysis/LibCallSemantics.cpp
    llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
    llvm/trunk/lib/Transforms/IPO/PruneEH.cpp
    llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp
    llvm/trunk/lib/Transforms/Utils/Local.cpp
    llvm/trunk/test/Other/2009-03-31-CallGraph.ll
    llvm/trunk/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll

Modified: llvm/trunk/docs/LangRef.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/docs/LangRef.rst (original)
+++ llvm/trunk/docs/LangRef.rst Tue Feb 10 19:23:16 2015
@@ -1236,9 +1236,12 @@ example:
     normally. This produces undefined behavior at runtime if the
     function ever does dynamically return.
 ``nounwind``
-    This function attribute indicates that the function never returns
-    with an unwind or exceptional control flow. If the function does
-    unwind, its runtime behavior is undefined.
+    This function attribute indicates that the function never raises an
+    exception. If the function does raise an exception, its runtime
+    behavior is undefined. However, functions marked nounwind may still
+    trap or generate asynchronous exceptions. Exception handling schemes
+    that are recognized by LLVM to handle asynchronous exceptions, such
+    as SEH, will still provide their implementation defined semantics.
 ``optnone``
     This function attribute indicates that the function is not optimized
     by any optimization or code generator passes with the

Modified: llvm/trunk/include/llvm/Analysis/LibCallSemantics.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LibCallSemantics.h?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/LibCallSemantics.h (original)
+++ llvm/trunk/include/llvm/Analysis/LibCallSemantics.h Tue Feb 10 19:23:16 2015
@@ -18,6 +18,7 @@
 #include "llvm/Analysis/AliasAnalysis.h"
 
 namespace llvm {
+class InvokeInst;
 
   /// LibCallLocationInfo - This struct describes a set of memory locations that
   /// are accessed by libcalls.  Identification of a location is doing with a
@@ -168,14 +169,21 @@ namespace llvm {
     GNU_C,
     GNU_CXX,
     GNU_ObjC,
+    MSVC_X86SEH,
     MSVC_Win64SEH,
     MSVC_CXX,
   };
 
-  /// ClassifyEHPersonality - See if the given exception handling personality
-  /// function is one that we understand.  If so, return a description of it;
-  /// otherwise return Unknown_Personality.
-  EHPersonality ClassifyEHPersonality(Value *Pers);
+  /// \brief See if the given exception handling personality function is one
+  /// that we understand.  If so, return a description of it; otherwise return
+  /// Unknown.
+  EHPersonality classifyEHPersonality(Value *Pers);
+
+  /// \brief Returns true if this personality function catches asynchronous
+  /// exceptions.
+  bool isAsynchronousEHPersonality(EHPersonality Pers);
+
+  bool canSimplifyInvokeNoUnwind(const InvokeInst *II);
 
 } // end namespace llvm
 

Modified: llvm/trunk/lib/Analysis/LibCallSemantics.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LibCallSemantics.cpp?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LibCallSemantics.cpp (original)
+++ llvm/trunk/lib/Analysis/LibCallSemantics.cpp Tue Feb 10 19:23:16 2015
@@ -64,7 +64,7 @@ LibCallInfo::getFunctionInfo(const Funct
 
 /// See if the given exception handling personality function is one that we
 /// understand.  If so, return a description of it; otherwise return Unknown.
-EHPersonality llvm::ClassifyEHPersonality(Value *Pers) {
+EHPersonality llvm::classifyEHPersonality(Value *Pers) {
   Function *F = dyn_cast<Function>(Pers->stripPointerCasts());
   if (!F)
     return EHPersonality::Unknown;
@@ -73,7 +73,30 @@ EHPersonality llvm::ClassifyEHPersonalit
     .Case("__gxx_personality_v0",  EHPersonality::GNU_CXX)
     .Case("__gcc_personality_v0",  EHPersonality::GNU_C)
     .Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
+    .Case("__except_handler3",     EHPersonality::MSVC_X86SEH)
+    .Case("__except_handler4",     EHPersonality::MSVC_X86SEH)
     .Case("__C_specific_handler",  EHPersonality::MSVC_Win64SEH)
     .Case("__CxxFrameHandler3",    EHPersonality::MSVC_CXX)
     .Default(EHPersonality::Unknown);
 }
+
+bool llvm::isAsynchronousEHPersonality(EHPersonality Pers) {
+  // The two SEH personality functions can catch asynch exceptions. We assume
+  // unknown personalities don't catch asynch exceptions.
+  switch (Pers) {
+  case EHPersonality::MSVC_X86SEH:
+  case EHPersonality::MSVC_Win64SEH:
+    return true;
+  default: return false;
+  }
+  llvm_unreachable("invalid enum");
+}
+
+bool llvm::canSimplifyInvokeNoUnwind(const InvokeInst *II) {
+  const LandingPadInst *LP = II->getLandingPadInst();
+  EHPersonality Personality = classifyEHPersonality(LP->getPersonalityFn());
+  // We can't simplify any invokes to nounwind functions if the personality
+  // function wants to catch asynch exceptions.  The nounwind attribute only
+  // implies that the function does not throw synchronous exceptions.
+  return !isAsynchronousEHPersonality(Personality);
+}

Modified: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Tue Feb 10 19:23:16 2015
@@ -75,7 +75,7 @@ bool WinEHPrepare::runOnFunction(Functio
     return false;
 
   // Classify the personality to see what kind of preparation we need.
-  EHPersonality Pers = ClassifyEHPersonality(LPads.back()->getPersonalityFn());
+  EHPersonality Pers = classifyEHPersonality(LPads.back()->getPersonalityFn());
 
   // Delegate through to the DWARF pass if this is unrecognized.
   if (!isMSVCPersonality(Pers))

Modified: llvm/trunk/lib/Transforms/IPO/PruneEH.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PruneEH.cpp?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/PruneEH.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/PruneEH.cpp Tue Feb 10 19:23:16 2015
@@ -18,8 +18,10 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Analysis/CallGraph.h"
 #include "llvm/Analysis/CallGraphSCCPass.h"
+#include "llvm/Analysis/LibCallSemantics.h"
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
@@ -175,7 +177,7 @@ bool PruneEH::SimplifyFunction(Function
   bool MadeChange = false;
   for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
     if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
-      if (II->doesNotThrow()) {
+      if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(II)) {
         SmallVector<Value*, 8> Args(II->op_begin(), II->op_end() - 3);
         // Insert a call instruction before the invoke.
         CallInst *Call = CallInst::Create(II->getCalledValue(), Args, "", II);

Modified: llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstructionCombining.cpp Tue Feb 10 19:23:16 2015
@@ -2275,6 +2275,7 @@ static bool isCatchAll(EHPersonality Per
     return false;
   case EHPersonality::GNU_CXX:
   case EHPersonality::GNU_ObjC:
+  case EHPersonality::MSVC_X86SEH:
   case EHPersonality::MSVC_Win64SEH:
   case EHPersonality::MSVC_CXX:
     return TypeInfo->isNullValue();
@@ -2293,7 +2294,7 @@ Instruction *InstCombiner::visitLandingP
   // The logic here should be correct for any real-world personality function.
   // However if that turns out not to be true, the offending logic can always
   // be conditioned on the personality function, like the catch-all logic is.
-  EHPersonality Personality = ClassifyEHPersonality(LI.getPersonalityFn());
+  EHPersonality Personality = classifyEHPersonality(LI.getPersonalityFn());
 
   // Simplify the list of clauses, eg by removing repeated catch clauses
   // (these are often created by inlining).

Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/Local.cpp Tue Feb 10 19:23:16 2015
@@ -17,6 +17,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/LibCallSemantics.h"
 #include "llvm/Analysis/InstructionSimplify.h"
 #include "llvm/Analysis/MemoryBuiltins.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -1260,7 +1261,7 @@ static bool markAliveBlocks(BasicBlock *
       if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) {
         changeToUnreachable(II, true);
         Changed = true;
-      } else if (II->doesNotThrow()) {
+      } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(II)) {
         if (II->use_empty() && II->onlyReadsMemory()) {
           // jump to the normal destination branch.
           BranchInst::Create(II->getNormalDest(), II);

Added: llvm/trunk/test/Feature/seh-nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Feature/seh-nounwind.ll?rev=228782&view=auto
==============================================================================
--- llvm/trunk/test/Feature/seh-nounwind.ll (added)
+++ llvm/trunk/test/Feature/seh-nounwind.ll Tue Feb 10 19:23:16 2015
@@ -0,0 +1,32 @@
+; RUN: opt -S -O2 < %s | FileCheck %s
+
+; Feature test that verifies that all optimizations leave asynch personality
+; invokes of nounwind functions alone.
+; The @div function in this test can fault, even though it can't
+; throw a synchronous exception.
+
+define i32 @div(i32 %n, i32 %d) nounwind noinline {
+entry:
+  %div = sdiv i32 %n, %d
+  ret i32 %div
+}
+
+define i32 @main() nounwind {
+entry:
+  %call = invoke i32 @div(i32 10, i32 0)
+          to label %__try.cont unwind label %lpad
+
+lpad:
+  %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+          catch i8* null
+  br label %__try.cont
+
+__try.cont:
+  %retval.0 = phi i32 [ %call, %entry ], [ 0, %lpad ]
+  ret i32 %retval.0
+}
+
+; CHECK-LABEL: define i32 @main()
+; CHECK: invoke i32 @div(i32 10, i32 0)
+
+declare i32 @__C_specific_handler(...)

Modified: llvm/trunk/test/Other/2009-03-31-CallGraph.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/2009-03-31-CallGraph.ll?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/test/Other/2009-03-31-CallGraph.ll (original)
+++ llvm/trunk/test/Other/2009-03-31-CallGraph.ll Tue Feb 10 19:23:16 2015
@@ -7,6 +7,8 @@ ok1:
     ret void
 
 lpad1:
+    landingpad {i8*, i32} personality i32 (...)* @__gxx_personality_v0
+            cleanup
     invoke void @f4()
         to label %ok2 unwind label %lpad2
 

Removed: llvm/trunk/test/Transforms/PruneEH/2003-11-21-PHIUpdate.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/PruneEH/2003-11-21-PHIUpdate.ll?rev=228781&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/PruneEH/2003-11-21-PHIUpdate.ll (original)
+++ llvm/trunk/test/Transforms/PruneEH/2003-11-21-PHIUpdate.ll (removed)
@@ -1,15 +0,0 @@
-; RUN: opt < %s -prune-eh -disable-output
-
-define internal void @callee() {
-	ret void
-}
-
-define i32 @caller() {
-; <label>:0
-	invoke void @callee( )
-			to label %E unwind label %E
-E:		; preds = %0, %0
-	%X = phi i32 [ 0, %0 ], [ 0, %0 ]		; <i32> [#uses=1]
-	ret i32 %X
-}
-

Added: llvm/trunk/test/Transforms/PruneEH/seh-nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/PruneEH/seh-nounwind.ll?rev=228782&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/PruneEH/seh-nounwind.ll (added)
+++ llvm/trunk/test/Transforms/PruneEH/seh-nounwind.ll Tue Feb 10 19:23:16 2015
@@ -0,0 +1,31 @@
+; RUN: opt -S -prune-eh < %s | FileCheck %s
+
+; Don't remove invokes of nounwind functions if the personality handles async
+; exceptions. The @div function in this test can fault, even though it can't
+; throw a synchronous exception.
+
+define i32 @div(i32 %n, i32 %d) nounwind {
+entry:
+  %div = sdiv i32 %n, %d
+  ret i32 %div
+}
+
+define i32 @main() nounwind {
+entry:
+  %call = invoke i32 @div(i32 10, i32 0)
+          to label %__try.cont unwind label %lpad
+
+lpad:
+  %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+          catch i8* null
+  br label %__try.cont
+
+__try.cont:
+  %retval.0 = phi i32 [ %call, %entry ], [ 0, %lpad ]
+  ret i32 %retval.0
+}
+
+; CHECK-LABEL: define i32 @main()
+; CHECK: invoke i32 @div(i32 10, i32 0)
+
+declare i32 @__C_specific_handler(...)

Modified: llvm/trunk/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll?rev=228782&r1=228781&r2=228782&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll (original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/2007-11-22-InvokeNoUnwind.ll Tue Feb 10 19:23:16 2015
@@ -12,5 +12,9 @@ Cont:		; preds = %0
 	ret i32 0
 
 Other:		; preds = %0
+	landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_v0
+		catch i8* null
 	ret i32 1
 }
+
+declare i32 @__gxx_personality_v0(...)

Added: llvm/trunk/test/Transforms/SimplifyCFG/seh-nounwind.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/seh-nounwind.ll?rev=228782&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/seh-nounwind.ll (added)
+++ llvm/trunk/test/Transforms/SimplifyCFG/seh-nounwind.ll Tue Feb 10 19:23:16 2015
@@ -0,0 +1,31 @@
+; RUN: opt -S -simplifycfg < %s | FileCheck %s
+
+; Don't remove invokes of nounwind functions if the personality handles async
+; exceptions. The @div function in this test can fault, even though it can't
+; throw a synchronous exception.
+
+define i32 @div(i32 %n, i32 %d) nounwind {
+entry:
+  %div = sdiv i32 %n, %d
+  ret i32 %div
+}
+
+define i32 @main() nounwind {
+entry:
+  %call = invoke i32 @div(i32 10, i32 0)
+          to label %__try.cont unwind label %lpad
+
+lpad:
+  %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
+          catch i8* null
+  br label %__try.cont
+
+__try.cont:
+  %retval.0 = phi i32 [ %call, %entry ], [ 0, %lpad ]
+  ret i32 %retval.0
+}
+
+; CHECK-LABEL: define i32 @main()
+; CHECK: invoke i32 @div(i32 10, i32 0)
+
+declare i32 @__C_specific_handler(...)





More information about the llvm-commits mailing list