[SEH] Implement GetExceptionCode in __except blocks
authorReid Kleckner <reid@kleckner.net>
Fri, 24 Apr 2015 20:25:05 +0000 (20:25 +0000)
committerReid Kleckner <reid@kleckner.net>
Fri, 24 Apr 2015 20:25:05 +0000 (20:25 +0000)
This introduces an intrinsic called llvm.eh.exceptioncode. It is lowered
by copying the EAX value live into whatever basic block it is called
from. Obviously, this only works if you insert it late during codegen,
because otherwise mid-level passes might reschedule it.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235768 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/FunctionLoweringInfo.h
include/llvm/IR/Intrinsics.td
lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/CodeGen/WinEHPrepare.cpp
test/CodeGen/WinEH/seh-resume-phi.ll
test/CodeGen/X86/seh-catch-all.ll

index 66a9ae7407bf3610a81755e18d4f352915c01650..dadaf15a48a4d0efa422eb2c242e8aa04b2be472 100644 (file)
@@ -221,7 +221,7 @@ public:
   int getArgumentFrameIndex(const Argument *A);
 
 private:
   int getArgumentFrameIndex(const Argument *A);
 
 private:
-  void addSEHHandlersForLPads();
+  void addSEHHandlersForLPads(ArrayRef<const LandingPadInst *> LPads);
 
   /// LiveOutRegInfo - Information about live out vregs.
   IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;
 
   /// LiveOutRegInfo - Information about live out vregs.
   IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;
index 4052a312fd0bad670aa1a26f245f76b8dc974779..b4b987682268116c2a8d02a49e3c50654a422143 100644 (file)
@@ -421,6 +421,8 @@ def int_eh_endcatch : Intrinsic<[], []>;
 // Represents the list of actions to take when an exception is thrown.
 def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
 
 // Represents the list of actions to take when an exception is thrown.
 def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
 
+def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], []>;
+
 // __builtin_unwind_init is an undocumented GCC intrinsic that causes all
 // callee-saved registers to be saved and restored (regardless of whether they
 // are used) in the calling function. It is used by libgcc_eh.
 // __builtin_unwind_init is an undocumented GCC intrinsic that causes all
 // callee-saved registers to be saved and restored (regardless of whether they
 // are used) in the calling function. It is used by libgcc_eh.
index b788232995594ce587ca1aeff141dc8126f92e47..fc5ca3ec58635304248f410e6c963d1d90edf574 100644 (file)
@@ -271,40 +271,49 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
   }
 
   // Mark landing pad blocks.
   }
 
   // Mark landing pad blocks.
-  const LandingPadInst *LP = nullptr;
+  SmallVector<const LandingPadInst *, 4> LPads;
   for (BB = Fn->begin(); BB != EB; ++BB) {
     if (const auto *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
       MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
     if (BB->isLandingPad())
   for (BB = Fn->begin(); BB != EB; ++BB) {
     if (const auto *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
       MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
     if (BB->isLandingPad())
-      LP = BB->getLandingPadInst();
+      LPads.push_back(BB->getLandingPadInst());
   }
 
   }
 
-  // Calculate EH numbers for MSVC C++ EH and save SEH handlers if necessary.
+  // If this is an MSVC EH personality, we need to do a bit more work.
   EHPersonality Personality = EHPersonality::Unknown;
   EHPersonality Personality = EHPersonality::Unknown;
-  if (LP)
-    Personality = classifyEHPersonality(LP->getPersonalityFn());
+  if (!LPads.empty())
+    Personality = classifyEHPersonality(LPads.back()->getPersonalityFn());
+  if (!isMSVCEHPersonality(Personality))
+    return;
+
+  WinEHFuncInfo *EHInfo = nullptr;
   if (Personality == EHPersonality::MSVC_Win64SEH) {
   if (Personality == EHPersonality::MSVC_Win64SEH) {
-    addSEHHandlersForLPads();
+    addSEHHandlersForLPads(LPads);
   } else if (Personality == EHPersonality::MSVC_CXX) {
     const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
   } else if (Personality == EHPersonality::MSVC_CXX) {
     const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
-    WinEHFuncInfo &FI = MMI.getWinEHFuncInfo(WinEHParentFn);
-    if (FI.LandingPadStateMap.empty()) {
-      WinEHNumbering Num(FI);
+    EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn);
+    if (EHInfo->LandingPadStateMap.empty()) {
+      WinEHNumbering Num(*EHInfo);
       Num.calculateStateNumbers(*WinEHParentFn);
       // Pop everything on the handler stack.
       Num.processCallSite(None, ImmutableCallSite());
     }
       Num.calculateStateNumbers(*WinEHParentFn);
       // Pop everything on the handler stack.
       Num.processCallSite(None, ImmutableCallSite());
     }
+
+    // Copy the state numbers to LandingPadInfo for the current function, which
+    // could be a handler or the parent.
+    for (const LandingPadInst *LP : LPads) {
+      MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
+      MMI.addWinEHState(LPadMBB, EHInfo->LandingPadStateMap[LP]);
+    }
   }
 }
 
   }
 }
 
