[llvm] r227405 - Add a Windows EH preparation pass that zaps resumes

Alexey Samsonov vonosmas at gmail.com
Thu Jan 29 13:40:42 PST 2015


This change breaks ASan bootstrap of LLVM:
http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/1113/steps/check-llvm%20asan/logs/stdio


On Wed, Jan 28, 2015 at 4:41 PM, Reid Kleckner <reid at kleckner.net> wrote:

> Author: rnk
> Date: Wed Jan 28 18:41:44 2015
> New Revision: 227405
>
> URL: http://llvm.org/viewvc/llvm-project?rev=227405&view=rev
> Log:
> Add a Windows EH preparation pass that zaps resumes
>
> If the personality is not a recognized MSVC personality function, this
> pass delegates to the dwarf EH preparation pass. This chaining supports
> people on *-windows-itanium or *-windows-gnu targets.
>
> Currently this recognizes some personalities used by MSVC and turns
> resume instructions into traps to avoid link errors.  Even if cleanups
> are not used in the source program, LLVM requires the frontend to emit a
> code path that resumes unwinding after an exception.  Clang does this,
> and we get unreachable resume instructions. PR20300 covers cleaning up
> these unreachable calls to resume.
>
> Reviewers: majnemer
>
> Differential Revision: http://reviews.llvm.org/D7216
>
> Added:
>     llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
>     llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll
> Modified:
>     llvm/trunk/include/llvm/CodeGen/Passes.h
>     llvm/trunk/include/llvm/InitializePasses.h
>     llvm/trunk/lib/CodeGen/CMakeLists.txt
>     llvm/trunk/lib/CodeGen/Passes.cpp
>     llvm/trunk/test/CodeGen/X86/seh-safe-div.ll
>     llvm/trunk/tools/opt/opt.cpp
>
> Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=227405&r1=227404&r2=227405&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/Passes.h Wed Jan 28 18:41:44 2015
> @@ -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.
>    ///
>
> Modified: llvm/trunk/include/llvm/InitializePasses.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=227405&r1=227404&r2=227405&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/InitializePasses.h (original)
> +++ llvm/trunk/include/llvm/InitializePasses.h Wed Jan 28 18:41:44 2015
> @@ -289,6 +289,7 @@ void initializeStackMapLivenessPass(Pass
>  void initializeMachineCombinerPass(PassRegistry &);
>  void initializeLoadCombinePass(PassRegistry&);
>  void initializeRewriteSymbolsPass(PassRegistry&);
> +void initializeWinEHPreparePass(PassRegistry&);
>  }
>
>  #endif
>
> Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=227405&r1=227404&r2=227405&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)
> +++ llvm/trunk/lib/CodeGen/CMakeLists.txt Wed Jan 28 18:41:44 2015
> @@ -118,6 +118,7 @@ add_llvm_library(LLVMCodeGen
>    TwoAddressInstructionPass.cpp
>    UnreachableBlockElim.cpp
>    VirtRegMap.cpp
> +  WinEHPrepare.cpp
>    )
>
>  add_dependencies(LLVMCodeGen intrinsics_gen)
>
> Modified: llvm/trunk/lib/CodeGen/Passes.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/Passes.cpp?rev=227405&r1=227404&r2=227405&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/Passes.cpp (original)
> +++ llvm/trunk/lib/CodeGen/Passes.cpp Wed Jan 28 18:41:44 2015
> @@ -450,9 +450,11 @@ void TargetPassConfig::addPassesToHandle
>      // 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());
>
>
> Added: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=227405&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (added)
> +++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Wed Jan 28 18:41:44 2015
> @@ -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;
>

^^
Shouldn't this be a std::unique_ptr?


> +
> +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);
> +}
>
> Modified: llvm/trunk/test/CodeGen/X86/seh-safe-div.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/seh-safe-div.ll?rev=227405&r1=227404&r2=227405&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/X86/seh-safe-div.ll (original)
> +++ llvm/trunk/test/CodeGen/X86/seh-safe-div.ll Wed Jan 28 18:41:44 2015
> @@ -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
>
> Added: llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll?rev=227405&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll (added)
> +++ llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll Wed Jan 28 18:41:44 2015
> @@ -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()
> +
> + at _ZTIi = external constant i8*
> + at 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)
>
> Modified: llvm/trunk/tools/opt/opt.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/opt.cpp?rev=227405&r1=227404&r2=227405&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/opt/opt.cpp (original)
> +++ llvm/trunk/tools/opt/opt.cpp Wed Jan 28 18:41:44 2015
> @@ -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);
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>



-- 
Alexey Samsonov
vonosmas at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150129/7d7c9264/attachment.html>


More information about the llvm-commits mailing list