[SEH] Re-land r234532, but use internal linkage for all SEH helpers
Even though these symbols are in a comdat group, the Microsoft linker really wants them to have internal linkage. I'm planning to tweak the mangling in a follow-up change. This is a straight revert with a 1-line fix. llvm-svn: 234613
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
@@ -408,13 +409,6 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
|
||||
return Builder.CreateLoad(getEHSelectorSlot(), "sel");
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {
|
||||
if (!AbnormalTerminationSlot)
|
||||
AbnormalTerminationSlot =
|
||||
CreateTempAlloca(Int8Ty, "abnormal.termination.slot");
|
||||
return AbnormalTerminationSlot;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
|
||||
bool KeepInsertionPoint) {
|
||||
if (const Expr *SubExpr = E->getSubExpr()) {
|
||||
@@ -1287,8 +1281,7 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
|
||||
return;
|
||||
}
|
||||
|
||||
SEHFinallyInfo FI;
|
||||
EnterSEHTryStmt(S, FI);
|
||||
EnterSEHTryStmt(S);
|
||||
{
|
||||
JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
|
||||
|
||||
@@ -1301,42 +1294,36 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
|
||||
else
|
||||
delete TryExit.getBlock();
|
||||
}
|
||||
ExitSEHTryStmt(S, FI);
|
||||
ExitSEHTryStmt(S);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct PerformSEHFinally : EHScopeStack::Cleanup {
|
||||
CodeGenFunction::SEHFinallyInfo *FI;
|
||||
PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}
|
||||
struct PerformSEHFinally : EHScopeStack::Cleanup {
|
||||
llvm::Function *OutlinedFinally;
|
||||
PerformSEHFinally(llvm::Function *OutlinedFinally)
|
||||
: OutlinedFinally(OutlinedFinally) {}
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags F) override {
|
||||
// Cleanups are emitted at most twice: once for normal control flow and once
|
||||
// for exception control flow. Branch into the finally block, and remember
|
||||
// the continuation block so we can branch out later.
|
||||
if (!FI->FinallyBB) {
|
||||
FI->FinallyBB = CGF.createBasicBlock("__finally");
|
||||
FI->FinallyBB->insertInto(CGF.CurFn);
|
||||
FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());
|
||||
}
|
||||
ASTContext &Context = CGF.getContext();
|
||||
QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy};
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
const auto *FTP = cast<FunctionType>(
|
||||
Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
|
||||
|
||||
// Set the termination status and branch in.
|
||||
CGF.Builder.CreateStore(
|
||||
llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),
|
||||
CGF.getAbnormalTerminationSlot());
|
||||
CGF.Builder.CreateBr(FI->FinallyBB);
|
||||
CallArgList Args;
|
||||
llvm::Value *IsForEH =
|
||||
llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
|
||||
Args.add(RValue::get(IsForEH), ArgTys[0]);
|
||||
|
||||
// Create a continuation block for normal or exceptional control.
|
||||
if (F.isForEHCleanup()) {
|
||||
assert(!FI->ResumeBB && "double emission for EH");
|
||||
FI->ResumeBB = CGF.createBasicBlock("__finally.resume");
|
||||
CGF.EmitBlock(FI->ResumeBB);
|
||||
} else {
|
||||
assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");
|
||||
FI->ContBB = CGF.createBasicBlock("__finally.cont");
|
||||
CGF.EmitBlock(FI->ContBB);
|
||||
// Try to keep source order.
|
||||
FI->ContBB->moveAfter(FI->FinallyBB);
|
||||
}
|
||||
CodeGenModule &CGM = CGF.CGM;
|
||||
llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);
|
||||
llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
|
||||
llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);
|
||||
Args.add(RValue::get(FP), ArgTys[1]);
|
||||
|
||||
const CGFunctionInfo &FnInfo =
|
||||
CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
|
||||
CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1354,7 +1341,8 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
|
||||
// See if this is a capture, then recurse.
|
||||
ConstStmtVisitor<CaptureFinder>::Visit(S);
|
||||
for (const Stmt *Child : S->children())
|
||||
Visit(Child);
|
||||
if (Child)
|
||||
Visit(Child);
|
||||
}
|
||||
|
||||
void VisitDeclRefExpr(const DeclRefExpr *E) {
|
||||
@@ -1403,12 +1391,16 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
|
||||
CGM.ErrorUnsupported(VD, "VLA captured by SEH");
|
||||
continue;
|
||||
}
|
||||
|
||||
assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
|
||||
"captured non-local variable");
|
||||
|
||||
llvm::Value *ParentVar = ParentCGF.LocalDeclMap[VD];
|
||||
assert(ParentVar && "capture was not a local decl");
|
||||
// If this decl hasn't been declared yet, it will be declared in the
|
||||
// OutlinedStmt.
|
||||
auto I = ParentCGF.LocalDeclMap.find(VD);
|
||||
if (I == ParentCGF.LocalDeclMap.end())
|
||||
continue;
|
||||
llvm::Value *ParentVar = I->second;
|
||||
|
||||
llvm::CallInst *RecoverCall = nullptr;
|
||||
CGBuilderTy Builder(AllocaInsertPt);
|
||||
if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
|
||||
@@ -1445,47 +1437,24 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a stub filter function that will ultimately hold the code of the
|
||||
/// filter expression. The EH preparation passes in LLVM will outline the code
|
||||
/// from the main function body into this stub.
|
||||
llvm::Function *
|
||||
CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
|
||||
const SEHExceptStmt &Except) {
|
||||
const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
|
||||
/// Arrange a function prototype that can be called by Windows exception
|
||||
/// handling personalities. On Win64, the prototype looks like:
|
||||
/// RetTy func(void *EHPtrs, void *ParentFP);
|
||||
void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
|
||||
StringRef Name, QualType RetTy,
|
||||
FunctionArgList &Args,
|
||||
const Stmt *OutlinedStmt) {
|
||||
llvm::Function *ParentFn = ParentCGF.CurFn;
|
||||
|
||||
Expr *FilterExpr = Except.getFilterExpr();
|
||||
|
||||
// Get the mangled function name.
|
||||
SmallString<128> Name;
|
||||
{
|
||||
llvm::raw_svector_ostream OS(Name);
|
||||
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
|
||||
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
|
||||
CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
|
||||
}
|
||||
|
||||
// Arrange a function with the declaration:
|
||||
// int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)
|
||||
QualType RetTy = getContext().IntTy;
|
||||
FunctionArgList Args;
|
||||
SEHPointersDecl = ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, FilterExpr->getLocStart(),
|
||||
&getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
|
||||
Args.push_back(SEHPointersDecl);
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, FilterExpr->getLocStart(),
|
||||
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
|
||||
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
|
||||
RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
|
||||
|
||||
llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
|
||||
llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),
|
||||
Name.str(), &CGM.getModule());
|
||||
llvm::Function *Fn = llvm::Function::Create(
|
||||
FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());
|
||||
// The filter is either in the same comdat as the function, or it's internal.
|
||||
if (llvm::Comdat *C = ParentFn->getComdat()) {
|
||||
Fn->setComdat(C);
|
||||
} else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
|
||||
// FIXME: Unreachable with Rafael's changes?
|
||||
llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
|
||||
ParentFn->setComdat(C);
|
||||
Fn->setComdat(C);
|
||||
@@ -1493,14 +1462,55 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
|
||||
Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
|
||||
}
|
||||
|
||||
StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
|
||||
FilterExpr->getLocStart(), FilterExpr->getLocStart());
|
||||
IsOutlinedSEHHelper = true;
|
||||
|
||||
EmitSEHExceptionCodeSave();
|
||||
StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
|
||||
OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
|
||||
|
||||
CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
|
||||
|
||||
auto AI = Fn->arg_begin();
|
||||
++AI;
|
||||
EmitCapturedLocals(ParentCGF, FilterExpr, &*AI);
|
||||
EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
|
||||
}
|
||||
|
||||
/// Create a stub filter function that will ultimately hold the code of the
|
||||
/// filter expression. The EH preparation passes in LLVM will outline the code
|
||||
/// from the main function body into this stub.
|
||||
llvm::Function *
|
||||
CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
|
||||
const SEHExceptStmt &Except) {
|
||||
const Expr *FilterExpr = Except.getFilterExpr();
|
||||
SourceLocation StartLoc = FilterExpr->getLocStart();
|
||||
|
||||
SEHPointersDecl = ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
|
||||
FunctionArgList Args;
|
||||
Args.push_back(SEHPointersDecl);
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
|
||||
|
||||
// Get the mangled function name.
|
||||
SmallString<128> Name;
|
||||
{
|
||||
llvm::raw_svector_ostream OS(Name);
|
||||
const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
|
||||
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
|
||||
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
|
||||
CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
|
||||
}
|
||||
|
||||
startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr);
|
||||
|
||||
// Mark finally block calls as nounwind and noinline to make LLVM's job a
|
||||
// little easier.
|
||||
// FIXME: Remove these restrictions in the future.
|
||||
CurFn->addFnAttr(llvm::Attribute::NoUnwind);
|
||||
CurFn->addFnAttr(llvm::Attribute::NoInline);
|
||||
|
||||
EmitSEHExceptionCodeSave();
|
||||
|
||||
// Emit the original filter expression, convert to i32, and return.
|
||||
llvm::Value *R = EmitScalarExpr(FilterExpr);
|
||||
@@ -1510,7 +1520,42 @@ CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
|
||||
|
||||
FinishFunction(FilterExpr->getLocEnd());
|
||||
|
||||
return Fn;
|
||||
return CurFn;
|
||||
}
|
||||
|
||||
llvm::Function *
|
||||
CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
|
||||
const SEHFinallyStmt &Finally) {
|
||||
const Stmt *FinallyBlock = Finally.getBlock();
|
||||
SourceLocation StartLoc = FinallyBlock->getLocStart();
|
||||
|
||||
FunctionArgList Args;
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("abnormal_termination"), getContext().BoolTy));
|
||||
Args.push_back(ImplicitParamDecl::Create(
|
||||
getContext(), nullptr, StartLoc,
|
||||
&getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
|
||||
|
||||
// Get the mangled function name.
|
||||
SmallString<128> Name;
|
||||
{
|
||||
llvm::raw_svector_ostream OS(Name);
|
||||
const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
|
||||
const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
|
||||
assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
|
||||
CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS);
|
||||
}
|
||||
|
||||
startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,
|
||||
FinallyBlock);
|
||||
|
||||
// Emit the original filter expression, convert to i32, and return.
|
||||
EmitStmt(FinallyBlock);
|
||||
|
||||
FinishFunction(FinallyBlock->getLocEnd());
|
||||
|
||||
return CurFn;
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitSEHExceptionCodeSave() {
|
||||
@@ -1554,21 +1599,24 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
|
||||
// Load from the abnormal termination slot. It will be uninitialized outside
|
||||
// of __finally blocks, which we should warn or error on.
|
||||
llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());
|
||||
return Builder.CreateZExt(IsEH, Int32Ty);
|
||||
// Abnormal termination is just the first parameter to the outlined finally
|
||||
// helper.
|
||||
auto AI = CurFn->arg_begin();
|
||||
return Builder.CreateZExt(&*AI, Int32Ty);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
|
||||
if (S.getFinallyHandler()) {
|
||||
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
|
||||
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
|
||||
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
|
||||
// Push a cleanup for __finally blocks.
|
||||
EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);
|
||||
llvm::Function *FinallyFunc =
|
||||
HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
|
||||
EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we must have an __except block.
|
||||
SEHExceptStmt *Except = S.getExceptHandler();
|
||||
const SEHExceptStmt *Except = S.getExceptHandler();
|
||||
assert(Except);
|
||||
EHCatchScope *CatchScope = EHStack.pushCatch(1);
|
||||
|
||||
@@ -1583,40 +1631,17 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
|
||||
|
||||
// In general, we have to emit an outlined filter function. Use the function
|
||||
// in place of the RTTI typeinfo global that C++ EH uses.
|
||||
CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
|
||||
llvm::Function *FilterFunc =
|
||||
FilterCGF.GenerateSEHFilterFunction(*this, *Except);
|
||||
HelperCGF.GenerateSEHFilterFunction(*this, *Except);
|
||||
llvm::Constant *OpaqueFunc =
|
||||
llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
|
||||
CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
|
||||
}
|
||||
|
||||
void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
|
||||
void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
|
||||
// Just pop the cleanup if it's a __finally block.
|
||||
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
|
||||
if (S.getFinallyHandler()) {
|
||||
PopCleanupBlock();
|
||||
assert(FI.ContBB && "did not emit normal cleanup");
|
||||
|
||||
// Emit the code into FinallyBB.
|
||||
CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
|
||||
Builder.SetInsertPoint(FI.FinallyBB);
|
||||
EmitStmt(Finally->getBlock());
|
||||
|
||||
if (HaveInsertPoint()) {
|
||||
if (FI.ResumeBB) {
|
||||
llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
|
||||
"abnormal.termination");
|
||||
IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
|
||||
Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
|
||||
} else {
|
||||
// There was nothing exceptional in the try body, so we only have normal
|
||||
// control flow.
|
||||
Builder.CreateBr(FI.ContBB);
|
||||
}
|
||||
}
|
||||
|
||||
Builder.restoreIP(SavedIP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1666,7 +1691,13 @@ void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
|
||||
if (HaveInsertPoint())
|
||||
EmitStopPoint(&S);
|
||||
|
||||
assert(!SEHTryEpilogueStack.empty() &&
|
||||
"sema should have rejected this __leave");
|
||||
// This must be a __leave from a __finally block, which we warn on and is UB.
|
||||
// Just emit unreachable.
|
||||
if (!isSEHTryScope()) {
|
||||
Builder.CreateUnreachable();
|
||||
Builder.ClearInsertionPoint();
|
||||
return;
|
||||
}
|
||||
|
||||
EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user