<div dir="ltr">This change breaks ASan bootstrap of LLVM: <a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/1113/steps/check-llvm%20asan/logs/stdio">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/1113/steps/check-llvm%20asan/logs/stdio</a><div><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 28, 2015 at 4:41 PM, Reid Kleckner <span dir="ltr"><<a href="mailto:reid@kleckner.net" target="_blank">reid@kleckner.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rnk<br>
Date: Wed Jan 28 18:41:44 2015<br>
New Revision: 227405<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=227405&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=227405&view=rev</a><br>
Log:<br>
Add a Windows EH preparation pass that zaps resumes<br>
<br>
If the personality is not a recognized MSVC personality function, this<br>
pass delegates to the dwarf EH preparation pass. This chaining supports<br>
people on *-windows-itanium or *-windows-gnu targets.<br>
<br>
Currently this recognizes some personalities used by MSVC and turns<br>
resume instructions into traps to avoid link errors.  Even if cleanups<br>
are not used in the source program, LLVM requires the frontend to emit a<br>
code path that resumes unwinding after an exception.  Clang does this,<br>
and we get unreachable resume instructions. PR20300 covers cleaning up<br>
these unreachable calls to resume.<br>
<br>
Reviewers: majnemer<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D7216" target="_blank">http://reviews.llvm.org/D7216</a><br>
<br>
Added:<br>
    llvm/trunk/lib/CodeGen/WinEHPrepare.cpp<br>
    llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll<br>
Modified:<br>
    llvm/trunk/include/llvm/CodeGen/Passes.h<br>
    llvm/trunk/include/llvm/InitializePasses.h<br>
    llvm/trunk/lib/CodeGen/CMakeLists.txt<br>
    llvm/trunk/lib/CodeGen/Passes.cpp<br>
    llvm/trunk/test/CodeGen/X86/seh-safe-div.ll<br>
    llvm/trunk/tools/opt/opt.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/CodeGen/Passes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=227405&r1=227404&r2=227405&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=227405&r1=227404&r2=227405&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/CodeGen/Passes.h (original)<br>
+++ llvm/trunk/include/llvm/CodeGen/Passes.h Wed Jan 28 18:41:44 2015<br>
@@ -573,6 +573,10 @@ namespace llvm {<br>
   /// adapted to code generation.  Required if using dwarf exception handling.<br>
   FunctionPass *createDwarfEHPass(const TargetMachine *TM);<br>
<br>
+  /// createWinEHPass - Prepares personality functions used by MSVC on Windows,<br>
+  /// in addition to the Itanium LSDA based personalities.<br>
+  FunctionPass *createWinEHPass(const TargetMachine *TM);<br>
+<br>
   /// createSjLjEHPreparePass - This pass adapts exception handling code to use<br>
   /// the GCC-style builtin setjmp/longjmp (sjlj) to handling EH control flow.<br>
   ///<br>
<br>
Modified: llvm/trunk/include/llvm/InitializePasses.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=227405&r1=227404&r2=227405&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=227405&r1=227404&r2=227405&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/InitializePasses.h (original)<br>
+++ llvm/trunk/include/llvm/InitializePasses.h Wed Jan 28 18:41:44 2015<br>
@@ -289,6 +289,7 @@ void initializeStackMapLivenessPass(Pass<br>
 void initializeMachineCombinerPass(PassRegistry &);<br>
 void initializeLoadCombinePass(PassRegistry&);<br>
 void initializeRewriteSymbolsPass(PassRegistry&);<br>
+void initializeWinEHPreparePass(PassRegistry&);<br>
 }<br>
<br>
 #endif<br>
<br>
Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=227405&r1=227404&r2=227405&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=227405&r1=227404&r2=227405&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/CodeGen/CMakeLists.txt Wed Jan 28 18:41:44 2015<br>
@@ -118,6 +118,7 @@ add_llvm_library(LLVMCodeGen<br>
   TwoAddressInstructionPass.cpp<br>
   UnreachableBlockElim.cpp<br>
   VirtRegMap.cpp<br>
+  WinEHPrepare.cpp<br>
   )<br>
<br>
 add_dependencies(LLVMCodeGen intrinsics_gen)<br>
<br>
Modified: llvm/trunk/lib/CodeGen/Passes.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/Passes.cpp?rev=227405&r1=227404&r2=227405&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/Passes.cpp?rev=227405&r1=227404&r2=227405&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/Passes.cpp (original)<br>
+++ llvm/trunk/lib/CodeGen/Passes.cpp Wed Jan 28 18:41:44 2015<br>
@@ -450,9 +450,11 @@ void TargetPassConfig::addPassesToHandle<br>
     // FALLTHROUGH<br>
   case ExceptionHandling::DwarfCFI:<br>
   case ExceptionHandling::ARM:<br>
-  case ExceptionHandling::WinEH:<br>
     addPass(createDwarfEHPass(TM));<br>
     break;<br>
+  case ExceptionHandling::WinEH:<br>
+    addPass(createWinEHPass(TM));<br>
+    break;<br>
   case ExceptionHandling::None:<br>
     addPass(createLowerInvokePass());<br>
<br>
<br>
Added: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=227405&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=227405&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (added)<br>
+++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Wed Jan 28 18:41:44 2015<br>
@@ -0,0 +1,106 @@<br>
+//===-- WinEHPrepare - Prepare exception handling for code generation ---===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This pass lowers LLVM IR exception handling into something closer to what the<br>
+// backend wants. It snifs the personality function to see which kind of<br>
+// preparation is necessary. If the personality function uses the Itanium LSDA,<br>
+// this pass delegates to the DWARF EH preparation pass.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "llvm/CodeGen/Passes.h"<br>
+#include "llvm/Analysis/LibCallSemantics.h"<br>
+#include "llvm/IR/Function.h"<br>
+#include "llvm/IR/Instructions.h"<br>
+#include "llvm/IR/Intrinsics.h"<br>
+#include "llvm/Pass.h"<br>
+#include "llvm/Target/TargetLowering.h"<br>
+using namespace llvm;<br>
+<br>
+#define DEBUG_TYPE "winehprepare"<br>
+<br>
+namespace {<br>
+class WinEHPrepare : public FunctionPass {<br>
+  const TargetMachine *TM;<br>
+  FunctionPass *DwarfPrepare;<br></blockquote><div><br></div><div>^^</div><div>Shouldn't this be a std::unique_ptr?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+public:<br>
+  static char ID; // Pass identification, replacement for typeid.<br>
+  WinEHPrepare(const TargetMachine *TM = nullptr)<br>
+      : FunctionPass(ID), TM(TM), DwarfPrepare(createDwarfEHPass(TM)) {<br>
+    initializeDominatorTreeWrapperPassPass(*PassRegistry::getPassRegistry());<br>
+  }<br>
+<br>
+  bool runOnFunction(Function &Fn) override;<br>
+<br>
+  bool doFinalization(Module &M) override;<br>
+<br>
+  void getAnalysisUsage(AnalysisUsage &AU) const override;<br>
+<br>
+  const char *getPassName() const override {<br>
+    return "Windows exception handling preparation";<br>
+  }<br>
+};<br>
+} // end anonymous namespace<br>
+<br>
+char WinEHPrepare::ID = 0;<br>
+INITIALIZE_TM_PASS(WinEHPrepare, "winehprepare",<br>
+                   "Prepare Windows exceptions", false, false)<br>
+<br>
+FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) {<br>
+  return new WinEHPrepare(TM);<br>
+}<br>
+<br>
+static bool isMSVCPersonality(EHPersonality Pers) {<br>
+  return Pers == EHPersonality::MSVC_Win64SEH ||<br>
+         Pers == EHPersonality::MSVC_CXX;<br>
+}<br>
+<br>
+bool WinEHPrepare::runOnFunction(Function &Fn) {<br>
+  SmallVector<LandingPadInst *, 4> LPads;<br>
+  SmallVector<ResumeInst *, 4> Resumes;<br>
+  for (BasicBlock &BB : Fn) {<br>
+    if (auto *LP = BB.getLandingPadInst())<br>
+      LPads.push_back(LP);<br>
+    if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))<br>
+      Resumes.push_back(Resume);<br>
+  }<br>
+<br>
+  // No need to prepare functions that lack landing pads.<br>
+  if (LPads.empty())<br>
+    return false;<br>
+<br>
+  // Classify the personality to see what kind of preparation we need.<br>
+  EHPersonality Pers = ClassifyEHPersonality(LPads.back()->getPersonalityFn());<br>
+<br>
+  // Delegate through to the DWARF pass if this is unrecognized.<br>
+  if (!isMSVCPersonality(Pers))<br>
+    return DwarfPrepare->runOnFunction(Fn);<br>
+<br>
+  // FIXME: Cleanups are unimplemented. Replace them with calls to @llvm.trap.<br>
+  if (Resumes.empty())<br>
+    return false;<br>
+<br>
+  Function *Trap =<br>
+      Intrinsic::getDeclaration(Fn.getParent(), Intrinsic::trap, None);<br>
+  for (ResumeInst *Resume : Resumes) {<br>
+    IRBuilder<>(Resume).CreateUnreachable();<br>
+    Resume->eraseFromParent();<br>
+  }<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+bool WinEHPrepare::doFinalization(Module &M) {<br>
+  return DwarfPrepare->doFinalization(M);<br>
+}<br>
+<br>
+void WinEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {<br>
+  DwarfPrepare->getAnalysisUsage(AU);<br>
+}<br>
<br>
Modified: llvm/trunk/test/CodeGen/X86/seh-safe-div.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/seh-safe-div.ll?rev=227405&r1=227404&r2=227405&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/seh-safe-div.ll?rev=227405&r1=227404&r2=227405&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/seh-safe-div.ll (original)<br>
+++ llvm/trunk/test/CodeGen/X86/seh-safe-div.ll Wed Jan 28 18:41:44 2015<br>
@@ -96,8 +96,9 @@ __try.cont:<br>
 ; CHECK: movl $-2, [[rloc]]<br>
 ; CHECK: jmp .LBB0_7<br>
