Move EH personality type classification to Analysis/LibCallSemantics.h

Summary:
Also add enum types for __C_specific_handler and _CxxFrameHandler3 for
which we know a few things.

Reviewers: majnemer

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D7214

llvm-svn: 227284
This commit is contained in:
Reid Kleckner 2015-01-28 01:17:38 +00:00
parent d1f2536829
commit 4af6415237
4 changed files with 97 additions and 28 deletions

View File

@ -162,6 +162,21 @@ namespace llvm {
virtual const LibCallFunctionInfo *getFunctionInfoArray() const = 0; virtual const LibCallFunctionInfo *getFunctionInfoArray() const = 0;
}; };
enum class EHPersonality {
Unknown,
GNU_Ada,
GNU_C,
GNU_CXX,
GNU_ObjC,
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);
} // end namespace llvm } // end namespace llvm
#endif #endif

View File

@ -15,6 +15,7 @@
#include "llvm/Analysis/LibCallSemantics.h" #include "llvm/Analysis/LibCallSemantics.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
using namespace llvm; using namespace llvm;
@ -61,3 +62,18 @@ LibCallInfo::getFunctionInfo(const Function *F) const {
return Map->lookup(F->getName()); return Map->lookup(F->getName());
} }
/// 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) {
Function *F = dyn_cast<Function>(Pers->stripPointerCasts());
if (!F)
return EHPersonality::Unknown;
return StringSwitch<EHPersonality>(F->getName())
.Case("__gnat_eh_personality", EHPersonality::GNU_Ada)
.Case("__gxx_personality_v0", EHPersonality::GNU_CXX)
.Case("__gcc_personality_v0", EHPersonality::GNU_C)
.Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
.Case("__C_specific_handler", EHPersonality::MSVC_Win64SEH)
.Case("__CxxFrameHandler3", EHPersonality::MSVC_CXX)
.Default(EHPersonality::Unknown);
}

View File

@ -43,6 +43,7 @@
#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LibCallSemantics.h"
#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h"
@ -2259,41 +2260,26 @@ Instruction *InstCombiner::visitExtractValueInst(ExtractValueInst &EV) {
return nullptr; return nullptr;
} }
enum Personality_Type {
Unknown_Personality,
GNU_Ada_Personality,
GNU_CXX_Personality,
GNU_ObjC_Personality
};
/// RecognizePersonality - See if the given exception handling personality
/// function is one that we understand. If so, return a description of it;
/// otherwise return Unknown_Personality.
static Personality_Type RecognizePersonality(Value *Pers) {
Function *F = dyn_cast<Function>(Pers->stripPointerCasts());
if (!F)
return Unknown_Personality;
return StringSwitch<Personality_Type>(F->getName())
.Case("__gnat_eh_personality", GNU_Ada_Personality)
.Case("__gxx_personality_v0", GNU_CXX_Personality)
.Case("__objc_personality_v0", GNU_ObjC_Personality)
.Default(Unknown_Personality);
}
/// isCatchAll - Return 'true' if the given typeinfo will match anything. /// isCatchAll - Return 'true' if the given typeinfo will match anything.
static bool isCatchAll(Personality_Type Personality, Constant *TypeInfo) { static bool isCatchAll(EHPersonality Personality, Constant *TypeInfo) {
switch (Personality) { switch (Personality) {
case Unknown_Personality: case EHPersonality::GNU_C:
// The GCC C EH personality only exists to support cleanups, so it's not
// clear what the semantics of catch clauses are.
return false; return false;
case GNU_Ada_Personality: case EHPersonality::Unknown:
return false;
case EHPersonality::GNU_Ada:
// While __gnat_all_others_value will match any Ada exception, it doesn't // While __gnat_all_others_value will match any Ada exception, it doesn't
// match foreign exceptions (or didn't, before gcc-4.7). // match foreign exceptions (or didn't, before gcc-4.7).
return false; return false;
case GNU_CXX_Personality: case EHPersonality::GNU_CXX:
case GNU_ObjC_Personality: case EHPersonality::GNU_ObjC:
case EHPersonality::MSVC_Win64SEH:
case EHPersonality::MSVC_CXX:
return TypeInfo->isNullValue(); return TypeInfo->isNullValue();
} }
llvm_unreachable("Unknown personality!"); llvm_unreachable("invalid enum");
} }
static bool shorter_filter(const Value *LHS, const Value *RHS) { static bool shorter_filter(const Value *LHS, const Value *RHS) {
@ -2307,7 +2293,7 @@ Instruction *InstCombiner::visitLandingPadInst(LandingPadInst &LI) {
// The logic here should be correct for any real-world personality function. // 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 // 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. // be conditioned on the personality function, like the catch-all logic is.
Personality_Type Personality = RecognizePersonality(LI.getPersonalityFn()); EHPersonality Personality = ClassifyEHPersonality(LI.getPersonalityFn());
// Simplify the list of clauses, eg by removing repeated catch clauses // Simplify the list of clauses, eg by removing repeated catch clauses
// (these are often created by inlining). // (these are often created by inlining).

View File

@ -7,6 +7,7 @@
declare i32 @generic_personality(i32, i64, i8*, i8*) declare i32 @generic_personality(i32, i64, i8*, i8*)
declare i32 @__gxx_personality_v0(i32, i64, i8*, i8*) declare i32 @__gxx_personality_v0(i32, i64, i8*, i8*)
declare i32 @__objc_personality_v0(i32, i64, i8*, i8*) declare i32 @__objc_personality_v0(i32, i64, i8*, i8*)
declare i32 @__C_specific_handler(...)
declare void @bar() declare void @bar()
@ -231,3 +232,54 @@ lpad.d:
; CHECK-NEXT: null ; CHECK-NEXT: null
; CHECK-NEXT: unreachable ; CHECK-NEXT: unreachable
} }
define void @foo_seh() {
; CHECK-LABEL: @foo_seh(
invoke void @bar()
to label %cont.a unwind label %lpad.a
cont.a:
invoke void @bar()
to label %cont.b unwind label %lpad.b
cont.b:
invoke void @bar()
to label %cont.c unwind label %lpad.c
cont.c:
invoke void @bar()
to label %cont.d unwind label %lpad.d
cont.d:
ret void
lpad.a:
%a = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler
catch i32* null
catch i32* @T1
unreachable
; CHECK: %a = landingpad
; CHECK-NEXT: null
; CHECK-NEXT: unreachable
lpad.b:
%b = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler
filter [1 x i32*] zeroinitializer
unreachable
; CHECK: %b = landingpad
; CHECK-NEXT: cleanup
; CHECK-NEXT: unreachable
lpad.c:
%c = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler
filter [2 x i32*] [i32* @T1, i32* null]
unreachable
; CHECK: %c = landingpad
; CHECK-NEXT: cleanup
; CHECK-NEXT: unreachable
lpad.d:
%d = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler
cleanup
catch i32* null
unreachable
; CHECK: %d = landingpad
; CHECK-NEXT: null
; CHECK-NEXT: unreachable
}