10b57cec5SDimitry Andric //===--- CGException.cpp - Emit LLVM Code for C++ exceptions ----*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This contains code dealing with C++ exception related code generation. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "CGCXXABI.h" 140b57cec5SDimitry Andric #include "CGCleanup.h" 150b57cec5SDimitry Andric #include "CGObjCRuntime.h" 16480093f4SDimitry Andric #include "CodeGenFunction.h" 170b57cec5SDimitry Andric #include "ConstantEmitter.h" 180b57cec5SDimitry Andric #include "TargetInfo.h" 190b57cec5SDimitry Andric #include "clang/AST/Mangle.h" 200b57cec5SDimitry Andric #include "clang/AST/StmtCXX.h" 210b57cec5SDimitry Andric #include "clang/AST/StmtObjC.h" 220b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h" 235ffd83dbSDimitry Andric #include "clang/Basic/DiagnosticSema.h" 240b57cec5SDimitry Andric #include "clang/Basic/TargetBuiltins.h" 250b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 26480093f4SDimitry Andric #include "llvm/IR/Intrinsics.h" 27480093f4SDimitry Andric #include "llvm/IR/IntrinsicsWebAssembly.h" 280b57cec5SDimitry Andric #include "llvm/Support/SaveAndRestore.h" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric using namespace clang; 310b57cec5SDimitry Andric using namespace CodeGen; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric static llvm::FunctionCallee getFreeExceptionFn(CodeGenModule &CGM) { 340b57cec5SDimitry Andric // void __cxa_free_exception(void *thrown_exception); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric llvm::FunctionType *FTy = 370b57cec5SDimitry Andric llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 42fe6060f1SDimitry Andric static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule &CGM) { 43fe6060f1SDimitry Andric llvm::FunctionType *FTy = 44fe6060f1SDimitry Andric llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); 45fe6060f1SDimitry Andric return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin"); 46fe6060f1SDimitry Andric } 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric static llvm::FunctionCallee getSehTryEndFn(CodeGenModule &CGM) { 49fe6060f1SDimitry Andric llvm::FunctionType *FTy = 50fe6060f1SDimitry Andric llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); 51fe6060f1SDimitry Andric return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end"); 52fe6060f1SDimitry Andric } 53fe6060f1SDimitry Andric 540b57cec5SDimitry Andric static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { 550b57cec5SDimitry Andric // void __cxa_call_unexpected(void *thrown_exception); 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric llvm::FunctionType *FTy = 580b57cec5SDimitry Andric llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric llvm::FunctionCallee CodeGenModule::getTerminateFn() { 640b57cec5SDimitry Andric // void __terminate(); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric llvm::FunctionType *FTy = 670b57cec5SDimitry Andric llvm::FunctionType::get(VoidTy, /*isVarArg=*/false); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric StringRef name; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // In C++, use std::terminate(). 720b57cec5SDimitry Andric if (getLangOpts().CPlusPlus && 730b57cec5SDimitry Andric getTarget().getCXXABI().isItaniumFamily()) { 740b57cec5SDimitry Andric name = "_ZSt9terminatev"; 750b57cec5SDimitry Andric } else if (getLangOpts().CPlusPlus && 760b57cec5SDimitry Andric getTarget().getCXXABI().isMicrosoft()) { 770b57cec5SDimitry Andric if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015)) 780b57cec5SDimitry Andric name = "__std_terminate"; 790b57cec5SDimitry Andric else 800b57cec5SDimitry Andric name = "?terminate@@YAXXZ"; 810b57cec5SDimitry Andric } else if (getLangOpts().ObjC && 820b57cec5SDimitry Andric getLangOpts().ObjCRuntime.hasTerminate()) 830b57cec5SDimitry Andric name = "objc_terminate"; 840b57cec5SDimitry Andric else 850b57cec5SDimitry Andric name = "abort"; 860b57cec5SDimitry Andric return CreateRuntimeFunction(FTy, name); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric static llvm::FunctionCallee getCatchallRethrowFn(CodeGenModule &CGM, 900b57cec5SDimitry Andric StringRef Name) { 910b57cec5SDimitry Andric llvm::FunctionType *FTy = 920b57cec5SDimitry Andric llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric return CGM.CreateRuntimeFunction(FTy, Name); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric const EHPersonality EHPersonality::GNU_C = { "__gcc_personality_v0", nullptr }; 980b57cec5SDimitry Andric const EHPersonality 990b57cec5SDimitry Andric EHPersonality::GNU_C_SJLJ = { "__gcc_personality_sj0", nullptr }; 1000b57cec5SDimitry Andric const EHPersonality 1010b57cec5SDimitry Andric EHPersonality::GNU_C_SEH = { "__gcc_personality_seh0", nullptr }; 1020b57cec5SDimitry Andric const EHPersonality 1030b57cec5SDimitry Andric EHPersonality::NeXT_ObjC = { "__objc_personality_v0", nullptr }; 1040b57cec5SDimitry Andric const EHPersonality 1050b57cec5SDimitry Andric EHPersonality::GNU_CPlusPlus = { "__gxx_personality_v0", nullptr }; 1060b57cec5SDimitry Andric const EHPersonality 1070b57cec5SDimitry Andric EHPersonality::GNU_CPlusPlus_SJLJ = { "__gxx_personality_sj0", nullptr }; 1080b57cec5SDimitry Andric const EHPersonality 1090b57cec5SDimitry Andric EHPersonality::GNU_CPlusPlus_SEH = { "__gxx_personality_seh0", nullptr }; 1100b57cec5SDimitry Andric const EHPersonality 1110b57cec5SDimitry Andric EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"}; 1120b57cec5SDimitry Andric const EHPersonality 1130b57cec5SDimitry Andric EHPersonality::GNU_ObjC_SJLJ = {"__gnu_objc_personality_sj0", "objc_exception_throw"}; 1140b57cec5SDimitry Andric const EHPersonality 1150b57cec5SDimitry Andric EHPersonality::GNU_ObjC_SEH = {"__gnu_objc_personality_seh0", "objc_exception_throw"}; 1160b57cec5SDimitry Andric const EHPersonality 1170b57cec5SDimitry Andric EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", nullptr }; 1180b57cec5SDimitry Andric const EHPersonality 1190b57cec5SDimitry Andric EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", nullptr }; 1200b57cec5SDimitry Andric const EHPersonality 1210b57cec5SDimitry Andric EHPersonality::MSVC_except_handler = { "_except_handler3", nullptr }; 1220b57cec5SDimitry Andric const EHPersonality 1230b57cec5SDimitry Andric EHPersonality::MSVC_C_specific_handler = { "__C_specific_handler", nullptr }; 1240b57cec5SDimitry Andric const EHPersonality 1250b57cec5SDimitry Andric EHPersonality::MSVC_CxxFrameHandler3 = { "__CxxFrameHandler3", nullptr }; 1260b57cec5SDimitry Andric const EHPersonality 1270b57cec5SDimitry Andric EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr }; 128e8d8bef9SDimitry Andric const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1", 129e8d8bef9SDimitry Andric nullptr}; 1307a6dacacSDimitry Andric const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2", 1317a6dacacSDimitry Andric nullptr}; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric static const EHPersonality &getCPersonality(const TargetInfo &Target, 1340b57cec5SDimitry Andric const LangOptions &L) { 1350b57cec5SDimitry Andric const llvm::Triple &T = Target.getTriple(); 1360b57cec5SDimitry Andric if (T.isWindowsMSVCEnvironment()) 1370b57cec5SDimitry Andric return EHPersonality::MSVC_CxxFrameHandler3; 138e8d8bef9SDimitry Andric if (L.hasSjLjExceptions()) 1390b57cec5SDimitry Andric return EHPersonality::GNU_C_SJLJ; 140e8d8bef9SDimitry Andric if (L.hasDWARFExceptions()) 1410b57cec5SDimitry Andric return EHPersonality::GNU_C; 142e8d8bef9SDimitry Andric if (L.hasSEHExceptions()) 1430b57cec5SDimitry Andric return EHPersonality::GNU_C_SEH; 1440b57cec5SDimitry Andric return EHPersonality::GNU_C; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric static const EHPersonality &getObjCPersonality(const TargetInfo &Target, 1480b57cec5SDimitry Andric const LangOptions &L) { 1490b57cec5SDimitry Andric const llvm::Triple &T = Target.getTriple(); 1500b57cec5SDimitry Andric if (T.isWindowsMSVCEnvironment()) 1510b57cec5SDimitry Andric return EHPersonality::MSVC_CxxFrameHandler3; 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric switch (L.ObjCRuntime.getKind()) { 1540b57cec5SDimitry Andric case ObjCRuntime::FragileMacOSX: 1550b57cec5SDimitry Andric return getCPersonality(Target, L); 1560b57cec5SDimitry Andric case ObjCRuntime::MacOSX: 1570b57cec5SDimitry Andric case ObjCRuntime::iOS: 1580b57cec5SDimitry Andric case ObjCRuntime::WatchOS: 1590b57cec5SDimitry Andric return EHPersonality::NeXT_ObjC; 1600b57cec5SDimitry Andric case ObjCRuntime::GNUstep: 161297eecfbSDimitry Andric if (T.isOSCygMing()) 162297eecfbSDimitry Andric return EHPersonality::GNU_CPlusPlus_SEH; 163297eecfbSDimitry Andric else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7)) 1640b57cec5SDimitry Andric return EHPersonality::GNUstep_ObjC; 165bdd1243dSDimitry Andric [[fallthrough]]; 1660b57cec5SDimitry Andric case ObjCRuntime::GCC: 1670b57cec5SDimitry Andric case ObjCRuntime::ObjFW: 168e8d8bef9SDimitry Andric if (L.hasSjLjExceptions()) 1690b57cec5SDimitry Andric return EHPersonality::GNU_ObjC_SJLJ; 170e8d8bef9SDimitry Andric if (L.hasSEHExceptions()) 1710b57cec5SDimitry Andric return EHPersonality::GNU_ObjC_SEH; 1720b57cec5SDimitry Andric return EHPersonality::GNU_ObjC; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric llvm_unreachable("bad runtime kind"); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric static const EHPersonality &getCXXPersonality(const TargetInfo &Target, 1780b57cec5SDimitry Andric const LangOptions &L) { 1790b57cec5SDimitry Andric const llvm::Triple &T = Target.getTriple(); 1800b57cec5SDimitry Andric if (T.isWindowsMSVCEnvironment()) 1810b57cec5SDimitry Andric return EHPersonality::MSVC_CxxFrameHandler3; 182e8d8bef9SDimitry Andric if (T.isOSAIX()) 183e8d8bef9SDimitry Andric return EHPersonality::XL_CPlusPlus; 184e8d8bef9SDimitry Andric if (L.hasSjLjExceptions()) 1850b57cec5SDimitry Andric return EHPersonality::GNU_CPlusPlus_SJLJ; 186e8d8bef9SDimitry Andric if (L.hasDWARFExceptions()) 1870b57cec5SDimitry Andric return EHPersonality::GNU_CPlusPlus; 188e8d8bef9SDimitry Andric if (L.hasSEHExceptions()) 1890b57cec5SDimitry Andric return EHPersonality::GNU_CPlusPlus_SEH; 190e8d8bef9SDimitry Andric if (L.hasWasmExceptions()) 1910b57cec5SDimitry Andric return EHPersonality::GNU_Wasm_CPlusPlus; 1927a6dacacSDimitry Andric if (T.isOSzOS()) 1937a6dacacSDimitry Andric return EHPersonality::ZOS_CPlusPlus; 1940b57cec5SDimitry Andric return EHPersonality::GNU_CPlusPlus; 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric /// Determines the personality function to use when both C++ 1980b57cec5SDimitry Andric /// and Objective-C exceptions are being caught. 1990b57cec5SDimitry Andric static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target, 2000b57cec5SDimitry Andric const LangOptions &L) { 2010b57cec5SDimitry Andric if (Target.getTriple().isWindowsMSVCEnvironment()) 2020b57cec5SDimitry Andric return EHPersonality::MSVC_CxxFrameHandler3; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric switch (L.ObjCRuntime.getKind()) { 2050b57cec5SDimitry Andric // In the fragile ABI, just use C++ exception handling and hope 2060b57cec5SDimitry Andric // they're not doing crazy exception mixing. 2070b57cec5SDimitry Andric case ObjCRuntime::FragileMacOSX: 2080b57cec5SDimitry Andric return getCXXPersonality(Target, L); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric // The ObjC personality defers to the C++ personality for non-ObjC 2110b57cec5SDimitry Andric // handlers. Unlike the C++ case, we use the same personality 2120b57cec5SDimitry Andric // function on targets using (backend-driven) SJLJ EH. 2130b57cec5SDimitry Andric case ObjCRuntime::MacOSX: 2140b57cec5SDimitry Andric case ObjCRuntime::iOS: 2150b57cec5SDimitry Andric case ObjCRuntime::WatchOS: 2160b57cec5SDimitry Andric return getObjCPersonality(Target, L); 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric case ObjCRuntime::GNUstep: 219297eecfbSDimitry Andric return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH 220297eecfbSDimitry Andric : EHPersonality::GNU_ObjCXX; 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric // The GCC runtime's personality function inherently doesn't support 2230b57cec5SDimitry Andric // mixed EH. Use the ObjC personality just to avoid returning null. 2240b57cec5SDimitry Andric case ObjCRuntime::GCC: 2250b57cec5SDimitry Andric case ObjCRuntime::ObjFW: 2260b57cec5SDimitry Andric return getObjCPersonality(Target, L); 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric llvm_unreachable("bad runtime kind"); 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) { 2320b57cec5SDimitry Andric if (T.getArch() == llvm::Triple::x86) 2330b57cec5SDimitry Andric return EHPersonality::MSVC_except_handler; 2340b57cec5SDimitry Andric return EHPersonality::MSVC_C_specific_handler; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric const EHPersonality &EHPersonality::get(CodeGenModule &CGM, 2380b57cec5SDimitry Andric const FunctionDecl *FD) { 2390b57cec5SDimitry Andric const llvm::Triple &T = CGM.getTarget().getTriple(); 2400b57cec5SDimitry Andric const LangOptions &L = CGM.getLangOpts(); 2410b57cec5SDimitry Andric const TargetInfo &Target = CGM.getTarget(); 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric // Functions using SEH get an SEH personality. 2440b57cec5SDimitry Andric if (FD && FD->usesSEHTry()) 2450b57cec5SDimitry Andric return getSEHPersonalityMSVC(T); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric if (L.ObjC) 2480b57cec5SDimitry Andric return L.CPlusPlus ? getObjCXXPersonality(Target, L) 2490b57cec5SDimitry Andric : getObjCPersonality(Target, L); 2500b57cec5SDimitry Andric return L.CPlusPlus ? getCXXPersonality(Target, L) 2510b57cec5SDimitry Andric : getCPersonality(Target, L); 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) { 2550b57cec5SDimitry Andric const auto *FD = CGF.CurCodeDecl; 2560b57cec5SDimitry Andric // For outlined finallys and filters, use the SEH personality in case they 2570b57cec5SDimitry Andric // contain more SEH. This mostly only affects finallys. Filters could 2580b57cec5SDimitry Andric // hypothetically use gnu statement expressions to sneak in nested SEH. 259bdd1243dSDimitry Andric FD = FD ? FD : CGF.CurSEHParent.getDecl(); 2600b57cec5SDimitry Andric return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD)); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM, 2640b57cec5SDimitry Andric const EHPersonality &Personality) { 2650b57cec5SDimitry Andric return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true), 2660b57cec5SDimitry Andric Personality.PersonalityFn, 2670b57cec5SDimitry Andric llvm::AttributeList(), /*Local=*/true); 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, 2710b57cec5SDimitry Andric const EHPersonality &Personality) { 2720b57cec5SDimitry Andric llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality); 2735f757f3fSDimitry Andric return cast<llvm::Constant>(Fn.getCallee()); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric /// Check whether a landingpad instruction only uses C++ features. 2770b57cec5SDimitry Andric static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { 2780b57cec5SDimitry Andric for (unsigned I = 0, E = LPI->getNumClauses(); I != E; ++I) { 2790b57cec5SDimitry Andric // Look for something that would've been returned by the ObjC 2800b57cec5SDimitry Andric // runtime's GetEHType() method. 2810b57cec5SDimitry Andric llvm::Value *Val = LPI->getClause(I)->stripPointerCasts(); 2820b57cec5SDimitry Andric if (LPI->isCatch(I)) { 2830b57cec5SDimitry Andric // Check if the catch value has the ObjC prefix. 2840b57cec5SDimitry Andric if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val)) 2850b57cec5SDimitry Andric // ObjC EH selector entries are always global variables with 2860b57cec5SDimitry Andric // names starting like this. 2875f757f3fSDimitry Andric if (GV->getName().starts_with("OBJC_EHTYPE")) 2880b57cec5SDimitry Andric return false; 2890b57cec5SDimitry Andric } else { 2900b57cec5SDimitry Andric // Check if any of the filter values have the ObjC prefix. 2910b57cec5SDimitry Andric llvm::Constant *CVal = cast<llvm::Constant>(Val); 2920b57cec5SDimitry Andric for (llvm::User::op_iterator 2930b57cec5SDimitry Andric II = CVal->op_begin(), IE = CVal->op_end(); II != IE; ++II) { 2940b57cec5SDimitry Andric if (llvm::GlobalVariable *GV = 2950b57cec5SDimitry Andric cast<llvm::GlobalVariable>((*II)->stripPointerCasts())) 2960b57cec5SDimitry Andric // ObjC EH selector entries are always global variables with 2970b57cec5SDimitry Andric // names starting like this. 2985f757f3fSDimitry Andric if (GV->getName().starts_with("OBJC_EHTYPE")) 2990b57cec5SDimitry Andric return false; 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric return true; 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric /// Check whether a personality function could reasonably be swapped 3070b57cec5SDimitry Andric /// for a C++ personality function. 3080b57cec5SDimitry Andric static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { 3090b57cec5SDimitry Andric for (llvm::User *U : Fn->users()) { 3100b57cec5SDimitry Andric // Conditionally white-list bitcasts. 3110b57cec5SDimitry Andric if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(U)) { 3120b57cec5SDimitry Andric if (CE->getOpcode() != llvm::Instruction::BitCast) return false; 3130b57cec5SDimitry Andric if (!PersonalityHasOnlyCXXUses(CE)) 3140b57cec5SDimitry Andric return false; 3150b57cec5SDimitry Andric continue; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Otherwise it must be a function. 3190b57cec5SDimitry Andric llvm::Function *F = dyn_cast<llvm::Function>(U); 3200b57cec5SDimitry Andric if (!F) return false; 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric for (auto BB = F->begin(), E = F->end(); BB != E; ++BB) { 3230b57cec5SDimitry Andric if (BB->isLandingPad()) 3240b57cec5SDimitry Andric if (!LandingPadHasOnlyCXXUses(BB->getLandingPadInst())) 3250b57cec5SDimitry Andric return false; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric return true; 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric /// Try to use the C++ personality function in ObjC++. Not doing this 3330b57cec5SDimitry Andric /// can cause some incompatibilities with gcc, which is more 3340b57cec5SDimitry Andric /// aggressive about only using the ObjC++ personality in a function 3350b57cec5SDimitry Andric /// when it really needs it. 3360b57cec5SDimitry Andric void CodeGenModule::SimplifyPersonality() { 3370b57cec5SDimitry Andric // If we're not in ObjC++ -fexceptions, there's nothing to do. 3380b57cec5SDimitry Andric if (!LangOpts.CPlusPlus || !LangOpts.ObjC || !LangOpts.Exceptions) 3390b57cec5SDimitry Andric return; 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric // Both the problem this endeavors to fix and the way the logic 3420b57cec5SDimitry Andric // above works is specific to the NeXT runtime. 3430b57cec5SDimitry Andric if (!LangOpts.ObjCRuntime.isNeXTFamily()) 3440b57cec5SDimitry Andric return; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric const EHPersonality &ObjCXX = EHPersonality::get(*this, /*FD=*/nullptr); 3470b57cec5SDimitry Andric const EHPersonality &CXX = getCXXPersonality(getTarget(), LangOpts); 3480b57cec5SDimitry Andric if (&ObjCXX == &CXX) 3490b57cec5SDimitry Andric return; 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric assert(std::strcmp(ObjCXX.PersonalityFn, CXX.PersonalityFn) != 0 && 3520b57cec5SDimitry Andric "Different EHPersonalities using the same personality function."); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric llvm::Function *Fn = getModule().getFunction(ObjCXX.PersonalityFn); 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric // Nothing to do if it's unused. 3570b57cec5SDimitry Andric if (!Fn || Fn->use_empty()) return; 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric // Can't do the optimization if it has non-C++ uses. 3600b57cec5SDimitry Andric if (!PersonalityHasOnlyCXXUses(Fn)) return; 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric // Create the C++ personality function and kill off the old 3630b57cec5SDimitry Andric // function. 3640b57cec5SDimitry Andric llvm::FunctionCallee CXXFn = getPersonalityFn(*this, CXX); 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric // This can happen if the user is screwing with us. 3670b57cec5SDimitry Andric if (Fn->getType() != CXXFn.getCallee()->getType()) 3680b57cec5SDimitry Andric return; 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric Fn->replaceAllUsesWith(CXXFn.getCallee()); 3710b57cec5SDimitry Andric Fn->eraseFromParent(); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric /// Returns the value to inject into a selector to indicate the 3750b57cec5SDimitry Andric /// presence of a catch-all. 3760b57cec5SDimitry Andric static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) { 3770b57cec5SDimitry Andric // Possibly we should use @llvm.eh.catch.all.value here. 3780b57cec5SDimitry Andric return llvm::ConstantPointerNull::get(CGF.Int8PtrTy); 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric namespace { 3820b57cec5SDimitry Andric /// A cleanup to free the exception object if its initialization 3830b57cec5SDimitry Andric /// throws. 3840b57cec5SDimitry Andric struct FreeException final : EHScopeStack::Cleanup { 3850b57cec5SDimitry Andric llvm::Value *exn; 3860b57cec5SDimitry Andric FreeException(llvm::Value *exn) : exn(exn) {} 3870b57cec5SDimitry Andric void Emit(CodeGenFunction &CGF, Flags flags) override { 3880b57cec5SDimitry Andric CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric }; 3910b57cec5SDimitry Andric } // end anonymous namespace 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // Emits an exception expression into the given location. This 3940b57cec5SDimitry Andric // differs from EmitAnyExprToMem only in that, if a final copy-ctor 3950b57cec5SDimitry Andric // call is required, an exception within that copy ctor causes 3960b57cec5SDimitry Andric // std::terminate to be invoked. 3970b57cec5SDimitry Andric void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { 3980b57cec5SDimitry Andric // Make sure the exception object is cleaned up if there's an 3990b57cec5SDimitry Andric // exception during initialization. 400*0fca6ea1SDimitry Andric pushFullExprCleanup<FreeException>(EHCleanup, addr.emitRawPointer(*this)); 4010b57cec5SDimitry Andric EHScopeStack::stable_iterator cleanup = EHStack.stable_begin(); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric // __cxa_allocate_exception returns a void*; we need to cast this 4040b57cec5SDimitry Andric // to the appropriate type for the object. 4050eae32dcSDimitry Andric llvm::Type *ty = ConvertTypeForMem(e->getType()); 40606c3fb27SDimitry Andric Address typedAddr = addr.withElementType(ty); 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric // FIXME: this isn't quite right! If there's a final unelided call 4090b57cec5SDimitry Andric // to a copy constructor, then according to [except.terminate]p1 we 4100b57cec5SDimitry Andric // must call std::terminate() if that constructor throws, because 4110b57cec5SDimitry Andric // technically that copy occurs after the exception expression is 4120b57cec5SDimitry Andric // evaluated but before the exception is caught. But the best way 4130b57cec5SDimitry Andric // to handle that is to teach EmitAggExpr to do the final copy 4140b57cec5SDimitry Andric // differently if it can't be elided. 4150b57cec5SDimitry Andric EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(), 4160b57cec5SDimitry Andric /*IsInit*/ true); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric // Deactivate the cleanup block. 419*0fca6ea1SDimitry Andric DeactivateCleanupBlock( 420*0fca6ea1SDimitry Andric cleanup, cast<llvm::Instruction>(typedAddr.emitRawPointer(*this))); 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric Address CodeGenFunction::getExceptionSlot() { 4240b57cec5SDimitry Andric if (!ExceptionSlot) 4250b57cec5SDimitry Andric ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot"); 4260eae32dcSDimitry Andric return Address(ExceptionSlot, Int8PtrTy, getPointerAlign()); 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric Address CodeGenFunction::getEHSelectorSlot() { 4300b57cec5SDimitry Andric if (!EHSelectorSlot) 4310b57cec5SDimitry Andric EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot"); 4320eae32dcSDimitry Andric return Address(EHSelectorSlot, Int32Ty, CharUnits::fromQuantity(4)); 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric llvm::Value *CodeGenFunction::getExceptionFromSlot() { 4360b57cec5SDimitry Andric return Builder.CreateLoad(getExceptionSlot(), "exn"); 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric llvm::Value *CodeGenFunction::getSelectorFromSlot() { 4400b57cec5SDimitry Andric return Builder.CreateLoad(getEHSelectorSlot(), "sel"); 4410b57cec5SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, 4440b57cec5SDimitry Andric bool KeepInsertionPoint) { 4455f757f3fSDimitry Andric // If the exception is being emitted in an OpenMP target region, 4465f757f3fSDimitry Andric // and the target is a GPU, we do not support exception handling. 4475f757f3fSDimitry Andric // Therefore, we emit a trap which will abort the program, and 4485f757f3fSDimitry Andric // prompt a warning indicating that a trap will be emitted. 4495f757f3fSDimitry Andric const llvm::Triple &T = Target.getTriple(); 4505f757f3fSDimitry Andric if (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())) { 4515f757f3fSDimitry Andric EmitTrapCall(llvm::Intrinsic::trap); 4525f757f3fSDimitry Andric return; 4535f757f3fSDimitry Andric } 4540b57cec5SDimitry Andric if (const Expr *SubExpr = E->getSubExpr()) { 4550b57cec5SDimitry Andric QualType ThrowType = SubExpr->getType(); 4560b57cec5SDimitry Andric if (ThrowType->isObjCObjectPointerType()) { 4570b57cec5SDimitry Andric const Stmt *ThrowStmt = E->getSubExpr(); 4580b57cec5SDimitry Andric const ObjCAtThrowStmt S(E->getExprLoc(), const_cast<Stmt *>(ThrowStmt)); 4590b57cec5SDimitry Andric CGM.getObjCRuntime().EmitThrowStmt(*this, S, false); 4600b57cec5SDimitry Andric } else { 4610b57cec5SDimitry Andric CGM.getCXXABI().emitThrow(*this, E); 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric } else { 4640b57cec5SDimitry Andric CGM.getCXXABI().emitRethrow(*this, /*isNoReturn=*/true); 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric // throw is an expression, and the expression emitters expect us 4680b57cec5SDimitry Andric // to leave ourselves at a valid insertion point. 4690b57cec5SDimitry Andric if (KeepInsertionPoint) 4700b57cec5SDimitry Andric EmitBlock(createBasicBlock("throw.cont")); 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric void CodeGenFunction::EmitStartEHSpec(const Decl *D) { 4740b57cec5SDimitry Andric if (!CGM.getLangOpts().CXXExceptions) 4750b57cec5SDimitry Andric return; 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); 4780b57cec5SDimitry Andric if (!FD) { 4790b57cec5SDimitry Andric // Check if CapturedDecl is nothrow and create terminate scope for it. 4800b57cec5SDimitry Andric if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) { 4810b57cec5SDimitry Andric if (CD->isNothrow()) 4820b57cec5SDimitry Andric EHStack.pushTerminate(); 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric return; 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); 4870b57cec5SDimitry Andric if (!Proto) 4880b57cec5SDimitry Andric return; 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric ExceptionSpecificationType EST = Proto->getExceptionSpecType(); 491349cc55cSDimitry Andric // In C++17 and later, 'throw()' aka EST_DynamicNone is treated the same way 492349cc55cSDimitry Andric // as noexcept. In earlier standards, it is handled in this block, along with 493349cc55cSDimitry Andric // 'throw(X...)'. 494349cc55cSDimitry Andric if (EST == EST_Dynamic || 495349cc55cSDimitry Andric (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { 4960b57cec5SDimitry Andric // TODO: Revisit exception specifications for the MS ABI. There is a way to 4970b57cec5SDimitry Andric // encode these in an object file but MSVC doesn't do anything with it. 4980b57cec5SDimitry Andric if (getTarget().getCXXABI().isMicrosoft()) 4990b57cec5SDimitry Andric return; 500fe6060f1SDimitry Andric // In Wasm EH we currently treat 'throw()' in the same way as 'noexcept'. In 5015ffd83dbSDimitry Andric // case of throw with types, we ignore it and print a warning for now. 502fe6060f1SDimitry Andric // TODO Correctly handle exception specification in Wasm EH 503e8d8bef9SDimitry Andric if (CGM.getLangOpts().hasWasmExceptions()) { 5045ffd83dbSDimitry Andric if (EST == EST_DynamicNone) 5055ffd83dbSDimitry Andric EHStack.pushTerminate(); 5065ffd83dbSDimitry Andric else 5075ffd83dbSDimitry Andric CGM.getDiags().Report(D->getLocation(), 5085ffd83dbSDimitry Andric diag::warn_wasm_dynamic_exception_spec_ignored) 5095ffd83dbSDimitry Andric << FD->getExceptionSpecSourceRange(); 5105ffd83dbSDimitry Andric return; 5115ffd83dbSDimitry Andric } 512fe6060f1SDimitry Andric // Currently Emscripten EH only handles 'throw()' but not 'throw' with 513fe6060f1SDimitry Andric // types. 'throw()' handling will be done in JS glue code so we don't need 514fe6060f1SDimitry Andric // to do anything in that case. Just print a warning message in case of 515fe6060f1SDimitry Andric // throw with types. 516fe6060f1SDimitry Andric // TODO Correctly handle exception specification in Emscripten EH 517fe6060f1SDimitry Andric if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly && 518fe6060f1SDimitry Andric CGM.getLangOpts().getExceptionHandling() == 519fe6060f1SDimitry Andric LangOptions::ExceptionHandlingKind::None && 520fe6060f1SDimitry Andric EST == EST_Dynamic) 521fe6060f1SDimitry Andric CGM.getDiags().Report(D->getLocation(), 522fe6060f1SDimitry Andric diag::warn_wasm_dynamic_exception_spec_ignored) 523fe6060f1SDimitry Andric << FD->getExceptionSpecSourceRange(); 524fe6060f1SDimitry Andric 5250b57cec5SDimitry Andric unsigned NumExceptions = Proto->getNumExceptions(); 5260b57cec5SDimitry Andric EHFilterScope *Filter = EHStack.pushFilter(NumExceptions); 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric for (unsigned I = 0; I != NumExceptions; ++I) { 5290b57cec5SDimitry Andric QualType Ty = Proto->getExceptionType(I); 5300b57cec5SDimitry Andric QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); 5310b57cec5SDimitry Andric llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, 5320b57cec5SDimitry Andric /*ForEH=*/true); 5330b57cec5SDimitry Andric Filter->setFilter(I, EHType); 5340b57cec5SDimitry Andric } 535349cc55cSDimitry Andric } else if (Proto->canThrow() == CT_Cannot) { 536349cc55cSDimitry Andric // noexcept functions are simple terminate scopes. 537349cc55cSDimitry Andric if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur 538349cc55cSDimitry Andric EHStack.pushTerminate(); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric /// Emit the dispatch block for a filter scope if necessary. 5430b57cec5SDimitry Andric static void emitFilterDispatchBlock(CodeGenFunction &CGF, 5440b57cec5SDimitry Andric EHFilterScope &filterScope) { 5450b57cec5SDimitry Andric llvm::BasicBlock *dispatchBlock = filterScope.getCachedEHDispatchBlock(); 5460b57cec5SDimitry Andric if (!dispatchBlock) return; 5470b57cec5SDimitry Andric if (dispatchBlock->use_empty()) { 5480b57cec5SDimitry Andric delete dispatchBlock; 5490b57cec5SDimitry Andric return; 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric CGF.EmitBlockAfterUses(dispatchBlock); 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric // If this isn't a catch-all filter, we need to check whether we got 5550b57cec5SDimitry Andric // here because the filter triggered. 5560b57cec5SDimitry Andric if (filterScope.getNumFilters()) { 5570b57cec5SDimitry Andric // Load the selector value. 5580b57cec5SDimitry Andric llvm::Value *selector = CGF.getSelectorFromSlot(); 5590b57cec5SDimitry Andric llvm::BasicBlock *unexpectedBB = CGF.createBasicBlock("ehspec.unexpected"); 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric llvm::Value *zero = CGF.Builder.getInt32(0); 5620b57cec5SDimitry Andric llvm::Value *failsFilter = 5630b57cec5SDimitry Andric CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails"); 5640b57cec5SDimitry Andric CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, 5650b57cec5SDimitry Andric CGF.getEHResumeBlock(false)); 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric CGF.EmitBlock(unexpectedBB); 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric // Call __cxa_call_unexpected. This doesn't need to be an invoke 5710b57cec5SDimitry Andric // because __cxa_call_unexpected magically filters exceptions 5720b57cec5SDimitry Andric // according to the last landing pad the exception was thrown 5730b57cec5SDimitry Andric // into. Seriously. 5740b57cec5SDimitry Andric llvm::Value *exn = CGF.getExceptionFromSlot(); 5750b57cec5SDimitry Andric CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn) 5760b57cec5SDimitry Andric ->setDoesNotReturn(); 5770b57cec5SDimitry Andric CGF.Builder.CreateUnreachable(); 5780b57cec5SDimitry Andric } 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric void CodeGenFunction::EmitEndEHSpec(const Decl *D) { 5810b57cec5SDimitry Andric if (!CGM.getLangOpts().CXXExceptions) 5820b57cec5SDimitry Andric return; 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); 5850b57cec5SDimitry Andric if (!FD) { 5860b57cec5SDimitry Andric // Check if CapturedDecl is nothrow and pop terminate scope for it. 5870b57cec5SDimitry Andric if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) { 588fe6060f1SDimitry Andric if (CD->isNothrow() && !EHStack.empty()) 5890b57cec5SDimitry Andric EHStack.popTerminate(); 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric return; 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); 5940b57cec5SDimitry Andric if (!Proto) 5950b57cec5SDimitry Andric return; 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric ExceptionSpecificationType EST = Proto->getExceptionSpecType(); 598349cc55cSDimitry Andric if (EST == EST_Dynamic || 599349cc55cSDimitry Andric (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { 6000b57cec5SDimitry Andric // TODO: Revisit exception specifications for the MS ABI. There is a way to 6010b57cec5SDimitry Andric // encode these in an object file but MSVC doesn't do anything with it. 6020b57cec5SDimitry Andric if (getTarget().getCXXABI().isMicrosoft()) 6030b57cec5SDimitry Andric return; 6045ffd83dbSDimitry Andric // In wasm we currently treat 'throw()' in the same way as 'noexcept'. In 6055ffd83dbSDimitry Andric // case of throw with types, we ignore it and print a warning for now. 6065ffd83dbSDimitry Andric // TODO Correctly handle exception specification in wasm 607e8d8bef9SDimitry Andric if (CGM.getLangOpts().hasWasmExceptions()) { 6085ffd83dbSDimitry Andric if (EST == EST_DynamicNone) 6095ffd83dbSDimitry Andric EHStack.popTerminate(); 6105ffd83dbSDimitry Andric return; 6115ffd83dbSDimitry Andric } 6120b57cec5SDimitry Andric EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin()); 6130b57cec5SDimitry Andric emitFilterDispatchBlock(*this, filterScope); 6140b57cec5SDimitry Andric EHStack.popFilter(); 615349cc55cSDimitry Andric } else if (Proto->canThrow() == CT_Cannot && 616349cc55cSDimitry Andric /* possible empty when under async exceptions */ 617349cc55cSDimitry Andric !EHStack.empty()) { 618349cc55cSDimitry Andric EHStack.popTerminate(); 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { 6235f757f3fSDimitry Andric const llvm::Triple &T = Target.getTriple(); 6245f757f3fSDimitry Andric // If we encounter a try statement on in an OpenMP target region offloaded to 6255f757f3fSDimitry Andric // a GPU, we treat it as a basic block. 6265f757f3fSDimitry Andric const bool IsTargetDevice = 6275f757f3fSDimitry Andric (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())); 6285f757f3fSDimitry Andric if (!IsTargetDevice) 6290b57cec5SDimitry Andric EnterCXXTryStmt(S); 6300b57cec5SDimitry Andric EmitStmt(S.getTryBlock()); 6315f757f3fSDimitry Andric if (!IsTargetDevice) 6320b57cec5SDimitry Andric ExitCXXTryStmt(S); 6330b57cec5SDimitry Andric } 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { 6360b57cec5SDimitry Andric unsigned NumHandlers = S.getNumHandlers(); 6370b57cec5SDimitry Andric EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers); 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric for (unsigned I = 0; I != NumHandlers; ++I) { 6400b57cec5SDimitry Andric const CXXCatchStmt *C = S.getHandler(I); 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric llvm::BasicBlock *Handler = createBasicBlock("catch"); 6430b57cec5SDimitry Andric if (C->getExceptionDecl()) { 6440b57cec5SDimitry Andric // FIXME: Dropping the reference type on the type into makes it 6450b57cec5SDimitry Andric // impossible to correctly implement catch-by-reference 6460b57cec5SDimitry Andric // semantics for pointers. Unfortunately, this is what all 6470b57cec5SDimitry Andric // existing compilers do, and it's not clear that the standard 6480b57cec5SDimitry Andric // personality routine is capable of doing this right. See C++ DR 388: 6490b57cec5SDimitry Andric // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388 6500b57cec5SDimitry Andric Qualifiers CaughtTypeQuals; 6510b57cec5SDimitry Andric QualType CaughtType = CGM.getContext().getUnqualifiedArrayType( 6520b57cec5SDimitry Andric C->getCaughtType().getNonReferenceType(), CaughtTypeQuals); 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric CatchTypeInfo TypeInfo{nullptr, 0}; 6550b57cec5SDimitry Andric if (CaughtType->isObjCObjectPointerType()) 6560b57cec5SDimitry Andric TypeInfo.RTTI = CGM.getObjCRuntime().GetEHType(CaughtType); 6570b57cec5SDimitry Andric else 6580b57cec5SDimitry Andric TypeInfo = CGM.getCXXABI().getAddrOfCXXCatchHandlerType( 6590b57cec5SDimitry Andric CaughtType, C->getCaughtType()); 6600b57cec5SDimitry Andric CatchScope->setHandler(I, TypeInfo, Handler); 6610b57cec5SDimitry Andric } else { 6620b57cec5SDimitry Andric // No exception decl indicates '...', a catch-all. 6630b57cec5SDimitry Andric CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler); 664fe6060f1SDimitry Andric // Under async exceptions, catch(...) need to catch HW exception too 665fe6060f1SDimitry Andric // Mark scope with SehTryBegin as a SEH __try scope 666fe6060f1SDimitry Andric if (getLangOpts().EHAsynch) 66706c3fb27SDimitry Andric EmitSehTryScopeBegin(); 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric } 6700b57cec5SDimitry Andric } 6710b57cec5SDimitry Andric 6720b57cec5SDimitry Andric llvm::BasicBlock * 6730b57cec5SDimitry Andric CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { 6740b57cec5SDimitry Andric if (EHPersonality::get(*this).usesFuncletPads()) 6750b57cec5SDimitry Andric return getFuncletEHDispatchBlock(si); 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric // The dispatch block for the end of the scope chain is a block that 6780b57cec5SDimitry Andric // just resumes unwinding. 6790b57cec5SDimitry Andric if (si == EHStack.stable_end()) 6800b57cec5SDimitry Andric return getEHResumeBlock(true); 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric // Otherwise, we should look at the actual scope. 6830b57cec5SDimitry Andric EHScope &scope = *EHStack.find(si); 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric llvm::BasicBlock *dispatchBlock = scope.getCachedEHDispatchBlock(); 6860b57cec5SDimitry Andric if (!dispatchBlock) { 6870b57cec5SDimitry Andric switch (scope.getKind()) { 6880b57cec5SDimitry Andric case EHScope::Catch: { 6890b57cec5SDimitry Andric // Apply a special case to a single catch-all. 6900b57cec5SDimitry Andric EHCatchScope &catchScope = cast<EHCatchScope>(scope); 6910b57cec5SDimitry Andric if (catchScope.getNumHandlers() == 1 && 6920b57cec5SDimitry Andric catchScope.getHandler(0).isCatchAll()) { 6930b57cec5SDimitry Andric dispatchBlock = catchScope.getHandler(0).Block; 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric // Otherwise, make a dispatch block. 6960b57cec5SDimitry Andric } else { 6970b57cec5SDimitry Andric dispatchBlock = createBasicBlock("catch.dispatch"); 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric break; 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric case EHScope::Cleanup: 7030b57cec5SDimitry Andric dispatchBlock = createBasicBlock("ehcleanup"); 7040b57cec5SDimitry Andric break; 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric case EHScope::Filter: 7070b57cec5SDimitry Andric dispatchBlock = createBasicBlock("filter.dispatch"); 7080b57cec5SDimitry Andric break; 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric case EHScope::Terminate: 7110b57cec5SDimitry Andric dispatchBlock = getTerminateHandler(); 7120b57cec5SDimitry Andric break; 7130b57cec5SDimitry Andric } 7140b57cec5SDimitry Andric scope.setCachedEHDispatchBlock(dispatchBlock); 7150b57cec5SDimitry Andric } 7160b57cec5SDimitry Andric return dispatchBlock; 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric llvm::BasicBlock * 7200b57cec5SDimitry Andric CodeGenFunction::getFuncletEHDispatchBlock(EHScopeStack::stable_iterator SI) { 7210b57cec5SDimitry Andric // Returning nullptr indicates that the previous dispatch block should unwind 7220b57cec5SDimitry Andric // to caller. 7230b57cec5SDimitry Andric if (SI == EHStack.stable_end()) 7240b57cec5SDimitry Andric return nullptr; 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric // Otherwise, we should look at the actual scope. 7270b57cec5SDimitry Andric EHScope &EHS = *EHStack.find(SI); 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric llvm::BasicBlock *DispatchBlock = EHS.getCachedEHDispatchBlock(); 7300b57cec5SDimitry Andric if (DispatchBlock) 7310b57cec5SDimitry Andric return DispatchBlock; 7320b57cec5SDimitry Andric 7330b57cec5SDimitry Andric if (EHS.getKind() == EHScope::Terminate) 7340b57cec5SDimitry Andric DispatchBlock = getTerminateFunclet(); 7350b57cec5SDimitry Andric else 7360b57cec5SDimitry Andric DispatchBlock = createBasicBlock(); 7370b57cec5SDimitry Andric CGBuilderTy Builder(*this, DispatchBlock); 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric switch (EHS.getKind()) { 7400b57cec5SDimitry Andric case EHScope::Catch: 7410b57cec5SDimitry Andric DispatchBlock->setName("catch.dispatch"); 7420b57cec5SDimitry Andric break; 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric case EHScope::Cleanup: 7450b57cec5SDimitry Andric DispatchBlock->setName("ehcleanup"); 7460b57cec5SDimitry Andric break; 7470b57cec5SDimitry Andric 7480b57cec5SDimitry Andric case EHScope::Filter: 7490b57cec5SDimitry Andric llvm_unreachable("exception specifications not handled yet!"); 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric case EHScope::Terminate: 7520b57cec5SDimitry Andric DispatchBlock->setName("terminate"); 7530b57cec5SDimitry Andric break; 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric EHS.setCachedEHDispatchBlock(DispatchBlock); 7560b57cec5SDimitry Andric return DispatchBlock; 7570b57cec5SDimitry Andric } 7580b57cec5SDimitry Andric 7590b57cec5SDimitry Andric /// Check whether this is a non-EH scope, i.e. a scope which doesn't 7600b57cec5SDimitry Andric /// affect exception handling. Currently, the only non-EH scopes are 7610b57cec5SDimitry Andric /// normal-only cleanup scopes. 7620b57cec5SDimitry Andric static bool isNonEHScope(const EHScope &S) { 7630b57cec5SDimitry Andric switch (S.getKind()) { 7640b57cec5SDimitry Andric case EHScope::Cleanup: 7650b57cec5SDimitry Andric return !cast<EHCleanupScope>(S).isEHCleanup(); 7660b57cec5SDimitry Andric case EHScope::Filter: 7670b57cec5SDimitry Andric case EHScope::Catch: 7680b57cec5SDimitry Andric case EHScope::Terminate: 7690b57cec5SDimitry Andric return false; 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric llvm_unreachable("Invalid EHScope Kind!"); 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { 7760b57cec5SDimitry Andric assert(EHStack.requiresLandingPad()); 7770b57cec5SDimitry Andric assert(!EHStack.empty()); 7780b57cec5SDimitry Andric 7795ffd83dbSDimitry Andric // If exceptions are disabled/ignored and SEH is not in use, then there is no 7805ffd83dbSDimitry Andric // invoke destination. SEH "works" even if exceptions are off. In practice, 7815ffd83dbSDimitry Andric // this means that C++ destructors and other EH cleanups don't run, which is 782fe6060f1SDimitry Andric // consistent with MSVC's behavior, except in the presence of -EHa 7830b57cec5SDimitry Andric const LangOptions &LO = CGM.getLangOpts(); 7845ffd83dbSDimitry Andric if (!LO.Exceptions || LO.IgnoreExceptions) { 7850b57cec5SDimitry Andric if (!LO.Borland && !LO.MicrosoftExt) 7860b57cec5SDimitry Andric return nullptr; 7870b57cec5SDimitry Andric if (!currentFunctionUsesSEHTry()) 7880b57cec5SDimitry Andric return nullptr; 7890b57cec5SDimitry Andric } 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric // CUDA device code doesn't have exceptions. 7920b57cec5SDimitry Andric if (LO.CUDA && LO.CUDAIsDevice) 7930b57cec5SDimitry Andric return nullptr; 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric // Check the innermost scope for a cached landing pad. If this is 7960b57cec5SDimitry Andric // a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad. 7970b57cec5SDimitry Andric llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad(); 7980b57cec5SDimitry Andric if (LP) return LP; 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric const EHPersonality &Personality = EHPersonality::get(*this); 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric if (!CurFn->hasPersonalityFn()) 8030b57cec5SDimitry Andric CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality)); 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric if (Personality.usesFuncletPads()) { 8060b57cec5SDimitry Andric // We don't need separate landing pads in the funclet model. 8070b57cec5SDimitry Andric LP = getEHDispatchBlock(EHStack.getInnermostEHScope()); 8080b57cec5SDimitry Andric } else { 8090b57cec5SDimitry Andric // Build the landing pad for this scope. 8100b57cec5SDimitry Andric LP = EmitLandingPad(); 8110b57cec5SDimitry Andric } 8120b57cec5SDimitry Andric 8130b57cec5SDimitry Andric assert(LP); 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric // Cache the landing pad on the innermost scope. If this is a 8160b57cec5SDimitry Andric // non-EH scope, cache the landing pad on the enclosing scope, too. 8170b57cec5SDimitry Andric for (EHScopeStack::iterator ir = EHStack.begin(); true; ++ir) { 8180b57cec5SDimitry Andric ir->setCachedLandingPad(LP); 8190b57cec5SDimitry Andric if (!isNonEHScope(*ir)) break; 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric return LP; 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { 8260b57cec5SDimitry Andric assert(EHStack.requiresLandingPad()); 8275ffd83dbSDimitry Andric assert(!CGM.getLangOpts().IgnoreExceptions && 8285ffd83dbSDimitry Andric "LandingPad should not be emitted when -fignore-exceptions are in " 8295ffd83dbSDimitry Andric "effect."); 8300b57cec5SDimitry Andric EHScope &innermostEHScope = *EHStack.find(EHStack.getInnermostEHScope()); 8310b57cec5SDimitry Andric switch (innermostEHScope.getKind()) { 8320b57cec5SDimitry Andric case EHScope::Terminate: 8330b57cec5SDimitry Andric return getTerminateLandingPad(); 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric case EHScope::Catch: 8360b57cec5SDimitry Andric case EHScope::Cleanup: 8370b57cec5SDimitry Andric case EHScope::Filter: 8380b57cec5SDimitry Andric if (llvm::BasicBlock *lpad = innermostEHScope.getCachedLandingPad()) 8390b57cec5SDimitry Andric return lpad; 8400b57cec5SDimitry Andric } 8410b57cec5SDimitry Andric 8420b57cec5SDimitry Andric // Save the current IR generation state. 8430b57cec5SDimitry Andric CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); 8440b57cec5SDimitry Andric auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation); 8450b57cec5SDimitry Andric 8460b57cec5SDimitry Andric // Create and configure the landing pad. 8470b57cec5SDimitry Andric llvm::BasicBlock *lpad = createBasicBlock("lpad"); 8480b57cec5SDimitry Andric EmitBlock(lpad); 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric llvm::LandingPadInst *LPadInst = 8510b57cec5SDimitry Andric Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0); 8520b57cec5SDimitry Andric 8530b57cec5SDimitry Andric llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0); 8540b57cec5SDimitry Andric Builder.CreateStore(LPadExn, getExceptionSlot()); 8550b57cec5SDimitry Andric llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1); 8560b57cec5SDimitry Andric Builder.CreateStore(LPadSel, getEHSelectorSlot()); 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric // Save the exception pointer. It's safe to use a single exception 8590b57cec5SDimitry Andric // pointer per function because EH cleanups can never have nested 8600b57cec5SDimitry Andric // try/catches. 8610b57cec5SDimitry Andric // Build the landingpad instruction. 8620b57cec5SDimitry Andric 8630b57cec5SDimitry Andric // Accumulate all the handlers in scope. 8640b57cec5SDimitry Andric bool hasCatchAll = false; 8650b57cec5SDimitry Andric bool hasCleanup = false; 8660b57cec5SDimitry Andric bool hasFilter = false; 8670b57cec5SDimitry Andric SmallVector<llvm::Value*, 4> filterTypes; 8680b57cec5SDimitry Andric llvm::SmallPtrSet<llvm::Value*, 4> catchTypes; 8690b57cec5SDimitry Andric for (EHScopeStack::iterator I = EHStack.begin(), E = EHStack.end(); I != E; 8700b57cec5SDimitry Andric ++I) { 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric switch (I->getKind()) { 8730b57cec5SDimitry Andric case EHScope::Cleanup: 8740b57cec5SDimitry Andric // If we have a cleanup, remember that. 8750b57cec5SDimitry Andric hasCleanup = (hasCleanup || cast<EHCleanupScope>(*I).isEHCleanup()); 8760b57cec5SDimitry Andric continue; 8770b57cec5SDimitry Andric 8780b57cec5SDimitry Andric case EHScope::Filter: { 8790b57cec5SDimitry Andric assert(I.next() == EHStack.end() && "EH filter is not end of EH stack"); 8800b57cec5SDimitry Andric assert(!hasCatchAll && "EH filter reached after catch-all"); 8810b57cec5SDimitry Andric 8820b57cec5SDimitry Andric // Filter scopes get added to the landingpad in weird ways. 8830b57cec5SDimitry Andric EHFilterScope &filter = cast<EHFilterScope>(*I); 8840b57cec5SDimitry Andric hasFilter = true; 8850b57cec5SDimitry Andric 8860b57cec5SDimitry Andric // Add all the filter values. 8870b57cec5SDimitry Andric for (unsigned i = 0, e = filter.getNumFilters(); i != e; ++i) 8880b57cec5SDimitry Andric filterTypes.push_back(filter.getFilter(i)); 8890b57cec5SDimitry Andric goto done; 8900b57cec5SDimitry Andric } 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric case EHScope::Terminate: 8930b57cec5SDimitry Andric // Terminate scopes are basically catch-alls. 8940b57cec5SDimitry Andric assert(!hasCatchAll); 8950b57cec5SDimitry Andric hasCatchAll = true; 8960b57cec5SDimitry Andric goto done; 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric case EHScope::Catch: 8990b57cec5SDimitry Andric break; 9000b57cec5SDimitry Andric } 9010b57cec5SDimitry Andric 9020b57cec5SDimitry Andric EHCatchScope &catchScope = cast<EHCatchScope>(*I); 9030b57cec5SDimitry Andric for (unsigned hi = 0, he = catchScope.getNumHandlers(); hi != he; ++hi) { 9040b57cec5SDimitry Andric EHCatchScope::Handler handler = catchScope.getHandler(hi); 9050b57cec5SDimitry Andric assert(handler.Type.Flags == 0 && 9060b57cec5SDimitry Andric "landingpads do not support catch handler flags"); 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric // If this is a catch-all, register that and abort. 9090b57cec5SDimitry Andric if (!handler.Type.RTTI) { 9100b57cec5SDimitry Andric assert(!hasCatchAll); 9110b57cec5SDimitry Andric hasCatchAll = true; 9120b57cec5SDimitry Andric goto done; 9130b57cec5SDimitry Andric } 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric // Check whether we already have a handler for this type. 9160b57cec5SDimitry Andric if (catchTypes.insert(handler.Type.RTTI).second) 9170b57cec5SDimitry Andric // If not, add it directly to the landingpad. 9180b57cec5SDimitry Andric LPadInst->addClause(handler.Type.RTTI); 9190b57cec5SDimitry Andric } 9200b57cec5SDimitry Andric } 9210b57cec5SDimitry Andric 9220b57cec5SDimitry Andric done: 9230b57cec5SDimitry Andric // If we have a catch-all, add null to the landingpad. 9240b57cec5SDimitry Andric assert(!(hasCatchAll && hasFilter)); 9250b57cec5SDimitry Andric if (hasCatchAll) { 9260b57cec5SDimitry Andric LPadInst->addClause(getCatchAllValue(*this)); 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric // If we have an EH filter, we need to add those handlers in the 9290b57cec5SDimitry Andric // right place in the landingpad, which is to say, at the end. 9300b57cec5SDimitry Andric } else if (hasFilter) { 9310b57cec5SDimitry Andric // Create a filter expression: a constant array indicating which filter 9320b57cec5SDimitry Andric // types there are. The personality routine only lands here if the filter 9330b57cec5SDimitry Andric // doesn't match. 9340b57cec5SDimitry Andric SmallVector<llvm::Constant*, 8> Filters; 9350b57cec5SDimitry Andric llvm::ArrayType *AType = 9360b57cec5SDimitry Andric llvm::ArrayType::get(!filterTypes.empty() ? 9370b57cec5SDimitry Andric filterTypes[0]->getType() : Int8PtrTy, 9380b57cec5SDimitry Andric filterTypes.size()); 9390b57cec5SDimitry Andric 9400b57cec5SDimitry Andric for (unsigned i = 0, e = filterTypes.size(); i != e; ++i) 9410b57cec5SDimitry Andric Filters.push_back(cast<llvm::Constant>(filterTypes[i])); 9420b57cec5SDimitry Andric llvm::Constant *FilterArray = llvm::ConstantArray::get(AType, Filters); 9430b57cec5SDimitry Andric LPadInst->addClause(FilterArray); 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric // Also check whether we need a cleanup. 9460b57cec5SDimitry Andric if (hasCleanup) 9470b57cec5SDimitry Andric LPadInst->setCleanup(true); 9480b57cec5SDimitry Andric 9490b57cec5SDimitry Andric // Otherwise, signal that we at least have cleanups. 9500b57cec5SDimitry Andric } else if (hasCleanup) { 9510b57cec5SDimitry Andric LPadInst->setCleanup(true); 9520b57cec5SDimitry Andric } 9530b57cec5SDimitry Andric 9540b57cec5SDimitry Andric assert((LPadInst->getNumClauses() > 0 || LPadInst->isCleanup()) && 9550b57cec5SDimitry Andric "landingpad instruction has no clauses!"); 9560b57cec5SDimitry Andric 9570b57cec5SDimitry Andric // Tell the backend how to generate the landing pad. 9580b57cec5SDimitry Andric Builder.CreateBr(getEHDispatchBlock(EHStack.getInnermostEHScope())); 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric // Restore the old IR generation state. 9610b57cec5SDimitry Andric Builder.restoreIP(savedIP); 9620b57cec5SDimitry Andric 9630b57cec5SDimitry Andric return lpad; 9640b57cec5SDimitry Andric } 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric static void emitCatchPadBlock(CodeGenFunction &CGF, EHCatchScope &CatchScope) { 9670b57cec5SDimitry Andric llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock(); 9680b57cec5SDimitry Andric assert(DispatchBlock); 9690b57cec5SDimitry Andric 9700b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP(); 9710b57cec5SDimitry Andric CGF.EmitBlockAfterUses(DispatchBlock); 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric llvm::Value *ParentPad = CGF.CurrentFuncletPad; 9740b57cec5SDimitry Andric if (!ParentPad) 9750b57cec5SDimitry Andric ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext()); 9760b57cec5SDimitry Andric llvm::BasicBlock *UnwindBB = 9770b57cec5SDimitry Andric CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope()); 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric unsigned NumHandlers = CatchScope.getNumHandlers(); 9800b57cec5SDimitry Andric llvm::CatchSwitchInst *CatchSwitch = 9810b57cec5SDimitry Andric CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers); 9820b57cec5SDimitry Andric 9830b57cec5SDimitry Andric // Test against each of the exception types we claim to catch. 9840b57cec5SDimitry Andric for (unsigned I = 0; I < NumHandlers; ++I) { 9850b57cec5SDimitry Andric const EHCatchScope::Handler &Handler = CatchScope.getHandler(I); 9860b57cec5SDimitry Andric 9870b57cec5SDimitry Andric CatchTypeInfo TypeInfo = Handler.Type; 9880b57cec5SDimitry Andric if (!TypeInfo.RTTI) 9890b57cec5SDimitry Andric TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy); 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric CGF.Builder.SetInsertPoint(Handler.Block); 9920b57cec5SDimitry Andric 9930b57cec5SDimitry Andric if (EHPersonality::get(CGF).isMSVCXXPersonality()) { 9940b57cec5SDimitry Andric CGF.Builder.CreateCatchPad( 9950b57cec5SDimitry Andric CatchSwitch, {TypeInfo.RTTI, CGF.Builder.getInt32(TypeInfo.Flags), 9960b57cec5SDimitry Andric llvm::Constant::getNullValue(CGF.VoidPtrTy)}); 9970b57cec5SDimitry Andric } else { 9980b57cec5SDimitry Andric CGF.Builder.CreateCatchPad(CatchSwitch, {TypeInfo.RTTI}); 9990b57cec5SDimitry Andric } 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric CatchSwitch->addHandler(Handler.Block); 10020b57cec5SDimitry Andric } 10030b57cec5SDimitry Andric CGF.Builder.restoreIP(SavedIP); 10040b57cec5SDimitry Andric } 10050b57cec5SDimitry Andric 10060b57cec5SDimitry Andric // Wasm uses Windows-style EH instructions, but it merges all catch clauses into 10070b57cec5SDimitry Andric // one big catchpad, within which we use Itanium's landingpad-style selector 10080b57cec5SDimitry Andric // comparison instructions. 10090b57cec5SDimitry Andric static void emitWasmCatchPadBlock(CodeGenFunction &CGF, 10100b57cec5SDimitry Andric EHCatchScope &CatchScope) { 10110b57cec5SDimitry Andric llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock(); 10120b57cec5SDimitry Andric assert(DispatchBlock); 10130b57cec5SDimitry Andric 10140b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveIP(); 10150b57cec5SDimitry Andric CGF.EmitBlockAfterUses(DispatchBlock); 10160b57cec5SDimitry Andric 10170b57cec5SDimitry Andric llvm::Value *ParentPad = CGF.CurrentFuncletPad; 10180b57cec5SDimitry Andric if (!ParentPad) 10190b57cec5SDimitry Andric ParentPad = llvm::ConstantTokenNone::get(CGF.getLLVMContext()); 10200b57cec5SDimitry Andric llvm::BasicBlock *UnwindBB = 10210b57cec5SDimitry Andric CGF.getEHDispatchBlock(CatchScope.getEnclosingEHScope()); 10220b57cec5SDimitry Andric 10230b57cec5SDimitry Andric unsigned NumHandlers = CatchScope.getNumHandlers(); 10240b57cec5SDimitry Andric llvm::CatchSwitchInst *CatchSwitch = 10250b57cec5SDimitry Andric CGF.Builder.CreateCatchSwitch(ParentPad, UnwindBB, NumHandlers); 10260b57cec5SDimitry Andric 10270b57cec5SDimitry Andric // We don't use a landingpad instruction, so generate intrinsic calls to 10280b57cec5SDimitry Andric // provide exception and selector values. 10290b57cec5SDimitry Andric llvm::BasicBlock *WasmCatchStartBlock = CGF.createBasicBlock("catch.start"); 10300b57cec5SDimitry Andric CatchSwitch->addHandler(WasmCatchStartBlock); 10310b57cec5SDimitry Andric CGF.EmitBlockAfterUses(WasmCatchStartBlock); 10320b57cec5SDimitry Andric 10330b57cec5SDimitry Andric // Create a catchpad instruction. 10340b57cec5SDimitry Andric SmallVector<llvm::Value *, 4> CatchTypes; 10350b57cec5SDimitry Andric for (unsigned I = 0, E = NumHandlers; I < E; ++I) { 10360b57cec5SDimitry Andric const EHCatchScope::Handler &Handler = CatchScope.getHandler(I); 10370b57cec5SDimitry Andric CatchTypeInfo TypeInfo = Handler.Type; 10380b57cec5SDimitry Andric if (!TypeInfo.RTTI) 10390b57cec5SDimitry Andric TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy); 10400b57cec5SDimitry Andric CatchTypes.push_back(TypeInfo.RTTI); 10410b57cec5SDimitry Andric } 10420b57cec5SDimitry Andric auto *CPI = CGF.Builder.CreateCatchPad(CatchSwitch, CatchTypes); 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric // Create calls to wasm.get.exception and wasm.get.ehselector intrinsics. 10450b57cec5SDimitry Andric // Before they are lowered appropriately later, they provide values for the 10460b57cec5SDimitry Andric // exception and selector. 10470b57cec5SDimitry Andric llvm::Function *GetExnFn = 10480b57cec5SDimitry Andric CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_get_exception); 10490b57cec5SDimitry Andric llvm::Function *GetSelectorFn = 10500b57cec5SDimitry Andric CGF.CGM.getIntrinsic(llvm::Intrinsic::wasm_get_ehselector); 10510b57cec5SDimitry Andric llvm::CallInst *Exn = CGF.Builder.CreateCall(GetExnFn, CPI); 10520b57cec5SDimitry Andric CGF.Builder.CreateStore(Exn, CGF.getExceptionSlot()); 10530b57cec5SDimitry Andric llvm::CallInst *Selector = CGF.Builder.CreateCall(GetSelectorFn, CPI); 10540b57cec5SDimitry Andric 1055*0fca6ea1SDimitry Andric llvm::Function *TypeIDFn = 1056*0fca6ea1SDimitry Andric CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for, {CGF.VoidPtrTy}); 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric // If there's only a single catch-all, branch directly to its handler. 10590b57cec5SDimitry Andric if (CatchScope.getNumHandlers() == 1 && 10600b57cec5SDimitry Andric CatchScope.getHandler(0).isCatchAll()) { 10610b57cec5SDimitry Andric CGF.Builder.CreateBr(CatchScope.getHandler(0).Block); 10620b57cec5SDimitry Andric CGF.Builder.restoreIP(SavedIP); 10630b57cec5SDimitry Andric return; 10640b57cec5SDimitry Andric } 10650b57cec5SDimitry Andric 10660b57cec5SDimitry Andric // Test against each of the exception types we claim to catch. 10670b57cec5SDimitry Andric for (unsigned I = 0, E = NumHandlers;; ++I) { 10680b57cec5SDimitry Andric assert(I < E && "ran off end of handlers!"); 10690b57cec5SDimitry Andric const EHCatchScope::Handler &Handler = CatchScope.getHandler(I); 10700b57cec5SDimitry Andric CatchTypeInfo TypeInfo = Handler.Type; 10710b57cec5SDimitry Andric if (!TypeInfo.RTTI) 10720b57cec5SDimitry Andric TypeInfo.RTTI = llvm::Constant::getNullValue(CGF.VoidPtrTy); 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric // Figure out the next block. 10750b57cec5SDimitry Andric llvm::BasicBlock *NextBlock; 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric bool EmitNextBlock = false, NextIsEnd = false; 10780b57cec5SDimitry Andric 10790b57cec5SDimitry Andric // If this is the last handler, we're at the end, and the next block is a 10800b57cec5SDimitry Andric // block that contains a call to the rethrow function, so we can unwind to 10810b57cec5SDimitry Andric // the enclosing EH scope. The call itself will be generated later. 10820b57cec5SDimitry Andric if (I + 1 == E) { 10830b57cec5SDimitry Andric NextBlock = CGF.createBasicBlock("rethrow"); 10840b57cec5SDimitry Andric EmitNextBlock = true; 10850b57cec5SDimitry Andric NextIsEnd = true; 10860b57cec5SDimitry Andric 10870b57cec5SDimitry Andric // If the next handler is a catch-all, we're at the end, and the 10880b57cec5SDimitry Andric // next block is that handler. 10890b57cec5SDimitry Andric } else if (CatchScope.getHandler(I + 1).isCatchAll()) { 10900b57cec5SDimitry Andric NextBlock = CatchScope.getHandler(I + 1).Block; 10910b57cec5SDimitry Andric NextIsEnd = true; 10920b57cec5SDimitry Andric 10930b57cec5SDimitry Andric // Otherwise, we're not at the end and we need a new block. 10940b57cec5SDimitry Andric } else { 10950b57cec5SDimitry Andric NextBlock = CGF.createBasicBlock("catch.fallthrough"); 10960b57cec5SDimitry Andric EmitNextBlock = true; 10970b57cec5SDimitry Andric } 10980b57cec5SDimitry Andric 10990b57cec5SDimitry Andric // Figure out the catch type's index in the LSDA's type table. 11000b57cec5SDimitry Andric llvm::CallInst *TypeIndex = CGF.Builder.CreateCall(TypeIDFn, TypeInfo.RTTI); 11010b57cec5SDimitry Andric TypeIndex->setDoesNotThrow(); 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric llvm::Value *MatchesTypeIndex = 11040b57cec5SDimitry Andric CGF.Builder.CreateICmpEQ(Selector, TypeIndex, "matches"); 11050b57cec5SDimitry Andric CGF.Builder.CreateCondBr(MatchesTypeIndex, Handler.Block, NextBlock); 11060b57cec5SDimitry Andric 11070b57cec5SDimitry Andric if (EmitNextBlock) 11080b57cec5SDimitry Andric CGF.EmitBlock(NextBlock); 11090b57cec5SDimitry Andric if (NextIsEnd) 11100b57cec5SDimitry Andric break; 11110b57cec5SDimitry Andric } 11120b57cec5SDimitry Andric 11130b57cec5SDimitry Andric CGF.Builder.restoreIP(SavedIP); 11140b57cec5SDimitry Andric } 11150b57cec5SDimitry Andric 11160b57cec5SDimitry Andric /// Emit the structure of the dispatch block for the given catch scope. 11170b57cec5SDimitry Andric /// It is an invariant that the dispatch block already exists. 11180b57cec5SDimitry Andric static void emitCatchDispatchBlock(CodeGenFunction &CGF, 11190b57cec5SDimitry Andric EHCatchScope &catchScope) { 11200b57cec5SDimitry Andric if (EHPersonality::get(CGF).isWasmPersonality()) 11210b57cec5SDimitry Andric return emitWasmCatchPadBlock(CGF, catchScope); 11220b57cec5SDimitry Andric if (EHPersonality::get(CGF).usesFuncletPads()) 11230b57cec5SDimitry Andric return emitCatchPadBlock(CGF, catchScope); 11240b57cec5SDimitry Andric 11250b57cec5SDimitry Andric llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); 11260b57cec5SDimitry Andric assert(dispatchBlock); 11270b57cec5SDimitry Andric 11280b57cec5SDimitry Andric // If there's only a single catch-all, getEHDispatchBlock returned 11290b57cec5SDimitry Andric // that catch-all as the dispatch block. 11300b57cec5SDimitry Andric if (catchScope.getNumHandlers() == 1 && 11310b57cec5SDimitry Andric catchScope.getHandler(0).isCatchAll()) { 11320b57cec5SDimitry Andric assert(dispatchBlock == catchScope.getHandler(0).Block); 11330b57cec5SDimitry Andric return; 11340b57cec5SDimitry Andric } 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP(); 11370b57cec5SDimitry Andric CGF.EmitBlockAfterUses(dispatchBlock); 11380b57cec5SDimitry Andric 11390b57cec5SDimitry Andric // Select the right handler. 11400b57cec5SDimitry Andric llvm::Function *llvm_eh_typeid_for = 1141*0fca6ea1SDimitry Andric CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for, {CGF.VoidPtrTy}); 11425f757f3fSDimitry Andric llvm::Type *argTy = llvm_eh_typeid_for->getArg(0)->getType(); 11435f757f3fSDimitry Andric LangAS globAS = CGF.CGM.GetGlobalVarAddressSpace(nullptr); 11440b57cec5SDimitry Andric 11450b57cec5SDimitry Andric // Load the selector value. 11460b57cec5SDimitry Andric llvm::Value *selector = CGF.getSelectorFromSlot(); 11470b57cec5SDimitry Andric 11480b57cec5SDimitry Andric // Test against each of the exception types we claim to catch. 11490b57cec5SDimitry Andric for (unsigned i = 0, e = catchScope.getNumHandlers(); ; ++i) { 11500b57cec5SDimitry Andric assert(i < e && "ran off end of handlers!"); 11510b57cec5SDimitry Andric const EHCatchScope::Handler &handler = catchScope.getHandler(i); 11520b57cec5SDimitry Andric 11530b57cec5SDimitry Andric llvm::Value *typeValue = handler.Type.RTTI; 11540b57cec5SDimitry Andric assert(handler.Type.Flags == 0 && 11550b57cec5SDimitry Andric "landingpads do not support catch handler flags"); 11560b57cec5SDimitry Andric assert(typeValue && "fell into catch-all case!"); 11575f757f3fSDimitry Andric // With opaque ptrs, only the address space can be a mismatch. 11585f757f3fSDimitry Andric if (typeValue->getType() != argTy) 11595f757f3fSDimitry Andric typeValue = 11605f757f3fSDimitry Andric CGF.getTargetHooks().performAddrSpaceCast(CGF, typeValue, globAS, 11615f757f3fSDimitry Andric LangAS::Default, argTy); 11620b57cec5SDimitry Andric 11630b57cec5SDimitry Andric // Figure out the next block. 11640b57cec5SDimitry Andric bool nextIsEnd; 11650b57cec5SDimitry Andric llvm::BasicBlock *nextBlock; 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric // If this is the last handler, we're at the end, and the next 11680b57cec5SDimitry Andric // block is the block for the enclosing EH scope. 11690b57cec5SDimitry Andric if (i + 1 == e) { 11700b57cec5SDimitry Andric nextBlock = CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope()); 11710b57cec5SDimitry Andric nextIsEnd = true; 11720b57cec5SDimitry Andric 11730b57cec5SDimitry Andric // If the next handler is a catch-all, we're at the end, and the 11740b57cec5SDimitry Andric // next block is that handler. 11750b57cec5SDimitry Andric } else if (catchScope.getHandler(i+1).isCatchAll()) { 11760b57cec5SDimitry Andric nextBlock = catchScope.getHandler(i+1).Block; 11770b57cec5SDimitry Andric nextIsEnd = true; 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric // Otherwise, we're not at the end and we need a new block. 11800b57cec5SDimitry Andric } else { 11810b57cec5SDimitry Andric nextBlock = CGF.createBasicBlock("catch.fallthrough"); 11820b57cec5SDimitry Andric nextIsEnd = false; 11830b57cec5SDimitry Andric } 11840b57cec5SDimitry Andric 11850b57cec5SDimitry Andric // Figure out the catch type's index in the LSDA's type table. 11860b57cec5SDimitry Andric llvm::CallInst *typeIndex = 11870b57cec5SDimitry Andric CGF.Builder.CreateCall(llvm_eh_typeid_for, typeValue); 11880b57cec5SDimitry Andric typeIndex->setDoesNotThrow(); 11890b57cec5SDimitry Andric 11900b57cec5SDimitry Andric llvm::Value *matchesTypeIndex = 11910b57cec5SDimitry Andric CGF.Builder.CreateICmpEQ(selector, typeIndex, "matches"); 11920b57cec5SDimitry Andric CGF.Builder.CreateCondBr(matchesTypeIndex, handler.Block, nextBlock); 11930b57cec5SDimitry Andric 11940b57cec5SDimitry Andric // If the next handler is a catch-all, we're completely done. 11950b57cec5SDimitry Andric if (nextIsEnd) { 11960b57cec5SDimitry Andric CGF.Builder.restoreIP(savedIP); 11970b57cec5SDimitry Andric return; 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric // Otherwise we need to emit and continue at that block. 12000b57cec5SDimitry Andric CGF.EmitBlock(nextBlock); 12010b57cec5SDimitry Andric } 12020b57cec5SDimitry Andric } 12030b57cec5SDimitry Andric 12040b57cec5SDimitry Andric void CodeGenFunction::popCatchScope() { 12050b57cec5SDimitry Andric EHCatchScope &catchScope = cast<EHCatchScope>(*EHStack.begin()); 12060b57cec5SDimitry Andric if (catchScope.hasEHBranches()) 12070b57cec5SDimitry Andric emitCatchDispatchBlock(*this, catchScope); 12080b57cec5SDimitry Andric EHStack.popCatch(); 12090b57cec5SDimitry Andric } 12100b57cec5SDimitry Andric 12110b57cec5SDimitry Andric void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { 12120b57cec5SDimitry Andric unsigned NumHandlers = S.getNumHandlers(); 12130b57cec5SDimitry Andric EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin()); 12140b57cec5SDimitry Andric assert(CatchScope.getNumHandlers() == NumHandlers); 12150b57cec5SDimitry Andric llvm::BasicBlock *DispatchBlock = CatchScope.getCachedEHDispatchBlock(); 12160b57cec5SDimitry Andric 12170b57cec5SDimitry Andric // If the catch was not required, bail out now. 12180b57cec5SDimitry Andric if (!CatchScope.hasEHBranches()) { 12190b57cec5SDimitry Andric CatchScope.clearHandlerBlocks(); 12200b57cec5SDimitry Andric EHStack.popCatch(); 12210b57cec5SDimitry Andric return; 12220b57cec5SDimitry Andric } 12230b57cec5SDimitry Andric 12240b57cec5SDimitry Andric // Emit the structure of the EH dispatch for this catch. 12250b57cec5SDimitry Andric emitCatchDispatchBlock(*this, CatchScope); 12260b57cec5SDimitry Andric 12270b57cec5SDimitry Andric // Copy the handler blocks off before we pop the EH stack. Emitting 12280b57cec5SDimitry Andric // the handlers might scribble on this memory. 12290b57cec5SDimitry Andric SmallVector<EHCatchScope::Handler, 8> Handlers( 12300b57cec5SDimitry Andric CatchScope.begin(), CatchScope.begin() + NumHandlers); 12310b57cec5SDimitry Andric 12320b57cec5SDimitry Andric EHStack.popCatch(); 12330b57cec5SDimitry Andric 12340b57cec5SDimitry Andric // The fall-through block. 12350b57cec5SDimitry Andric llvm::BasicBlock *ContBB = createBasicBlock("try.cont"); 12360b57cec5SDimitry Andric 12370b57cec5SDimitry Andric // We just emitted the body of the try; jump to the continue block. 12380b57cec5SDimitry Andric if (HaveInsertPoint()) 12390b57cec5SDimitry Andric Builder.CreateBr(ContBB); 12400b57cec5SDimitry Andric 12410b57cec5SDimitry Andric // Determine if we need an implicit rethrow for all these catch handlers; 12420b57cec5SDimitry Andric // see the comment below. 12430b57cec5SDimitry Andric bool doImplicitRethrow = false; 12440b57cec5SDimitry Andric if (IsFnTryBlock) 12450b57cec5SDimitry Andric doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) || 12460b57cec5SDimitry Andric isa<CXXConstructorDecl>(CurCodeDecl); 12470b57cec5SDimitry Andric 12480b57cec5SDimitry Andric // Wasm uses Windows-style EH instructions, but merges all catch clauses into 12490b57cec5SDimitry Andric // one big catchpad. So we save the old funclet pad here before we traverse 12500b57cec5SDimitry Andric // each catch handler. 1251bdd1243dSDimitry Andric SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad); 12520b57cec5SDimitry Andric llvm::BasicBlock *WasmCatchStartBlock = nullptr; 12530b57cec5SDimitry Andric if (EHPersonality::get(*this).isWasmPersonality()) { 12540b57cec5SDimitry Andric auto *CatchSwitch = 12550b57cec5SDimitry Andric cast<llvm::CatchSwitchInst>(DispatchBlock->getFirstNonPHI()); 12560b57cec5SDimitry Andric WasmCatchStartBlock = CatchSwitch->hasUnwindDest() 12570b57cec5SDimitry Andric ? CatchSwitch->getSuccessor(1) 12580b57cec5SDimitry Andric : CatchSwitch->getSuccessor(0); 12590b57cec5SDimitry Andric auto *CPI = cast<llvm::CatchPadInst>(WasmCatchStartBlock->getFirstNonPHI()); 12600b57cec5SDimitry Andric CurrentFuncletPad = CPI; 12610b57cec5SDimitry Andric } 12620b57cec5SDimitry Andric 12630b57cec5SDimitry Andric // Perversely, we emit the handlers backwards precisely because we 12640b57cec5SDimitry Andric // want them to appear in source order. In all of these cases, the 12650b57cec5SDimitry Andric // catch block will have exactly one predecessor, which will be a 12660b57cec5SDimitry Andric // particular block in the catch dispatch. However, in the case of 12670b57cec5SDimitry Andric // a catch-all, one of the dispatch blocks will branch to two 12680b57cec5SDimitry Andric // different handlers, and EmitBlockAfterUses will cause the second 12690b57cec5SDimitry Andric // handler to be moved before the first. 12700b57cec5SDimitry Andric bool HasCatchAll = false; 12710b57cec5SDimitry Andric for (unsigned I = NumHandlers; I != 0; --I) { 12720b57cec5SDimitry Andric HasCatchAll |= Handlers[I - 1].isCatchAll(); 12730b57cec5SDimitry Andric llvm::BasicBlock *CatchBlock = Handlers[I-1].Block; 12740b57cec5SDimitry Andric EmitBlockAfterUses(CatchBlock); 12750b57cec5SDimitry Andric 12760b57cec5SDimitry Andric // Catch the exception if this isn't a catch-all. 12770b57cec5SDimitry Andric const CXXCatchStmt *C = S.getHandler(I-1); 12780b57cec5SDimitry Andric 12790b57cec5SDimitry Andric // Enter a cleanup scope, including the catch variable and the 12800b57cec5SDimitry Andric // end-catch. 12810b57cec5SDimitry Andric RunCleanupsScope CatchScope(*this); 12820b57cec5SDimitry Andric 12830b57cec5SDimitry Andric // Initialize the catch variable and set up the cleanups. 1284bdd1243dSDimitry Andric SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad); 12850b57cec5SDimitry Andric CGM.getCXXABI().emitBeginCatch(*this, C); 12860b57cec5SDimitry Andric 12870b57cec5SDimitry Andric // Emit the PGO counter increment. 12880b57cec5SDimitry Andric incrementProfileCounter(C); 12890b57cec5SDimitry Andric 12900b57cec5SDimitry Andric // Perform the body of the catch. 12910b57cec5SDimitry Andric EmitStmt(C->getHandlerBlock()); 12920b57cec5SDimitry Andric 12930b57cec5SDimitry Andric // [except.handle]p11: 12940b57cec5SDimitry Andric // The currently handled exception is rethrown if control 12950b57cec5SDimitry Andric // reaches the end of a handler of the function-try-block of a 12960b57cec5SDimitry Andric // constructor or destructor. 12970b57cec5SDimitry Andric 12980b57cec5SDimitry Andric // It is important that we only do this on fallthrough and not on 12990b57cec5SDimitry Andric // return. Note that it's illegal to put a return in a 13000b57cec5SDimitry Andric // constructor function-try-block's catch handler (p14), so this 13010b57cec5SDimitry Andric // really only applies to destructors. 13020b57cec5SDimitry Andric if (doImplicitRethrow && HaveInsertPoint()) { 13030b57cec5SDimitry Andric CGM.getCXXABI().emitRethrow(*this, /*isNoReturn*/false); 13040b57cec5SDimitry Andric Builder.CreateUnreachable(); 13050b57cec5SDimitry Andric Builder.ClearInsertionPoint(); 13060b57cec5SDimitry Andric } 13070b57cec5SDimitry Andric 13080b57cec5SDimitry Andric // Fall out through the catch cleanups. 13090b57cec5SDimitry Andric CatchScope.ForceCleanup(); 13100b57cec5SDimitry Andric 13110b57cec5SDimitry Andric // Branch out of the try. 13120b57cec5SDimitry Andric if (HaveInsertPoint()) 13130b57cec5SDimitry Andric Builder.CreateBr(ContBB); 13140b57cec5SDimitry Andric } 13150b57cec5SDimitry Andric 13160b57cec5SDimitry Andric // Because in wasm we merge all catch clauses into one big catchpad, in case 13170b57cec5SDimitry Andric // none of the types in catch handlers matches after we test against each of 13180b57cec5SDimitry Andric // them, we should unwind to the next EH enclosing scope. We generate a call 13190b57cec5SDimitry Andric // to rethrow function here to do that. 13200b57cec5SDimitry Andric if (EHPersonality::get(*this).isWasmPersonality() && !HasCatchAll) { 13210b57cec5SDimitry Andric assert(WasmCatchStartBlock); 13220b57cec5SDimitry Andric // Navigate for the "rethrow" block we created in emitWasmCatchPadBlock(). 13230b57cec5SDimitry Andric // Wasm uses landingpad-style conditional branches to compare selectors, so 13240b57cec5SDimitry Andric // we follow the false destination for each of the cond branches to reach 13250b57cec5SDimitry Andric // the rethrow block. 13260b57cec5SDimitry Andric llvm::BasicBlock *RethrowBlock = WasmCatchStartBlock; 13270b57cec5SDimitry Andric while (llvm::Instruction *TI = RethrowBlock->getTerminator()) { 13280b57cec5SDimitry Andric auto *BI = cast<llvm::BranchInst>(TI); 13290b57cec5SDimitry Andric assert(BI->isConditional()); 13300b57cec5SDimitry Andric RethrowBlock = BI->getSuccessor(1); 13310b57cec5SDimitry Andric } 13320b57cec5SDimitry Andric assert(RethrowBlock != WasmCatchStartBlock && RethrowBlock->empty()); 13330b57cec5SDimitry Andric Builder.SetInsertPoint(RethrowBlock); 13340b57cec5SDimitry Andric llvm::Function *RethrowInCatchFn = 1335e8d8bef9SDimitry Andric CGM.getIntrinsic(llvm::Intrinsic::wasm_rethrow); 13360b57cec5SDimitry Andric EmitNoreturnRuntimeCallOrInvoke(RethrowInCatchFn, {}); 13370b57cec5SDimitry Andric } 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andric EmitBlock(ContBB); 13400b57cec5SDimitry Andric incrementProfileCounter(&S); 13410b57cec5SDimitry Andric } 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric namespace { 13440b57cec5SDimitry Andric struct CallEndCatchForFinally final : EHScopeStack::Cleanup { 13450b57cec5SDimitry Andric llvm::Value *ForEHVar; 13460b57cec5SDimitry Andric llvm::FunctionCallee EndCatchFn; 13470b57cec5SDimitry Andric CallEndCatchForFinally(llvm::Value *ForEHVar, 13480b57cec5SDimitry Andric llvm::FunctionCallee EndCatchFn) 13490b57cec5SDimitry Andric : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {} 13500b57cec5SDimitry Andric 13510b57cec5SDimitry Andric void Emit(CodeGenFunction &CGF, Flags flags) override { 13520b57cec5SDimitry Andric llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch"); 13530b57cec5SDimitry Andric llvm::BasicBlock *CleanupContBB = 13540b57cec5SDimitry Andric CGF.createBasicBlock("finally.cleanup.cont"); 13550b57cec5SDimitry Andric 13560b57cec5SDimitry Andric llvm::Value *ShouldEndCatch = 13570b57cec5SDimitry Andric CGF.Builder.CreateFlagLoad(ForEHVar, "finally.endcatch"); 13580b57cec5SDimitry Andric CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); 13590b57cec5SDimitry Andric CGF.EmitBlock(EndCatchBB); 13600b57cec5SDimitry Andric CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw 13610b57cec5SDimitry Andric CGF.EmitBlock(CleanupContBB); 13620b57cec5SDimitry Andric } 13630b57cec5SDimitry Andric }; 13640b57cec5SDimitry Andric 13650b57cec5SDimitry Andric struct PerformFinally final : EHScopeStack::Cleanup { 13660b57cec5SDimitry Andric const Stmt *Body; 13670b57cec5SDimitry Andric llvm::Value *ForEHVar; 13680b57cec5SDimitry Andric llvm::FunctionCallee EndCatchFn; 13690b57cec5SDimitry Andric llvm::FunctionCallee RethrowFn; 13700b57cec5SDimitry Andric llvm::Value *SavedExnVar; 13710b57cec5SDimitry Andric 13720b57cec5SDimitry Andric PerformFinally(const Stmt *Body, llvm::Value *ForEHVar, 13730b57cec5SDimitry Andric llvm::FunctionCallee EndCatchFn, 13740b57cec5SDimitry Andric llvm::FunctionCallee RethrowFn, llvm::Value *SavedExnVar) 13750b57cec5SDimitry Andric : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn), 13760b57cec5SDimitry Andric RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {} 13770b57cec5SDimitry Andric 13780b57cec5SDimitry Andric void Emit(CodeGenFunction &CGF, Flags flags) override { 13790b57cec5SDimitry Andric // Enter a cleanup to call the end-catch function if one was provided. 13800b57cec5SDimitry Andric if (EndCatchFn) 13810b57cec5SDimitry Andric CGF.EHStack.pushCleanup<CallEndCatchForFinally>(NormalAndEHCleanup, 13820b57cec5SDimitry Andric ForEHVar, EndCatchFn); 13830b57cec5SDimitry Andric 13840b57cec5SDimitry Andric // Save the current cleanup destination in case there are 13850b57cec5SDimitry Andric // cleanups in the finally block. 13860b57cec5SDimitry Andric llvm::Value *SavedCleanupDest = 13870b57cec5SDimitry Andric CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot(), 13880b57cec5SDimitry Andric "cleanup.dest.saved"); 13890b57cec5SDimitry Andric 13900b57cec5SDimitry Andric // Emit the finally block. 13910b57cec5SDimitry Andric CGF.EmitStmt(Body); 13920b57cec5SDimitry Andric 13930b57cec5SDimitry Andric // If the end of the finally is reachable, check whether this was 13940b57cec5SDimitry Andric // for EH. If so, rethrow. 13950b57cec5SDimitry Andric if (CGF.HaveInsertPoint()) { 13960b57cec5SDimitry Andric llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow"); 13970b57cec5SDimitry Andric llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont"); 13980b57cec5SDimitry Andric 13990b57cec5SDimitry Andric llvm::Value *ShouldRethrow = 14000b57cec5SDimitry Andric CGF.Builder.CreateFlagLoad(ForEHVar, "finally.shouldthrow"); 14010b57cec5SDimitry Andric CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); 14020b57cec5SDimitry Andric 14030b57cec5SDimitry Andric CGF.EmitBlock(RethrowBB); 14040b57cec5SDimitry Andric if (SavedExnVar) { 14050b57cec5SDimitry Andric CGF.EmitRuntimeCallOrInvoke(RethrowFn, 1406fe6060f1SDimitry Andric CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar, 1407fe6060f1SDimitry Andric CGF.getPointerAlign())); 14080b57cec5SDimitry Andric } else { 14090b57cec5SDimitry Andric CGF.EmitRuntimeCallOrInvoke(RethrowFn); 14100b57cec5SDimitry Andric } 14110b57cec5SDimitry Andric CGF.Builder.CreateUnreachable(); 14120b57cec5SDimitry Andric 14130b57cec5SDimitry Andric CGF.EmitBlock(ContBB); 14140b57cec5SDimitry Andric 14150b57cec5SDimitry Andric // Restore the cleanup destination. 14160b57cec5SDimitry Andric CGF.Builder.CreateStore(SavedCleanupDest, 14170b57cec5SDimitry Andric CGF.getNormalCleanupDestSlot()); 14180b57cec5SDimitry Andric } 14190b57cec5SDimitry Andric 14200b57cec5SDimitry Andric // Leave the end-catch cleanup. As an optimization, pretend that 14210b57cec5SDimitry Andric // the fallthrough path was inaccessible; we've dynamically proven 14220b57cec5SDimitry Andric // that we're not in the EH case along that path. 14230b57cec5SDimitry Andric if (EndCatchFn) { 14240b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); 14250b57cec5SDimitry Andric CGF.PopCleanupBlock(); 14260b57cec5SDimitry Andric CGF.Builder.restoreIP(SavedIP); 14270b57cec5SDimitry Andric } 14280b57cec5SDimitry Andric 14290b57cec5SDimitry Andric // Now make sure we actually have an insertion point or the 14300b57cec5SDimitry Andric // cleanup gods will hate us. 14310b57cec5SDimitry Andric CGF.EnsureInsertPoint(); 14320b57cec5SDimitry Andric } 14330b57cec5SDimitry Andric }; 14340b57cec5SDimitry Andric } // end anonymous namespace 14350b57cec5SDimitry Andric 14360b57cec5SDimitry Andric /// Enters a finally block for an implementation using zero-cost 14370b57cec5SDimitry Andric /// exceptions. This is mostly general, but hard-codes some 14380b57cec5SDimitry Andric /// language/ABI-specific behavior in the catch-all sections. 14390b57cec5SDimitry Andric void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF, const Stmt *body, 14400b57cec5SDimitry Andric llvm::FunctionCallee beginCatchFn, 14410b57cec5SDimitry Andric llvm::FunctionCallee endCatchFn, 14420b57cec5SDimitry Andric llvm::FunctionCallee rethrowFn) { 14430b57cec5SDimitry Andric assert((!!beginCatchFn) == (!!endCatchFn) && 14440b57cec5SDimitry Andric "begin/end catch functions not paired"); 14450b57cec5SDimitry Andric assert(rethrowFn && "rethrow function is required"); 14460b57cec5SDimitry Andric 14470b57cec5SDimitry Andric BeginCatchFn = beginCatchFn; 14480b57cec5SDimitry Andric 14490b57cec5SDimitry Andric // The rethrow function has one of the following two types: 14500b57cec5SDimitry Andric // void (*)() 14510b57cec5SDimitry Andric // void (*)(void*) 14520b57cec5SDimitry Andric // In the latter case we need to pass it the exception object. 14530b57cec5SDimitry Andric // But we can't use the exception slot because the @finally might 14540b57cec5SDimitry Andric // have a landing pad (which would overwrite the exception slot). 14550b57cec5SDimitry Andric llvm::FunctionType *rethrowFnTy = rethrowFn.getFunctionType(); 14560b57cec5SDimitry Andric SavedExnVar = nullptr; 14570b57cec5SDimitry Andric if (rethrowFnTy->getNumParams()) 14580b57cec5SDimitry Andric SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn"); 14590b57cec5SDimitry Andric 14600b57cec5SDimitry Andric // A finally block is a statement which must be executed on any edge 14610b57cec5SDimitry Andric // out of a given scope. Unlike a cleanup, the finally block may 14620b57cec5SDimitry Andric // contain arbitrary control flow leading out of itself. In 14630b57cec5SDimitry Andric // addition, finally blocks should always be executed, even if there 14640b57cec5SDimitry Andric // are no catch handlers higher on the stack. Therefore, we 14650b57cec5SDimitry Andric // surround the protected scope with a combination of a normal 14660b57cec5SDimitry Andric // cleanup (to catch attempts to break out of the block via normal 14670b57cec5SDimitry Andric // control flow) and an EH catch-all (semantically "outside" any try 14680b57cec5SDimitry Andric // statement to which the finally block might have been attached). 14690b57cec5SDimitry Andric // The finally block itself is generated in the context of a cleanup 14700b57cec5SDimitry Andric // which conditionally leaves the catch-all. 14710b57cec5SDimitry Andric 14720b57cec5SDimitry Andric // Jump destination for performing the finally block on an exception 14730b57cec5SDimitry Andric // edge. We'll never actually reach this block, so unreachable is 14740b57cec5SDimitry Andric // fine. 14750b57cec5SDimitry Andric RethrowDest = CGF.getJumpDestInCurrentScope(CGF.getUnreachableBlock()); 14760b57cec5SDimitry Andric 14770b57cec5SDimitry Andric // Whether the finally block is being executed for EH purposes. 14780b57cec5SDimitry Andric ForEHVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "finally.for-eh"); 14790b57cec5SDimitry Andric CGF.Builder.CreateFlagStore(false, ForEHVar); 14800b57cec5SDimitry Andric 14810b57cec5SDimitry Andric // Enter a normal cleanup which will perform the @finally block. 14820b57cec5SDimitry Andric CGF.EHStack.pushCleanup<PerformFinally>(NormalCleanup, body, 14830b57cec5SDimitry Andric ForEHVar, endCatchFn, 14840b57cec5SDimitry Andric rethrowFn, SavedExnVar); 14850b57cec5SDimitry Andric 14860b57cec5SDimitry Andric // Enter a catch-all scope. 14870b57cec5SDimitry Andric llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall"); 14880b57cec5SDimitry Andric EHCatchScope *catchScope = CGF.EHStack.pushCatch(1); 14890b57cec5SDimitry Andric catchScope->setCatchAllHandler(0, catchBB); 14900b57cec5SDimitry Andric } 14910b57cec5SDimitry Andric 14920b57cec5SDimitry Andric void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) { 14930b57cec5SDimitry Andric // Leave the finally catch-all. 14940b57cec5SDimitry Andric EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin()); 14950b57cec5SDimitry Andric llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block; 14960b57cec5SDimitry Andric 14970b57cec5SDimitry Andric CGF.popCatchScope(); 14980b57cec5SDimitry Andric 14990b57cec5SDimitry Andric // If there are any references to the catch-all block, emit it. 15000b57cec5SDimitry Andric if (catchBB->use_empty()) { 15010b57cec5SDimitry Andric delete catchBB; 15020b57cec5SDimitry Andric } else { 15030b57cec5SDimitry Andric CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP(); 15040b57cec5SDimitry Andric CGF.EmitBlock(catchBB); 15050b57cec5SDimitry Andric 15060b57cec5SDimitry Andric llvm::Value *exn = nullptr; 15070b57cec5SDimitry Andric 15080b57cec5SDimitry Andric // If there's a begin-catch function, call it. 15090b57cec5SDimitry Andric if (BeginCatchFn) { 15100b57cec5SDimitry Andric exn = CGF.getExceptionFromSlot(); 15110b57cec5SDimitry Andric CGF.EmitNounwindRuntimeCall(BeginCatchFn, exn); 15120b57cec5SDimitry Andric } 15130b57cec5SDimitry Andric 15140b57cec5SDimitry Andric // If we need to remember the exception pointer to rethrow later, do so. 15150b57cec5SDimitry Andric if (SavedExnVar) { 15160b57cec5SDimitry Andric if (!exn) exn = CGF.getExceptionFromSlot(); 15170b57cec5SDimitry Andric CGF.Builder.CreateAlignedStore(exn, SavedExnVar, CGF.getPointerAlign()); 15180b57cec5SDimitry Andric } 15190b57cec5SDimitry Andric 15200b57cec5SDimitry Andric // Tell the cleanups in the finally block that we're do this for EH. 15210b57cec5SDimitry Andric CGF.Builder.CreateFlagStore(true, ForEHVar); 15220b57cec5SDimitry Andric 15230b57cec5SDimitry Andric // Thread a jump through the finally cleanup. 15240b57cec5SDimitry Andric CGF.EmitBranchThroughCleanup(RethrowDest); 15250b57cec5SDimitry Andric 15260b57cec5SDimitry Andric CGF.Builder.restoreIP(savedIP); 15270b57cec5SDimitry Andric } 15280b57cec5SDimitry Andric 15290b57cec5SDimitry Andric // Finally, leave the @finally cleanup. 15300b57cec5SDimitry Andric CGF.PopCleanupBlock(); 15310b57cec5SDimitry Andric } 15320b57cec5SDimitry Andric 15330b57cec5SDimitry Andric llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { 15340b57cec5SDimitry Andric if (TerminateLandingPad) 15350b57cec5SDimitry Andric return TerminateLandingPad; 15360b57cec5SDimitry Andric 15370b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); 15380b57cec5SDimitry Andric 15390b57cec5SDimitry Andric // This will get inserted at the end of the function. 15400b57cec5SDimitry Andric TerminateLandingPad = createBasicBlock("terminate.lpad"); 15410b57cec5SDimitry Andric Builder.SetInsertPoint(TerminateLandingPad); 15420b57cec5SDimitry Andric 15430b57cec5SDimitry Andric // Tell the backend that this is a landing pad. 15440b57cec5SDimitry Andric const EHPersonality &Personality = EHPersonality::get(*this); 15450b57cec5SDimitry Andric 15460b57cec5SDimitry Andric if (!CurFn->hasPersonalityFn()) 15470b57cec5SDimitry Andric CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality)); 15480b57cec5SDimitry Andric 15490b57cec5SDimitry Andric llvm::LandingPadInst *LPadInst = 15500b57cec5SDimitry Andric Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty), 0); 15510b57cec5SDimitry Andric LPadInst->addClause(getCatchAllValue(*this)); 15520b57cec5SDimitry Andric 15530b57cec5SDimitry Andric llvm::Value *Exn = nullptr; 15540b57cec5SDimitry Andric if (getLangOpts().CPlusPlus) 15550b57cec5SDimitry Andric Exn = Builder.CreateExtractValue(LPadInst, 0); 15560b57cec5SDimitry Andric llvm::CallInst *terminateCall = 15570b57cec5SDimitry Andric CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); 15580b57cec5SDimitry Andric terminateCall->setDoesNotReturn(); 15590b57cec5SDimitry Andric Builder.CreateUnreachable(); 15600b57cec5SDimitry Andric 15610b57cec5SDimitry Andric // Restore the saved insertion state. 15620b57cec5SDimitry Andric Builder.restoreIP(SavedIP); 15630b57cec5SDimitry Andric 15640b57cec5SDimitry Andric return TerminateLandingPad; 15650b57cec5SDimitry Andric } 15660b57cec5SDimitry Andric 15670b57cec5SDimitry Andric llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { 15680b57cec5SDimitry Andric if (TerminateHandler) 15690b57cec5SDimitry Andric return TerminateHandler; 15700b57cec5SDimitry Andric 15710b57cec5SDimitry Andric // Set up the terminate handler. This block is inserted at the very 15720b57cec5SDimitry Andric // end of the function by FinishFunction. 15730b57cec5SDimitry Andric TerminateHandler = createBasicBlock("terminate.handler"); 15740b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); 15750b57cec5SDimitry Andric Builder.SetInsertPoint(TerminateHandler); 15760b57cec5SDimitry Andric 15770b57cec5SDimitry Andric llvm::Value *Exn = nullptr; 15780b57cec5SDimitry Andric if (getLangOpts().CPlusPlus) 15790b57cec5SDimitry Andric Exn = getExceptionFromSlot(); 15800b57cec5SDimitry Andric llvm::CallInst *terminateCall = 15810b57cec5SDimitry Andric CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); 15820b57cec5SDimitry Andric terminateCall->setDoesNotReturn(); 15830b57cec5SDimitry Andric Builder.CreateUnreachable(); 15840b57cec5SDimitry Andric 15850b57cec5SDimitry Andric // Restore the saved insertion state. 15860b57cec5SDimitry Andric Builder.restoreIP(SavedIP); 15870b57cec5SDimitry Andric 15880b57cec5SDimitry Andric return TerminateHandler; 15890b57cec5SDimitry Andric } 15900b57cec5SDimitry Andric 15910b57cec5SDimitry Andric llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() { 15920b57cec5SDimitry Andric assert(EHPersonality::get(*this).usesFuncletPads() && 15930b57cec5SDimitry Andric "use getTerminateLandingPad for non-funclet EH"); 15940b57cec5SDimitry Andric 15950b57cec5SDimitry Andric llvm::BasicBlock *&TerminateFunclet = TerminateFunclets[CurrentFuncletPad]; 15960b57cec5SDimitry Andric if (TerminateFunclet) 15970b57cec5SDimitry Andric return TerminateFunclet; 15980b57cec5SDimitry Andric 15990b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); 16000b57cec5SDimitry Andric 16010b57cec5SDimitry Andric // Set up the terminate handler. This block is inserted at the very 16020b57cec5SDimitry Andric // end of the function by FinishFunction. 16030b57cec5SDimitry Andric TerminateFunclet = createBasicBlock("terminate.handler"); 16040b57cec5SDimitry Andric Builder.SetInsertPoint(TerminateFunclet); 16050b57cec5SDimitry Andric 16060b57cec5SDimitry Andric // Create the cleanuppad using the current parent pad as its token. Use 'none' 16070b57cec5SDimitry Andric // if this is a top-level terminate scope, which is the common case. 1608bdd1243dSDimitry Andric SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad); 16090b57cec5SDimitry Andric llvm::Value *ParentPad = CurrentFuncletPad; 16100b57cec5SDimitry Andric if (!ParentPad) 16110b57cec5SDimitry Andric ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext()); 16120b57cec5SDimitry Andric CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad); 16130b57cec5SDimitry Andric 16140b57cec5SDimitry Andric // Emit the __std_terminate call. 16150b57cec5SDimitry Andric llvm::CallInst *terminateCall = 1616fe6060f1SDimitry Andric CGM.getCXXABI().emitTerminateForUnexpectedException(*this, nullptr); 16170b57cec5SDimitry Andric terminateCall->setDoesNotReturn(); 16180b57cec5SDimitry Andric Builder.CreateUnreachable(); 16190b57cec5SDimitry Andric 16200b57cec5SDimitry Andric // Restore the saved insertion state. 16210b57cec5SDimitry Andric Builder.restoreIP(SavedIP); 16220b57cec5SDimitry Andric 16230b57cec5SDimitry Andric return TerminateFunclet; 16240b57cec5SDimitry Andric } 16250b57cec5SDimitry Andric 16260b57cec5SDimitry Andric llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { 16270b57cec5SDimitry Andric if (EHResumeBlock) return EHResumeBlock; 16280b57cec5SDimitry Andric 16290b57cec5SDimitry Andric CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); 16300b57cec5SDimitry Andric 16310b57cec5SDimitry Andric // We emit a jump to a notional label at the outermost unwind state. 16320b57cec5SDimitry Andric EHResumeBlock = createBasicBlock("eh.resume"); 16330b57cec5SDimitry Andric Builder.SetInsertPoint(EHResumeBlock); 16340b57cec5SDimitry Andric 16350b57cec5SDimitry Andric const EHPersonality &Personality = EHPersonality::get(*this); 16360b57cec5SDimitry Andric 16370b57cec5SDimitry Andric // This can always be a call because we necessarily didn't find 16380b57cec5SDimitry Andric // anything on the EH stack which needs our help. 16390b57cec5SDimitry Andric const char *RethrowName = Personality.CatchallRethrowFn; 16400b57cec5SDimitry Andric if (RethrowName != nullptr && !isCleanup) { 16410b57cec5SDimitry Andric EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName), 16420b57cec5SDimitry Andric getExceptionFromSlot())->setDoesNotReturn(); 16430b57cec5SDimitry Andric Builder.CreateUnreachable(); 16440b57cec5SDimitry Andric Builder.restoreIP(SavedIP); 16450b57cec5SDimitry Andric return EHResumeBlock; 16460b57cec5SDimitry Andric } 16470b57cec5SDimitry Andric 16480b57cec5SDimitry Andric // Recreate the landingpad's return value for the 'resume' instruction. 16490b57cec5SDimitry Andric llvm::Value *Exn = getExceptionFromSlot(); 16500b57cec5SDimitry Andric llvm::Value *Sel = getSelectorFromSlot(); 16510b57cec5SDimitry Andric 16520b57cec5SDimitry Andric llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType()); 1653bdd1243dSDimitry Andric llvm::Value *LPadVal = llvm::PoisonValue::get(LPadType); 16540b57cec5SDimitry Andric LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val"); 16550b57cec5SDimitry Andric LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val"); 16560b57cec5SDimitry Andric 16570b57cec5SDimitry Andric Builder.CreateResume(LPadVal); 16580b57cec5SDimitry Andric Builder.restoreIP(SavedIP); 16590b57cec5SDimitry Andric return EHResumeBlock; 16600b57cec5SDimitry Andric } 16610b57cec5SDimitry Andric 16620b57cec5SDimitry Andric void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { 16630b57cec5SDimitry Andric EnterSEHTryStmt(S); 16640b57cec5SDimitry Andric { 16650b57cec5SDimitry Andric JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); 16660b57cec5SDimitry Andric 16670b57cec5SDimitry Andric SEHTryEpilogueStack.push_back(&TryExit); 1668fe6060f1SDimitry Andric 1669fe6060f1SDimitry Andric llvm::BasicBlock *TryBB = nullptr; 1670fe6060f1SDimitry Andric // IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa 1671fe6060f1SDimitry Andric if (getLangOpts().EHAsynch) { 1672fe6060f1SDimitry Andric EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM)); 1673fe6060f1SDimitry Andric if (SEHTryEpilogueStack.size() == 1) // outermost only 1674fe6060f1SDimitry Andric TryBB = Builder.GetInsertBlock(); 1675fe6060f1SDimitry Andric } 1676fe6060f1SDimitry Andric 16770b57cec5SDimitry Andric EmitStmt(S.getTryBlock()); 1678fe6060f1SDimitry Andric 1679fe6060f1SDimitry Andric // Volatilize all blocks in Try, till current insert point 1680fe6060f1SDimitry Andric if (TryBB) { 1681fe6060f1SDimitry Andric llvm::SmallPtrSet<llvm::BasicBlock *, 10> Visited; 1682fe6060f1SDimitry Andric VolatilizeTryBlocks(TryBB, Visited); 1683fe6060f1SDimitry Andric } 1684fe6060f1SDimitry Andric 16850b57cec5SDimitry Andric SEHTryEpilogueStack.pop_back(); 16860b57cec5SDimitry Andric 16870b57cec5SDimitry Andric if (!TryExit.getBlock()->use_empty()) 16880b57cec5SDimitry Andric EmitBlock(TryExit.getBlock(), /*IsFinished=*/true); 16890b57cec5SDimitry Andric else 16900b57cec5SDimitry Andric delete TryExit.getBlock(); 16910b57cec5SDimitry Andric } 16920b57cec5SDimitry Andric ExitSEHTryStmt(S); 16930b57cec5SDimitry Andric } 16940b57cec5SDimitry Andric 1695fe6060f1SDimitry Andric // Recursively walk through blocks in a _try 1696fe6060f1SDimitry Andric // and make all memory instructions volatile 1697fe6060f1SDimitry Andric void CodeGenFunction::VolatilizeTryBlocks( 1698fe6060f1SDimitry Andric llvm::BasicBlock *BB, llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V) { 1699fe6060f1SDimitry Andric if (BB == SEHTryEpilogueStack.back()->getBlock() /* end of Try */ || 1700fe6060f1SDimitry Andric !V.insert(BB).second /* already visited */ || 1701fe6060f1SDimitry Andric !BB->getParent() /* not emitted */ || BB->empty()) 1702fe6060f1SDimitry Andric return; 1703fe6060f1SDimitry Andric 1704fe6060f1SDimitry Andric if (!BB->isEHPad()) { 1705fe6060f1SDimitry Andric for (llvm::BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; 1706fe6060f1SDimitry Andric ++J) { 1707fe6060f1SDimitry Andric if (auto LI = dyn_cast<llvm::LoadInst>(J)) { 1708fe6060f1SDimitry Andric LI->setVolatile(true); 1709fe6060f1SDimitry Andric } else if (auto SI = dyn_cast<llvm::StoreInst>(J)) { 1710fe6060f1SDimitry Andric SI->setVolatile(true); 1711fe6060f1SDimitry Andric } else if (auto* MCI = dyn_cast<llvm::MemIntrinsic>(J)) { 1712fe6060f1SDimitry Andric MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1)); 1713fe6060f1SDimitry Andric } 1714fe6060f1SDimitry Andric } 1715fe6060f1SDimitry Andric } 1716fe6060f1SDimitry Andric const llvm::Instruction *TI = BB->getTerminator(); 1717fe6060f1SDimitry Andric if (TI) { 1718fe6060f1SDimitry Andric unsigned N = TI->getNumSuccessors(); 1719fe6060f1SDimitry Andric for (unsigned I = 0; I < N; I++) 1720fe6060f1SDimitry Andric VolatilizeTryBlocks(TI->getSuccessor(I), V); 1721fe6060f1SDimitry Andric } 1722fe6060f1SDimitry Andric } 1723fe6060f1SDimitry Andric 17240b57cec5SDimitry Andric namespace { 17250b57cec5SDimitry Andric struct PerformSEHFinally final : EHScopeStack::Cleanup { 17260b57cec5SDimitry Andric llvm::Function *OutlinedFinally; 17270b57cec5SDimitry Andric PerformSEHFinally(llvm::Function *OutlinedFinally) 17280b57cec5SDimitry Andric : OutlinedFinally(OutlinedFinally) {} 17290b57cec5SDimitry Andric 17300b57cec5SDimitry Andric void Emit(CodeGenFunction &CGF, Flags F) override { 17310b57cec5SDimitry Andric ASTContext &Context = CGF.getContext(); 17320b57cec5SDimitry Andric CodeGenModule &CGM = CGF.CGM; 17330b57cec5SDimitry Andric 17340b57cec5SDimitry Andric CallArgList Args; 17350b57cec5SDimitry Andric 17360b57cec5SDimitry Andric // Compute the two argument values. 17370b57cec5SDimitry Andric QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy}; 17380b57cec5SDimitry Andric llvm::Value *FP = nullptr; 17390b57cec5SDimitry Andric // If CFG.IsOutlinedSEHHelper is true, then we are within a finally block. 17400b57cec5SDimitry Andric if (CGF.IsOutlinedSEHHelper) { 17410b57cec5SDimitry Andric FP = &CGF.CurFn->arg_begin()[1]; 17420b57cec5SDimitry Andric } else { 17430b57cec5SDimitry Andric llvm::Function *LocalAddrFn = 17440b57cec5SDimitry Andric CGM.getIntrinsic(llvm::Intrinsic::localaddress); 17450b57cec5SDimitry Andric FP = CGF.Builder.CreateCall(LocalAddrFn); 17460b57cec5SDimitry Andric } 17470b57cec5SDimitry Andric 17480b57cec5SDimitry Andric llvm::Value *IsForEH = 17490b57cec5SDimitry Andric llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup()); 17505ffd83dbSDimitry Andric 17515ffd83dbSDimitry Andric // Except _leave and fall-through at the end, all other exits in a _try 17525ffd83dbSDimitry Andric // (return/goto/continue/break) are considered as abnormal terminations 17535ffd83dbSDimitry Andric // since _leave/fall-through is always Indexed 0, 17545ffd83dbSDimitry Andric // just use NormalCleanupDestSlot (>= 1 for goto/return/..), 17555ffd83dbSDimitry Andric // as 1st Arg to indicate abnormal termination 17565ffd83dbSDimitry Andric if (!F.isForEHCleanup() && F.hasExitSwitch()) { 17575ffd83dbSDimitry Andric Address Addr = CGF.getNormalCleanupDestSlot(); 17585ffd83dbSDimitry Andric llvm::Value *Load = CGF.Builder.CreateLoad(Addr, "cleanup.dest"); 17595ffd83dbSDimitry Andric llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int32Ty); 17605ffd83dbSDimitry Andric IsForEH = CGF.Builder.CreateICmpNE(Load, Zero); 17615ffd83dbSDimitry Andric } 17625ffd83dbSDimitry Andric 17630b57cec5SDimitry Andric Args.add(RValue::get(IsForEH), ArgTys[0]); 17640b57cec5SDimitry Andric Args.add(RValue::get(FP), ArgTys[1]); 17650b57cec5SDimitry Andric 17660b57cec5SDimitry Andric // Arrange a two-arg function info and type. 17670b57cec5SDimitry Andric const CGFunctionInfo &FnInfo = 17680b57cec5SDimitry Andric CGM.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, Args); 17690b57cec5SDimitry Andric 17700b57cec5SDimitry Andric auto Callee = CGCallee::forDirect(OutlinedFinally); 17710b57cec5SDimitry Andric CGF.EmitCall(FnInfo, Callee, ReturnValueSlot(), Args); 17720b57cec5SDimitry Andric } 17730b57cec5SDimitry Andric }; 17740b57cec5SDimitry Andric } // end anonymous namespace 17750b57cec5SDimitry Andric 17760b57cec5SDimitry Andric namespace { 17770b57cec5SDimitry Andric /// Find all local variable captures in the statement. 17780b57cec5SDimitry Andric struct CaptureFinder : ConstStmtVisitor<CaptureFinder> { 17790b57cec5SDimitry Andric CodeGenFunction &ParentCGF; 17800b57cec5SDimitry Andric const VarDecl *ParentThis; 17810b57cec5SDimitry Andric llvm::SmallSetVector<const VarDecl *, 4> Captures; 17820b57cec5SDimitry Andric Address SEHCodeSlot = Address::invalid(); 17830b57cec5SDimitry Andric CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis) 17840b57cec5SDimitry Andric : ParentCGF(ParentCGF), ParentThis(ParentThis) {} 17850b57cec5SDimitry Andric 17860b57cec5SDimitry Andric // Return true if we need to do any capturing work. 17870b57cec5SDimitry Andric bool foundCaptures() { 17880b57cec5SDimitry Andric return !Captures.empty() || SEHCodeSlot.isValid(); 17890b57cec5SDimitry Andric } 17900b57cec5SDimitry Andric 17910b57cec5SDimitry Andric void Visit(const Stmt *S) { 17920b57cec5SDimitry Andric // See if this is a capture, then recurse. 17930b57cec5SDimitry Andric ConstStmtVisitor<CaptureFinder>::Visit(S); 17940b57cec5SDimitry Andric for (const Stmt *Child : S->children()) 17950b57cec5SDimitry Andric if (Child) 17960b57cec5SDimitry Andric Visit(Child); 17970b57cec5SDimitry Andric } 17980b57cec5SDimitry Andric 17990b57cec5SDimitry Andric void VisitDeclRefExpr(const DeclRefExpr *E) { 18000b57cec5SDimitry Andric // If this is already a capture, just make sure we capture 'this'. 1801fe6060f1SDimitry Andric if (E->refersToEnclosingVariableOrCapture()) 18020b57cec5SDimitry Andric Captures.insert(ParentThis); 18030b57cec5SDimitry Andric 18040b57cec5SDimitry Andric const auto *D = dyn_cast<VarDecl>(E->getDecl()); 18050b57cec5SDimitry Andric if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage()) 18060b57cec5SDimitry Andric Captures.insert(D); 18070b57cec5SDimitry Andric } 18080b57cec5SDimitry Andric 18090b57cec5SDimitry Andric void VisitCXXThisExpr(const CXXThisExpr *E) { 18100b57cec5SDimitry Andric Captures.insert(ParentThis); 18110b57cec5SDimitry Andric } 18120b57cec5SDimitry Andric 18130b57cec5SDimitry Andric void VisitCallExpr(const CallExpr *E) { 18140b57cec5SDimitry Andric // We only need to add parent frame allocations for these builtins in x86. 18150b57cec5SDimitry Andric if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86) 18160b57cec5SDimitry Andric return; 18170b57cec5SDimitry Andric 18180b57cec5SDimitry Andric unsigned ID = E->getBuiltinCallee(); 18190b57cec5SDimitry Andric switch (ID) { 18200b57cec5SDimitry Andric case Builtin::BI__exception_code: 18210b57cec5SDimitry Andric case Builtin::BI_exception_code: 18220b57cec5SDimitry Andric // This is the simple case where we are the outermost finally. All we 18230b57cec5SDimitry Andric // have to do here is make sure we escape this and recover it in the 18240b57cec5SDimitry Andric // outlined handler. 18250b57cec5SDimitry Andric if (!SEHCodeSlot.isValid()) 18260b57cec5SDimitry Andric SEHCodeSlot = ParentCGF.SEHCodeSlotStack.back(); 18270b57cec5SDimitry Andric break; 18280b57cec5SDimitry Andric } 18290b57cec5SDimitry Andric } 18300b57cec5SDimitry Andric }; 18310b57cec5SDimitry Andric } // end anonymous namespace 18320b57cec5SDimitry Andric 18330b57cec5SDimitry Andric Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, 18340b57cec5SDimitry Andric Address ParentVar, 18350b57cec5SDimitry Andric llvm::Value *ParentFP) { 18360b57cec5SDimitry Andric llvm::CallInst *RecoverCall = nullptr; 18370b57cec5SDimitry Andric CGBuilderTy Builder(*this, AllocaInsertPt); 1838*0fca6ea1SDimitry Andric if (auto *ParentAlloca = 1839*0fca6ea1SDimitry Andric dyn_cast_or_null<llvm::AllocaInst>(ParentVar.getBasePointer())) { 18400b57cec5SDimitry Andric // Mark the variable escaped if nobody else referenced it and compute the 18410b57cec5SDimitry Andric // localescape index. 18420b57cec5SDimitry Andric auto InsertPair = ParentCGF.EscapedLocals.insert( 18430b57cec5SDimitry Andric std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); 18440b57cec5SDimitry Andric int FrameEscapeIdx = InsertPair.first->second; 18455f757f3fSDimitry Andric // call ptr @llvm.localrecover(ptr @parentFn, ptr %fp, i32 N) 18460b57cec5SDimitry Andric llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( 18470b57cec5SDimitry Andric &CGM.getModule(), llvm::Intrinsic::localrecover); 18480b57cec5SDimitry Andric RecoverCall = Builder.CreateCall( 18495f757f3fSDimitry Andric FrameRecoverFn, {ParentCGF.CurFn, ParentFP, 18500b57cec5SDimitry Andric llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); 18510b57cec5SDimitry Andric 18520b57cec5SDimitry Andric } else { 18530b57cec5SDimitry Andric // If the parent didn't have an alloca, we're doing some nested outlining. 18540b57cec5SDimitry Andric // Just clone the existing localrecover call, but tweak the FP argument to 18550b57cec5SDimitry Andric // use our FP value. All other arguments are constants. 1856*0fca6ea1SDimitry Andric auto *ParentRecover = cast<llvm::IntrinsicInst>( 1857*0fca6ea1SDimitry Andric ParentVar.emitRawPointer(*this)->stripPointerCasts()); 18580b57cec5SDimitry Andric assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover && 18590b57cec5SDimitry Andric "expected alloca or localrecover in parent LocalDeclMap"); 18600b57cec5SDimitry Andric RecoverCall = cast<llvm::CallInst>(ParentRecover->clone()); 18610b57cec5SDimitry Andric RecoverCall->setArgOperand(1, ParentFP); 18620b57cec5SDimitry Andric RecoverCall->insertBefore(AllocaInsertPt); 18630b57cec5SDimitry Andric } 18640b57cec5SDimitry Andric 18650b57cec5SDimitry Andric // Bitcast the variable, rename it, and insert it in the local decl map. 18660b57cec5SDimitry Andric llvm::Value *ChildVar = 18670b57cec5SDimitry Andric Builder.CreateBitCast(RecoverCall, ParentVar.getType()); 18680b57cec5SDimitry Andric ChildVar->setName(ParentVar.getName()); 186906c3fb27SDimitry Andric return ParentVar.withPointer(ChildVar, KnownNonNull); 18700b57cec5SDimitry Andric } 18710b57cec5SDimitry Andric 18720b57cec5SDimitry Andric void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, 18730b57cec5SDimitry Andric const Stmt *OutlinedStmt, 18740b57cec5SDimitry Andric bool IsFilter) { 18750b57cec5SDimitry Andric // Find all captures in the Stmt. 18760b57cec5SDimitry Andric CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl); 18770b57cec5SDimitry Andric Finder.Visit(OutlinedStmt); 18780b57cec5SDimitry Andric 18790b57cec5SDimitry Andric // We can exit early on x86_64 when there are no captures. We just have to 18800b57cec5SDimitry Andric // save the exception code in filters so that __exception_code() works. 18810b57cec5SDimitry Andric if (!Finder.foundCaptures() && 18820b57cec5SDimitry Andric CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { 18830b57cec5SDimitry Andric if (IsFilter) 18840b57cec5SDimitry Andric EmitSEHExceptionCodeSave(ParentCGF, nullptr, nullptr); 18850b57cec5SDimitry Andric return; 18860b57cec5SDimitry Andric } 18870b57cec5SDimitry Andric 18880b57cec5SDimitry Andric llvm::Value *EntryFP = nullptr; 18890b57cec5SDimitry Andric CGBuilderTy Builder(CGM, AllocaInsertPt); 18900b57cec5SDimitry Andric if (IsFilter && CGM.getTarget().getTriple().getArch() == llvm::Triple::x86) { 18910b57cec5SDimitry Andric // 32-bit SEH filters need to be careful about FP recovery. The end of the 18920b57cec5SDimitry Andric // EH registration is passed in as the EBP physical register. We can 18930b57cec5SDimitry Andric // recover that with llvm.frameaddress(1). 18940b57cec5SDimitry Andric EntryFP = Builder.CreateCall( 1895a7dea167SDimitry Andric CGM.getIntrinsic(llvm::Intrinsic::frameaddress, AllocaInt8PtrTy), 1896a7dea167SDimitry Andric {Builder.getInt32(1)}); 18970b57cec5SDimitry Andric } else { 18980b57cec5SDimitry Andric // Otherwise, for x64 and 32-bit finally functions, the parent FP is the 18990b57cec5SDimitry Andric // second parameter. 19000b57cec5SDimitry Andric auto AI = CurFn->arg_begin(); 19010b57cec5SDimitry Andric ++AI; 19020b57cec5SDimitry Andric EntryFP = &*AI; 19030b57cec5SDimitry Andric } 19040b57cec5SDimitry Andric 19050b57cec5SDimitry Andric llvm::Value *ParentFP = EntryFP; 19060b57cec5SDimitry Andric if (IsFilter) { 19070b57cec5SDimitry Andric // Given whatever FP the runtime provided us in EntryFP, recover the true 19080b57cec5SDimitry Andric // frame pointer of the parent function. We only need to do this in filters, 19090b57cec5SDimitry Andric // since finally funclets recover the parent FP for us. 19100b57cec5SDimitry Andric llvm::Function *RecoverFPIntrin = 19110b57cec5SDimitry Andric CGM.getIntrinsic(llvm::Intrinsic::eh_recoverfp); 19125f757f3fSDimitry Andric ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentCGF.CurFn, EntryFP}); 19135ffd83dbSDimitry Andric 19145ffd83dbSDimitry Andric // if the parent is a _finally, the passed-in ParentFP is the FP 19155ffd83dbSDimitry Andric // of parent _finally, not Establisher's FP (FP of outermost function). 19165ffd83dbSDimitry Andric // Establkisher FP is 2nd paramenter passed into parent _finally. 19175ffd83dbSDimitry Andric // Fortunately, it's always saved in parent's frame. The following 19185ffd83dbSDimitry Andric // code retrieves it, and escapes it so that spill instruction won't be 19195ffd83dbSDimitry Andric // optimized away. 19205ffd83dbSDimitry Andric if (ParentCGF.ParentCGF != nullptr) { 19215ffd83dbSDimitry Andric // Locate and escape Parent's frame_pointer.addr alloca 19225ffd83dbSDimitry Andric // Depending on target, should be 1st/2nd one in LocalDeclMap. 19235ffd83dbSDimitry Andric // Let's just scan for ImplicitParamDecl with VoidPtrTy. 19245ffd83dbSDimitry Andric llvm::AllocaInst *FramePtrAddrAlloca = nullptr; 19255ffd83dbSDimitry Andric for (auto &I : ParentCGF.LocalDeclMap) { 19265ffd83dbSDimitry Andric const VarDecl *D = cast<VarDecl>(I.first); 19275ffd83dbSDimitry Andric if (isa<ImplicitParamDecl>(D) && 19285ffd83dbSDimitry Andric D->getType() == getContext().VoidPtrTy) { 19295f757f3fSDimitry Andric assert(D->getName().starts_with("frame_pointer")); 1930*0fca6ea1SDimitry Andric FramePtrAddrAlloca = 1931*0fca6ea1SDimitry Andric cast<llvm::AllocaInst>(I.second.getBasePointer()); 19325ffd83dbSDimitry Andric break; 19335ffd83dbSDimitry Andric } 19345ffd83dbSDimitry Andric } 19355ffd83dbSDimitry Andric assert(FramePtrAddrAlloca); 19365ffd83dbSDimitry Andric auto InsertPair = ParentCGF.EscapedLocals.insert( 19375ffd83dbSDimitry Andric std::make_pair(FramePtrAddrAlloca, ParentCGF.EscapedLocals.size())); 19385ffd83dbSDimitry Andric int FrameEscapeIdx = InsertPair.first->second; 19395ffd83dbSDimitry Andric 19405ffd83dbSDimitry Andric // an example of a filter's prolog:: 19415f757f3fSDimitry Andric // %0 = call ptr @llvm.eh.recoverfp(@"?fin$0@0@main@@",..) 19425f757f3fSDimitry Andric // %1 = call ptr @llvm.localrecover(@"?fin$0@0@main@@",..) 19435f757f3fSDimitry Andric // %2 = load ptr, ptr %1, align 8 19445f757f3fSDimitry Andric // ==> %2 is the frame-pointer of outermost host function 19455ffd83dbSDimitry Andric llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( 19465ffd83dbSDimitry Andric &CGM.getModule(), llvm::Intrinsic::localrecover); 19475ffd83dbSDimitry Andric ParentFP = Builder.CreateCall( 19485f757f3fSDimitry Andric FrameRecoverFn, {ParentCGF.CurFn, ParentFP, 19495ffd83dbSDimitry Andric llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); 195081ad6265SDimitry Andric ParentFP = Builder.CreateLoad( 195181ad6265SDimitry Andric Address(ParentFP, CGM.VoidPtrTy, getPointerAlign())); 19525ffd83dbSDimitry Andric } 19530b57cec5SDimitry Andric } 19540b57cec5SDimitry Andric 19550b57cec5SDimitry Andric // Create llvm.localrecover calls for all captures. 19560b57cec5SDimitry Andric for (const VarDecl *VD : Finder.Captures) { 19570b57cec5SDimitry Andric if (VD->getType()->isVariablyModifiedType()) { 19580b57cec5SDimitry Andric CGM.ErrorUnsupported(VD, "VLA captured by SEH"); 19590b57cec5SDimitry Andric continue; 19600b57cec5SDimitry Andric } 19610b57cec5SDimitry Andric assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) && 19620b57cec5SDimitry Andric "captured non-local variable"); 19630b57cec5SDimitry Andric 1964fe6060f1SDimitry Andric auto L = ParentCGF.LambdaCaptureFields.find(VD); 1965fe6060f1SDimitry Andric if (L != ParentCGF.LambdaCaptureFields.end()) { 1966fe6060f1SDimitry Andric LambdaCaptureFields[VD] = L->second; 1967fe6060f1SDimitry Andric continue; 1968fe6060f1SDimitry Andric } 1969fe6060f1SDimitry Andric 19700b57cec5SDimitry Andric // If this decl hasn't been declared yet, it will be declared in the 19710b57cec5SDimitry Andric // OutlinedStmt. 19720b57cec5SDimitry Andric auto I = ParentCGF.LocalDeclMap.find(VD); 19730b57cec5SDimitry Andric if (I == ParentCGF.LocalDeclMap.end()) 19740b57cec5SDimitry Andric continue; 19750b57cec5SDimitry Andric 19760b57cec5SDimitry Andric Address ParentVar = I->second; 1977fe6060f1SDimitry Andric Address Recovered = 1978fe6060f1SDimitry Andric recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); 1979fe6060f1SDimitry Andric setAddrOfLocalVar(VD, Recovered); 1980fe6060f1SDimitry Andric 1981fe6060f1SDimitry Andric if (isa<ImplicitParamDecl>(VD)) { 1982fe6060f1SDimitry Andric CXXABIThisAlignment = ParentCGF.CXXABIThisAlignment; 1983fe6060f1SDimitry Andric CXXThisAlignment = ParentCGF.CXXThisAlignment; 1984fe6060f1SDimitry Andric CXXABIThisValue = Builder.CreateLoad(Recovered, "this"); 1985fe6060f1SDimitry Andric if (ParentCGF.LambdaThisCaptureField) { 1986fe6060f1SDimitry Andric LambdaThisCaptureField = ParentCGF.LambdaThisCaptureField; 1987fe6060f1SDimitry Andric // We are in a lambda function where "this" is captured so the 1988fe6060f1SDimitry Andric // CXXThisValue need to be loaded from the lambda capture 1989fe6060f1SDimitry Andric LValue ThisFieldLValue = 1990fe6060f1SDimitry Andric EmitLValueForLambdaField(LambdaThisCaptureField); 1991fe6060f1SDimitry Andric if (!LambdaThisCaptureField->getType()->isPointerType()) { 1992*0fca6ea1SDimitry Andric CXXThisValue = ThisFieldLValue.getAddress().emitRawPointer(*this); 1993fe6060f1SDimitry Andric } else { 1994fe6060f1SDimitry Andric CXXThisValue = EmitLoadOfLValue(ThisFieldLValue, SourceLocation()) 1995fe6060f1SDimitry Andric .getScalarVal(); 1996fe6060f1SDimitry Andric } 1997fe6060f1SDimitry Andric } else { 1998fe6060f1SDimitry Andric CXXThisValue = CXXABIThisValue; 1999fe6060f1SDimitry Andric } 2000fe6060f1SDimitry Andric } 20010b57cec5SDimitry Andric } 20020b57cec5SDimitry Andric 20030b57cec5SDimitry Andric if (Finder.SEHCodeSlot.isValid()) { 20040b57cec5SDimitry Andric SEHCodeSlotStack.push_back( 20050b57cec5SDimitry Andric recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP)); 20060b57cec5SDimitry Andric } 20070b57cec5SDimitry Andric 20080b57cec5SDimitry Andric if (IsFilter) 20090b57cec5SDimitry Andric EmitSEHExceptionCodeSave(ParentCGF, ParentFP, EntryFP); 20100b57cec5SDimitry Andric } 20110b57cec5SDimitry Andric 20120b57cec5SDimitry Andric /// Arrange a function prototype that can be called by Windows exception 20130b57cec5SDimitry Andric /// handling personalities. On Win64, the prototype looks like: 20140b57cec5SDimitry Andric /// RetTy func(void *EHPtrs, void *ParentFP); 20150b57cec5SDimitry Andric void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, 20160b57cec5SDimitry Andric bool IsFilter, 20170b57cec5SDimitry Andric const Stmt *OutlinedStmt) { 20180b57cec5SDimitry Andric SourceLocation StartLoc = OutlinedStmt->getBeginLoc(); 20190b57cec5SDimitry Andric 20200b57cec5SDimitry Andric // Get the mangled function name. 20210b57cec5SDimitry Andric SmallString<128> Name; 20220b57cec5SDimitry Andric { 20230b57cec5SDimitry Andric llvm::raw_svector_ostream OS(Name); 2024bdd1243dSDimitry Andric GlobalDecl ParentSEHFn = ParentCGF.CurSEHParent; 20250b57cec5SDimitry Andric assert(ParentSEHFn && "No CurSEHParent!"); 20260b57cec5SDimitry Andric MangleContext &Mangler = CGM.getCXXABI().getMangleContext(); 20270b57cec5SDimitry Andric if (IsFilter) 20280b57cec5SDimitry Andric Mangler.mangleSEHFilterExpression(ParentSEHFn, OS); 20290b57cec5SDimitry Andric else 20300b57cec5SDimitry Andric Mangler.mangleSEHFinallyBlock(ParentSEHFn, OS); 20310b57cec5SDimitry Andric } 20320b57cec5SDimitry Andric 20330b57cec5SDimitry Andric FunctionArgList Args; 20340b57cec5SDimitry Andric if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) { 20350b57cec5SDimitry Andric // All SEH finally functions take two parameters. Win64 filters take two 20360b57cec5SDimitry Andric // parameters. Win32 filters take no parameters. 20370b57cec5SDimitry Andric if (IsFilter) { 20380b57cec5SDimitry Andric Args.push_back(ImplicitParamDecl::Create( 20390b57cec5SDimitry Andric getContext(), /*DC=*/nullptr, StartLoc, 20400b57cec5SDimitry Andric &getContext().Idents.get("exception_pointers"), 20415f757f3fSDimitry Andric getContext().VoidPtrTy, ImplicitParamKind::Other)); 20420b57cec5SDimitry Andric } else { 20430b57cec5SDimitry Andric Args.push_back(ImplicitParamDecl::Create( 20440b57cec5SDimitry Andric getContext(), /*DC=*/nullptr, StartLoc, 20450b57cec5SDimitry Andric &getContext().Idents.get("abnormal_termination"), 20465f757f3fSDimitry Andric getContext().UnsignedCharTy, ImplicitParamKind::Other)); 20470b57cec5SDimitry Andric } 20480b57cec5SDimitry Andric Args.push_back(ImplicitParamDecl::Create( 20490b57cec5SDimitry Andric getContext(), /*DC=*/nullptr, StartLoc, 20500b57cec5SDimitry Andric &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy, 20515f757f3fSDimitry Andric ImplicitParamKind::Other)); 20520b57cec5SDimitry Andric } 20530b57cec5SDimitry Andric 20540b57cec5SDimitry Andric QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy; 20550b57cec5SDimitry Andric 20560b57cec5SDimitry Andric const CGFunctionInfo &FnInfo = 20570b57cec5SDimitry Andric CGM.getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args); 20580b57cec5SDimitry Andric 20590b57cec5SDimitry Andric llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo); 20600b57cec5SDimitry Andric llvm::Function *Fn = llvm::Function::Create( 20610b57cec5SDimitry Andric FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule()); 20620b57cec5SDimitry Andric 20630b57cec5SDimitry Andric IsOutlinedSEHHelper = true; 20640b57cec5SDimitry Andric 20650b57cec5SDimitry Andric StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args, 20660b57cec5SDimitry Andric OutlinedStmt->getBeginLoc(), OutlinedStmt->getBeginLoc()); 20670b57cec5SDimitry Andric CurSEHParent = ParentCGF.CurSEHParent; 20680b57cec5SDimitry Andric 20695ffd83dbSDimitry Andric CGM.SetInternalFunctionAttributes(GlobalDecl(), CurFn, FnInfo); 20700b57cec5SDimitry Andric EmitCapturedLocals(ParentCGF, OutlinedStmt, IsFilter); 20710b57cec5SDimitry Andric } 20720b57cec5SDimitry Andric 20730b57cec5SDimitry Andric /// Create a stub filter function that will ultimately hold the code of the 20740b57cec5SDimitry Andric /// filter expression. The EH preparation passes in LLVM will outline the code 20750b57cec5SDimitry Andric /// from the main function body into this stub. 20760b57cec5SDimitry Andric llvm::Function * 20770b57cec5SDimitry Andric CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, 20780b57cec5SDimitry Andric const SEHExceptStmt &Except) { 20790b57cec5SDimitry Andric const Expr *FilterExpr = Except.getFilterExpr(); 20800b57cec5SDimitry Andric startOutlinedSEHHelper(ParentCGF, true, FilterExpr); 20810b57cec5SDimitry Andric 20820b57cec5SDimitry Andric // Emit the original filter expression, convert to i32, and return. 20830b57cec5SDimitry Andric llvm::Value *R = EmitScalarExpr(FilterExpr); 20840b57cec5SDimitry Andric R = Builder.CreateIntCast(R, ConvertType(getContext().LongTy), 20850b57cec5SDimitry Andric FilterExpr->getType()->isSignedIntegerType()); 20860b57cec5SDimitry Andric Builder.CreateStore(R, ReturnValue); 20870b57cec5SDimitry Andric 20880b57cec5SDimitry Andric FinishFunction(FilterExpr->getEndLoc()); 20890b57cec5SDimitry Andric 20900b57cec5SDimitry Andric return CurFn; 20910b57cec5SDimitry Andric } 20920b57cec5SDimitry Andric 20930b57cec5SDimitry Andric llvm::Function * 20940b57cec5SDimitry Andric CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, 20950b57cec5SDimitry Andric const SEHFinallyStmt &Finally) { 20960b57cec5SDimitry Andric const Stmt *FinallyBlock = Finally.getBlock(); 20970b57cec5SDimitry Andric startOutlinedSEHHelper(ParentCGF, false, FinallyBlock); 20980b57cec5SDimitry Andric 20990b57cec5SDimitry Andric // Emit the original filter expression, convert to i32, and return. 21000b57cec5SDimitry Andric EmitStmt(FinallyBlock); 21010b57cec5SDimitry Andric 21020b57cec5SDimitry Andric FinishFunction(FinallyBlock->getEndLoc()); 21030b57cec5SDimitry Andric 21040b57cec5SDimitry Andric return CurFn; 21050b57cec5SDimitry Andric } 21060b57cec5SDimitry Andric 21070b57cec5SDimitry Andric void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, 21080b57cec5SDimitry Andric llvm::Value *ParentFP, 21090b57cec5SDimitry Andric llvm::Value *EntryFP) { 21100b57cec5SDimitry Andric // Get the pointer to the EXCEPTION_POINTERS struct. This is returned by the 21110b57cec5SDimitry Andric // __exception_info intrinsic. 21120b57cec5SDimitry Andric if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { 21130b57cec5SDimitry Andric // On Win64, the info is passed as the first parameter to the filter. 21140b57cec5SDimitry Andric SEHInfo = &*CurFn->arg_begin(); 21150b57cec5SDimitry Andric SEHCodeSlotStack.push_back( 21160b57cec5SDimitry Andric CreateMemTemp(getContext().IntTy, "__exception_code")); 21170b57cec5SDimitry Andric } else { 21180b57cec5SDimitry Andric // On Win32, the EBP on entry to the filter points to the end of an 21190b57cec5SDimitry Andric // exception registration object. It contains 6 32-bit fields, and the info 21200b57cec5SDimitry Andric // pointer is stored in the second field. So, GEP 20 bytes backwards and 21210b57cec5SDimitry Andric // load the pointer. 21220b57cec5SDimitry Andric SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryFP, -20); 21230b57cec5SDimitry Andric SEHInfo = Builder.CreateAlignedLoad(Int8PtrTy, SEHInfo, getPointerAlign()); 21240b57cec5SDimitry Andric SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal( 21250b57cec5SDimitry Andric ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP)); 21260b57cec5SDimitry Andric } 21270b57cec5SDimitry Andric 21280b57cec5SDimitry Andric // Save the exception code in the exception slot to unify exception access in 21290b57cec5SDimitry Andric // the filter function and the landing pad. 21300b57cec5SDimitry Andric // struct EXCEPTION_POINTERS { 21310b57cec5SDimitry Andric // EXCEPTION_RECORD *ExceptionRecord; 21320b57cec5SDimitry Andric // CONTEXT *ContextRecord; 21330b57cec5SDimitry Andric // }; 21340b57cec5SDimitry Andric // int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode; 213506c3fb27SDimitry Andric llvm::Type *RecordTy = llvm::PointerType::getUnqual(getLLVMContext()); 21360b57cec5SDimitry Andric llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy); 213706c3fb27SDimitry Andric llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, SEHInfo, 0); 2138fe6060f1SDimitry Andric Rec = Builder.CreateAlignedLoad(RecordTy, Rec, getPointerAlign()); 2139fe6060f1SDimitry Andric llvm::Value *Code = Builder.CreateAlignedLoad(Int32Ty, Rec, getIntAlign()); 21400b57cec5SDimitry Andric assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); 21410b57cec5SDimitry Andric Builder.CreateStore(Code, SEHCodeSlotStack.back()); 21420b57cec5SDimitry Andric } 21430b57cec5SDimitry Andric 21440b57cec5SDimitry Andric llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() { 21450b57cec5SDimitry Andric // Sema should diagnose calling this builtin outside of a filter context, but 21460b57cec5SDimitry Andric // don't crash if we screw up. 21470b57cec5SDimitry Andric if (!SEHInfo) 21480b57cec5SDimitry Andric return llvm::UndefValue::get(Int8PtrTy); 21490b57cec5SDimitry Andric assert(SEHInfo->getType() == Int8PtrTy); 21500b57cec5SDimitry Andric return SEHInfo; 21510b57cec5SDimitry Andric } 21520b57cec5SDimitry Andric 21530b57cec5SDimitry Andric llvm::Value *CodeGenFunction::EmitSEHExceptionCode() { 21540b57cec5SDimitry Andric assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); 21550b57cec5SDimitry Andric return Builder.CreateLoad(SEHCodeSlotStack.back()); 21560b57cec5SDimitry Andric } 21570b57cec5SDimitry Andric 21580b57cec5SDimitry Andric llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() { 21590b57cec5SDimitry Andric // Abnormal termination is just the first parameter to the outlined finally 21600b57cec5SDimitry Andric // helper. 21610b57cec5SDimitry Andric auto AI = CurFn->arg_begin(); 21620b57cec5SDimitry Andric return Builder.CreateZExt(&*AI, Int32Ty); 21630b57cec5SDimitry Andric } 21640b57cec5SDimitry Andric 21650b57cec5SDimitry Andric void CodeGenFunction::pushSEHCleanup(CleanupKind Kind, 21660b57cec5SDimitry Andric llvm::Function *FinallyFunc) { 21670b57cec5SDimitry Andric EHStack.pushCleanup<PerformSEHFinally>(Kind, FinallyFunc); 21680b57cec5SDimitry Andric } 21690b57cec5SDimitry Andric 21700b57cec5SDimitry Andric void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { 21710b57cec5SDimitry Andric CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true); 21725ffd83dbSDimitry Andric HelperCGF.ParentCGF = this; 21730b57cec5SDimitry Andric if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) { 21740b57cec5SDimitry Andric // Outline the finally block. 21750b57cec5SDimitry Andric llvm::Function *FinallyFunc = 21760b57cec5SDimitry Andric HelperCGF.GenerateSEHFinallyFunction(*this, *Finally); 21770b57cec5SDimitry Andric 21780b57cec5SDimitry Andric // Push a cleanup for __finally blocks. 21790b57cec5SDimitry Andric EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc); 21800b57cec5SDimitry Andric return; 21810b57cec5SDimitry Andric } 21820b57cec5SDimitry Andric 21830b57cec5SDimitry Andric // Otherwise, we must have an __except block. 21840b57cec5SDimitry Andric const SEHExceptStmt *Except = S.getExceptHandler(); 21850b57cec5SDimitry Andric assert(Except); 21860b57cec5SDimitry Andric EHCatchScope *CatchScope = EHStack.pushCatch(1); 21870b57cec5SDimitry Andric SEHCodeSlotStack.push_back( 21880b57cec5SDimitry Andric CreateMemTemp(getContext().IntTy, "__exception_code")); 21890b57cec5SDimitry Andric 21900b57cec5SDimitry Andric // If the filter is known to evaluate to 1, then we can use the clause 21910b57cec5SDimitry Andric // "catch i8* null". We can't do this on x86 because the filter has to save 21920b57cec5SDimitry Andric // the exception code. 21930b57cec5SDimitry Andric llvm::Constant *C = 21940b57cec5SDimitry Andric ConstantEmitter(*this).tryEmitAbstract(Except->getFilterExpr(), 21950b57cec5SDimitry Andric getContext().IntTy); 21960b57cec5SDimitry Andric if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 && C && 21970b57cec5SDimitry Andric C->isOneValue()) { 21980b57cec5SDimitry Andric CatchScope->setCatchAllHandler(0, createBasicBlock("__except")); 21990b57cec5SDimitry Andric return; 22000b57cec5SDimitry Andric } 22010b57cec5SDimitry Andric 22020b57cec5SDimitry Andric // In general, we have to emit an outlined filter function. Use the function 22030b57cec5SDimitry Andric // in place of the RTTI typeinfo global that C++ EH uses. 22040b57cec5SDimitry Andric llvm::Function *FilterFunc = 22050b57cec5SDimitry Andric HelperCGF.GenerateSEHFilterFunction(*this, *Except); 22065f757f3fSDimitry Andric CatchScope->setHandler(0, FilterFunc, createBasicBlock("__except.ret")); 22070b57cec5SDimitry Andric } 22080b57cec5SDimitry Andric 22090b57cec5SDimitry Andric void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { 22100b57cec5SDimitry Andric // Just pop the cleanup if it's a __finally block. 22110b57cec5SDimitry Andric if (S.getFinallyHandler()) { 22120b57cec5SDimitry Andric PopCleanupBlock(); 22130b57cec5SDimitry Andric return; 22140b57cec5SDimitry Andric } 22150b57cec5SDimitry Andric 2216fe6060f1SDimitry Andric // IsEHa: emit an invoke _seh_try_end() to mark end of FT flow 2217fe6060f1SDimitry Andric if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) { 2218fe6060f1SDimitry Andric llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM); 2219fe6060f1SDimitry Andric EmitRuntimeCallOrInvoke(SehTryEnd); 2220fe6060f1SDimitry Andric } 2221fe6060f1SDimitry Andric 22220b57cec5SDimitry Andric // Otherwise, we must have an __except block. 22230b57cec5SDimitry Andric const SEHExceptStmt *Except = S.getExceptHandler(); 22240b57cec5SDimitry Andric assert(Except && "__try must have __finally xor __except"); 22250b57cec5SDimitry Andric EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin()); 22260b57cec5SDimitry Andric 22270b57cec5SDimitry Andric // Don't emit the __except block if the __try block lacked invokes. 22280b57cec5SDimitry Andric // TODO: Model unwind edges from instructions, either with iload / istore or 22290b57cec5SDimitry Andric // a try body function. 22300b57cec5SDimitry Andric if (!CatchScope.hasEHBranches()) { 22310b57cec5SDimitry Andric CatchScope.clearHandlerBlocks(); 22320b57cec5SDimitry Andric EHStack.popCatch(); 22330b57cec5SDimitry Andric SEHCodeSlotStack.pop_back(); 22340b57cec5SDimitry Andric return; 22350b57cec5SDimitry Andric } 22360b57cec5SDimitry Andric 22370b57cec5SDimitry Andric // The fall-through block. 22380b57cec5SDimitry Andric llvm::BasicBlock *ContBB = createBasicBlock("__try.cont"); 22390b57cec5SDimitry Andric 22400b57cec5SDimitry Andric // We just emitted the body of the __try; jump to the continue block. 22410b57cec5SDimitry Andric if (HaveInsertPoint()) 22420b57cec5SDimitry Andric Builder.CreateBr(ContBB); 22430b57cec5SDimitry Andric 22440b57cec5SDimitry Andric // Check if our filter function returned true. 22450b57cec5SDimitry Andric emitCatchDispatchBlock(*this, CatchScope); 22460b57cec5SDimitry Andric 22470b57cec5SDimitry Andric // Grab the block before we pop the handler. 22480b57cec5SDimitry Andric llvm::BasicBlock *CatchPadBB = CatchScope.getHandler(0).Block; 22490b57cec5SDimitry Andric EHStack.popCatch(); 22500b57cec5SDimitry Andric 22510b57cec5SDimitry Andric EmitBlockAfterUses(CatchPadBB); 22520b57cec5SDimitry Andric 22530b57cec5SDimitry Andric // __except blocks don't get outlined into funclets, so immediately do a 22540b57cec5SDimitry Andric // catchret. 22550b57cec5SDimitry Andric llvm::CatchPadInst *CPI = 22560b57cec5SDimitry Andric cast<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI()); 22570b57cec5SDimitry Andric llvm::BasicBlock *ExceptBB = createBasicBlock("__except"); 22580b57cec5SDimitry Andric Builder.CreateCatchRet(CPI, ExceptBB); 22590b57cec5SDimitry Andric EmitBlock(ExceptBB); 22600b57cec5SDimitry Andric 22610b57cec5SDimitry Andric // On Win64, the exception code is returned in EAX. Copy it into the slot. 22620b57cec5SDimitry Andric if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) { 22630b57cec5SDimitry Andric llvm::Function *SEHCodeIntrin = 22640b57cec5SDimitry Andric CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioncode); 22650b57cec5SDimitry Andric llvm::Value *Code = Builder.CreateCall(SEHCodeIntrin, {CPI}); 22660b57cec5SDimitry Andric Builder.CreateStore(Code, SEHCodeSlotStack.back()); 22670b57cec5SDimitry Andric } 22680b57cec5SDimitry Andric 22690b57cec5SDimitry Andric // Emit the __except body. 22700b57cec5SDimitry Andric EmitStmt(Except->getBlock()); 22710b57cec5SDimitry Andric 22720b57cec5SDimitry Andric // End the lifetime of the exception code. 22730b57cec5SDimitry Andric SEHCodeSlotStack.pop_back(); 22740b57cec5SDimitry Andric 22750b57cec5SDimitry Andric if (HaveInsertPoint()) 22760b57cec5SDimitry Andric Builder.CreateBr(ContBB); 22770b57cec5SDimitry Andric 22780b57cec5SDimitry Andric EmitBlock(ContBB); 22790b57cec5SDimitry Andric } 22800b57cec5SDimitry Andric 22810b57cec5SDimitry Andric void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) { 22820b57cec5SDimitry Andric // If this code is reachable then emit a stop point (if generating 22830b57cec5SDimitry Andric // debug info). We have to do this ourselves because we are on the 22840b57cec5SDimitry Andric // "simple" statement path. 22850b57cec5SDimitry Andric if (HaveInsertPoint()) 22860b57cec5SDimitry Andric EmitStopPoint(&S); 22870b57cec5SDimitry Andric 22880b57cec5SDimitry Andric // This must be a __leave from a __finally block, which we warn on and is UB. 22890b57cec5SDimitry Andric // Just emit unreachable. 22900b57cec5SDimitry Andric if (!isSEHTryScope()) { 22910b57cec5SDimitry Andric Builder.CreateUnreachable(); 22920b57cec5SDimitry Andric Builder.ClearInsertionPoint(); 22930b57cec5SDimitry Andric return; 22940b57cec5SDimitry Andric } 22950b57cec5SDimitry Andric 22960b57cec5SDimitry Andric EmitBranchThroughCleanup(*SEHTryEpilogueStack.back()); 22970b57cec5SDimitry Andric } 2298