diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/CGException.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/CodeGen/CGException.cpp | 291 |
1 files changed, 201 insertions, 90 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp index 7a64963183bc..5a9d06da12de 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp @@ -39,6 +39,18 @@ static llvm::FunctionCallee getFreeExceptionFn(CodeGenModule &CGM) { return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); } +static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule &CGM) { + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); + return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin"); +} + +static llvm::FunctionCallee getSehTryEndFn(CodeGenModule &CGM) { + llvm::FunctionType *FTy = + llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); + return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end"); +} + static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) { // void __cxa_call_unexpected(void *thrown_exception); @@ -115,6 +127,8 @@ const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = { "__gxx_wasm_personality_v0", nullptr }; const EHPersonality EHPersonality::XL_CPlusPlus = {"__xlcxx_personality_v1", nullptr}; +const EHPersonality EHPersonality::ZOS_CPlusPlus = {"__zos_cxx_personality_v2", + nullptr}; static const EHPersonality &getCPersonality(const TargetInfo &Target, const LangOptions &L) { @@ -144,9 +158,11 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target, case ObjCRuntime::WatchOS: return EHPersonality::NeXT_ObjC; case ObjCRuntime::GNUstep: - if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7)) + if (T.isOSCygMing()) + return EHPersonality::GNU_CPlusPlus_SEH; + else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7)) return EHPersonality::GNUstep_ObjC; - LLVM_FALLTHROUGH; + [[fallthrough]]; case ObjCRuntime::GCC: case ObjCRuntime::ObjFW: if (L.hasSjLjExceptions()) @@ -173,6 +189,8 @@ static const EHPersonality &getCXXPersonality(const TargetInfo &Target, return EHPersonality::GNU_CPlusPlus_SEH; if (L.hasWasmExceptions()) return EHPersonality::GNU_Wasm_CPlusPlus; + if (T.isOSzOS()) + return EHPersonality::ZOS_CPlusPlus; return EHPersonality::GNU_CPlusPlus; } @@ -198,7 +216,8 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target, return getObjCPersonality(Target, L); case ObjCRuntime::GNUstep: - return EHPersonality::GNU_ObjCXX; + return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH + : EHPersonality::GNU_ObjCXX; // The GCC runtime's personality function inherently doesn't support // mixed EH. Use the ObjC personality just to avoid returning null. @@ -237,7 +256,7 @@ const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) { // For outlined finallys and filters, use the SEH personality in case they // contain more SEH. This mostly only affects finallys. Filters could // hypothetically use gnu statement expressions to sneak in nested SEH. - FD = FD ? FD : CGF.CurSEHParent; + FD = FD ? FD : CGF.CurSEHParent.getDecl(); return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD)); } @@ -251,12 +270,7 @@ static llvm::FunctionCallee getPersonalityFn(CodeGenModule &CGM, static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { llvm::FunctionCallee Fn = getPersonalityFn(CGM, Personality); - llvm::PointerType* Int8PtrTy = llvm::PointerType::get( - llvm::Type::getInt8Ty(CGM.getLLVMContext()), - CGM.getDataLayout().getProgramAddressSpace()); - - return llvm::ConstantExpr::getBitCast(cast<llvm::Constant>(Fn.getCallee()), - Int8PtrTy); + return cast<llvm::Constant>(Fn.getCallee()); } /// Check whether a landingpad instruction only uses C++ features. @@ -270,7 +284,7 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { if (llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(Val)) // ObjC EH selector entries are always global variables with // names starting like this. - if (GV->getName().startswith("OBJC_EHTYPE")) + if (GV->getName().starts_with("OBJC_EHTYPE")) return false; } else { // Check if any of the filter values have the ObjC prefix. @@ -281,7 +295,7 @@ static bool LandingPadHasOnlyCXXUses(llvm::LandingPadInst *LPI) { cast<llvm::GlobalVariable>((*II)->stripPointerCasts())) // ObjC EH selector entries are always global variables with // names starting like this. - if (GV->getName().startswith("OBJC_EHTYPE")) + if (GV->getName().starts_with("OBJC_EHTYPE")) return false; } } @@ -388,8 +402,8 @@ void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { // __cxa_allocate_exception returns a void*; we need to cast this // to the appropriate type for the object. - llvm::Type *ty = ConvertTypeForMem(e->getType())->getPointerTo(); - Address typedAddr = Builder.CreateBitCast(addr, ty); + llvm::Type *ty = ConvertTypeForMem(e->getType()); + Address typedAddr = addr.withElementType(ty); // FIXME: this isn't quite right! If there's a final unelided call // to a copy constructor, then according to [except.terminate]p1 we @@ -409,13 +423,13 @@ void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { Address CodeGenFunction::getExceptionSlot() { if (!ExceptionSlot) ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot"); - return Address(ExceptionSlot, getPointerAlign()); + return Address(ExceptionSlot, Int8PtrTy, getPointerAlign()); } Address CodeGenFunction::getEHSelectorSlot() { if (!EHSelectorSlot) EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot"); - return Address(EHSelectorSlot, CharUnits::fromQuantity(4)); + return Address(EHSelectorSlot, Int32Ty, CharUnits::fromQuantity(4)); } llvm::Value *CodeGenFunction::getExceptionFromSlot() { @@ -428,6 +442,15 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() { void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint) { + // If the exception is being emitted in an OpenMP target region, + // and the target is a GPU, we do not support exception handling. + // Therefore, we emit a trap which will abort the program, and + // prompt a warning indicating that a trap will be emitted. + const llvm::Triple &T = Target.getTriple(); + if (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())) { + EmitTrapCall(llvm::Intrinsic::trap); + return; + } if (const Expr *SubExpr = E->getSubExpr()) { QualType ThrowType = SubExpr->getType(); if (ThrowType->isObjCObjectPointerType()) { @@ -465,17 +488,18 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { - // noexcept functions are simple terminate scopes. - EHStack.pushTerminate(); - } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + // In C++17 and later, 'throw()' aka EST_DynamicNone is treated the same way + // as noexcept. In earlier standards, it is handled in this block, along with + // 'throw(X...)'. + if (EST == EST_Dynamic || + (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { // TODO: Revisit exception specifications for the MS ABI. There is a way to // encode these in an object file but MSVC doesn't do anything with it. if (getTarget().getCXXABI().isMicrosoft()) return; - // In wasm we currently treat 'throw()' in the same way as 'noexcept'. In + // In Wasm EH we currently treat 'throw()' in the same way as 'noexcept'. In // case of throw with types, we ignore it and print a warning for now. - // TODO Correctly handle exception specification in wasm + // TODO Correctly handle exception specification in Wasm EH if (CGM.getLangOpts().hasWasmExceptions()) { if (EST == EST_DynamicNone) EHStack.pushTerminate(); @@ -485,6 +509,19 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { << FD->getExceptionSpecSourceRange(); return; } + // Currently Emscripten EH only handles 'throw()' but not 'throw' with + // types. 'throw()' handling will be done in JS glue code so we don't need + // to do anything in that case. Just print a warning message in case of + // throw with types. + // TODO Correctly handle exception specification in Emscripten EH + if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly && + CGM.getLangOpts().getExceptionHandling() == + LangOptions::ExceptionHandlingKind::None && + EST == EST_Dynamic) + CGM.getDiags().Report(D->getLocation(), + diag::warn_wasm_dynamic_exception_spec_ignored) + << FD->getExceptionSpecSourceRange(); + unsigned NumExceptions = Proto->getNumExceptions(); EHFilterScope *Filter = EHStack.pushFilter(NumExceptions); @@ -495,6 +532,10 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { /*ForEH=*/true); Filter->setFilter(I, EHType); } + } else if (Proto->canThrow() == CT_Cannot) { + // noexcept functions are simple terminate scopes. + if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur + EHStack.pushTerminate(); } } @@ -544,7 +585,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (!FD) { // Check if CapturedDecl is nothrow and pop terminate scope for it. if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) { - if (CD->isNothrow()) + if (CD->isNothrow() && !EHStack.empty()) EHStack.popTerminate(); } return; @@ -554,9 +595,8 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { - EHStack.popTerminate(); - } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + if (EST == EST_Dynamic || + (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { // TODO: Revisit exception specifications for the MS ABI. There is a way to // encode these in an object file but MSVC doesn't do anything with it. if (getTarget().getCXXABI().isMicrosoft()) @@ -572,13 +612,24 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { EHFilterScope &filterScope = cast<EHFilterScope>(*EHStack.begin()); emitFilterDispatchBlock(*this, filterScope); EHStack.popFilter(); + } else if (Proto->canThrow() == CT_Cannot && + /* possible empty when under async exceptions */ + !EHStack.empty()) { + EHStack.popTerminate(); } } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { - EnterCXXTryStmt(S); + const llvm::Triple &T = Target.getTriple(); + // If we encounter a try statement on in an OpenMP target region offloaded to + // a GPU, we treat it as a basic block. + const bool IsTargetDevice = + (CGM.getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN())); + if (!IsTargetDevice) + EnterCXXTryStmt(S); EmitStmt(S.getTryBlock()); - ExitCXXTryStmt(S); + if (!IsTargetDevice) + ExitCXXTryStmt(S); } void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { @@ -610,6 +661,10 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { } else { // No exception decl indicates '...', a catch-all. CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler); + // Under async exceptions, catch(...) need to catch HW exception too + // Mark scope with SehTryBegin as a SEH __try scope + if (getLangOpts().EHAsynch) + EmitSehTryScopeBegin(); } } } @@ -724,7 +779,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { // If exceptions are disabled/ignored and SEH is not in use, then there is no // invoke destination. SEH "works" even if exceptions are off. In practice, // this means that C++ destructors and other EH cleanups don't run, which is - // consistent with MSVC's behavior. + // consistent with MSVC's behavior, except in the presence of -EHa const LangOptions &LO = CGM.getLangOpts(); if (!LO.Exceptions || LO.IgnoreExceptions) { if (!LO.Borland && !LO.MicrosoftExt) @@ -1083,6 +1138,8 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, // Select the right handler. llvm::Function *llvm_eh_typeid_for = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); + llvm::Type *argTy = llvm_eh_typeid_for->getArg(0)->getType(); + LangAS globAS = CGF.CGM.GetGlobalVarAddressSpace(nullptr); // Load the selector value. llvm::Value *selector = CGF.getSelectorFromSlot(); @@ -1096,7 +1153,11 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF, assert(handler.Type.Flags == 0 && "landingpads do not support catch handler flags"); assert(typeValue && "fell into catch-all case!"); - typeValue = CGF.Builder.CreateBitCast(typeValue, CGF.Int8PtrTy); + // With opaque ptrs, only the address space can be a mismatch. + if (typeValue->getType() != argTy) + typeValue = + CGF.getTargetHooks().performAddrSpaceCast(CGF, typeValue, globAS, + LangAS::Default, argTy); // Figure out the next block. bool nextIsEnd; @@ -1186,8 +1247,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { // Wasm uses Windows-style EH instructions, but merges all catch clauses into // one big catchpad. So we save the old funclet pad here before we traverse // each catch handler. - SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad( - CurrentFuncletPad); + SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad); llvm::BasicBlock *WasmCatchStartBlock = nullptr; if (EHPersonality::get(*this).isWasmPersonality()) { auto *CatchSwitch = @@ -1220,8 +1280,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { RunCleanupsScope CatchScope(*this); // Initialize the catch variable and set up the cleanups. - SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad( - CurrentFuncletPad); + SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad); CGM.getCXXABI().emitBeginCatch(*this, C); // Emit the PGO counter increment. @@ -1343,7 +1402,8 @@ namespace { CGF.EmitBlock(RethrowBB); if (SavedExnVar) { CGF.EmitRuntimeCallOrInvoke(RethrowFn, - CGF.Builder.CreateAlignedLoad(SavedExnVar, CGF.getPointerAlign())); + CGF.Builder.CreateAlignedLoad(CGF.Int8PtrTy, SavedExnVar, + CGF.getPointerAlign())); } else { CGF.EmitRuntimeCallOrInvoke(RethrowFn); } @@ -1544,25 +1604,15 @@ llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() { // Create the cleanuppad using the current parent pad as its token. Use 'none' // if this is a top-level terminate scope, which is the common case. - SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad( - CurrentFuncletPad); + SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad); llvm::Value *ParentPad = CurrentFuncletPad; if (!ParentPad) ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext()); CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad); // Emit the __std_terminate call. - llvm::Value *Exn = nullptr; - // In case of wasm personality, we need to pass the exception value to - // __clang_call_terminate function. - if (getLangOpts().CPlusPlus && - EHPersonality::get(*this).isWasmPersonality()) { - llvm::Function *GetExnFn = - CGM.getIntrinsic(llvm::Intrinsic::wasm_get_exception); - Exn = Builder.CreateCall(GetExnFn, CurrentFuncletPad); - } llvm::CallInst *terminateCall = - CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); + CGM.getCXXABI().emitTerminateForUnexpectedException(*this, nullptr); terminateCall->setDoesNotReturn(); Builder.CreateUnreachable(); @@ -1599,7 +1649,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { llvm::Value *Sel = getSelectorFromSlot(); llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType()); - llvm::Value *LPadVal = llvm::UndefValue::get(LPadType); + llvm::Value *LPadVal = llvm::PoisonValue::get(LPadType); LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val"); LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val"); @@ -1614,7 +1664,23 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave"); SEHTryEpilogueStack.push_back(&TryExit); + + llvm::BasicBlock *TryBB = nullptr; + // IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa + if (getLangOpts().EHAsynch) { + EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM)); + if (SEHTryEpilogueStack.size() == 1) // outermost only + TryBB = Builder.GetInsertBlock(); + } + EmitStmt(S.getTryBlock()); + + // Volatilize all blocks in Try, till current insert point + if (TryBB) { + llvm::SmallPtrSet<llvm::BasicBlock *, 10> Visited; + VolatilizeTryBlocks(TryBB, Visited); + } + SEHTryEpilogueStack.pop_back(); if (!TryExit.getBlock()->use_empty()) @@ -1625,6 +1691,35 @@ void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) { ExitSEHTryStmt(S); } +// Recursively walk through blocks in a _try +// and make all memory instructions volatile +void CodeGenFunction::VolatilizeTryBlocks( + llvm::BasicBlock *BB, llvm::SmallPtrSet<llvm::BasicBlock *, 10> &V) { + if (BB == SEHTryEpilogueStack.back()->getBlock() /* end of Try */ || + !V.insert(BB).second /* already visited */ || + !BB->getParent() /* not emitted */ || BB->empty()) + return; + + if (!BB->isEHPad()) { + for (llvm::BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; + ++J) { + if (auto LI = dyn_cast<llvm::LoadInst>(J)) { + LI->setVolatile(true); + } else if (auto SI = dyn_cast<llvm::StoreInst>(J)) { + SI->setVolatile(true); + } else if (auto* MCI = dyn_cast<llvm::MemIntrinsic>(J)) { + MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1)); + } + } + } + const llvm::Instruction *TI = BB->getTerminator(); + if (TI) { + unsigned N = TI->getNumSuccessors(); + for (unsigned I = 0; I < N; I++) + VolatilizeTryBlocks(TI->getSuccessor(I), V); + } +} + namespace { struct PerformSEHFinally final : EHScopeStack::Cleanup { llvm::Function *OutlinedFinally; @@ -1702,10 +1797,8 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> { void VisitDeclRefExpr(const DeclRefExpr *E) { // If this is already a capture, just make sure we capture 'this'. - if (E->refersToEnclosingVariableOrCapture()) { + if (E->refersToEnclosingVariableOrCapture()) Captures.insert(ParentThis); - return; - } const auto *D = dyn_cast<VarDecl>(E->getDecl()); if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage()) @@ -1747,13 +1840,11 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, auto InsertPair = ParentCGF.EscapedLocals.insert( std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); int FrameEscapeIdx = InsertPair.first->second; - // call i8* @llvm.localrecover(i8* bitcast(@parentFn), i8* %fp, i32 N) + // call ptr @llvm.localrecover(ptr @parentFn, ptr %fp, i32 N) llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); RecoverCall = Builder.CreateCall( - FrameRecoverFn, {ParentI8Fn, ParentFP, + FrameRecoverFn, {ParentCGF.CurFn, ParentFP, llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); } else { @@ -1773,7 +1864,7 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, llvm::Value *ChildVar = Builder.CreateBitCast(RecoverCall, ParentVar.getType()); ChildVar->setName(ParentVar.getName()); - return Address(ChildVar, ParentVar.getAlignment()); + return ParentVar.withPointer(ChildVar, KnownNonNull); } void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, @@ -1816,9 +1907,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, // since finally funclets recover the parent FP for us. llvm::Function *RecoverFPIntrin = CGM.getIntrinsic(llvm::Intrinsic::eh_recoverfp); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); - ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentI8Fn, EntryFP}); + ParentFP = Builder.CreateCall(RecoverFPIntrin, {ParentCGF.CurFn, EntryFP}); // if the parent is a _finally, the passed-in ParentFP is the FP // of parent _finally, not Establisher's FP (FP of outermost function). @@ -1835,7 +1924,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, const VarDecl *D = cast<VarDecl>(I.first); if (isa<ImplicitParamDecl>(D) && D->getType() == getContext().VoidPtrTy) { - assert(D->getName().startswith("frame_pointer")); + assert(D->getName().starts_with("frame_pointer")); FramePtrAddrAlloca = cast<llvm::AllocaInst>(I.second.getPointer()); break; } @@ -1846,30 +1935,22 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, int FrameEscapeIdx = InsertPair.first->second; // an example of a filter's prolog:: - // %0 = call i8* @llvm.eh.recoverfp(bitcast(@"?fin$0@0@main@@"),..) - // %1 = call i8* @llvm.localrecover(bitcast(@"?fin$0@0@main@@"),..) - // %2 = bitcast i8* %1 to i8** - // %3 = load i8*, i8* *%2, align 8 - // ==> %3 is the frame-pointer of outermost host function + // %0 = call ptr @llvm.eh.recoverfp(@"?fin$0@0@main@@",..) + // %1 = call ptr @llvm.localrecover(@"?fin$0@0@main@@",..) + // %2 = load ptr, ptr %1, align 8 + // ==> %2 is the frame-pointer of outermost host function llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); - llvm::Constant *ParentI8Fn = - llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy); ParentFP = Builder.CreateCall( - FrameRecoverFn, {ParentI8Fn, ParentFP, + FrameRecoverFn, {ParentCGF.CurFn, ParentFP, llvm::ConstantInt::get(Int32Ty, FrameEscapeIdx)}); - ParentFP = Builder.CreateBitCast(ParentFP, CGM.VoidPtrPtrTy); - ParentFP = Builder.CreateLoad(Address(ParentFP, getPointerAlign())); + ParentFP = Builder.CreateLoad( + Address(ParentFP, CGM.VoidPtrTy, getPointerAlign())); } } // Create llvm.localrecover calls for all captures. for (const VarDecl *VD : Finder.Captures) { - if (isa<ImplicitParamDecl>(VD)) { - CGM.ErrorUnsupported(VD, "'this' captured by SEH"); - CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType())); - continue; - } if (VD->getType()->isVariablyModifiedType()) { CGM.ErrorUnsupported(VD, "VLA captured by SEH"); continue; @@ -1877,6 +1958,12 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) && "captured non-local variable"); + auto L = ParentCGF.LambdaCaptureFields.find(VD); + if (L != ParentCGF.LambdaCaptureFields.end()) { + LambdaCaptureFields[VD] = L->second; + continue; + } + // If this decl hasn't been declared yet, it will be declared in the // OutlinedStmt. auto I = ParentCGF.LocalDeclMap.find(VD); @@ -1884,8 +1971,30 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, continue; Address ParentVar = I->second; - setAddrOfLocalVar( - VD, recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP)); + Address Recovered = + recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); + setAddrOfLocalVar(VD, Recovered); + + if (isa<ImplicitParamDecl>(VD)) { + CXXABIThisAlignment = ParentCGF.CXXABIThisAlignment; + CXXThisAlignment = ParentCGF.CXXThisAlignment; + CXXABIThisValue = Builder.CreateLoad(Recovered, "this"); + if (ParentCGF.LambdaThisCaptureField) { + LambdaThisCaptureField = ParentCGF.LambdaThisCaptureField; + // We are in a lambda function where "this" is captured so the + // CXXThisValue need to be loaded from the lambda capture + LValue ThisFieldLValue = + EmitLValueForLambdaField(LambdaThisCaptureField); + if (!LambdaThisCaptureField->getType()->isPointerType()) { + CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer(); + } else { + CXXThisValue = EmitLoadOfLValue(ThisFieldLValue, SourceLocation()) + .getScalarVal(); + } + } else { + CXXThisValue = CXXABIThisValue; + } + } } if (Finder.SEHCodeSlot.isValid()) { @@ -1909,7 +2018,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, SmallString<128> Name; { llvm::raw_svector_ostream OS(Name); - const NamedDecl *ParentSEHFn = ParentCGF.CurSEHParent; + GlobalDecl ParentSEHFn = ParentCGF.CurSEHParent; assert(ParentSEHFn && "No CurSEHParent!"); MangleContext &Mangler = CGM.getCXXABI().getMangleContext(); if (IsFilter) @@ -1926,17 +2035,17 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF, Args.push_back(ImplicitParamDecl::Create( getContext(), /*DC=*/nullptr, StartLoc, &getContext().Idents.get("exception_pointers"), - getContext().VoidPtrTy, ImplicitParamDecl::Other)); + getContext().VoidPtrTy, ImplicitParamKind::Other)); } else { Args.push_back(ImplicitParamDecl::Create( getContext(), /*DC=*/nullptr, StartLoc, &getContext().Idents.get("abnormal_termination"), - getContext().UnsignedCharTy, ImplicitParamDecl::Other)); + getContext().UnsignedCharTy, ImplicitParamKind::Other)); } Args.push_back(ImplicitParamDecl::Create( getContext(), /*DC=*/nullptr, StartLoc, &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy, - ImplicitParamDecl::Other)); + ImplicitParamKind::Other)); } QualType RetTy = IsFilter ? getContext().LongTy : getContext().VoidTy; @@ -2008,7 +2117,6 @@ void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, // pointer is stored in the second field. So, GEP 20 bytes backwards and // load the pointer. SEHInfo = Builder.CreateConstInBoundsGEP1_32(Int8Ty, EntryFP, -20); - SEHInfo = Builder.CreateBitCast(SEHInfo, Int8PtrTy->getPointerTo()); SEHInfo = Builder.CreateAlignedLoad(Int8PtrTy, SEHInfo, getPointerAlign()); SEHCodeSlotStack.push_back(recoverAddrOfEscapedLocal( ParentCGF, ParentCGF.SEHCodeSlotStack.back(), ParentFP)); @@ -2021,12 +2129,11 @@ void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, // CONTEXT *ContextRecord; // }; // int exceptioncode = exception_pointers->ExceptionRecord->ExceptionCode; - llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo(); + llvm::Type *RecordTy = llvm::PointerType::getUnqual(getLLVMContext()); llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy); - llvm::Value *Ptrs = Builder.CreateBitCast(SEHInfo, PtrsTy->getPointerTo()); - llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, Ptrs, 0); - Rec = Builder.CreateAlignedLoad(Rec, getPointerAlign()); - llvm::Value *Code = Builder.CreateAlignedLoad(Rec, getIntAlign()); + llvm::Value *Rec = Builder.CreateStructGEP(PtrsTy, SEHInfo, 0); + Rec = Builder.CreateAlignedLoad(RecordTy, Rec, getPointerAlign()); + llvm::Value *Code = Builder.CreateAlignedLoad(Int32Ty, Rec, getIntAlign()); assert(!SEHCodeSlotStack.empty() && "emitting EH code outside of __except"); Builder.CreateStore(Code, SEHCodeSlotStack.back()); } @@ -2093,9 +2200,7 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) { // in place of the RTTI typeinfo global that C++ EH uses. llvm::Function *FilterFunc = HelperCGF.GenerateSEHFilterFunction(*this, *Except); - llvm::Constant *OpaqueFunc = - llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy); - CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except.ret")); + CatchScope->setHandler(0, FilterFunc, createBasicBlock("__except.ret")); } void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { @@ -2105,6 +2210,12 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) { return; } + // IsEHa: emit an invoke _seh_try_end() to mark end of FT flow + if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) { + llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM); + EmitRuntimeCallOrInvoke(SehTryEnd); + } + // Otherwise, we must have an __except block. const SEHExceptStmt *Except = S.getExceptHandler(); assert(Except && "__try must have __finally xor __except"); |