summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2015-10-28 23:06:42 +0000
committerReid Kleckner <rnk@google.com>2015-10-28 23:06:42 +0000
commita002bd544c52c6033d973123874c1fa57a85f455 (patch)
tree09fa69d77e4d9049b06e5ff2ad74ac984c140bcd /clang/lib
parentbdd292ae22739b77abd36b459df2aaf181195ba4 (diff)
downloadbcm5719-llvm-a002bd544c52c6033d973123874c1fa57a85f455.tar.gz
bcm5719-llvm-a002bd544c52c6033d973123874c1fa57a85f455.zip
[WinEH] Mark calls inside cleanups as noinline
This works around PR25162. The MSVC tables make it very difficult to correctly inline a C++ destructor that contains try / catch. We've attempted to address PR25162 in LLVM's backend, but it feels pretty infeasible. MSVC and ICC both appear to avoid inlining such complex destructors. Long term, we want to fix this by making the inliner smart enough to know when it is inlining into a cleanup, so it can inline simple destructors (~unique_ptr and ~vector) while avoiding destructors containing try / catch. llvm-svn: 251576
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGCall.cpp10
-rw-r--r--clang/lib/CodeGen/CGCleanup.cpp23
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h5
3 files changed, 27 insertions, 11 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 8a2006f18e7..05fbfa0e9ff 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3440,8 +3440,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
llvm::Attribute::AlwaysInline);
- // Disable inlining inside SEH __try blocks.
- if (isSEHTryScope())
+ // Disable inlining inside SEH __try blocks and cleanup funclets. None of the
+ // funclet EH personalities that clang supports have tables that are
+ // expressive enough to describe catching an exception inside a cleanup.
+ // __CxxFrameHandler3, for example, will terminate the program without
+ // catching it.
+ // FIXME: Move this decision to the LLVM inliner. Before we can do that, the
+ // inliner needs to know if a given call site is part of a cleanuppad.
+ if (isSEHTryScope() || isCleanupPadScope())
Attrs =
Attrs.addAttribute(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoInline);
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 5217e24a52f..f1f6a8b8f32 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -19,6 +19,7 @@
#include "CGCleanup.h"
#include "CodeGenFunction.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace CodeGen;
@@ -902,19 +903,19 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EmitBlock(EHEntry);
- // Push terminate scopes around the potentially throwing destructor calls.
- // We don't emit these when using funclets, because the runtime does it for
- // us as part of unwinding out of a cleanuppad.
+ llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent);
+
+ // Push a terminate scope or cleanupendpad scope around the potentially
+ // throwing cleanups. For funclet EH personalities, the cleanupendpad models
+ // program termination when cleanups throw.
bool PushedTerminate = false;
+ SaveAndRestore<bool> RestoreIsCleanupPadScope(IsCleanupPadScope);
+ llvm::CleanupPadInst *CPI = nullptr;
+ llvm::BasicBlock *CleanupEndBB = nullptr;
if (!EHPersonality::get(*this).usesFuncletPads()) {
EHStack.pushTerminate();
PushedTerminate = true;
- }
-
- llvm::CleanupPadInst *CPI = nullptr;
- llvm::BasicBlock *CleanupEndBB = nullptr;
- llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent);
- if (EHPersonality::get(*this).usesFuncletPads()) {
+ } else {
CPI = Builder.CreateCleanupPad({});
// Build a cleanupendpad to unwind through. Our insertion point should be
@@ -922,6 +923,10 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
CleanupEndBB = createBasicBlock("ehcleanup.end");
CGBuilderTy(*this, CleanupEndBB).CreateCleanupEndPad(CPI, NextAction);
EHStack.pushPadEnd(CleanupEndBB);
+
+ // Mark that we're inside a cleanuppad to block inlining.
+ // FIXME: Remove this once the inliner knows when it's safe to do so.
+ IsCleanupPadScope = true;
}
// We only actually emit the cleanup code if the cleanup is either
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 5d5c7f50536..214fd45205a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -279,6 +279,8 @@ public:
/// finally block or filter expression.
bool IsOutlinedSEHHelper;
+ bool IsCleanupPadScope = false;
+
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@@ -372,6 +374,9 @@ public:
/// Returns true inside SEH __try blocks.
bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }
+ /// Returns true while emitting a cleanuppad.
+ bool isCleanupPadScope() const { return IsCleanupPadScope; }
+
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
/// we're currently inside a conditionally-evaluated expression.
OpenPOWER on IntegriCloud