[llvm] r247835 - [WinEHPrepare] Provide a cloning mode which doesn't demote

David Majnemer via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 11:40:37 PDT 2015


Author: majnemer
Date: Wed Sep 16 13:40:37 2015
New Revision: 247835

URL: http://llvm.org/viewvc/llvm-project?rev=247835&view=rev
Log:
[WinEHPrepare] Provide a cloning mode which doesn't demote

We are experimenting with a new approach to saving and restoring SSA
values used across funclets: let the register allocator do the dirty
work for us.

However, this means that we need to be able to clone commoned blocks
without relying on demotion.

Added:
    llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll
Modified:
    llvm/trunk/lib/CodeGen/WinEHPrepare.cpp

Modified: llvm/trunk/lib/CodeGen/WinEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WinEHPrepare.cpp?rev=247835&r1=247834&r2=247835&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WinEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WinEHPrepare.cpp Wed Sep 16 13:40:37 2015
@@ -41,6 +41,7 @@
 #include "llvm/Transforms/Utils/Cloning.h"
 #include "llvm/Transforms/Utils/Local.h"
 #include "llvm/Transforms/Utils/PromoteMemToReg.h"
+#include "llvm/Transforms/Utils/SSAUpdater.h"
 #include <memory>
 
 using namespace llvm;
@@ -48,6 +49,17 @@ using namespace llvm::PatternMatch;
 
 #define DEBUG_TYPE "winehprepare"
 
+static cl::opt<bool> DisableDemotion(
+    "disable-demotion", cl::Hidden,
+    cl::desc(
+        "Clone multicolor basic blocks but do not demote cross funclet values"),
+    cl::init(false));
+
+static cl::opt<bool> DisableCleanups(
+    "disable-cleanups", cl::Hidden,
+    cl::desc("Do not remove implausible terminators or other similar cleanups"),
+    cl::init(false));
+
 namespace {
 
 // This map is used to model frame variable usage during outlining, to
@@ -3399,6 +3411,77 @@ void WinEHPrepare::cloneCommonBlocks(
       // Loop over all instructions, fixing each one as we find it...
       for (Instruction &I : *BB)
         RemapInstruction(&I, VMap, RF_IgnoreMissingEntries);
+
+    // Check to see if SuccBB has PHI nodes. If so, we need to add entries to
+    // the PHI nodes for NewBB now.
+    for (auto &BBMapping : Orig2Clone) {
+      BasicBlock *OldBlock = BBMapping.first;
+      BasicBlock *NewBlock = BBMapping.second;
+      for (BasicBlock *SuccBB : successors(NewBlock)) {
+        for (Instruction &SuccI : *SuccBB) {
+          auto *SuccPN = dyn_cast<PHINode>(&SuccI);
+          if (!SuccPN)
+            break;
+
+          // Ok, we have a PHI node.  Figure out what the incoming value was for
+          // the OldBlock.
+          int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock);
+          if (OldBlockIdx == -1)
+            break;
+          Value *IV = SuccPN->getIncomingValue(OldBlockIdx);
+
+          // Remap the value if necessary.
+          if (auto *Inst = dyn_cast<Instruction>(IV)) {
+            ValueToValueMapTy::iterator I = VMap.find(Inst);
+            if (I != VMap.end())
+              IV = I->second;
+          }
+
+          SuccPN->addIncoming(IV, NewBlock);
+        }
+      }
+    }
+
+    for (ValueToValueMapTy::value_type VT : VMap) {
+      // If there were values defined in BB that are used outside the funclet,
+      // then we now have to update all uses of the value to use either the
+      // original value, the cloned value, or some PHI derived value.  This can
+      // require arbitrary PHI insertion, of which we are prepared to do, clean
+      // these up now.
+      SmallVector<Use *, 16> UsesToRename;
+
+      auto *OldI = dyn_cast<Instruction>(const_cast<Value *>(VT.first));
+      if (!OldI)
+        continue;
+      auto *NewI = cast<Instruction>(VT.second);
+      // Scan all uses of this instruction to see if it is used outside of its
+      // funclet, and if so, record them in UsesToRename.
+      for (Use &U : OldI->uses()) {
+        Instruction *UserI = cast<Instruction>(U.getUser());
+        BasicBlock *UserBB = UserI->getParent();
+        std::set<BasicBlock *> &ColorsForUserBB = BlockColors[UserBB];
+        assert(!ColorsForUserBB.empty());
+        if (ColorsForUserBB.size() > 1 ||
+            *ColorsForUserBB.begin() != FuncletPadBB)
+          UsesToRename.push_back(&U);
+      }
+
+      // If there are no uses outside the block, we're done with this
+      // instruction.
+      if (UsesToRename.empty())
+        continue;
+
+      // We found a use of OldI outside of the funclet.  Rename all uses of OldI
+      // that are outside its funclet to be uses of the appropriate PHI node
+      // etc.
+      SSAUpdater SSAUpdate;
+      SSAUpdate.Initialize(OldI->getType(), OldI->getName());
+      SSAUpdate.AddAvailableValue(OldI->getParent(), OldI);
+      SSAUpdate.AddAvailableValue(NewI->getParent(), NewI);
+
+      while (!UsesToRename.empty())
+        SSAUpdate.RewriteUseAfterInsertions(*UsesToRename.pop_back_val());
+    }
   }
 }
 
