forked from OSchip/llvm-project
[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
This commit is contained in:
parent
6634aef71f
commit
66f1dcd872
|
@ -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 =
|
||||
|
|
|
@ -264,6 +264,9 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue