diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
| commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
| tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /clang/lib/CodeGen/CGException.cpp | |
| parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
vendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
Diffstat (limited to 'clang/lib/CodeGen/CGException.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGException.cpp | 153 |
1 files changed, 124 insertions, 29 deletions
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 7a64963183bc..9f65e9eb120c 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/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); @@ -467,15 +479,16 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { ExceptionSpecificationType EST = Proto->getExceptionSpecType(); if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { // noexcept functions are simple terminate scopes. - EHStack.pushTerminate(); + if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur + EHStack.pushTerminate(); } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { // 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 +498,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); @@ -544,7 +570,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,7 +580,8 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { + if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot && + !EHStack.empty() /* possible empty when under async exceptions */) { EHStack.popTerminate(); } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { // TODO: Revisit exception specifications for the MS ABI. There is a way to @@ -610,6 +637,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) + EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM)); } } } @@ -724,7 +755,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) @@ -1343,7 +1374,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); } @@ -1552,17 +1584,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() { 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(); @@ -1614,7 +1637,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 +1664,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 +1770,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()) @@ -1865,11 +1931,6 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, // 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 +1938,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 +1951,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()) { @@ -2025,8 +2114,8 @@ void CodeGenFunction::EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, 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()); + 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()); } @@ -2105,6 +2194,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"); |
