aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGException.cpp
diff options
context:
space:
mode:
authorTen Tzen <tentzen@microsoft.com>2020-07-12 01:37:56 -0700
committerTen Tzen <tentzen@microsoft.com>2020-07-12 01:37:56 -0700
commit66f1dcd872dba189ee054fb016f4bff535fb5afc (patch)
treefbdef482c2cbd8f08808296ae1a5db16d9f224ec /clang/lib/CodeGen/CGException.cpp
parent6634aef71f3b5e9820d2955bd6b39d2744de06eb (diff)
downloadllvm-66f1dcd872dba189ee054fb016f4bff535fb5afc.zip
llvm-66f1dcd872dba189ee054fb016f4bff535fb5afc.tar.gz
llvm-66f1dcd872dba189ee054fb016f4bff535fb5afc.tar.bz2
[Windows SEH] Fix the frame-ptr of a nested-filter within a _finally
This change fixed a SEH bug (exposed by test58 & test61 in MSVC test xcpt4u.c); when an Except-filter is located inside a finally, the frame-pointer generated today via intrinsic @llvm.eh.recoverfp is the frame-pointer of the immediate parent _finally, not the frame-ptr of outermost host function. The fix is to retrieve the Establisher's frame-pointer that was previously saved in parent's frame. The prolog of a filter inside a _finally should be like code below: %0 = call i8* @llvm.eh.recoverfp(i8* bitcast (@"?fin$0@0@main@@"), i8*%frame_pointer) %1 = call i8* @llvm.localrecover(i8* bitcast (@"?fin$0@0@main@@"), i8*%0, i32 0) %2 = bitcast i8* %1 to i8** %3 = load i8*, i8** %2, align 8 Differential Revision: https://reviews.llvm.org/D77982
Diffstat (limited to 'clang/lib/CodeGen/CGException.cpp')
-rw-r--r--clang/lib/CodeGen/CGException.cpp43
1 files changed, 43 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 2494f38..bdf7025 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -1815,6 +1815,48 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
llvm::Constant *ParentI8Fn =
llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP});
+
+ // if the parent is a _finally, the passed-in ParentFP is the FP
+ // of parent _finally, not Establisher's FP (FP of outermost function).
+ // Establkisher FP is 2nd paramenter passed into parent _finally.
+ // Fortunately, it's always saved in parent's frame. The following
+ // code retrieves it, and escapes it so that spill instruction won't be
+ // optimized away.
+ if (ParentCGF.ParentCGF != nullptr) {
+ // Locate and escape Parent's frame_pointer.addr alloca
+ // Depending on target, should be 1st/2nd one in LocalDeclMap.
+ // Let's just scan for ImplicitParamDecl with VoidPtrTy.
+ llvm::AllocaInst *FramePtrAddrAlloca = nullptr;
+ for (auto &I : ParentCGF.LocalDeclMap) {
+ const VarDecl *D = cast<VarDecl>(I.first);
+ if (isa<ImplicitParamDecl>(D) &&
+ D->getType() == getContext().VoidPtrTy) {
+ assert(D->getName().startswith("frame_pointer"));
+ FramePtrAddrAlloca = cast<llvm::AllocaInst>(I.second.getPointer());
+ break;
+ }
+ }
+ assert(FramePtrAddrAlloca);
+ auto InsertPair = ParentCGF.EscapedLocals.insert(
+ std::make_pair(FramePtrAddrAlloca, ParentCGF.EscapedLocals.size()));
+ int FrameEscapeIdx = InsertPair.first->second;
+
+ // an example of a filter's prolog::
+ // %0 = call i8* @llvm.eh.recoverfp(bitcast(@"?fin$0@0@main@@"),..)
+ // %1 = call i8* @llvm.localrecover(bitcast(@"?fin$0@0@main@@"),..)
+ // %2 = bitcast i8* %1 to i8**
+ // %3 = load i8*, i8* *%2, align 8
+ // ==> %3 is the frame-pointer of outermost host function
+ llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
+ &CGM.getModule(), llvm::Intrinsic::localrecover);
+ llvm::Constant *ParentI8Fn =
+ llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
+ ParentFP = Builder.CreateCall(
+ FrameRecoverFn, {ParentI8Fn, ParentFP,
+ llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)});
+ ParentFP = Builder.CreateBitCast(ParentFP, CGM.VoidPtrPtrTy);
+ ParentFP = Builder.CreateLoad(Address(ParentFP, getPointerAlign()));
+ }
}
// Create llvm.localrecover calls for all captures.
@@ -2013,6 +2055,7 @@ void CodeGenFunction::pushSEHCleanup(CleanupKind Kind,
void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
+ HelperCGF.ParentCGF = this;
if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
// Outline the finally block.
llvm::Function *FinallyFunc =