<br>
-; FIXME: EH preparation should not call _Unwind_Resume.<br>
-; CHECK: callq _Unwind_Resume<br>
+; FIXME: EH preparation should eliminate the 'resume' instr and we should not do<br>
+; the previous 'cmp;jeq'.<br>
+; CHECK-NOT: _Unwind_Resume<br>
 ; CHECK: ud2<br>
<br>
 ; CHECK: .seh_handlerdata<br>
<br>
Added: llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll?rev=227405&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll?rev=227405&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll (added)<br>
+++ llvm/trunk/test/CodeGen/X86/win_eh_prepare.ll Wed Jan 28 18:41:44 2015<br>
@@ -0,0 +1,80 @@<br>
+; RUN: opt -S -winehprepare -mtriple x86_64-pc-windows-msvc < %s | FileCheck %s<br>
+<br>
+; FIXME: Add and test outlining here.<br>
+<br>
+declare void @maybe_throw()<br>
+<br>
+@_ZTIi = external constant i8*<br>
+@g = external global i32<br>
+<br>
+declare i32 @__C_specific_handler(...)<br>
+declare i32 @__gxx_personality_seh0(...)<br>
+declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind<br>
+<br>
+define i32 @use_seh() {<br>
+entry:<br>
+  invoke void @maybe_throw()<br>
+      to label %cont unwind label %lpad<br>
+<br>
+cont:<br>
+  ret i32 0<br>
+<br>
+lpad:<br>
+  %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler<br>
+      cleanup<br>
+      catch i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*)<br>
+  %ehsel = extractvalue { i8*, i32 } %ehvals, 1<br>
+  %filt_g_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*))<br>
+  %matches = icmp eq i32 %ehsel, %filt_g_sel<br>
+  br i1 %matches, label %ret1, label %eh.resume<br>
+<br>
+ret1:<br>
+  ret i32 1<br>
+<br>
+eh.resume:<br>
+  resume { i8*, i32 } %ehvals<br>
+}<br>
+<br>
+define internal i32 @filt_g(i8*, i8*) {<br>
+  %g = load i32* @g<br>
+  ret i32 %g<br>
+}<br>
+<br>
+; CHECK-LABEL: define i32 @use_seh()<br>
+; CHECK: invoke void @maybe_throw()<br>
+; CHECK-NEXT: to label %cont unwind label %lpad<br>
+; CHECK: eh.resume:<br>
+; CHECK-NEXT: unreachable<br>
+<br>
+<br>
+; A MinGW64-ish EH style. It could happen if a binary uses both MSVC CRT and<br>
+; mingw CRT and is linked with LTO.<br>
+define i32 @use_gcc() {<br>
+entry:<br>
+  invoke void @maybe_throw()<br>
+      to label %cont unwind label %lpad<br>
+<br>
+cont:<br>
+  ret i32 0<br>
+<br>
+lpad:<br>
+  %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__gxx_personality_seh0<br>
+      cleanup<br>
+      catch i8* bitcast (i8** @_ZTIi to i8*)<br>
+  %ehsel = extractvalue { i8*, i32 } %ehvals, 1<br>
+  %filt_g_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filt_g to i8*))<br>
+  %matches = icmp eq i32 %ehsel, %filt_g_sel<br>
+  br i1 %matches, label %ret1, label %eh.resume<br>
+<br>
+ret1:<br>
+  ret i32 1<br>
+<br>
+eh.resume:<br>
+  resume { i8*, i32 } %ehvals<br>
+}<br>
+<br>
+; CHECK-LABEL: define i32 @use_gcc()<br>
+; CHECK: invoke void @maybe_throw()<br>
+; CHECK-NEXT: to label %cont unwind label %lpad<br>
+; CHECK: eh.resume:<br>
+; CHECK: call void @_Unwind_Resume(i8* %exn.obj)<br>
<br>
Modified: llvm/trunk/tools/opt/opt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/opt.cpp?rev=227405&r1=227404&r2=227405&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/opt/opt.cpp?rev=227405&r1=227404&r2=227405&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/opt/opt.cpp (original)<br>
+++ llvm/trunk/tools/opt/opt.cpp Wed Jan 28 18:41:44 2015<br>
@@ -322,6 +322,7 @@ int main(int argc, char **argv) {<br>
   initializeCodeGenPreparePass(Registry);<br>
   initializeAtomicExpandPass(Registry);<br>
   initializeRewriteSymbolsPass(Registry);<br>
+  initializeWinEHPreparePass(Registry);<br>
<br>
 #ifdef LINK_POLLY_INTO_TOOLS<br>
   polly::initializePollyPasses(Registry);<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr">Alexey Samsonov<br><a href="mailto:vonosmas@gmail.com" target="_blank">vonosmas@gmail.com</a></div></div>
</div></div>