aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/CodeGen/CGException.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/CGException.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/CodeGen/CGException.cpp291
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");