Workaround for PR1508.
authorDuncan Sands <baldrick@free.fr>
Fri, 15 Jun 2007 19:04:19 +0000 (19:04 +0000)
committerDuncan Sands <baldrick@free.fr>
Fri, 15 Jun 2007 19:04:19 +0000 (19:04 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@37597 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
test/CodeGen/Generic/2007-04-14-EHSelectorCrash.ll
test/CodeGen/Generic/2007-06-06-CriticalEdgeLandingPad.ll

index ed833e26efdca221bb7f329fdafcf70f5b8e21b6..b29fb0d65ed24e98bf12bc614e0b6e5452a0ffdb 100644 (file)
@@ -179,6 +179,11 @@ namespace llvm {
     /// anywhere in the function.
     std::map<const AllocaInst*, int> StaticAllocaMap;
 
+#ifndef NDEBUG
+    SmallSet<Instruction*, 8> CatchInfoLost;
+    SmallSet<Instruction*, 8> CatchInfoFound;
+#endif
+
     unsigned MakeReg(MVT::ValueType VT) {
       return RegMap->createVirtualRegister(TLI.getRegClassFor(VT));
     }
@@ -199,6 +204,15 @@ namespace llvm {
   };
 }
 
+/// isFilterOrSelector - Return true if this instruction is a call to the
+/// eh.filter or the eh.selector intrinsic.
+static bool isFilterOrSelector(Instruction *I) {
+  if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
+    return II->getIntrinsicID() == Intrinsic::eh_selector
+      || II->getIntrinsicID() == Intrinsic::eh_filter;
+  return false;
+}
+
 /// isUsedOutsideOfDefiningBlock - Return true if this instruction is used by
 /// PHI nodes or outside of the basic block that defines it, or used by a 
 /// switch instruction, which may expand to multiple basic blocks.
@@ -2463,6 +2477,33 @@ static GlobalVariable *ExtractGlobalVariable (Constant *C) {
   return NULL;
 }
 
+/// addCatchInfo - Extract the personality and type infos from an eh.selector
+/// or eh.filter call, and add them to the specified machine basic block.
+static void addCatchInfo(CallInst &I, MachineModuleInfo *MMI,
+                         MachineBasicBlock *MBB) {
+  // Inform the MachineModuleInfo of the personality for this landing pad.
+  ConstantExpr *CE = cast<ConstantExpr>(I.getOperand(2));
+  assert(CE->getOpcode() == Instruction::BitCast &&
+         isa<Function>(CE->getOperand(0)) &&
+         "Personality should be a function");
+  MMI->addPersonality(MBB, cast<Function>(CE->getOperand(0)));
+
+  // Gather all the type infos for this landing pad and pass them along to
+  // MachineModuleInfo.
+  std::vector<GlobalVariable *> TyInfo;
+  for (unsigned i = 3, N = I.getNumOperands(); i < N; ++i) {
+    Constant *C = cast<Constant>(I.getOperand(i));
+    GlobalVariable *GV = ExtractGlobalVariable(C);
+    assert (GV || isa<ConstantPointerNull>(C) &&
+            "TypeInfo must be a global variable or NULL");
+    TyInfo.push_back(GV);
+  }
+  if (I.getCalledFunction()->getIntrinsicID() == Intrinsic::eh_filter)
+    MMI->addFilterTypeInfo(MBB, TyInfo);
+  else
+    MMI->addCatchTypeInfo(MBB, TyInfo);
+}
+
 /// visitIntrinsicCall - Lower the call to the specified intrinsic function.  If
 /// we want to emit this as a call to a named external function, return the name
 /// otherwise lower it and return null.
@@ -2595,29 +2636,14 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
   case Intrinsic::eh_selector:
   case Intrinsic::eh_filter:{
     MachineModuleInfo *MMI = DAG.getMachineModuleInfo();
-    
+
     if (ExceptionHandling && MMI) {
-      // Inform the MachineModuleInfo of the personality for this landing pad.
-      ConstantExpr *CE = dyn_cast<ConstantExpr>(I.getOperand(2));
-      assert(CE && CE->getOpcode() == Instruction::BitCast &&
-             isa<Function>(CE->getOperand(0)) &&
-             "Personality should be a function");
-      MMI->addPersonality(CurMBB, cast<Function>(CE->getOperand(0)));
-
-      // Gather all the type infos for this landing pad and pass them along to
-      // MachineModuleInfo.
-      std::vector<GlobalVariable *> TyInfo;
-      for (unsigned i = 3, N = I.getNumOperands(); i < N; ++i) {
-        Constant *C = cast<Constant>(I.getOperand(i));
-        GlobalVariable *GV = ExtractGlobalVariable(C);
-        assert (GV || isa<ConstantPointerNull>(C) &&
-                "TypeInfo must be a global variable or NULL");
-        TyInfo.push_back(GV);
-      }
-      if (Intrinsic == Intrinsic::eh_filter)
-        MMI->addFilterTypeInfo(CurMBB, TyInfo);
+      if (CurMBB->isLandingPad())
+        addCatchInfo(I, MMI, CurMBB);
+#ifndef NDEBUG
       else
-        MMI->addCatchTypeInfo(CurMBB, TyInfo);
+        FuncInfo.CatchInfoLost.insert(&I);
+#endif
 
       // Mark exception selector register as live in.
       unsigned Reg = TLI.getExceptionSelectorRegister();
@@ -4403,6 +4429,11 @@ bool SelectionDAGISel::runOnFunction(Function &Fn) {
            E = MF.livein_end(); I != E; ++I)
       BB->addLiveIn(I->first);
 
+#ifndef NDEBUG
+  assert(FuncInfo.CatchInfoFound.size() == FuncInfo.CatchInfoLost.size() &&
+         "Not all catch info was assigned to a landing pad!");
+#endif
+
   return true;
 }
 
@@ -4513,6 +4544,20 @@ LowerArguments(BasicBlock *LLVMBB, SelectionDAGLowering &SDL,
   EmitFunctionEntryCode(F, SDL.DAG.getMachineFunction());
 }
 
+static void copyCatchInfo(BasicBlock *SrcBB, BasicBlock *DestBB,
+                          MachineModuleInfo *MMI, FunctionLoweringInfo &FLI) {
+  assert(!FLI.MBBMap[SrcBB]->isLandingPad() &&
+         "Copying catch info out of a landing pad!");
+  for (BasicBlock::iterator I = SrcBB->begin(), E = --SrcBB->end(); I != E; ++I)
+    if (isFilterOrSelector(I)) {
+      // Apply the catch info to DestBB.
+      addCatchInfo(cast<CallInst>(*I), MMI, FLI.MBBMap[DestBB]);
+#ifndef NDEBUG
+      FLI.CatchInfoFound.insert(I);
+#endif
+    }
+}
+
 void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
        std::vector<std::pair<MachineInstr*, unsigned> > &PHINodesToUpdate,
                                          FunctionLoweringInfo &FuncInfo) {
@@ -4527,15 +4572,37 @@ void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
   BB = FuncInfo.MBBMap[LLVMBB];
   SDL.setCurrentBasicBlock(BB);
 
-  if (ExceptionHandling && BB->isLandingPad()) {
-    MachineModuleInfo *MMI = DAG.getMachineModuleInfo();
+  MachineModuleInfo *MMI = DAG.getMachineModuleInfo();
 
-    if (MMI) {
-      // Add a label to mark the beginning of the landing pad.  Deletion of the
-      // landing pad can thus be detected via the MachineModuleInfo.
-      unsigned LabelID = MMI->addLandingPad(BB);
-      DAG.setRoot(DAG.getNode(ISD::LABEL, MVT::Other, DAG.getEntryNode(),
-                              DAG.getConstant(LabelID, MVT::i32)));
+  if (ExceptionHandling && MMI && BB->isLandingPad()) {
+    // Add a label to mark the beginning of the landing pad.  Deletion of the
+    // landing pad can thus be detected via the MachineModuleInfo.
+    unsigned LabelID = MMI->addLandingPad(BB);
+    DAG.setRoot(DAG.getNode(ISD::LABEL, MVT::Other, DAG.getEntryNode(),
+                            DAG.getConstant(LabelID, MVT::i32)));
+
+    // FIXME: Hack around an exception handling flaw (PR1508): the personality
+    // function and list of typeids logically belong to the invoke (or, if you
+    // like, the basic block containing the invoke), and need to be associated
+    // with it in the dwarf exception handling tables.  Currently however the
+    // information is provided by intrinsics (eh.filter and eh.selector) that
+    // can be moved to unexpected places by the optimizers: if the unwind edge
+    // is critical, then breaking it can result in the intrinsics being in the
+    // successor of the landing pad, not the landing pad itself.  This results
+    // in exceptions not being caught because no typeids are associated with
+    // the invoke.  This may not be the only way things can go wrong, but it
+    // is the only way we try to work around for the moment.
+    BranchInst *Br = dyn_cast<BranchInst>(LLVMBB->getTerminator());
+
+    if (Br && Br->isUnconditional()) { // Critical edge?
+      BasicBlock::iterator I, E;
+      for (I = LLVMBB->begin(), E = --LLVMBB->end(); I != E; ++I)
+        if (isFilterOrSelector(I))
+          break;
+
+      if (I == E)
+        // No catch info found - try to extract some from the successor.
+        copyCatchInfo(Br->getSuccessor(0), LLVMBB, MMI, FuncInfo);
     }
   }
 
index 2a7cb2469ba62cba1d00421e76f3a8d547c1c14a..be039bf757d353b417be8f8d6d8a1e9274f6997e 100644 (file)
@@ -1,5 +1,7 @@
 ; RUN: llvm-as < %s | llc -enable-eh
 ; RUN: llvm-as < %s | llc -enable-eh -march=x86-64 
+; XFAIL: *
+; Un-XFAIL this when PR1508 is fixed.
 
 ; PR1326
 
index e791d9cc8d1ed906d79d6c9a00dab78da7ce34d9..2ad0019764e45af5ed99b698057ab94aeb01d641 100644 (file)
@@ -1,5 +1,7 @@
-; RUN: llvm-as < %s | llc -enable-eh -asm-verbose -o - | grep {Llabel137.*Region start}
+; RUN: llvm-as < %s | llc -enable-eh -asm-verbose -o - | \
+; RUN:   grep -A 3 {Llabel137.*Region start} | grep {5.*Action}
 ; PR1422
+; PR1508
 
 target triple = "i686-pc-linux-gnu"
        %struct.exception = type { i8, i8, i32, i8*, i8*, i32, i8* }