[WinEH] Allow for multiple terminatepads
Fixes verifier errors with Windows EH and OpenMP, which injects a
terminate scope around parallel blocks.
Fixes PR35778
llvm-svn: 321676
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 1ec084f..1978d27 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -646,7 +646,7 @@
return DispatchBlock;
if (EHS.getKind() == EHScope::Terminate)
- DispatchBlock = getTerminateHandler();
+ DispatchBlock = getTerminateFunclet();
else
DispatchBlock = createBasicBlock();
CGBuilderTy Builder(*this, DispatchBlock);
@@ -1334,24 +1334,15 @@
if (TerminateHandler)
return TerminateHandler;
- CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
-
// Set up the terminate handler. This block is inserted at the very
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
+ CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
Builder.SetInsertPoint(TerminateHandler);
+
llvm::Value *Exn = nullptr;
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
- if (EHPersonality::get(*this).usesFuncletPads()) {
- llvm::Value *ParentPad = CurrentFuncletPad;
- if (!ParentPad)
- ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
- CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad);
- } else {
- if (getLangOpts().CPlusPlus)
- Exn = getExceptionFromSlot();
- }
+ if (getLangOpts().CPlusPlus)
+ Exn = getExceptionFromSlot();
llvm::CallInst *terminateCall =
CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);
terminateCall->setDoesNotReturn();
@@ -1363,6 +1354,42 @@
return TerminateHandler;
}
+llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() {
+ assert(EHPersonality::get(*this).usesFuncletPads() &&
+ "use getTerminateLandingPad for non-funclet EH");
+
+ llvm::BasicBlock *&TerminateFunclet = TerminateFunclets[CurrentFuncletPad];
+ if (TerminateFunclet)
+ return TerminateFunclet;
+
+ CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
+
+ // Set up the terminate handler. This block is inserted at the very
+ // end of the function by FinishFunction.
+ TerminateFunclet = createBasicBlock("terminate.handler");
+ Builder.SetInsertPoint(TerminateFunclet);
+
+ // Create the cleanuppad using the current parent pad as its token. Use 'none'
+ // if this is a top-level terminate scope, which is the common case.
+ SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
+ CurrentFuncletPad);
+ llvm::Value *ParentPad = CurrentFuncletPad;
+ if (!ParentPad)
+ ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
+ CurrentFuncletPad = Builder.CreateCleanupPad(ParentPad);
+
+ // Emit the __std_terminate call.
+ llvm::CallInst *terminateCall =
+ CGM.getCXXABI().emitTerminateForUnexpectedException(*this, nullptr);
+ terminateCall->setDoesNotReturn();
+ Builder.CreateUnreachable();
+
+ // Restore the saved insertion state.
+ Builder.restoreIP(SavedIP);
+
+ return TerminateFunclet;
+}
+
llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
if (EHResumeBlock) return EHResumeBlock;
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 9dbd7cc..664b510 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -419,6 +419,9 @@
EmitIfUsed(*this, TerminateHandler);
EmitIfUsed(*this, UnreachableBlock);
+ for (const auto &FuncletAndParent : TerminateFunclets)
+ EmitIfUsed(*this, FuncletAndParent.second);
+
if (CGM.getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a7c322d..3e89586 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -34,6 +34,7 @@
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
@@ -1420,6 +1421,9 @@
llvm::BasicBlock *TerminateHandler;
llvm::BasicBlock *TrapBB;
+ /// Terminate funclets keyed by parent funclet pad.
+ llvm::MapVector<llvm::Value *, llvm::BasicBlock *> TerminateFunclets;
+
/// True if we need emit the life-time markers.
const bool ShouldEmitLifetimeMarkers;
@@ -1808,6 +1812,10 @@
/// getTerminateLandingPad - Return a landing pad that just calls terminate.
llvm::BasicBlock *getTerminateLandingPad();
+ /// getTerminateLandingPad - Return a cleanup funclet that just calls
+ /// terminate.
+ llvm::BasicBlock *getTerminateFunclet();
+
/// getTerminateHandler - Return a handler (not a landing pad, just
/// a catch handler) that just calls terminate. This is used when
/// a terminate scope encloses a try.