majnemer created this revision.
majnemer added a reviewer: rnk.
majnemer added a subscriber: cfe-commits.
The new EH instructions make it possible for LLVM to generate .xdata
tables that the MSVC personality routines will be happy about. Because
this is experimental, hide it behind a -cc1 flag (-fnew-ms-eh).
http://reviews.llvm.org/D11405
Files:
include/clang/Basic/LangOptions.def
include/clang/Driver/CC1Options.td
lib/CodeGen/CGCleanup.cpp
lib/CodeGen/CGCleanup.h
lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/EHScopeStack.h
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Frontend/CompilerInvocation.cpp
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);
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<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);
}
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/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/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<EHCatchScope>(*I);
@@ -820,19 +892,70 @@
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);
// If there's only a single catch-all, getEHDispatchBlock returned
// that catch-all as the dispatch block.
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<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
@@ -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/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<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");
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: 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/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")
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits