summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/CodeGen/Passes.h4
-rw-r--r--llvm/include/llvm/InitializePasses.h1
-rw-r--r--llvm/lib/CodeGen/CMakeLists.txt1
-rw-r--r--llvm/lib/CodeGen/Passes.cpp4
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp106
-rw-r--r--llvm/test/CodeGen/X86/seh-safe-div.ll5
-rw-r--r--llvm/test/CodeGen/X86/win_eh_prepare.ll80
-rw-r--r--llvm/tools/opt/opt.cpp1
8 files changed, 199 insertions, 3 deletions
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index bff58e12fe5..7e5e9008320 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -573,6 +573,10 @@ namespace llvm {
/// adapted to code generation. Required if using dwarf exception handling.
FunctionPass *createDwarfEHPass(const TargetMachine *TM);
+ /// createWinEHPass - Prepares personality functions used by MSVC on Windows,
+ /// in addition to the Itanium LSDA based personalities.
+ FunctionPass *createWinEHPass(const TargetMachine *TM);
+
/// createSjLjEHPreparePass - This pass adapts exception handling code to use
/// the GCC-style builtin setjmp/longjmp (sjlj) to handling EH control flow.
///
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 91884097504..6a6d48cc42f 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -289,6 +289,7 @@ void initializeStackMapLivenessPass(PassRegistry&);
void initializeMachineCombinerPass(PassRegistry &);
void initializeLoadCombinePass(PassRegistry&);
void initializeRewriteSymbolsPass(PassRegistry&);
+void initializeWinEHPreparePass(PassRegistry&);
}
#endif
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 8df2042d68b..417da69f543 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -118,6 +118,7 @@ add_llvm_library(LLVMCodeGen
TwoAddressInstructionPass.cpp
UnreachableBlockElim.cpp
VirtRegMap.cpp
+ WinEHPrepare.cpp
)
add_dependencies(LLVMCodeGen intrinsics_gen)
diff --git a/llvm/lib/CodeGen/Passes.cpp b/llvm/lib/CodeGen/Passes.cpp
index c66d2131f8f..b9dd0f78c81 100644
--- a/llvm/lib/CodeGen/Passes.cpp
+++ b/llvm/lib/CodeGen/Passes.cpp
@@ -450,9 +450,11 @@ void TargetPassConfig::addPassesToHandleExceptions() {
// FALLTHROUGH
case ExceptionHandling::DwarfCFI:
case ExceptionHandling::ARM:
- case ExceptionHandling::WinEH:
addPass(createDwarfEHPass(TM));
break;
+ case ExceptionHandling::WinEH:
+ addPass(createWinEHPass(TM));
+ break;
case ExceptionHandling::None:
addPass(createLowerInvokePass());
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
new file mode 100644
index 00000000000..a01adcd43d0
--- /dev/null
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -0,0 +1,106 @@
+//===-- WinEHPrepare - Prepare exception handling for code generation ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass lowers LLVM IR exception handling into something closer to what the
+// backend wants. It snifs the personality function to see which kind of
+// preparation is necessary. If the personality function uses the Itanium LSDA,
+// this pass delegates to the DWARF EH preparation pass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/Analysis/LibCallSemantics.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/Pass.h"
+#include "llvm/Target/TargetLowering.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "winehprepare"
+
+namespace {
+class WinEHPrepare : public FunctionPass {
+ const TargetMachine *TM;
+ FunctionPass *DwarfPrepare;
+
+public:
+ static char ID; // Pass identification, replacement for typeid.
+ WinEHPrepare(const TargetMachine *TM = nullptr)
+ : FunctionPass(ID), TM(TM), DwarfPrepare(createDwarfEHPass(TM)) {
+ initializeDominatorTreeWrapperPassPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &Fn) override;
+
+ bool doFinalization(Module &M) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+ const char *getPassName() const override {
+ return "Windows exception handling preparation";
+ }
+};
+} // end anonymous namespace
+
+char WinEHPrepare::ID = 0;
+INITIALIZE_TM_PASS(WinEHPrepare, "winehprepare",
+ "Prepare Windows exceptions", false, false)
+
+FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) {
+ return new WinEHPrepare(TM);
+}
+
+static bool isMSVCPersonality(EHPersonality Pers) {
+ return Pers == EHPersonality::MSVC_Win64SEH ||
+ Pers == EHPersonality::MSVC_CXX;
+}
+
+bool WinEHPrepare::runOnFunction(Function &Fn) {
+ SmallVector<LandingPadInst *, 4> LPads;
+ SmallVector<ResumeInst *, 4> Resumes;
+ for (BasicBlock &BB : Fn) {
+ if (auto *LP = BB.getLandingPadInst())
+ LPads.push_back(LP);
+ if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))
+ Resumes.push_back(Resume);
+ }
+
+ // No need to prepare functions that lack landing pads.
+ if (LPads.empty())
+ return false;
+
+ // Classify the personality to see what kind of preparation we need.
+ EHPersonality Pers = ClassifyEHPersonality(LPads.back()->getPersonalityFn());
+
+ // Delegate through to the DWARF pass if this is unrecognized.
+ if (!isMSVCPersonality(Pers))
+ return DwarfPrepare->runOnFunction(Fn);
+
+ // FIXME: Cleanups are unimplemented. Replace them with calls to @llvm.trap.
+ if (Resumes.empty())
+ return false;
+
+ Function *Trap =
+ Intrinsic::getDeclaration(Fn.getParent(), Intrinsic::trap, None);
+ for (ResumeInst *Resume : Resumes) {
+ IRBuilder<>(Resume).CreateUnreachable();
+ Resume->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool WinEHPrepare::doFinalization(Module &M) {
+ return DwarfPrepare->doFinalization(M);
+}
+
+void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
+ DwarfPrepare->getAnalysisUsage(AU);
+}
diff --git a/llvm/test/CodeGen/X86/seh-safe-div.ll b/llvm/test/CodeGen/X86/seh-safe-div.ll
index e911df04ded..e294f24f28b 100644
--- a/llvm/test/CodeGen/X86/seh-safe-div.ll
+++ b/llvm/test/CodeGen/X86/seh-safe-div.ll
@@ -96,8 +96,9 @@ __try.cont:
; CHECK: movl $-2, [[rloc]]
; CHECK: jmp .LBB0_7
-; FIXME: EH preparation should not call _Unwind_Resume.
-; CHECK: callq _Unwind_Resume
+; FIXME: EH preparation should eliminate the 'resume' instr and we should not do
+; the previous 'cmp;jeq'.
+; CHECK-NOT: _Unwind_Resume
; CHECK: ud2
; CHECK: .seh_handlerdata
diff --git a/llvm/test/CodeGen/X86/win_eh_prepare.ll b/llvm/test/CodeGen/X86/win_eh_prepare.ll
new file mode 100644
index 00000000000..f96fed5095f
--- /dev/null
+++ b/llvm/test/CodeGen/X86/win_eh_prepare.ll
@@ -0,0 +1,80 @@
+; RUN: opt -S -winehprepare -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s
+
+; FIXME: Add and test outlining here.
+
+declare void @maybe_throw()
+
+@_ZTIi = external constant i8*
+@g = external global i32
+
+declare i32 @__C_specific_handler(...)
+declare i32 @__gxx_personality_seh0(...)
+declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
+
+define i32 @use_seh() {
+entry:
+ invoke void @maybe_throw()
+ to label %cont unwind label %lpad
+
+cont:
+ ret i32 0
+
+lpad:
+ %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler
+ cleanup
+ catch i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*)
+ %ehsel = extractvalue { i8*, i32 } %ehvals, 1
+ %filt_g_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*))
+ %matches = icmp eq i32 %ehsel, %filt_g_sel
+ br i1 %matches, label %ret1, label %eh.resume
+
+ret1:
+ ret i32 1
+
+eh.resume:
+ resume { i8*, i32 } %ehvals
+}
+
+define internal i32 @filt_g(i8*, i8*) {
+ %g = load i32* @g
+ ret i32 %g
+}
+
+; CHECK-LABEL: define i32 @use_seh()
+; CHECK: invoke void @maybe_throw()
+; CHECK-NEXT: to label %cont unwind label %lpad
+; CHECK: eh.resume:
+; CHECK-NEXT: unreachable
+
+
+; A MinGW64-ish EH style. It could happen if a binary uses both MSVC CRT and
+; mingw CRT and is linked with LTO.
+define i32 @use_gcc() {
+entry:
+ invoke void @maybe_throw()
+ to label %cont unwind label %lpad
+
+cont:
+ ret i32 0
+
+lpad:
+ %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_seh0
+ cleanup
+ catch i8* bitcast (i8** @_ZTIi to i8*)
+ %ehsel = extractvalue { i8*, i32 } %ehvals, 1
+ %filt_g_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*))
+ %matches = icmp eq i32 %ehsel, %filt_g_sel
+ br i1 %matches, label %ret1, label %eh.resume
+
+ret1:
+ ret i32 1
+
+eh.resume:
+ resume { i8*, i32 } %ehvals
+}
+
+; CHECK-LABEL: define i32 @use_gcc()
+; CHECK: invoke void @maybe_throw()
+; CHECK-NEXT: to label %cont unwind label %lpad
+; CHECK: eh.resume:
+; CHECK: call void @_Unwind_Resume(i8* %exn.obj)
diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp
index 3cd07c53e5d..6083e7a70a8 100644
--- a/llvm/tools/opt/opt.cpp
+++ b/llvm/tools/opt/opt.cpp
@@ -322,6 +322,7 @@ int main(int argc, char **argv) {
initializeCodeGenPreparePass(Registry);
initializeAtomicExpandPass(Registry);
initializeRewriteSymbolsPass(Registry);
+ initializeWinEHPreparePass(Registry);
#ifdef LINK_POLLY_INTO_TOOLS
polly::initializePollyPasses(Registry);
OpenPOWER on IntegriCloud