[clang] 66f1dcd - [Windows SEH] Fix the frame-ptr of a nested-filter within a _finally
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(I.first); +if (isa(D) && +D->getType() == getContext().VoidPtrTy) { + assert(D->getName().startswith("frame_pointer")); + FramePtrAddrAlloca = cast(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 ComplexPairTy; LoopInfoStack LoopStack; CGBuilderTy Builder; diff
[clang] 797ad70 - [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 1
Author: Ten Tzen Date: 2021-05-17T22:42:17-07:00 New Revision: 797ad701522988e212495285dade8efac41a24d4 URL: https://github.com/llvm/llvm-project/commit/797ad701522988e212495285dade8efac41a24d4 DIFF: https://github.com/llvm/llvm-project/commit/797ad701522988e212495285dade8efac41a24d4.diff LOG: [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 1 This patch is the Part-1 (FE Clang) implementation of HW Exception handling. This new feature adds the support of Hardware Exception for Microsoft Windows SEH (Structured Exception Handling). This is the first step of this project; only X86_64 target is enabled in this patch. Compiler options: For clang-cl.exe, the option is -EHa, the same as MSVC. For clang.exe, the extra option is -fasync-exceptions, plus -triple x86_64-windows -fexceptions and -fcxx-exceptions as usual. NOTE:: Without the -EHa or -fasync-exceptions, this patch is a NO-DIFF change. The rules for C code: For C-code, one way (MSVC approach) to achieve SEH -EHa semantic is to follow three rules: * First, no exception can move in or out of _try region., i.e., no "potential faulty instruction can be moved across _try boundary. * Second, the order of exceptions for instructions 'directly' under a _try must be preserved (not applied to those in callees). * Finally, global states (local/global/heap variables) that can be read outside of _try region must be updated in memory (not just in register) before the subsequent exception occurs. The impact to C++ code: Although SEH is a feature for C code, -EHa does have a profound effect on C++ side. When a C++ function (in the same compilation unit with option -EHa ) is called by a SEH C function, a hardware exception occurs in C++ code can also be handled properly by an upstream SEH _try-handler or a C++ catch(...). As such, when that happens in the middle of an object's life scope, the dtor must be invoked the same way as C++ Synchronous Exception during unwinding process. Design: A natural way to achieve the rules above in LLVM today is to allow an EH edge added on memory/computation instruction (previous iload/istore idea) so that exception path is modeled in Flow graph preciously. However, tracking every single memory instruction and potential faulty instruction can create many Invokes, complicate flow graph and possibly result in negative performance impact for downstream optimization and code generation. Making all optimizations be aware of the new semantic is also substantial. This design does not intend to model exception path at instruction level. Instead, the proposed design tracks and reports EH state at BLOCK-level to reduce the complexity of flow graph and minimize the performance-impact on CPP code under -EHa option. One key element of this design is the ability to compute State number at block-level. Our algorithm is based on the following rationales: A _try scope is always a SEME (Single Entry Multiple Exits) region as jumping into a _try is not allowed. The single entry must start with a seh_try_begin() invoke with a correct State number that is the initial state of the SEME. Through control-flow, state number is propagated into all blocks. Side exits marked by seh_try_end() will unwind to parent state based on existing SEHUnwindMap[]. Note side exits can ONLY jump into parent scopes (lower state number). Thus, when a block succeeds various states from its predecessors, the lowest State triumphs others. If some exits flow to unreachable, propagation on those paths terminate, not affecting remaining blocks. For CPP code, object lifetime region is usually a SEME as SEH _try. However there is one rare exception: jumping into a lifetime that has Dtor but has no Ctor is warned, but allowed: Warning: jump bypasses variable with a non-trivial destructor In that case, the region is actually a MEME (multiple entry multiple exits). Our solution is to inject a eha_scope_begin() invoke in the side entry block to ensure a correct State. Implementation: Part-1: Clang implementation described below. Two intrinsic are created to track CPP object scopes; eha_scope_begin() and eha_scope_end(). _scope_begin() is immediately added after ctor() is called and EHStack is pushed. So it must be an invoke, not a call. With that it's also guaranteed an EH-cleanup-pad is created regardless whether there exists a call in this scope. _scope_end is added before dtor(). These two intrinsics make the computation of Block-State possible in downstream code gen pass, even in the presence of ctor/dtor inlining. Two intrinsic, seh_try_begin() and seh_try_end(), are added for C-code to mark _try boundary and to prevent from exceptions being moved across _try boundary. All memory instructions inside a _try are considered as 'volatile' to assure 2nd and 3rd rules for C-code above. This is a little sub-optimized. But it's acceptable as the amount of code directly under _try is very small. Part-2 (will be in Part-2 patch): LLVM implementation
RE: [EXTERNAL] [PATCH] D80344: [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 1
Hi, Alexandre Thank you for reporting this . From the callstack it does not seem related to this patch. Could you share the repro case @__compile.rsp temp.i with me? Thanks, --Ten -Original Message- From: Alexandre Ganea via Phabricator Sent: Tuesday, June 1, 2021 12:44 PM To: Ten Tzen ; andrew.kay...@intel.com; r...@google.com; david.majne...@gmail.com; pengfei.w...@intel.com; eli.fried...@gmail.com; Joseph Tremoulet ; aaron.lee.sm...@gmail.com; jdoerf...@anl.gov; lebedev...@gmail.com; rich...@metafoo.co.uk; aaron.ball...@gmail.com; rjmcc...@gmail.com; jan_svob...@apple.com Cc: markus.boec...@gmail.com; alexandre.ga...@ubisoft.com; reviews.llvm@jfbastien.com; belli...@codingworkshop.eu.org; dexonsm...@apple.com; aeuba...@google.com; riccib...@gmail.com; dany.grumb...@gmail.com; nemanja.i@gmail.com; kristof.be...@arm.com; kit.bar...@gmail.com; cfe-commits@lists.llvm.org; llvm-comm...@lists.llvm.org; bhuvanendra.kum...@amd.com; ...@gmail.com; dougp...@gmail.com; mlek...@skidmore.edu; blitzrak...@gmail.com; shen...@google.com; ztur...@roblox.com; yuanfang.c...@sony.com; david.gr...@arm.com; kuh...@google.com Subject: [EXTERNAL] [PATCH] D80344: [Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 1 aganea added a comment. Hello, this patch introduces a regression in one of our codebases. The compilation of several TUs fails with the following callstack: PLEASE submit a bug report to https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugs.llvm.org%2F&data=04%7C01%7Ctentzen%40microsoft.com%7C0d1857a9e02f491b171a08d92535a510%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637581734644682500%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=aaj5xRDyKWxqKzJHHsxMLCxa%2BuEu%2FSuNy5X7%2FxTUuFs%3D&reserved=0 and include the crash backtrace, preprocessed source, and associated run script. Stack dump: 0. Program arguments: /media/project2/llvm-project/stage0/bin/clang-cl @__compile.rsp temp.i 1. parser at end of file 2. Optimizer #0 0x043c2633 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /media/project2/llvm-project/llvm/lib/Support/Unix/Signals.inc:565:13 #1 0x043c08f0 llvm::sys::RunSignalHandlers() /media/project2/llvm-project/llvm/lib/Support/Signals.cpp:77:18 #2 0x043c1d7d llvm::sys::CleanupOnSignal(unsigned long) /media/project2/llvm-project/llvm/lib/Support/Unix/Signals.inc:0:3 #3 0x04343206 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) /media/project2/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:75:5 #4 0x04343206 CrashRecoverySignalHandler(int) /media/project2/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:388:51 #5 0x7f58152c4a90 __restore_rt sigaction.c:0:0 #6 0x03c5c11f llvm::ilist_sentinel >::empty() const /media/project2/llvm-project/llvm/include/llvm/ADT/ilist_node.h:248:36 #7 0x03c5c11f llvm::simple_ilist::empty() const /media/project2/llvm-project/llvm/include/llvm/ADT/simple_ilist.h:131:55 #8 0x03c5c11f llvm::BasicBlock::empty() const /media/project2/llvm-project/llvm/include/llvm/IR/BasicBlock.h:307:66 #9 0x03c5c11f llvm::BasicBlock::removePredecessor(llvm::BasicBlock*, bool) /media/project2/llvm-project/llvm/lib/IR/BasicBlock.cpp:328:7 #10 0x04432005 markAliveBlocks(llvm::Function&, llvm::SmallPtrSetImpl&, llvm::DomTreeUpdater*) /media/project2/llvm-project/llvm/lib/Transforms/Utils/Local.cpp:2290:15 #11 0x04432005 llvm::removeUnreachableBlocks(llvm::Function&, llvm::DomTreeUpdater*, llvm::MemorySSAUpdater*) /media/project2/llvm-project/llvm/lib/Transforms/Utils/Local.cpp:2402:18 #12 0x042e72c7 simplifyFunctionCFGImpl(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) /media/project2/llvm-project/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp:0:22 #13 0x042e72c7 simplifyFunctionCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) /media/project2/llvm-project/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp:275:18 #14 0x042e70d1 llvm::SimplifyCFGPass::run(llvm::Function&, llvm::AnalysisManager&) /media/project2/llvm-project/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp:321:7 #15 0x02e605bd llvm::detail::PassModel >::run(llvm::Function&, llvm::AnalysisManager&) BPFTargetMachine.cpp:0:0 #16 0x03d54659 llvm::SmallPtrSet::operator=(llvm::SmallPtrSet&&) /media/project2/llvm-project/llvm/include/llvm/ADT/SmallPtrSet.h:488:13 #17 0x03d54659 llvm::PreservedAnalyses::operator=(llvm::PreservedAnalyses&&) /media/project2/llvm-project/llvm/include/llvm/IR/PassManager.h:155:7 #18 0x03d54659 llvm::PassManager >::run(llvm::Function&, llvm::AnalysisManager&) /media/project2/llvm-pro
[clang] 33ba8bd - [Windows SEH]: Fix -O2 crash for Windows -EHa
Author: Ten Tzen Date: 2021-06-04T14:07:44-07:00 New Revision: 33ba8bd2c942062731a17e1b864b5953e3d79f1a URL: https://github.com/llvm/llvm-project/commit/33ba8bd2c942062731a17e1b864b5953e3d79f1a DIFF: https://github.com/llvm/llvm-project/commit/33ba8bd2c942062731a17e1b864b5953e3d79f1a.diff LOG: [Windows SEH]: Fix -O2 crash for Windows -EHa This patch fixes a Windows -EHa crash induced by previous commit 797ad701522988e212495285dade8efac41a24d4. The crash was caused by "LifetimeMarker" scope (with option -O2) that should not be considered as SEH Scope. This change also turns off -fasync-exceptions by default under -EHa option for now. Differential Revision: https://reviews.llvm.org/D103664#2799944 Added: Modified: clang/lib/CodeGen/CGCleanup.cpp clang/lib/Driver/ToolChains/Clang.cpp Removed: diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index b439204cf047..b9364fcd2231 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -195,7 +195,7 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { Scope->setLifetimeMarker(); // With Windows -EHa, Invoke llvm.seh.scope.begin() for EHCleanup - if (CGF->getLangOpts().EHAsynch && IsEHCleanup && + if (CGF->getLangOpts().EHAsynch && IsEHCleanup && !IsLifetimeMarker && CGF->getTarget().getCXXABI().isMicrosoft()) CGF->EmitSehCppScopeBegin(); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ee40df35b850..a0e1208fd709 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7151,8 +7151,6 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, if (types::isCXX(InputType)) CmdArgs.push_back("-fcxx-exceptions"); CmdArgs.push_back("-fexceptions"); -if (EH.Asynch) - CmdArgs.push_back("-fasync-exceptions"); } if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) CmdArgs.push_back("-fexternc-nounwind"); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits