[llvm] r249257 - [WinEH] Permit branch folding in the face of funclets

David Majnemer via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 3 19:22:53 PDT 2015


Author: majnemer
Date: Sat Oct  3 21:22:52 2015
New Revision: 249257

URL: http://llvm.org/viewvc/llvm-project?rev=249257&view=rev
Log:
[WinEH] Permit branch folding in the face of funclets

Track which basic blocks belong to which funclets.  Permit branch
folding to fire but only if it can prove that doing so will not cause
code in one funclet to be reused in another.

Modified:
    llvm/trunk/include/llvm/CodeGen/Analysis.h
    llvm/trunk/lib/CodeGen/Analysis.cpp
    llvm/trunk/lib/CodeGen/BranchFolding.cpp
    llvm/trunk/lib/CodeGen/BranchFolding.h
    llvm/trunk/lib/CodeGen/FuncletLayout.cpp
    llvm/trunk/test/CodeGen/X86/funclet-layout.ll

Modified: llvm/trunk/include/llvm/CodeGen/Analysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Analysis.h?rev=249257&r1=249256&r2=249257&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/Analysis.h (original)
+++ llvm/trunk/include/llvm/CodeGen/Analysis.h Sat Oct  3 21:22:52 2015
@@ -15,6 +15,7 @@
 #define LLVM_CODEGEN_ANALYSIS_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/CodeGen/ISDOpcodes.h"
 #include "llvm/IR/CallSite.h"
