Index: include/llvm/CodeGen/Passes.h =================================================================== --- include/llvm/CodeGen/Passes.h +++ include/llvm/CodeGen/Passes.h @@ -569,6 +569,10 @@ /// 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. /// Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -117,6 +117,7 @@ TwoAddressInstructionPass.cpp UnreachableBlockElim.cpp VirtRegMap.cpp + WinEHPrepare.cpp ) add_dependencies(LLVMCodeGen intrinsics_gen) Index: lib/CodeGen/Passes.cpp =================================================================== --- lib/CodeGen/Passes.cpp +++ lib/CodeGen/Passes.cpp @@ -447,9 +447,11 @@ // 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()); Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- /dev/null +++ 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) + : 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; + +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 LPads; + SmallVector Resumes; + for (BasicBlock &BB : Fn) { + if (auto *LP = BB.getLandingPadInst()) + LPads.push_back(LP); + if (auto *Resume = dyn_cast(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[0]->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<> Builder(Resume); + Builder.CreateCall(Trap); + Builder.CreateUnreachable(); + Resume->eraseFromParent(); + } + + return true; +} + +bool WinEHPrepare::doFinalization(Module &M) { + return DwarfPrepare->doFinalization(M); +} + +void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const { + DwarfPrepare->getAnalysisUsage(AU); +} Index: test/CodeGen/X86/seh-safe-div.ll =================================================================== --- test/CodeGen/X86/seh-safe-div.ll +++ test/CodeGen/X86/seh-safe-div.ll @@ -96,8 +96,8 @@ ; 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: ud2 ; CHECK: .seh_handlerdata