-void FunctionLoweringInfo::addSEHHandlersForLPads() {
+void FunctionLoweringInfo::addSEHHandlersForLPads(
+    ArrayRef<const LandingPadInst *> LPads) {
   MachineModuleInfo &MMI = MF->getMMI();
 
   // Iterate over all landing pads with llvm.eh.actions calls.
   MachineModuleInfo &MMI = MF->getMMI();
 
   // Iterate over all landing pads with llvm.eh.actions calls.
-  for (const BasicBlock &BB : *Fn) {
-    const LandingPadInst *LP = BB.getLandingPadInst();
-    if (!LP)
-      continue;
+  for (const LandingPadInst *LP : LPads) {
     const IntrinsicInst *ActionsCall =
         dyn_cast<IntrinsicInst>(LP->getNextNode());
     if (!ActionsCall ||
     const IntrinsicInst *ActionsCall =
         dyn_cast<IntrinsicInst>(LP->getNextNode());
     if (!ActionsCall ||
index 01419cf8fa1cbf7d88af17bd1dd329f5bb2543fa..fd59d57580bcfc74457208a44feca1e4b0833457 100644 (file)
@@ -4817,6 +4817,18 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
   case Intrinsic::eh_begincatch:
   case Intrinsic::eh_endcatch:
     llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
   case Intrinsic::eh_begincatch:
   case Intrinsic::eh_endcatch:
     llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
+  case Intrinsic::eh_exceptioncode: {
+    unsigned Reg = TLI.getExceptionPointerRegister();
+    assert(Reg && "cannot get exception code on this platform");
+    MVT PtrVT = TLI.getPointerTy();
+    const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT);
+    unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC);
+    SDValue N =
+        DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT);
+    N = DAG.getZExtOrTrunc(N, getCurSDLoc(), MVT::i32);
+    setValue(&I, N);
+    return nullptr;
+  }
   }
 }
 
   }
 }
 
index f3735cb5315d5b3e329927b2c808951f1f439a99..056ba4a41984338f1d0a58a21b1dafa4f7b8f33a 100644 (file)
@@ -961,12 +961,6 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
     for (MachineBasicBlock *InvokeBB : InvokeBBs)
       InvokeBB->removeSuccessor(MBB);
 
     for (MachineBasicBlock *InvokeBB : InvokeBBs)
       InvokeBB->removeSuccessor(MBB);
 
-    // Transfer EH state number assigned to the IR block to the MBB.
-    if (Personality == EHPersonality::MSVC_CXX) {
-      WinEHFuncInfo &FI = MF->getMMI().getWinEHFuncInfo(MF->getFunction());
-      MF->getMMI().addWinEHState(MBB, FI.LandingPadStateMap[LPadInst]);
-    }
-
     // Don't select instructions for the landingpad.
     return false;
   }
     // Don't select instructions for the landingpad.
     return false;
   }
index 8a0fb7fd1bccbedc491b281d3ae79ea41ec9f181..963692a245ff3f3a9ef2297fd095f4b9fc1b7c11 100644 (file)
@@ -71,7 +71,7 @@ class WinEHPrepare : public FunctionPass {
 public:
   static char ID; // Pass identification, replacement for typeid.
   WinEHPrepare(const TargetMachine *TM = nullptr)
 public:
   static char ID; // Pass identification, replacement for typeid.
   WinEHPrepare(const TargetMachine *TM = nullptr)
-      : FunctionPass(ID), DT(nullptr) {}
+      : FunctionPass(ID), DT(nullptr), SEHExceptionCodeSlot(nullptr) {}
 
   bool runOnFunction(Function &Fn) override;
 
 
   bool runOnFunction(Function &Fn) override;
 
@@ -133,6 +133,8 @@ private:
   // outlined into a handler.  This is done after all handlers have been
   // outlined but before the outlined code is pruned from the parent function.
   DenseMap<const BasicBlock *, BasicBlock *> LPadTargetBlocks;
   // outlined into a handler.  This is done after all handlers have been
   // outlined but before the outlined code is pruned from the parent function.
   DenseMap<const BasicBlock *, BasicBlock *> LPadTargetBlocks;
+
+  AllocaInst *SEHExceptionCodeSlot;
 };
 
 class WinEHFrameVariableMaterializer : public ValueMaterializer {
 };
 
 class WinEHFrameVariableMaterializer : public ValueMaterializer {
@@ -628,6 +630,13 @@ bool WinEHPrepare::prepareExceptionHandlers(
   Type *Int32Type = Type::getInt32Ty(Context);
   Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions);
 
   Type *Int32Type = Type::getInt32Ty(Context);
   Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions);
 