@@ -23,6 +24,8 @@
 
 namespace llvm {
 class GlobalValue;
+class MachineBasicBlock;
+class MachineFunction;
 class TargetLoweringBase;
 class TargetLowering;
 class TargetMachine;
@@ -115,6 +118,9 @@ bool returnTypeIsEligibleForTailCall(con
 // or we are in LTO.
 bool canBeOmittedFromSymbolTable(const GlobalValue *GV);
 
+DenseMap<const MachineBasicBlock *, int>
+getFuncletMembership(const MachineFunction &MF);
+
 } // End llvm namespace
 
 #endif

Modified: llvm/trunk/lib/CodeGen/Analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/Analysis.cpp?rev=249257&r1=249256&r2=249257&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/Analysis.cpp (original)
+++ llvm/trunk/lib/CodeGen/Analysis.cpp Sat Oct  3 21:22:52 2015
@@ -14,6 +14,7 @@
 #include "llvm/CodeGen/Analysis.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
@@ -25,6 +26,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetInstrInfo.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
 #include "llvm/Transforms/Utils/GlobalStatus.h"
 
@@ -643,3 +645,86 @@ bool llvm::canBeOmittedFromSymbolTable(c
 
   return !GS.IsCompared;
 }
+
+static void collectFuncletMembers(
+    DenseMap<const MachineBasicBlock *, int> &FuncletMembership, int Funclet,
+    const MachineBasicBlock *MBB) {
+  // Don't revisit blocks.
+  if (FuncletMembership.count(MBB) > 0) {
+    if (FuncletMembership[MBB] != Funclet) {
+      assert(false && "MBB is part of two funclets!");
+      report_fatal_error("MBB is part of two funclets!");
+    }
+    return;
+  }
+
+  // Add this MBB to our funclet.
+  FuncletMembership[MBB] = Funclet;
+
+  bool IsReturn = false;
+  int NumTerminators = 0;
+  for (const MachineInstr &MI : MBB->terminators()) {
+    IsReturn |= MI.isReturn();
+    ++NumTerminators;
+  }
+  assert((!IsReturn || NumTerminators == 1) &&
+         "Expected only one terminator when a return is present!");
+
+  // Returns are boundaries where funclet transfer can occur, don't follow
+  // successors.
+  if (IsReturn)
+    return;
+
+  for (const MachineBasicBlock *SMBB : MBB->successors())
+    if (!SMBB->isEHPad())
+      collectFuncletMembers(FuncletMembership, Funclet, SMBB);
+}
+
+DenseMap<const MachineBasicBlock *, int>
+llvm::getFuncletMembership(const MachineFunction &MF) {
+  DenseMap<const MachineBasicBlock *, int> FuncletMembership;
+
+  // We don't have anything to do if there aren't any EH pads.
+  if (!MF.getMMI().hasEHFunclets())
+    return FuncletMembership;
+
+  bool IsSEH = isAsynchronousEHPersonality(
+      classifyEHPersonality(MF.getFunction()->getPersonalityFn()));
+
+  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+  SmallVector<const MachineBasicBlock *, 16> FuncletBlocks;
+  SmallVector<std::pair<const MachineBasicBlock *, int>, 16> CatchRetSuccessors;
+  for (const MachineBasicBlock &MBB : MF) {
+    if (MBB.isEHFuncletEntry())
+      FuncletBlocks.push_back(&MBB);
+
+    MachineBasicBlock::const_iterator MBBI = MBB.getFirstTerminator();
+    // CatchPads are not funclets for SEH so do not consider CatchRet to
+    // transfer control to another funclet.
+    if (IsSEH || MBBI->getOpcode() != TII->getCatchReturnOpcode())
+      continue;
+
+    const MachineBasicBlock *Successor = MBBI->getOperand(0).getMBB();
+    const MachineBasicBlock *SuccessorColor = MBBI->getOperand(1).getMBB();
+    CatchRetSuccessors.push_back({Successor, SuccessorColor->getNumber()});
+  }
+
+  // We don't have anything to do if there aren't any EH pads.
+  if (FuncletBlocks.empty())
+    return FuncletMembership;
+
+  // Identify all the basic blocks reachable from the function entry.
+  collectFuncletMembers(FuncletMembership, MF.front().getNumber(), MF.begin());
+  // Next, identify all the blocks inside the funclets.
+  for (const MachineBasicBlock *MBB : FuncletBlocks)
+    collectFuncletMembers(FuncletMembership, MBB->getNumber(), MBB);
+  // Finally, identify all the targets of a catchret.
+  for (std::pair<const MachineBasicBlock *, int> CatchRetPair :
+       CatchRetSuccessors)
+    collectFuncletMembers(FuncletMembership, CatchRetPair.second,
+                          CatchRetPair.first);
+  // All blocks not part of a funclet are in the parent function.
+  for (const MachineBasicBlock &MBB : MF)
+    FuncletMembership.insert({&MBB, MF.front().getNumber()});
+  return FuncletMembership;
+}

Modified: llvm/trunk/lib/CodeGen/BranchFolding.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/BranchFolding.cpp?rev=249257&r1=249256&r2=249257&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/BranchFolding.cpp (original)
+++ llvm/trunk/lib/CodeGen/BranchFolding.cpp Sat Oct  3 21:22:52 2015
@@ -21,6 +21,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
 #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
@@ -94,10 +95,8 @@ bool BranchFolderPass::runOnMachineFunct
 
   TargetPassConfig *PassConfig = &getAnalysis<TargetPassConfig>();
   // TailMerge can create jump into if branches that make CFG irreducible for
-  // HW that requires structurized CFG.  It can also cause BBs to get shared
-  // between funclets.
+  // HW that requires structurized CFG.
   bool EnableTailMerge = !MF.getTarget().requiresStructuredCFG() &&
-                         !MF.getMMI().hasEHFunclets() &&
                          PassConfig->getEnableTailMerge();
   BranchFolder Folder(EnableTailMerge, /*CommonHoist=*/true,
                       getAnalysis<MachineBlockFrequencyInfo>(),
@@ -135,6 +134,7 @@ void BranchFolder::RemoveDeadBlock(Machi
 
   // Remove the block.
   MF->erase(MBB);
+  FuncletMembership.erase(MBB);
 }
 
 /// OptimizeImpDefsBlock - If a basic block is just a bunch of implicit_def
@@ -222,6 +222,9 @@ bool BranchFolder::OptimizeFunction(Mach
     MadeChange |= OptimizeImpDefsBlock(&MBB);
   }
 
+  // Recalculate funclet membership.
+  FuncletMembership = getFuncletMembership(MF);
+
   bool MadeChangeThisIteration = true;
   while (MadeChangeThisIteration) {
     MadeChangeThisIteration    = TailMergeBlocks(MF);
@@ -448,6 +451,11 @@ MachineBasicBlock *BranchFolder::SplitMB
   // For targets that use the register scavenger, we must maintain LiveIns.
   MaintainLiveIns(&CurMBB, NewMBB);
 
+  // Add the new block to the funclet.
+  const auto &FuncletI = FuncletMembership.find(&CurMBB);
+  if (FuncletI != FuncletMembership.end())
+    FuncletMembership[NewMBB] = FuncletI->second;
+
   return NewMBB;
 }
 
@@ -552,14 +560,23 @@ static unsigned CountTerminators(Machine
 /// and decide if it would be profitable to merge those tails.  Return the
 /// length of the common tail and iterators to the first common instruction
 /// in each block.
-static bool ProfitableToMerge(MachineBasicBlock *MBB1,
-                              MachineBasicBlock *MBB2,
-                              unsigned minCommonTailLength,
-                              unsigned &CommonTailLen,
-                              MachineBasicBlock::iterator &I1,
-                              MachineBasicBlock::iterator &I2,
-                              MachineBasicBlock *SuccBB,
-                              MachineBasicBlock *PredBB) {
+static bool
+ProfitableToMerge(MachineBasicBlock *MBB1, MachineBasicBlock *MBB2,
+                  unsigned minCommonTailLength, unsigned &CommonTailLen,
+                  MachineBasicBlock::iterator &I1,
+                  MachineBasicBlock::iterator &I2, MachineBasicBlock *SuccBB,
+                  MachineBasicBlock *PredBB,
+                  DenseMap<const MachineBasicBlock *, int> &FuncletMembership) {
+  // It is never profitable to tail-merge blocks from two different funclets.
+  if (!FuncletMembership.empty()) {
+    auto Funclet1 = FuncletMembership.find(MBB1);
+    assert(Funclet1 != FuncletMembership.end());
+    auto Funclet2 = FuncletMembership.find(MBB2);
+    assert(Funclet2 != FuncletMembership.end());
+    if (Funclet1->second != Funclet2->second)
+      return false;
+  }
+
   CommonTailLen = ComputeCommonTailLength(MBB1, MBB2, I1, I2);
   if (CommonTailLen == 0)
     return false;
@@ -636,7 +653,8 @@ unsigned BranchFolder::ComputeSameTails(
       if (ProfitableToMerge(CurMPIter->getBlock(), I->getBlock(),
                             minCommonTailLength,
                             CommonTailLen, TrialBBI1, TrialBBI2,
-                            SuccBB, PredBB)) {
+                            SuccBB, PredBB,
+                            FuncletMembership)) {
         if (CommonTailLen > maxCommonTailLength) {
           SameTails.clear();
           maxCommonTailLength = CommonTailLen;
@@ -1099,6 +1117,8 @@ bool BranchFolder::OptimizeBranches(Mach
 
   // Make sure blocks are numbered in order
   MF.RenumberBlocks();
+  // Renumbering blocks alters funclet membership, recalculate it.
+  FuncletMembership = getFuncletMembership(MF);
 
   for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end();
        I != E; ) {
@@ -1112,6 +1132,7 @@ bool BranchFolder::OptimizeBranches(Mach
       ++NumDeadBlocks;
     }
   }
+
   return MadeChange;
 }
 
@@ -1171,11 +1192,22 @@ ReoptimizeBlock:
   MachineFunction::iterator FallThrough = MBB;
   ++FallThrough;
 
+  // Make sure MBB and FallThrough belong to the same funclet.
+  bool SameFunclet = true;
+  if (!FuncletMembership.empty() && FallThrough != MF.end()) {
+    auto MBBFunclet = FuncletMembership.find(MBB);
+    assert(MBBFunclet != FuncletMembership.end());
+    auto FallThroughFunclet = FuncletMembership.find(FallThrough);
+    assert(FallThroughFunclet != FuncletMembership.end());
+    SameFunclet = MBBFunclet->second == FallThroughFunclet->second;
+  }
+
   // If this block is empty, make everyone use its fall-through, not the block
   // explicitly.  Landing pads should not do this since the landing-pad table
   // points to this block.  Blocks with their addresses taken shouldn't be
   // optimized away.
-  if (IsEmptyBlock(MBB) && !MBB->isEHPad() && !MBB->hasAddressTaken()) {
+  if (IsEmptyBlock(MBB) && !MBB->isEHPad() && !MBB->hasAddressTaken() &&
+      SameFunclet) {
     // Dead block?  Leave for cleanup later.
     if (MBB->pred_empty()) return MadeChange;
 

Modified: llvm/trunk/lib/CodeGen/BranchFolding.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/BranchFolding.h?rev=249257&r1=249256&r2=249257&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/BranchFolding.h (original)
+++ llvm/trunk/lib/CodeGen/BranchFolding.h Sat Oct  3 21:22:52 2015
@@ -54,6 +54,7 @@ namespace llvm {
     typedef std::vector<MergePotentialsElt>::iterator MPIterator;
     std::vector<MergePotentialsElt> MergePotentials;
     SmallPtrSet<const MachineBasicBlock*, 2> TriedMerging;
+    DenseMap<const MachineBasicBlock *, int> FuncletMembership;
 
     class SameTailElt {
       MPIterator MPIter;

Modified: llvm/trunk/lib/CodeGen/FuncletLayout.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/FuncletLayout.cpp?rev=249257&r1=249256&r2=249257&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/FuncletLayout.cpp (original)
+++ llvm/trunk/lib/CodeGen/FuncletLayout.cpp Sat Oct  3 21:22:52 2015
@@ -12,12 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 #include "llvm/CodeGen/Passes.h"
-#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/Target/TargetInstrInfo.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
 using namespace llvm;
 
 #define DEBUG_TYPE "funclet-layout"
@@ -34,81 +31,17 @@ public:
 };
 }
 
-static void
-collectFuncletMembers(DenseMap<MachineBasicBlock *, int> &FuncletMembership,
-                      int Funclet, MachineBasicBlock *MBB) {
-  // Don't revisit blocks.
-  if (FuncletMembership.count(MBB) > 0) {
-    if (FuncletMembership[MBB] != Funclet) {
-      assert(false && "MBB is part of two funclets!");
-      report_fatal_error("MBB is part of two funclets!");
-    }
-    return;
-  }
-
-  // Add this MBB to our funclet.
-  FuncletMembership[MBB] = Funclet;
-
-  bool IsReturn = false;
-  int NumTerminators = 0;
-  for (MachineInstr &MI : MBB->terminators()) {
-    IsReturn |= MI.isReturn();
-    ++NumTerminators;
-  }
-  assert((!IsReturn || NumTerminators == 1) &&
-         "Expected only one terminator when a return is present!");
-
-  // Returns are boundaries where funclet transfer can occur, don't follow
-  // successors.
-  if (IsReturn)
-    return;
-
-  for (MachineBasicBlock *SMBB : MBB->successors())
-    if (!SMBB->isEHPad())
-      collectFuncletMembers(FuncletMembership, Funclet, SMBB);
-}
-
 char FuncletLayout::ID = 0;
 char &llvm::FuncletLayoutID = FuncletLayout::ID;
 INITIALIZE_PASS(FuncletLayout, "funclet-layout",
                 "Contiguously Lay Out Funclets", false, false)
 
 bool FuncletLayout::runOnMachineFunction(MachineFunction &F) {
-  // We don't have anything to do if there aren't any EH pads.
-  if (!F.getMMI().hasEHFunclets())
-    return false;
-
-  const TargetInstrInfo *TII = F.getSubtarget().getInstrInfo();
-  SmallVector<MachineBasicBlock *, 16> FuncletBlocks;
-  SmallVector<std::pair<MachineBasicBlock *, int>, 16> CatchRetSuccessors;
-  for (MachineBasicBlock &MBB : F) {
-    if (MBB.isEHFuncletEntry())
-      FuncletBlocks.push_back(&MBB);
-
-    MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
-    if (MBBI->getOpcode() != TII->getCatchReturnOpcode())
-      continue;
-
-    MachineBasicBlock *Successor = MBBI->getOperand(0).getMBB();
-    MachineBasicBlock *SuccessorColor = MBBI->getOperand(1).getMBB();
-    CatchRetSuccessors.push_back({Successor, SuccessorColor->getNumber()});
-  }
-
-  // We don't have anything to do if there aren't any EH pads.
-  if (FuncletBlocks.empty())
+  DenseMap<const MachineBasicBlock *, int> FuncletMembership =
+      getFuncletMembership(F);
+  if (FuncletMembership.empty())
     return false;
 
-  DenseMap<MachineBasicBlock *, int> FuncletMembership;
-  // Identify all the basic blocks reachable from the function entry.
-  collectFuncletMembers(FuncletMembership, F.front().getNumber(), F.begin());
-  // Next, identify all the blocks inside the funclets.
-  for (MachineBasicBlock *MBB : FuncletBlocks)
-    collectFuncletMembers(FuncletMembership, MBB->getNumber(), MBB);
-  // Finally, identify all the targets of a catchret.
-  for (std::pair<MachineBasicBlock *, int> CatchRetPair : CatchRetSuccessors)
-    collectFuncletMembers(FuncletMembership, CatchRetPair.second,
-                          CatchRetPair.first);
-
   F.sort([&](MachineBasicBlock &x, MachineBasicBlock &y) {
     return FuncletMembership[&x] < FuncletMembership[&y];
   });

Modified: llvm/trunk/test/CodeGen/X86/funclet-layout.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/funclet-layout.ll?rev=249257&r1=249256&r2=249257&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/funclet-layout.ll (original)
+++ llvm/trunk/test/CodeGen/X86/funclet-layout.ll Sat Oct  3 21:22:52 2015
@@ -103,7 +103,7 @@ unreachable:
 ; CHECK: retq
 
 
-define void @test3() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+define void @test3(i1 %V) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
 entry:
   invoke void @g()
           to label %try.cont unwind label %catch.dispatch
@@ -128,7 +128,15 @@ catchendblock:
   catchendpad unwind to caller
 
 try.cont:                                         ; preds = %entry
-  ret void
+  br i1 %V, label %exit_one, label %exit_two
+
+exit_one:
+  tail call void @exit(i32 0)
+  unreachable
+
+exit_two:
+  tail call void @exit(i32 0)
+  unreachable
 }
 
 ; CHECK-LABEL: test3:
@@ -136,15 +144,20 @@ try.cont:
 ; The entry funclet contains %entry and %try.cont
 ; CHECK: # %entry
 ; CHECK: # %try.cont
-; CHECK: retq
+; CHECK: callq exit
+; CHECK-NOT: # exit_one
+; CHECK-NOT: # exit_two
+; CHECK: ud2
 
 ; The catch(int) funclet contains %catch.2
 ; CHECK: # %catch.2
 ; CHECK: callq exit
+; CHECK: ud2
 
 ; The catch(...) funclet contains %catch
 ; CHECK: # %catch{{$}}
 ; CHECK: callq exit
+; CHECK: ud2
 
 declare void @exit(i32) noreturn nounwind
 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)




More information about the llvm-commits mailing list