From 039d60c2548f8f46d2051198cd5d803342d75e9f Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 1 May 2015 22:50:14 +0000 Subject: [PATCH] Revert "[WinEH] Add an EH registration and state insertion pass for 32-bit x86" This reverts commit r236359. Things are still broken despite testing. :( git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236360 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCAsmInfo.h | 8 +- lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 - lib/CodeGen/WinEHPrepare.cpp | 11 +- lib/Target/X86/CMakeLists.txt | 1 - lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp | 3 +- lib/Target/X86/X86.h | 6 - lib/Target/X86/X86TargetMachine.cpp | 9 - lib/Target/X86/X86WinEHState.cpp | 317 ------------------- test/CodeGen/X86/inalloca-invoke.ll | 6 +- test/CodeGen/X86/win32-eh.ll | 77 ----- 10 files changed, 12 insertions(+), 428 deletions(-) delete mode 100644 lib/Target/X86/X86WinEHState.cpp delete mode 100644 test/CodeGen/X86/win32-eh.ll diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index 60a415ec68d..05da1d1871f 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -37,7 +37,6 @@ enum class EncodingType { ARM, /// Windows NT (Windows on ARM) CE, /// Windows CE ARM, PowerPC, SH3, SH4 Itanium, /// Windows x64, Windows Itanium (IA-64) - X86, /// Windows x86, uses no CFI, just EH tables MIPS = Alpha, }; } @@ -507,13 +506,12 @@ public: /// frame information to unwind. bool usesCFIForEH() const { return (ExceptionsType == ExceptionHandling::DwarfCFI || - ExceptionsType == ExceptionHandling::ARM || usesWindowsCFI()); + ExceptionsType == ExceptionHandling::ARM || + ExceptionsType == ExceptionHandling::WinEH); } bool usesWindowsCFI() const { - return ExceptionsType == ExceptionHandling::WinEH && - (WinEHEncodingType != WinEH::EncodingType::Invalid && - WinEHEncodingType != WinEH::EncodingType::X86); + return ExceptionsType == ExceptionHandling::WinEH; } bool doesDwarfUseRelocationsAcrossSections() const { diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index f385ac3c3d5..d56a1808049 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -266,8 +266,6 @@ bool AsmPrinter::doInitialization(Module &M) { case ExceptionHandling::WinEH: switch (MAI->getWinEHEncodingType()) { default: llvm_unreachable("unsupported unwinding information encoding"); - case WinEH::EncodingType::Invalid: - break; case WinEH::EncodingType::Itanium: ES = new Win64Exception(this); break; diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp index db91c02ee46..c1067c5d560 100644 --- a/lib/CodeGen/WinEHPrepare.cpp +++ b/lib/CodeGen/WinEHPrepare.cpp @@ -8,11 +8,9 @@ //===----------------------------------------------------------------------===// // // This pass lowers LLVM IR exception handling into something closer to what the -// backend wants for functions using a personality function from a runtime -// provided by MSVC. Functions with other personality functions are left alone -// and may be prepared by other passes. In particular, all supported MSVC -// personality functions require cleanup code to be outlined, and the C++ -// personality requires catch handler code to be outlined. +// backend wants. It snifs the personality function to see which kind of +// preparation is necessary. If the personality function uses the Itanium LSDA, +// this pass delegates to the DWARF EH preparation pass. // //===----------------------------------------------------------------------===// @@ -33,6 +31,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -923,7 +922,7 @@ bool WinEHPrepare::prepareExceptionHandlers( if (SEHExceptionCodeSlot) { if (SEHExceptionCodeSlot->hasNUses(0)) SEHExceptionCodeSlot->eraseFromParent(); - else if (isAllocaPromotable(SEHExceptionCodeSlot)) + else PromoteMemToReg(SEHExceptionCodeSlot, *DT); } diff --git a/lib/Target/X86/CMakeLists.txt b/lib/Target/X86/CMakeLists.txt index be8e7f6b7c5..be61b4701aa 100644 --- a/lib/Target/X86/CMakeLists.txt +++ b/lib/Target/X86/CMakeLists.txt @@ -32,7 +32,6 @@ set(sources X86TargetTransformInfo.cpp X86VZeroUpper.cpp X86FixupLEAs.cpp - X86WinEHState.cpp ) if( CMAKE_CL_64 ) diff --git a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp index bda35f2b972..e64b9635ba0 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp @@ -132,10 +132,9 @@ X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) { PrivateLabelPrefix = ".L"; PointerSize = 8; WinEHEncodingType = WinEH::EncodingType::Itanium; + ExceptionsType = ExceptionHandling::WinEH; } - ExceptionsType = ExceptionHandling::WinEH; - AssemblerDialect = AsmWriterFlavor; TextAlignFillValue = 0x90; diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h index 62c65bacef5..8b0a4cf477f 100644 --- a/lib/Target/X86/X86.h +++ b/lib/Target/X86/X86.h @@ -69,12 +69,6 @@ FunctionPass *createX86FixupLEAs(); /// esp-relative movs with pushes. FunctionPass *createX86CallFrameOptimization(); -/// createX86WinEHStatePass - Return an IR pass that inserts EH registration -/// stack objects and explicit EH state updates. This pass must run after EH -/// preparation, which does Windows-specific but architecture-neutral -/// preparation. -FunctionPass *createX86WinEHStatePass(); - } // End llvm namespace #endif diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index 9484f678808..919072aa913 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -185,7 +185,6 @@ public: void addIRPasses() override; bool addInstSelector() override; bool addILPOpts() override; - bool addPreISel() override; void addPreRegAlloc() override; void addPostRegAlloc() override; void addPreEmitPass() override; @@ -221,14 +220,6 @@ bool X86PassConfig::addILPOpts() { return true; } -bool X86PassConfig::addPreISel() { - // Only add this pass for 32-bit x86. - Triple TT(TM->getTargetTriple()); - if (TT.getArch() == Triple::x86) - addPass(createX86WinEHStatePass()); - return true; -} - void X86PassConfig::addPreRegAlloc() { addPass(createX86CallFrameOptimization()); } diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp deleted file mode 100644 index e4bbffcc55a..00000000000 --- a/lib/Target/X86/X86WinEHState.cpp +++ /dev/null @@ -1,317 +0,0 @@ -//===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// All functions using an MSVC EH personality use an explicitly updated state -// number stored in an exception registration stack object. The registration -// object is linked into a thread-local chain of registrations stored at fs:00. -// This pass adds the registration object and EH state updates. -// -//===----------------------------------------------------------------------===// - -#include "X86.h" -#include "llvm/Analysis/LibCallSemantics.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/CodeGen/WinEHFuncInfo.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/PatternMatch.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/Local.h" - -using namespace llvm; -using namespace llvm::PatternMatch; - -#define DEBUG_TYPE "winehstate" - -namespace { -class WinEHStatePass : public FunctionPass { -public: - static char ID; // Pass identification, replacement for typeid. - - WinEHStatePass() : FunctionPass(ID) {} - - bool runOnFunction(Function &Fn) override; - - bool doInitialization(Module &M) override; - - bool doFinalization(Module &M) override; - - void getAnalysisUsage(AnalysisUsage &AU) const override; - - const char *getPassName() const override { - return "Windows 32-bit x86 EH state insertion"; - } - -private: - void emitExceptionRegistrationRecord(Function *F); - - void linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode, - Value *Handler); - void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode); - - // Module-level type getters. - Type *getEHRegistrationType(); - Type *getSEH3RegistrationType(); - Type *getSEH4RegistrationType(); - Type *getCXXEH3RegistrationType(); - - // Per-module data. - Module *TheModule = nullptr; - StructType *EHRegistrationTy = nullptr; - StructType *CXXEH3RegistrationTy = nullptr; - StructType *SEH3RegistrationTy = nullptr; - StructType *SEH4RegistrationTy = nullptr; - - // Per-function state - EHPersonality Personality = EHPersonality::Unknown; - Function *PersonalityFn = nullptr; -}; -} - -FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); } - -char WinEHStatePass::ID = 0; - -bool WinEHStatePass::doInitialization(Module &M) { - TheModule = &M; - return false; -} - -bool WinEHStatePass::doFinalization(Module &M) { - assert(TheModule == &M); - TheModule = nullptr; - EHRegistrationTy = nullptr; - CXXEH3RegistrationTy = nullptr; - SEH3RegistrationTy = nullptr; - SEH4RegistrationTy = nullptr; - return false; -} - -void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const { - // This pass should only insert a stack allocation, memory accesses, and - // framerecovers. - AU.setPreservesCFG(); -} - -bool WinEHStatePass::runOnFunction(Function &F) { - // Check the personality. Do nothing if this is not an MSVC personality. - LandingPadInst *LP = nullptr; - for (BasicBlock &BB : F) { - LP = BB.getLandingPadInst(); - if (LP) - break; - } - if (!LP) - return false; - PersonalityFn = - dyn_cast(LP->getPersonalityFn()->stripPointerCasts()); - if (!PersonalityFn) - return false; - Personality = classifyEHPersonality(PersonalityFn); - if (!isMSVCEHPersonality(Personality)) - return false; - - emitExceptionRegistrationRecord(&F); - // FIXME: State insertion. - - // Reset per-function state. - PersonalityFn = nullptr; - Personality = EHPersonality::Unknown; - return true; -} - -/// Get the common EH registration subobject: -/// struct EHRegistrationNode { -/// EHRegistrationNode *Next; -/// EXCEPTION_DISPOSITION (*Handler)(...); -/// }; -Type *WinEHStatePass::getEHRegistrationType() { - if (EHRegistrationTy) - return EHRegistrationTy; - LLVMContext &Context = TheModule->getContext(); - EHRegistrationTy = StructType::create(Context, "EHRegistrationNode"); - Type *FieldTys[] = { - EHRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next - Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...) - }; - EHRegistrationTy->setBody(FieldTys, false); - return EHRegistrationTy; -} - -/// The __CxxFrameHandler3 registration node: -/// struct CXXExceptionRegistration { -/// void *SavedESP; -/// EHRegistrationNode SubRecord; -/// int32_t TryLevel; -/// }; -Type *WinEHStatePass::getCXXEH3RegistrationType() { - if (CXXEH3RegistrationTy) - return CXXEH3RegistrationTy; - LLVMContext &Context = TheModule->getContext(); - Type *FieldTys[] = { - Type::getInt8PtrTy(Context), // void *SavedESP - getEHRegistrationType(), // EHRegistrationNode SubRecord - Type::getInt32Ty(Context) // int32_t TryLevel - }; - CXXEH3RegistrationTy = - StructType::create(FieldTys, "CXXExceptionRegistration"); - return CXXEH3RegistrationTy; -} - -/// The _except_handler3 registration node: -/// struct EH3ExceptionRegistration { -/// EHRegistrationNode SubRecord; -/// void *ScopeTable; -/// int32_t TryLevel; -/// }; -Type *WinEHStatePass::getSEH3RegistrationType() { - if (SEH3RegistrationTy) - return SEH3RegistrationTy; - LLVMContext &Context = TheModule->getContext(); - Type *FieldTys[] = { - getEHRegistrationType(), // EHRegistrationNode SubRecord - Type::getInt8PtrTy(Context), // void *ScopeTable - Type::getInt32Ty(Context) // int32_t TryLevel - }; - SEH3RegistrationTy = StructType::create(FieldTys, "EH3ExceptionRegistration"); - return SEH3RegistrationTy; -} - -/// The _except_handler4 registration node: -/// struct EH4ExceptionRegistration { -/// void *SavedESP; -/// _EXCEPTION_POINTERS *ExceptionPointers; -/// EHRegistrationNode SubRecord; -/// int32_t EncodedScopeTable; -/// int32_t TryLevel; -/// }; -Type *WinEHStatePass::getSEH4RegistrationType() { - if (SEH4RegistrationTy) - return SEH4RegistrationTy; - LLVMContext &Context = TheModule->getContext(); - Type *FieldTys[] = { - Type::getInt8PtrTy(Context), // void *SavedESP - Type::getInt8PtrTy(Context), // void *ExceptionPointers - getEHRegistrationType(), // EHRegistrationNode SubRecord - Type::getInt32Ty(Context), // int32_t EncodedScopeTable - Type::getInt32Ty(Context) // int32_t TryLevel - }; - SEH4RegistrationTy = StructType::create(FieldTys, "EH4ExceptionRegistration"); - return SEH4RegistrationTy; -} - -// Emit an exception registration record. These are stack allocations with the -// common subobject of two pointers: the previous registration record (the old -// fs:00) and the personality function for the current frame. The data before -// and after that is personality function specific. -void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { - assert(Personality == EHPersonality::MSVC_CXX || - Personality == EHPersonality::MSVC_X86SEH); - - StringRef PersonalityName = PersonalityFn->getName(); - IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin()); - Type *Int8PtrType = Builder.getInt8PtrTy(); - Value *SubRecord = nullptr; - if (PersonalityName == "__CxxFrameHandler3") { - Type *RegNodeTy = getCXXEH3RegistrationType(); - Value *RegNode = Builder.CreateAlloca(RegNodeTy); - // FIXME: We can skip this in -GS- mode, when we figure that out. - // SavedESP = llvm.stacksave() - Value *SP = Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave)); - Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // TryLevel = -1 - Builder.CreateStore(Builder.getInt32(-1), - Builder.CreateStructGEP(RegNodeTy, RegNode, 2)); - // FIXME: 'Personality' is incorrect here. We need to generate a trampoline - // that effectively gets the LSDA. - SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); - linkExceptionRegistration(Builder, SubRecord, PersonalityFn); - } else if (PersonalityName == "_except_handler3") { - Type *RegNodeTy = getSEH3RegistrationType(); - Value *RegNode = Builder.CreateAlloca(RegNodeTy); - // TryLevel = -1 - Builder.CreateStore(Builder.getInt32(-1), - Builder.CreateStructGEP(RegNodeTy, RegNode, 2)); - // FIXME: Generalize llvm.eh.sjljl.lsda for this. - // ScopeTable = nullptr - Builder.CreateStore(Constant::getNullValue(Int8PtrType), - Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); - SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0); - linkExceptionRegistration(Builder, SubRecord, PersonalityFn); - } else if (PersonalityName == "_except_handler4") { - Type *RegNodeTy = getSEH4RegistrationType(); - Value *RegNode = Builder.CreateAlloca(RegNodeTy); - // SavedESP = llvm.stacksave() - Value *SP = Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave)); - Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // TryLevel = -2 - Builder.CreateStore(Builder.getInt32(-2), - Builder.CreateStructGEP(RegNodeTy, RegNode, 4)); - // FIXME: Generalize llvm.eh.sjljl.lsda for this, and then do the stack - // cookie xor. - // ScopeTable = nullptr - Builder.CreateStore(Builder.getInt32(0), - Builder.CreateStructGEP(RegNodeTy, RegNode, 3)); - SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); - linkExceptionRegistration(Builder, SubRecord, PersonalityFn); - } else { - llvm_unreachable("unexpected personality function"); - } - - // FIXME: Insert an unlink before all returns. - for (BasicBlock &BB : *F) { - TerminatorInst *T = BB.getTerminator(); - if (!isa(T)) - continue; - Builder.SetInsertPoint(T); - unlinkExceptionRegistration(Builder, SubRecord); - } -} - -void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, - Value *RegNode, Value *Handler) { - Type *RegNodeTy = getEHRegistrationType(); - // Handler = Handler - Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy()); - Builder.CreateStore(Handler, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); - // Next = [fs:00] - Constant *FSZero = - Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257)); - Value *Next = Builder.CreateLoad(FSZero); - Builder.CreateStore(Next, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // [fs:00] = RegNode - Builder.CreateStore(RegNode, FSZero); -} - -void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder, - Value *RegNode) { - // Clone RegNode into the current BB for better address mode folding. - if (auto *GEP = dyn_cast(RegNode)) { - GEP = cast(GEP->clone()); - Builder.Insert(GEP); - RegNode = GEP; - } - Type *RegNodeTy = getEHRegistrationType(); - // [fs:00] = RegNode->Next - Value *Next = - Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - Constant *FSZero = - Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257)); - Builder.CreateStore(Next, FSZero); -} diff --git a/test/CodeGen/X86/inalloca-invoke.ll b/test/CodeGen/X86/inalloca-invoke.ll index cf5cbe142ec..d6fc76ee50b 100644 --- a/test/CodeGen/X86/inalloca-invoke.ll +++ b/test/CodeGen/X86/inalloca-invoke.ll @@ -4,7 +4,6 @@ %frame.reverse = type { %Iter, %Iter } -declare i32 @pers(...) declare void @llvm.stackrestore(i8*) declare i8* @llvm.stacksave() declare void @begin(%Iter* sret) @@ -23,7 +22,8 @@ blah: ; CHECK: calll __chkstk ; CHECK: movl %esp, %[[beg:[^ ]*]] -; CHECK: leal 12(%[[beg]]), %[[end:[^ ]*]] +; CHECK: movl %esp, %[[end:[^ ]*]] +; CHECK: addl $12, %[[end]] call void @begin(%Iter* sret %temp.lvalue) ; CHECK: calll _begin @@ -49,7 +49,7 @@ invoke.cont5: ; preds = %invoke.cont ret i32 0 lpad: ; preds = %invoke.cont, %entry - %lp = landingpad { i8*, i32 } personality i32 (...)* @pers + %lp = landingpad { i8*, i32 } personality i8* null cleanup unreachable } diff --git a/test/CodeGen/X86/win32-eh.ll b/test/CodeGen/X86/win32-eh.ll deleted file mode 100644 index 875949740ec..00000000000 --- a/test/CodeGen/X86/win32-eh.ll +++ /dev/null @@ -1,77 +0,0 @@ -; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s - -declare void @may_throw_or_crash() -declare i32 @_except_handler3(...) -declare i32 @_except_handler4(...) -declare i32 @__CxxFrameHandler3(...) -declare void @llvm.eh.begincatch(i8*, i8*) -declare void @llvm.eh.endcatch() - -define void @use_except_handler3() { - invoke void @may_throw_or_crash() - to label %cont unwind label %catchall -cont: - ret void -catchall: - landingpad { i8*, i32 } personality i32 (...)* @_except_handler3 - catch i8* null - br label %cont -} - -; CHECK-LABEL: _use_except_handler3: -; CHECK: subl ${{[0-9]+}}, %esp -; CHECK: movl %fs:0, %[[next:[^ ,]*]] -; CHECK: movl %[[next]], (%esp) -; CHECK: leal (%esp), %[[node:[^ ,]*]] -; CHECK: movl %[[node]], %fs:0 -; CHECK: calll _may_throw_or_crash -; CHECK: movl (%esp), %[[next:[^ ,]*]] -; CHECK: movl %[[next]], %fs:0 -; CHECK: retl - -define void @use_except_handler4() { - invoke void @may_throw_or_crash() - to label %cont unwind label %catchall -cont: - ret void -catchall: - landingpad { i8*, i32 } personality i32 (...)* @_except_handler4 - catch i8* null - br label %cont -} - -; CHECK-LABEL: _use_except_handler4: -; CHECK: subl ${{[0-9]+}}, %esp -; CHECK: leal 8(%esp), %[[node:[^ ,]*]] -; CHECK: movl %fs:0, %[[next:[^ ,]*]] -; CHECK: movl %[[next]], 8(%esp) -; CHECK: movl %[[node]], %fs:0 -; CHECK: calll _may_throw_or_crash -; CHECK: movl 8(%esp), %[[next:[^ ,]*]] -; CHECK: movl %[[next]], %fs:0 -; CHECK: retl - -define void @use_CxxFrameHandler3() { - invoke void @may_throw_or_crash() - to label %cont unwind label %catchall -cont: - ret void -catchall: - %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__CxxFrameHandler3 - catch i8* null - %ehptr = extractvalue { i8*, i32 } %ehvals, 0 - call void @llvm.eh.begincatch(i8* %ehptr, i8* null) - call void @llvm.eh.endcatch() - br label %cont -} - -; CHECK-LABEL: _use_CxxFrameHandler3: -; CHECK: subl ${{[0-9]+}}, %esp -; CHECK: leal 4(%esp), %[[node:[^ ,]*]] -; CHECK: movl %fs:0, %[[next:[^ ,]*]] -; CHECK: movl %[[next]], 4(%esp) -; CHECK: movl %[[node]], %fs:0 -; CHECK: calll _may_throw_or_crash -; CHECK: movl 4(%esp), %[[next:[^ ,]*]] -; CHECK: movl %[[next]], %fs:0 -; CHECK: retl -- 2.34.1