+  if (isAsynchronousEHPersonality(Personality)) {
+    // FIXME: Switch the ehptr type to i32 and then switch this.
+    SEHExceptionCodeSlot =
+        new AllocaInst(Int8PtrType, nullptr, "seh_exception_code",
+                       F.getEntryBlock().getFirstInsertionPt());
+  }
+
   for (LandingPadInst *LPad : LPads) {
     // Look for evidence that this landingpad has already been processed.
     bool LPadHasActionList = false;
   for (LandingPadInst *LPad : LPads) {
     // Look for evidence that this landingpad has already been processed.
     bool LPadHasActionList = false;
@@ -680,23 +689,48 @@ bool WinEHPrepare::prepareExceptionHandlers(
 
     // Replace all extracted values with undef and ultimately replace the
     // landingpad with undef.
 
     // Replace all extracted values with undef and ultimately replace the
     // landingpad with undef.
-    // FIXME: This doesn't handle SEH GetExceptionCode(). For now, we just give
-    // out undef until we figure out the codegen support.
-    SmallVector<Instruction *, 4> Extracts;
+    SmallVector<Instruction *, 4> SEHCodeUses;
+    SmallVector<Instruction *, 4> EHUndefs;
     for (User *U : LPad->users()) {
       auto *E = dyn_cast<ExtractValueInst>(U);
       if (!E)
         continue;
       assert(E->getNumIndices() == 1 &&
              "Unexpected operation: extracting both landing pad values");
     for (User *U : LPad->users()) {
       auto *E = dyn_cast<ExtractValueInst>(U);
       if (!E)
         continue;
       assert(E->getNumIndices() == 1 &&
              "Unexpected operation: extracting both landing pad values");
-      Extracts.push_back(E);
+      unsigned Idx = *E->idx_begin();
+      assert((Idx == 0 || Idx == 1) && "unexpected index");
+      if (Idx == 0 && isAsynchronousEHPersonality(Personality))
+        SEHCodeUses.push_back(E);
+      else
+        EHUndefs.push_back(E);
     }
     }
-    for (Instruction *E : Extracts) {
+    for (Instruction *E : EHUndefs) {
       E->replaceAllUsesWith(UndefValue::get(E->getType()));
       E->eraseFromParent();
     }
     LPad->replaceAllUsesWith(UndefValue::get(LPad->getType()));
 
       E->replaceAllUsesWith(UndefValue::get(E->getType()));
       E->eraseFromParent();
     }
     LPad->replaceAllUsesWith(UndefValue::get(LPad->getType()));
 
+    // Rewrite uses of the exception pointer to loads of an alloca.
+    for (Instruction *E : SEHCodeUses) {
+      SmallVector<Use *, 4> Uses;
+      for (Use &U : E->uses())
+        Uses.push_back(&U);
+      for (Use *U : Uses) {
+        auto *I = cast<Instruction>(U->getUser());
+        if (isa<ResumeInst>(I))
+          continue;
+        LoadInst *LI;
+        if (auto *Phi = dyn_cast<PHINode>(I))
+          LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false,
+                            Phi->getIncomingBlock(*U));
+        else
+          LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I);
+        U->set(LI);
+      }
+      E->replaceAllUsesWith(UndefValue::get(E->getType()));
+      E->eraseFromParent();
+    }
+
     // Add a call to describe the actions for this landing pad.
     std::vector<Value *> ActionArgs;
     for (ActionHandler *Action : Actions) {
     // Add a call to describe the actions for this landing pad.
     std::vector<Value *> ActionArgs;
     for (ActionHandler *Action : Actions) {
@@ -820,6 +854,13 @@ bool WinEHPrepare::prepareExceptionHandlers(
   Builder.SetInsertPoint(&F.getEntryBlock().back());
   Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
 
   Builder.SetInsertPoint(&F.getEntryBlock().back());
   Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
 
+  if (SEHExceptionCodeSlot) {
+    if (SEHExceptionCodeSlot->hasNUses(0))
+      SEHExceptionCodeSlot->eraseFromParent();
+    else
+      PromoteMemToReg(SEHExceptionCodeSlot, *DT);
+  }
+
   // Clean up the handler action maps we created for this function
   DeleteContainerSeconds(CatchHandlerMap);
   CatchHandlerMap.clear();
   // Clean up the handler action maps we created for this function
   DeleteContainerSeconds(CatchHandlerMap);
   CatchHandlerMap.clear();
@@ -1193,6 +1234,7 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
 /// target.
 void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
                                           BasicBlock *StartBB) {
 /// target.
 void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
                                           BasicBlock *StartBB) {
+  LLVMContext &Context = StartBB->getContext();
   BasicBlock *HandlerBB;
   BasicBlock *NextBB;
   Constant *Selector;
   BasicBlock *HandlerBB;
   BasicBlock *NextBB;
   Constant *Selector;
@@ -1210,6 +1252,12 @@ void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
     HandlerBB =
         StartBB->splitBasicBlock(StartBB->getFirstInsertionPt(), "catch.all");
   }
     HandlerBB =
         StartBB->splitBasicBlock(StartBB->getFirstInsertionPt(), "catch.all");
   }
+  IRBuilder<> Builder(HandlerBB->getFirstInsertionPt());
+  Function *EHCodeFn = Intrinsic::getDeclaration(
+      StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode);
+  Value *Code = Builder.CreateCall(EHCodeFn, "sehcode");
+  Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType());
+  Builder.CreateStore(Code, SEHExceptionCodeSlot);
   CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB));
   TinyPtrVector<BasicBlock *> Targets(HandlerBB);
   CatchAction->setReturnTargets(Targets);
   CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB));
   TinyPtrVector<BasicBlock *> Targets(HandlerBB);
   CatchAction->setReturnTargets(Targets);
