[WinEH] Implement state numbering for CoreCLR
authorJoseph Tremoulet <jotrem@microsoft.com>
Tue, 6 Oct 2015 20:30:33 +0000 (20:30 +0000)
committerJoseph Tremoulet <jotrem@microsoft.com>
Tue, 6 Oct 2015 20:30:33 +0000 (20:30 +0000)
Summary:
Assign one state number per handler/funclet, tracking parent state,
handler type, and catch type token.
State numbers are arranged such that ancestors have lower state numbers
than their descendants.

Reviewers: majnemer, andrew.w.kaylor, rnk

Subscribers: pgavlin, AndyAyers, llvm-commits

Differential Revision: http://reviews.llvm.org/D13450

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

include/llvm/CodeGen/WinEHFuncInfo.h
lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
lib/CodeGen/WinEHPrepare.cpp

index 5d12209..11591a8 100644 (file)
@@ -161,6 +161,15 @@ struct WinEHTryBlockMapEntry {
   SmallVector<WinEHHandlerType, 1> HandlerArray;
 };
 
+enum class ClrHandlerType { Catch, Finally, Fault, Filter };
+
+struct ClrEHUnwindMapEntry {
+  MBBOrBasicBlock Handler;
+  uint32_t TypeToken;
+  int Parent;
+  ClrHandlerType HandlerType;
+};
+
 struct WinEHFuncInfo {
   DenseMap<const Instruction *, int> EHPadStateMap;
   DenseMap<const CatchReturnInst *, const BasicBlock *>
@@ -169,6 +178,7 @@ struct WinEHFuncInfo {
   SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
   SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
   SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
+  SmallVector<ClrEHUnwindMapEntry, 4> ClrEHUnwindMap;
   int UnwindHelpFrameIdx = INT_MAX;
   int UnwindHelpFrameOffset = -1;
 
@@ -196,6 +206,8 @@ void calculateWinCXXEHStateNumbers(const Function *ParentFn,
 void calculateSEHStateNumbers(const Function *ParentFn,
                               WinEHFuncInfo &FuncInfo);
 
+void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
+
 void calculateCatchReturnSuccessorColors(const Function *Fn,
                                          WinEHFuncInfo &FuncInfo);
 }
index fb45594..d718ede 100644 (file)
@@ -292,6 +292,8 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
     calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
   else if (isAsynchronousEHPersonality(Personality))
     calculateSEHStateNumbers(WinEHParentFn, EHInfo);
+  else if (Personality == EHPersonality::CoreCLR)
+    calculateClrEHStateNumbers(WinEHParentFn, EHInfo);
 
   calculateCatchReturnSuccessorColors(WinEHParentFn, EHInfo);
 
@@ -316,6 +318,10 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
     const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
     UME.Handler = MBBMap[BB];
   }
+  for (ClrEHUnwindMapEntry &CME : EHInfo.ClrEHUnwindMap) {
+    const BasicBlock *BB = CME.Handler.get<const BasicBlock *>();
+    CME.Handler = MBBMap[BB];
+  }
 
   // If there's an explicit EH registration node on the stack, record its
   // frame index.
index 88a639e..cd813e6 100644 (file)
@@ -2864,6 +2864,91 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
   }
 }
 
+static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
+                           ClrHandlerType HandlerType, uint32_t TypeToken,
+                           const BasicBlock *Handler) {
+  ClrEHUnwindMapEntry Entry;
+  Entry.Parent = ParentState;
+  Entry.Handler = Handler;
+  Entry.HandlerType = HandlerType;
+  Entry.TypeToken = TypeToken;
+  FuncInfo.ClrEHUnwindMap.push_back(Entry);
+  return FuncInfo.ClrEHUnwindMap.size() - 1;
+}
+
+void llvm::calculateClrEHStateNumbers(const Function *Fn,
+                                      WinEHFuncInfo &FuncInfo) {
+  // Return if it's already been done.
+  if (!FuncInfo.EHPadStateMap.empty())
+    return;
+
+  SmallVector<std::pair<const Instruction *, int>, 8> Worklist;
+
+  // Each pad needs to be able to refer to its parent, so scan the function
+  // looking for top-level handlers and seed the worklist with them.
+  for (const BasicBlock &BB : *Fn) {
+    if (!BB.isEHPad())
+      continue;
+    if (BB.isLandingPad())
+      report_fatal_error("CoreCLR EH cannot use landingpads");
+    const Instruction *FirstNonPHI = BB.getFirstNonPHI();
+    if (!doesEHPadUnwindToCaller(FirstNonPHI))
+      continue;
+    // queue this with sentinel parent state -1 to mean unwind to caller.
+    Worklist.emplace_back(FirstNonPHI, -1);
+  }
+
+  while (!Worklist.empty()) {
+    const Instruction *Pad;
+    int ParentState;
+    std::tie(Pad, ParentState) = Worklist.pop_back_val();
+
+    int PredState;
+    if (const CleanupEndPadInst *EndPad = dyn_cast<CleanupEndPadInst>(Pad)) {
+      FuncInfo.EHPadStateMap[EndPad] = ParentState;
+      // Queue the cleanuppad, in case it doesn't have a cleanupret.
+      Worklist.emplace_back(EndPad->getCleanupPad(), ParentState);
+      // Preds of the endpad should get the parent state.
+      PredState = ParentState;
+    } else if (const CleanupPadInst *Cleanup = dyn_cast<CleanupPadInst>(Pad)) {
+      // A cleanup can have multiple exits; don't re-process after the first.
+      if (FuncInfo.EHPadStateMap.count(Pad))
+        continue;
+      // CoreCLR personality uses arity to distinguish faults from finallies.
+      const BasicBlock *PadBlock = Cleanup->getParent();
+      ClrHandlerType HandlerType =
+          (Cleanup->getNumOperands() ? ClrHandlerType::Fault
+                                     : ClrHandlerType::Finally);
+      int NewState =
+          addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock);
+      FuncInfo.EHPadStateMap[Cleanup] = NewState;
+      // Propagate the new state to all preds of the cleanup
+      PredState = NewState;
+    } else if (const CatchEndPadInst *EndPad = dyn_cast<CatchEndPadInst>(Pad)) {
+      FuncInfo.EHPadStateMap[EndPad] = ParentState;
+      // Preds of the endpad should get the parent state.
+      PredState = ParentState;
+    } else if (const CatchPadInst *Catch = dyn_cast<CatchPadInst>(Pad)) {
+      const BasicBlock *Handler = Catch->getNormalDest();
+      uint32_t TypeToken = static_cast<uint32_t>(
+          cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue());
+      int NewState = addClrEHHandler(FuncInfo, ParentState,
+                                     ClrHandlerType::Catch, TypeToken, Handler);
+      FuncInfo.EHPadStateMap[Catch] = NewState;
+      // Preds of the catch get its state
+      PredState = NewState;
+    } else {
+      llvm_unreachable("Unexpected EH pad");
+    }
+
+    // Queue all predecessors with the given state
+    for (const BasicBlock *Pred : predecessors(Pad->getParent())) {
+      if ((Pred = getEHPadFromPredecessor(Pred)))
+        Worklist.emplace_back(Pred->getFirstNonPHI(), PredState);
+    }
+  }
+}
+
 void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) {
   if (Personality != EHPersonality::MSVC_CXX)
     return;