@@ -3429,6 +3512,11 @@ void WinEHPrepare::removeImplausibleTerm
         IsUnreachableCleanupendpad = CEPI->getCleanupPad() != CleanupPad;
       if (IsUnreachableRet || IsUnreachableCatchret ||
           IsUnreachableCleanupret || IsUnreachableCleanupendpad) {
+        // Loop through all of our successors and make sure they know that one
+        // of their predecessors is going away.
+        for (BasicBlock *SuccBB : TI->successors())
+          SuccBB->removePredecessor(BB);
+
         new UnreachableInst(BB->getContext(), TI);
         TI->eraseFromParent();
       }
@@ -3460,10 +3548,12 @@ void WinEHPrepare::verifyPreparedFunclet
       report_fatal_error("Uncolored BB!");
     if (NumColors > 1)
       report_fatal_error("Multicolor BB!");
-    bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin());
-    assert(!EHPadHasPHI && "EH Pad still has a PHI!");
-    if (EHPadHasPHI)
-      report_fatal_error("EH Pad still has a PHI!");
+    if (!DisableDemotion) {
+      bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin());
+      assert(!EHPadHasPHI && "EH Pad still has a PHI!");
+      if (EHPadHasPHI)
+        report_fatal_error("EH Pad still has a PHI!");
+    }
   }
 }
 
@@ -3477,17 +3567,21 @@ bool WinEHPrepare::prepareExplicitEH(
   // Determine which blocks are reachable from which funclet entries.
   colorFunclets(F, EntryBlocks);
 
-  demotePHIsOnFunclets(F);
+  if (!DisableDemotion) {
+    demotePHIsOnFunclets(F);
 
-  demoteUsesBetweenFunclets(F);
+    demoteUsesBetweenFunclets(F);
 
-  demoteArgumentUses(F);
+    demoteArgumentUses(F);
+  }
 
   cloneCommonBlocks(F, EntryBlocks);
 
-  removeImplausibleTerminators(F);
+  if (!DisableCleanups) {
+    removeImplausibleTerminators(F);
 
-  cleanupPreparedFunclets(F);
+    cleanupPreparedFunclets(F);
+  }
 
   verifyPreparedFunclets(F);
 

Added: llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll?rev=247835&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll (added)
+++ llvm/trunk/test/CodeGen/WinEH/wineh-no-demotion.ll Wed Sep 16 13:40:37 2015
@@ -0,0 +1,87 @@
+; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare -disable-demotion < %s | FileCheck %s
+
+declare i32 @__CxxFrameHandler3(...)
+
+declare void @f()
+
+declare i32 @g()
+
+declare void @h(i32)
+
+; CHECK-LABEL: @test1(
+define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+  invoke void @f()
+          to label %invoke.cont1 unwind label %left
+
+invoke.cont1:
+  invoke void @f()
+          to label %invoke.cont2 unwind label %right
+
+invoke.cont2:
+  invoke void @f()
+          to label %exit unwind label %inner
+
+left:
+  %0 = cleanuppad []
+  br label %shared
+
+right:
+  %1 = cleanuppad []
+  br label %shared
+
+shared:
+  %x = call i32 @g()
+  invoke void @f()
+          to label %shared.cont unwind label %inner
+
+shared.cont:
+  unreachable
+
+inner:
+  ; CHECK: %phi = phi i32 [ %x, %right ], [ 0, %invoke.cont2 ], [ %x.for.left, %left ]
+  %phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont2 ]
+  %i = cleanuppad []
+  call void @h(i32 %phi)
+  unreachable
+
+exit:
+  unreachable
+}
+
+; CHECK-LABEL: @test2(
+define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+  invoke void @f()
+          to label %invoke.cont unwind label %left
+
+invoke.cont:
+  invoke void @f()
+          to label %exit unwind label %right
+
+left:
+  cleanuppad []
+  br label %shared
+
+right:
+  cleanuppad []
+  br label %shared
+
+shared:
+  %x = call i32 @g()
+  invoke void @f()
+          to label %shared.cont unwind label %inner
+
+shared.cont:
+  unreachable
+
+inner:
+  ; CHECK: %x1 = phi i32 [ %x.for.left, %left ], [ %x, %right ]
+  ; CHECK: call void @h(i32 %x1)
+  %i = cleanuppad []
+  call void @h(i32 %x)
+  unreachable
+
+exit:
+  unreachable
+}




More information about the llvm-commits mailing list