index cd30bfcc589f5a6153fb80d489a949bed8fab9cf..256dd852d287e5757547d7b787f3b8d3284e1712 100644 (file)
@@ -55,9 +55,8 @@ eh.resume:
 ; CHECK-NEXT: indirectbr {{.*}} [label %__except]
 ;
 ; CHECK: __except:
 ; CHECK-NEXT: indirectbr {{.*}} [label %__except]
 ;
 ; CHECK: __except:
-;      FIXME: This should not be undef, it should be the new landingpad value, which
-;      should ultimately lower down to eax.
-; CHECK: invoke void @might_crash(i8* undef)
+; CHECK: call i32 @llvm.eh.exceptioncode()
+; CHECK: invoke void @might_crash(i8* %{{.*}})
 ; CHECK: landingpad { i8*, i32 }
 ; CHECK-NEXT: cleanup
 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @resume_phi.cleanup)
 ; CHECK: landingpad { i8*, i32 }
 ; CHECK-NEXT: cleanup
 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @resume_phi.cleanup)
index 931046e51158150ed130fd37636acb75630d2f19..51840134eda38731b94c0880d976d62e881a5f87 100644 (file)
@@ -1,10 +1,10 @@
 ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
 
 ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
 
-@str = internal unnamed_addr constant [10 x i8] c"recovered\00", align 1
+@str = linkonce_odr unnamed_addr constant [27 x i8] c"GetExceptionCode(): 0x%lx\0A\00", align 1
 
 declare i32 @__C_specific_handler(...)
 declare void @crash()
 
 declare i32 @__C_specific_handler(...)
 declare void @crash()
-declare i32 @puts(i8*)
+declare i32 @printf(i8* nocapture readonly, ...) nounwind
 
 define i32 @main() {
 entry:
 
 define i32 @main() {
 entry:
@@ -14,7 +14,10 @@ entry:
 lpad:
   %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
           catch i8* null
 lpad:
   %0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
           catch i8* null
-  call i32 @puts(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @str, i64 0, i64 0))
+  %1 = extractvalue { i8*, i32 } %0, 0
+  %2 = ptrtoint i8* %1 to i64
+  %3 = trunc i64 %2 to i32
+  call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i64 0, i64 0), i32 %3)
   br label %__try.cont
 
 __try.cont:
   br label %__try.cont
 
 __try.cont:
@@ -24,7 +27,15 @@ eh.resume:
   resume { i8*, i32 } %0
 }
 
   resume { i8*, i32 } %0
 }
 
+; Check that we can get the exception code from eax to the printf.
+
 ; CHECK-LABEL: main:
 ; CHECK-LABEL: main:
+; CHECK: retq
+; CHECK: # Block address taken
+; CHECK: leaq str(%rip), %rcx
+; CHECK: movl %eax, %edx
+; CHECK: callq printf
+
 ; CHECK: .seh_handlerdata
 ; CHECK-NEXT: .long 1
 ; CHECK-NEXT: .Ltmp{{[0-9]+}}@IMGREL
 ; CHECK: .seh_handlerdata
 ; CHECK-NEXT: .long 1
 ; CHECK-NEXT: .Ltmp{{[0-9]+}}@IMGREL