Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -108,6 +108,7 @@ LANGOPT(ObjCExceptions , 1, 0, "Objective-C exceptions") LANGOPT(CXXExceptions , 1, 0, "C++ exceptions") LANGOPT(SjLjExceptions , 1, 0, "setjmp-longjump exception handling") +LANGOPT(NewMSEH , 1, 0, "new IR representation for MS exceptions") LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation") LANGOPT(RTTI , 1, 1, "run-time type information") LANGOPT(RTTIData , 1, 1, "emit run-time type information data") Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -486,6 +486,8 @@ HelpText<"Weakly link in the blocks runtime">; def fsjlj_exceptions : Flag<["-"], "fsjlj-exceptions">, HelpText<"Use SjLj style exceptions">; +def fnew_ms_eh: Flag<["-"], "fnew-ms-eh">, + HelpText<"Use the new IR representation for MS exceptions">; def split_dwarf_file : Separate<["-"], "split-dwarf-file">, HelpText<"File name to use for split dwarf debug info output">; def fno_wchar : Flag<["-"], "fno-wchar">, Index: lib/CodeGen/CGCleanup.h =================================================================== --- lib/CodeGen/CGCleanup.h +++ lib/CodeGen/CGCleanup.h @@ -37,9 +37,9 @@ class CommonBitFields { friend class EHScope; - unsigned Kind : 2; + unsigned Kind : 3; }; - enum { NumCommonBits = 2 }; + enum { NumCommonBits = 3 }; protected: class CatchBitFields { @@ -78,7 +78,7 @@ /// The number of fixups required by enclosing scopes (not including /// this one). If this is the top cleanup scope, all the fixups /// from this index onwards belong to this scope. - unsigned FixupDepth : 32 - 18 - NumCommonBits; // currently 13 + unsigned FixupDepth : 32 - 18 - NumCommonBits; // currently 12 }; class FilterBitFields { @@ -96,7 +96,7 @@ }; public: - enum Kind { Cleanup, Catch, Terminate, Filter }; + enum Kind { Cleanup, Catch, Terminate, Filter, CatchEnd }; EHScope(Kind kind, EHScopeStack::stable_iterator enclosingEHScope) : CachedLandingPad(nullptr), CachedEHDispatchBlock(nullptr), @@ -463,6 +463,17 @@ } }; +class EHCatchEndScope : public EHScope { +public: + EHCatchEndScope(EHScopeStack::stable_iterator enclosingEHScope) + : EHScope(CatchEnd, enclosingEHScope) {} + static size_t getSize() { return sizeof(EHCatchEndScope); } + + static bool classof(const EHScope *scope) { + return scope->getKind() == CatchEnd; + } +}; + /// A non-stable pointer into the scope stack. class EHScopeStack::iterator { char *Ptr; @@ -500,6 +511,10 @@ case EHScope::Terminate: Size = EHTerminateScope::getSize(); break; + + case EHScope::CatchEnd: + Size = EHCatchEndScope::getSize(); + break; } Ptr += llvm::RoundUpToAlignment(Size, ScopeStackAlignment); return *this; @@ -548,6 +563,14 @@ deallocate(EHTerminateScope::getSize()); } +inline void EHScopeStack::popCatchEnd() { + assert(!empty() && "popping exception stack when not empty"); + + EHCatchEndScope &scope = cast(*begin()); + InnermostEHScope = scope.getEnclosingEHScope(); + deallocate(EHCatchEndScope::getSize()); +} + inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { assert(sp.isValid() && "finding invalid savepoint"); assert(sp.Size <= stable_begin().Size && "finding savepoint after pop"); Index: lib/CodeGen/CGCleanup.cpp =================================================================== --- lib/CodeGen/CGCleanup.cpp +++ lib/CodeGen/CGCleanup.cpp @@ -247,6 +247,13 @@ InnermostEHScope = stable_begin(); } +void EHScopeStack::pushCatchEnd(llvm::BasicBlock *CatchEndBlockBB) { + char *Buffer = allocate(EHCatchEndScope::getSize()); + auto *CES = new (Buffer) EHCatchEndScope(InnermostEHScope); + CES->setCachedEHDispatchBlock(CatchEndBlockBB); + InnermostEHScope = stable_begin(); +} + /// Remove any 'null' fixups on the stack. However, we can't pop more /// fixups than the fixup depth on the innermost normal cleanup, or /// else fixups that we try to add to that cleanup will end up in the @@ -896,6 +903,13 @@ CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); EmitBlock(EHEntry); + llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent); + if (CGM.getLangOpts().NewMSEH && getTarget().getCXXABI().isMicrosoft()) { + if (NextAction) + Builder.CreateCleanupPad(VoidTy, NextAction); + else + Builder.CreateCleanupPad(VoidTy, {}); + } // We only actually emit the cleanup code if the cleanup is either // active or was used before it was deactivated. @@ -905,7 +919,10 @@ EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); } - Builder.CreateBr(getEHDispatchBlock(EHParent)); + if (CGM.getLangOpts().NewMSEH && getTarget().getCXXABI().isMicrosoft()) + Builder.CreateCleanupRet(NextAction); + else + Builder.CreateBr(NextAction); Builder.restoreIP(SavedIP); Index: lib/CodeGen/CGException.cpp =================================================================== --- lib/CodeGen/CGException.cpp +++ lib/CodeGen/CGException.cpp @@ -110,6 +110,15 @@ static const EHPersonality MSVC_except_handler; static const EHPersonality MSVC_C_specific_handler; static const EHPersonality MSVC_CxxFrameHandler3; + + bool isMSVCPersonality() const { + return this == &MSVC_except_handler || this == &MSVC_C_specific_handler || + this == &MSVC_CxxFrameHandler3; + } + + bool isMSVCXXPersonality() const { + return this == &MSVC_CxxFrameHandler3; + } }; } @@ -587,6 +596,10 @@ llvm::BasicBlock * CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { + if (CGM.getLangOpts().NewMSEH && + EHPersonality::get(*this).isMSVCPersonality()) + return getMSVCDispatchBlock(si); + // The dispatch block for the end of the scope chain is a block that // just resumes unwinding. if (si == EHStack.stable_end()) @@ -623,12 +636,58 @@ case EHScope::Terminate: dispatchBlock = getTerminateHandler(); break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); } scope.setCachedEHDispatchBlock(dispatchBlock); } return dispatchBlock; } +llvm::BasicBlock * +CodeGenFunction::getMSVCDispatchBlock(EHScopeStack::stable_iterator SI) { + // Returning nullptr indicates that the previous dispatch block should unwind + // to caller. + if (SI == EHStack.stable_end()) + return nullptr; + + // Otherwise, we should look at the actual scope. + EHScope &EHS = *EHStack.find(SI); + + llvm::BasicBlock *DispatchBlock = EHS.getCachedEHDispatchBlock(); + if (DispatchBlock) + return DispatchBlock; + + if (EHS.getKind() == EHScope::Terminate) + DispatchBlock = getTerminateHandler(); + else + DispatchBlock = createBasicBlock(); + CGBuilderTy Builder(DispatchBlock); + + switch (EHS.getKind()) { + case EHScope::Catch: + DispatchBlock->setName("catch.dispatch"); + break; + + case EHScope::Cleanup: + DispatchBlock->setName("ehcleanup"); + break; + + case EHScope::Filter: + llvm_unreachable("exception specifications not handled yet!"); + + case EHScope::Terminate: + DispatchBlock->setName("terminate"); + break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd dispatch block missing!"); + } + EHS.setCachedEHDispatchBlock(DispatchBlock); + return DispatchBlock; +} + /// Check whether this is a non-EH scope, i.e. a scope which doesn't /// affect exception handling. Currently, the only non-EH scopes are /// normal-only cleanup scopes. @@ -639,6 +698,7 @@ case EHScope::Filter: case EHScope::Catch: case EHScope::Terminate: + case EHScope::CatchEnd: return false; } @@ -664,8 +724,19 @@ llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad(); if (LP) return LP; - // Build the landing pad for this scope. - LP = EmitLandingPad(); + const EHPersonality &Personality = EHPersonality::get(*this); + + if (!CurFn->hasPersonalityFn()) + CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, Personality)); + + if (CGM.getLangOpts().NewMSEH && Personality.isMSVCPersonality()) { + // We don't need separate landing pads in the MSVC model. + LP = getEHDispatchBlock(EHStack.getInnermostEHScope()); + } else { + // Build the landing pad for this scope. + LP = EmitLandingPad(); + } + assert(LP); // Cache the landing pad on the innermost scope. If this is a @@ -686,6 +757,9 @@ case EHScope::Terminate: return getTerminateLandingPad(); + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); + case EHScope::Catch: case EHScope::Cleanup: case EHScope::Filter: @@ -697,11 +771,6 @@ CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, CurEHLocation); - const EHPersonality &personality = EHPersonality::get(*this); - - if (!CurFn->hasPersonalityFn()) - CurFn->setPersonalityFn(getOpaquePersonalityFn(CGM, personality)); - // Create and configure the landing pad. llvm::BasicBlock *lpad = createBasicBlock("lpad"); EmitBlock(lpad); @@ -756,6 +825,9 @@ case EHScope::Catch: break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); } EHCatchScope &catchScope = cast(*I); @@ -820,10 +892,61 @@ return lpad; } +static llvm::BasicBlock *emitMSVCCatchDispatchBlock(CodeGenFunction &CGF, + EHCatchScope &catchScope) { + llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); + assert(dispatchBlock); + + CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP(); + CGF.EmitBlockAfterUses(dispatchBlock); + + // Figure out the next block. + llvm::BasicBlock *nextBlock = nullptr; + + // Test against each of the exception types we claim to catch. + for (unsigned i = 0, e = catchScope.getNumHandlers(); i < e; ++i) { + const EHCatchScope::Handler &handler = catchScope.getHandler(i); + + llvm::Value *typeValue = handler.Type; + assert((typeValue != nullptr || handler.isCatchAll())); + if (!typeValue) + typeValue = llvm::Constant::getNullValue(CGF.VoidPtrTy); + + // If this is the last handler, we're at the end, and the next + // block is the block for the enclosing EH scope. + if (i + 1 == e) { + nextBlock = CGF.createBasicBlock("catchendblock"); + CGBuilderTy(nextBlock).CreateCatchEndPad( + CGF.getEHDispatchBlock(catchScope.getEnclosingEHScope())); + } else { + nextBlock = CGF.createBasicBlock("catch.dispatch"); + } + + if (EHPersonality::get(CGF).isMSVCXXPersonality()) { + CGF.Builder.CreateCatchPad( + CGF.VoidTy, handler.Block, nextBlock, + {typeValue, llvm::Constant::getNullValue(CGF.VoidPtrTy)}); + } else { + CGF.Builder.CreateCatchPad(CGF.VoidTy, handler.Block, nextBlock, + {typeValue}); + } + + // Otherwise we need to emit and continue at that block. + CGF.EmitBlock(nextBlock); + } + CGF.Builder.restoreIP(savedIP); + + return nextBlock; +} + /// Emit the structure of the dispatch block for the given catch scope. /// It is an invariant that the dispatch block already exists. -static void emitCatchDispatchBlock(CodeGenFunction &CGF, - EHCatchScope &catchScope) { +static llvm::BasicBlock *emitCatchDispatchBlock(CodeGenFunction &CGF, + EHCatchScope &catchScope) { + if (CGF.CGM.getLangOpts().NewMSEH && + EHPersonality::get(CGF).isMSVCPersonality()) + return emitMSVCCatchDispatchBlock(CGF, catchScope); + llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); assert(dispatchBlock); @@ -832,7 +955,7 @@ if (catchScope.getNumHandlers() == 1 && catchScope.getHandler(0).isCatchAll()) { assert(dispatchBlock == catchScope.getHandler(0).Block); - return; + return nullptr; } CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP(); @@ -888,11 +1011,12 @@ // If the next handler is a catch-all, we're completely done. if (nextIsEnd) { CGF.Builder.restoreIP(savedIP); - return; + return nullptr; } // Otherwise we need to emit and continue at that block. CGF.EmitBlock(nextBlock); } + return nullptr; } void CodeGenFunction::popCatchScope() { @@ -915,7 +1039,7 @@ } // Emit the structure of the EH dispatch for this catch. - emitCatchDispatchBlock(*this, CatchScope); + llvm::BasicBlock *CatchEndBlockBB = emitCatchDispatchBlock(*this, CatchScope); // Copy the handler blocks off before we pop the EH stack. Emitting // the handlers might scribble on this memory. @@ -939,6 +1063,9 @@ doImplicitRethrow = isa(CurCodeDecl) || isa(CurCodeDecl); + if (CatchEndBlockBB) + EHStack.pushCatchEnd(CatchEndBlockBB); + // Perversely, we emit the handlers backwards precisely because we // want them to appear in source order. In all of these cases, the // catch block will have exactly one predecessor, which will be a @@ -991,6 +1118,8 @@ EmitBlock(ContBB); incrementProfileCounter(&S); + if (CatchEndBlockBB) + EHStack.popCatchEnd(); } namespace { @@ -1228,13 +1357,17 @@ // end of the function by FinishFunction. TerminateHandler = createBasicBlock("terminate.handler"); Builder.SetInsertPoint(TerminateHandler); - llvm::Value *Exn = 0; - if (getLangOpts().CPlusPlus) - Exn = getExceptionFromSlot(); - llvm::CallInst *terminateCall = - CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); - terminateCall->setDoesNotReturn(); - Builder.CreateUnreachable(); + if (CGM.getLangOpts().NewMSEH && getTarget().getCXXABI().isMicrosoft()) { + Builder.CreateTerminatePad(/*UnwindBB=*/nullptr, CGM.getTerminateFn()); + } else { + llvm::Value *Exn = 0; + if (getLangOpts().CPlusPlus) + Exn = getExceptionFromSlot(); + llvm::CallInst *terminateCall = + CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn); + terminateCall->setDoesNotReturn(); + Builder.CreateUnreachable(); + } // Restore the saved insertion state. Builder.restoreIP(SavedIP); Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -665,6 +665,7 @@ llvm::BasicBlock *getEHResumeBlock(bool isCleanup); llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope); + llvm::BasicBlock *getMSVCDispatchBlock(EHScopeStack::stable_iterator scope); /// An object to manage conditionally-evaluated expressions. class ConditionalEvaluation { Index: lib/CodeGen/EHScopeStack.h =================================================================== --- lib/CodeGen/EHScopeStack.h +++ lib/CodeGen/EHScopeStack.h @@ -329,6 +329,10 @@ /// Pops a terminate handler off the stack. void popTerminate(); + void pushCatchEnd(llvm::BasicBlock *CatchEndBlockBB); + + void popCatchEnd(); + // Returns true iff the current scope is either empty or contains only // lifetime markers, i.e. no real cleanup code bool containsOnlyLifetimeMarkers(stable_iterator Old) const; Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -851,8 +851,14 @@ struct CallEndCatchMSVC : EHScopeStack::Cleanup { CallEndCatchMSVC() {} void Emit(CodeGenFunction &CGF, Flags flags) override { - CGF.EmitNounwindRuntimeCall( - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch)); + if (CGF.CGM.getLangOpts().NewMSEH) { + llvm::BasicBlock *BB = CGF.createBasicBlock("catchret.dest"); + CGF.Builder.CreateCatchRet(BB); + CGF.EmitBlock(BB); + } else { + CGF.EmitNounwindRuntimeCall( + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch)); + } } }; } @@ -862,24 +868,36 @@ // In the MS ABI, the runtime handles the copy, and the catch handler is // responsible for destruction. VarDecl *CatchParam = S->getExceptionDecl(); - llvm::Value *Exn = CGF.getExceptionFromSlot(); - llvm::Function *BeginCatch = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch); - + llvm::Value *Exn = nullptr; + llvm::Function *BeginCatch = nullptr; + bool NewEH = CGF.CGM.getLangOpts().NewMSEH; + if (!NewEH) { + Exn = CGF.getExceptionFromSlot(); + BeginCatch = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch); + } // If this is a catch-all or the catch parameter is unnamed, we don't need to // emit an alloca to the object. if (!CatchParam || !CatchParam->getDeclName()) { - llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)}; - CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + if (!NewEH) { + llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)}; + CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + } CGF.EHStack.pushCleanup(NormalCleanup); return; } CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam); - llvm::Value *ParamAddr = - CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy); - llvm::Value *Args[2] = {Exn, ParamAddr}; - CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + if (!NewEH) { + llvm::Value *ParamAddr = + CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy); + llvm::Value *Args[2] = {Exn, ParamAddr}; + CGF.EmitNounwindRuntimeCall(BeginCatch, Args); + } else { + llvm::BasicBlock *CatchPadBB = + CGF.Builder.GetInsertBlock()->getSinglePredecessor(); + auto *CPI = cast(CatchPadBB->getFirstNonPHI()); + CPI->setArgOperand(1, var.getObjectAddress(CGF)); + } CGF.EHStack.pushCleanup(NormalCleanup); CGF.EmitAutoVarCleanups(var); } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1516,6 +1516,7 @@ Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); + Opts.NewMSEH = Args.hasArg(OPT_fnew_ms_eh); Opts.TraditionalCPP = Args.hasArg(OPT_traditional_cpp); Opts.RTTI = !Args.hasArg(OPT_fno_rtti);