Opportunistically use the C++ personality function in ObjC++

translation units that don't catch ObjC types.  rdar://problem/8434851



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@114070 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2010-09-16 06:16:50 +00:00
Родитель f902153696
Коммит b25938303d
4 изменённых файлов: 105 добавлений и 19 удалений

Просмотреть файл

@ -14,6 +14,7 @@
#include "clang/AST/StmtCXX.h"
#include "llvm/Intrinsics.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/CallSite.h"
#include "CGObjCRuntime.h"
@ -287,7 +288,7 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
}
static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
const char *Name) {
llvm::StringRef Name) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@ -357,17 +358,95 @@ const EHPersonality &EHPersonality::get(const LangOptions &L) {
return getCPersonality(L);
}
static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF,
static llvm::Constant *getPersonalityFn(CodeGenModule &CGM,
const EHPersonality &Personality) {
const char *Name = Personality.getPersonalityFnName();
llvm::Constant *Fn =
CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getInt32Ty(
CGF.CGM.getLLVMContext()),
true),
Name);
return llvm::ConstantExpr::getBitCast(Fn, CGF.CGM.PtrToInt8Ty);
CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getInt32Ty(CGM.getLLVMContext()),
true),
Personality.getPersonalityFnName());
return Fn;
}
static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM,
const EHPersonality &Personality) {
llvm::Constant *Fn = getPersonalityFn(CGM, Personality);
return llvm::ConstantExpr::getBitCast(Fn, CGM.PtrToInt8Ty);
}
/// Check whether a personality function could reasonably be swapped
/// for a C++ personality function.
static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) {
for (llvm::Constant::use_iterator
I = Fn->use_begin(), E = Fn->use_end(); I != E; ++I) {
llvm::User *User = *I;
// Conditionally white-list bitcasts.
if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(User)) {
if (CE->getOpcode() != llvm::Instruction::BitCast) return false;
if (!PersonalityHasOnlyCXXUses(CE))
return false;
continue;
}
// Otherwise, it has to be a selector call.
if (!isa<llvm::EHSelectorInst>(User)) return false;
llvm::EHSelectorInst *Selector = cast<llvm::EHSelectorInst>(User);
for (unsigned I = 2, E = Selector->getNumArgOperands(); I != E; ++I) {
// Look for something that would've been returned by the ObjC
// runtime's GetEHType() method.
llvm::GlobalVariable *GV
= dyn_cast<llvm::GlobalVariable>(Selector->getArgOperand(I));
if (!GV) continue;
// ObjC EH selector entries are always global variables with
// names starting like this.
if (GV->getName().startswith("OBJC_EHTYPE"))
return false;
}
}
return true;
}
/// Try to use the C++ personality function in ObjC++. Not doing this
/// can cause some incompatibilities with gcc, which is more
/// aggressive about only using the ObjC++ personality in a function
/// when it really needs it.
void CodeGenModule::SimplifyPersonality() {
// For now, this is really a Darwin-specific operation.
if (Context.Target.getTriple().getOS() != llvm::Triple::Darwin)
return;
// If we're not in ObjC++ -fexceptions, there's nothing to do.
if (!Features.CPlusPlus || !Features.ObjC1 || !Features.Exceptions)
return;
const EHPersonality &ObjCXX = EHPersonality::get(Features);
const EHPersonality &CXX = getCXXPersonality(Features);
if (&ObjCXX == &CXX ||
ObjCXX.getPersonalityFnName() == CXX.getPersonalityFnName())
return;
llvm::Function *Fn =
getModule().getFunction(ObjCXX.getPersonalityFnName());
// Nothing to do if it's unused.
if (!Fn || Fn->use_empty()) return;
// Can't do the optimization if it has non-C++ uses.
if (!PersonalityHasOnlyCXXUses(Fn)) return;
// Create the C++ personality function and kill off the old
// function.
llvm::Constant *CXXFn = getPersonalityFn(*this, CXX);
// This can happen if the user is screwing with us.
if (Fn->getType() != CXXFn->getType()) return;
Fn->replaceAllUsesWith(CXXFn);
Fn->eraseFromParent();
}
/// Returns the value to inject into a selector to indicate the
@ -757,7 +836,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Build the selector arguments.
llvm::SmallVector<llvm::Value*, 8> EHSelector;
EHSelector.push_back(Exn);
EHSelector.push_back(getPersonalityFn(*this, Personality));
EHSelector.push_back(getOpaquePersonalityFn(CGM, Personality));
// Accumulate all the handlers in scope.
llvm::DenseMap<llvm::Value*, UnwindDest> EHHandlers;
@ -1502,7 +1581,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
// Tell the backend what the exception table should be:
// nothing but a catch-all.
llvm::Value *Args[3] = { Exn, getPersonalityFn(*this, Personality),
llvm::Value *Args[3] = { Exn, getOpaquePersonalityFn(CGM, Personality),
getCatchAllValue(*this) };
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
Args, Args+3, "eh.selector")
@ -1553,8 +1632,9 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName();
llvm::Constant *RethrowFn;
if (const char *RethrowName = Personality.getCatchallRethrowFnName())
if (!RethrowName.empty())
RethrowFn = getCatchallRethrowFn(*this, RethrowName);
else
RethrowFn = getUnwindResumeOrRethrowFn();

Просмотреть файл

@ -29,15 +29,15 @@ namespace CodeGen {
/// The exceptions personality for a function. When
class EHPersonality {
const char *PersonalityFn;
llvm::StringRef PersonalityFn;
// If this is non-null, this personality requires a non-standard
// function for rethrowing an exception after a catchall cleanup.
// This function must have prototype void(void*).
const char *CatchallRethrowFn;
llvm::StringRef CatchallRethrowFn;
EHPersonality(const char *PersonalityFn,
const char *CatchallRethrowFn = 0)
EHPersonality(llvm::StringRef PersonalityFn,
llvm::StringRef CatchallRethrowFn = llvm::StringRef())
: PersonalityFn(PersonalityFn),
CatchallRethrowFn(CatchallRethrowFn) {}
@ -49,8 +49,8 @@ public:
static const EHPersonality GNU_CPlusPlus;
static const EHPersonality GNU_CPlusPlus_SJLJ;
const char *getPersonalityFnName() const { return PersonalityFn; }
const char *getCatchallRethrowFnName() const { return CatchallRethrowFn; }
llvm::StringRef getPersonalityFnName() const { return PersonalityFn; }
llvm::StringRef getCatchallRethrowFnName() const { return CatchallRethrowFn; }
};
/// A protected scope for zero-cost EH handling.

Просмотреть файл

@ -110,6 +110,8 @@ void CodeGenModule::Release() {
EmitAnnotations();
EmitLLVMUsed();
SimplifyPersonality();
if (getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
}

Просмотреть файл

@ -613,6 +613,10 @@ private:
/// lazily; this is only relevant for definitions. The given decl
/// must be either a function or var decl.
bool MayDeferGeneration(const ValueDecl *D);
/// SimplifyPersonality - Check whether we can use a "simpler", more
/// core exceptions personality function.
void SimplifyPersonality();
};
} // end namespace CodeGen
} // end namespace clang