[llvm] r235768 - [SEH] Implement GetExceptionCode in __except blocks

Reid Kleckner reid at kleckner.net
Fri Apr 24 13:25:05 PDT 2015


Author: rnk
Date: Fri Apr 24 15:25:05 2015
New Revision: 235768

URL: http://llvm.org/viewvc/llvm-project?rev=235768&view=rev
Log:
[SEH] Implement GetExceptionCode in __except blocks

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.

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

Modified: llvm/trunk/include/llvm/CodeGen/FunctionLoweringInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/FunctionLoweringInfo.h?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/FunctionLoweringInfo.h (original)
+++ llvm/trunk/include/llvm/CodeGen/FunctionLoweringInfo.h Fri Apr 24 15:25:05 2015
@@ -221,7 +221,7 @@ public:
   int getArgumentFrameIndex(const Argument *A);
 
 private:
-  void addSEHHandlersForLPads();
+  void addSEHHandlersForLPads(ArrayRef<const LandingPadInst *> LPads);
 
   /// LiveOutRegInfo - Information about live out vregs.
   IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;

Modified: llvm/trunk/include/llvm/IR/Intrinsics.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Intrinsics.td?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Intrinsics.td (original)
+++ llvm/trunk/include/llvm/IR/Intrinsics.td Fri Apr 24 15:25:05 2015
@@ -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], []>;
 
+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.

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp Fri Apr 24 15:25:05 2015
@@ -271,40 +271,49 @@ void FunctionLoweringInfo::set(const Fun
   }
 
   // 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())
-      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;
-  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) {
-    addSEHHandlersForLPads();
+    addSEHHandlersForLPads(LPads);
   } 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());
     }
+
+    // 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.
-  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 ||

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Fri Apr 24 15:25:05 2015
@@ -4817,6 +4817,18 @@ SelectionDAGBuilder::visitIntrinsicCall(
   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;
+  }
   }
 }
 

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Fri Apr 24 15:25:05 2015
@@ -961,12 +961,6 @@ bool SelectionDAGISel::PrepareEHLandingP
     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;
   }

Modified: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Fri Apr 24 15:25:05 2015
@@ -71,7 +71,7 @@ class WinEHPrepare : public FunctionPass
 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;
 
@@ -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;
+
+  AllocaInst *SEHExceptionCodeSlot;
 };
 
 class WinEHFrameVariableMaterializer : public ValueMaterializer {
@@ -628,6 +630,13 @@ bool WinEHPrepare::prepareExceptionHandl
   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;
@@ -680,23 +689,48 @@ bool WinEHPrepare::prepareExceptionHandl
 
     // 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");
-      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()));
 
+    // 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) {
@@ -820,6 +854,13 @@ bool WinEHPrepare::prepareExceptionHandl
   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();
@@ -1193,6 +1234,7 @@ bool WinEHPrepare::outlineHandler(Action
 /// target.
 void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
                                           BasicBlock *StartBB) {
+  LLVMContext &Context = StartBB->getContext();
   BasicBlock *HandlerBB;
   BasicBlock *NextBB;
   Constant *Selector;
@@ -1210,6 +1252,12 @@ void WinEHPrepare::processSEHCatchHandle
     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);

Modified: llvm/trunk/test/CodeGen/WinEH/seh-resume-phi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WinEH/seh-resume-phi.ll?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WinEH/seh-resume-phi.ll (original)
+++ llvm/trunk/test/CodeGen/WinEH/seh-resume-phi.ll Fri Apr 24 15:25:05 2015
@@ -55,9 +55,8 @@ eh.resume:
 ; 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)

Modified: llvm/trunk/test/CodeGen/X86/seh-catch-all.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/seh-catch-all.ll?rev=235768&r1=235767&r2=235768&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/seh-catch-all.ll (original)
+++ llvm/trunk/test/CodeGen/X86/seh-catch-all.ll Fri Apr 24 15:25:05 2015
@@ -1,10 +1,10 @@
 ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
 
- at str = internal unnamed_addr constant [10 x i8] c"recovered\00", align 1
+ at 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 @puts(i8*)
+declare i32 @printf(i8* nocapture readonly, ...) nounwind
 
 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
-  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:
@@ -24,7 +27,15 @@ eh.resume:
   resume { i8*, i32 } %0
 }
 
+; Check that we can get the exception code from eax to the printf.
+
 ; 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





More information about the llvm-commits mailing list