Author: Ten Tzen Date: 2020-07-12T01:37:56-07:00 New Revision: 66f1dcd872dba189ee054fb016f4bff535fb5afc
URL: https://github.com/llvm/llvm-project/commit/66f1dcd872dba189ee054fb016f4bff535fb5afc DIFF: https://github.com/llvm/llvm-project/commit/66f1dcd872dba189ee054fb016f4bff535fb5afc.diff LOG: [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 Added: clang/test/CodeGen/windows-seh-filter-inFinally.c Modified: clang/lib/CodeGen/CGException.cpp clang/lib/CodeGen/CodeGenFunction.h Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 2494f38b3159..bdf70252b5ad 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 = diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b1841d646643..1fc2ed76ca9e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -264,6 +264,9 @@ class CodeGenFunction : public CodeGenTypeCache { CodeGenModule &CGM; // Per-module state. const TargetInfo &Target; + // For EH/SEH outlined funclets, this field points to parent's CGF + CodeGenFunction *ParentCGF = nullptr; + typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy; LoopInfoStack LoopStack; CGBuilderTy Builder; diff --git a/clang/test/CodeGen/windows-seh-filter-inFinally.c b/clang/test/CodeGen/windows-seh-filter-inFinally.c new file mode 100644 index 000000000000..f9dfca14f020 --- /dev/null +++ b/clang/test/CodeGen/windows-seh-filter-inFinally.c @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple x86_64-windows -fms-extensions -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: %[[dst:[0-9-]+]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (i8, i8*)* @"?fin$0@0@main@@" to i8*), i8* %frame_pointer) +// CHECK-NEXT: %[[dst1:[0-9-]+]] = call i8* @llvm.localrecover(i8* bitcast (void (i8, i8*)* @"?fin$0@0@main@@" to i8*), i8* %[[dst]], i32 0) +// CHECK-NEXT: %[[dst2:[0-9-]+]] = bitcast i8* %[[dst1]] to i8** +// CHECK-NEXT: = load i8*, i8** %[[dst2]], align 8 + +int +main(int argc, char *argv[]) +{ + int Counter = 0; + // + // Try/except within the finally clause of a try/finally. + // + __try { + Counter -= 1; + } + __finally { + __try { + Counter += 2; + // RtlRaiseStatus(STATUS_INTEGER_OVERFLOW); + } __except(Counter) { + __try { + Counter += 3; + } + __finally { + if (abnormal_termination() == 1) { + Counter += 5; + } + } + } + } + // expect Counter == 9 + return 1; +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits