Handle PHI nodes prefacing EH pads too
authorDavid Majnemer <david.majnemer@gmail.com>
Thu, 6 Aug 2015 21:08:32 +0000 (21:08 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Thu, 6 Aug 2015 21:08:32 +0000 (21:08 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244274 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/WinEHPrepare.cpp
lib/Transforms/Utils/DemoteRegToStack.cpp

index fb059b92cdb23366314486c95170c13fc664ef43..df9da1456a1c13e9e31572f9d2d5605657308992 100644 (file)
@@ -2951,6 +2951,7 @@ void WinEHPrepare::numberFunclet(BasicBlock *InitialBB, BasicBlock *FuncletBB) {
 }
 
 bool WinEHPrepare::prepareExplicitEH(Function &F) {
+  LLVMContext &Context = F.getContext();
   // Remove unreachable blocks.  It is not valuable to assign them a color and
   // their existence can trick us into thinking values are alive when they are
   // not.
@@ -2980,24 +2981,97 @@ bool WinEHPrepare::prepareExplicitEH(Function &F) {
       numberFunclet(CRI->getSuccessor(), EntryBlock);
   }
 
-  // Strip PHI nodes off of EH pads.
+  // Insert cleanuppads before EH blocks with PHI nodes.
   for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) {
     BasicBlock *BB = FI++;
+    // Skip any BBs which aren't EH pads.
+    if (!BB->isEHPad())
+      continue;
+    // Skip any cleanuppads, they can hold non-PHI instructions.
+    if (isa<CleanupPadInst>(BB->getFirstNonPHI()))
+      continue;
+    // Skip any EH pads without PHIs, we don't need to worry about demoting into
+    // them.
+    if (!isa<PHINode>(BB->begin()))
+      continue;
+
+    // Create our new cleanuppad BB, terminate it with a cleanupret.
+    auto *NewCleanupBB = BasicBlock::Create(
+        Context, Twine(BB->getName(), ".wineh.phibb"), &F, BB);
+    auto *CPI = CleanupPadInst::Create(Type::getVoidTy(Context), {BB}, "",
+                                       NewCleanupBB);
+    CleanupReturnInst::Create(Context, /*RetVal=*/nullptr, BB, NewCleanupBB);
+
+    // Update the funclet data structures to keep them in the loop.
+    BlockColors[NewCleanupBB].insert(NewCleanupBB);
+    FuncletBlocks[NewCleanupBB].insert(NewCleanupBB);
+
+    // Reparent PHIs from the old EH BB into the cleanuppad.
     for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) {
-      if (!BI->isEHPad())
+      Instruction *I = BI++;
+      auto *PN = dyn_cast<PHINode>(I);
+      // Stop at the first non-PHI.
+      if (!PN)
+        break;
+      PN->removeFromParent();
+      PN->insertBefore(CPI);
+    }
+
+    // Redirect predecessors from the old EH BB to the cleanuppad.
+    std::set<BasicBlock *> Preds;
+    Preds.insert(pred_begin(BB), pred_end(BB));
+    for (BasicBlock *Pred : Preds) {
+      // Don't redirect the new cleanuppad to itself!
+      if (Pred == NewCleanupBB)
         continue;
+      TerminatorInst *TI = Pred->getTerminator();
+      for (unsigned TII = 0, TIE = TI->getNumSuccessors(); TII != TIE; ++TII) {
+        BasicBlock *Successor = TI->getSuccessor(TII);
+        if (Successor == BB)
+          TI->setSuccessor(TII, NewCleanupBB);
+      }
+    }
+  }
+
+  // Get rid of polychromatic PHI nodes.
+  for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) {
+    BasicBlock *BB = FI++;
+    std::set<BasicBlock *> &ColorsForBB = BlockColors[BB];
+    bool IsEHPad = BB->isEHPad();
+    for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) {
       Instruction *I = BI++;
       auto *PN = dyn_cast<PHINode>(I);
+      // Stop at the first non-PHI node.
       if (!PN)
+        break;
+
+      // EH pads cannot be lowered with PHI nodes prefacing them.
+      if (IsEHPad) {
+        // We should have removed PHIs from all non-cleanuppad blocks.
+        if (!isa<CleanupPadInst>(BB->getFirstNonPHI()))
+          report_fatal_error("Unexpected PHI on EH Pad");
+        DemotePHIToStack(PN);
         continue;
-      auto *SpillSlot = new AllocaInst(I->getType(), nullptr,
-                                       Twine(I->getName(), ".wineh.phispill"),
-                                       EntryBlock->begin());
-
-      // Iterate over each operand inserting a store in each predecessor.
-      for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i)
-        new StoreInst(P->getIncomingValue(i), Slot,
-                      P->getIncomingBlock(i)->getTerminator());
+      }
+
+      // See if *all* the basic blocks involved in this PHI node are in the
+      // same, lone, color.  If so, demotion is not needed.
+      bool SameColor = ColorsForBB.size() == 1;
+      if (SameColor) {
+        for (unsigned PNI = 0, PNE = PN->getNumIncomingValues(); PNI != PNE;
+             ++PNI) {
+          BasicBlock *IncomingBB = PN->getIncomingBlock(PNI);
+          std::set<BasicBlock *> &ColorsForIncomingBB = BlockColors[IncomingBB];
+          // If the colors differ, bail out early and demote.
+          if (ColorsForIncomingBB != ColorsForBB) {
+            SameColor = false;
+            break;
+          }
+        }
+      }
+
+      if (!SameColor)
+        DemotePHIToStack(PN);
     }
   }
 
@@ -3180,9 +3254,9 @@ bool WinEHPrepare::prepareExplicitEH(Function &F) {
   // branches, etc.
   for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE;) {
     BasicBlock *BB = FI++;
-    SimplifyInstructionsInBlock(BB);
-    ConstantFoldTerminator(BB, /*DeleteDeadConditions=*/true);
-    MergeBlockIntoPredecessor(BB);
+    //SimplifyInstructionsInBlock(BB);
+    //ConstantFoldTerminator(BB, /*DeleteDeadConditions=*/true);
+    //MergeBlockIntoPredecessor(BB);
   }
 
   // TODO: Do something about cleanupblocks which branch to implausible
index f11b6099939cb8ac3492135ab35cf634d674ca7c..1d7c740b6e0f74d2f7d71ee2e1630ff2026e1259 100644 (file)
@@ -135,7 +135,7 @@ AllocaInst *llvm::DemotePHIToStack(PHINode *P, Instruction *AllocaPoint) {
   // Insert a load in place of the PHI and replace all uses.
   BasicBlock::iterator InsertPt = P;
 
-  for (; isa<PHINode>(InsertPt) || isa<LandingPadInst>(InsertPt); ++InsertPt)
+  for (; isa<PHINode>(InsertPt) || InsertPt->isEHPad(); ++InsertPt)
     /* empty */;   // Don't insert before PHI nodes or landingpad instrs.
 
   Value *V = new LoadInst(Slot, P->getName()+".reload", InsertPt);