[llvm] r306919 - [Dominators] Reapply r306892, r306893, r306893.

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 4 00:37:05 PDT 2017


Hi Jakub,

I get a crash when running -loop-rotate on the attached program with 
your patch:

opt -S -loop-rotate -o - reduced9.ll

gives

opt: ../include/llvm/Support/GenericDomTree.h:499: void 
llvm::DominatorTreeBase<llvm::BasicBlock>::changeImmediateDominator(DomTreeNodeBase<NodeT> 
*, DomTreeNodeBase<NodeT> *) [N = llvm::BasicBlock]: Assertion `N && 
NewIDom && "Cannot change null node pointers!"' failed.


-debug printouts:

LoopSimplify: Resolving "br i1 undef" to exit in bb2
LoopSimplify: Creating dedicated exit block bb6.loopexit
LoopRotation: rotating Loop at depth 1 containing: 
%bb1<header><exiting>,%bb2<exiting>,%bb4<latch>

Regards,
Mikael

On 07/01/2017 02:23 AM, Jakub Kuderski via llvm-commits wrote:
> Author: kuhar
> Date: Fri Jun 30 17:23:01 2017
> New Revision: 306919
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=306919&view=rev
> Log:
> [Dominators] Reapply r306892, r306893, r306893.
> 
> This reverts commit r306907 and reapplies the patches in the title.
> The patches used to make one of the
> CodeGen/ARM/2011-02-07-AntidepClobber.ll test to fail because of a
> missing null check.
> 
> Modified:
>      llvm/trunk/include/llvm/Analysis/IteratedDominanceFrontier.h
>      llvm/trunk/include/llvm/Support/GenericDomTree.h
>      llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h
>      llvm/trunk/lib/Analysis/IteratedDominanceFrontier.cpp
>      llvm/trunk/unittests/IR/DominatorTreeTest.cpp
> 
> Modified: llvm/trunk/include/llvm/Analysis/IteratedDominanceFrontier.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/IteratedDominanceFrontier.h?rev=306919&r1=306918&r2=306919&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Analysis/IteratedDominanceFrontier.h (original)
> +++ llvm/trunk/include/llvm/Analysis/IteratedDominanceFrontier.h Fri Jun 30 17:23:01 2017
> @@ -86,7 +86,6 @@ public:
>   private:
>     DominatorTreeBase<BasicBlock> &DT;
>     bool useLiveIn;
> -  DenseMap<DomTreeNode *, unsigned> DomLevels;
>     const SmallPtrSetImpl<BasicBlock *> *LiveInBlocks;
>     const SmallPtrSetImpl<BasicBlock *> *DefBlocks;
>   };
> 
> Modified: llvm/trunk/include/llvm/Support/GenericDomTree.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/GenericDomTree.h?rev=306919&r1=306918&r2=306919&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/GenericDomTree.h (original)
> +++ llvm/trunk/include/llvm/Support/GenericDomTree.h Fri Jun 30 17:23:01 2017
> @@ -65,12 +65,14 @@ template <class NodeT> class DomTreeNode
>   
>     NodeT *TheBB;
>     DomTreeNodeBase *IDom;
> +  unsigned Level;
>     std::vector<DomTreeNodeBase *> Children;
>     mutable unsigned DFSNumIn = ~0;
>     mutable unsigned DFSNumOut = ~0;
>   
>    public:
> -  DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom) : TheBB(BB), IDom(iDom) {}
> +  DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom)
> +      : TheBB(BB), IDom(iDom), Level(IDom ? IDom->Level + 1 : 0) {}
>   
>     using iterator = typename std::vector<DomTreeNodeBase *>::iterator;
>     using const_iterator =
> @@ -83,6 +85,7 @@ template <class NodeT> class DomTreeNode
>   
>     NodeT *getBlock() const { return TheBB; }
>     DomTreeNodeBase *getIDom() const { return IDom; }
> +  unsigned getLevel() const { return Level; }
>   
>     const std::vector<DomTreeNodeBase *> &getChildren() const { return Children; }
>   
> @@ -100,6 +103,8 @@ template <class NodeT> class DomTreeNode
>       if (getNumChildren() != Other->getNumChildren())
>         return true;
>   
> +    if (Level != Other->Level) return true;
> +
>       SmallPtrSet<const NodeT *, 4> OtherChildren;
>       for (const DomTreeNodeBase *I : *Other) {
>         const NodeT *Nd = I->getBlock();
> @@ -116,18 +121,19 @@ template <class NodeT> class DomTreeNode
>   
>     void setIDom(DomTreeNodeBase *NewIDom) {
>       assert(IDom && "No immediate dominator?");
> -    if (IDom != NewIDom) {
> -      typename std::vector<DomTreeNodeBase *>::iterator I =
> -          find(IDom->Children, this);
> -      assert(I != IDom->Children.end() &&
> -             "Not in immediate dominator children set!");
> -      // I am no longer your child...
> -      IDom->Children.erase(I);
> -
> -      // Switch to new dominator
> -      IDom = NewIDom;
> -      IDom->Children.push_back(this);
> -    }
> +    if (IDom == NewIDom) return;
> +
> +    auto I = find(IDom->Children, this);
> +    assert(I != IDom->Children.end() &&
> +           "Not in immediate dominator children set!");
> +    // I am no longer your child...
> +    IDom->Children.erase(I);
> +
> +    // Switch to new dominator
> +    IDom = NewIDom;
> +    IDom->Children.push_back(this);
> +
> +    UpdateLevel();
>     }
>   
>     /// getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes
> @@ -143,6 +149,23 @@ private:
>       return this->DFSNumIn >= other->DFSNumIn &&
>              this->DFSNumOut <= other->DFSNumOut;
>     }
> +
> +  void UpdateLevel() {
> +    assert(IDom);
> +    if (Level == IDom->Level + 1) return;
> +
> +    SmallVector<DomTreeNodeBase *, 64> WorkStack = {this};
> +
> +    while (!WorkStack.empty()) {
> +      DomTreeNodeBase *Current = WorkStack.pop_back_val();
> +      Current->Level = Current->IDom->Level + 1;
> +
> +      for (DomTreeNodeBase *C : *Current) {
> +        assert(C->IDom);
> +        if (C->Level != C->IDom->Level + 1) WorkStack.push_back(C);
> +      }
> +    }
> +  }
>   };
>   
>   template <class NodeT>
> @@ -152,9 +175,10 @@ raw_ostream &operator<<(raw_ostream &O,
>     else
>       O << " <<exit node>>";
>   
> -  O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "}";
> +  O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "} ["
> +    << Node->getLevel() << "]\n";
>   
> -  return O << "\n";
> +  return O;
>   }
>   
>   template <class NodeT>
> @@ -345,6 +369,13 @@ template <class NodeT> class DominatorTr
>       if (!isReachableFromEntry(A))
>         return false;
>   
> +    if (B->getIDom() == A) return true;
> +
> +    if (A->getIDom() == B) return false;
> +
> +    // A can only dominate B if it is higher in the tree.
> +    if (A->getLevel() >= B->getLevel()) return false;
> +
>       // Compare the result of the tree walk and the dfs numbers, if expensive
>       // checks are enabled.
>   #ifdef EXPENSIVE_CHECKS
> @@ -376,7 +407,7 @@ template <class NodeT> class DominatorTr
>   
>     /// findNearestCommonDominator - Find nearest common dominator basic block
>     /// for basic block A and B. If there is no such block then return NULL.
> -  NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) {
> +  NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) const {
>       assert(A->getParent() == B->getParent() &&
>              "Two blocks are not in same function");
>   
> @@ -388,54 +419,24 @@ template <class NodeT> class DominatorTr
>           return &Entry;
>       }
>   
> -    // If B dominates A then B is nearest common dominator.
> -    if (dominates(B, A))
> -      return B;
> -
> -    // If A dominates B then A is nearest common dominator.
> -    if (dominates(A, B))
> -      return A;
> -
>       DomTreeNodeBase<NodeT> *NodeA = getNode(A);
>       DomTreeNodeBase<NodeT> *NodeB = getNode(B);
>   
> -    // If we have DFS info, then we can avoid all allocations by just querying
> -    // it from each IDom. Note that because we call 'dominates' twice above, we
> -    // expect to call through this code at most 16 times in a row without
> -    // building valid DFS information. This is important as below is a *very*
> -    // slow tree walk.
> -    if (DFSInfoValid) {
> -      DomTreeNodeBase<NodeT> *IDomA = NodeA->getIDom();
> -      while (IDomA) {
> -        if (NodeB->DominatedBy(IDomA))
> -          return IDomA->getBlock();
> -        IDomA = IDomA->getIDom();
> -      }
> -      return nullptr;
> -    }
> -
> -    // Collect NodeA dominators set.
> -    SmallPtrSet<DomTreeNodeBase<NodeT> *, 16> NodeADoms;
> -    NodeADoms.insert(NodeA);
> -    DomTreeNodeBase<NodeT> *IDomA = NodeA->getIDom();
> -    while (IDomA) {
> -      NodeADoms.insert(IDomA);
> -      IDomA = IDomA->getIDom();
> -    }
> +    if (!NodeA || !NodeB) return nullptr;
>   
> -    // Walk NodeB immediate dominators chain and find common dominator node.
> -    DomTreeNodeBase<NodeT> *IDomB = NodeB->getIDom();
> -    while (IDomB) {
> -      if (NodeADoms.count(IDomB) != 0)
> -        return IDomB->getBlock();
> +    // Use level information to go up the tree until the levels match. Then
> +    // continue going up til we arrive at the same node.
> +    while (NodeA && NodeA != NodeB) {
> +      if (NodeA->getLevel() < NodeB->getLevel()) std::swap(NodeA, NodeB);
>   
> -      IDomB = IDomB->getIDom();
> +      NodeA = NodeA->IDom;
>       }
>   
> -    return nullptr;
> +    return NodeA ? NodeA->getBlock() : nullptr;
>     }
>   
> -  const NodeT *findNearestCommonDominator(const NodeT *A, const NodeT *B) {
> +  const NodeT *findNearestCommonDominator(const NodeT *A,
> +                                          const NodeT *B) const {
>       // Cast away the const qualifiers here. This is ok since
>       // const is re-introduced on the return type.
>       return findNearestCommonDominator(const_cast<NodeT *>(A),
> @@ -481,8 +482,10 @@ template <class NodeT> class DominatorTr
>       } else {
>         assert(Roots.size() == 1);
>         NodeT *OldRoot = Roots.front();
> -      DomTreeNodes[OldRoot] =
> -        NewNode->addChild(std::move(DomTreeNodes[OldRoot]));
> +      auto &OldNode = DomTreeNodes[OldRoot];
> +      OldNode = NewNode->addChild(std::move(DomTreeNodes[OldRoot]));
> +      OldNode->IDom = NewNode;
> +      OldNode->UpdateLevel();
>         Roots[0] = BB;
>       }
>       return RootNode = NewNode;
> 
> Modified: llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h?rev=306919&r1=306918&r2=306919&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h (original)
> +++ llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h Fri Jun 30 17:23:01 2017
> @@ -280,6 +280,7 @@ struct SemiNCAInfo {
>     }
>   
>     void doFullDFSWalk(const DomTreeT &DT) {
> +    NumToNode.push_back(nullptr);
>       unsigned Num = 0;
>       for (auto *Root : DT.Roots)
>         if (!DT.isPostDominator())
> @@ -317,6 +318,78 @@ struct SemiNCAInfo {
>   
>       return true;
>     }
> +
> +  // Check if for every parent with a level L in the tree all of its children
> +  // have level L + 1.
> +  static bool VerifyLevels(const DomTreeT &DT) {
> +    for (auto &NodeToTN : DT.DomTreeNodes) {
> +      const TreeNodePtr TN = NodeToTN.second.get();
> +      const NodePtr BB = TN->getBlock();
> +      if (!BB) continue;
> +
> +      const TreeNodePtr IDom = TN->getIDom();
> +      if (!IDom && TN->getLevel() != 0) {
> +        errs() << "Node without an IDom ";
> +        PrintBlockOrNullptr(errs(), BB);
> +        errs() << " has a nonzero level " << TN->getLevel() << "!\n";
> +        errs().flush();
> +
> +        return false;
> +      }
> +
> +      if (IDom && TN->getLevel() != IDom->getLevel() + 1) {
> +        errs() << "Node ";
> +        PrintBlockOrNullptr(errs(), BB);
> +        errs() << " has level " << TN->getLevel() << " while it's IDom ";
> +        PrintBlockOrNullptr(errs(), IDom->getBlock());
> +        errs() << " has level " << IDom->getLevel() << "!\n";
> +        errs().flush();
> +
> +        return false;
> +      }
> +    }
> +
> +    return true;
> +  }
> +
> +  // Checks if for every edge From -> To in the graph
> +  //     NCD(From, To) == IDom(To) or To.
> +  bool verifyNCD(const DomTreeT &DT) {
> +    clear();
> +    doFullDFSWalk(DT);
> +
> +    for (auto &BlockToInfo : NodeToInfo) {
> +      auto &Info = BlockToInfo.second;
> +
> +      const NodePtr From = NumToNode[Info.Parent];
> +      if (!From) continue;
> +
> +      const NodePtr To = BlockToInfo.first;
> +      const TreeNodePtr ToTN = DT.getNode(To);
> +      assert(ToTN);
> +
> +      const NodePtr NCD = DT.findNearestCommonDominator(From, To);
> +      const TreeNodePtr NCDTN = NCD ? DT.getNode(NCD) : nullptr;
> +      const TreeNodePtr ToIDom = ToTN->getIDom();
> +      if (NCDTN != ToTN && NCDTN != ToIDom) {
> +        errs() << "NearestCommonDominator verification failed:\n\tNCD(From:";
> +        PrintBlockOrNullptr(errs(), From);
> +        errs() << ", To:";
> +        PrintBlockOrNullptr(errs(), To);
> +        errs() << ") = ";
> +        PrintBlockOrNullptr(errs(), NCD);
> +        errs() << ",\t (should be To or IDom[To]: ";
> +        PrintBlockOrNullptr(errs(), ToIDom ? ToIDom->getBlock() : nullptr);
> +        errs() << ")\n";
> +        errs().flush();
> +
> +        return false;
> +      }
> +    }
> +
> +    return true;
> +  }
> +
>     // The below routines verify the correctness of the dominator tree relative to
>     // the CFG it's coming from.  A tree is a dominator tree iff it has two
>     // properties, called the parent property and the sibling property.  Tarjan
> @@ -441,9 +514,9 @@ bool Verify(const DominatorTreeBaseByGra
>                   "NodePtr should be a pointer type");
>     SemiNCAInfo<typename std::remove_pointer<NodePtr>::type> SNCA;
>   
> -  return SNCA.verifyReachability(DT) && SNCA.verifyParentProperty(DT) &&
> +  return SNCA.verifyReachability(DT) && SNCA.VerifyLevels(DT) &&
> +         SNCA.verifyNCD(DT) && SNCA.verifyParentProperty(DT) &&
>            SNCA.verifySiblingProperty(DT);
> -
>   }
>   
>   }  // namespace DomTreeBuilder
> 
> Modified: llvm/trunk/lib/Analysis/IteratedDominanceFrontier.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/IteratedDominanceFrontier.cpp?rev=306919&r1=306918&r2=306919&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/IteratedDominanceFrontier.cpp (original)
> +++ llvm/trunk/lib/Analysis/IteratedDominanceFrontier.cpp Fri Jun 30 17:23:01 2017
> @@ -20,14 +20,6 @@ namespace llvm {
>   template <class NodeTy>
>   void IDFCalculator<NodeTy>::calculate(
>       SmallVectorImpl<BasicBlock *> &PHIBlocks) {
> -  // If we haven't computed dominator tree levels, do so now.
> -  if (DomLevels.empty()) {
> -    for (auto DFI = df_begin(DT.getRootNode()), DFE = df_end(DT.getRootNode());
> -         DFI != DFE; ++DFI) {
> -      DomLevels[*DFI] = DFI.getPathLength() - 1;
> -    }
> -  }
> -
>     // Use a priority queue keyed on dominator tree level so that inserted nodes
>     // are handled from the bottom of the dominator tree upwards.
>     typedef std::pair<DomTreeNode *, unsigned> DomTreeNodePair;
> @@ -37,7 +29,7 @@ void IDFCalculator<NodeTy>::calculate(
>   
>     for (BasicBlock *BB : *DefBlocks) {
>       if (DomTreeNode *Node = DT.getNode(BB))
> -      PQ.push(std::make_pair(Node, DomLevels.lookup(Node)));
> +      PQ.push({Node, Node->getLevel()});
>     }
>   
>     SmallVector<DomTreeNode *, 32> Worklist;
> @@ -72,7 +64,7 @@ void IDFCalculator<NodeTy>::calculate(
>           if (SuccNode->getIDom() == Node)
>             continue;
>   
> -        unsigned SuccLevel = DomLevels.lookup(SuccNode);
> +        const unsigned SuccLevel = SuccNode->getLevel();
>           if (SuccLevel > RootLevel)
>             continue;
>   
> 
> Modified: llvm/trunk/unittests/IR/DominatorTreeTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/DominatorTreeTest.cpp?rev=306919&r1=306918&r2=306919&view=diff
> ==============================================================================
> --- llvm/trunk/unittests/IR/DominatorTreeTest.cpp (original)
> +++ llvm/trunk/unittests/IR/DominatorTreeTest.cpp Fri Jun 30 17:23:01 2017
> @@ -230,6 +230,12 @@ TEST(DominatorTree, Unreachable) {
>           EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 3UL);
>           EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 4UL);
>   
> +        // Check levels before
> +        EXPECT_EQ(DT->getNode(BB0)->getLevel(), 0U);
> +        EXPECT_EQ(DT->getNode(BB1)->getLevel(), 1U);
> +        EXPECT_EQ(DT->getNode(BB2)->getLevel(), 1U);
> +        EXPECT_EQ(DT->getNode(BB4)->getLevel(), 1U);
> +
>           // Reattach block 3 to block 1 and recalculate
>           BB1->getTerminator()->eraseFromParent();
>           BranchInst::Create(BB4, BB3, ConstantInt::getTrue(F.getContext()), BB1);
> @@ -248,6 +254,13 @@ TEST(DominatorTree, Unreachable) {
>           EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 5UL);
>           EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 6UL);
>   
> +        // Check levels after
> +        EXPECT_EQ(DT->getNode(BB0)->getLevel(), 0U);
> +        EXPECT_EQ(DT->getNode(BB1)->getLevel(), 1U);
> +        EXPECT_EQ(DT->getNode(BB2)->getLevel(), 1U);
> +        EXPECT_EQ(DT->getNode(BB3)->getLevel(), 2U);
> +        EXPECT_EQ(DT->getNode(BB4)->getLevel(), 1U);
> +
>           // Change root node
>           DT->verifyDomTree();
>           BasicBlock *NewEntry =
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> 
-------------- next part --------------
define void @func() {
bb0:
  br label %bb1

bb1:                                              ; preds = %bb4, %bb0
  %0 = phi i16 [ %2, %bb4 ], [ 0, %bb0 ]
  %1 = icmp sle i16 %0, 2
  br i1 %1, label %bb2, label %bb5

bb2:                                              ; preds = %bb1
  br i1 undef, label %bb6, label %bb4

bb3:                                              ; No predecessors!
  br label %bb6

bb4:                                              ; preds = %bb2
  %2 = add i16 undef, 1
  br label %bb1

bb5:                                              ; preds = %bb1
  br label %bb6

bb6:                                              ; preds = %bb5, %bb3, %bb2
  unreachable
}


More information about the llvm-commits mailing list