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: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -33,6 +33,7 @@ CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm. CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe. +CODEGENOPT(NewMSEH , 1, 0) ///< Whether we should use the new IR representation for MS exceptions CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files. CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files. CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files. Index: lib/CodeGen/CGCleanup.h =================================================================== --- lib/CodeGen/CGCleanup.h +++ lib/CodeGen/CGCleanup.h @@ -40,9 +40,9 @@ class CommonBitFields { friend class EHScope; - unsigned Kind : 2; + unsigned Kind : 3; }; - enum { NumCommonBits = 2 }; + enum { NumCommonBits = 3 }; protected: class CatchBitFields { @@ -81,7 +81,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 { @@ -99,7 +99,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), @@ -466,6 +466,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; @@ -503,6 +514,10 @@ case EHScope::Terminate: Size = EHTerminateScope::getSize(); break; + + case EHScope::CatchEnd: + Size = EHCatchEndScope::getSize(); + break; } Ptr += llvm::RoundUpToAlignment(Size, ScopeStackAlignment); return *this; @@ -551,6 +566,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"); @@ -588,6 +611,13 @@ 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; } }; } } 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,14 @@ CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); EmitBlock(EHEntry); + llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent); + if (CGM.getCodeGenOpts().NewMSEH && + EHPersonality::get(*this).isMSVCPersonality()) { + 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 +920,10 @@ EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); } - Builder.CreateBr(getEHDispatchBlock(EHParent)); + if (CGM.getCodeGenOpts().NewMSEH && EHPersonality::get(*this).isMSVCPersonality()) + Builder.CreateCleanupRet(NextAction); + else + Builder.CreateBr(NextAction); Builder.restoreIP(SavedIP); Index: lib/CodeGen/CGException.cpp =================================================================== --- lib/CodeGen/CGException.cpp +++ lib/CodeGen/CGException.cpp @@ -559,6 +559,10 @@ llvm::BasicBlock * CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { + if (CGM.getCodeGenOpts().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()) @@ -595,12 +599,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. @@ -611,6 +661,7 @@ case EHScope::Filter: case EHScope::Catch: case EHScope::Terminate: + case EHScope::CatchEnd: return false; } @@ -636,8 +687,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.getCodeGenOpts().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 @@ -658,6 +720,9 @@ case EHScope::Terminate: return getTerminateLandingPad(); + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); + case EHScope::Catch: case EHScope::Cleanup: case EHScope::Filter: @@ -669,11 +734,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); @@ -728,6 +788,9 @@ case EHScope::Catch: break; + + case EHScope::CatchEnd: + llvm_unreachable("CatchEnd unnecessary for Itanium!"); } EHCatchScope &catchScope = cast(*I); @@ -792,10 +855,63 @@ 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) { +/// If the catchblock instructions are used for EH dispatch, then the basic +/// block holding the final catchendblock instruction is returned. +static llvm::BasicBlock *emitCatchDispatchBlock(CodeGenFunction &CGF, + EHCatchScope &catchScope) { + if (CGF.CGM.getCodeGenOpts().NewMSEH && + EHPersonality::get(CGF).isMSVCPersonality()) + return emitMSVCCatchDispatchBlock(CGF, catchScope); + llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock(); assert(dispatchBlock); @@ -804,7 +920,7 @@ if (catchScope.getNumHandlers() == 1 && catchScope.getHandler(0).isCatchAll()) { assert(dispatchBlock == catchScope.getHandler(0).Block); - return; + return nullptr; } CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP(); @@ -860,11 +976,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() { @@ -887,7 +1004,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. @@ -911,6 +1028,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 @@ -963,6 +1083,8 @@ EmitBlock(ContBB); incrementProfileCounter(&S); + if (CatchEndBlockBB) + EHStack.popCatchEnd(); } namespace { @@ -1200,13 +1322,18 @@ // 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.getCodeGenOpts().NewMSEH && + EHPersonality::get(*this).isMSVCPersonality()) { + 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.getCodeGenOpts().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.getCodeGenOpts().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 @@ -456,6 +456,7 @@ Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); + Opts.NewMSEH = Args.hasArg(OPT_fnew_ms_eh); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getCodeModel(Args, Diags);