[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