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">,
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.
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
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.
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);
class CommonBitFields {
friend class EHScope;
- unsigned Kind : 2;
+ unsigned Kind : 3;
};
- enum { NumCommonBits = 2 };
+ enum { NumCommonBits = 3 };
protected:
class CatchBitFields {
/// 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 {
};
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),
}
};
+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;
case EHScope::Terminate:
Size = EHTerminateScope::getSize();
break;
+
+ case EHScope::CatchEnd:
+ Size = EHCatchEndScope::getSize();
+ break;
}
Ptr += llvm::RoundUpToAlignment(Size, ScopeStackAlignment);
return *this;
deallocate(EHTerminateScope::getSize());
}
+inline void EHScopeStack::popCatchEnd() {
+ assert(!empty() && "popping exception stack when not empty");
+
+ EHCatchEndScope &scope = cast<EHCatchEndScope>(*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");
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; }
};
}
}
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())
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.
case EHScope::Filter:
case EHScope::Catch:
case EHScope::Terminate:
+ case EHScope::CatchEnd:
return false;
}
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
case EHScope::Terminate:
return getTerminateLandingPad();
+ case EHScope::CatchEnd:
+ llvm_unreachable("CatchEnd unnecessary for Itanium!");
+
case EHScope::Catch:
case EHScope::Cleanup:
case EHScope::Filter:
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);
case EHScope::Catch:
break;
+
+ case EHScope::CatchEnd:
+ llvm_unreachable("CatchEnd unnecessary for Itanium!");
}
EHCatchScope &catchScope = cast<EHCatchScope>(*I);
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);
if (catchScope.getNumHandlers() == 1 &&
catchScope.getHandler(0).isCatchAll()) {
assert(dispatchBlock == catchScope.getHandler(0).Block);
- return;
+ return nullptr;
}
CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveIP();
// 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() {
}
// 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.
doImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
isa<CXXConstructorDecl>(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
EmitBlock(ContBB);
incrementProfileCounter(&S);
+ if (CatchEndBlockBB)
+ EHStack.popCatchEnd();
}
namespace {
// 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);
// can't do this on functions that can be overwritten.
if (F->mayBeOverridden()) return;
- for (llvm::Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI)
- for (llvm::BasicBlock::iterator
- BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
- if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(&*BI)) {
- if (!Call->doesNotThrow())
- return;
- } else if (isa<llvm::ResumeInst>(&*BI)) {
+ for (llvm::BasicBlock &BB : *F)
+ for (llvm::Instruction &I : BB)
+ if (I.mayThrow())
return;
- }
+
F->setDoesNotThrow();
}
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 {
/// 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;
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));
+ }
}
};
}
// 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<CallEndCatchMSVC>(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<llvm::CatchPadInst>(CatchPadBB->getFirstNonPHI());
+ CPI->setArgOperand(1, var.getObjectAddress(CGF));
+ }
CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalCleanup);
CGF.EmitAutoVarCleanups(var);
}
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);